@_linked/core 2.26.0 → 2.27.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.
- package/CHANGELOG.md +13 -0
- package/README.md +27 -0
- package/lib/esm/index.d.ts +9 -0
- package/lib/esm/index.js +8 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/interfaces/IDataset.d.ts +15 -0
- package/lib/esm/interfaces/IDataset.js.map +1 -1
- package/lib/esm/live/LiveQueryStore.d.ts +240 -0
- package/lib/esm/live/LiveQueryStore.js +729 -0
- package/lib/esm/live/LiveQueryStore.js.map +1 -0
- package/lib/esm/live/changes.d.ts +30 -0
- package/lib/esm/live/changes.js +30 -0
- package/lib/esm/live/changes.js.map +1 -0
- package/lib/esm/live/keys.d.ts +54 -0
- package/lib/esm/live/keys.js +112 -0
- package/lib/esm/live/keys.js.map +1 -0
- package/lib/esm/live/matcher.d.ts +43 -0
- package/lib/esm/live/matcher.js +115 -0
- package/lib/esm/live/matcher.js.map +1 -0
- package/lib/esm/live/registry.d.ts +24 -0
- package/lib/esm/live/registry.js +41 -0
- package/lib/esm/live/registry.js.map +1 -0
- package/lib/esm/live.d.ts +12 -0
- package/lib/esm/live.js +15 -0
- package/lib/esm/live.js.map +1 -0
- package/lib/esm/queries/AskBuilder.d.ts +10 -0
- package/lib/esm/queries/AskBuilder.js +14 -0
- package/lib/esm/queries/AskBuilder.js.map +1 -1
- package/lib/esm/queries/CountBuilder.d.ts +10 -0
- package/lib/esm/queries/CountBuilder.js +14 -0
- package/lib/esm/queries/CountBuilder.js.map +1 -1
- package/lib/esm/queries/QueryBuilder.d.ts +10 -0
- package/lib/esm/queries/QueryBuilder.js +14 -0
- package/lib/esm/queries/QueryBuilder.js.map +1 -1
- package/lib/esm/queries/QueryContext.js +9 -2
- package/lib/esm/queries/QueryContext.js.map +1 -1
- package/lib/esm/queries/queryDependencies.d.ts +58 -0
- package/lib/esm/queries/queryDependencies.js +494 -0
- package/lib/esm/queries/queryDependencies.js.map +1 -0
- package/lib/esm/queries/queryDispatch.d.ts +46 -0
- package/lib/esm/queries/queryDispatch.js +88 -3
- package/lib/esm/queries/queryDispatch.js.map +1 -1
- package/lib/esm/shapes/nodeShapeData.d.ts +16 -0
- package/lib/esm/shapes/nodeShapeData.js +41 -1
- package/lib/esm/shapes/nodeShapeData.js.map +1 -1
- package/lib/esm/sparql/irToAlgebra.js +1 -32
- package/lib/esm/sparql/irToAlgebra.js.map +1 -1
- package/lib/esm/utils/LinkedStorage.d.ts +6 -0
- package/lib/esm/utils/LinkedStorage.js +32 -6
- package/lib/esm/utils/LinkedStorage.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiveQueryStore.js","sourceRoot":"","sources":["../../../src/live/LiveQueryStore.ts"],"names":[],"mappings":";;;;;;;;;AAAA;;;;GAIG;AACH,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAC;AAExD,OAAO,EAAC,qBAAqB,EAAE,sBAAsB,EAAC,MAAM,4BAA4B,CAAC;AACzF,OAAO,EAAC,gBAAgB,EAAC,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAC,sBAAsB,EAA0B,MAAM,6BAA6B,CAAC;AAC5F,OAAO,EACL,eAAe,EACf,iBAAiB,GAGlB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAC,WAAW,EAAE,eAAe,EAAsC,MAAM,cAAc,CAAC;AAC/F,OAAO,EAAC,eAAe,EAAC,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,MAAM,EACN,SAAS,EACT,UAAU,EACV,eAAe,EACf,aAAa,GAId,MAAM,WAAW,CAAC;AACnB,OAAO,EAAC,iBAAiB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAmHpE,MAAM,IAAI,GAAc,MAAM,CAAC,MAAM,CAAC,EAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAC,CAAc,CAAC;AAE5G,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAkBzB;QAjBS,YAAO,GAA0B,EAAC,IAAI,EAAE,KAAM,EAAE,MAAM,EAAE,EAAE,EAAC,CAAC;QAErE,gBAAgB;QACP,eAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;QAClD,oDAAoD;QAC3C,oBAAe,GAAG,IAAI,GAAG,EAAyB,CAAC;QAC5D,gBAAgB;QACP,qBAAgB,GAAG,IAAI,GAAG,EAAyB,CAAC;QAC7D,gBAAgB;QACP,kBAAa,GAAG,IAAI,GAAG,EAAyB,CAAC;QAEzC,eAAU,GAAsB,EAAE,CAAC;QACnC,WAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;QACzC,mBAAc,GAAG,IAAI,GAAG,EAA8C,CAAC;QAChF,oBAAe,GAAG,IAAI,GAAG,EAAY,CAAC;QACtC,oBAAe,GAAG,KAAK,CAAC;QAG9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC;QACrF,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,4EAA4E;IAC5E,YAAY;IACZ,4EAA4E;IAE5E,2FAA2F;IAC3F,QAAQ,CAAC,KAAkB,EAAE,OAAyB,EAAE;QACtD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;IAEO,SAAS,CAAC,YAAqC,EAAE,KAAkB,EAAE,IAAsB;QACjG,MAAM,GAAG,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,CAAC,GAAG;gBACF,GAAG;gBACH,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC;gBACnB,IAAI,EAAE,YAAY;gBAClB,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC;gBAC7B,QAAQ,EAAE,OAAO,YAAY,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,YAAY,CAAC,KAAgB,CAAC,CAAC,CAAC,SAAS;gBAC7F,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,KAAK;gBACb,SAAS,EAAE,IAAI,GAAG,EAAE;aACrB,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAChD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;YAAE,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5D,IAAI,IAAI,CAAC,MAAM;YAAE,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC;QACjC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,gEAAgE;IAChE,SAAS;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAC,CAAC,CAAC,CAAC;IAC5G,CAAC;IAED,iGAAiG;IACjG,OAAO;QACL,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;YAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,QAAkB;QACvB,IAAI,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe;YAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;QACrE,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,GAAG,iBAAiB,CAAC,QAAQ,CAAC,OAAc,CAAC,CAAC;YAC3D,QAAQ,CAAC,eAAe,GAAG,KAAK,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,CAAC,GAAG,YAAY,sBAAsB,CAAC;gBAAE,MAAM,GAAG,CAAC;YACxD,IAAI,QAAQ,CAAC,IAAI;gBAAE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,oBAAoB;YAC7D,QAAQ,CAAC,IAAI,GAAG;gBACd,MAAM,EAAE,IAAI,GAAG,EAAE;gBACjB,MAAM,EAAE,IAAI,GAAG,EAAE;gBACjB,MAAM,EAAE,IAAI,GAAG,EAAE;gBACjB,MAAM,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7D,OAAO,EAAE,KAAK;aACf,CAAC;YACF,QAAQ,CAAC,eAAe,GAAG,IAAI,CAAC;QAClC,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACtB,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IAEO,MAAM,CAAC,CAAW;QACxB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAK,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1D,KAAK,MAAM,CAAC,IAAI,GAAG;gBAAE,UAAU,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,UAAU,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC;IAEO,gBAAgB,CAAC,CAAW;QAClC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE;YAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/D,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE;YAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,4EAA4E;IAC5E,wBAAwB;IACxB,4EAA4E;IAE5E,4FAA4F;IAC5F,QAAQ,CAAC,QAAkB,EAAE,MAAsB,EAAE,OAAoB;QACvE,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC7B,IAAI,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,sDAAsD;YAC7E,IAAI,GAAG;gBACL,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,EAAE;gBAC5B,QAAQ;gBACR,MAAM;gBACN,OAAO;gBACP,KAAK,EAAE,IAAI;gBACX,GAAG,EAAE,CAAC;gBACN,QAAQ,EAAE,KAAK;gBACf,kBAAkB,EAAE,KAAK;gBACzB,GAAG,EAAE,IAAI,GAAG,EAAE;gBACd,SAAS,EAAE,IAAI,GAAG,EAAE;gBACpB,OAAO,EAAE,KAAK;aACf,CAAC;YACF,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAc,KAAkB,EAAE,QAA0B,EAAE,OAAyB,EAAE;QAChG,MAAM,EAAC,YAAY,EAAE,MAAM,EAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAI,IAAI,EAAE,IAAI,CAAC,CAAC;QAClD,IAAI,QAAQ;YAAE,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,kGAAkG;IAClG,QAAQ,CAAC,IAAc;;QACrB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC/B,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,MAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,mCAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzG,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,gBAAgB;IAChB,OAAO,CAAC,IAAc,EAAE,QAAsB;QAC5C,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACtD,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,gBAAgB;IAChB,OAAO,CAAC,IAAc,EAAE,QAAsB;QAC5C,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACzE,CAAC;IAED,2FAA2F;IAC3F,OAAO,CAAC,IAAc;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAc,EAAE,OAAgB;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAChC,MAAM,SAAS,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACpF,MAAM,IAAI,GACR,OAAO,OAAO,KAAK,UAAU;YAC3B,CAAC,CAAE,OAAmC,CAAC,OAAO,CAAC;YAC/C,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC;gBACxC,CAAC,iCAAM,OAAkB,GAAM,OAAkB,EACjD,CAAC,CAAC,OAAO,CAAC;QAChB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,IAAI,CAAC,SAAS,CAAC,IAAI,kCAAM,IAAI,CAAC,KAAK,KAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,KAAK,IAAI,IAAE,CAAC;QACnF,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,MAA8E;;QACvF,IAAI,OAAO,MAAM,KAAK,UAAU,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/D,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAC,MAAkC,CAAC,KAAK,0CAAE,EAAE,CAAC;YAClG,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;YACtF,IAAI,CAAC,OAAO,CAAC,EAAC,OAAO,EAAE,EAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAC,EAAC,EAAE,QAAQ,CAAC,CAAC;YACzH,OAAO;QACT,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAY,CAAC;QACtC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE;gBAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;aAAM,IAAI,OAAQ,MAAiC,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC9E,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,UAAU,CAAC,MAAqB,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;YAC/F,IAAI,CAAC;gBAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE;oBAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;aAAM,IAAI,OAAQ,MAAyB,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC7D,KAAK,MAAM,CAAC,IAAI,MAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAE,MAAuB,CAAC,EAAE,CAAC,mCAAI,EAAE;gBAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9F,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,+FAA+F;IAC/F,WAAW,CAAC,SAA6B;QACvC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO;gBAAE,SAAS,CAAC,yDAAyD;YAClH,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;;gBAC7C,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,iBAAiB;IACjB,4EAA4E;IAE5E;;;;;;;;;OASG;IACH,OAAO,CAAC,KAAkB,EAAE,SAAuB,KAAK;QACtD,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACtG,OAAO,CAAC,uCAAuC;YACjD,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,EAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAC,CAAC,CAAC;YACjD,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC;gBACnC,mFAAmF;gBACnF,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,cAAc;oBAAE,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM;wBAAE,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACjH,CAAC;QACH,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC;YAAE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClF,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAEO,cAAc;QACpB,IAAI,IAAI,CAAC,eAAe;YAAE,OAAO;QACjC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,cAAc,CAAC,GAAG,EAAE;YAClB,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;YAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC;YACnC,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAE,CAAC;YACjC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,WAAW,CAAC,CAAqB;;QACvC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO;QAC9E,MAAM,KAAK,GAAG,CAAC,CAAC,KAAgC,CAAC;QACjD,MAAM,OAAO,GACX,MAAA,CAAC,CAAC,MAAM,mCACR,aAAa,CAAC,uBAAuB,CACnC,CAAC,CAAA,MAAA,KAAK,CAAC,KAAK,0CAAE,EAAE,EAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAyB,CACtF,CAAC;QACJ,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,oBAAoB;YAAE,OAAO,CAAC,wCAAwC;QACnF,CAAC,CAAC,MAAM,CAAC,IAAI,CACX,CAAC,MAAM,EAAE,EAAE;YACT,IAAI,OAAwB,CAAC;YAC7B,IAAI,CAAC;gBACH,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,KAAY,EAAE,MAAM,CAAC,CAAC;YACpD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,sFAAsF,EAAE,GAAG,CAAC,CAAC;gBAC3G,OAAO;YACT,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,EAAC,OAAO,EAAC,EAAE,OAAO,CAAC,CAAC;QACnC,CAAC,EACD,GAAG,EAAE,GAAE,CAAC,CACT,CAAC;IACJ,CAAC;IAED,wGAAwG;IAChG,aAAa;QACnB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAW,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/D,KAAK,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1B,GAAG,EAAE,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;YAC9B,IAAI,OAAO,OAAO,CAAC,gBAAgB,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YACzF,MAAM,GAAG,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC7C,IAAI,CAAC;oBACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gBAC9B,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,KAAK,CAAC,sDAAsD,EAAE,GAAG,CAAC,CAAC;gBAC7E,CAAC;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,iBAAiB;QACvB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAC5B,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;YAC9C,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;gBAC7C,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;oBAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;;oBACnD,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IAED,+EAA+E;IAC/E,KAAK;QACH,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;YAC9C,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;gBAAE,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;IAED,gBAAgB;IAChB,OAAO;QACL,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,UAAU;YAAE,GAAG,EAAE,CAAC;QACzC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;YAAE,GAAG,EAAE,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,4EAA4E;IAC5E,WAAW;IACX,4EAA4E;IAE9D,MAAM,CAAC,IAAc;;YACjC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;YAC5E,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE,IAAI,iBAAiB,EAAE,CAAC;gBACxD,6EAA6E;gBAC7E,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;oBAC7D,IAAI,CAAC,SAAS,CAAC,IAAI,kCAAM,IAAI,CAAC,KAAK,KAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,IAAE,CAAC;gBAC9E,CAAC;gBACD,OAAO;YACT,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,4BAA4B;YAC3F,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;YACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;YAC9C,IAAI,CAAC,SAAS,CAAC,IAAI,kCACd,IAAI,CAAC,KAAK,KACb,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAC/C,UAAU,EAAE,OAAO,IACnB,CAAC;YACH,IAAI,CAAC;gBACH,qEAAqE;gBACrE,sEAAsE;gBACtE,MAAM,IAAI,GAAG,MAAO,IAAI,CAAC,OAAsC,CAAC,IAAI,EAAE,CAAC;gBACvE,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG;oBAAE,OAAO;gBAC7B,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG;oBAAE,OAAO;gBAC7B,IAAI,CAAC,SAAS,CAAC,IAAI,kCACd,IAAI,CAAC,KAAK,KACb,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAC1D,UAAU,EAAE,KAAK,IACjB,CAAC;YACL,CAAC;oBAAS,CAAC;gBACT,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;oBACrB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;oBACtB,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;wBAC5B,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;wBAChC,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;KAAA;IAEO,YAAY,CAAC,IAAc,EAAE,IAAa;QAChD,MAAM,QAAQ,GAAG,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChH,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACxE,oEAAoE;YACpE,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU;gBAAE,IAAI,CAAC,SAAS,CAAC,IAAI,kCAAM,IAAI,CAAC,KAAK,KAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,IAAE,CAAC;YACtG,OAAO;QACT,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAC,CAAC,CAAC;IACjG,CAAC;IAEO,WAAW,CAAC,IAAc,EAAE,IAAa;;QAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtD,KAAK,MAAM,CAAC,IAAI,MAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,mCAAI,EAAE;YAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACvD,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACtB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,GAAG;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,eAAe,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QAC9F,KAAK,MAAM,EAAE,IAAI,GAAG;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,UAAU,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACtF,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAEO,SAAS,CAAC,IAAc,EAAE,KAAgB;QAChD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,CAAC,CAAC,KAAK,CAAC,CAAC;YACX,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,GAAG,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,gBAAgB;IAChB,4EAA4E;IAE5E;;;;OAIG;IACK,gBAAgB,CAAC,IAAY;;QACnC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;YAC9C,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;gBAC7C,IAAI,MAAA,IAAI,CAAC,MAAM,CAAC,YAAY,0CAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC7C,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;wBACtB,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;wBACzB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;oBACjB,CAAC;oBACD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC;wBAAE,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;gBACxD,CAAC;gBACD,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,IAAI;oBAAE,SAAS;gBAC/C,MAAM,MAAM,qBAAuB,IAAI,CAAC,MAAM,CAAC,CAAC;gBAChD,IAAI,QAAQ;oBAAE,MAAM,CAAC,OAAO,GAAG,QAAQ,CAAC;;oBACnC,OAAO,MAAM,CAAC,OAAO,CAAC;gBAC3B,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;oBAAE,SAAS;gBAC3D,+EAA+E;gBAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;gBACpD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBACrB,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;gBACtC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;gBACvB,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,0DAA0D;gBACtE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;gBACpB,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC/B,KAAK,MAAM,CAAC,IAAI,SAAS;oBAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACjD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;oBAC5B,IAAI,CAAC,QAAQ;wBAAE,IAAI,CAAC,SAAS,CAAC,IAAI,oBAAM,IAAI,EAAE,CAAC;yBAC1C,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ;wBAAE,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;;wBAC9E,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,kDAAkD;gBAC3F,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,KAAK;IACL,4EAA4E;IAE5E,+FAA+F;IACvF,aAAa,CAAC,IAAc,EAAE,YAAY,GAAG,KAAK;QACxD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;QACxB,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI;YAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACjG,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,GAAG;YAAE,eAAe,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACzE,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YACzD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,IAAc;;QAChC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrB,0EAA0E;QAC1E,iBAAiB;QACjB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;YACzB,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC;gBAAE,OAAO;YACpC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,MAAA,MAAC,KAA8B,EAAC,KAAK,kDAAI,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAEO,SAAS,CAAC,IAAc;QAC9B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC3B,CAAC;IACH,CAAC;CACF;AAED,8EAA8E;AAC9E,SAAS;AACT,8EAA8E;AAE9E,MAAM,eAAe;IAInB,YACmB,KAAqB,EACtC,IAAc;QADG,UAAK,GAAL,KAAK,CAAgB;QAHvB,UAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;QAM/C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,uFAAuF;IACvF,IAAY,IAAI;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrE,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,IAAI,CAAC,KAAqB,CAAC;IACzC,CAAC;IAED,IAAI,GAAG;QACL,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IACvB,CAAC;IAED,SAAS,CAAC,QAAyB;QACjC,MAAM,CAAC,GAAG,QAAwB,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5B,OAAO,GAAG,EAAE;YACV,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,OAAyC;QAC7C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,KAAK;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,CACF,WAAyD,EACzD,UAA+D;QAE/D,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAC3D,CAAC;IAED,iGAAiG;IACzF,YAAY;QAClB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QACrB,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAS,CAAC,CAAC;QAChE,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACzD,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE;gBAChC,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBAC5B,GAAG,EAAE,CAAC;oBACN,OAAO,CAAC,EAAE,CAAC,IAAS,CAAC,CAAC;gBACxB,CAAC;qBAAM,IAAI,EAAE,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBACjC,GAAG,EAAE,CAAC;oBACN,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,UAAU,CAAO,KAAqB,EAAE,GAAM,EAAE,KAAQ;IAC/D,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,GAAG;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;IAC5C,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED,SAAS,eAAe,CAAO,KAAqB,EAAE,GAAM,EAAE,KAAQ;IACpE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClB,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;QAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,WAAW,IAAK,CAAY,IAAI,SAAS,IAAK,CAAY,CAAC;AACpG,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,IAAiB;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,EAAE,CAAC;QAC1E,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YACtE,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;iBAChD,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,SAAS,CAAC,CAAU,EAAE,CAAU;IAC9C,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC;QAC3C,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;IAC/E,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAClF,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC7D,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAW,CAAC,CAAC;QACpC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAW,CAAC,CAAC;QACpC,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC1C,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAE,CAA6B,CAAC,CAAC,CAAC,EAAG,CAA6B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,0FAA0F;AAC1F,MAAM,UAAU,iBAAiB;IAC/B,IAAI,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,IAAI,cAAc,EAAE,CAAC;QAC7B,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,KAAkB;IAC9C,iBAAiB,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED,uGAAuG;AACvG,MAAM,UAAU,UAAU,CAAC,MAA8E;IACvG,iBAAiB,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC;AAID,kDAAkD;AAClD,MAAM,UAAU,mBAAmB;;IACjC,MAAA,kBAAkB,EAAE,0CAAE,OAAO,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,cAAc,EAAE,CAAC;IACnC,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACzB,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wEAAwE;AACxE,IAAI,CAAC,kBAAkB,EAAE;IAAE,iBAAiB,CAAC,IAAI,cAAc,EAAE,CAAC,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 */\nimport {LinkedStorage} from '../utils/LinkedStorage.js';\nimport type {IDataset} from '../interfaces/IDataset.js';\nimport {subscribeQueryContext, UnresolvedContextError} from '../queries/QueryContext.js';\nimport {resolveContextId} from '../queries/ContextRef.js';\nimport {subscribeQueryDispatch, type QueryDispatchEvent} from '../queries/queryDispatch.js';\nimport {\n mutationEffects,\n queryDependencies,\n type MutationEffects,\n type QueryDependencies,\n} from '../queries/queryDependencies.js';\nimport {getShapeClass} from '../utils/ShapeClass.js';\nimport type {ShapeConstructor} from '../shapes/Shape.js';\nimport {effectsHash, normalizeChange, type ChangeEvent, type ChangeOrigin} from './changes.js';\nimport {selectInstances} from './matcher.js';\nimport {\n kindOf,\n paramsKey,\n splitQuery,\n stableStringify,\n stripSubjects,\n type InstanceParams,\n type LiveBuilder,\n type LiveQueryKind,\n} from './keys.js';\nimport {setLiveQueryStore, peekLiveQueryStore} from './registry.js';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport type LiveStatus = 'pending' | 'loading' | 'success' | 'error';\n\n/**\n * What a live query currently knows.\n *\n * - `pending`: nothing requested yet (no storage configured, or the subject is\n * a query context that has not been set).\n * - `loading`: first request in flight, no data yet.\n * - `success` / `error`: last request settled. On error the previous `data`,\n * if any, is kept so a screen does not go blank over a transient failure.\n * - `refreshing`: a request is in flight while `data` is present.\n * - `notFound`: a single-subject query answered `null`.\n *\n * The object is replaced (never mutated) on every change, so it is safe as a\n * `useSyncExternalStore` snapshot.\n */\nexport type LiveState<R = unknown> = {\n status: LiveStatus;\n data?: R;\n error?: Error;\n notFound: boolean;\n refreshing: boolean;\n};\n\nexport type LiveListener<R = unknown> = (state: LiveState<R>) => void;\n\nexport type LiveQueryOptions = {\n /** Metadata for the template registry (`prepare()`), not identity. */\n name?: string;\n /** `false` opts this template — every query with this exact template — out of automatic invalidation. Default `true`. */\n reactive?: boolean;\n /** A pinned template survives having no instances (component definitions, `prepare()`). */\n pinned?: boolean;\n};\n\n/**\n * The handle returned by `query.live()`.\n *\n * It is `PromiseLike`: `await live` resolves with the first successful `data`\n * (or rejects with the first error) and the handle stays live afterwards. It\n * waits for as long as storage is not configured or a pending query context is\n * not set. Because the handle is thenable, do not `return` it from an `async`\n * function — the promise machinery would unwrap it. `subscribe(cb)` follows\n * the Svelte store contract (returns the unsubscribe function). `close()`\n * detaches every listener added through this handle; the handle can be used\n * again afterwards, which is what React's StrictMode needs.\n */\nexport interface LiveQuery<R = unknown> extends PromiseLike<R> {\n readonly state: LiveState<R>;\n /** Identity of the underlying instance (template key + params). */\n readonly key: string;\n subscribe(listener: LiveListener<R>): () => void;\n /** Refetch now, keeping the current data until the response lands. */\n refresh(): Promise<void>;\n /**\n * Local edit of the cached data, no request; overwritten by the next refetch\n * and visible to every subscriber of the same query. An object merges into\n * object data; an array or a function replaces.\n */\n patch(partial: Partial<R> | ((current: R) => R)): void;\n /** Detach every listener added through this handle. */\n close(): void;\n}\n\nexport type Template = {\n key: string;\n kind: LiveQueryKind;\n name?: string;\n json: Record<string, unknown>;\n /** Subject-stripped builder, used for dependency analysis only. */\n builder: LiveBuilder;\n shapeIri?: string;\n reactive: boolean;\n pinned: boolean;\n deps?: QueryDependencies;\n /** `deps` could not be computed (a query context in `where` is unset); recomputed on the next use. */\n depsProvisional?: boolean;\n instances: Map<string, Instance>;\n};\n\nexport type Instance = {\n key: string;\n template: Template;\n params: InstanceParams;\n /** The bound builder this instance executes (what `.live()` was called on). */\n builder: LiveBuilder;\n state: LiveState;\n /** Sequence of the latest issued request; a response carrying an older sequence is dropped. */\n seq: number;\n inflight: boolean;\n /** Invalidated while a request was in flight: run one more request when it settles. */\n staleWhileInflight: boolean;\n /** Every node id the last result mentions, plus the subject(s). */\n ids: Set<string>;\n listeners: Set<LiveListener>;\n /** Removed from its template (GC, routing change); a handle that still holds it re-resolves on use. */\n dropped: boolean;\n /** Set when a query context re-keyed this instance: handles follow it to the new one. */\n movedTo?: Instance;\n gcTimer?: ReturnType<typeof setTimeout>;\n};\n\nexport type LiveQueryStoreOptions = {\n /** Grace period before an instance with no listeners is dropped. */\n gcMs: number;\n /** Window in which a remote echo of a local change (or the reverse) folds into one refetch. */\n echoMs: number;\n};\n\nconst IDLE: LiveState = Object.freeze({status: 'pending', notFound: false, refreshing: false}) as LiveState;\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\n\n/**\n * Holds every live query in the runtime: templates (what is read) and\n * instances (what it is applied to, and the data). Framework-free; UI layers\n * subscribe to instances. One store per runtime, registered on `globalThis`\n * (see `registry.ts`).\n */\nexport class LiveQueryStore {\n readonly options: LiveQueryStoreOptions = {gcMs: 30_000, echoMs: 50};\n\n /** @internal */\n readonly _templates = new Map<string, Template>();\n /** @internal Indexes read by the change matcher. */\n readonly templatesByProp = new Map<string, Set<Template>>();\n /** @internal */\n readonly templatesByShape = new Map<string, Set<Template>>();\n /** @internal */\n readonly instancesById = new Map<string, Set<Instance>>();\n\n private readonly _disposers: Array<() => void> = [];\n private readonly _feeds = new Map<IDataset, () => void>();\n private readonly _recentChanges = new Map<string, {at: number; origin: ChangeOrigin}>();\n private _pendingRefetch = new Set<Instance>();\n private _flushScheduled = false;\n\n constructor() {\n this._disposers.push(subscribeQueryContext((name) => this._onContextChange(name)));\n this._disposers.push(subscribeQueryDispatch((e) => this._onDispatch(e)));\n this._disposers.push(LinkedStorage.onRoutingChanged(() => this._onRoutingChanged()));\n this._scanDatasets();\n }\n\n // -------------------------------------------------------------------------\n // Templates\n // -------------------------------------------------------------------------\n\n /** Register (or find) the template of `query`. Options merge into an existing template. */\n template(query: LiveBuilder, opts: LiveQueryOptions = {}): Template {\n return this._template(splitQuery(query).templateJson, query, opts);\n }\n\n private _template(templateJson: Record<string, unknown>, query: LiveBuilder, opts: LiveQueryOptions): Template {\n const key = stableStringify(templateJson);\n let t = this._templates.get(key);\n if (!t) {\n t = {\n key,\n kind: kindOf(query),\n json: templateJson,\n builder: stripSubjects(query),\n shapeIri: typeof templateJson.shape === 'string' ? (templateJson.shape as string) : undefined,\n reactive: true,\n pinned: false,\n instances: new Map(),\n };\n this._templates.set(key, t);\n }\n if (opts.name !== undefined) t.name = opts.name;\n if (opts.reactive !== undefined) t.reactive = opts.reactive;\n if (opts.pinned) t.pinned = true;\n return t;\n }\n\n /** The registered templates (for database tuning, devtools). */\n templates(): ReadonlyArray<{key: string; kind: LiveQueryKind; name?: string; json: Record<string, unknown>}> {\n return [...this._templates.values()].map((t) => ({key: t.key, kind: t.kind, name: t.name, json: t.json}));\n }\n\n /** Compute the dependencies of every template now (they are otherwise computed on first use). */\n prepare(): void {\n for (const t of this._templates.values()) this.depsOf(t);\n }\n\n /**\n * The watch set of a template, computed once. When a query context used in\n * `where` is not set yet, lowering throws; the template then gets provisional\n * dependencies (its shape only) and is recomputed on its next use, which the\n * context change triggers.\n */\n depsOf(template: Template): QueryDependencies {\n if (template.deps && !template.depsProvisional) return template.deps;\n try {\n template.deps = queryDependencies(template.builder as any);\n template.depsProvisional = false;\n } catch (err) {\n if (!(err instanceof UnresolvedContextError)) throw err;\n if (template.deps) return template.deps; // still provisional\n template.deps = {\n narrow: new Set(),\n filter: new Set(),\n hidden: new Set(),\n shapes: new Set(template.shapeIri ? [template.shapeIri] : []),\n unbound: false,\n };\n template.depsProvisional = true;\n }\n this._index(template);\n return template.deps;\n }\n\n private _index(t: Template): void {\n const deps = t.deps!;\n for (const set of [deps.narrow, deps.filter, deps.hidden]) {\n for (const p of set) addToIndex(this.templatesByProp, p, t);\n }\n for (const s of deps.shapes) addToIndex(this.templatesByShape, s, t);\n }\n\n private _unindexTemplate(t: Template): void {\n for (const set of this.templatesByProp.values()) set.delete(t);\n for (const set of this.templatesByShape.values()) set.delete(t);\n }\n\n // -------------------------------------------------------------------------\n // Instances and handles\n // -------------------------------------------------------------------------\n\n /** @internal Get or create the instance of `template` for `params`, executing `builder`. */\n instance(template: Template, params: InstanceParams, builder: LiveBuilder): Instance {\n const pk = paramsKey(params);\n let inst = template.instances.get(pk);\n if (!inst) {\n this.depsOf(template); // index the template before its first instance exists\n inst = {\n key: `${template.key}|${pk}`,\n template,\n params,\n builder,\n state: IDLE,\n seq: 0,\n inflight: false,\n staleWhileInflight: false,\n ids: new Set(),\n listeners: new Set(),\n dropped: false,\n };\n template.instances.set(pk, inst);\n }\n return inst;\n }\n\n /**\n * Subscribe to `query`. The first listener on an instance starts its fetch;\n * identical queries share one instance and one request. A handle created\n * without a listener holds nothing: its instance is released after the grace\n * period unless something subscribes.\n */\n subscribe<R = unknown>(query: LiveBuilder, listener?: LiveListener<R>, opts: LiveQueryOptions = {}): LiveQuery<R> {\n const {templateJson, params} = splitQuery(query);\n const template = this._template(templateJson, query, opts);\n const inst = this.instance(template, params, query);\n if (inst.listeners.size === 0) this._scheduleGc(inst);\n const handle = new LiveQueryHandle<R>(this, inst);\n if (listener) handle.subscribe(listener);\n return handle;\n }\n\n /** @internal The live instance for a possibly dropped one (same template, params and builder). */\n _resolve(inst: Instance): Instance {\n if (!inst.dropped) return inst;\n if (inst.movedTo) return this._resolve(inst.movedTo);\n const t = this._templates.get(inst.template.key) ?? this._template(inst.template.json, inst.builder, {});\n return this.instance(t, inst.params, inst.builder);\n }\n\n /** @internal */\n _attach(inst: Instance, listener: LiveListener): void {\n this._cancelGc(inst);\n inst.listeners.add(listener);\n if (inst.state.status === 'pending' && !inst.inflight) {\n void this._fetch(inst);\n }\n }\n\n /** @internal */\n _detach(inst: Instance, listener: LiveListener): void {\n inst.listeners.delete(listener);\n if (inst.listeners.size === 0 && !inst.dropped) this._scheduleGc(inst);\n }\n\n /** Refetch an instance, keeping its data on screen. Resolves when that request settles. */\n refresh(inst: Instance): Promise<void> {\n return this._fetch(inst);\n }\n\n /**\n * Local edit of an instance's data. Never touches the store. A patched\n * instance counts as loaded (`success`), so `await live` resolves with it.\n */\n patch(inst: Instance, partial: unknown): void {\n const current = inst.state.data;\n const mergeable = (v: unknown) => !!v && typeof v === 'object' && !Array.isArray(v);\n const next =\n typeof partial === 'function'\n ? (partial as (c: unknown) => unknown)(current)\n : mergeable(current) && mergeable(partial)\n ? {...(current as object), ...(partial as object)}\n : partial;\n const status = inst.state.status === 'error' ? 'error' : 'success';\n this._setState(inst, {...inst.state, status, data: next, notFound: next === null});\n this._collectIds(inst, next);\n }\n\n /**\n * Refetch every instance matching `target`: a shape class or shape IRI\n * (everything that scans or traverses it, as after a delete), a node\n * reference (`{id}`), a query (its template), or a template. Never folded\n * with other change events.\n */\n invalidate(target: ShapeConstructor<any> | string | {id: string} | LiveBuilder | Template): void {\n if (typeof target === 'function' || typeof target === 'string') {\n const shape = typeof target === 'string' ? target : (target as {shape?: {id?: string}}).shape?.id;\n if (!shape) throw new Error('invalidate(): the shape class has no registered shape.');\n this.publish({effects: {op: 'delete', shape, props: new Set(), ids: undefined, membership: new Set([shape])}}, 'manual');\n return;\n }\n const instances = new Set<Instance>();\n if (isTemplate(target)) {\n for (const i of target.instances.values()) instances.add(i);\n } else if (typeof (target as {__queryKind?: string}).__queryKind === 'string') {\n const t = this._templates.get(stableStringify(splitQuery(target as LiveBuilder).templateJson));\n if (t) for (const i of t.instances.values()) instances.add(i);\n } else if (typeof (target as {id?: unknown}).id === 'string') {\n for (const i of this.instancesById.get((target as {id: string}).id) ?? []) instances.add(i);\n }\n this._refetchAll(instances);\n }\n\n /** @internal Refetch a set of instances, folding in-flight ones into one follow-up request. */\n _refetchAll(instances: Iterable<Instance>): void {\n for (const inst of instances) {\n if (inst.listeners.size === 0 || inst.dropped) continue; // nobody is watching; it refetches when subscribed again\n if (inst.inflight) inst.staleWhileInflight = true;\n else void this._fetch(inst);\n }\n }\n\n // -------------------------------------------------------------------------\n // Change sources\n // -------------------------------------------------------------------------\n\n /**\n * Tell the store that data changed. Every source ends here: local mutations\n * (automatically, origin `local`), dataset change feeds (`feed`), application\n * code via `publishChange()` (`app`) and `invalidate()` (`manual`).\n *\n * A local change and its remote confirmation carry identical effects; when\n * they arrive within `options.echoMs` of each other they refetch once. Two\n * events of the same origin are never folded — two writes to the same node\n * in quick succession are two changes — and manual invalidations never are.\n */\n publish(event: ChangeEvent, origin: ChangeOrigin = 'app'): void {\n const effects = normalizeChange(event);\n if (origin !== 'manual') {\n const hash = effectsHash(effects);\n const now = Date.now();\n const prev = this._recentChanges.get(hash);\n if (prev && prev.origin !== 'manual' && prev.origin !== origin && now - prev.at < this.options.echoMs) {\n return; // the echo of a change already applied\n }\n this._recentChanges.set(hash, {at: now, origin});\n if (this._recentChanges.size > 256) {\n // Bounded: anything older than the echo window can no longer fold with a newcomer.\n for (const [h, r] of this._recentChanges) if (now - r.at >= this.options.echoMs) this._recentChanges.delete(h);\n }\n }\n for (const inst of selectInstances(this, effects)) this._pendingRefetch.add(inst);\n this._scheduleFlush();\n }\n\n private _scheduleFlush(): void {\n if (this._flushScheduled) return;\n this._flushScheduled = true;\n queueMicrotask(() => {\n this._flushScheduled = false;\n const batch = this._pendingRefetch;\n this._pendingRefetch = new Set();\n this._refetchAll(batch);\n });\n }\n\n /**\n * Local mutations. Select and ask events are ignored: the store's own fetches\n * run through the same dispatch and must not feed back into it.\n */\n private _onDispatch(e: QueryDispatchEvent): void {\n if (e.kind !== 'create' && e.kind !== 'update' && e.kind !== 'delete') return;\n const query = e.query as {shape?: {id?: string}};\n const dataset =\n e.target ??\n LinkedStorage.getDatasetForShapeClass(\n (query.shape?.id ? getShapeClass(query.shape.id) : undefined) as Function | undefined,\n );\n if (dataset?.authoritativeChanges) return; // the dataset's own feed will report it\n e.result.then(\n (result) => {\n let effects: MutationEffects;\n try {\n effects = mutationEffects(e.query as any, result);\n } catch (err) {\n console.error('[linked] could not derive the effects of a mutation; live queries were not refetched', err);\n return;\n }\n this.publish({effects}, 'local');\n },\n () => {}, // a failed mutation changed nothing\n );\n }\n\n /** Subscribe to the change feeds of the datasets currently routed; drop feeds of datasets that left. */\n private _scanDatasets(): void {\n const current = new Set<IDataset>(LinkedStorage.getDatasets());\n for (const [dataset, off] of [...this._feeds]) {\n if (!current.has(dataset)) {\n off();\n this._feeds.delete(dataset);\n }\n }\n for (const dataset of current) {\n if (typeof dataset.subscribeChanges !== 'function' || this._feeds.has(dataset)) continue;\n const off = dataset.subscribeChanges((event) => {\n try {\n this.publish(event, 'feed');\n } catch (err) {\n console.error('[linked] a dataset change event could not be applied', err);\n }\n });\n this._feeds.set(dataset, off);\n }\n }\n\n /**\n * Storage changed (a dataset was set, pinned or unpinned): what is cached may\n * come from a store that no longer answers, so instances nobody watches are\n * dropped and watched ones fetch again. Also refreshes the feed subscriptions.\n */\n private _onRoutingChanged(): void {\n this._scanDatasets();\n this._recentChanges.clear();\n for (const t of [...this._templates.values()]) {\n for (const inst of [...t.instances.values()]) {\n if (inst.listeners.size === 0) this._dropInstance(inst);\n else this._refetchAll([inst]);\n }\n }\n }\n\n /** Drop every template and instance (tests). Subscriptions to sources stay. */\n reset(): void {\n for (const t of [...this._templates.values()]) {\n for (const i of [...t.instances.values()]) this._dropInstance(i, true);\n }\n this._templates.clear();\n this.templatesByProp.clear();\n this.templatesByShape.clear();\n this.instancesById.clear();\n this._recentChanges.clear();\n this._pendingRefetch.clear();\n }\n\n /** @internal */\n dispose(): void {\n this.reset();\n for (const off of this._disposers) off();\n for (const off of this._feeds.values()) off();\n this._feeds.clear();\n }\n\n // -------------------------------------------------------------------------\n // Fetching\n // -------------------------------------------------------------------------\n\n private async _fetch(inst: Instance): Promise<void> {\n const unresolvedSubject = !!inst.params.contextName && !inst.params.subject;\n if (!LinkedStorage.isInitialised() || unresolvedSubject) {\n // Nothing to request yet. Stay quiet if that is already what listeners know.\n if (inst.state.status !== 'pending' || inst.state.refreshing) {\n this._setState(inst, {...inst.state, status: 'pending', refreshing: false});\n }\n return;\n }\n if (inst.template.depsProvisional) this.depsOf(inst.template); // a context may have landed\n const seq = ++inst.seq;\n inst.inflight = true;\n const hasData = inst.state.data !== undefined;\n this._setState(inst, {\n ...inst.state,\n status: hasData ? inst.state.status : 'loading',\n refreshing: hasData,\n });\n try {\n // `exec()` is the same path `await query` takes: dispatch, count/ask\n // contracts, error wrapping. The store adds nothing of its own to it.\n const data = await (inst.builder as {exec(): Promise<unknown>}).exec();\n if (seq !== inst.seq) return;\n this._applyResult(inst, data);\n } catch (err) {\n if (seq !== inst.seq) return;\n this._setState(inst, {\n ...inst.state,\n status: 'error',\n error: err instanceof Error ? err : new Error(String(err)),\n refreshing: false,\n });\n } finally {\n if (seq === inst.seq) {\n inst.inflight = false;\n if (inst.staleWhileInflight) {\n inst.staleWhileInflight = false;\n void this._fetch(inst);\n }\n }\n }\n }\n\n private _applyResult(inst: Instance, data: unknown): void {\n const notFound = data === null && inst.template.kind === 'select' && !!(inst.params.subject || inst.params.one);\n if (inst.state.status === 'success' && deepEqual(inst.state.data, data)) {\n // Structural sharing: same data, keep the reference and stay quiet.\n if (inst.state.refreshing) this._setState(inst, {...inst.state, refreshing: false, error: undefined});\n return;\n }\n this._collectIds(inst, data);\n this._setState(inst, {status: 'success', data, error: undefined, notFound, refreshing: false});\n }\n\n private _collectIds(inst: Instance, data: unknown): void {\n const ids = new Set<string>();\n if (inst.params.subject) ids.add(inst.params.subject);\n for (const s of inst.params.subjects ?? []) ids.add(s);\n collectIds(data, ids);\n for (const old of inst.ids) if (!ids.has(old)) removeFromIndex(this.instancesById, old, inst);\n for (const id of ids) if (!inst.ids.has(id)) addToIndex(this.instancesById, id, inst);\n inst.ids = ids;\n }\n\n private _setState(inst: Instance, state: LiveState): void {\n inst.state = state;\n for (const l of [...inst.listeners]) {\n try {\n l(state);\n } catch (err) {\n console.error('[linked] live query listener failed', err);\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // Query context\n // -------------------------------------------------------------------------\n\n /**\n * A query context changed. An instance whose *subject* is that context is\n * re-keyed to the new id (the builder resolves the context lazily, so it is\n * reused); an instance that references it in `where` just fetches again.\n */\n private _onContextChange(name: string): void {\n const resolved = resolveContextId(name, false);\n for (const t of [...this._templates.values()]) {\n for (const inst of [...t.instances.values()]) {\n if (inst.params.contextNames?.includes(name)) {\n if (t.depsProvisional) {\n this._unindexTemplate(t);\n this.depsOf(t);\n }\n if (inst.listeners.size > 0) this._refetchAll([inst]);\n }\n if (inst.params.contextName !== name) continue;\n const params: InstanceParams = {...inst.params};\n if (resolved) params.subject = resolved;\n else delete params.subject;\n if (paramsKey(params) === paramsKey(inst.params)) continue;\n // Move the listeners to the instance for the new subject and drop the old one.\n const next = this.instance(t, params, inst.builder);\n this._cancelGc(next);\n const listeners = [...inst.listeners];\n inst.listeners.clear();\n inst.seq++; // any in-flight response for the old subject is now stale\n inst.movedTo = next;\n this._dropInstance(inst, true);\n for (const l of listeners) next.listeners.add(l);\n if (next.listeners.size > 0) {\n if (!resolved) this._setState(next, {...IDLE});\n else if (next.state.status === 'pending' && !next.inflight) void this._fetch(next);\n else this._setState(next, next.state); // publish the cached state to the moved listeners\n } else {\n this._scheduleGc(next);\n }\n }\n }\n }\n\n // -------------------------------------------------------------------------\n // GC\n // -------------------------------------------------------------------------\n\n /** Remove an instance from its template (and the template when it is empty and not pinned). */\n private _dropInstance(inst: Instance, keepTemplate = false): void {\n this._cancelGc(inst);\n inst.dropped = true;\n const t = inst.template;\n if (t.instances.get(paramsKey(inst.params)) === inst) t.instances.delete(paramsKey(inst.params));\n for (const id of inst.ids) removeFromIndex(this.instancesById, id, inst);\n if (!keepTemplate && t.instances.size === 0 && !t.pinned) {\n this._templates.delete(t.key);\n this._unindexTemplate(t);\n }\n }\n\n private _scheduleGc(inst: Instance): void {\n this._cancelGc(inst);\n // `unref` so a pending grace period never keeps a Node process (or a test\n // runner) alive.\n const timer = setTimeout(() => {\n inst.gcTimer = undefined;\n if (inst.listeners.size > 0) return;\n this._dropInstance(inst);\n }, this.options.gcMs);\n (timer as {unref?: () => void}).unref?.();\n inst.gcTimer = timer;\n }\n\n private _cancelGc(inst: Instance): void {\n if (inst.gcTimer) {\n clearTimeout(inst.gcTimer);\n inst.gcTimer = undefined;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Handle\n// ---------------------------------------------------------------------------\n\nclass LiveQueryHandle<R> implements LiveQuery<R> {\n private _inst: Instance;\n private readonly _mine = new Set<LiveListener>();\n\n constructor(\n private readonly store: LiveQueryStore,\n inst: Instance,\n ) {\n this._inst = inst;\n }\n\n /** The current instance, re-resolved if the store dropped the one this handle held. */\n private get inst(): Instance {\n if (this._inst.dropped) this._inst = this.store._resolve(this._inst);\n return this._inst;\n }\n\n get state(): LiveState<R> {\n return this.inst.state as LiveState<R>;\n }\n\n get key(): string {\n return this.inst.key;\n }\n\n subscribe(listener: LiveListener<R>): () => void {\n const l = listener as LiveListener;\n const inst = this.inst;\n this._mine.add(l);\n this.store._attach(inst, l);\n return () => {\n if (this._mine.delete(l)) this.store._detach(inst, l);\n };\n }\n\n refresh(): Promise<void> {\n return this.store.refresh(this.inst);\n }\n\n patch(partial: Partial<R> | ((current: R) => R)): void {\n this.store.patch(this.inst, partial);\n }\n\n close(): void {\n const inst = this._inst;\n for (const l of this._mine) this.store._detach(inst, l);\n this._mine.clear();\n }\n\n then<T1 = R, T2 = never>(\n onfulfilled?: ((value: R) => T1 | PromiseLike<T1>) | null,\n onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null,\n ): Promise<T1 | T2> {\n return this._firstResult().then(onfulfilled, onrejected);\n }\n\n /** Resolves with the first successful data; the subscription it needs is released afterwards. */\n private _firstResult(): Promise<R> {\n const s = this.state;\n if (s.status === 'success') return Promise.resolve(s.data as R);\n if (s.status === 'error') return Promise.reject(s.error);\n return new Promise<R>((resolve, reject) => {\n const off = this.subscribe((st) => {\n if (st.status === 'success') {\n off();\n resolve(st.data as R);\n } else if (st.status === 'error') {\n off();\n reject(st.error);\n }\n });\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction addToIndex<K, V>(index: Map<K, Set<V>>, key: K, value: V): void {\n let set = index.get(key);\n if (!set) index.set(key, (set = new Set()));\n set.add(value);\n}\n\nfunction removeFromIndex<K, V>(index: Map<K, Set<V>>, key: K, value: V): void {\n const set = index.get(key);\n if (!set) return;\n set.delete(value);\n if (set.size === 0) index.delete(key);\n}\n\nfunction isTemplate(v: unknown): v is Template {\n return !!v && typeof v === 'object' && 'instances' in (v as object) && 'builder' in (v as object);\n}\n\n/** Every string value under an `id` key, at any depth. */\nexport function collectIds(value: unknown, into: Set<string>): Set<string> {\n if (Array.isArray(value)) {\n for (const v of value) collectIds(v, into);\n } else if (value && typeof value === 'object' && !(value instanceof Date)) {\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k === 'id' && typeof v === 'string') into.add(v);\n else if (v && typeof v === 'object') collectIds(v, into);\n }\n }\n return into;\n}\n\n/** Deep equality over the plain-data results the store holds (objects, arrays, dates, primitives). */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a instanceof Date || b instanceof Date) {\n return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();\n }\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n return a.every((v, i) => deepEqual(v, b[i]));\n }\n if (a && b && typeof a === 'object' && typeof b === 'object') {\n const ka = Object.keys(a as object);\n const kb = Object.keys(b as object);\n if (ka.length !== kb.length) return false;\n return ka.every((k) => deepEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k]));\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Registration\n// ---------------------------------------------------------------------------\n\n/** The runtime's live-query store (registered on `globalThis` when this module loads). */\nexport function getLiveQueryStore(): LiveQueryStore {\n let store = peekLiveQueryStore();\n if (!store) {\n store = new LiveQueryStore();\n setLiveQueryStore(store);\n }\n return store;\n}\n\n/** Publish a change from application code (your own transport, a server push). */\nexport function publishChange(event: ChangeEvent): void {\n getLiveQueryStore().publish(event, 'app');\n}\n\n/** Refetch every live query that `target` can have affected. See {@link LiveQueryStore.invalidate}. */\nexport function invalidate(target: ShapeConstructor<any> | string | {id: string} | LiveBuilder | Template): void {\n getLiveQueryStore().invalidate(target);\n}\n\nexport type {ChangeEvent, ChangeOrigin, MutationEffects};\n\n/** Replace the store with a fresh one (tests). */\nexport function resetLiveQueryStore(): LiveQueryStore {\n peekLiveQueryStore()?.dispose();\n const store = new LiveQueryStore();\n setLiveQueryStore(store);\n return store;\n}\n\n// Register on load: importing this module is what makes `.live()` work.\nif (!peekLiveQueryStore()) setLiveQueryStore(new LiveQueryStore());\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type MutationEffects } from '../queries/queryDependencies.js';
|
|
2
|
+
import type { MutationJSON } from '../queries/MutationSerialization.js';
|
|
3
|
+
/**
|
|
4
|
+
* A change in the data, from any source, in one of two forms:
|
|
5
|
+
*
|
|
6
|
+
* - `{mutation, result?}` — the mutation's DSL-JSON (what a server already has
|
|
7
|
+
* when it executed it) and, if known, the result it produced. The receiving
|
|
8
|
+
* runtime computes the effects itself with `mutationEffects`.
|
|
9
|
+
* - `{effects}` — precomputed {@link MutationEffects}, for producers that
|
|
10
|
+
* already know what changed.
|
|
11
|
+
*
|
|
12
|
+
* Both are plain data, so they cross a serialization boundary unchanged. Local
|
|
13
|
+
* mutations, dataset change feeds (`IDataset.subscribeChanges`) and
|
|
14
|
+
* `publishChange()` all speak this type.
|
|
15
|
+
*/
|
|
16
|
+
export type ChangeEvent = {
|
|
17
|
+
effects: MutationEffects;
|
|
18
|
+
} | {
|
|
19
|
+
mutation: MutationJSON;
|
|
20
|
+
result?: unknown;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Where a change event came from. Only used to fold a remote echo (`feed`,
|
|
24
|
+
* `app`) onto the local original of the same change, or the reverse; two local
|
|
25
|
+
* events are never folded, and `manual` (`invalidate()`) is never folded.
|
|
26
|
+
*/
|
|
27
|
+
export type ChangeOrigin = 'local' | 'feed' | 'app' | 'manual';
|
|
28
|
+
export declare function normalizeChange(event: ChangeEvent): MutationEffects;
|
|
29
|
+
/** A stable fingerprint of an effects object, used to fold a local change and its remote echo into one. */
|
|
30
|
+
export declare function effectsHash(e: MutationEffects): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
import { fromJSON } from '../queries/fromJSON.js';
|
|
7
|
+
import { mutationEffects } from '../queries/queryDependencies.js';
|
|
8
|
+
export function normalizeChange(event) {
|
|
9
|
+
if ('effects' in event)
|
|
10
|
+
return reviveEffects(event.effects);
|
|
11
|
+
const builder = fromJSON(event.mutation);
|
|
12
|
+
return mutationEffects(builder, event.result);
|
|
13
|
+
}
|
|
14
|
+
/** Accept effects whose sets arrived as arrays (e.g. after JSON transport). */
|
|
15
|
+
function reviveEffects(e) {
|
|
16
|
+
const toSet = (v) => (v instanceof Set ? v : new Set(Array.isArray(v) ? v : []));
|
|
17
|
+
return {
|
|
18
|
+
op: e.op,
|
|
19
|
+
shape: e.shape,
|
|
20
|
+
props: toSet(e.props),
|
|
21
|
+
ids: e.ids === undefined ? undefined : toSet(e.ids),
|
|
22
|
+
membership: toSet(e.membership),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** A stable fingerprint of an effects object, used to fold a local change and its remote echo into one. */
|
|
26
|
+
export function effectsHash(e) {
|
|
27
|
+
const sorted = (s) => [...s].sort().join(',');
|
|
28
|
+
return `${e.op}|${e.shape}|${sorted(e.props)}|${e.ids ? sorted(e.ids) : '*'}|${sorted(e.membership)}`;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=changes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changes.js","sourceRoot":"","sources":["../../../src/live/changes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAC,eAAe,EAAuB,MAAM,iCAAiC,CAAC;AA2BtF,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,IAAI,SAAS,IAAI,KAAK;QAAE,OAAO,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAe,CAAQ,CAAC;IACvD,OAAO,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,+EAA+E;AAC/E,SAAS,aAAa,CAAC,CAAkB;IACvC,MAAM,KAAK,GAAG,CAAC,CAAU,EAAe,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrH,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QACrB,GAAG,EAAE,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;QACnD,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,WAAW,CAAC,CAAkB;IAC5C,MAAM,MAAM,GAAG,CAAC,CAAc,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3D,OAAO,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;AACxG,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 */\nimport {fromJSON} from '../queries/fromJSON.js';\nimport {mutationEffects, type MutationEffects} from '../queries/queryDependencies.js';\nimport type {MutationJSON} from '../queries/MutationSerialization.js';\n\n/**\n * A change in the data, from any source, in one of two forms:\n *\n * - `{mutation, result?}` — the mutation's DSL-JSON (what a server already has\n * when it executed it) and, if known, the result it produced. The receiving\n * runtime computes the effects itself with `mutationEffects`.\n * - `{effects}` — precomputed {@link MutationEffects}, for producers that\n * already know what changed.\n *\n * Both are plain data, so they cross a serialization boundary unchanged. Local\n * mutations, dataset change feeds (`IDataset.subscribeChanges`) and\n * `publishChange()` all speak this type.\n */\nexport type ChangeEvent =\n | {effects: MutationEffects}\n | {mutation: MutationJSON; result?: unknown};\n\n/**\n * Where a change event came from. Only used to fold a remote echo (`feed`,\n * `app`) onto the local original of the same change, or the reverse; two local\n * events are never folded, and `manual` (`invalidate()`) is never folded.\n */\nexport type ChangeOrigin = 'local' | 'feed' | 'app' | 'manual';\n\nexport function normalizeChange(event: ChangeEvent): MutationEffects {\n if ('effects' in event) return reviveEffects(event.effects);\n const builder = fromJSON(event.mutation as any) as any;\n return mutationEffects(builder, event.result);\n}\n\n/** Accept effects whose sets arrived as arrays (e.g. after JSON transport). */\nfunction reviveEffects(e: MutationEffects): MutationEffects {\n const toSet = (v: unknown): Set<string> => (v instanceof Set ? v : new Set(Array.isArray(v) ? (v as string[]) : []));\n return {\n op: e.op,\n shape: e.shape,\n props: toSet(e.props),\n ids: e.ids === undefined ? undefined : toSet(e.ids),\n membership: toSet(e.membership),\n };\n}\n\n/** A stable fingerprint of an effects object, used to fold a local change and its remote echo into one. */\nexport function effectsHash(e: MutationEffects): string {\n const sorted = (s: Set<string>) => [...s].sort().join(',');\n return `${e.op}|${e.shape}|${sorted(e.props)}|${e.ids ? sorted(e.ids) : '*'}|${sorted(e.membership)}`;\n}\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { SelectBuilder } from '../queries/QueryBuilder.js';
|
|
2
|
+
import type { CountBuilder } from '../queries/CountBuilder.js';
|
|
3
|
+
import type { AskBuilder } from '../queries/AskBuilder.js';
|
|
4
|
+
/** A builder that can go live: a select, a count, or an ask. */
|
|
5
|
+
export type LiveBuilder = SelectBuilder<any, any, any> | CountBuilder | AskBuilder;
|
|
6
|
+
export type LiveQueryKind = 'select' | 'count' | 'ask';
|
|
7
|
+
/**
|
|
8
|
+
* The part of a query that varies per instance of a template: what it is
|
|
9
|
+
* applied to, and how it is windowed. Everything else is the template.
|
|
10
|
+
*
|
|
11
|
+
* `contextName` is recorded next to the resolved `subject` so the store can
|
|
12
|
+
* re-key an instance when that query context changes (`subscribeQueryContext`).
|
|
13
|
+
* `vars` is reserved for query variables; nothing fills it yet.
|
|
14
|
+
*/
|
|
15
|
+
export type InstanceParams = {
|
|
16
|
+
subject?: string;
|
|
17
|
+
subjects?: string[];
|
|
18
|
+
/** The query context the subject comes from (`.for(getQueryContext(name))`). */
|
|
19
|
+
contextName?: string;
|
|
20
|
+
/** Query contexts referenced inside `where` (`p.x.equals(getQueryContext(name))`): a change refetches, it does not re-key. */
|
|
21
|
+
contextNames?: string[];
|
|
22
|
+
one?: boolean;
|
|
23
|
+
limit?: number;
|
|
24
|
+
offset?: number;
|
|
25
|
+
vars?: Record<string, unknown>;
|
|
26
|
+
};
|
|
27
|
+
export type SplitQuery = {
|
|
28
|
+
kind: LiveQueryKind;
|
|
29
|
+
/** The subject-less, window-less query (DSL-JSON). Identity of the template. */
|
|
30
|
+
templateJson: Record<string, unknown>;
|
|
31
|
+
params: InstanceParams;
|
|
32
|
+
};
|
|
33
|
+
export declare function kindOf(query: LiveBuilder): LiveQueryKind;
|
|
34
|
+
/**
|
|
35
|
+
* Split a query into its template (identity) and its instance params.
|
|
36
|
+
*
|
|
37
|
+
* Works on the DSL-JSON, so it does not depend on builder internals: a select's
|
|
38
|
+
* `subject`/`subjects`/`one`/`limit`/`offset` are params; a `{@ctx}` subject is
|
|
39
|
+
* recorded as `contextName` and resolved to an id when the context is set.
|
|
40
|
+
* Count and ask builders cannot be rebound (they carry their subject in their
|
|
41
|
+
* spec), so their subject stays in the template; only a context reference is
|
|
42
|
+
* lifted into params so a context change creates a fresh instance.
|
|
43
|
+
*/
|
|
44
|
+
export declare function splitQuery(query: LiveBuilder): SplitQuery;
|
|
45
|
+
/**
|
|
46
|
+
* The subject-less form of a builder, used only for dependency analysis: what
|
|
47
|
+
* a query reads does not depend on which node it is applied to.
|
|
48
|
+
*/
|
|
49
|
+
export declare function stripSubjects(query: LiveBuilder): LiveBuilder;
|
|
50
|
+
/** Canonical identity of a query's template, memoized per builder instance (builders are immutable). */
|
|
51
|
+
export declare function templateKey(query: LiveBuilder): string;
|
|
52
|
+
export declare function paramsKey(params: InstanceParams): string;
|
|
53
|
+
/** JSON with object keys in sorted order at every depth, so equal values give equal strings. */
|
|
54
|
+
export declare function stableStringify(value: unknown): string;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { isContextRefJSON, resolveContextId, CONTEXT_REF_KEY } from '../queries/ContextRef.js';
|
|
2
|
+
const PARAM_KEYS = ['subject', 'subjects', 'one', 'limit', 'offset'];
|
|
3
|
+
export function kindOf(query) {
|
|
4
|
+
return query.__queryKind;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Split a query into its template (identity) and its instance params.
|
|
8
|
+
*
|
|
9
|
+
* Works on the DSL-JSON, so it does not depend on builder internals: a select's
|
|
10
|
+
* `subject`/`subjects`/`one`/`limit`/`offset` are params; a `{@ctx}` subject is
|
|
11
|
+
* recorded as `contextName` and resolved to an id when the context is set.
|
|
12
|
+
* Count and ask builders cannot be rebound (they carry their subject in their
|
|
13
|
+
* spec), so their subject stays in the template; only a context reference is
|
|
14
|
+
* lifted into params so a context change creates a fresh instance.
|
|
15
|
+
*/
|
|
16
|
+
export function splitQuery(query) {
|
|
17
|
+
const kind = kindOf(query);
|
|
18
|
+
const json = query.toJSON();
|
|
19
|
+
const params = {};
|
|
20
|
+
const liftContext = (subject) => {
|
|
21
|
+
if (isContextRefJSON(subject)) {
|
|
22
|
+
const name = subject[CONTEXT_REF_KEY];
|
|
23
|
+
params.contextName = name;
|
|
24
|
+
return resolveContextId(name, false);
|
|
25
|
+
}
|
|
26
|
+
return typeof subject === 'string' ? subject : undefined;
|
|
27
|
+
};
|
|
28
|
+
if (kind === 'select') {
|
|
29
|
+
const templateJson = {};
|
|
30
|
+
for (const [k, v] of Object.entries(json)) {
|
|
31
|
+
if (!PARAM_KEYS.includes(k))
|
|
32
|
+
templateJson[k] = v;
|
|
33
|
+
}
|
|
34
|
+
const j = json;
|
|
35
|
+
const subject = liftContext(j.subject);
|
|
36
|
+
if (subject)
|
|
37
|
+
params.subject = subject;
|
|
38
|
+
if (j.subjects && j.subjects.length)
|
|
39
|
+
params.subjects = [...j.subjects];
|
|
40
|
+
// `.for(id)` / `.for(ctx)` imply `one`; it is only a param for a subject-less `.one()`.
|
|
41
|
+
if (j.one && !subject && !params.contextName)
|
|
42
|
+
params.one = true;
|
|
43
|
+
if (j.limit !== undefined)
|
|
44
|
+
params.limit = j.limit;
|
|
45
|
+
if (j.offset !== undefined)
|
|
46
|
+
params.offset = j.offset;
|
|
47
|
+
liftWhereContexts(json.where, params);
|
|
48
|
+
return { kind, templateJson, params };
|
|
49
|
+
}
|
|
50
|
+
// count / ask: the subject is part of the template; only a context ref is lifted.
|
|
51
|
+
const subject = liftContext(json.subject);
|
|
52
|
+
if (params.contextName && subject)
|
|
53
|
+
params.subject = subject;
|
|
54
|
+
liftWhereContexts(json.where, params);
|
|
55
|
+
return { kind, templateJson: json, params };
|
|
56
|
+
}
|
|
57
|
+
/** Every `{@ctx: name}` inside a where clause, so a context change can refetch the instance. */
|
|
58
|
+
function liftWhereContexts(where, params) {
|
|
59
|
+
const names = new Set();
|
|
60
|
+
const walk = (v) => {
|
|
61
|
+
if (Array.isArray(v))
|
|
62
|
+
v.forEach(walk);
|
|
63
|
+
else if (v && typeof v === 'object') {
|
|
64
|
+
if (isContextRefJSON(v))
|
|
65
|
+
names.add(v[CONTEXT_REF_KEY]);
|
|
66
|
+
else
|
|
67
|
+
Object.values(v).forEach(walk);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
walk(where);
|
|
71
|
+
if (names.size)
|
|
72
|
+
params.contextNames = [...names].sort();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The subject-less form of a builder, used only for dependency analysis: what
|
|
76
|
+
* a query reads does not depend on which node it is applied to.
|
|
77
|
+
*/
|
|
78
|
+
export function stripSubjects(query) {
|
|
79
|
+
return kindOf(query) === 'select' ? query.forAll() : query;
|
|
80
|
+
}
|
|
81
|
+
const templateKeyMemo = new WeakMap();
|
|
82
|
+
/** Canonical identity of a query's template, memoized per builder instance (builders are immutable). */
|
|
83
|
+
export function templateKey(query) {
|
|
84
|
+
const cached = templateKeyMemo.get(query);
|
|
85
|
+
if (cached)
|
|
86
|
+
return cached;
|
|
87
|
+
const key = stableStringify(splitQuery(query).templateJson);
|
|
88
|
+
templateKeyMemo.set(query, key);
|
|
89
|
+
return key;
|
|
90
|
+
}
|
|
91
|
+
export function paramsKey(params) {
|
|
92
|
+
return stableStringify(params);
|
|
93
|
+
}
|
|
94
|
+
/** JSON with object keys in sorted order at every depth, so equal values give equal strings. */
|
|
95
|
+
export function stableStringify(value) {
|
|
96
|
+
return JSON.stringify(sortKeys(value));
|
|
97
|
+
}
|
|
98
|
+
function sortKeys(value) {
|
|
99
|
+
if (Array.isArray(value))
|
|
100
|
+
return value.map(sortKeys);
|
|
101
|
+
if (value && typeof value === 'object' && !(value instanceof Date)) {
|
|
102
|
+
const out = {};
|
|
103
|
+
for (const k of Object.keys(value).sort()) {
|
|
104
|
+
const v = value[k];
|
|
105
|
+
if (v !== undefined)
|
|
106
|
+
out[k] = sortKeys(v);
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../../src/live/keys.ts"],"names":[],"mappings":"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","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 */\nimport type {SelectBuilder, QueryBuilderJSON} from '../queries/QueryBuilder.js';\nimport type {CountBuilder} from '../queries/CountBuilder.js';\nimport type {AskBuilder} from '../queries/AskBuilder.js';\nimport {isContextRefJSON, resolveContextId, CONTEXT_REF_KEY} from '../queries/ContextRef.js';\n\n/** A builder that can go live: a select, a count, or an ask. */\nexport type LiveBuilder = SelectBuilder<any, any, any> | CountBuilder | AskBuilder;\nexport type LiveQueryKind = 'select' | 'count' | 'ask';\n\n/**\n * The part of a query that varies per instance of a template: what it is\n * applied to, and how it is windowed. Everything else is the template.\n *\n * `contextName` is recorded next to the resolved `subject` so the store can\n * re-key an instance when that query context changes (`subscribeQueryContext`).\n * `vars` is reserved for query variables; nothing fills it yet.\n */\nexport type InstanceParams = {\n subject?: string;\n subjects?: string[];\n /** The query context the subject comes from (`.for(getQueryContext(name))`). */\n contextName?: string;\n /** Query contexts referenced inside `where` (`p.x.equals(getQueryContext(name))`): a change refetches, it does not re-key. */\n contextNames?: string[];\n one?: boolean;\n limit?: number;\n offset?: number;\n vars?: Record<string, unknown>;\n};\n\nexport type SplitQuery = {\n kind: LiveQueryKind;\n /** The subject-less, window-less query (DSL-JSON). Identity of the template. */\n templateJson: Record<string, unknown>;\n params: InstanceParams;\n};\n\nconst PARAM_KEYS = ['subject', 'subjects', 'one', 'limit', 'offset'] as const;\n\nexport function kindOf(query: LiveBuilder): LiveQueryKind {\n return (query as {__queryKind: LiveQueryKind}).__queryKind;\n}\n\n/**\n * Split a query into its template (identity) and its instance params.\n *\n * Works on the DSL-JSON, so it does not depend on builder internals: a select's\n * `subject`/`subjects`/`one`/`limit`/`offset` are params; a `{@ctx}` subject is\n * recorded as `contextName` and resolved to an id when the context is set.\n * Count and ask builders cannot be rebound (they carry their subject in their\n * spec), so their subject stays in the template; only a context reference is\n * lifted into params so a context change creates a fresh instance.\n */\nexport function splitQuery(query: LiveBuilder): SplitQuery {\n const kind = kindOf(query);\n const json = query.toJSON() as Record<string, unknown>;\n const params: InstanceParams = {};\n\n const liftContext = (subject: unknown): string | undefined => {\n if (isContextRefJSON(subject)) {\n const name = (subject as unknown as Record<string, string>)[CONTEXT_REF_KEY];\n params.contextName = name;\n return resolveContextId(name, false);\n }\n return typeof subject === 'string' ? subject : undefined;\n };\n\n if (kind === 'select') {\n const templateJson: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(json)) {\n if (!(PARAM_KEYS as readonly string[]).includes(k)) templateJson[k] = v;\n }\n const j = json as QueryBuilderJSON;\n const subject = liftContext(j.subject);\n if (subject) params.subject = subject;\n if (j.subjects && j.subjects.length) params.subjects = [...j.subjects];\n // `.for(id)` / `.for(ctx)` imply `one`; it is only a param for a subject-less `.one()`.\n if (j.one && !subject && !params.contextName) params.one = true;\n if (j.limit !== undefined) params.limit = j.limit;\n if (j.offset !== undefined) params.offset = j.offset;\n liftWhereContexts(json.where, params);\n return {kind, templateJson, params};\n }\n\n // count / ask: the subject is part of the template; only a context ref is lifted.\n const subject = liftContext(json.subject);\n if (params.contextName && subject) params.subject = subject;\n liftWhereContexts(json.where, params);\n return {kind, templateJson: json, params};\n}\n\n/** Every `{@ctx: name}` inside a where clause, so a context change can refetch the instance. */\nfunction liftWhereContexts(where: unknown, params: InstanceParams): void {\n const names = new Set<string>();\n const walk = (v: unknown): void => {\n if (Array.isArray(v)) v.forEach(walk);\n else if (v && typeof v === 'object') {\n if (isContextRefJSON(v)) names.add((v as unknown as Record<string, string>)[CONTEXT_REF_KEY]);\n else Object.values(v as Record<string, unknown>).forEach(walk);\n }\n };\n walk(where);\n if (names.size) params.contextNames = [...names].sort();\n}\n\n/**\n * The subject-less form of a builder, used only for dependency analysis: what\n * a query reads does not depend on which node it is applied to.\n */\nexport function stripSubjects(query: LiveBuilder): LiveBuilder {\n return kindOf(query) === 'select' ? (query as SelectBuilder<any, any, any>).forAll() : query;\n}\n\nconst templateKeyMemo = new WeakMap<object, string>();\n\n/** Canonical identity of a query's template, memoized per builder instance (builders are immutable). */\nexport function templateKey(query: LiveBuilder): string {\n const cached = templateKeyMemo.get(query as object);\n if (cached) return cached;\n const key = stableStringify(splitQuery(query).templateJson);\n templateKeyMemo.set(query as object, key);\n return key;\n}\n\nexport function paramsKey(params: InstanceParams): string {\n return stableStringify(params);\n}\n\n/** JSON with object keys in sorted order at every depth, so equal values give equal strings. */\nexport function stableStringify(value: unknown): string {\n return JSON.stringify(sortKeys(value));\n}\n\nfunction sortKeys(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortKeys);\n if (value && typeof value === 'object' && !(value instanceof Date)) {\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(value as object).sort()) {\n const v = (value as Record<string, unknown>)[k];\n if (v !== undefined) out[k] = sortKeys(v);\n }\n return out;\n }\n return value;\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { MutationEffects, QueryDependencies } from '../queries/queryDependencies.js';
|
|
2
|
+
import type { Instance, Template } from './LiveQueryStore.js';
|
|
3
|
+
/** The indexes the matcher reads. Maintained by the store. */
|
|
4
|
+
export type LiveIndexes = {
|
|
5
|
+
templatesByProp: Map<string, Set<Template>>;
|
|
6
|
+
templatesByShape: Map<string, Set<Template>>;
|
|
7
|
+
instancesById: Map<string, Set<Instance>>;
|
|
8
|
+
depsOf(template: Template): QueryDependencies;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Which live instances a change can have affected.
|
|
12
|
+
*
|
|
13
|
+
* Precise where it is cheap, conservative where it is not:
|
|
14
|
+
* 1. A change with known ids reaches the instances that mention those ids and
|
|
15
|
+
* read one of the written predicates on a projected node (`narrow`).
|
|
16
|
+
* 2. A written predicate that a template filters, sorts or reads on hidden
|
|
17
|
+
* nodes (`filter ∪ hidden`) reaches every instance of that template —
|
|
18
|
+
* membership or order may have changed for nodes no result mentions.
|
|
19
|
+
* 3. A change with unknown ids (bulk update/delete) reaches every instance of
|
|
20
|
+
* every template reading a written predicate.
|
|
21
|
+
* 4. A membership change (create/upsert/delete of a shape) reaches the unbound
|
|
22
|
+
* instances of templates that scan or traverse that shape or a related one
|
|
23
|
+
* in the class hierarchy; a delete also reaches every instance that mentions
|
|
24
|
+
* a deleted id and the bound instances of those templates (a traversal into
|
|
25
|
+
* the deleted shape may hide the id, e.g. `size()`).
|
|
26
|
+
* 5. Templates with `reactive: false` are never selected.
|
|
27
|
+
*
|
|
28
|
+
* Rules 1–3 are scoped by shape: a predicate written on a node of shape S can
|
|
29
|
+
* only change nodes of S or of a related shape in its class hierarchy, so a
|
|
30
|
+
* template that neither scans nor traverses any of those shapes is skipped.
|
|
31
|
+
* This is what keeps a `Team` rename away from a `Person` list sorted by the
|
|
32
|
+
* same `schema:name` predicate.
|
|
33
|
+
*/
|
|
34
|
+
export declare function selectInstances(index: LiveIndexes, e: MutationEffects): Set<Instance>;
|
|
35
|
+
/**
|
|
36
|
+
* Whether an instance scans its whole shape (so a create can add to it). For a
|
|
37
|
+
* select the subject is an instance param; count and ask builders carry it in
|
|
38
|
+
* their spec, so their template dependencies decide.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isUnbound(index: LiveIndexes, inst: Instance): boolean;
|
|
41
|
+
/** A set of shape IRIs plus every ancestor and descendant shape of each. */
|
|
42
|
+
export declare function expandShapes(shapes: Iterable<string>): Set<string>;
|
|
43
|
+
export declare function intersects(a: Set<string>, b: Set<string>): boolean;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { getSubShapes, getSuperShapes } from '../utils/ShapeClass.js';
|
|
2
|
+
/**
|
|
3
|
+
* Which live instances a change can have affected.
|
|
4
|
+
*
|
|
5
|
+
* Precise where it is cheap, conservative where it is not:
|
|
6
|
+
* 1. A change with known ids reaches the instances that mention those ids and
|
|
7
|
+
* read one of the written predicates on a projected node (`narrow`).
|
|
8
|
+
* 2. A written predicate that a template filters, sorts or reads on hidden
|
|
9
|
+
* nodes (`filter ∪ hidden`) reaches every instance of that template —
|
|
10
|
+
* membership or order may have changed for nodes no result mentions.
|
|
11
|
+
* 3. A change with unknown ids (bulk update/delete) reaches every instance of
|
|
12
|
+
* every template reading a written predicate.
|
|
13
|
+
* 4. A membership change (create/upsert/delete of a shape) reaches the unbound
|
|
14
|
+
* instances of templates that scan or traverse that shape or a related one
|
|
15
|
+
* in the class hierarchy; a delete also reaches every instance that mentions
|
|
16
|
+
* a deleted id and the bound instances of those templates (a traversal into
|
|
17
|
+
* the deleted shape may hide the id, e.g. `size()`).
|
|
18
|
+
* 5. Templates with `reactive: false` are never selected.
|
|
19
|
+
*
|
|
20
|
+
* Rules 1–3 are scoped by shape: a predicate written on a node of shape S can
|
|
21
|
+
* only change nodes of S or of a related shape in its class hierarchy, so a
|
|
22
|
+
* template that neither scans nor traverses any of those shapes is skipped.
|
|
23
|
+
* This is what keeps a `Team` rename away from a `Person` list sorted by the
|
|
24
|
+
* same `schema:name` predicate.
|
|
25
|
+
*/
|
|
26
|
+
export function selectInstances(index, e) {
|
|
27
|
+
var _a, _b, _c;
|
|
28
|
+
const out = new Set();
|
|
29
|
+
const add = (inst) => {
|
|
30
|
+
if (inst.template.reactive)
|
|
31
|
+
out.add(inst);
|
|
32
|
+
};
|
|
33
|
+
const addAll = (t) => {
|
|
34
|
+
if (!t.reactive)
|
|
35
|
+
return;
|
|
36
|
+
for (const inst of t.instances.values())
|
|
37
|
+
out.add(inst);
|
|
38
|
+
};
|
|
39
|
+
// Shapes whose nodes this change can have touched.
|
|
40
|
+
const scope = expandShapes([e.shape, ...e.membership]);
|
|
41
|
+
const inScope = (t) => intersects(index.depsOf(t).shapes, scope);
|
|
42
|
+
// Templates reading any written predicate, within the shape scope.
|
|
43
|
+
const byProp = new Set();
|
|
44
|
+
for (const p of e.props) {
|
|
45
|
+
for (const t of (_a = index.templatesByProp.get(p)) !== null && _a !== void 0 ? _a : [])
|
|
46
|
+
if (inScope(t))
|
|
47
|
+
byProp.add(t);
|
|
48
|
+
}
|
|
49
|
+
// Rule 1 — narrow by id.
|
|
50
|
+
if (e.ids) {
|
|
51
|
+
for (const id of e.ids) {
|
|
52
|
+
for (const inst of (_b = index.instancesById.get(id)) !== null && _b !== void 0 ? _b : []) {
|
|
53
|
+
if (e.op === 'delete' || (byProp.has(inst.template) && intersects(index.depsOf(inst.template).narrow, e.props))) {
|
|
54
|
+
add(inst);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Rules 2 and 3 — template-wide.
|
|
60
|
+
for (const t of byProp) {
|
|
61
|
+
const deps = index.depsOf(t);
|
|
62
|
+
const wide = intersects(deps.filter, e.props) || intersects(deps.hidden, e.props);
|
|
63
|
+
if (wide || (!e.ids && intersects(deps.narrow, e.props)))
|
|
64
|
+
addAll(t);
|
|
65
|
+
}
|
|
66
|
+
// Rule 4 — membership.
|
|
67
|
+
if (e.membership.size) {
|
|
68
|
+
for (const shape of expandShapes(e.membership)) {
|
|
69
|
+
for (const t of (_c = index.templatesByShape.get(shape)) !== null && _c !== void 0 ? _c : []) {
|
|
70
|
+
if (e.op === 'delete') {
|
|
71
|
+
addAll(t);
|
|
72
|
+
}
|
|
73
|
+
else if (t.reactive) {
|
|
74
|
+
for (const inst of t.instances.values())
|
|
75
|
+
if (isUnbound(index, inst))
|
|
76
|
+
out.add(inst);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Whether an instance scans its whole shape (so a create can add to it). For a
|
|
85
|
+
* select the subject is an instance param; count and ask builders carry it in
|
|
86
|
+
* their spec, so their template dependencies decide.
|
|
87
|
+
*/
|
|
88
|
+
export function isUnbound(index, inst) {
|
|
89
|
+
if (inst.template.kind === 'select') {
|
|
90
|
+
return !(inst.params.subject || inst.params.contextName || (inst.params.subjects && inst.params.subjects.length));
|
|
91
|
+
}
|
|
92
|
+
return index.depsOf(inst.template).unbound;
|
|
93
|
+
}
|
|
94
|
+
/** A set of shape IRIs plus every ancestor and descendant shape of each. */
|
|
95
|
+
export function expandShapes(shapes) {
|
|
96
|
+
const out = new Set();
|
|
97
|
+
for (const s of shapes) {
|
|
98
|
+
out.add(s);
|
|
99
|
+
for (const sup of getSuperShapes(s))
|
|
100
|
+
out.add(sup.id);
|
|
101
|
+
for (const sub of getSubShapes(s))
|
|
102
|
+
out.add(sub.id);
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
export function intersects(a, b) {
|
|
107
|
+
if (a.size === 0 || b.size === 0)
|
|
108
|
+
return false;
|
|
109
|
+
const [small, large] = a.size <= b.size ? [a, b] : [b, a];
|
|
110
|
+
for (const v of small)
|
|
111
|
+
if (large.has(v))
|
|
112
|
+
return true;
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.js","sourceRoot":"","sources":["../../../src/live/matcher.ts"],"names":[],"mappings":"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","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 */\nimport type {MutationEffects, QueryDependencies} from '../queries/queryDependencies.js';\nimport {getSubShapes, getSuperShapes} from '../utils/ShapeClass.js';\nimport type {Instance, Template} from './LiveQueryStore.js';\n\n/** The indexes the matcher reads. Maintained by the store. */\nexport type LiveIndexes = {\n templatesByProp: Map<string, Set<Template>>;\n templatesByShape: Map<string, Set<Template>>;\n instancesById: Map<string, Set<Instance>>;\n depsOf(template: Template): QueryDependencies;\n};\n\n/**\n * Which live instances a change can have affected.\n *\n * Precise where it is cheap, conservative where it is not:\n * 1. A change with known ids reaches the instances that mention those ids and\n * read one of the written predicates on a projected node (`narrow`).\n * 2. A written predicate that a template filters, sorts or reads on hidden\n * nodes (`filter ∪ hidden`) reaches every instance of that template —\n * membership or order may have changed for nodes no result mentions.\n * 3. A change with unknown ids (bulk update/delete) reaches every instance of\n * every template reading a written predicate.\n * 4. A membership change (create/upsert/delete of a shape) reaches the unbound\n * instances of templates that scan or traverse that shape or a related one\n * in the class hierarchy; a delete also reaches every instance that mentions\n * a deleted id and the bound instances of those templates (a traversal into\n * the deleted shape may hide the id, e.g. `size()`).\n * 5. Templates with `reactive: false` are never selected.\n *\n * Rules 1–3 are scoped by shape: a predicate written on a node of shape S can\n * only change nodes of S or of a related shape in its class hierarchy, so a\n * template that neither scans nor traverses any of those shapes is skipped.\n * This is what keeps a `Team` rename away from a `Person` list sorted by the\n * same `schema:name` predicate.\n */\nexport function selectInstances(index: LiveIndexes, e: MutationEffects): Set<Instance> {\n const out = new Set<Instance>();\n const add = (inst: Instance) => {\n if (inst.template.reactive) out.add(inst);\n };\n const addAll = (t: Template) => {\n if (!t.reactive) return;\n for (const inst of t.instances.values()) out.add(inst);\n };\n\n // Shapes whose nodes this change can have touched.\n const scope = expandShapes([e.shape, ...e.membership]);\n const inScope = (t: Template) => intersects(index.depsOf(t).shapes, scope);\n\n // Templates reading any written predicate, within the shape scope.\n const byProp = new Set<Template>();\n for (const p of e.props) {\n for (const t of index.templatesByProp.get(p) ?? []) if (inScope(t)) byProp.add(t);\n }\n\n // Rule 1 — narrow by id.\n if (e.ids) {\n for (const id of e.ids) {\n for (const inst of index.instancesById.get(id) ?? []) {\n if (e.op === 'delete' || (byProp.has(inst.template) && intersects(index.depsOf(inst.template).narrow, e.props))) {\n add(inst);\n }\n }\n }\n }\n\n // Rules 2 and 3 — template-wide.\n for (const t of byProp) {\n const deps = index.depsOf(t);\n const wide = intersects(deps.filter, e.props) || intersects(deps.hidden, e.props);\n if (wide || (!e.ids && intersects(deps.narrow, e.props))) addAll(t);\n }\n\n // Rule 4 — membership.\n if (e.membership.size) {\n for (const shape of expandShapes(e.membership)) {\n for (const t of index.templatesByShape.get(shape) ?? []) {\n if (e.op === 'delete') {\n addAll(t);\n } else if (t.reactive) {\n for (const inst of t.instances.values()) if (isUnbound(index, inst)) out.add(inst);\n }\n }\n }\n }\n\n return out;\n}\n\n/**\n * Whether an instance scans its whole shape (so a create can add to it). For a\n * select the subject is an instance param; count and ask builders carry it in\n * their spec, so their template dependencies decide.\n */\nexport function isUnbound(index: LiveIndexes, inst: Instance): boolean {\n if (inst.template.kind === 'select') {\n return !(inst.params.subject || inst.params.contextName || (inst.params.subjects && inst.params.subjects.length));\n }\n return index.depsOf(inst.template).unbound;\n}\n\n/** A set of shape IRIs plus every ancestor and descendant shape of each. */\nexport function expandShapes(shapes: Iterable<string>): Set<string> {\n const out = new Set<string>();\n for (const s of shapes) {\n out.add(s);\n for (const sup of getSuperShapes(s)) out.add(sup.id);\n for (const sub of getSubShapes(s)) out.add(sub.id);\n }\n return out;\n}\n\nexport function intersects(a: Set<string>, b: Set<string>): boolean {\n if (a.size === 0 || b.size === 0) return false;\n const [small, large] = a.size <= b.size ? [a, b] : [b, a];\n for (const v of small) if (large.has(v)) return true;\n return false;\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LiveQueryStore } from './LiveQueryStore.js';
|
|
2
|
+
/**
|
|
3
|
+
* Where the live-query store registers itself.
|
|
4
|
+
*
|
|
5
|
+
* `globalThis`-backed for the same reason the query dispatch and the routing
|
|
6
|
+
* table are (see `docs/architecture/runtime-instances.md`): a second physical
|
|
7
|
+
* copy of this module must find the same store rather than fork it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const LIVE_STORE_KEY = "__linkedLiveQueryStore";
|
|
10
|
+
/**
|
|
11
|
+
* The registered live-query store, or `undefined` when `./LiveQueryStore.js`
|
|
12
|
+
* has not been evaluated yet.
|
|
13
|
+
*
|
|
14
|
+
* The builders reach the store through this tiny module — never by importing
|
|
15
|
+
* `LiveQueryStore.ts` — so a bundle that only builds and forwards queries never
|
|
16
|
+
* pulls in the store, and with it the IR lowering the store needs for its
|
|
17
|
+
* dependency analysis. Importing the package root (`@_linked/core`) or
|
|
18
|
+
* `@_linked/core/live` registers the store.
|
|
19
|
+
*/
|
|
20
|
+
export declare function peekLiveQueryStore(): LiveQueryStore | undefined;
|
|
21
|
+
/** The registered store; throws when live queries have not been loaded. */
|
|
22
|
+
export declare function requireLiveQueryStore(): LiveQueryStore;
|
|
23
|
+
/** @internal Register (or replace) the store — called by `LiveQueryStore.ts` on load and by `resetLiveQueryStore()`. */
|
|
24
|
+
export declare function setLiveQueryStore(store: LiveQueryStore | undefined): void;
|