@ng-org/orm 0.1.2-alpha.1

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 (54) hide show
  1. package/README.md +347 -0
  2. package/dist/connector/applyPatches.d.ts +106 -0
  3. package/dist/connector/applyPatches.d.ts.map +1 -0
  4. package/dist/connector/applyPatches.js +317 -0
  5. package/dist/connector/applyPatches.test.d.ts +2 -0
  6. package/dist/connector/applyPatches.test.d.ts.map +1 -0
  7. package/dist/connector/applyPatches.test.js +772 -0
  8. package/dist/connector/createSignalObjectForShape.d.ts +14 -0
  9. package/dist/connector/createSignalObjectForShape.d.ts.map +1 -0
  10. package/dist/connector/createSignalObjectForShape.js +24 -0
  11. package/dist/connector/initNg.d.ts +14 -0
  12. package/dist/connector/initNg.d.ts.map +1 -0
  13. package/dist/connector/initNg.js +16 -0
  14. package/dist/connector/ormConnectionHandler.d.ts +47 -0
  15. package/dist/connector/ormConnectionHandler.d.ts.map +1 -0
  16. package/dist/connector/ormConnectionHandler.js +240 -0
  17. package/dist/frontendAdapters/react/index.d.ts +3 -0
  18. package/dist/frontendAdapters/react/index.d.ts.map +1 -0
  19. package/dist/frontendAdapters/react/index.js +2 -0
  20. package/dist/frontendAdapters/react/useShape.d.ts +6 -0
  21. package/dist/frontendAdapters/react/useShape.d.ts.map +1 -0
  22. package/dist/frontendAdapters/react/useShape.js +24 -0
  23. package/dist/frontendAdapters/svelte/index.d.ts +3 -0
  24. package/dist/frontendAdapters/svelte/index.d.ts.map +1 -0
  25. package/dist/frontendAdapters/svelte/index.js +2 -0
  26. package/dist/frontendAdapters/svelte/useShape.svelte.d.ts +14 -0
  27. package/dist/frontendAdapters/svelte/useShape.svelte.d.ts.map +1 -0
  28. package/dist/frontendAdapters/svelte/useShape.svelte.js +22 -0
  29. package/dist/frontendAdapters/vue/index.d.ts +3 -0
  30. package/dist/frontendAdapters/vue/index.d.ts.map +1 -0
  31. package/dist/frontendAdapters/vue/index.js +2 -0
  32. package/dist/frontendAdapters/vue/useShape.d.ts +5 -0
  33. package/dist/frontendAdapters/vue/useShape.d.ts.map +1 -0
  34. package/dist/frontendAdapters/vue/useShape.js +22 -0
  35. package/dist/index.d.ts +8 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +7 -0
  38. package/dist/types.d.ts +13 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +10 -0
  41. package/package.json +90 -0
  42. package/src/connector/applyPatches.test.ts +842 -0
  43. package/src/connector/applyPatches.ts +404 -0
  44. package/src/connector/createSignalObjectForShape.ts +35 -0
  45. package/src/connector/initNg.ts +30 -0
  46. package/src/connector/ormConnectionHandler.ts +300 -0
  47. package/src/frontendAdapters/react/index.ts +2 -0
  48. package/src/frontendAdapters/react/useShape.ts +36 -0
  49. package/src/frontendAdapters/svelte/index.ts +2 -0
  50. package/src/frontendAdapters/svelte/useShape.svelte.ts +46 -0
  51. package/src/frontendAdapters/vue/index.ts +2 -0
  52. package/src/frontendAdapters/vue/useShape.ts +33 -0
  53. package/src/index.ts +14 -0
  54. package/src/types.ts +26 -0
package/README.md ADDED
@@ -0,0 +1,347 @@
1
+ # @ng-org/orm
2
+
3
+ Reactive ORM library for NextGraph — use typed, reactive objects that automatically sync to NextGraph's encrypted, local-first storage.
4
+
5
+ For a walk-through, you can see the the [expense-tracker example app](https://git.nextgraph.org/NextGraph/expense-tracker) which shows
6
+ - React, Vue, and Svelte frontends sharing data
7
+ - SHEX schema definitions
8
+ - CRUD operations
9
+ - Cross-framework real-time sync
10
+
11
+ ## Table of Contents
12
+
13
+ - [@ng-org/orm](#ng-orgorm)
14
+ - [Table of Contents](#table-of-contents)
15
+ - [Installation](#installation)
16
+ - [Quick Start](#quick-start)
17
+ - [Defining Schemas](#defining-schemas)
18
+ - [Framework Usage](#framework-usage)
19
+ - [React](#react)
20
+ - [Vue](#vue)
21
+ - [Svelte](#svelte)
22
+ - [Working with Data](#working-with-data)
23
+ - [Adding Objects](#adding-objects)
24
+ - [Modifying Objects](#modifying-objects)
25
+ - [Deleting Objects](#deleting-objects)
26
+ - [Working with Sets](#working-with-sets)
27
+ - [Relationships](#relationships)
28
+ - [API Reference](#api-reference)
29
+ - [`useShape(shapeType)`](#useshapeshapetype)
30
+ - [Shared State](#shared-state)
31
+ - [License](#license)
32
+
33
+ ---
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pnpm add @ng-org/orm @ng-org/web @ng-org/alien-deepsignals
39
+ ```
40
+
41
+ For schema code generation, also install:
42
+
43
+ ```bash
44
+ pnpm add -D @ng-org/shex-orm
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Quick Start
50
+
51
+ Before using the ORM, initialize NextGraph in your app entry point:
52
+
53
+ ```typescript
54
+ import { ng, init } from "@ng-org/web";
55
+ import { initNg } from "@ng-org/orm";
56
+
57
+ await init(
58
+ async (event) => {
59
+ initNg(ng, event.session);
60
+ },
61
+ true,
62
+ []
63
+ );
64
+ ```
65
+
66
+ Then use `useShape()` in your components:
67
+
68
+ ```typescript
69
+ import { useShape } from "@ng-org/orm/react"; // or /vue, /svelte
70
+ import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
71
+
72
+ const dogs = useShape(DogShapeType);
73
+
74
+ // Iterate, modify, add — changes auto-sync everywhere
75
+ for (const dog of dogs) {
76
+ console.log(dog.name);
77
+ }
78
+ ```
79
+
80
+ ---
81
+
82
+ ## Defining Schemas
83
+
84
+ Define your data model using [SHEX (Shape Expressions)](https://shex.io/):
85
+
86
+ **`shapes/shex/dogShape.shex`**:
87
+ ```shex
88
+ PREFIX ex: <http://example.org/>
89
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
90
+
91
+ ex:Dog {
92
+ a [ex:Dog] ;
93
+ ex:name xsd:string ;
94
+ ex:age xsd:integer ? ;
95
+ ex:toys xsd:string * ;
96
+ }
97
+ ```
98
+
99
+ Generate TypeScript types. Add the following to your `package.json` scripts and run `build:orm`:
100
+
101
+ ```json
102
+ "build:orm": "rdf-orm build --input ./src/shapes/shex --output ./src/shapes/orm"
103
+ ```
104
+
105
+ This creates:
106
+ - `dogShape.typings.ts` — TypeScript interfaces
107
+ - `dogShape.shapeTypes.ts` — Shape type objects for `useShape()`
108
+ - `dogShape.schema.ts` — Internal schema metadata
109
+
110
+ See [@ng-org/shex-orm](../shex-orm/README.md) for full documentation.
111
+
112
+ ---
113
+
114
+ ## Framework Usage
115
+
116
+ ### React
117
+
118
+ ```tsx
119
+ import { useShape } from "@ng-org/orm/react";
120
+ import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
121
+ import type { Dog } from "./shapes/orm/dogShape.typings";
122
+
123
+ export function DogList() {
124
+ const dogs = useShape(DogShapeType); // DeepSignalSet<Dog>
125
+
126
+ return (
127
+ <ul>
128
+ {[...dogs].map(dog => (
129
+ <li key={dog["@id"]}>
130
+ {/* Direct mutation triggers re-render */}
131
+ <input
132
+ value={dog.name}
133
+ onChange={e => dog.name = e.target.value}
134
+ />
135
+ </li>
136
+ ))}
137
+ </ul>
138
+ );
139
+ }
140
+ ```
141
+
142
+ > **Note**: No `setState` needed — just mutate the object directly.
143
+
144
+ ### Vue
145
+
146
+ **Parent component** (`DogList.vue`):
147
+ ```vue
148
+ <script setup lang="ts">
149
+ import { useShape } from "@ng-org/orm/vue";
150
+ import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
151
+ import DogCard from "./DogCard.vue";
152
+
153
+ const dogs = useShape(DogShapeType); // DeepSignalSet<Dog>
154
+ </script>
155
+
156
+ <template>
157
+ <DogCard
158
+ v-for="dog in dogs"
159
+ :key="dog['@id']"
160
+ :dog="dog"
161
+ />
162
+ </template>
163
+ ```
164
+
165
+ **Child component** (`DogCard.vue`):
166
+ ```vue
167
+ <script setup lang="ts">
168
+ import { useDeepSignal } from "@ng-org/alien-deepsignals/vue";
169
+ import type { Dog } from "./shapes/orm/dogShape.typings";
170
+
171
+ const props = defineProps<{ dog: Dog }>();
172
+
173
+ // Required for reactivity in child components!
174
+ const dog = useDeepSignal(props.dog);
175
+ </script>
176
+
177
+ <template>
178
+ <div>
179
+ <input v-model="dog.name" />
180
+ </div>
181
+ </template>
182
+ ```
183
+
184
+ > **Important**: In Vue child components, wrap props with `useDeepSignal()` to enable reactivity.
185
+
186
+ ### Svelte
187
+
188
+ ```svelte
189
+ <script lang="ts">
190
+ import { useShape } from "@ng-org/orm/svelte";
191
+ import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
192
+
193
+ const dogs = useShape(DogShapeType); // Reactive store
194
+ </script>
195
+
196
+ <ul>
197
+ {#each [...$dogs] as dog (dog['@id'])}
198
+ <li>
199
+ <input bind:value={dog.name} />
200
+ </li>
201
+ {/each}
202
+ </ul>
203
+ ```
204
+
205
+ > **Note**: Access the store value with `$dogs`. Standard Svelte binding works.
206
+
207
+ ---
208
+
209
+ ## Working with Data
210
+
211
+ ### Adding Objects
212
+
213
+ To add a new object, you need a document IRI (`@graph`). Create a document first:
214
+
215
+ ```typescript
216
+ import { sessionPromise } from "./utils/ngSession";
217
+
218
+ const session = await sessionPromise;
219
+
220
+ // Create a new NextGraph document
221
+ const docIri = await session.ng.doc_create(
222
+ session.session_id,
223
+ "Graph",
224
+ "data:graph",
225
+ "store",
226
+ undefined
227
+ );
228
+
229
+ // Add to the reactive set
230
+ dogs.add({
231
+ "@graph": docIri, // Required: document IRI
232
+ "@type": "http://example.org/Dog", // Required: RDF type
233
+ "@id": "", // Empty = auto-generate subject IRI
234
+ name: "Buddy",
235
+ age: 3,
236
+ toys: new Set(["ball", "rope"]),
237
+ });
238
+ ```
239
+
240
+ > **Note**: For nested sub-objects, `@graph` is optional — the parent's graph IRI is used.
241
+ >
242
+ > **Note**: If you want to use the ORM signal object in a non-component context, you can use `createSignalObjectForShape` function as well.
243
+
244
+ ### Modifying Objects
245
+
246
+ Simply assign new values:
247
+
248
+ ```typescript
249
+ dog.name = "Max";
250
+ dog.age = 4;
251
+ ```
252
+
253
+ Changes are:
254
+ - Immediately reflected in all components using the same shape
255
+ - Automatically persisted to NextGraph storage
256
+ - Synced to other devices in real-time
257
+
258
+ ### Deleting Objects
259
+
260
+ ```typescript
261
+ dogs.delete(dog);
262
+ ```
263
+
264
+ ### Working with Sets
265
+
266
+ Properties with SHEX cardinality `*` or `+` become reactive Sets:
267
+
268
+ ```typescript
269
+ // Add items
270
+ dog.toys.add("frisbee");
271
+
272
+ // Remove items
273
+ dog.toys.delete("ball");
274
+
275
+ // Check membership
276
+ if (dog.toys.has("rope")) { ... }
277
+
278
+ // Iterate
279
+ for (const toy of dog.toys) {
280
+ console.log(toy);
281
+ }
282
+
283
+ // Get size
284
+ console.log(dog.toys.size);
285
+
286
+ // NOTE: For ES2025 environment, set iterator objects are directly attached:
287
+ dogs.forEach((dog) => {
288
+ console.log(dog.toys.size);
289
+ });
290
+ ```
291
+
292
+ ### Relationships
293
+
294
+ Link objects by storing the target's `@id` IRI:
295
+
296
+ ```typescript
297
+ // In your SHEX schema:
298
+ // ex:owner IRI ;
299
+
300
+ // Link to another object
301
+ dog.owner = person["@id"];
302
+
303
+ // Resolve the relationship
304
+ const owner = people.find(p => p["@id"] === dog.owner);
305
+ ```
306
+
307
+ ---
308
+
309
+ ## API Reference
310
+
311
+ ### `useShape(shapeType)`
312
+
313
+ Returns a `DeepSignalSet<T>` containing all objects of the given shape type.
314
+
315
+ ```typescript
316
+ const dogs = useShape(DogShapeType);
317
+ ```
318
+
319
+ **DeepSignalSet methods:**
320
+ - `add(obj)` — Add a new object
321
+ - `delete(obj)` — Remove an object
322
+ - `has(obj)` — Check if object exists
323
+ - `size` — Number of objects
324
+ - `getBy(graphIri, subjectIri)` — Find object by IRIs
325
+ - `[Symbol.iterator]` — Iterate with `for...of` or spread `[...set]`
326
+ - ... and all symbol iterator helper methods (like `.map`, `.find`, ...), if you are in an ES2025+ environment.
327
+
328
+ ### Shared State
329
+
330
+ When `useShape()` is called with the same shape type and scope in multiple components, they share the exact same reactive data. Changes in one component instantly appear in all others.
331
+
332
+ ---
333
+
334
+ ## License
335
+
336
+ Licensed under either of
337
+
338
+ - Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
339
+ - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
340
+
341
+ at your option.
342
+
343
+ `SPDX-License-Identifier: Apache-2.0 OR MIT`
344
+
345
+ ---
346
+
347
+ NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme.
@@ -0,0 +1,106 @@
1
+ export type Patch = {
2
+ /** Property path (array indices, object keys, synthetic Set entry ids) from the root to the mutated location. */
3
+ path: string;
4
+ valType?: string & {};
5
+ value?: unknown;
6
+ } & (SetAddPatch | SetRemovePatch | ObjectAddPatch | RemovePatch | LiteralAddPatch);
7
+ export interface SetAddPatch {
8
+ /** Mutation kind applied at the resolved `path`. */
9
+ op: "add";
10
+ valType: "set";
11
+ /**
12
+ * New value for set mutations:
13
+ * - A single primitive
14
+ * - An array of primitives
15
+ */
16
+ value: number | string | boolean | (number | string | boolean)[];
17
+ }
18
+ export interface SetRemovePatch {
19
+ /** Mutation kind applied at the resolved `path`. */
20
+ op: "remove";
21
+ valType: "set";
22
+ /**
23
+ * The value(s) to be removed from the set. Either:
24
+ * - A single primitive
25
+ * - An array of primitives
26
+ */
27
+ value: number | string | boolean | (number | string | boolean)[];
28
+ }
29
+ export interface ObjectAddPatch {
30
+ /** Mutation kind applied at the resolved `path`. */
31
+ op: "add";
32
+ valType: "object";
33
+ }
34
+ export interface RemovePatch {
35
+ /** Mutation kind applied at the resolved `path`. */
36
+ op: "remove";
37
+ }
38
+ export interface LiteralAddPatch {
39
+ /** Mutation kind applied at the resolved `path`. */
40
+ op: "add";
41
+ /** The literal value to be added at the resolved `path` */
42
+ value: string | number | boolean;
43
+ }
44
+ /**
45
+ * Apply a diff to an object.
46
+ *
47
+ * The syntax is inspired by RFC 6902 but it is not compatible.
48
+ *
49
+ * It supports Sets for multi-valued properties:
50
+ * - Primitive values are added as Sets (Set<string | number | boolean>)
51
+ * - Multi-valued objects are stored in Sets, accessed by their @id property
52
+ * - Single objects are plain objects with an @id property
53
+ *
54
+ * Path traversal:
55
+ * - When traversing through a Set, the path segment is treated as an @id to find the object
56
+ * - When traversing through a plain object, the path segment is a property name
57
+ *
58
+ * @example operations
59
+ * ```jsonc
60
+ * // === SINGLE OBJECT ===
61
+ * // Creating a single object (has @id at same level)
62
+ * { "op": "add", "path": "/urn:example:person1/address", "valType": "object" }
63
+ * { "op": "add", "path": "/urn:example:person1/address/@id", "value": "urn:test:address1" }
64
+ * // Adding primitives to single object
65
+ * { "op": "add", "path": "/urn:example:person1/address/street", "value": "1st street" }
66
+ * { "op": "add", "path": "/urn:example:person1/address/country", "value": "Greece" }
67
+ * // Remove a primitive from object
68
+ * { "op": "remove", "path": "/urn:example:person1/address/street" }
69
+ * // Remove the entire object
70
+ * { "op": "remove", "path": "/urn:example:person1/address" }
71
+ *
72
+ * // === MULTI-VALUED OBJECTS (Set) ===
73
+ * // Creating a multi-object container (NO @id at this level -> creates Set)
74
+ * { "op": "add", "path": "/urn:example:person1/children", "valType": "object" }
75
+ * // Adding an object to the Set (path includes object's @id)
76
+ * { "op": "add", "path": "/urn:example:person1/children/urn:example:child1", "valType": "object" }
77
+ * { "op": "add", "path": "/urn:example:person1/children/urn:example:child1/@id", "value": "urn:example:child1" }
78
+ * // Adding properties to object in Set
79
+ * { "op": "add", "path": "/urn:example:person1/children/urn:example:child1/name", "value": "Alice" }
80
+ * // Remove an object from Set
81
+ * { "op": "remove", "path": "/urn:example:person1/children/urn:example:child1" }
82
+ * // Remove all objects (the Set itself)
83
+ * { "op": "remove", "path": "/urn:example:person1/children" }
84
+ *
85
+ * // === PRIMITIVE SETS ===
86
+ * // Add primitive types to Sets
87
+ * { "op": "add", "valType": "set", "path": "/urn:example:person1/tags", "value": [1,2,3] }
88
+ * // Remove primitive types from a Set
89
+ * { "op": "remove", "valType": "set", "path": "/urn:example:person1/tags", "value": [1,2] }
90
+ * ```
91
+ *
92
+ * @param currentState The object before the patch
93
+ * @param patches An array of patches to apply to the object.
94
+ * @param ensurePathExists If true, create nested objects along the path if the path does not exist.
95
+ *
96
+ * @note When creating new objects, this function pre-scans upcoming patches to find @id and @graph
97
+ * values that will be assigned to the object. This prevents the signal library's propGenerator
98
+ * from being triggered before these identity fields are set, which would cause it to generate
99
+ * random IDs unnecessarily.
100
+ */
101
+ export declare function applyPatches(currentState: Record<string, any>, patches: Patch[], ensurePathExists?: boolean): void;
102
+ /**
103
+ * See documentation for applyDiff
104
+ */
105
+ export declare function applyPatchesToDeepSignal(currentState: object, patch: Patch[]): void;
106
+ //# sourceMappingURL=applyPatches.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatches.d.ts","sourceRoot":"","sources":["../../src/connector/applyPatches.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,KAAK,GAAG;IAChB,iHAAiH;IACjH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,CACE,WAAW,GACX,cAAc,GACd,cAAc,GACd,WAAW,GACX,eAAe,CACpB,CAAC;AAEF,MAAM,WAAW,WAAW;IACxB,oDAAoD;IACpD,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,KAAK,CAAC;IACf;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;CACpE;AAED,MAAM,WAAW,cAAc;IAC3B,oDAAoD;IACpD,EAAE,EAAE,QAAQ,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;IACf;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;CACpE;AAED,MAAM,WAAW,cAAc;IAC3B,oDAAoD;IACpD,EAAE,EAAE,KAAK,CAAC;IACV,OAAO,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IACxB,oDAAoD;IACpD,EAAE,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC5B,oDAAoD;IACpD,EAAE,EAAE,KAAK,CAAC;IACV,2DAA2D;IAC3D,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CACpC;AAyCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,YAAY,CACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,OAAO,EAAE,KAAK,EAAE,EAChB,gBAAgB,GAAE,OAAe,QAgOpC;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAI5E"}