@ng-org/orm 0.1.2-alpha.7 → 0.1.2-alpha.9

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 (53) hide show
  1. package/README.md +74 -92
  2. package/dist/connector/applyPatches.d.ts +13 -4
  3. package/dist/connector/applyPatches.d.ts.map +1 -1
  4. package/dist/connector/applyPatches.js +9 -5
  5. package/dist/connector/discrete/discreteOrmSubscriptionHandler.d.ts +156 -0
  6. package/dist/connector/discrete/discreteOrmSubscriptionHandler.d.ts.map +1 -0
  7. package/dist/connector/discrete/{discreteOrmConnectionHandler.js → discreteOrmSubscriptionHandler.js} +130 -19
  8. package/dist/connector/getObjects.js +2 -2
  9. package/dist/connector/initNg.d.ts +35 -0
  10. package/dist/connector/initNg.d.ts.map +1 -1
  11. package/dist/connector/initNg.js +35 -0
  12. package/dist/connector/insertObject.js +2 -2
  13. package/dist/connector/ormSubscriptionHandler.d.ts +166 -0
  14. package/dist/connector/ormSubscriptionHandler.d.ts.map +1 -0
  15. package/dist/connector/{ormConnectionHandler.js → ormSubscriptionHandler.js} +157 -32
  16. package/dist/frontendAdapters/react/useDiscrete.d.ts +89 -69
  17. package/dist/frontendAdapters/react/useDiscrete.d.ts.map +1 -1
  18. package/dist/frontendAdapters/react/useDiscrete.js +103 -81
  19. package/dist/frontendAdapters/react/useShape.d.ts +55 -55
  20. package/dist/frontendAdapters/react/useShape.d.ts.map +1 -1
  21. package/dist/frontendAdapters/react/useShape.js +71 -73
  22. package/dist/frontendAdapters/svelte/useDiscrete.svelte.d.ts +80 -71
  23. package/dist/frontendAdapters/svelte/useDiscrete.svelte.d.ts.map +1 -1
  24. package/dist/frontendAdapters/svelte/useDiscrete.svelte.js +102 -91
  25. package/dist/frontendAdapters/svelte/useShape.svelte.d.ts +70 -64
  26. package/dist/frontendAdapters/svelte/useShape.svelte.d.ts.map +1 -1
  27. package/dist/frontendAdapters/svelte/useShape.svelte.js +73 -62
  28. package/dist/frontendAdapters/svelte4/index.d.ts +5 -0
  29. package/dist/frontendAdapters/svelte4/index.d.ts.map +1 -0
  30. package/dist/frontendAdapters/svelte4/index.js +12 -0
  31. package/dist/frontendAdapters/svelte4/useDiscrete.svelte.d.ts +85 -0
  32. package/dist/frontendAdapters/svelte4/useDiscrete.svelte.d.ts.map +1 -0
  33. package/dist/frontendAdapters/svelte4/useDiscrete.svelte.js +124 -0
  34. package/dist/frontendAdapters/svelte4/useShape.svelte.d.ts +76 -0
  35. package/dist/frontendAdapters/svelte4/useShape.svelte.d.ts.map +1 -0
  36. package/dist/frontendAdapters/svelte4/useShape.svelte.js +84 -0
  37. package/dist/frontendAdapters/vue/useDiscrete.d.ts +87 -80
  38. package/dist/frontendAdapters/vue/useDiscrete.d.ts.map +1 -1
  39. package/dist/frontendAdapters/vue/useDiscrete.js +96 -84
  40. package/dist/frontendAdapters/vue/useShape.d.ts +57 -63
  41. package/dist/frontendAdapters/vue/useShape.d.ts.map +1 -1
  42. package/dist/frontendAdapters/vue/useShape.js +59 -64
  43. package/dist/index.d.ts +6 -3
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +14 -3
  46. package/dist/types.d.ts +17 -7
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js +11 -2
  49. package/package.json +7 -3
  50. package/dist/connector/discrete/discreteOrmConnectionHandler.d.ts +0 -45
  51. package/dist/connector/discrete/discreteOrmConnectionHandler.d.ts.map +0 -1
  52. package/dist/connector/ormConnectionHandler.d.ts +0 -48
  53. package/dist/connector/ormConnectionHandler.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,34 +1,41 @@
1
- # @ng-org/orm
1
+ # NextGraph ORM SDK
2
2
 
3
- Reactive ORM library for NextGraph use typed, reactive objects that automatically sync to NextGraph's encrypted, local-first storage.
3
+ Reactive ORM library for NextGraph: use reactive (typed) objects that automatically sync to NextGraph's encrypted, local-first storage.
4
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
5
+ For a walk-through you can see the the expense-tracker example apps for [discrete JSON documents](https://git.nextgraph.org/NextGraph/expense-tracker-discrete) or [typed graph documents](https://git.nextgraph.org/NextGraph/expense-tracker-graph).
6
+
7
+ ## Why?
8
+
9
+ Different CRDTs have different APIs. We want to make it as easy as possible to use them in the same way:\
10
+ **You modify a plain old TypeScript object and that updates the CRDT.**\
11
+ Vice versa, the CRDT is modified and that is reflected in your TS object.\
12
+ We offer this for **React, Vue, and Svelte**.
13
+
14
+ Note that we support discrete (**JSON**) CRDT and graph (**RDF**) CRDT ORMs.
15
+
16
+ - For graphs, you specify a schema using a SHEX shape and optionally a scope. This provides you with typing support.
17
+ - For discrete CRDTs, all you need is a document id.
10
18
 
11
19
  ## Table of Contents
12
20
 
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)
21
+ - [NextGraph ORM SDK](#nextgraph-orm-sdk)
22
+ - [Why?](#why)
23
+ - [Table of Contents](#table-of-contents)
24
+ - [Installation](#installation)
25
+ - [Start](#start)
26
+ - [Graph ORM: Defining Schemas](#graph-orm-defining-schemas)
27
+ - [Framework Usage](#framework-usage)
28
+ - [React](#react)
29
+ - [Vue](#vue)
30
+ - [Svelte](#svelte)
31
+ - [Working with Data](#working-with-data)
32
+ - [Adding Objects](#adding-objects)
33
+ - [Modifying Objects](#modifying-objects)
34
+ - [Deleting Objects](#deleting-objects)
35
+ - [Working with Sets](#working-with-sets)
36
+ - [Relationships](#relationships)
37
+ - [About NextGraph](#about-nextgraph)
38
+ - [License](#license)
32
39
 
33
40
  ---
34
41
 
@@ -38,7 +45,7 @@ For a walk-through, you can see the the [expense-tracker example app](https://gi
38
45
  pnpm add @ng-org/orm @ng-org/web @ng-org/alien-deepsignals
39
46
  ```
40
47
 
41
- For schema code generation, also install:
48
+ For schema generation, also install:
42
49
 
43
50
  ```bash
44
51
  pnpm add -D @ng-org/shex-orm
@@ -46,7 +53,9 @@ pnpm add -D @ng-org/shex-orm
46
53
 
47
54
  ---
48
55
 
49
- ## Quick Start
56
+ ## Start
57
+
58
+ You are strongly advised to look at the example apps for [discrete JSON documents](https://git.nextgraph.org/NextGraph/expense-tracker-discrete) and [typed graph documents](https://git.nextgraph.org/NextGraph/expense-tracker-graph).
50
59
 
51
60
  Before using the ORM, initialize NextGraph in your app entry point:
52
61
 
@@ -56,6 +65,7 @@ import { initNg } from "@ng-org/orm";
56
65
 
57
66
  await init(
58
67
  async (event) => {
68
+ // The ORM needs to have access to ng, the interface to the engine running in WASM.
59
69
  initNg(ng, event.session);
60
70
  },
61
71
  true,
@@ -63,27 +73,24 @@ await init(
63
73
  );
64
74
  ```
65
75
 
66
- Then use `useShape()` in your components:
76
+ Then use `useShape()` for graph, or `useDiscrete()` for discrete documents.
67
77
 
68
- ```typescript
69
- import { useShape } from "@ng-org/orm/react"; // or /vue, /svelte
70
- import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
78
+ In some cases, you may want to use advanced features managing subscriptions with the engine.
79
+ For that, you can directly use:
71
80
 
72
- const dogs = useShape(DogShapeType);
81
+ - `OrmSubscription.getOrCreate(ShapeType, scope)` for graphs
82
+ - `DiscreteOrmSubscription.getOrCreate(documentId)` for discrete documents
73
83
 
74
- // Iterate, modify, add changes auto-sync everywhere
75
- for (const dog of dogs) {
76
- console.log(dog.name);
77
- }
78
- ```
84
+ Internally, the OrmSubscription keeps a signalObject, a proxied, reactive object. When modifications are made, this makes the frontend components rerender and sends the update to the engine to be persisted.
85
+ In all cases, you have to create a document first with `ng.doc_create()`. For more details, you can consult the example apps and the inline jsdoc documentation.
79
86
 
80
- ---
81
-
82
- ## Defining Schemas
87
+ ## Graph ORM: Defining Schemas
83
88
 
84
89
  Define your data model using [SHEX (Shape Expressions)](https://shex.io/):
90
+ See [@ng-org/shex-orm](../shex-orm/README.md) for details.
85
91
 
86
92
  **`shapes/shex/dogShape.shex`**:
93
+
87
94
  ```shex
88
95
  PREFIX ex: <http://example.org/>
89
96
  PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
@@ -102,15 +109,6 @@ Generate TypeScript types. Add the following to your `package.json` scripts and
102
109
  "build:orm": "rdf-orm build --input ./src/shapes/shex --output ./src/shapes/orm"
103
110
  ```
104
111
 
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
112
  ## Framework Usage
115
113
 
116
114
  ### React
@@ -121,16 +119,16 @@ import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
121
119
  import type { Dog } from "./shapes/orm/dogShape.typings";
122
120
 
123
121
  export function DogList() {
124
- const dogs = useShape(DogShapeType); // DeepSignalSet<Dog>
122
+ const dogs = useShape(DogShapeType); // DeepSignalSet<Dog>
125
123
 
126
124
  return (
127
125
  <ul>
128
- {[...dogs].map(dog => (
126
+ {[...dogs].map((dog) => (
129
127
  <li key={dog["@id"]}>
130
128
  {/* Direct mutation triggers re-render */}
131
129
  <input
132
130
  value={dog.name}
133
- onChange={e => dog.name = e.target.value}
131
+ onChange={(e) => (dog.name = e.target.value)}
134
132
  />
135
133
  </li>
136
134
  ))}
@@ -144,25 +142,23 @@ export function DogList() {
144
142
  ### Vue
145
143
 
146
144
  **Parent component** (`DogList.vue`):
145
+
147
146
  ```vue
148
147
  <script setup lang="ts">
149
148
  import { useShape } from "@ng-org/orm/vue";
150
149
  import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
151
150
  import DogCard from "./DogCard.vue";
152
151
 
153
- const dogs = useShape(DogShapeType); // DeepSignalSet<Dog>
152
+ const dogs = useShape(DogShapeType); // DeepSignalSet<Dog>
154
153
  </script>
155
154
 
156
155
  <template>
157
- <DogCard
158
- v-for="dog in dogs"
159
- :key="dog['@id']"
160
- :dog="dog"
161
- />
156
+ <DogCard v-for="dog in dogs" :key="dog['@id']" :dog="dog" />
162
157
  </template>
163
158
  ```
164
159
 
165
160
  **Child component** (`DogCard.vue`):
161
+
166
162
  ```vue
167
163
  <script setup lang="ts">
168
164
  import { useDeepSignal } from "@ng-org/alien-deepsignals/vue";
@@ -187,14 +183,14 @@ const dog = useDeepSignal(props.dog);
187
183
 
188
184
  ```svelte
189
185
  <script lang="ts">
190
- import { useShape } from "@ng-org/orm/svelte";
191
- import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
186
+ import { useShape } from "@ng-org/orm/svelte";
187
+ import { DogShapeType } from "./shapes/orm/dogShape.shapeTypes";
192
188
 
193
- const dogs = useShape(DogShapeType); // Reactive store
189
+ const dogs = useShape(DogShapeType); // Reactive store
194
190
  </script>
195
191
 
196
192
  <ul>
197
- {#each [...$dogs] as dog (dog['@id'])}
193
+ {#each [...$dogs] as dog (dog["@id"])}
198
194
  <li>
199
195
  <input bind:value={dog.name} />
200
196
  </li>
@@ -228,9 +224,9 @@ const docIri = await session.ng.doc_create(
228
224
 
229
225
  // Add to the reactive set
230
226
  dogs.add({
231
- "@graph": docIri, // Required: document IRI
232
- "@type": "http://example.org/Dog", // Required: RDF type
233
- "@id": "", // Empty = auto-generate subject IRI
227
+ "@graph": docIri, // Required: document IRI
228
+ "@type": "http://example.org/Dog", // Required: RDF type
229
+ "@id": "", // Empty = auto-generate subject IRI
234
230
  name: "Buddy",
235
231
  age: 3,
236
232
  toys: new Set(["ball", "rope"]),
@@ -239,7 +235,7 @@ dogs.add({
239
235
 
240
236
  > **Note**: For nested sub-objects, `@graph` is optional — the parent's graph IRI is used.
241
237
  >
242
- > **Note**: If you want to use the ORM signal object in a non-component context, you can create an ORM connection manually using `OrmConnection.getOrCreate()`.
238
+ > **Note**: If you want to use the ORM signal object in a non-component context, you can create an ORM connection manually using `OrmSubscription.getOrCreate()`.
243
239
 
244
240
  ### Modifying Objects
245
241
 
@@ -251,6 +247,7 @@ dog.age = 4;
251
247
  ```
252
248
 
253
249
  Changes are:
250
+
254
251
  - Immediately reflected in all components using the same shape
255
252
  - Automatically persisted to NextGraph storage
256
253
  - Synced to other devices in real-time
@@ -301,35 +298,20 @@ Link objects by storing the target's `@id` IRI:
301
298
  dog.owner = person["@id"];
302
299
 
303
300
  // Resolve the relationship
304
- const owner = people.find(p => p["@id"] === dog.owner);
301
+ const owner = people.find((p) => p["@id"] === dog.owner);
305
302
  ```
306
303
 
307
304
  ---
308
305
 
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
306
+ ## About NextGraph
329
307
 
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
- ---
308
+ > **NextGraph** brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs.
309
+ >
310
+ > This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy.
311
+ >
312
+ > Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers.
313
+ >
314
+ > More info: [https://nextgraph.org](https://nextgraph.org)
333
315
 
334
316
  ## License
335
317
 
@@ -337,7 +319,7 @@ Licensed under either of
337
319
 
338
320
  - Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0)
339
321
  - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
340
-
322
+
341
323
  at your option.
342
324
 
343
325
  `SPDX-License-Identifier: Apache-2.0 OR MIT`
@@ -1,9 +1,11 @@
1
+ /** @internal */
1
2
  export type Patch = {
2
3
  /** Property path (array indices, object keys, synthetic Set entry ids) from the root to the mutated location. */
3
4
  path: string;
4
5
  valType?: string & {};
5
6
  value?: unknown;
6
7
  } & (SetAddPatch | SetRemovePatch | RemovePatch | LiteralAddPatch);
8
+ /** @internal */
7
9
  export interface SetAddPatch {
8
10
  /** Mutation kind applied at the resolved `path`. */
9
11
  op: "add";
@@ -15,6 +17,7 @@ export interface SetAddPatch {
15
17
  */
16
18
  value: number | string | boolean | (number | string | boolean)[];
17
19
  }
20
+ /** @internal */
18
21
  export interface SetRemovePatch {
19
22
  /** Mutation kind applied at the resolved `path`. */
20
23
  op: "remove";
@@ -26,10 +29,12 @@ export interface SetRemovePatch {
26
29
  */
27
30
  value: number | string | boolean | object | (number | string | boolean | object)[];
28
31
  }
32
+ /** @internal */
29
33
  export interface RemovePatch {
30
34
  /** Mutation kind applied at the resolved `path`. */
31
35
  op: "remove";
32
36
  }
37
+ /** @internal */
33
38
  export interface LiteralAddPatch {
34
39
  /** Mutation kind applied at the resolved `path`. */
35
40
  op: "add";
@@ -37,17 +42,19 @@ export interface LiteralAddPatch {
37
42
  value: string | number | boolean | object;
38
43
  }
39
44
  /**
45
+ * @internal
46
+ *
40
47
  * Apply a diff to an object.
41
48
  *
42
49
  * The syntax is inspired by RFC 6902 but it is not compatible.
43
50
  *
44
51
  * It supports Sets for multi-valued properties:
45
52
  * - Primitive values are added as Sets (Set<string | number | boolean>)
46
- * - Multi-valued objects are stored in Sets, accessed by their @id property
47
- * - Single objects are plain objects with an @id property
53
+ * - Multi-valued objects are stored in Sets, accessed by their `@id` property
54
+ * - Single objects are plain objects with an `@id` property
48
55
  *
49
56
  * Path traversal:
50
- * - When traversing through a Set, the path segment is treated as an @id to find the object
57
+ * - When traversing through a Set, the path segment is treated as an `@id` to find the object
51
58
  * - When traversing through a plain object, the path segment is a property name
52
59
  *
53
60
  * @example operations
@@ -88,13 +95,15 @@ export interface LiteralAddPatch {
88
95
  * @param patches An array of patches to apply to the object.
89
96
  * @param ensurePathExists If true, create nested objects along the path if the path does not exist.
90
97
  *
91
- * @note When creating new objects, this function pre-scans upcoming patches to find @id and @graph
98
+ * Note: When creating new objects, this function pre-scans upcoming patches to find `@id` and `@graph`
92
99
  * values that will be assigned to the object. This prevents the signal library's propGenerator
93
100
  * from being triggered before these identity fields are set, which would cause it to generate
94
101
  * random IDs unnecessarily.
95
102
  */
96
103
  export declare function applyPatches(currentState: Record<string, any>, patches: Patch[], ormType: "set" | "discrete", ensurePathExists?: boolean): void;
97
104
  /**
105
+ * @internal
106
+ *
98
107
  * See documentation for applyPatches
99
108
  */
100
109
  export declare function applyPatchesToDeepSignal(currentState: object, patch: Patch[], ormType: "set" | "discrete"): void;
@@ -1 +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,CAAC,WAAW,GAAG,cAAc,GAAG,WAAW,GAAG,eAAe,CAAC,CAAC;AAEnE,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,EACC,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC;CAChD;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,GAAG,MAAM,CAAC;CAC7C;AAyCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,YAAY,CACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,OAAO,EAAE,KAAK,EAAE,EAChB,OAAO,EAAE,KAAK,GAAG,UAAU,EAC3B,gBAAgB,GAAE,OAAe,QA6PpC;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACpC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,KAAK,EAAE,EACd,OAAO,EAAE,KAAK,GAAG,UAAU,QAU9B"}
1
+ {"version":3,"file":"applyPatches.d.ts","sourceRoot":"","sources":["../../src/connector/applyPatches.ts"],"names":[],"mappings":"AAYA,gBAAgB;AAChB,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,CAAC,WAAW,GAAG,cAAc,GAAG,WAAW,GAAG,eAAe,CAAC,CAAC;AAEnE,gBAAgB;AAChB,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,gBAAgB;AAChB,MAAM,WAAW,cAAc;IAC3B,oDAAoD;IACpD,EAAE,EAAE,QAAQ,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;IACf;;;;OAIG;IACH,KAAK,EACC,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC;CAChD;AAED,gBAAgB;AAChB,MAAM,WAAW,WAAW;IACxB,oDAAoD;IACpD,EAAE,EAAE,QAAQ,CAAC;CAChB;AAED,gBAAgB;AAChB,MAAM,WAAW,eAAe;IAC5B,oDAAoD;IACpD,EAAE,EAAE,KAAK,CAAC;IACV,2DAA2D;IAC3D,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;CAC7C;AAyCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,wBAAgB,YAAY,CACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACjC,OAAO,EAAE,KAAK,EAAE,EAChB,OAAO,EAAE,KAAK,GAAG,UAAU,EAC3B,gBAAgB,GAAE,OAAe,QA6PpC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACpC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,KAAK,EAAE,EACd,OAAO,EAAE,KAAK,GAAG,UAAU,QAU9B"}
@@ -45,17 +45,19 @@ function findInSetBySegment(set, seg) {
45
45
  return undefined;
46
46
  }
47
47
  /**
48
+ * @internal
49
+ *
48
50
  * Apply a diff to an object.
49
51
  *
50
52
  * The syntax is inspired by RFC 6902 but it is not compatible.
51
53
  *
52
54
  * It supports Sets for multi-valued properties:
53
55
  * - Primitive values are added as Sets (Set<string | number | boolean>)
54
- * - Multi-valued objects are stored in Sets, accessed by their @id property
55
- * - Single objects are plain objects with an @id property
56
+ * - Multi-valued objects are stored in Sets, accessed by their `@id` property
57
+ * - Single objects are plain objects with an `@id` property
56
58
  *
57
59
  * Path traversal:
58
- * - When traversing through a Set, the path segment is treated as an @id to find the object
60
+ * - When traversing through a Set, the path segment is treated as an `@id` to find the object
59
61
  * - When traversing through a plain object, the path segment is a property name
60
62
  *
61
63
  * @example operations
@@ -96,7 +98,7 @@ function findInSetBySegment(set, seg) {
96
98
  * @param patches An array of patches to apply to the object.
97
99
  * @param ensurePathExists If true, create nested objects along the path if the path does not exist.
98
100
  *
99
- * @note When creating new objects, this function pre-scans upcoming patches to find @id and @graph
101
+ * Note: When creating new objects, this function pre-scans upcoming patches to find `@id` and `@graph`
100
102
  * values that will be assigned to the object. This prevents the signal library's propGenerator
101
103
  * from being triggered before these identity fields are set, which would cause it to generate
102
104
  * random IDs unnecessarily.
@@ -273,7 +275,7 @@ export function applyPatches(currentState, patches, ormType, ensurePathExists =
273
275
  if (patch.op === "add" &&
274
276
  typeof patch.value === "object" &&
275
277
  patch.value !== null &&
276
- ormType === "set" // TODO: The backend should preferably add valType: "set" here (we don't need ormType then).
278
+ ormType === "set" // TODO: The engine should preferably add valType: "set" here (we don't need ormType then).
277
279
  ) {
278
280
  const leafVal = parentVal[key];
279
281
  const hasId = patches.at(patchIndex + 2)?.path.endsWith("@id");
@@ -334,6 +336,8 @@ export function applyPatches(currentState, patches, ormType, ensurePathExists =
334
336
  }
335
337
  }
336
338
  /**
339
+ * @internal
340
+ *
337
341
  * See documentation for applyPatches
338
342
  */
339
343
  export function applyPatchesToDeepSignal(currentState, patch, ormType) {
@@ -0,0 +1,156 @@
1
+ import { DiscreteArray, DiscreteObject } from "../../types.ts";
2
+ import { Patch } from "../applyPatches.ts";
3
+ import type { DeepPatch, DeepSignal } from "@ng-org/alien-deepsignals";
4
+ import type { BaseType } from "@ng-org/shex-orm";
5
+ /**
6
+ * Class for managing RDF-based ORM subscriptions with the engine.
7
+ *
8
+ * You have two options on how to interact with the ORM:
9
+ * - Use a hook for your favorite framework under `@ng-org/orm/react|vue|svelte`
10
+ * - Call {@link OrmSubscription.getOrCreate} to create a subscription manually
11
+ *
12
+ * For more information about RDF-based ORM subscriptions,
13
+ * see the [README](../../../README.md) and follow the tutorial.
14
+ */
15
+ export declare class DiscreteOrmSubscription {
16
+ /** Global store of all subscriptions. We use that for pooling. */
17
+ private static idToEntry;
18
+ /** The document id (IRI) of the subscribed document. */
19
+ readonly documentId: string;
20
+ private _signalObject;
21
+ private stopSignalListening;
22
+ /** The subscription id kept as an identifier for communicating with the verifier. */
23
+ private subscriptionId;
24
+ /** The number of OrmSubscriptions with the same shape and scope (for pooling). */
25
+ private refCount;
26
+ /** When true, modifications from the signalObject are not processed. */
27
+ suspendDeepWatcher: boolean;
28
+ /** True, if a transaction is running. */
29
+ inTransaction: boolean;
30
+ /** Aggregation of patches to be sent when in transaction. */
31
+ pendingPatches: Patch[] | undefined;
32
+ /** **Await to ensure that the subscription is established and the data arrived.** */
33
+ readyPromise: Promise<void>;
34
+ private closeOrmSubscription;
35
+ /** Function to call once initial data has been applied. */
36
+ private resolveReady;
37
+ private constructor();
38
+ get signalObject(): DeepSignal<DiscreteArray | DiscreteObject> | undefined;
39
+ /**
40
+ * Returns an OrmSubscription which subscribes to the given
41
+ * document in a 2-way binding.
42
+ *
43
+ * You **find the document data** in the **`signalObject`**
44
+ * once {@link readyPromise} resolves.
45
+ * This is a {@link DeepSignal} object or array, depending on
46
+ * your CRDT document (e.g. YArray vs YMap). The signalObject
47
+ * behaves like a regular set to the outside but has a couple
48
+ * of additional features:
49
+ * - Modifications are propagated back to the document.
50
+ * Note that multiple immediate modifications in the same task,
51
+ * e.g. `obj[0] = "foo"; obj[1] = "bar"` are batched together
52
+ * and sent in a subsequent microtask.
53
+ * - External document changes are immediately reflected in the object.
54
+ * - Watch for object changes using {@link watchDeepSignal}.
55
+ *
56
+ * You can use **transactions**, to prevent excessive calls to the engine
57
+ * with {@link beginTransaction} and {@link commitTransaction}.
58
+ *
59
+ * In many cases, you are advised to use a hook for your
60
+ * favorite framework under `@ng-org/orm/react|vue|svelte`
61
+ * instead of calling `getOrCreate` directly.
62
+ *
63
+ * Call `{@link close}, to close the subscription.
64
+ *
65
+ * Note: If another call to `getOrCreate` was previously made
66
+ * and {@link close} was not called on it (or only shortly after),
67
+ * it will return the same OrmSubscription.
68
+ *
69
+ * @param documentId The document ID (IRI) of the CRDT
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * // We assume you have created a CRDT document already, as below.
74
+ * // const documentId = await ng.doc_create(
75
+ * // session_id,
76
+ * // crdt, // "Automerge" | "YMap" | "YArray". YArray is for root arrays, the other two have objects at root.
77
+ * // crdt === "Automerge" ? "data:json" : crdt === "YMap ? "data:map" : "data:array",
78
+ * // "store",
79
+ * // undefined
80
+ * // );
81
+ * const subscription = DiscreteOrmSubscription.getOrCreate(documentId);
82
+ * // Wait for data.
83
+ * await subscription.readyPromise;
84
+ *
85
+ * const document = subscription.signalObject;
86
+ * if (!document.expenses) {
87
+ * document.expenses = [];
88
+ * }
89
+ * document.expenses.push({
90
+ * name: "New Expense name",
91
+ * description: "Expense description"
92
+ * });
93
+ *
94
+ * // Await promise to run the below code in a new task.
95
+ * // That will push the changes to the database.
96
+ * await Promise.resolve();
97
+ *
98
+ * // Here, the expense modifications have been have been committed
99
+ * // (unless you had previously called subscription.beginTransaction()).
100
+ * // The data is available in subscriptions running on a different device too.
101
+ *
102
+ * subscription.close();
103
+ *
104
+ * // If you create a new subscription with the same document within a couple of 100ms,
105
+ * // The subscription hasn't been closed and the old one is returned so that the data
106
+ * // is available instantly. This is especially useful in the context of frontend frameworks.
107
+ * const subscription2 = DiscreteOrmSubscription.getOrCreate(documentId);
108
+ *
109
+ * subscription2.signalObject.expenses.push({
110
+ * name: "Second expense",
111
+ * description: "Second description"
112
+ * });
113
+ *
114
+ * subscription2.close();
115
+ * ```
116
+ */
117
+ static getOrCreate: <T extends BaseType>(documentId: string) => DiscreteOrmSubscription;
118
+ /**
119
+ * Stop the subscription.
120
+ *
121
+ * **If there is more than one subscription with the same shape type and scope
122
+ * the orm subscription will persist.**
123
+ *
124
+ * Additionally, the closing of the subscription is delayed by a couple hundred milliseconds
125
+ * so that when frontend frameworks unmount and soon mound a component again with the same
126
+ * shape type and scope, no new orm subscription has be set up with the engine.
127
+ */
128
+ close: () => void;
129
+ /** Handle updates (patches) coming from signal object modifications. */
130
+ private onSignalObjectUpdate;
131
+ /** Handle messages coming from the engine (initial data or patches). */
132
+ private onBackendMessage;
133
+ private handleInitialResponse;
134
+ /** Handle incoming patches from the engine */
135
+ private onBackendUpdate;
136
+ /**
137
+ * Begins a transaction that batches changes to be committed to the database.
138
+ * This is useful for performance reasons.
139
+ *
140
+ * Note that this does not disable reactivity of the `signalObject`.
141
+ * Modifications keep being rendered.
142
+ */
143
+ beginTransaction: () => void;
144
+ /**
145
+ * Commits a transactions sending all modifications made during the transaction
146
+ * (started with `beginTransaction`) to the database.
147
+ */
148
+ commitTransaction: () => Promise<void>;
149
+ }
150
+ /**
151
+ * Converts DeepSignal patches to ORM Wasm-compatible patches
152
+ * @param patches DeepSignal patches
153
+ * @returns Patches with stringified path
154
+ */
155
+ export declare function deepPatchesToWasm(patches: DeepPatch[]): Patch[];
156
+ //# sourceMappingURL=discreteOrmSubscriptionHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discreteOrmSubscriptionHandler.d.ts","sourceRoot":"","sources":["../../../src/connector/discrete/discreteOrmSubscriptionHandler.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAA4B,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAQrE,OAAO,KAAK,EACR,SAAS,EACT,UAAU,EAEb,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AASjD;;;;;;;;;GASG;AACH,qBAAa,uBAAuB;IAChC,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,SAAS,CAA8C;IAEtE,wDAAwD;IACxD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,aAAa,CAEL;IAChB,OAAO,CAAC,mBAAmB,CAA2B;IACtD,qFAAqF;IACrF,OAAO,CAAC,cAAc,CAAqB;IAC3C,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAS;IACzB,wEAAwE;IACxE,kBAAkB,EAAE,OAAO,CAAC;IAC5B,yCAAyC;IACzC,aAAa,EAAE,OAAO,CAAS;IAC/B,6DAA6D;IAC7D,cAAc,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;IACpC,qFAAqF;IACrF,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,CAAC,oBAAoB,CAAa;IACzC,2DAA2D;IAC3D,OAAO,CAAC,YAAY,CAAc;IAElC,OAAO;IA+BP,IAAW,YAAY,2DAEtB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6EG;IACH,OAAc,WAAW,GAAI,CAAC,SAAS,QAAQ,EAC3C,YAAY,MAAM,KACnB,uBAAuB,CAcxB;IAEF;;;;;;;;;OASG;IAEI,KAAK,aASV;IAEF,wEAAwE;IACxE,OAAO,CAAC,oBAAoB,CAsB1B;IAEF,wEAAwE;IACxE,OAAO,CAAC,gBAAgB,CAStB;IAEF,OAAO,CAAC,qBAAqB,CAiB3B;IAEF,8CAA8C;IAC9C,OAAO,CAAC,eAAe,CAUrB;IAEF;;;;;;OAMG;IACI,gBAAgB,aAerB;IAEF;;;OAGG;IACI,iBAAiB,sBAiCtB;CACL;AAED;;;;GAIG;AAEH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,CAO/D"}