@graphprotocol/hypergraph 0.4.2 → 0.5.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/cli/Cli.js +1 -1
  2. package/dist/cli/bin.js +0 -0
  3. package/dist/cli/bin.js.map +1 -1
  4. package/dist/cli/bun.js +0 -0
  5. package/dist/cli/services/Model.d.ts +99 -0
  6. package/dist/cli/services/Model.d.ts.map +1 -0
  7. package/dist/cli/services/Model.js +52 -0
  8. package/dist/cli/services/Model.js.map +1 -0
  9. package/dist/cli/services/Typesync.d.ts +7 -4
  10. package/dist/cli/services/Typesync.d.ts.map +1 -1
  11. package/dist/cli/services/Typesync.js +106 -4
  12. package/dist/cli/services/Typesync.js.map +1 -1
  13. package/dist/cli/services/Utils.d.ts +81 -0
  14. package/dist/cli/services/Utils.d.ts.map +1 -1
  15. package/dist/cli/services/Utils.js +198 -8
  16. package/dist/cli/services/Utils.js.map +1 -1
  17. package/dist/cli/subcommands/typesync.d.ts +13 -2
  18. package/dist/cli/subcommands/typesync.d.ts.map +1 -1
  19. package/dist/cli/subcommands/typesync.js +141 -21
  20. package/dist/cli/subcommands/typesync.js.map +1 -1
  21. package/dist/entity/findMany.d.ts.map +1 -1
  22. package/dist/entity/findMany.js +21 -13
  23. package/dist/entity/findMany.js.map +1 -1
  24. package/dist/entity/types.d.ts +0 -6
  25. package/dist/entity/types.d.ts.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/mapping/Mapping.d.ts +24 -12
  31. package/dist/mapping/Mapping.d.ts.map +1 -1
  32. package/dist/mapping/Mapping.js +12 -4
  33. package/dist/mapping/Mapping.js.map +1 -1
  34. package/dist/typesync-studio/dist/assets/authenticate-callback-XTxFqKgn.js +1 -0
  35. package/dist/typesync-studio/dist/assets/ccip-_s3urR1L.js +1 -0
  36. package/dist/typesync-studio/dist/assets/index-B-tctDXW.js +88 -0
  37. package/dist/typesync-studio/dist/assets/index-BHBkzpXd.css +1 -0
  38. package/dist/typesync-studio/dist/assets/index-bioTPE3q.js +215 -0
  39. package/dist/typesync-studio/dist/index.html +30 -0
  40. package/dist/typesync-studio/dist/manifest.json +20 -0
  41. package/dist/typesync-studio/dist/robots.txt +3 -0
  42. package/package.json +9 -8
  43. package/src/cli/Cli.ts +1 -1
  44. package/src/cli/bin.ts +0 -1
  45. package/src/cli/services/Model.ts +87 -0
  46. package/src/cli/services/Typesync.ts +137 -9
  47. package/src/cli/services/Utils.ts +231 -11
  48. package/src/cli/subcommands/typesync.ts +251 -42
  49. package/src/entity/findMany.ts +27 -15
  50. package/src/entity/types.ts +0 -6
  51. package/src/index.ts +1 -0
  52. package/src/mapping/Mapping.ts +21 -6
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html>
2
+ <html
3
+ lang="en"
4
+ class="h-full min-h-screen w-full p-0 m-0 dark:bg-slate-950 dark:text-white bg-white text-gray-950 font-mono"
5
+ >
6
+ <head>
7
+ <meta charset="UTF-8" />
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
9
+ <link
10
+ rel="icon"
11
+ type="image/png"
12
+ sizes="64x64"
13
+ href="https://storage.thegraph.com/favicons/64x64.png"
14
+ />
15
+ <link
16
+ rel="icon"
17
+ type="image/png"
18
+ sizes="256x256"
19
+ href="https://storage.thegraph.com/favicons/256x256.png"
20
+ />
21
+ <title>Graph Protocol | Hypergraph TypeSync</title>
22
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
23
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
24
+ <script type="module" crossorigin src="/assets/index-bioTPE3q.js"></script>
25
+ <link rel="stylesheet" crossorigin href="/assets/index-BHBkzpXd.css">
26
+ </head>
27
+ <body class="h-full w-full">
28
+ <div id="root"></div>
29
+ </body>
30
+ </html>
@@ -0,0 +1,20 @@
1
+ {
2
+ "short_name": "Hypergraph Typesync Studio",
3
+ "name": "Graph Protocol Hypergraph Typesync Studio",
4
+ "icons": [
5
+ {
6
+ "src": "https://storage.thegraph.com/favicons/64x64.png",
7
+ "sizes": "64x64 32x32 24x24 16x16",
8
+ "type": "image/png"
9
+ },
10
+ {
11
+ "src": "https://storage.thegraph.com/favicons/256x256.png",
12
+ "type": "image/png",
13
+ "sizes": "256x256"
14
+ }
15
+ ],
16
+ "start_url": ".",
17
+ "display": "standalone",
18
+ "theme_color": "#000000",
19
+ "background_color": "#ffffff"
20
+ }
@@ -0,0 +1,3 @@
1
+ # https://www.robotstxt.org/robotstxt.html
2
+ User-agent: *
3
+ Disallow:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphprotocol/hypergraph",
3
- "version": "0.4.2",
3
+ "version": "0.5.0-alpha",
4
4
  "description": "SDK for building performant, type-safe, local-first dapps on top of The Graph ecosystem knowledge graphs.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,12 +28,13 @@
28
28
  "./space-info": "./dist/space-info/index.js",
29
29
  "./store": "./dist/store.js",
30
30
  "./store-connect": "./dist/store-connect.js",
31
- "./types": "./dist/types.js"
31
+ "./types": "./dist/types.js",
32
+ "./typesync": "./dist/cli/services/Model.js"
32
33
  },
33
34
  "dependencies": {
34
- "@automerge/automerge": "^2.2.9",
35
- "@automerge/automerge-repo": "^2.0.6",
36
- "@effect/experimental": "^0.51.1",
35
+ "@automerge/automerge": "^3.1.1",
36
+ "@automerge/automerge-repo": "^2.2.0",
37
+ "@effect/experimental": "^0.54.3",
37
38
  "@graphprotocol/grc-20": "^0.24.1",
38
39
  "@noble/ciphers": "^1.3.0",
39
40
  "@noble/curves": "^1.9.0",
@@ -43,15 +44,15 @@
43
44
  "@serenity-kit/noble-sodium": "^0.2.1",
44
45
  "@xstate/store": "^3.5.1",
45
46
  "bs58check": "^4.0.0",
46
- "effect": "^3.17.3",
47
+ "effect": "^3.17.6",
47
48
  "permissionless": "^0.2.47",
48
49
  "siwe": "^3.0.0",
49
50
  "uuid": "^11.1.0",
50
51
  "viem": "^2.30.6"
51
52
  },
52
53
  "bin": {
53
- "hypergraph": "./dist/cli/bin.js",
54
- "hg": "./dist/cli/bin.js"
54
+ "hypergraph": "./dist/cli/bun.js",
55
+ "hg": "./dist/cli/bun.js"
55
56
  },
56
57
  "publishConfig": {
57
58
  "provenance": false
package/src/cli/Cli.ts CHANGED
@@ -11,5 +11,5 @@ const hypergraph = Command.make('hypergraph').pipe(
11
11
 
12
12
  export const run = Command.run(hypergraph, {
13
13
  name: 'hypergraph',
14
- version: '0.3.0',
14
+ version: '0.4.2',
15
15
  });
package/src/cli/bin.ts CHANGED
@@ -6,7 +6,6 @@ import * as AnsiDoc from '@effect/printer-ansi/AnsiDoc';
6
6
  import * as Effect from 'effect/Effect';
7
7
  import * as Logger from 'effect/Logger';
8
8
  import * as LogLevel from 'effect/LogLevel';
9
-
10
9
  import { run } from './Cli.js';
11
10
  import { AnsiDocLogger } from './Logger.js';
12
11
 
@@ -0,0 +1,87 @@
1
+ import { Schema } from 'effect';
2
+
3
+ import * as Mapping from '../../mapping/Mapping.js';
4
+ import * as Utils from '../../mapping/Utils.js';
5
+
6
+ export const TypesyncHypergraphSchemaStatus = Schema.NullOr(
7
+ Schema.Literal(
8
+ // the type/property has been synced to the schema file and published to the Knowledge Graph
9
+ 'published',
10
+ // the type/property has been synced to the schema file, but requires publishing to the Knowledge Graph
11
+ 'synced',
12
+ // the type/property exists in the Knowledge Graph, has been added to the users schema through the Typesync UI, but requires syncing to the schema file
13
+ 'published_not_synced',
14
+ ),
15
+ );
16
+ export type TypesyncHypergraphSchemaStatus = typeof TypesyncHypergraphSchemaStatus.Type;
17
+
18
+ export const TypesyncHypergraphSchemaTypeProperty = Schema.Union(
19
+ Mapping.SchemaTypePropertyPrimitive,
20
+ Mapping.SchemaTypePropertyRelation,
21
+ ).pipe(
22
+ Schema.extend(
23
+ Schema.Struct({
24
+ status: TypesyncHypergraphSchemaStatus,
25
+ }),
26
+ ),
27
+ );
28
+ export type TypesyncHypergraphSchemaTypeProperty = typeof TypesyncHypergraphSchemaTypeProperty.Type;
29
+ export class TypesyncHypergraphSchemaType extends Schema.Class<TypesyncHypergraphSchemaType>(
30
+ '/Hypergraph/cli/models/TypesyncHypergraphSchemaType',
31
+ )({
32
+ ...Mapping.SchemaType.omit('properties').fields,
33
+ status: TypesyncHypergraphSchemaStatus,
34
+ properties: Schema.Array(TypesyncHypergraphSchemaTypeProperty).pipe(
35
+ Schema.minItems(1),
36
+ Schema.filter(Utils.namesAreUnique, {
37
+ identifier: 'DuplicatePropertyNames',
38
+ jsonSchema: {},
39
+ description: 'The property.name must be unique across all properties in the type',
40
+ }),
41
+ ),
42
+ }) {}
43
+ export class TypesyncHypergraphSchema extends Schema.Class<TypesyncHypergraphSchema>(
44
+ '/Hypergraph/cli/models/TypesyncHypergraphSchema',
45
+ )({
46
+ types: Schema.Array(TypesyncHypergraphSchemaType).pipe(
47
+ Schema.minItems(1),
48
+ Schema.filter(Utils.namesAreUnique, {
49
+ identifier: 'DuplicateTypeNames',
50
+ jsonSchema: {},
51
+ description: 'The type.name must be unique across all types in the schema',
52
+ }),
53
+ Schema.filter(Mapping.allRelationPropertyTypesExist, {
54
+ identifier: 'AllRelationTypesExist',
55
+ jsonSchema: {},
56
+ description: 'Each type property of dataType RELATION must have a type of the same name in the schema',
57
+ }),
58
+ ),
59
+ }) {}
60
+
61
+ /**
62
+ * Extending the hypergraph [Mapping definition](../../mapping/Mapping.ts) to make it an effect Schema instance.
63
+ * Allows decoding as well as passing in the api request payload
64
+ */
65
+ export const TypesyncHypergraphMapping = Schema.Record({
66
+ key: Schema.NonEmptyTrimmedString,
67
+ value: Schema.Struct({
68
+ typeIds: Schema.Array(Schema.UUID).pipe(Schema.minItems(1)),
69
+ properties: Schema.optional(
70
+ Schema.UndefinedOr(
71
+ Schema.Record({
72
+ key: Schema.NonEmptyTrimmedString,
73
+ value: Schema.UUID,
74
+ }),
75
+ ),
76
+ ),
77
+ relations: Schema.optional(
78
+ Schema.UndefinedOr(
79
+ Schema.Record({
80
+ key: Schema.NonEmptyTrimmedString,
81
+ value: Schema.UUID,
82
+ }),
83
+ ),
84
+ ),
85
+ }),
86
+ });
87
+ export type TypesyncHypergraphMapping = typeof TypesyncHypergraphMapping.Type;
@@ -1,21 +1,32 @@
1
- import { FileSystem, Path } from '@effect/platform';
1
+ import { FileSystem, KeyValueStore, Path } from '@effect/platform';
2
2
  import { NodeFileSystem } from '@effect/platform-node';
3
3
  import { AnsiDoc } from '@effect/printer-ansi';
4
4
  import { Cause, Data, Effect, Array as EffectArray, Option, Stream } from 'effect';
5
5
  import type { NonEmptyReadonlyArray } from 'effect/Array';
6
- import type { Schema as HypergraphSchema, Mapping } from '../../mapping/Mapping.js';
7
- import { parseHypergraphMapping, parseSchema } from './Utils.js';
6
+ import { type Mapping, propertyIsRelation } from '../../mapping/Mapping.js';
7
+ import { toCamelCase, toPascalCase } from '../../mapping/Utils.js';
8
+ import {
9
+ type TypesyncHypergraphMapping,
10
+ TypesyncHypergraphSchema,
11
+ TypesyncHypergraphSchemaType,
12
+ type TypesyncHypergraphSchemaTypeProperty,
13
+ } from './Model.js';
14
+ import { buildMappingFile, buildSchemaFile, parseHypergraphMapping, parseSchema } from './Utils.js';
8
15
 
9
16
  export class TypesyncSchemaStreamBuilder extends Effect.Service<TypesyncSchemaStreamBuilder>()(
10
17
  '/Hypergraph/cli/services/TypesyncSchemaStreamBuilder',
11
18
  {
12
- dependencies: [NodeFileSystem.layer],
19
+ dependencies: [NodeFileSystem.layer, KeyValueStore.layerMemory],
13
20
  effect: Effect.gen(function* () {
14
21
  const fs = yield* FileSystem.FileSystem;
15
22
  const path = yield* Path.Path;
23
+ const kv = yield* KeyValueStore.KeyValueStore;
16
24
 
17
25
  const encoder = new TextEncoder();
18
26
 
27
+ const SCHEMA_FILE_PATH_STORAGE_KEY = 'SCHEMA_FILE_PATH';
28
+ const MAPPING_FILE_PATH_STORAGE_KEY = 'MAPPING_FILE_PATH';
29
+
19
30
  const schemaCandidates = (cwd = '.') =>
20
31
  EffectArray.make(
21
32
  path.resolve(cwd, 'schema.ts'),
@@ -81,7 +92,7 @@ export class TypesyncSchemaStreamBuilder extends Effect.Service<TypesyncSchemaSt
81
92
  const currentSchemaStream = (
82
93
  schemaFilePath: Option.Option<string>,
83
94
  mappingFilePath: Option.Option<string>,
84
- ): Stream.Stream<HypergraphSchema, never, never> =>
95
+ ): Stream.Stream<TypesyncHypergraphSchema, never, never> =>
85
96
  Stream.fromEffect(
86
97
  Effect.gen(function* () {
87
98
  const schema = yield* Option.match(schemaFilePath, {
@@ -102,7 +113,7 @@ export class TypesyncSchemaStreamBuilder extends Effect.Service<TypesyncSchemaSt
102
113
  ),
103
114
  ),
104
115
  // if failure, don't bubble to return and just return empty schema
105
- Stream.orElseSucceed(() => ({ types: [] }) satisfies HypergraphSchema),
116
+ Stream.orElseSucceed(() => ({ types: [] }) satisfies TypesyncHypergraphSchema),
106
117
  );
107
118
  /**
108
119
  * Reads the schema.ts file, and maybe reads the mapping.ts file (if exists).
@@ -117,7 +128,7 @@ export class TypesyncSchemaStreamBuilder extends Effect.Service<TypesyncSchemaSt
117
128
  const watchSchemaStream = (
118
129
  schemaFilePath: Option.Option<string>,
119
130
  mappingFilePath: Option.Option<string>,
120
- ): Stream.Stream<HypergraphSchema, never, never> => {
131
+ ): Stream.Stream<TypesyncHypergraphSchema, never, never> => {
121
132
  const schemaWatch = Option.match(schemaFilePath, {
122
133
  // @todo watch the root here so if a schema is created, it will get picked up
123
134
  onNone: () => Stream.empty,
@@ -147,7 +158,7 @@ export class TypesyncSchemaStreamBuilder extends Effect.Service<TypesyncSchemaSt
147
158
  Effect.logError(AnsiDoc.text('Failure parsing schema changes into types'), { cause: Cause.pretty(cause) }),
148
159
  ),
149
160
  // if failure, don't bubble to return and just return empty schema
150
- Stream.orElseSucceed(() => ({ types: [] }) satisfies HypergraphSchema),
161
+ Stream.orElseSucceed(() => ({ types: [] }) satisfies TypesyncHypergraphSchema),
151
162
  );
152
163
  };
153
164
 
@@ -162,10 +173,17 @@ export class TypesyncSchemaStreamBuilder extends Effect.Service<TypesyncSchemaSt
162
173
  AnsiDoc.text('No Hypergraph schema file found. Searched:'),
163
174
  AnsiDoc.cats(schemaFileCandidates.map((candidate) => AnsiDoc.text(candidate))),
164
175
  );
176
+ } else if (Option.isSome(schemaFilePath)) {
177
+ // store schema file location in KeyValueStore for reference
178
+ yield* kv.set(SCHEMA_FILE_PATH_STORAGE_KEY, schemaFilePath.value);
165
179
  }
166
180
  // Fetch the Mapping definition from any mapping.ts in the directory.
167
181
  // If exists, use it to get the knowledgeGraphId for each type/property in the parsed schema
168
182
  const mappingFilePath = yield* findHypergraphSchema(mappingCandidates(cwd));
183
+ if (Option.isSome(mappingFilePath)) {
184
+ // store mapping file location in KeyValueStore for reference
185
+ yield* kv.set(MAPPING_FILE_PATH_STORAGE_KEY, mappingFilePath.value);
186
+ }
169
187
 
170
188
  return currentSchemaStream(schemaFilePath, mappingFilePath).pipe(
171
189
  Stream.concat(watchSchemaStream(schemaFilePath, mappingFilePath)),
@@ -177,7 +195,117 @@ export class TypesyncSchemaStreamBuilder extends Effect.Service<TypesyncSchemaSt
177
195
  );
178
196
  });
179
197
 
180
- return { hypergraphSchemaStream } as const;
198
+ /**
199
+ * Write the user-submitted Hypergraph schema to the schema.ts file in the users repo.
200
+ *
201
+ * @param schema the user-submitted Hypergraph schema from the Typesync UI
202
+ * @returns the updated Hypergraph schema
203
+ */
204
+ const syncSchema = (schema: TypesyncHypergraphSchema) =>
205
+ Effect.gen(function* () {
206
+ const cwd = process.cwd();
207
+
208
+ const schemaFilePath = yield* kv
209
+ .get(SCHEMA_FILE_PATH_STORAGE_KEY)
210
+ .pipe(Effect.map(Option.getOrElse(() => path.join(cwd, 'src', 'schema.ts'))));
211
+ // update schema file with updated content from the typesync studio UI
212
+ yield* fs.writeFileString(schemaFilePath, buildSchemaFile(schema));
213
+
214
+ return TypesyncHypergraphSchema.make({
215
+ types: EffectArray.map(schema.types, (type) =>
216
+ TypesyncHypergraphSchemaType.make({
217
+ name: type.name,
218
+ knowledgeGraphId: type.knowledgeGraphId,
219
+ status: type.knowledgeGraphId != null ? 'published' : 'synced',
220
+ properties: EffectArray.map(type.properties, (prop) => {
221
+ if (propertyIsRelation(prop)) {
222
+ return {
223
+ name: prop.name,
224
+ knowledgeGraphId: prop.knowledgeGraphId,
225
+ dataType: prop.dataType,
226
+ relationType: prop.relationType,
227
+ status: prop.knowledgeGraphId != null ? 'published' : 'synced',
228
+ } satisfies TypesyncHypergraphSchemaTypeProperty;
229
+ }
230
+
231
+ return {
232
+ name: prop.name,
233
+ knowledgeGraphId: prop.knowledgeGraphId,
234
+ dataType: prop.dataType,
235
+ status: prop.knowledgeGraphId != null ? 'published' : 'synced',
236
+ } satisfies TypesyncHypergraphSchemaTypeProperty;
237
+ }),
238
+ }),
239
+ ),
240
+ });
241
+ });
242
+
243
+ /**
244
+ * Update the mapping.ts file in the users repo with the up-to-date, published to the Knowledge Graph, mapping
245
+ *
246
+ * @param schema the Hypergraph schema
247
+ * @param mapping the up-to-date Hypergraph Mapping with all types/properties having Id
248
+ * @returns the updated schema with connected knowledgeGraphIds
249
+ */
250
+ const syncMapping = (schema: TypesyncHypergraphSchema, mapping: TypesyncHypergraphMapping) =>
251
+ Effect.gen(function* () {
252
+ const cwd = process.cwd();
253
+
254
+ const mappingFilePath = yield* kv
255
+ .get(MAPPING_FILE_PATH_STORAGE_KEY)
256
+ .pipe(Effect.map(Option.getOrElse(() => path.join(cwd, 'src', 'mapping.ts'))));
257
+ // update mapping file with updated content from the typesync studio UI
258
+ yield* fs.writeFileString(mappingFilePath, buildMappingFile(mapping));
259
+
260
+ // update Schema to update with generated GRC-20 Ids for types/properties
261
+ return TypesyncHypergraphSchema.make({
262
+ types: EffectArray.map(schema.types, (type) => {
263
+ const mappingEntry = mapping[toPascalCase(type.name)];
264
+
265
+ let knowledgeGraphId = type.knowledgeGraphId;
266
+ if (!knowledgeGraphId) {
267
+ const typeKnowledgeGraphId = mappingEntry?.typeIds?.[0] ? mappingEntry.typeIds[0] : null;
268
+ if (typeKnowledgeGraphId) {
269
+ knowledgeGraphId = typeKnowledgeGraphId;
270
+ }
271
+ }
272
+
273
+ return TypesyncHypergraphSchemaType.make({
274
+ name: type.name,
275
+ knowledgeGraphId,
276
+ status: knowledgeGraphId != null ? 'published' : 'synced',
277
+ properties: EffectArray.map(type.properties, (prop) => {
278
+ const propName = toCamelCase(prop.name);
279
+
280
+ if (propertyIsRelation(prop)) {
281
+ const relKnowledgeGraphId = prop.knowledgeGraphId || mappingEntry?.relations?.[propName] || null;
282
+ return {
283
+ name: prop.name,
284
+ knowledgeGraphId: relKnowledgeGraphId,
285
+ dataType: prop.dataType,
286
+ relationType: prop.relationType,
287
+ status: relKnowledgeGraphId != null ? 'published' : 'synced',
288
+ } satisfies TypesyncHypergraphSchemaTypeProperty;
289
+ }
290
+
291
+ const propKnowledgeGraphId = prop.knowledgeGraphId || mappingEntry?.properties?.[propName] || null;
292
+ return {
293
+ name: prop.name,
294
+ knowledgeGraphId: propKnowledgeGraphId,
295
+ dataType: prop.dataType,
296
+ status: propKnowledgeGraphId != null ? 'published' : 'synced',
297
+ } satisfies TypesyncHypergraphSchemaTypeProperty;
298
+ }),
299
+ });
300
+ }),
301
+ });
302
+ });
303
+
304
+ return {
305
+ hypergraphSchemaStream,
306
+ syncSchema,
307
+ syncMapping,
308
+ } as const;
181
309
  }),
182
310
  },
183
311
  ) {}