Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/connect/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@tanstack/react-router-devtools": "^1.122.0",
"@xstate/store": "^3.5.1",
"clsx": "^2.1.1",
"effect": "^3.16.12",
"effect": "^3.16.16",
"framer-motion": "^12.10.1",
"graphql-request": "^7.2.0",
"lucide-react": "^0.508.0",
Expand Down
3 changes: 2 additions & 1 deletion apps/events/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@graphprotocol/grc-20": "^0.21.6",
"@graphprotocol/hypergraph": "workspace:*",
"@graphprotocol/hypergraph-react": "workspace:*",
"@graphprotocol/typesync": "workspace:*",
"@noble/hashes": "^1.8.0",
"@radix-ui/react-avatar": "^1.1.9",
"@radix-ui/react-icons": "^1.3.2",
Expand All @@ -21,7 +22,7 @@
"@xstate/store": "^3.5.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"effect": "^3.16.12",
"effect": "^3.16.16",
"framer-motion": "^12.10.1",
"graphql-request": "^7.1.2",
"isomorphic-ws": "^5.0.0",
Expand Down
2 changes: 1 addition & 1 deletion apps/events/src/mapping.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Id } from '@graphprotocol/grc-20';
import type { Mapping } from '@graphprotocol/hypergraph';
import type { Mapping } from '@graphprotocol/typesync/Mapping';

export const mapping: Mapping = {
Event: {
Expand Down
4 changes: 3 additions & 1 deletion apps/events/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
"@graphprotocol/hypergraph": ["../../packages/hypergraph/src/index.js"],
"@graphprotocol/hypergraph/*": ["../../packages/hypergraph/src/*.js"],
"@graphprotocol/hypergraph-react": ["../../packages/hypergraph-react/src/index.js"],
"@graphprotocol/hypergraph-react/*": ["../../packages/hypergraph-react/src/*.js"]
"@graphprotocol/hypergraph-react/*": ["../../packages/hypergraph-react/src/*.js"],
"@graphprotocol/typesync": ["../../packages/typesync/src/index.js"],
"@graphprotocol/typesync/*": ["../../packages/typesync/src/*.js"]
}
}
}
2 changes: 1 addition & 1 deletion apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@privy-io/server-auth": "^1.26.0",
"body-parser": "^2.2.0",
"cors": "^2.8.5",
"effect": "^3.16.12",
"effect": "^3.16.16",
"express": "^5.1.0",
"prisma": "^6.7.0",
"siwe": "^3.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RelationTypeOption extends Schema.Class<RelationTypeOption>('/hypergraph/t
const typeOptions: Array<TypeOption> = [
TypeOption.make({ id: 'DefaultEntityText', name: 'Text' }),
TypeOption.make({ id: 'DefaultEntityNumber', name: 'Number' }),
TypeOption.make({ id: 'DefaultEntityBoolean', name: 'Boolean' }),
TypeOption.make({ id: 'DefaultEntityCheckbox', name: 'Checkbox' }),
TypeOption.make({ id: 'DefaultEntityDate', name: 'Date' }),
TypeOption.make({ id: 'DefaultEntityUrl', name: 'Url' }),
TypeOption.make({ id: 'DefaultEntityPoint', name: 'Point' }),
Expand Down
8 changes: 5 additions & 3 deletions apps/typesync/client/src/routes/apps/create.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import { isDataTypeRelation } from '@graphprotocol/typesync/Mapping';
import {
ArrowUturnLeftIcon,
CheckCircleIcon,
Expand All @@ -14,7 +15,7 @@ import { Link, createFileRoute } from '@tanstack/react-router';
import { Array as EffectArray, String as EffectString, Option, Schema, pipe } from 'effect';
import { useState } from 'react';

import { InsertAppSchema, isDataTypeRelation } from '../../../../domain/Domain.js';
import { InsertAppSchema } from '../../../../domain/Domain.js';

import { SchemaBrowser } from '../../Components/App/CreateAppForm/SchemaBuilder/SchemaBrowser.js';
import { useAppForm } from '../../Components/App/CreateAppForm/useCreateAppForm.js';
Expand Down Expand Up @@ -98,7 +99,8 @@ function CreateAppPage() {
defaultValues,
validators: {
onChangeAsyncDebounceMs: 100,
onChange: Schema.standardSchemaV1(InsertAppSchema),
// biome-ignore lint/suspicious/noExplicitAny: fixes an issue with the prop.dataType type-string of `Relation(${name})`
onChange: Schema.standardSchemaV1(InsertAppSchema) as any,
},
async onSubmit({ formApi, value }) {
await mutateAsync(value).then(() => formApi.reset(undefined, { keepDefaultValues: true }));
Expand Down Expand Up @@ -794,7 +796,7 @@ function CreateAppPage() {
</div>
</TabsPrimitive.Content>

<TabsPrimitive.List className="mt-6 flex items-center justify-end gap-x-6 fixed bottom-4 right-4 bg-white dark:bg-black p-4 rounded-lg">
<TabsPrimitive.List className="mt-6 flex items-center justify-end gap-x-6 fixed bottom-4 right-4 bg-white dark:bg-inherit p-4 rounded-lg">
<Link to="/" className="text-sm/6 font-semibold text-gray-900 dark:text-white">
Cancel
</Link>
Expand Down
8 changes: 4 additions & 4 deletions apps/typesync/client/src/utils/mapper.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { SchemaDataType } from '../../../domain/Domain';
import type { SchemaDataType } from '@graphprotocol/typesync/Mapping';

import type { DataType } from '../generated/graphql';
import type { DataTypes } from '../generated/graphql';

export function mapKGDataTypeToPrimitiveType(dataType: DataType, entity: string): SchemaDataType {
export function mapKGDataTypeToPrimitiveType(dataType: DataTypes, entity: string): SchemaDataType {
switch (dataType) {
case 'CHECKBOX': {
return 'Boolean';
return 'Checkbox';
}
case 'NUMBER': {
return 'Number';
Expand Down
86 changes: 4 additions & 82 deletions apps/typesync/domain/Domain.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,5 @@
import { Array as EffectArray, String as EffectString, Schema, pipe } from 'effect';

function namesAreUnique<T extends { readonly name: string }>(entries: ReadonlyArray<T>): boolean {
const names = new Set<string>();

for (const entry of entries) {
const name = EffectString.toLowerCase(entry.name);
if (names.has(name)) {
return false;
}
names.add(name);
}

return true;
}

export type DataTypeRelation = `Relation(${string})`;
export function isDataTypeRelation(val: string): val is DataTypeRelation {
return /^Relation\((.+)\)$/.test(val);
}

export const SchemaDataTypeRelation = Schema.NonEmptyTrimmedString.pipe(
Schema.filter((val) => isDataTypeRelation(val)),
);
export type SchemaDataTypeRelation = typeof SchemaDataTypeRelation.Type;

export const SchemaDataTypePrimitive = Schema.Literal('Text', 'Number', 'Boolean', 'Date', 'Point', 'Url');
export type SchemaDataTypePrimitive = typeof SchemaDataTypePrimitive.Type;

export const SchemaDataType = Schema.Union(SchemaDataTypePrimitive, SchemaDataTypeRelation);
export type SchemaDataType = typeof SchemaDataType.Type;

export const SchemaTypePropertyRelation = Schema.Struct({
name: Schema.NonEmptyTrimmedString,
knowledgeGraphId: Schema.NullOr(Schema.UUID),
dataType: Schema.NonEmptyTrimmedString, // The correct type for this is: `SchemaDataTypeRelation`. however, the standard schema definition to use in the form schema validation fails because of the `Relation(${string})` template string type.
relationType: Schema.NonEmptyTrimmedString.annotations({
identifier: 'SchemaTypePropertyRelation.relationType',
description: 'name of the type within the schema that this property is related to',
examples: ['Account'],
}),
});
export type SchemaTypePropertyRelation = typeof SchemaTypePropertyRelation.Type;

export const SchemaTypePropertyPrimitive = Schema.Struct({
name: Schema.NonEmptyTrimmedString,
knowledgeGraphId: Schema.NullOr(Schema.UUID),
dataType: SchemaDataTypePrimitive,
});
export type SchemaTypePropertyPrimitive = typeof SchemaTypePropertyPrimitive.Type;

export function propertyIsRelation(
property: SchemaTypePropertyPrimitive | SchemaTypePropertyRelation,
): property is SchemaTypePropertyRelation {
return isDataTypeRelation(property.dataType);
}

export const SchemaType = Schema.Struct({
name: Schema.NonEmptyTrimmedString,
knowledgeGraphId: Schema.NullOr(Schema.UUID),
properties: Schema.Array(Schema.Union(SchemaTypePropertyPrimitive, SchemaTypePropertyRelation)).pipe(
Schema.minItems(1),
Schema.filter(namesAreUnique, {
identifier: 'DuplicatePropertyNames',
jsonSchema: {},
description: 'The property.name must be unique across all properties in the type',
}),
),
});
export type SchemaType = typeof SchemaType.Type;

export function allRelationPropertyTypesExist(types: ReadonlyArray<SchemaType>): boolean {
const unqTypeNames = EffectArray.reduce(types, new Set<string>(), (names, curr) => names.add(curr.name));
return pipe(
types,
EffectArray.flatMap((curr) => curr.properties),
EffectArray.filter((prop) => propertyIsRelation(prop)),
EffectArray.every((prop) => unqTypeNames.has(prop.relationType)),
);
}
import { Mapping, Utils } from '@graphprotocol/typesync';
import { Schema } from 'effect';

/**
* Defines the type to be received by the app schema builder.
Expand All @@ -88,9 +10,9 @@ export const InsertAppSchema = Schema.Struct({
description: Schema.NullOr(Schema.String),
directory: Schema.NullOr(Schema.String.pipe(Schema.pattern(/^(\.\/|~\/|\/|[a-zA-Z]:\/)[\w\-\.\s\/]*[\w\-\.]$/))),
template: Schema.Literal('vite_react'),
types: Schema.Array(SchemaType).pipe(
types: Schema.Array(Mapping.SchemaType).pipe(
Schema.minItems(1),
Schema.filter(namesAreUnique, {
Schema.filter(Utils.namesAreUnique, {
identifier: 'DuplicateTypeNames',
jsonSchema: {},
description: 'The type.name must be unique across all types in the schema',
Expand Down
28 changes: 15 additions & 13 deletions apps/typesync/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,21 @@
"hypergraph": "pnpx tsx ./src/bin.ts typesync"
},
"devDependencies": {
"@effect/cli": "^0.67.0",
"@effect/experimental": "^0.52.0",
"@effect/language-service": "^0.26.0",
"@effect/platform": "^0.88.0",
"@effect/platform-node": "^0.90.0",
"@effect/sql": "^0.41.0",
"@effect/sql-sqlite-node": "^0.42.0",
"@effect/vitest": "^0.24.0",
"@effect/cli": "^0.67.1",
"@effect/experimental": "^0.52.2",
"@effect/language-service": "^0.27.1",
"@effect/platform": "^0.88.1",
"@effect/platform-node": "^0.91.0",
"@effect/printer": "^0.44.14",
"@effect/sql": "^0.42.0",
"@effect/sql-sqlite-node": "^0.43.0",
"@effect/vitest": "^0.24.1",
"@graphql-codegen/cli": "^5.0.7",
"@graphql-codegen/client-preset": "^4.8.3",
"@graphql-codegen/typescript": "^4.1.6",
"@graphql-codegen/typescript-operations": "^4.6.1",
"@tanstack/router-plugin": "^1.127.5",
"@types/node": "^24.0.13",
"@tanstack/router-plugin": "^1.128.0",
"@types/node": "^24.0.14",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.6.0",
Expand All @@ -64,6 +65,7 @@
"dependencies": {
"@graphql-typed-document-node/core": "^3.2.0",
"@graphprotocol/grc-20": "^0.21.6",
"@graphprotocol/typesync": "workspace:*",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can typesync depend on typesync here?

"@headlessui/react": "^2.2.4",
"@heroicons/react": "^2.2.0",
"@phosphor-icons/react": "^2.1.10",
Expand All @@ -72,11 +74,11 @@
"@tanstack/react-form": "^1.14.1",
"@tanstack/react-query": "^5.83.0",
"@tanstack/react-query-devtools": "^5.83.0",
"@tanstack/react-router": "^1.127.3",
"@tanstack/react-router-devtools": "^1.127.3",
"@tanstack/react-router": "^1.128.0",
"@tanstack/react-router-devtools": "^1.128.0",
"better-sqlite3": "^12.2.0",
"date-fns": "^4.1.0",
"effect": "^3.16.13",
"effect": "^3.16.16",
"graphql": "^16.11.0",
"graphql-request": "^7.2.0",
"jotai": "^2.12.5",
Expand Down
5 changes: 2 additions & 3 deletions apps/typesync/src/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { fileURLToPath } from 'node:url';
import { NodeContext } from '@effect/platform-node';
import { SqlClient, SqlError, SqlResolver, SqlSchema } from '@effect/sql';
import { SqliteMigrator as Migrator, SqliteClient } from '@effect/sql-sqlite-node';
import { propertyIsRelation } from '@graphprotocol/typesync/Mapping';
import { Chunk, Console, Effect, Array as EffectArray, Layer, Option, Order, Schema, Stream } from 'effect';

import * as TypesyncDomain from '../domain/Domain.js';
Expand Down Expand Up @@ -234,9 +235,7 @@ export class DatabaseService extends Effect.Service<DatabaseService>()('/typesyn
app_schema_type_id: createdType.id,
name: property.name,
type_name: property.dataType,
relation_type_name: TypesyncDomain.propertyIsRelation(property)
? property.relationType
: null,
relation_type_name: propertyIsRelation(property) ? property.relationType : null,
description: null,
nullable: null,
optional: null,
Expand Down
Loading
Loading