@_linked/core 2.34.0 → 2.35.0

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 (85) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +24 -0
  3. package/lib/esm/index.d.ts +2 -1
  4. package/lib/esm/index.js +2 -0
  5. package/lib/esm/index.js.map +1 -1
  6. package/lib/esm/live/LiveQueryStore.d.ts +22 -0
  7. package/lib/esm/live/LiveQueryStore.js +86 -19
  8. package/lib/esm/live/LiveQueryStore.js.map +1 -1
  9. package/lib/esm/live/changes.d.ts +9 -1
  10. package/lib/esm/live/changes.js +7 -2
  11. package/lib/esm/live/changes.js.map +1 -1
  12. package/lib/esm/live/keys.d.ts +6 -0
  13. package/lib/esm/live/keys.js +10 -1
  14. package/lib/esm/live/keys.js.map +1 -1
  15. package/lib/esm/live/matcher.d.ts +4 -1
  16. package/lib/esm/live/matcher.js +10 -5
  17. package/lib/esm/live/matcher.js.map +1 -1
  18. package/lib/esm/queries/AskBuilder.d.ts +6 -0
  19. package/lib/esm/queries/AskBuilder.js +14 -0
  20. package/lib/esm/queries/AskBuilder.js.map +1 -1
  21. package/lib/esm/queries/CountBuilder.d.ts +6 -0
  22. package/lib/esm/queries/CountBuilder.js +14 -0
  23. package/lib/esm/queries/CountBuilder.js.map +1 -1
  24. package/lib/esm/queries/CreateBuilder.d.ts +4 -0
  25. package/lib/esm/queries/CreateBuilder.js +15 -1
  26. package/lib/esm/queries/CreateBuilder.js.map +1 -1
  27. package/lib/esm/queries/DeleteBuilder.d.ts +4 -0
  28. package/lib/esm/queries/DeleteBuilder.js +15 -1
  29. package/lib/esm/queries/DeleteBuilder.js.map +1 -1
  30. package/lib/esm/queries/FieldSet.d.ts +10 -0
  31. package/lib/esm/queries/FieldSet.js +85 -18
  32. package/lib/esm/queries/FieldSet.js.map +1 -1
  33. package/lib/esm/queries/IRLower.js +3 -2
  34. package/lib/esm/queries/IRLower.js.map +1 -1
  35. package/lib/esm/queries/IRMutation.js +15 -14
  36. package/lib/esm/queries/IRMutation.js.map +1 -1
  37. package/lib/esm/queries/MutationSerialization.js +2 -2
  38. package/lib/esm/queries/MutationSerialization.js.map +1 -1
  39. package/lib/esm/queries/PropertyPath.js +2 -2
  40. package/lib/esm/queries/PropertyPath.js.map +1 -1
  41. package/lib/esm/queries/QueryBuilder.d.ts +7 -0
  42. package/lib/esm/queries/QueryBuilder.js +40 -3
  43. package/lib/esm/queries/QueryBuilder.js.map +1 -1
  44. package/lib/esm/queries/SelectQuery.js +2 -2
  45. package/lib/esm/queries/SelectQuery.js.map +1 -1
  46. package/lib/esm/queries/UpdateBuilder.d.ts +4 -0
  47. package/lib/esm/queries/UpdateBuilder.js +15 -1
  48. package/lib/esm/queries/UpdateBuilder.js.map +1 -1
  49. package/lib/esm/queries/fromJSON.d.ts +12 -1
  50. package/lib/esm/queries/fromJSON.js +5 -1
  51. package/lib/esm/queries/fromJSON.js.map +1 -1
  52. package/lib/esm/queries/lower.js +12 -5
  53. package/lib/esm/queries/lower.js.map +1 -1
  54. package/lib/esm/queries/queryDependencies.js +14 -10
  55. package/lib/esm/queries/queryDependencies.js.map +1 -1
  56. package/lib/esm/queries/resolveShape.js +14 -2
  57. package/lib/esm/queries/resolveShape.js.map +1 -1
  58. package/lib/esm/shapes/Shape.js +2 -1
  59. package/lib/esm/shapes/Shape.js.map +1 -1
  60. package/lib/esm/shapes/nodeShapeData.js +7 -10
  61. package/lib/esm/shapes/nodeShapeData.js.map +1 -1
  62. package/lib/esm/shapes/registerRuntimeShape.js +3 -1
  63. package/lib/esm/shapes/registerRuntimeShape.js.map +1 -1
  64. package/lib/esm/shapes/syncShapes.d.ts +6 -2
  65. package/lib/esm/shapes/syncShapes.js +16 -9
  66. package/lib/esm/shapes/syncShapes.js.map +1 -1
  67. package/lib/esm/shapes/validation.js +2 -2
  68. package/lib/esm/shapes/validation.js.map +1 -1
  69. package/lib/esm/sparql/irToAlgebra.js +117 -52
  70. package/lib/esm/sparql/irToAlgebra.js.map +1 -1
  71. package/lib/esm/sparql/ownedLinkCheck.js +6 -1
  72. package/lib/esm/sparql/ownedLinkCheck.js.map +1 -1
  73. package/lib/esm/utils/LinkedStorage.d.ts +7 -0
  74. package/lib/esm/utils/LinkedStorage.js +39 -12
  75. package/lib/esm/utils/LinkedStorage.js.map +1 -1
  76. package/lib/esm/utils/ShapeCatalog.d.ts +57 -0
  77. package/lib/esm/utils/ShapeCatalog.js +86 -0
  78. package/lib/esm/utils/ShapeCatalog.js.map +1 -0
  79. package/lib/esm/utils/ShapeClass.d.ts +73 -8
  80. package/lib/esm/utils/ShapeClass.js +245 -66
  81. package/lib/esm/utils/ShapeClass.js.map +1 -1
  82. package/lib/esm/utils/registryCache.d.ts +15 -0
  83. package/lib/esm/utils/registryCache.js +50 -0
  84. package/lib/esm/utils/registryCache.js.map +1 -0
  85. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.35.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#343](https://github.com/linked-fw/core/pull/343) [`84ddff8`](https://github.com/linked-fw/core/commit/84ddff8fc91a773296461da6983237ba1a1f8c31) Thanks [@flyon](https://github.com/flyon)! - ShapeCatalog and withShapeCatalog: build and run queries against a catalog without registering it.
8
+
9
+ `ShapeCatalog.from(shapes, {name})` builds an immutable set of shapes (core's six built-ins always included from core's code); `withShapeCatalog(catalog, fn)` makes it the shapes every registry accessor reads while `fn` runs. Builders, field sets and IRs capture the catalog and re-enter it when they are lowered, compiled or live-tracked later, so one shape IRI can mean different shapes in different catalogs at once. `fromJSON(json, {catalog})` decodes against a catalog; the wire format is unchanged. Registry caches are kept per catalog, and an app that never uses a catalog runs as before.
10
+
11
+ `syncShapes` now also writes core's six built-in shapes (`Shape`, `NodeShape`, `PropertyShape`, `List`, `PathNode`, `PathList`) into the dataset, with the same hash skip as every other shape. The first sync after upgrading writes them once; after that a sync rewrites one only when its hash changes, which happens when processes on different core versions sync the same dataset (each rewrites the built-ins its version describes differently). Under `orphanScope: 'ownedNamespaces'` core's namespace is never pruned. A `ShapeCatalog` ignores built-in rows in its data and resolves the six from code.
12
+
3
13
  ## 2.34.0
4
14
 
5
15
  ### Minor Changes
package/README.md CHANGED
@@ -1246,6 +1246,30 @@ import {lower} from '@_linked/core';
1246
1246
  const ir = lower(CreateBuilder.from(Person).set({name: 'Alice'}));
1247
1247
  ```
1248
1248
 
1249
+ ### Shape catalogs — queries against shapes you do not register
1250
+
1251
+ The shape registry holds one definition per IRI. A host serving several projects (or branches)
1252
+ that share shape IRIs with different properties resolves each query against a `ShapeCatalog`
1253
+ instead:
1254
+
1255
+ ```typescript
1256
+ import {ShapeCatalog, withShapeCatalog, fromJSON} from '@_linked/core';
1257
+
1258
+ const branch = ShapeCatalog.from(nodeShapeWires, {name: 'project-1#main'}); // immutable
1259
+ const query = withShapeCatalog(branch, () =>
1260
+ SelectBuilder.from('https://example.org/shape/Person').select(['name']),
1261
+ );
1262
+ await query; // lowers and compiles against `branch`, though the scope has closed
1263
+
1264
+ const received = fromJSON(json, {catalog: branch}); // the wire never carries a catalog
1265
+ ```
1266
+
1267
+ A builder keeps the catalog it was made in (`catalogOf(query)`), through clones, `exists()`,
1268
+ `count()`, lowering, compile and live queries. Inside a scope every registry read sees the
1269
+ catalog's shapes plus core's six built-ins (always from code, though `syncShapes` writes them
1270
+ into every dataset); a class the catalog does not hold keeps resolving
1271
+ globally. See [runtime instances](./docs/architecture/runtime-instances.md#shape-catalogs).
1272
+
1249
1273
  ### DSL-JSON — the standard query format
1250
1274
 
1251
1275
  Every Linked query — select **and** every mutation — has one canonical, language-neutral form:
@@ -13,7 +13,8 @@ export { SelectBuilder, QueryBuilder } from './queries/QueryBuilder.js';
13
13
  export { lower } from './queries/lower.js';
14
14
  export type { LowerableQuery } from './queries/lower.js';
15
15
  export { fromJSON } from './queries/fromJSON.js';
16
- export type { QueryJSON } from './queries/fromJSON.js';
16
+ export type { QueryJSON, FromJSONOptions } from './queries/fromJSON.js';
17
+ export { ShapeCatalog, withShapeCatalog, getActiveShapeCatalog, catalogOf, shapeCatalogKey, } from './utils/ShapeCatalog.js';
17
18
  export { getQueryContext, setQueryContext, subscribeQueryContext, PendingQueryContext, UnresolvedContextError, } from './queries/QueryContext.js';
18
19
  export { subscribeQueryDispatch } from './queries/queryDispatch.js';
19
20
  export type { QueryDispatchEvent, QueryDispatchListener } from './queries/queryDispatch.js';
package/lib/esm/index.js CHANGED
@@ -20,6 +20,8 @@ export { LinkedStorage } from './utils/LinkedStorage.js';
20
20
  export { SelectBuilder, QueryBuilder } from './queries/QueryBuilder.js';
21
21
  export { lower } from './queries/lower.js';
22
22
  export { fromJSON } from './queries/fromJSON.js';
23
+ // Shape catalogs: resolve queries against a set of shapes without registering them.
24
+ export { ShapeCatalog, withShapeCatalog, getActiveShapeCatalog, catalogOf, shapeCatalogKey, } from './utils/ShapeCatalog.js';
23
25
  export { getQueryContext, setQueryContext, subscribeQueryContext, PendingQueryContext, UnresolvedContextError, } from './queries/QueryContext.js';
24
26
  export { subscribeQueryDispatch } from './queries/queryDispatch.js';
25
27
  export { CONTEXT_REF_KEY, encodeContextRef, isContextRefJSON, resolveContextId, } from './queries/ContextRef.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,0DAA0D;AAC1D,OAAO,mBAAmB,CAAC;AAC3B,8EAA8E;AAC9E,OAAO,WAAW,CAAC;AACnB,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,uBAAuB,EAAC,MAAM,qCAAqC,CAAC;AAC5E,sEAAsE;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACxC,kEAAkE;AAClE,OAAO,EAAC,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAQnF,OAAO,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAC;AACvD,2CAA2C;AAC3C,OAAO,EAAC,aAAa,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAEzC,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAE/C,OAAO,EACL,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAC,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AAElE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAEzE,sBAAsB;AACtB,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAM/C,+BAA+B;AAC/B,OAAO,EAAC,UAAU,EAAE,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAC,YAAY,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAGrE,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAGzD,8CAA8C;AAC9C,OAAO,EAAC,cAAc,EAAC,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAC,IAAI,EAAC,MAAM,uBAAuB,CAAC;AAe3C,sEAAsE;AACtE,OAAO,EACL,cAAc,EACd,WAAW,GACZ,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;AAWxC,0FAA0F;AAC1F,OAAO,EAAC,iBAAiB,EAAE,eAAe,EAAC,MAAM,gCAAgC,CAAC;AAElF,OAAO,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AAEhE,mDAAmD;AACnD,OAAO,EAAC,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAC","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n// Registers every shape core defines (side effects only).\nimport './shapes/index.js';\n// Registers the live-query store so `query.live()` works (side effects only).\nimport './live.js';\nexport {syncShapes, syncShape} from './shapes/syncShapes.js';\nexport type {SyncShapesOptions, SyncShapeOptions} from './shapes/syncShapes.js';\nexport {\n singleOwnerShapeIri,\n singleOwnerProperties,\n buildSingleOwnerConstraints,\n} from './shapes/singleOwnerConstraint.js';\nexport {rdfList} from './shapes/List.js';\nexport {serializePathToNodeData} from './shapes/serializePathToNodeData.js';\n// Core public API surface (documented as root imports in the README).\nexport {Shape} from './shapes/Shape.js';\n// SHACL-aligned validation of plain data objects against a shape.\nexport {validate, assertValid, ShapeValidationError} from './shapes/validation.js';\nexport type {\n ValidationReport,\n ValidationResult,\n ValidationMode,\n ValidateOptions,\n ValidatableShape,\n} from './shapes/validation.js';\nexport {LinkedStorage} from './utils/LinkedStorage.js';\n// New dynamic query building API (Phase 2)\nexport {SelectBuilder, QueryBuilder} from './queries/QueryBuilder.js';\nexport {lower} from './queries/lower.js';\nexport type {LowerableQuery} from './queries/lower.js';\nexport {fromJSON} from './queries/fromJSON.js';\nexport type {QueryJSON} from './queries/fromJSON.js';\nexport {\n getQueryContext,\n setQueryContext,\n subscribeQueryContext,\n PendingQueryContext,\n UnresolvedContextError,\n} from './queries/QueryContext.js';\nexport {subscribeQueryDispatch} from './queries/queryDispatch.js';\nexport type {QueryDispatchEvent, QueryDispatchListener} from './queries/queryDispatch.js';\nexport {\n CONTEXT_REF_KEY,\n encodeContextRef,\n isContextRefJSON,\n resolveContextId,\n} from './queries/ContextRef.js';\nexport type {ContextRefJSON} from './queries/ContextRef.js';\nexport {PropertyPath, walkPropertyPath} from './queries/PropertyPath.js';\n\n// Phase 3a — FieldSet\nexport {FieldSet} from './queries/FieldSet.js';\nexport type {FieldSetEntry, FieldSetInput, FieldSetJSON, FieldSetFieldJSON} from './queries/FieldSet.js';\n\n// Phase 4 — Serialization types\nexport type {QueryBuilderJSON} from './queries/QueryBuilder.js';\n\n// Phase 3b — Mutation builders\nexport {AskBuilder, isAskQuery} from './queries/AskBuilder.js';\nexport type {AskSpec} from './queries/AskBuilder.js';\nexport type {AskQuery, AskQueryJSON, RawAskInput} from './queries/AskQuery.js';\nexport {CountBuilder, isCountQuery} from './queries/CountBuilder.js';\nexport type {CountSpec} from './queries/CountBuilder.js';\nexport type {CountQuery, CountQueryJSON, RawCountInput} from './queries/CountQuery.js';\nexport {CreateBuilder} from './queries/CreateBuilder.js';\nexport {UpdateBuilder} from './queries/UpdateBuilder.js';\nexport {DeleteBuilder} from './queries/DeleteBuilder.js';\nexport type {DeleteId} from './queries/DeleteBuilder.js';\n\n// Expressions — computed fields and functions\nexport {ExpressionNode} from './expressions/ExpressionNode.js';\nexport type {ExpressionInput, PropertyRefMap} from './expressions/ExpressionNode.js';\nexport {Expr} from './expressions/Expr.js';\nexport type {\n ExpressionUpdateProxy,\n ExpressionUpdateResult,\n BaseExpressionMethods,\n NumericExpressionMethods,\n StringExpressionMethods,\n DateExpressionMethods,\n BooleanExpressionMethods,\n} from './expressions/ExpressionMethods.js';\n\n// Phase 5 — Component query integration\nexport type {LinkedComponentInterface, QueryComponentLike} from './queries/SelectQuery.js';\n\n\n// Mutation DSL-JSON serialization (create/update/delete to/from JSON)\nexport {\n encodeNodeData,\n encodeValue,\n} from './queries/MutationSerialization.js';\nexport {\n decodeNodeData,\n lowerMutationJSON,\n} from './queries/lowerMutationJSON.js';\nexport type {\n MutationJSON,\n CreateMutationJSON,\n UpdateMutationJSON,\n DeleteMutationJSON,\n MutationValueJSON,\n MutationNodeDataJSON,\n} from './queries/MutationSerialization.js';\n\n\n// Live-query dependency helpers — what a query reads and a mutation writes, as predicates\nexport {queryDependencies, mutationEffects} from './queries/queryDependencies.js';\nexport type {QueryDependencies, MutationEffects} from './queries/queryDependencies.js';\nexport {findPropertyShapeById} from './shapes/nodeShapeData.js';\n\n// Live queries — see documentation/live-queries.md\nexport {LiveQueryStore, getLiveQueryStore, resetLiveQueryStore, publishChange, invalidate} from './live/LiveQueryStore.js';\nexport type {ChangeEvent} from './live/changes.js';\nexport type {\n LiveQuery,\n LiveState,\n LiveStatus,\n LiveListener,\n LiveQueryOptions,\n LiveQueryStoreOptions,\n} from './live/LiveQueryStore.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,0DAA0D;AAC1D,OAAO,mBAAmB,CAAC;AAC3B,8EAA8E;AAC9E,OAAO,WAAW,CAAC;AACnB,OAAO,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,uBAAuB,EAAC,MAAM,qCAAqC,CAAC;AAC5E,sEAAsE;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACxC,kEAAkE;AAClE,OAAO,EAAC,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAQnF,OAAO,EAAC,aAAa,EAAC,MAAM,0BAA0B,CAAC;AACvD,2CAA2C;AAC3C,OAAO,EAAC,aAAa,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAEzC,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAE/C,oFAAoF;AACpF,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,SAAS,EACT,eAAe,GAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAC,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AAElE,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAEzE,sBAAsB;AACtB,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAC;AAM/C,+BAA+B;AAC/B,OAAO,EAAC,UAAU,EAAE,UAAU,EAAC,MAAM,yBAAyB,CAAC;AAG/D,OAAO,EAAC,YAAY,EAAE,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAGrE,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC;AAGzD,8CAA8C;AAC9C,OAAO,EAAC,cAAc,EAAC,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAC,IAAI,EAAC,MAAM,uBAAuB,CAAC;AAe3C,sEAAsE;AACtE,OAAO,EACL,cAAc,EACd,WAAW,GACZ,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;AAWxC,0FAA0F;AAC1F,OAAO,EAAC,iBAAiB,EAAE,eAAe,EAAC,MAAM,gCAAgC,CAAC;AAElF,OAAO,EAAC,qBAAqB,EAAC,MAAM,2BAA2B,CAAC;AAEhE,mDAAmD;AACnD,OAAO,EAAC,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,0BAA0B,CAAC","sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n */\n// Registers every shape core defines (side effects only).\nimport './shapes/index.js';\n// Registers the live-query store so `query.live()` works (side effects only).\nimport './live.js';\nexport {syncShapes, syncShape} from './shapes/syncShapes.js';\nexport type {SyncShapesOptions, SyncShapeOptions} from './shapes/syncShapes.js';\nexport {\n singleOwnerShapeIri,\n singleOwnerProperties,\n buildSingleOwnerConstraints,\n} from './shapes/singleOwnerConstraint.js';\nexport {rdfList} from './shapes/List.js';\nexport {serializePathToNodeData} from './shapes/serializePathToNodeData.js';\n// Core public API surface (documented as root imports in the README).\nexport {Shape} from './shapes/Shape.js';\n// SHACL-aligned validation of plain data objects against a shape.\nexport {validate, assertValid, ShapeValidationError} from './shapes/validation.js';\nexport type {\n ValidationReport,\n ValidationResult,\n ValidationMode,\n ValidateOptions,\n ValidatableShape,\n} from './shapes/validation.js';\nexport {LinkedStorage} from './utils/LinkedStorage.js';\n// New dynamic query building API (Phase 2)\nexport {SelectBuilder, QueryBuilder} from './queries/QueryBuilder.js';\nexport {lower} from './queries/lower.js';\nexport type {LowerableQuery} from './queries/lower.js';\nexport {fromJSON} from './queries/fromJSON.js';\nexport type {QueryJSON, FromJSONOptions} from './queries/fromJSON.js';\n// Shape catalogs: resolve queries against a set of shapes without registering them.\nexport {\n ShapeCatalog,\n withShapeCatalog,\n getActiveShapeCatalog,\n catalogOf,\n shapeCatalogKey,\n} from './utils/ShapeCatalog.js';\nexport {\n getQueryContext,\n setQueryContext,\n subscribeQueryContext,\n PendingQueryContext,\n UnresolvedContextError,\n} from './queries/QueryContext.js';\nexport {subscribeQueryDispatch} from './queries/queryDispatch.js';\nexport type {QueryDispatchEvent, QueryDispatchListener} from './queries/queryDispatch.js';\nexport {\n CONTEXT_REF_KEY,\n encodeContextRef,\n isContextRefJSON,\n resolveContextId,\n} from './queries/ContextRef.js';\nexport type {ContextRefJSON} from './queries/ContextRef.js';\nexport {PropertyPath, walkPropertyPath} from './queries/PropertyPath.js';\n\n// Phase 3a — FieldSet\nexport {FieldSet} from './queries/FieldSet.js';\nexport type {FieldSetEntry, FieldSetInput, FieldSetJSON, FieldSetFieldJSON} from './queries/FieldSet.js';\n\n// Phase 4 — Serialization types\nexport type {QueryBuilderJSON} from './queries/QueryBuilder.js';\n\n// Phase 3b — Mutation builders\nexport {AskBuilder, isAskQuery} from './queries/AskBuilder.js';\nexport type {AskSpec} from './queries/AskBuilder.js';\nexport type {AskQuery, AskQueryJSON, RawAskInput} from './queries/AskQuery.js';\nexport {CountBuilder, isCountQuery} from './queries/CountBuilder.js';\nexport type {CountSpec} from './queries/CountBuilder.js';\nexport type {CountQuery, CountQueryJSON, RawCountInput} from './queries/CountQuery.js';\nexport {CreateBuilder} from './queries/CreateBuilder.js';\nexport {UpdateBuilder} from './queries/UpdateBuilder.js';\nexport {DeleteBuilder} from './queries/DeleteBuilder.js';\nexport type {DeleteId} from './queries/DeleteBuilder.js';\n\n// Expressions — computed fields and functions\nexport {ExpressionNode} from './expressions/ExpressionNode.js';\nexport type {ExpressionInput, PropertyRefMap} from './expressions/ExpressionNode.js';\nexport {Expr} from './expressions/Expr.js';\nexport type {\n ExpressionUpdateProxy,\n ExpressionUpdateResult,\n BaseExpressionMethods,\n NumericExpressionMethods,\n StringExpressionMethods,\n DateExpressionMethods,\n BooleanExpressionMethods,\n} from './expressions/ExpressionMethods.js';\n\n// Phase 5 — Component query integration\nexport type {LinkedComponentInterface, QueryComponentLike} from './queries/SelectQuery.js';\n\n\n// Mutation DSL-JSON serialization (create/update/delete to/from JSON)\nexport {\n encodeNodeData,\n encodeValue,\n} from './queries/MutationSerialization.js';\nexport {\n decodeNodeData,\n lowerMutationJSON,\n} from './queries/lowerMutationJSON.js';\nexport type {\n MutationJSON,\n CreateMutationJSON,\n UpdateMutationJSON,\n DeleteMutationJSON,\n MutationValueJSON,\n MutationNodeDataJSON,\n} from './queries/MutationSerialization.js';\n\n\n// Live-query dependency helpers — what a query reads and a mutation writes, as predicates\nexport {queryDependencies, mutationEffects} from './queries/queryDependencies.js';\nexport type {QueryDependencies, MutationEffects} from './queries/queryDependencies.js';\nexport {findPropertyShapeById} from './shapes/nodeShapeData.js';\n\n// Live queries — see documentation/live-queries.md\nexport {LiveQueryStore, getLiveQueryStore, resetLiveQueryStore, publishChange, invalidate} from './live/LiveQueryStore.js';\nexport type {ChangeEvent} from './live/changes.js';\nexport type {\n LiveQuery,\n LiveState,\n LiveStatus,\n LiveListener,\n LiveQueryOptions,\n LiveQueryStoreOptions,\n} from './live/LiveQueryStore.js';\n"]}
@@ -1,4 +1,5 @@
1
1
  import { type MutationEffects, type QueryDependencies } from '../queries/queryDependencies.js';
2
+ import type { ShapeCatalog } from '../utils/ShapeCatalog.js';
2
3
  import type { ShapeConstructor } from '../shapes/Shape.js';
3
4
  import { type ChangeEvent, type ChangeOrigin } from './changes.js';
4
5
  import { type InstanceParams, type LiveBuilder, type LiveQueryKind } from './keys.js';
@@ -64,6 +65,11 @@ export interface LiveQuery<R = unknown> extends PromiseLike<R> {
64
65
  export type Template = {
65
66
  key: string;
66
67
  kind: LiveQueryKind;
68
+ /**
69
+ * The catalog the template's queries resolve in (undefined = the global registry). Part
70
+ * of its identity: the same JSON in two catalogs is two templates.
71
+ */
72
+ catalog?: ShapeCatalog;
67
73
  name?: string;
68
74
  json: Record<string, unknown>;
69
75
  /** Subject-stripped builder, used for dependency analysis only. */
@@ -124,6 +130,8 @@ export declare class LiveQueryStore {
124
130
  private readonly _recentChanges;
125
131
  private _pendingRefetch;
126
132
  private _flushScheduled;
133
+ /** How many templates each catalog has; a change is decoded once per catalog listed here. */
134
+ private readonly _catalogTemplates;
127
135
  constructor();
128
136
  /** Register (or find) the template of `query`. Options merge into an existing template. */
129
137
  template(query: LiveBuilder, opts?: LiveQueryOptions): Template;
@@ -190,6 +198,19 @@ export declare class LiveQueryStore {
190
198
  * in quick succession are two changes — and manual invalidations never are.
191
199
  */
192
200
  publish(event: ChangeEvent, origin?: ChangeOrigin): void;
201
+ /**
202
+ * `within` limits the change to one catalog's templates (undefined = the global registry's):
203
+ * a local mutation changes the data of the catalog it was made in, and only that one.
204
+ */
205
+ private _publish;
206
+ /**
207
+ * The effects of a change in the global registry and in each catalog that has
208
+ * templates. A mutation is decoded once per catalog; one that does not resolve in a
209
+ * catalog (its shape is not there) leaves that catalog's templates alone, and effects
210
+ * given as data apply to a catalog only when it holds their shape. Throws only when
211
+ * the change resolves nowhere, as a change that cannot be decoded did before catalogs.
212
+ */
213
+ private _decodePerCatalog;
193
214
  private _scheduleFlush;
194
215
  /**
195
216
  * Local mutations. Select and ask events are ignored: the store's own fetches
@@ -220,6 +241,7 @@ export declare class LiveQueryStore {
220
241
  private _onContextChange;
221
242
  /** Remove an instance from its template (and the template when it is empty and not pinned). */
222
243
  private _dropInstance;
244
+ private _forgetCatalogTemplate;
223
245
  private _scheduleGc;
224
246
  private _cancelGc;
225
247
  }
@@ -17,10 +17,10 @@ import { subscribeQueryContext, UnresolvedContextError } from '../queries/QueryC
17
17
  import { resolveContextId } from '../queries/ContextRef.js';
18
18
  import { subscribeQueryDispatch } from '../queries/queryDispatch.js';
19
19
  import { mutationEffects, queryDependencies, } from '../queries/queryDependencies.js';
20
- import { getShapeClass } from '../utils/ShapeClass.js';
20
+ import { catalogOf, getActiveShapeCatalog, getShapeClass, withShapeCatalog, } from '../utils/ShapeClass.js';
21
21
  import { effectsHash, normalizeChange } from './changes.js';
22
22
  import { selectInstances } from './matcher.js';
23
- import { kindOf, paramsKey, splitQuery, stableStringify, stripSubjects, } from './keys.js';
23
+ import { kindOf, paramsKey, splitQuery, stripSubjects, templateKeyFor, } from './keys.js';
24
24
  import { setLiveQueryStore, peekLiveQueryStore } from './registry.js';
25
25
  const IDLE = Object.freeze({ status: 'pending', notFound: false, refreshing: false });
26
26
  // ---------------------------------------------------------------------------
@@ -48,6 +48,8 @@ export class LiveQueryStore {
48
48
  this._recentChanges = new Map();
49
49
  this._pendingRefetch = new Set();
50
50
  this._flushScheduled = false;
51
+ /** How many templates each catalog has; a change is decoded once per catalog listed here. */
52
+ this._catalogTemplates = new Map();
51
53
  this._disposers.push(subscribeQueryContext((name) => this._onContextChange(name)));
52
54
  this._disposers.push(subscribeQueryDispatch((e) => this._onDispatch(e)));
53
55
  this._disposers.push(LinkedStorage.onRoutingChanged(() => this._onRoutingChanged()));
@@ -61,20 +63,16 @@ export class LiveQueryStore {
61
63
  return this._template(splitQuery(query).templateJson, query, opts);
62
64
  }
63
65
  _template(templateJson, query, opts) {
64
- const key = stableStringify(templateJson);
66
+ var _a;
67
+ const catalog = catalogOf(query);
68
+ const key = templateKeyFor(templateJson, catalog);
65
69
  let t = this._templates.get(key);
66
70
  if (!t) {
67
- t = {
68
- key,
69
- kind: kindOf(query),
70
- json: templateJson,
71
- builder: stripSubjects(query),
72
- shapeIri: typeof templateJson.shape === 'string' ? templateJson.shape : undefined,
73
- reactive: true,
74
- pinned: false,
75
- instances: new Map(),
76
- };
71
+ t = Object.assign(Object.assign({ key, kind: kindOf(query) }, (catalog !== undefined ? { catalog } : {})), { json: templateJson, builder: stripSubjects(query), shapeIri: typeof templateJson.shape === 'string' ? templateJson.shape : undefined, reactive: true, pinned: false, instances: new Map() });
77
72
  this._templates.set(key, t);
73
+ if (catalog !== undefined) {
74
+ this._catalogTemplates.set(catalog, ((_a = this._catalogTemplates.get(catalog)) !== null && _a !== void 0 ? _a : 0) + 1);
75
+ }
78
76
  }
79
77
  if (opts.name !== undefined)
80
78
  t.name = opts.name;
@@ -245,7 +243,7 @@ export class LiveQueryStore {
245
243
  instances.add(i);
246
244
  }
247
245
  else if (typeof target.__queryKind === 'string') {
248
- const t = this._templates.get(stableStringify(splitQuery(target).templateJson));
246
+ const t = this._templates.get(templateKeyFor(splitQuery(target).templateJson, catalogOf(target)));
249
247
  if (t)
250
248
  for (const i of t.instances.values())
251
249
  instances.add(i);
@@ -281,7 +279,17 @@ export class LiveQueryStore {
281
279
  * in quick succession are two changes — and manual invalidations never are.
282
280
  */
283
281
  publish(event, origin = 'app') {
284
- const effects = normalizeChange(event);
282
+ this._publish(event, origin);
283
+ }
284
+ /**
285
+ * `within` limits the change to one catalog's templates (undefined = the global registry's):
286
+ * a local mutation changes the data of the catalog it was made in, and only that one.
287
+ */
288
+ _publish(event, origin, within) {
289
+ const decoded = within
290
+ ? [[within.catalog, normalizeChange(event, { catalog: within.catalog })]]
291
+ : this._decodePerCatalog(event);
292
+ const effects = decoded[0][1];
285
293
  if (origin !== 'manual') {
286
294
  const hash = effectsHash(effects);
287
295
  const now = Date.now();
@@ -297,10 +305,52 @@ export class LiveQueryStore {
297
305
  this._recentChanges.delete(h);
298
306
  }
299
307
  }
300
- for (const inst of selectInstances(this, effects))
301
- this._pendingRefetch.add(inst);
308
+ if (decoded.length === 1 && decoded[0][0] === undefined && this._catalogTemplates.size === 0) {
309
+ for (const inst of selectInstances(this, effects))
310
+ this._pendingRefetch.add(inst);
311
+ }
312
+ else {
313
+ for (const [catalog, e] of decoded) {
314
+ for (const inst of selectInstances(this, e, { catalog }))
315
+ this._pendingRefetch.add(inst);
316
+ }
317
+ }
302
318
  this._scheduleFlush();
303
319
  }
320
+ /**
321
+ * The effects of a change in the global registry and in each catalog that has
322
+ * templates. A mutation is decoded once per catalog; one that does not resolve in a
323
+ * catalog (its shape is not there) leaves that catalog's templates alone, and effects
324
+ * given as data apply to a catalog only when it holds their shape. Throws only when
325
+ * the change resolves nowhere, as a change that cannot be decoded did before catalogs.
326
+ */
327
+ _decodePerCatalog(event) {
328
+ if (this._catalogTemplates.size === 0) {
329
+ return [[undefined, normalizeChange(event, { catalog: undefined })]];
330
+ }
331
+ const out = [];
332
+ let globalError;
333
+ try {
334
+ out.push([undefined, normalizeChange(event, { catalog: undefined })]);
335
+ }
336
+ catch (err) {
337
+ globalError = err;
338
+ }
339
+ for (const catalog of this._catalogTemplates.keys()) {
340
+ try {
341
+ const effects = normalizeChange(event, { catalog });
342
+ if ('effects' in event && !catalog.has(effects.shape))
343
+ continue;
344
+ out.push([catalog, effects]);
345
+ }
346
+ catch (_a) {
347
+ // Not a change to this catalog's shapes.
348
+ }
349
+ }
350
+ if (out.length === 0)
351
+ throw globalError;
352
+ return out;
353
+ }
304
354
  _scheduleFlush() {
305
355
  if (this._flushScheduled)
306
356
  return;
@@ -321,7 +371,12 @@ export class LiveQueryStore {
321
371
  if (e.kind !== 'create' && e.kind !== 'update' && e.kind !== 'delete')
322
372
  return;
323
373
  const query = e.query;
324
- const dataset = (_a = e.target) !== null && _a !== void 0 ? _a : LinkedStorage.getDatasetForShapeClass((((_b = query.shape) === null || _b === void 0 ? void 0 : _b.id) ? getShapeClass(query.shape.id) : undefined));
374
+ // The routing lookup reads the registry, so it runs in the mutation's catalog.
375
+ const catalog = catalogOf(query);
376
+ const shapeClassOf = (id) => catalog === getActiveShapeCatalog()
377
+ ? getShapeClass(id)
378
+ : withShapeCatalog(catalog, () => getShapeClass(id));
379
+ const dataset = (_a = e.target) !== null && _a !== void 0 ? _a : LinkedStorage.getDatasetForShapeClass((((_b = query.shape) === null || _b === void 0 ? void 0 : _b.id) ? shapeClassOf(query.shape.id) : undefined));
325
380
  if (dataset === null || dataset === void 0 ? void 0 : dataset.authoritativeChanges)
326
381
  return; // the dataset's own feed will report it
327
382
  e.result.then((result) => {
@@ -333,7 +388,7 @@ export class LiveQueryStore {
333
388
  console.error('[linked] could not derive the effects of a mutation; live queries were not refetched', err);
334
389
  return;
335
390
  }
336
- this.publish({ effects }, 'local');
391
+ this._publish({ effects }, 'local', { catalog });
337
392
  }, () => { });
338
393
  }
339
394
  /** Subscribe to the change feeds of the datasets currently routed; drop feeds of datasets that left. */
@@ -383,6 +438,7 @@ export class LiveQueryStore {
383
438
  this._dropInstance(i, true);
384
439
  }
385
440
  this._templates.clear();
441
+ this._catalogTemplates.clear();
386
442
  this.templatesByProp.clear();
387
443
  this.templatesByShape.clear();
388
444
  this.instancesById.clear();
@@ -548,8 +604,19 @@ export class LiveQueryStore {
548
604
  if (!keepTemplate && t.instances.size === 0 && !t.pinned) {
549
605
  this._templates.delete(t.key);
550
606
  this._unindexTemplate(t);
607
+ this._forgetCatalogTemplate(t);
551
608
  }
552
609
  }
610
+ _forgetCatalogTemplate(t) {
611
+ var _a;
612
+ if (t.catalog === undefined)
613
+ return;
614
+ const left = ((_a = this._catalogTemplates.get(t.catalog)) !== null && _a !== void 0 ? _a : 1) - 1;
615
+ if (left > 0)
616
+ this._catalogTemplates.set(t.catalog, left);
617
+ else
618
+ this._catalogTemplates.delete(t.catalog);
619
+ }
553
620
  _scheduleGc(inst) {
554
621
  var _a, _b;
555
622
  this._cancelGc(inst);