@ng-org/orm 0.1.2-alpha.1 → 0.1.2-alpha.10

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 (89) hide show
  1. package/README.md +151 -230
  2. package/dist/connector/applyPatches.d.ts +19 -49
  3. package/dist/connector/applyPatches.d.ts.map +1 -1
  4. package/dist/connector/applyPatches.js +57 -58
  5. package/dist/connector/discrete/discreteOrmSubscriptionHandler.d.ts +168 -0
  6. package/dist/connector/discrete/discreteOrmSubscriptionHandler.d.ts.map +1 -0
  7. package/dist/connector/discrete/discreteOrmSubscriptionHandler.js +309 -0
  8. package/dist/connector/getObjects.d.ts +11 -0
  9. package/dist/connector/getObjects.d.ts.map +1 -0
  10. package/dist/connector/getObjects.js +26 -0
  11. package/dist/connector/initNg.d.ts +33 -2
  12. package/dist/connector/initNg.d.ts.map +1 -1
  13. package/dist/connector/initNg.js +30 -0
  14. package/dist/connector/insertObject.d.ts +9 -0
  15. package/dist/connector/insertObject.d.ts.map +1 -0
  16. package/dist/connector/insertObject.js +24 -0
  17. package/dist/connector/ormSubscriptionHandler.d.ts +167 -0
  18. package/dist/connector/ormSubscriptionHandler.d.ts.map +1 -0
  19. package/dist/connector/ormSubscriptionHandler.js +400 -0
  20. package/dist/connector/utils.d.ts +17 -0
  21. package/dist/connector/utils.d.ts.map +1 -0
  22. package/dist/connector/utils.js +68 -0
  23. package/dist/frontendAdapters/react/index.d.ts +2 -1
  24. package/dist/frontendAdapters/react/index.d.ts.map +1 -1
  25. package/dist/frontendAdapters/react/index.js +2 -1
  26. package/dist/frontendAdapters/react/useDiscrete.d.ts +104 -0
  27. package/dist/frontendAdapters/react/useDiscrete.d.ts.map +1 -0
  28. package/dist/frontendAdapters/react/useDiscrete.js +151 -0
  29. package/dist/frontendAdapters/react/useShape.d.ts +69 -2
  30. package/dist/frontendAdapters/react/useShape.d.ts.map +1 -1
  31. package/dist/frontendAdapters/react/useShape.js +89 -8
  32. package/dist/frontendAdapters/svelte/index.d.ts +2 -1
  33. package/dist/frontendAdapters/svelte/index.d.ts.map +1 -1
  34. package/dist/frontendAdapters/svelte/index.js +2 -1
  35. package/dist/frontendAdapters/svelte/useDiscrete.svelte.d.ts +94 -0
  36. package/dist/frontendAdapters/svelte/useDiscrete.svelte.d.ts.map +1 -0
  37. package/dist/frontendAdapters/svelte/useDiscrete.svelte.js +137 -0
  38. package/dist/frontendAdapters/svelte/useShape.svelte.d.ts +79 -10
  39. package/dist/frontendAdapters/svelte/useShape.svelte.d.ts.map +1 -1
  40. package/dist/frontendAdapters/svelte/useShape.svelte.js +88 -9
  41. package/dist/frontendAdapters/svelte4/index.d.ts +5 -0
  42. package/dist/frontendAdapters/svelte4/index.d.ts.map +1 -0
  43. package/dist/{connector/createSignalObjectForShape.js → frontendAdapters/svelte4/index.js} +3 -15
  44. package/dist/frontendAdapters/svelte4/useDiscrete.svelte.d.ts +84 -0
  45. package/dist/frontendAdapters/svelte4/useDiscrete.svelte.d.ts.map +1 -0
  46. package/dist/frontendAdapters/svelte4/useDiscrete.svelte.js +126 -0
  47. package/dist/frontendAdapters/svelte4/useShape.svelte.d.ts +77 -0
  48. package/dist/frontendAdapters/svelte4/useShape.svelte.d.ts.map +1 -0
  49. package/dist/frontendAdapters/svelte4/useShape.svelte.js +91 -0
  50. package/dist/frontendAdapters/utils.d.ts +2 -0
  51. package/dist/frontendAdapters/utils.d.ts.map +1 -0
  52. package/dist/frontendAdapters/utils.js +14 -0
  53. package/dist/frontendAdapters/vue/index.d.ts +2 -1
  54. package/dist/frontendAdapters/vue/index.d.ts.map +1 -1
  55. package/dist/frontendAdapters/vue/index.js +2 -1
  56. package/dist/frontendAdapters/vue/useDiscrete.d.ts +99 -0
  57. package/dist/frontendAdapters/vue/useDiscrete.d.ts.map +1 -0
  58. package/dist/frontendAdapters/vue/useDiscrete.js +123 -0
  59. package/dist/frontendAdapters/vue/useShape.d.ts +73 -2
  60. package/dist/frontendAdapters/vue/useShape.d.ts.map +1 -1
  61. package/dist/frontendAdapters/vue/useShape.js +79 -4
  62. package/dist/index.d.ts +13 -6
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +21 -6
  65. package/dist/types.d.ts +63 -11
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/types.js +13 -1
  68. package/package.json +37 -48
  69. package/dist/connector/applyPatches.test.d.ts +0 -2
  70. package/dist/connector/applyPatches.test.d.ts.map +0 -1
  71. package/dist/connector/applyPatches.test.js +0 -772
  72. package/dist/connector/createSignalObjectForShape.d.ts +0 -14
  73. package/dist/connector/createSignalObjectForShape.d.ts.map +0 -1
  74. package/dist/connector/ormConnectionHandler.d.ts +0 -47
  75. package/dist/connector/ormConnectionHandler.d.ts.map +0 -1
  76. package/dist/connector/ormConnectionHandler.js +0 -240
  77. package/src/connector/applyPatches.test.ts +0 -842
  78. package/src/connector/applyPatches.ts +0 -404
  79. package/src/connector/createSignalObjectForShape.ts +0 -35
  80. package/src/connector/initNg.ts +0 -30
  81. package/src/connector/ormConnectionHandler.ts +0 -300
  82. package/src/frontendAdapters/react/index.ts +0 -2
  83. package/src/frontendAdapters/react/useShape.ts +0 -36
  84. package/src/frontendAdapters/svelte/index.ts +0 -2
  85. package/src/frontendAdapters/svelte/useShape.svelte.ts +0 -46
  86. package/src/frontendAdapters/vue/index.ts +0 -2
  87. package/src/frontendAdapters/vue/useShape.ts +0 -33
  88. package/src/index.ts +0 -14
  89. package/src/types.ts +0 -26
@@ -1,2 +1,3 @@
1
1
  import useShape from "./useShape.js";
2
- export { useShape };
2
+ import { useDiscrete } from "./useDiscrete.js";
3
+ export { useShape, useDiscrete };
@@ -0,0 +1,99 @@
1
+ import { MaybeRefOrGetter, ToRefs } from "vue";
2
+ import { DiscreteRoot } from "../../types.ts";
3
+ /**
4
+ * Hook to subscribe to an existing discrete (JSON) CRDT document.
5
+ * You can modify the returned object like any other JSON object. Changes are immediately
6
+ * reflected in the CRDT document.
7
+ *
8
+ * Establishes a 2-way binding: Modifications to the object are immediately committed,
9
+ * changes coming from the engine (or other components) cause an immediate rerender.
10
+ *
11
+ * In comparison to `useShape`, discrete CRDTs are untyped.
12
+ * You can put any JSON data inside and need to validate the schema yourself.
13
+ *
14
+ * @param documentId The NURI of the CRDT document or `undefined` as MaybeRefOrGetter.
15
+ * @returns An object that contains as `data` the reactive DeepSignal object or undefined if not loaded yet or `documentId` is undefined.
16
+ *
17
+ *@example
18
+ * ```html
19
+ * <script lang="ts">
20
+ * // We assume you have created a CRDT document already, as below.
21
+ * // const documentId = await ng.doc_create(
22
+ * // session_id,
23
+ * // crdt, // "Automerge" | "YMap" | "YArray"
24
+ * // crdt === "Automerge" ? "data:json" : crdt === "YMap ? "data:map" : "data:array",
25
+ * // "store",
26
+ * // undefined
27
+ * // );
28
+ * const { doc } = useDiscrete(documentId);
29
+ *
30
+ * // If document is new, we need to set up the basic structure.
31
+ * effect(() => {
32
+ * if (doc.value && !doc.value.expenses) {
33
+ * doc.value.expenses = [];
34
+ * }
35
+ * })
36
+ *
37
+ * const createExpense = () => {
38
+ * // Note that we use *expense["@id"]* as a key in the expense list.
39
+ * // Every object added to a CRDT array gets a stable `@id` property assigned
40
+ * // which you can use for referencing objects in arrays even as
41
+ * // objects are removed or added from the array.
42
+ * // The `@id` is an NURI with the schema `<documentId>:d:<object-specific id>`.
43
+ * // Since the `@id` is generated in the engine, the object is
44
+ * // *preliminarily given a mock id* which will be replaced immediately.
45
+ * doc.value.expenses.push({
46
+ * title: "New expense",
47
+ * date: new Date().toISOString(),
48
+ * });
49
+ * };
50
+ * </script>
51
+ *
52
+ * <template>
53
+ * <div v-if="!doc">
54
+ * Loading...
55
+ * </div>
56
+ * <div v-else>
57
+ * <p v-if="expenses.length === 0">
58
+ * No expenses yet.
59
+ * </p>
60
+ * <template v-else>
61
+ * <button
62
+ * @click={() => createExpense()}
63
+ * >
64
+ * + Add expense
65
+ * </button>
66
+ * <ExpenseCard
67
+ * v-for="expense in expenses"
68
+ * :key="expense['@id']"
69
+ * :expense="expense"
70
+ * />
71
+ * </template>
72
+ * </div>
73
+ * </template>
74
+ * ```
75
+ *
76
+ * In the `ExpenseCard` component:
77
+ * ```html
78
+ * <script lang="ts">
79
+ * const { expense } = defineProps<{
80
+ * expense: DeepSignal<Expense>;
81
+ * }>();
82
+ *
83
+ * // If you modify expense in the component,
84
+ * // the changes are immediately propagated to other consuming components
85
+ * // And persisted in the database.
86
+ * </script>
87
+ *
88
+ * <template>
89
+ * <input
90
+ * v-model="expense.title"
91
+ * placeholder="Expense title"
92
+ * />
93
+ * </template>
94
+ * ```
95
+ */
96
+ export declare function useDiscrete<T extends DiscreteRoot = DiscreteRoot>(documentId: MaybeRefOrGetter<string | undefined>): ToRefs<{
97
+ doc: T;
98
+ }>;
99
+ //# sourceMappingURL=useDiscrete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDiscrete.d.ts","sourceRoot":"","sources":["../../../src/frontendAdapters/vue/useDiscrete.ts"],"names":[],"mappings":"AAUA,OAAO,EAEH,gBAAgB,EAGhB,MAAM,EAIT,MAAM,KAAK,CAAC;AAGb,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4FG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAC7D,UAAU,EAAE,gBAAgB,CAAC,MAAM,GAAG,SAAS,CAAC,GAoB1B,MAAM,CAAC;IAAE,GAAG,EAAE,CAAC,CAAA;CAAE,CAAC,CAC3C"}
@@ -0,0 +1,123 @@
1
+ // Copyright (c) 2026 Laurin Weger, Par le Peuple, NextGraph.org developers
2
+ // All rights reserved.
3
+ // Licensed under the Apache License, Version 2.0
4
+ // <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
5
+ // or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6
+ // at your option. All files in the project carrying such
7
+ // notice may not be copied, modified, or distributed except
8
+ // according to those terms.
9
+ // SPDX-License-Identifier: Apache-2.0 OR MIT
10
+ import { computed, onBeforeUnmount, shallowReactive, toRefs, toValue, watchEffect, } from "vue";
11
+ import { useDeepSignal } from "@ng-org/alien-deepsignals/vue";
12
+ import { DiscreteOrmSubscription } from "../../connector/discrete/discreteOrmSubscriptionHandler.js";
13
+ /**
14
+ * Hook to subscribe to an existing discrete (JSON) CRDT document.
15
+ * You can modify the returned object like any other JSON object. Changes are immediately
16
+ * reflected in the CRDT document.
17
+ *
18
+ * Establishes a 2-way binding: Modifications to the object are immediately committed,
19
+ * changes coming from the engine (or other components) cause an immediate rerender.
20
+ *
21
+ * In comparison to `useShape`, discrete CRDTs are untyped.
22
+ * You can put any JSON data inside and need to validate the schema yourself.
23
+ *
24
+ * @param documentId The NURI of the CRDT document or `undefined` as MaybeRefOrGetter.
25
+ * @returns An object that contains as `data` the reactive DeepSignal object or undefined if not loaded yet or `documentId` is undefined.
26
+ *
27
+ *@example
28
+ * ```html
29
+ * <script lang="ts">
30
+ * // We assume you have created a CRDT document already, as below.
31
+ * // const documentId = await ng.doc_create(
32
+ * // session_id,
33
+ * // crdt, // "Automerge" | "YMap" | "YArray"
34
+ * // crdt === "Automerge" ? "data:json" : crdt === "YMap ? "data:map" : "data:array",
35
+ * // "store",
36
+ * // undefined
37
+ * // );
38
+ * const { doc } = useDiscrete(documentId);
39
+ *
40
+ * // If document is new, we need to set up the basic structure.
41
+ * effect(() => {
42
+ * if (doc.value && !doc.value.expenses) {
43
+ * doc.value.expenses = [];
44
+ * }
45
+ * })
46
+ *
47
+ * const createExpense = () => {
48
+ * // Note that we use *expense["@id"]* as a key in the expense list.
49
+ * // Every object added to a CRDT array gets a stable `@id` property assigned
50
+ * // which you can use for referencing objects in arrays even as
51
+ * // objects are removed or added from the array.
52
+ * // The `@id` is an NURI with the schema `<documentId>:d:<object-specific id>`.
53
+ * // Since the `@id` is generated in the engine, the object is
54
+ * // *preliminarily given a mock id* which will be replaced immediately.
55
+ * doc.value.expenses.push({
56
+ * title: "New expense",
57
+ * date: new Date().toISOString(),
58
+ * });
59
+ * };
60
+ * </script>
61
+ *
62
+ * <template>
63
+ * <div v-if="!doc">
64
+ * Loading...
65
+ * </div>
66
+ * <div v-else>
67
+ * <p v-if="expenses.length === 0">
68
+ * No expenses yet.
69
+ * </p>
70
+ * <template v-else>
71
+ * <button
72
+ * @click={() => createExpense()}
73
+ * >
74
+ * + Add expense
75
+ * </button>
76
+ * <ExpenseCard
77
+ * v-for="expense in expenses"
78
+ * :key="expense['@id']"
79
+ * :expense="expense"
80
+ * />
81
+ * </template>
82
+ * </div>
83
+ * </template>
84
+ * ```
85
+ *
86
+ * In the `ExpenseCard` component:
87
+ * ```html
88
+ * <script lang="ts">
89
+ * const { expense } = defineProps<{
90
+ * expense: DeepSignal<Expense>;
91
+ * }>();
92
+ *
93
+ * // If you modify expense in the component,
94
+ * // the changes are immediately propagated to other consuming components
95
+ * // And persisted in the database.
96
+ * </script>
97
+ *
98
+ * <template>
99
+ * <input
100
+ * v-model="expense.title"
101
+ * placeholder="Expense title"
102
+ * />
103
+ * </template>
104
+ * ```
105
+ */
106
+ export function useDiscrete(documentId) {
107
+ const ormSubscription = computed(() => {
108
+ const id = toValue(documentId);
109
+ return id ? DiscreteOrmSubscription.getOrCreate(id) : undefined;
110
+ });
111
+ const ret = shallowReactive({
112
+ doc: undefined,
113
+ });
114
+ watchEffect(() => {
115
+ ormSubscription.value?.readyPromise.then(() => {
116
+ ret.doc = useDeepSignal(ormSubscription.value.signalObject);
117
+ });
118
+ });
119
+ onBeforeUnmount(() => {
120
+ ormSubscription.value?.close();
121
+ });
122
+ return toRefs(ret);
123
+ }
@@ -1,5 +1,76 @@
1
- import type { Scope } from "../../types.ts";
1
+ import { type Scope } from "../../types.ts";
2
2
  import type { BaseType, ShapeType } from "@ng-org/shex-orm";
3
- export declare function useShape<T extends BaseType>(shape: ShapeType<T>, scope?: Scope): import("@ng-org/alien-deepsignals").DeepSignalSet<T>;
3
+ import { DeepSignalSet } from "@ng-org/alien-deepsignals";
4
+ /**
5
+ * Hook to subscribe to RDF data in the graph database using a shape, see {@link ShapeType}.
6
+ * The returned objects are as easy to use as other TypeScript objects.
7
+ *
8
+ * Returns a {@link DeepSignalSet} of objects matching the shape and that are within the scope.
9
+ * Establishes a 2-way binding: Modifications to the object are immediately committed,
10
+ * changes coming from the backend (or other components) cause an immediate rerender.
11
+ *
12
+ * @param shape The {@link ShapeType} the objects should have (generated by the shex-orm tool).
13
+ * @param scope The {@link Scope} as graph string or scope object with graphs and subjects.
14
+ * @returns A {@link DeepSignalSet} with the orm objects or an empty set, if still loading.\
15
+ * If the scope is explicitly set to `undefined`, an empty set is returned which errors
16
+ * if you try to make modifications on it.
17
+ *
18
+ * @example
19
+ * ```html
20
+ * <script lang="ts">
21
+ * // Contains all expense objects with `@id` <s1 IRI> or <s2 IRI> and `@graph` <g1 NURI> or <g2 NURI>
22
+ * const expenses: DeepSignal<Set<Expense>> = useShape(ExpenseShapeType,
23
+ * {graphs: ["<g1 NURI>", "<g2 NURI>"],
24
+ * subjects: ["<s1 IRI>", "<s2 IRI>"]});
25
+ *
26
+ *
27
+ * const expensesSorted = computed(() => [...expenses].sort((a, b) =>
28
+ * a.dateOfPurchase.localeCompare(b.dateOfPurchase)
29
+ * ));
30
+ *
31
+ * // Simply call expenses.add({"@graph": "<g1 or g2 NURI>", "@id": "", title: "Example title"}), to add new elements.
32
+ * // Leave `@id` an empty string to auto-generate a subject NURI (adjust your scope accordingly).
33
+ *
34
+ * // Note that if you use `@id` (the subject IRI) as key, you need to ensure that it is unique within your scope.
35
+ * // If it is not (i.e. there are two graphs with the same subject), use the combination of `@graph` and `@id`.
36
+ * </script>
37
+ *
38
+ * <template>
39
+ * <div>
40
+ * <p v-if="expensesSorted.length === 0">
41
+ * No expenses yet.
42
+ * </p>
43
+ * <template v-else>
44
+ * <ExpenseCard
45
+ * v-for="expense in expensesSorted"
46
+ * :key="expense['@id'])"
47
+ * :expense="expense"
48
+ * />
49
+ * </template>
50
+ * </div>
51
+ * </template>
52
+ * ```
53
+ *
54
+ * In the `ExpenseCard` component:
55
+ * ```html
56
+ * <script lang="ts">
57
+ * const { expense } = defineProps<{
58
+ * expense: DeepSignal<Expense>;
59
+ * }>();
60
+ *
61
+ * // If you modify expense in the component,
62
+ * // the changes are immediately propagated to other consuming components.
63
+ * // And persisted in the database.
64
+ * </script>
65
+ *
66
+ * <template>
67
+ * <input
68
+ * v-model="expense.title"
69
+ * placeholder="Expense title"
70
+ * />
71
+ * </template>
72
+ * ```
73
+ */
74
+ export declare function useShape<T extends BaseType>(shape: ShapeType<T>, scope: Scope | string | undefined): DeepSignalSet<T>;
4
75
  export default useShape;
5
76
  //# sourceMappingURL=useShape.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useShape.d.ts","sourceRoot":"","sources":["../../../src/frontendAdapters/vue/useShape.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5C,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE5D,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EACvC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EACnB,KAAK,CAAC,EAAE,KAAK,wDAYhB;AAED,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"useShape.d.ts","sourceRoot":"","sources":["../../../src/frontendAdapters/vue/useShape.ts"],"names":[],"mappings":"AAUA,OAAO,EAAkB,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAG5D,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,QAAQ,EACvC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EACnB,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,oBAmBpC;AAED,eAAe,QAAQ,CAAC"}
@@ -7,16 +7,91 @@
7
7
  // notice may not be copied, modified, or distributed except
8
8
  // according to those terms.
9
9
  // SPDX-License-Identifier: Apache-2.0 OR MIT
10
- import { createSignalObjectForShape } from "../../connector/createSignalObjectForShape.js";
10
+ import { normalizeScope } from "../../types.js";
11
11
  import { useDeepSignal } from "@ng-org/alien-deepsignals/vue";
12
12
  import { onBeforeUnmount } from "vue";
13
+ import { OrmSubscription } from "../../connector/ormSubscriptionHandler.js";
14
+ import { readOnlySet } from "../utils.js";
15
+ /**
16
+ * Hook to subscribe to RDF data in the graph database using a shape, see {@link ShapeType}.
17
+ * The returned objects are as easy to use as other TypeScript objects.
18
+ *
19
+ * Returns a {@link DeepSignalSet} of objects matching the shape and that are within the scope.
20
+ * Establishes a 2-way binding: Modifications to the object are immediately committed,
21
+ * changes coming from the backend (or other components) cause an immediate rerender.
22
+ *
23
+ * @param shape The {@link ShapeType} the objects should have (generated by the shex-orm tool).
24
+ * @param scope The {@link Scope} as graph string or scope object with graphs and subjects.
25
+ * @returns A {@link DeepSignalSet} with the orm objects or an empty set, if still loading.\
26
+ * If the scope is explicitly set to `undefined`, an empty set is returned which errors
27
+ * if you try to make modifications on it.
28
+ *
29
+ * @example
30
+ * ```html
31
+ * <script lang="ts">
32
+ * // Contains all expense objects with `@id` <s1 IRI> or <s2 IRI> and `@graph` <g1 NURI> or <g2 NURI>
33
+ * const expenses: DeepSignal<Set<Expense>> = useShape(ExpenseShapeType,
34
+ * {graphs: ["<g1 NURI>", "<g2 NURI>"],
35
+ * subjects: ["<s1 IRI>", "<s2 IRI>"]});
36
+ *
37
+ *
38
+ * const expensesSorted = computed(() => [...expenses].sort((a, b) =>
39
+ * a.dateOfPurchase.localeCompare(b.dateOfPurchase)
40
+ * ));
41
+ *
42
+ * // Simply call expenses.add({"@graph": "<g1 or g2 NURI>", "@id": "", title: "Example title"}), to add new elements.
43
+ * // Leave `@id` an empty string to auto-generate a subject NURI (adjust your scope accordingly).
44
+ *
45
+ * // Note that if you use `@id` (the subject IRI) as key, you need to ensure that it is unique within your scope.
46
+ * // If it is not (i.e. there are two graphs with the same subject), use the combination of `@graph` and `@id`.
47
+ * </script>
48
+ *
49
+ * <template>
50
+ * <div>
51
+ * <p v-if="expensesSorted.length === 0">
52
+ * No expenses yet.
53
+ * </p>
54
+ * <template v-else>
55
+ * <ExpenseCard
56
+ * v-for="expense in expensesSorted"
57
+ * :key="expense['@id'])"
58
+ * :expense="expense"
59
+ * />
60
+ * </template>
61
+ * </div>
62
+ * </template>
63
+ * ```
64
+ *
65
+ * In the `ExpenseCard` component:
66
+ * ```html
67
+ * <script lang="ts">
68
+ * const { expense } = defineProps<{
69
+ * expense: DeepSignal<Expense>;
70
+ * }>();
71
+ *
72
+ * // If you modify expense in the component,
73
+ * // the changes are immediately propagated to other consuming components.
74
+ * // And persisted in the database.
75
+ * </script>
76
+ *
77
+ * <template>
78
+ * <input
79
+ * v-model="expense.title"
80
+ * placeholder="Expense title"
81
+ * />
82
+ * </template>
83
+ * ```
84
+ */
13
85
  export function useShape(shape, scope) {
14
- const handle = createSignalObjectForShape(shape, scope);
86
+ if (scope === undefined) {
87
+ return useDeepSignal(readOnlySet);
88
+ }
89
+ const connection = OrmSubscription.getOrCreate(shape, normalizeScope(scope));
15
90
  // Cleanup
16
91
  onBeforeUnmount(() => {
17
- handle.stop();
92
+ connection.close();
18
93
  });
19
- const ref = useDeepSignal(handle.signalObject);
94
+ const ref = useDeepSignal(connection.signalObject);
20
95
  return ref;
21
96
  }
22
97
  export default useShape;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,15 @@
1
- import { createSignalObjectForShape } from "./connector/createSignalObjectForShape.ts";
2
- import { useShape as svelteUseShape } from "./frontendAdapters/svelte/index.ts";
3
- import { useShape as reactUseShape } from "./frontendAdapters/react/index.ts";
4
- import { useShape as vueUseShape } from "./frontendAdapters/vue/useShape.ts";
5
- import { initNgSignals } from "./connector/initNg.ts";
1
+ import { OrmSubscription } from "./connector/ormSubscriptionHandler.ts";
2
+ import { DiscreteOrmSubscription } from "./connector/discrete/discreteOrmSubscriptionHandler.ts";
3
+ import { useShape as svelteUseShape, useDiscrete as svelteUseDiscrete } from "./frontendAdapters/svelte/index.ts";
4
+ import { useShape as svelte4UseShape, useDiscrete as svelte4UseDiscrete } from "./frontendAdapters/svelte4/index.ts";
5
+ import { useShape as reactUseShape, useDiscrete as reactUseDiscrete } from "./frontendAdapters/react/index.ts";
6
+ import { useShape as vueUseShape, useDiscrete as vueUseDiscrete } from "./frontendAdapters/vue/index.ts";
7
+ import { initNgSignals, ngSession } from "./connector/initNg.ts";
8
+ import { insertObject } from "./connector/insertObject.ts";
9
+ import { getObjects } from "./connector/getObjects.ts";
6
10
  export * from "./connector/applyPatches.ts";
7
- export { initNgSignals as initNg, createSignalObjectForShape, svelteUseShape, reactUseShape, vueUseShape, };
11
+ export * from "./types.ts";
12
+ export type { DeepSignal, DeepSignalObject, DeepSignalSet, } from "@ng-org/alien-deepsignals";
13
+ export { getRaw, watch, effect } from "@ng-org/alien-deepsignals";
14
+ export { initNgSignals as initNg, ngSession, OrmSubscription as OrmSubscription, DiscreteOrmSubscription, svelteUseShape, svelteUseDiscrete, svelte4UseShape, svelte4UseDiscrete, reactUseShape, reactUseDiscrete, vueUseShape, vueUseDiscrete, insertObject, getObjects, };
8
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,cAAc,6BAA6B,CAAC;AAE5C,OAAO,EACH,aAAa,IAAI,MAAM,EACvB,0BAA0B,EAC1B,cAAc,EACd,aAAa,EACb,WAAW,GACd,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wDAAwD,CAAC;AACjG,OAAO,EACH,QAAQ,IAAI,cAAc,EAC1B,WAAW,IAAI,iBAAiB,EACnC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACH,QAAQ,IAAI,eAAe,EAC3B,WAAW,IAAI,kBAAkB,EACpC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACH,QAAQ,IAAI,aAAa,EACzB,WAAW,IAAI,gBAAgB,EAClC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACH,QAAQ,IAAI,WAAW,EACvB,WAAW,IAAI,cAAc,EAChC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,YAAY,CAAC;AAE3B,YAAY,EACR,UAAU,EACV,gBAAgB,EAChB,aAAa,GAChB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EACH,aAAa,IAAI,MAAM,EACvB,SAAS,EACT,eAAe,IAAI,eAAe,EAClC,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,UAAU,GACb,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,22 @@
1
- import { createSignalObjectForShape } from "./connector/createSignalObjectForShape.js";
2
- import { useShape as svelteUseShape } from "./frontendAdapters/svelte/index.js";
3
- import { useShape as reactUseShape } from "./frontendAdapters/react/index.js";
4
- import { useShape as vueUseShape } from "./frontendAdapters/vue/useShape.js";
5
- import { initNgSignals } from "./connector/initNg.js";
1
+ // Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
2
+ // All rights reserved.
3
+ // Licensed under the Apache License, Version 2.0
4
+ // <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
5
+ // or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
6
+ // at your option. All files in the project carrying such
7
+ // notice may not be copied, modified, or distributed except
8
+ // according to those terms.
9
+ // SPDX-License-Identifier: Apache-2.0 OR MIT
10
+ import { OrmSubscription } from "./connector/ormSubscriptionHandler.js";
11
+ import { DiscreteOrmSubscription } from "./connector/discrete/discreteOrmSubscriptionHandler.js";
12
+ import { useShape as svelteUseShape, useDiscrete as svelteUseDiscrete, } from "./frontendAdapters/svelte/index.js";
13
+ import { useShape as svelte4UseShape, useDiscrete as svelte4UseDiscrete, } from "./frontendAdapters/svelte4/index.js";
14
+ import { useShape as reactUseShape, useDiscrete as reactUseDiscrete, } from "./frontendAdapters/react/index.js";
15
+ import { useShape as vueUseShape, useDiscrete as vueUseDiscrete, } from "./frontendAdapters/vue/index.js";
16
+ import { initNgSignals, ngSession } from "./connector/initNg.js";
17
+ import { insertObject } from "./connector/insertObject.js";
18
+ import { getObjects } from "./connector/getObjects.js";
6
19
  export * from "./connector/applyPatches.js";
7
- export { initNgSignals as initNg, createSignalObjectForShape, svelteUseShape, reactUseShape, vueUseShape, };
20
+ export * from "./types.js";
21
+ export { getRaw, watch, effect } from "@ng-org/alien-deepsignals";
22
+ export { initNgSignals as initNg, ngSession, OrmSubscription as OrmSubscription, DiscreteOrmSubscription, svelteUseShape, svelteUseDiscrete, svelte4UseShape, svelte4UseDiscrete, reactUseShape, reactUseDiscrete, vueUseShape, vueUseDiscrete, insertObject, getObjects, };
package/dist/types.d.ts CHANGED
@@ -1,13 +1,65 @@
1
- import type { Patch } from "./connector/applyPatches.ts";
2
- /** The shape of an object requested. */
3
- export type Shape = "Shape1" | "Shape2" | "TestShape";
4
- /** The Scope of a shape request */
5
- export type Scope = string;
6
- /** The diff format used to communicate updates between wasm-land and js-land. */
7
- export type Diff = Patch[];
8
- /** A connection established between wasm-land and js-land for subscription of a shape. */
9
- export type Connection = {
10
- id: string;
11
- onUpdateFromWasm: (diff: Diff) => void;
1
+ /**
2
+ * When dealing with shapes (RDF-based graph database ORMs):
3
+ * The scope of a shape request.
4
+ * In most cases, it is recommended to use a narrow scope for performance.
5
+ * You can filter results by `subjects` and `graphs`. Only objects in that scope will be returned.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * // Contains all expense objects with `@id` <s1 IRI> or <s2 IRI> and `@graph` <g1 NURI> or <g2 NURI>
10
+ * const expenses: DeepSignal<Set<Expense>> = useShape(ExpenseShape,
11
+ * {graphs: ["<graph1 NURI>", "<graph2 NURI>"],
12
+ * subjects: ["<subject1 IRI>", "<subject2 IRI>"]});
13
+ * ```
14
+ */
15
+ export type Scope = {
16
+ /**
17
+ * The graphs to filter for. If more than one NURI is provided, the union of all graphs is considered.
18
+ *
19
+ * - Set value to `["did:ng:i"]` or `[""]` for whole dataset.
20
+ * - Setting value to `[]` or leaving it `undefined`, no objects are returned.
21
+ */
22
+ graphs?: string[];
23
+ /**
24
+ * Subjects to filter for. Set to `[]` or leave it `undefined` for no filtering.
25
+ */
26
+ subjects?: string[];
12
27
  };
28
+ /**
29
+ * Converts undefined to [] and for graphs "" to "did:ng:i". If scope is string, it means {graphs: [\<scope string>], subjects: []}.
30
+ * @ignore
31
+ */
32
+ export declare const normalizeScope: (scope?: Scope | string | undefined) => {
33
+ graphs: string[];
34
+ subjects: string[];
35
+ };
36
+ /** An allowed array in the CRDT. */
37
+ export interface DiscreteArray extends Array<DiscreteType> {
38
+ }
39
+ /** An allowed object in the CRDT. */
40
+ export interface DiscreteObject {
41
+ [key: string]: DiscreteType;
42
+ }
43
+ /** An allowed type in the CRDT. */
44
+ export type DiscreteType = DiscreteArray | DiscreteObject | string | number | boolean;
45
+ /**
46
+ * The root array for reading and modifying the CRDT as a plain object.
47
+ */
48
+ export type DiscreteRootArray = (DiscreteArray | string | number | boolean | (DiscreteObject & {
49
+ readonly "@id": string;
50
+ }))[];
51
+ /**
52
+ * The root object for reading and modifying the CRDT as a plain object.
53
+ */
54
+ export interface DiscreteRootObject {
55
+ [key: string]: DiscreteObject | string | number | boolean | DiscreteRootArray;
56
+ }
57
+ /** A discrete document's root object, either an array or an object. */
58
+ export type DiscreteRoot = DiscreteRootArray | DiscreteRootObject;
59
+ /**
60
+ * The supported discrete (JSON) CRDTs.
61
+ * Automerge and YMap require objects as roots.
62
+ * YArray requires an array as root.
63
+ */
64
+ export type DiscreteCrdt = "YMap" | "YArray" | "Automerge";
13
65
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEzD,wCAAwC;AACxC,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEtD,mCAAmC;AACnC,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC;AAE3B,iFAAiF;AACjF,MAAM,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC;AAE3B,0FAA0F;AAC1F,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CAC1C,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,KAAK,GAAG;IAChB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,QAAO,KAAK,GAAG,MAAM,GAAG,SAAc;;;CASpE,CAAC;AAEF,oCAAoC;AACpC,MAAM,WAAW,aAAc,SAAQ,KAAK,CAAC,YAAY,CAAC;CAAG;AAE7D,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC;CAC/B;AACD,mCAAmC;AACnC,MAAM,MAAM,YAAY,GAClB,aAAa,GACb,cAAc,GACd,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC1B,aAAa,GACb,MAAM,GACN,MAAM,GACN,OAAO,GACP,CAAC,cAAc,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAClD,EAAE,CAAC;AAEJ;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,CAAC,GAAG,EAAE,MAAM,GACN,cAAc,GACd,MAAM,GACN,MAAM,GACN,OAAO,GACP,iBAAiB,CAAC;CAC3B;AAED,uEAAuE;AACvE,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAElE;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC"}
package/dist/types.js CHANGED
@@ -7,4 +7,16 @@
7
7
  // notice may not be copied, modified, or distributed except
8
8
  // according to those terms.
9
9
  // SPDX-License-Identifier: Apache-2.0 OR MIT
10
- export {};
10
+ /**
11
+ * Converts undefined to [] and for graphs "" to "did:ng:i". If scope is string, it means {graphs: [\<scope string>], subjects: []}.
12
+ * @ignore
13
+ */
14
+ export const normalizeScope = (scope = {}) => {
15
+ if (typeof scope === "string") {
16
+ return { graphs: [scope], subjects: [] };
17
+ }
18
+ // Convert "" to did:ng:i
19
+ const graphs = (scope.graphs ?? []).map((g) => (g === "" ? "did:ng:i" : g));
20
+ const subjects = scope.subjects ?? [];
21
+ return { graphs, subjects };
22
+ };