Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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": "^0.0.3",
"@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