teamplay 0.5.0-alpha.8 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +3 -3
  2. package/dist/config.d.ts +2 -0
  3. package/dist/config.js +1 -0
  4. package/dist/connect/index.d.ts +1 -1
  5. package/dist/connect/index.js +6 -2
  6. package/dist/connect/offline/index.d.ts +1 -1
  7. package/dist/connect/offline/index.js +8 -4
  8. package/dist/connect/offline/react-native.d.ts +1 -1
  9. package/dist/connect/offline/web.d.ts +1 -1
  10. package/dist/connect/test.d.ts +1 -1
  11. package/dist/connect/test.js +5 -1
  12. package/dist/index.d.ts +9 -5
  13. package/dist/index.js +6 -5
  14. package/dist/orm/$.js +1 -1
  15. package/dist/orm/Aggregation.d.ts +5 -3
  16. package/dist/orm/Aggregation.js +39 -15
  17. package/dist/orm/Doc.js +0 -55
  18. package/dist/orm/Query.d.ts +1 -0
  19. package/dist/orm/Query.js +25 -82
  20. package/dist/orm/Root.d.ts +4 -0
  21. package/dist/orm/Root.js +16 -0
  22. package/dist/orm/Signal.d.ts +0 -2
  23. package/dist/orm/Signal.js +1 -4
  24. package/dist/orm/SignalBase.d.ts +21 -1
  25. package/dist/orm/SignalBase.js +259 -56
  26. package/dist/orm/batchScheduler.d.ts +7 -7
  27. package/dist/orm/connection.d.ts +0 -4
  28. package/dist/orm/connection.js +0 -12
  29. package/dist/orm/dataTree.d.ts +12 -12
  30. package/dist/orm/dataTree.js +55 -107
  31. package/dist/orm/disposeRootContext.js +0 -14
  32. package/dist/orm/events.d.ts +6 -0
  33. package/dist/orm/events.js +48 -0
  34. package/dist/orm/getSignal.d.ts +1 -1
  35. package/dist/orm/getSignal.js +4 -33
  36. package/dist/orm/idFields.d.ts +10 -1
  37. package/dist/orm/idFields.js +102 -14
  38. package/dist/orm/index.d.ts +2 -0
  39. package/dist/orm/index.js +1 -0
  40. package/dist/orm/initModels.js +1 -1
  41. package/dist/orm/privateData.d.ts +7 -22
  42. package/dist/orm/privateData.js +20 -1
  43. package/dist/orm/queryReadiness.d.ts +13 -0
  44. package/dist/orm/{Compat/queryReadiness.js → queryReadiness.js} +10 -10
  45. package/dist/orm/reaction.d.ts +11 -0
  46. package/dist/orm/reaction.js +47 -0
  47. package/dist/orm/rootContext.d.ts +0 -16
  48. package/dist/orm/rootContext.js +0 -28
  49. package/dist/orm/signalMetadata.js +3 -3
  50. package/dist/orm/signalReads.js +3 -9
  51. package/dist/orm/signalStorageMutations.d.ts +0 -2
  52. package/dist/orm/signalStorageMutations.js +0 -9
  53. package/dist/orm/signalSymbols.js +1 -1
  54. package/dist/orm/signalValueMutations.d.ts +1 -1
  55. package/dist/orm/signalValueMutations.js +0 -3
  56. package/dist/orm/sub.d.ts +12 -7
  57. package/dist/orm/sub.js +87 -30
  58. package/dist/orm/subscriptionGcDelay.js +2 -6
  59. package/dist/react/convertToObserver.js +1 -4
  60. package/dist/react/promiseBatcher.js +1 -1
  61. package/dist/react/renderAttemptDestroyer.d.ts +0 -8
  62. package/dist/react/renderAttemptDestroyer.js +2 -28
  63. package/dist/react/trapRender.js +3 -3
  64. package/dist/react/useSub.d.ts +86 -5
  65. package/dist/react/useSub.js +191 -32
  66. package/dist/react/useSuspendMemo.js +1 -5
  67. package/dist/server.d.ts +2 -3
  68. package/dist/server.js +5 -3
  69. package/package.json +16 -14
  70. package/dist/orm/Compat/SignalCompat.d.ts +0 -3
  71. package/dist/orm/Compat/SignalCompat.js +0 -1267
  72. package/dist/orm/Compat/eventsCompat.d.ts +0 -3
  73. package/dist/orm/Compat/eventsCompat.js +0 -73
  74. package/dist/orm/Compat/hooksCompat.d.ts +0 -33
  75. package/dist/orm/Compat/hooksCompat.js +0 -360
  76. package/dist/orm/Compat/modelEvents.d.ts +0 -6
  77. package/dist/orm/Compat/modelEvents.js +0 -228
  78. package/dist/orm/Compat/queryReadiness.d.ts +0 -5
  79. package/dist/orm/Compat/refFallback.d.ts +0 -13
  80. package/dist/orm/Compat/refFallback.js +0 -65
  81. package/dist/orm/Compat/refRegistry.d.ts +0 -6
  82. package/dist/orm/Compat/refRegistry.js +0 -54
  83. package/dist/orm/Compat/silentContext.d.ts +0 -5
  84. package/dist/orm/Compat/silentContext.js +0 -48
  85. package/dist/orm/Compat/startStopCompat.d.ts +0 -3
  86. package/dist/orm/Compat/startStopCompat.js +0 -217
  87. package/dist/orm/compatEnv.d.ts +0 -1
  88. package/dist/orm/compatEnv.js +0 -4
  89. package/dist/react/compatComponentRegistry.d.ts +0 -4
  90. package/dist/react/compatComponentRegistry.js +0 -19
  91. /package/dist/orm/{Reaction.d.ts → reactionSubscriptions.d.ts} +0 -0
  92. /package/dist/orm/{Reaction.js → reactionSubscriptions.js} +0 -0
package/README.md CHANGED
@@ -13,16 +13,16 @@ Features:
13
13
 
14
14
  > __*__ deep signals -- with support for objects and arrays\
15
15
  > __**__ concurrent changes to the same data are auto-merged using [OT](https://en.wikipedia.org/wiki/Operational_transformation)\
16
- > __***__ similar to Firebase but with your own MongoDB-compatible database
16
+ > __***__ similar to Firebase but with your own MongoDB database
17
17
 
18
18
  ## Installation
19
19
 
20
20
  For installation and documentation see [teamplay.dev](https://teamplay.dev)
21
21
 
22
- ## ORM Compat Helpers
22
+ ## ORM Helpers
23
23
 
24
24
  For legacy Racer-style model mixins (for example versioning libraries which call
25
- `getAssociations()`), use ORM compat helpers from the `teamplay/orm` subpath:
25
+ `getAssociations()`), use ORM helpers from the `teamplay/orm` subpath:
26
26
 
27
27
  ```js
28
28
  import BaseModel, { hasMany, hasOne, belongsTo } from 'teamplay/orm'
@@ -0,0 +1,2 @@
1
+ export { TEAMPLAY_RUNTIME_CONFIG_SYMBOL, configureTeamplay, getTeamplayConfig, getDefaultIdFields, setDefaultIdFields } from './orm/idFields.js';
2
+ export type { IdField, IdFields, TeamplayRuntimeConfig } from './orm/idFields.js';
package/dist/config.js ADDED
@@ -0,0 +1 @@
1
+ export { TEAMPLAY_RUNTIME_CONFIG_SYMBOL, configureTeamplay, getTeamplayConfig, getDefaultIdFields, setDefaultIdFields } from "./orm/idFields.js";
@@ -1 +1 @@
1
- export default function connect(options: any): void;
1
+ export default function connect(options?: {}): void;
@@ -1,9 +1,13 @@
1
1
  import Socket from '@teamplay/channel';
2
2
  import Connection from './sharedbConnection.cjs';
3
3
  import { connection, setConnection } from "../orm/connection.js";
4
- export default function connect(options) {
4
+ import { configureTeamplay } from "../config.js";
5
+ export default function connect(options = {}) {
6
+ const { idFields, ...socketOptions } = options || {};
7
+ if (idFields !== undefined)
8
+ configureTeamplay({ idFields });
5
9
  if (connection)
6
10
  return;
7
- const socket = new Socket(options);
11
+ const socket = new Socket(socketOptions);
8
12
  setConnection(new Connection(socket));
9
13
  }
@@ -1 +1 @@
1
- export default function createConnectWithPersistence({ storage, createPubsub }?: {}): () => Promise<void>;
1
+ export default function createConnectWithPersistence({ storage, createPubsub }?: {}): (options?: {}) => Promise<void>;
@@ -3,21 +3,25 @@
3
3
  import ShareDbMingo from '@startupjs/sharedb-mingo-memory';
4
4
  import ShareBackend from 'sharedb';
5
5
  import { connection, setConnection } from "../../orm/connection.js";
6
+ import { configureTeamplay } from "../../config.js";
6
7
  const STORAGE_NAMESPACE = 'teamplay-offline';
7
8
  const DOCS_PREFIX = `${STORAGE_NAMESPACE}:docs:`;
8
9
  const LAST_OP_PREFIX = `${STORAGE_NAMESPACE}:last-op:`;
9
10
  export default function createConnectWithPersistence({ storage, createPubsub } = {}) {
10
11
  if (!storage)
11
12
  throw new Error('[connect-offline] storage is required');
12
- return async function connect() {
13
+ return async function connect(options = {}) {
14
+ const { idFields } = options || {};
15
+ if (idFields !== undefined)
16
+ configureTeamplay({ idFields });
13
17
  if (connection)
14
18
  return;
15
19
  const db = new ShareDbMingo();
16
- const options = { db };
20
+ const backendOptions = { db };
17
21
  const { pubsub } = (await init(db, storage, createPubsub)) || {};
18
22
  if (pubsub)
19
- options.pubsub = pubsub;
20
- const backend = new ShareBackend(options);
23
+ backendOptions.pubsub = pubsub;
24
+ const backend = new ShareBackend(backendOptions);
21
25
  setConnection(backend.connect());
22
26
  };
23
27
  }
@@ -3,7 +3,7 @@ export namespace storage {
3
3
  export { setItem };
4
4
  export { iterate };
5
5
  }
6
- declare const _default: () => Promise<void>;
6
+ declare const _default: (options?: {}) => Promise<void>;
7
7
  export default _default;
8
8
  declare function getItem(key: any): Promise<any>;
9
9
  declare function setItem(key: any, value: any): Promise<any>;
@@ -4,6 +4,6 @@ export namespace storage {
4
4
  function setItem(key: any, value: any): Promise<any>;
5
5
  function iterate(iterator: any): Promise<any>;
6
6
  }
7
- declare const _default: () => Promise<void>;
7
+ declare const _default: (options?: {}) => Promise<void>;
8
8
  export default _default;
9
9
  import SharedbCrosstabPubsub from '../lib/sharedb-crosstab-pubsub.cjs';
@@ -1 +1 @@
1
- export default function connect(): void;
1
+ export default function connect(options?: {}): void;
@@ -4,7 +4,11 @@
4
4
  import ShareDbMingo from '@startupjs/sharedb-mingo-memory';
5
5
  import ShareBackend from 'sharedb';
6
6
  import { connection, setConnection } from "../orm/connection.js";
7
- export default function connect() {
7
+ import { configureTeamplay } from "../config.js";
8
+ export default function connect(options = {}) {
9
+ const { idFields } = options || {};
10
+ if (idFields !== undefined)
11
+ configureTeamplay({ idFields });
8
12
  if (connection)
9
13
  return;
10
14
  const backend = new ShareBackend({ db: new ShareDbMingo() });
package/dist/index.d.ts CHANGED
@@ -53,15 +53,19 @@ export { default as signal } from './orm/getSignal.js';
53
53
  export { GLOBAL_ROOT_ID } from './orm/Root.js';
54
54
  export declare const $: RootSignal;
55
55
  export default $;
56
- export { default as sub } from './orm/sub.js';
57
- export { default as useSub, useAsyncSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from './react/useSub.js';
56
+ export { default as sub, unsub } from './orm/sub.js';
57
+ export type { SubMode, SubOptions } from './orm/sub.js';
58
+ export { default as useSub, useAsyncSub, useBatchSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from './react/useSub.js';
58
59
  export { default as useSuspendMemo, useSuspendMemoByKey } from './react/useSuspendMemo.js';
59
60
  export declare const observer: ObserverFunction;
60
- export { useValue, useValue$, useModel, useLocal, useLocal$, useLocalDoc, useLocalDoc$, useSession, useSession$, usePage, usePage$, useBatch, useDoc, useDoc$, useBatchDoc, useBatchDoc$, useAsyncDoc, useAsyncDoc$, useQuery, useQuery$, useAsyncQuery, useAsyncQuery$, useBatchQuery, useBatchQuery$, useQueryIds, useBatchQueryIds, useAsyncQueryIds, useQueryDoc, useQueryDoc$, useBatchQueryDoc, useBatchQueryDoc$, useAsyncQueryDoc, useAsyncQueryDoc$ } from './orm/Compat/hooksCompat.js';
61
- export { emit, useOn, useEmit } from './orm/Compat/eventsCompat.js';
61
+ export { emit, useOn, useEmit } from './orm/events.js';
62
+ export { default as reaction } from './orm/reaction.js';
63
+ export type { ReactionHandle, ReactionOptions } from './orm/reaction.js';
62
64
  export { useDidUpdate, useOnce, useSyncEffect } from './react/helpers.js';
63
- export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly, publicOnly, setPublicOnly } from './orm/connection.js';
65
+ export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly } from './orm/connection.js';
64
66
  export type { TeamplayConnection, TeamplayShareDoc } from './orm/connection.js';
67
+ export { TEAMPLAY_RUNTIME_CONFIG_SYMBOL, configureTeamplay, getTeamplayConfig, getDefaultIdFields, setDefaultIdFields } from './config.js';
68
+ export type { IdField, IdFields, TeamplayRuntimeConfig } from './config.js';
65
69
  export { getSubscriptionGcDelay, setSubscriptionGcDelay } from './orm/subscriptionGcDelay.js';
66
70
  export { useId, useNow, useScheduleUpdate, useTriggerUpdate } from './react/helpers.js';
67
71
  export { GUID_PATTERN, defineSchema, hasMany, hasOne, hasManyFlags, belongsTo, pickFormFields } from '@teamplay/schema';
package/dist/index.js CHANGED
@@ -14,14 +14,15 @@ export { GLOBAL_ROOT_ID } from "./orm/Root.js";
14
14
  const getRuntimeRootSignal = _getRootSignal;
15
15
  export const $ = getRuntimeRootSignal({ rootId: GLOBAL_ROOT_ID, rootFunction: universal$ });
16
16
  export default $;
17
- export { default as sub } from "./orm/sub.js";
18
- export { default as useSub, useAsyncSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from "./react/useSub.js";
17
+ export { default as sub, unsub } from "./orm/sub.js";
18
+ export { default as useSub, useAsyncSub, useBatchSub, setUseDeferredValue as __setUseDeferredValue, setDefaultDefer as __setDefaultDefer } from "./react/useSub.js";
19
19
  export { default as useSuspendMemo, useSuspendMemoByKey } from "./react/useSuspendMemo.js";
20
20
  export const observer = runtimeObserver;
21
- export { useValue, useValue$, useModel, useLocal, useLocal$, useLocalDoc, useLocalDoc$, useSession, useSession$, usePage, usePage$, useBatch, useDoc, useDoc$, useBatchDoc, useBatchDoc$, useAsyncDoc, useAsyncDoc$, useQuery, useQuery$, useAsyncQuery, useAsyncQuery$, useBatchQuery, useBatchQuery$, useQueryIds, useBatchQueryIds, useAsyncQueryIds, useQueryDoc, useQueryDoc$, useBatchQueryDoc, useBatchQueryDoc$, useAsyncQueryDoc, useAsyncQueryDoc$ } from './orm/Compat/hooksCompat.js';
22
- export { emit, useOn, useEmit } from './orm/Compat/eventsCompat.js';
21
+ export { emit, useOn, useEmit } from './orm/events.js';
22
+ export { default as reaction } from "./orm/reaction.js";
23
23
  export { useDidUpdate, useOnce, useSyncEffect } from "./react/helpers.js";
24
- export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly, publicOnly, setPublicOnly } from "./orm/connection.js";
24
+ export { connection, setConnection, getConnection, getDefaultFetchOnly, setDefaultFetchOnly } from "./orm/connection.js";
25
+ export { TEAMPLAY_RUNTIME_CONFIG_SYMBOL, configureTeamplay, getTeamplayConfig, getDefaultIdFields, setDefaultIdFields } from "./config.js";
25
26
  export { getSubscriptionGcDelay, setSubscriptionGcDelay } from "./orm/subscriptionGcDelay.js";
26
27
  export { useId, useNow, useScheduleUpdate, useTriggerUpdate } from "./react/helpers.js";
27
28
  export { GUID_PATTERN, defineSchema, hasMany, hasOne, hasManyFlags, belongsTo, pickFormFields } from '@teamplay/schema';
package/dist/orm/$.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import getSignal from "./getSignal.js";
5
5
  import Signal from "./Signal.js";
6
6
  import { LOCAL, valueSubscriptions } from './Value.js';
7
- import { reactionSubscriptions } from './Reaction.js';
7
+ import { reactionSubscriptions } from './reactionSubscriptions.js';
8
8
  export { LOCAL } from './Value.js';
9
9
  let counter = 0;
10
10
  function newIncrementalId() {
@@ -3,15 +3,17 @@ import type {
3
3
  QuerySubscriptions,
4
4
  QuerySignalOptions
5
5
  } from './Query.js'
6
+ import type { PathSegment } from './types/path.js'
6
7
 
7
8
  export const IS_AGGREGATION: unique symbol
8
9
  export const AGGREGATIONS: '$aggregations'
9
10
  export const aggregationSubscriptions: QuerySubscriptions
10
11
  export function getAggregationSignal (collectionName: string, params: unknown, options?: QuerySignalOptions): Signal
11
12
  export function isAggregationSignal ($signal: unknown): boolean | undefined
13
+ export function getAggregationRowId (row: unknown, collectionName?: string): string | undefined
12
14
  export function getAggregationDocId (
13
- segments: readonly unknown[],
15
+ segments: readonly PathSegment[],
14
16
  rootId?: string,
15
- method?: (path: unknown[]) => unknown
17
+ method?: (path: PathSegment[]) => unknown
16
18
  ): string | undefined
17
- export function getAggregationCollectionName (segments: readonly unknown[]): string | undefined
19
+ export function getAggregationCollectionName (segments: readonly PathSegment[]): string | undefined
@@ -1,13 +1,14 @@
1
1
  import { raw } from '@nx-js/observer-util';
2
2
  import { getRaw } from './dataTree.js';
3
3
  import getSignal from "./getSignal.js";
4
- import { QuerySubscriptions, hashQuery, Query, HASH, PARAMS, COLLECTION_NAME, parseQueryHash } from './Query.js';
4
+ import { QuerySubscriptions, hashQuery, Query, cloneQueryParams, HASH, PARAMS, COLLECTION_NAME, parseQueryHash } from './Query.js';
5
5
  import Signal, { SEGMENTS } from "./Signal.js";
6
6
  import { getIdFieldsForSegments, isPlainObject } from "./idFields.js";
7
7
  import { delPrivateData, getPrivateData, setPrivateData } from './privateData.js';
8
8
  import { setSignalRuntimeDescriptor } from "./signalRuntimeDescriptor.js";
9
9
  export const IS_AGGREGATION = Symbol('is aggregation signal');
10
10
  export const AGGREGATIONS = '$aggregations';
11
+ const DEFAULT_AGGREGATION_ID_FIELDS = ['_id', 'id'];
11
12
  class Aggregation extends Query {
12
13
  _initData() {
13
14
  this._syncAllRootsData();
@@ -39,21 +40,31 @@ aggregationSubscriptions.runtimeKind = 'aggregation';
39
40
  function injectAggregationIds(extra, collectionName) {
40
41
  if (!Array.isArray(extra))
41
42
  return;
42
- const idFields = getIdFieldsForSegments([collectionName, '']);
43
+ const idFields = getCollectionIdFields(collectionName);
43
44
  for (const doc of extra) {
44
45
  if (!isPlainObject(doc))
45
46
  continue;
46
- const docId = doc._id ?? doc.id;
47
+ const docId = getAggregationRowId(doc, collectionName);
47
48
  if (docId == null)
48
49
  continue;
49
- if (idFields.includes('_id') && doc._id !== docId)
50
- doc._id = docId;
51
- if (idFields.includes('id') && doc.id !== docId)
52
- doc.id = docId;
50
+ for (const field of idFields) {
51
+ if (doc[field] !== docId)
52
+ doc[field] = docId;
53
+ }
54
+ }
55
+ }
56
+ export function getAggregationRowId(row, collectionName) {
57
+ if (!isPlainObject(row))
58
+ return;
59
+ const idFields = getAggregationIdFields(collectionName);
60
+ for (const field of idFields) {
61
+ const value = row[field];
62
+ if (typeof value === 'string')
63
+ return value;
53
64
  }
54
65
  }
55
66
  export function getAggregationSignal(collectionName, params, options) {
56
- params = JSON.parse(JSON.stringify(params));
67
+ params = cloneQueryParams(collectionName, params);
57
68
  const transportHash = hashQuery(collectionName, params);
58
69
  const { root, signalOptions } = parseAggregationSignalOptions(options);
59
70
  const $aggregation = getSignal(root, [AGGREGATIONS, transportHash], signalOptions);
@@ -80,7 +91,7 @@ export function isAggregationSignal($signal) {
80
91
  return true;
81
92
  }
82
93
  // example: ['$aggregations', '{"active":true}', 42]
83
- // AND only if it also has either '_id' or 'id' field inside
94
+ // AND only if the aggregation row carries a source document id field
84
95
  export function getAggregationDocId(segments, rootId, method) {
85
96
  if (!(segments.length >= 3))
86
97
  return;
@@ -88,15 +99,16 @@ export function getAggregationDocId(segments, rootId, method) {
88
99
  return;
89
100
  if (!(typeof segments[2] === 'number'))
90
101
  return;
102
+ const collectionName = getAggregationCollectionName(segments);
103
+ const idFields = getAggregationIdFields(collectionName);
91
104
  if (typeof method !== 'function') {
92
105
  method = path => rootId == null ? getRaw(path) : getPrivateData(rootId, path);
93
106
  }
94
- const underscoreId = method([...segments.slice(0, 3), '_id']);
95
- if (typeof underscoreId === 'string')
96
- return underscoreId;
97
- const id = method([...segments.slice(0, 3), 'id']);
98
- if (typeof id === 'string')
99
- return id;
107
+ for (const field of idFields) {
108
+ const id = method([...segments.slice(0, 3), field]);
109
+ if (typeof id === 'string')
110
+ return id;
111
+ }
100
112
  }
101
113
  export function getAggregationCollectionName(segments) {
102
114
  if (!(segments.length >= 2))
@@ -117,3 +129,15 @@ function parseAggregationSignalOptions(options) {
117
129
  const { root, ...signalOptions } = options;
118
130
  return { root, signalOptions };
119
131
  }
132
+ function getAggregationIdFields(collectionName) {
133
+ const idFields = getCollectionIdFields(collectionName);
134
+ return uniq(idFields.concat(DEFAULT_AGGREGATION_ID_FIELDS));
135
+ }
136
+ function getCollectionIdFields(collectionName) {
137
+ return collectionName
138
+ ? getIdFieldsForSegments([collectionName, ''])
139
+ : [];
140
+ }
141
+ function uniq(values) {
142
+ return Array.from(new Set(values));
143
+ }
package/dist/orm/Doc.js CHANGED
@@ -5,7 +5,6 @@ import { getConnection } from "./connection.js";
5
5
  import FinalizationRegistry from "../utils/MockFinalizationRegistry.js";
6
6
  import SubscriptionState from './SubscriptionState.js';
7
7
  import { getIdFieldsForSegments, injectIdFields, isPlainObject } from "./idFields.js";
8
- import { emitModelChange, isModelEventsEnabled } from './Compat/modelEvents.js';
9
8
  import { getSubscriptionGcDelay } from "./subscriptionGcDelay.js";
10
9
  import { isMissingShareDoc } from './missingDoc.js';
11
10
  import { getRoot, ROOT_ID, GLOBAL_ROOT_ID, getRootTransportMode } from "./Root.js";
@@ -148,9 +147,6 @@ class Doc {
148
147
  doc.on('load', () => this._refData());
149
148
  doc.on('create', () => this._refData());
150
149
  doc.on('del', () => this._refMissingData());
151
- if (isModelEventsEnabled()) {
152
- doc.on('op', op => emitDocOp(this.collection, this.docId, op));
153
- }
154
150
  }
155
151
  _refMissingData() {
156
152
  _del([this.collection, this.docId]);
@@ -870,57 +866,6 @@ function createPendingDestroyEntry() {
870
866
  reject: rejectPending
871
867
  };
872
868
  }
873
- function emitDocOp(collection, docId, op) {
874
- if (!isModelEventsEnabled())
875
- return;
876
- const ops = Array.isArray(op) ? op : [op];
877
- for (const component of ops) {
878
- if (!component || !component.p)
879
- continue;
880
- const baseSegments = [collection, docId];
881
- let pathSegments = baseSegments.concat(component.p);
882
- const meta = {};
883
- let value;
884
- let prevValue;
885
- if (has(component, 'si') || has(component, 'sd')) {
886
- const index = component.p[component.p.length - 1];
887
- meta.op = has(component, 'si') ? 'stringInsert' : 'stringRemove';
888
- meta.index = index;
889
- pathSegments = baseSegments.concat(component.p.slice(0, -1));
890
- value = _getRaw(pathSegments);
891
- prevValue = component.sd;
892
- }
893
- else if (has(component, 'lm')) {
894
- meta.op = 'arrayMove';
895
- meta.from = component.p[component.p.length - 1];
896
- meta.to = component.lm;
897
- pathSegments = baseSegments.concat(component.p.slice(0, -1));
898
- value = _getRaw(pathSegments);
899
- }
900
- else if (has(component, 'li') || has(component, 'ld')) {
901
- meta.op = has(component, 'li') ? 'arrayInsert' : 'arrayRemove';
902
- meta.index = component.p[component.p.length - 1];
903
- value = _getRaw(pathSegments);
904
- prevValue = component.ld;
905
- }
906
- else if (has(component, 'na')) {
907
- meta.op = 'increment';
908
- meta.by = component.na;
909
- value = _getRaw(pathSegments);
910
- if (typeof value === 'number')
911
- prevValue = value - component.na;
912
- }
913
- else {
914
- meta.op = 'set';
915
- value = has(component, 'oi') ? component.oi : _getRaw(pathSegments);
916
- prevValue = component.od;
917
- }
918
- emitModelChange(pathSegments, value, prevValue, meta);
919
- }
920
- }
921
- function has(obj, key) {
922
- return Object.prototype.hasOwnProperty.call(obj, key);
923
- }
924
869
  const ERRORS = {
925
870
  notSubscribed: $doc => Error('trying to unsubscribe when not subscribed. Doc: ' + $doc.path())
926
871
  };
@@ -113,5 +113,6 @@ export class QuerySubscriptions {
113
113
 
114
114
  export const querySubscriptions: QuerySubscriptions
115
115
  export function getQuerySignal (collectionName: string, params: unknown, options?: QuerySignalOptions): Signal
116
+ export function materializeQueryDataDocsToCollection (collectionName: string, docs: unknown): void
116
117
  export function hashQuery (collectionName: string, params: unknown): string
117
118
  export function parseQueryHash (hash: string): QueryHashParts
package/dist/orm/Query.js CHANGED
@@ -2,8 +2,6 @@ import { raw } from '@nx-js/observer-util';
2
2
  import { set as _set, getRaw } from './dataTree.js';
3
3
  import getSignal from "./getSignal.js";
4
4
  import { getConnection } from "./connection.js";
5
- import { emitModelChange, isModelEventsEnabled } from './Compat/modelEvents.js';
6
- import { isCompatEnv } from './compatEnv.js';
7
5
  import { docSubscriptions } from './Doc.js';
8
6
  import FinalizationRegistry from "../utils/MockFinalizationRegistry.js";
9
7
  import SubscriptionState from './SubscriptionState.js';
@@ -127,22 +125,6 @@ export class Query {
127
125
  return;
128
126
  docs.splice(index, 0, ...newDocs);
129
127
  idsState.splice(index, 0, ...ids);
130
- if (!isModelEventsEnabled())
131
- return;
132
- const docsPath = [QUERIES, this.hash, 'docs'];
133
- const idsPath = [QUERIES, this.hash, 'ids'];
134
- for (let i = 0; i < newDocs.length; i++) {
135
- emitModelChange(rootId, docsPath.concat(index + i), newDocs[i], undefined, {
136
- op: 'queryInsert',
137
- index: index + i
138
- });
139
- }
140
- for (let i = 0; i < ids.length; i++) {
141
- emitModelChange(rootId, idsPath.concat(index + i), ids[i], undefined, {
142
- op: 'queryInsert',
143
- index: index + i
144
- });
145
- }
146
128
  });
147
129
  });
148
130
  this.shareQuery.on('move', (shareDocs, from, to) => {
@@ -153,26 +135,10 @@ export class Query {
153
135
  const ids = getPrivateData(rootId, [QUERIES, this.hash, 'ids']);
154
136
  if (!Array.isArray(docs) || !Array.isArray(ids))
155
137
  return;
156
- const prevDocs = isModelEventsEnabled() ? docs.slice() : undefined;
157
138
  docs.splice(from, shareDocs.length);
158
139
  docs.splice(to, 0, ...movedDocs);
159
- const prevIds = isModelEventsEnabled() ? ids.slice() : undefined;
160
140
  ids.splice(from, shareDocs.length);
161
141
  ids.splice(to, 0, ...movedIds);
162
- if (!isModelEventsEnabled())
163
- return;
164
- emitModelChange(rootId, [QUERIES, this.hash, 'docs'], docs, prevDocs, {
165
- op: 'queryMove',
166
- from,
167
- to,
168
- howMany: shareDocs.length
169
- });
170
- emitModelChange(rootId, [QUERIES, this.hash, 'ids'], ids, prevIds, {
171
- op: 'queryMove',
172
- from,
173
- to,
174
- howMany: shareDocs.length
175
- });
176
142
  });
177
143
  });
178
144
  this.shareQuery.on('remove', (shareDocs, index) => {
@@ -187,26 +153,8 @@ export class Query {
187
153
  const ids = getPrivateData(rootId, [QUERIES, this.hash, 'ids']);
188
154
  if (!Array.isArray(docs) || !Array.isArray(ids))
189
155
  return;
190
- const removedDocs = isModelEventsEnabled() ? docs.slice(index, index + shareDocs.length) : undefined;
191
156
  docs.splice(index, shareDocs.length);
192
- const removedIds = isModelEventsEnabled() ? ids.slice(index, index + docIds.length) : undefined;
193
157
  ids.splice(index, docIds.length);
194
- if (!isModelEventsEnabled())
195
- return;
196
- const docsPath = [QUERIES, this.hash, 'docs'];
197
- const idsPath = [QUERIES, this.hash, 'ids'];
198
- for (let i = 0; i < removedDocs.length; i++) {
199
- emitModelChange(rootId, docsPath.concat(index + i), undefined, removedDocs[i], {
200
- op: 'queryRemove',
201
- index: index + i
202
- });
203
- }
204
- for (let i = 0; i < removedIds.length; i++) {
205
- emitModelChange(rootId, idsPath.concat(index + i), undefined, removedIds[i], {
206
- op: 'queryRemove',
207
- index: index + i
208
- });
209
- }
210
158
  });
211
159
  });
212
160
  this.shareQuery.on('extra', extra => {
@@ -465,7 +413,7 @@ export class QuerySubscriptions {
465
413
  }
466
414
  subscribe($query, { intent = 'subscribe' } = {}) {
467
415
  const collectionName = $query[COLLECTION_NAME];
468
- const params = cloneQueryParams($query[PARAMS]);
416
+ const params = cloneQueryParams(collectionName, $query[PARAMS]);
469
417
  const transportHash = $query[HASH];
470
418
  const rootId = getOwningRootId($query);
471
419
  const ownerKey = getQueryOwnerKey(rootId, transportHash);
@@ -887,8 +835,6 @@ export class QuerySubscriptions {
887
835
  }
888
836
  export const querySubscriptions = new QuerySubscriptions();
889
837
  function maybeMaterializeQueryDocsToCollection(collectionName, shareDocs) {
890
- if (!isCompatEnv())
891
- return;
892
838
  for (const doc of shareDocs) {
893
839
  if (!doc?.id || doc.data == null)
894
840
  continue;
@@ -901,8 +847,26 @@ function maybeMaterializeQueryDocsToCollection(collectionName, shareDocs) {
901
847
  _set([collectionName, doc.id], raw(doc.data));
902
848
  }
903
849
  }
850
+ export function materializeQueryDataDocsToCollection(collectionName, docs) {
851
+ if (!Array.isArray(docs))
852
+ return;
853
+ for (const doc of docs) {
854
+ const rawDoc = raw(doc);
855
+ if (!isPlainObject(rawDoc))
856
+ continue;
857
+ const docId = rawDoc._id ?? rawDoc.id;
858
+ if (docId == null)
859
+ continue;
860
+ const existing = getRaw([collectionName, docId]);
861
+ if (existing != null)
862
+ continue;
863
+ const idFields = getIdFieldsForSegments([collectionName, docId]);
864
+ injectIdFields(rawDoc, idFields, docId);
865
+ _set([collectionName, docId], rawDoc);
866
+ }
867
+ }
904
868
  export function hashQuery(collectionName, params) {
905
- params = normalizeQueryParamsForHash(params);
869
+ params = normalizeQueryParamsForHash(collectionName, params);
906
870
  // TODO: probably makes sense to use fast-stable-json-stringify for this because of the params
907
871
  return JSON.stringify({ query: [collectionName, params] });
908
872
  }
@@ -916,7 +880,7 @@ export function parseQueryHash(hash) {
916
880
  }
917
881
  }
918
882
  export function getQuerySignal(collectionName, params, options) {
919
- params = cloneQueryParams(params);
883
+ params = cloneQueryParams(collectionName, params);
920
884
  const transportHash = hashQuery(collectionName, params);
921
885
  const { root, signalOptions } = parseQuerySignalOptions(options);
922
886
  const signalHash = getScopedSignalHash(root?.[ROOT_ID] ?? signalOptions.rootId, transportHash, 'querySignal');
@@ -969,10 +933,8 @@ function getOwningRootId($query) {
969
933
  function getQueryOwnerKey(rootId, transportHash) {
970
934
  return getScopedSignalHash(rootId, transportHash, 'queryOwner');
971
935
  }
972
- function cloneQueryParams(params) {
973
- if (!isCompatEnv())
974
- return JSON.parse(JSON.stringify(params));
975
- return cloneQueryParamsCompat(params);
936
+ export function cloneQueryParams(collectionName, params) {
937
+ return JSON.parse(JSON.stringify(params));
976
938
  }
977
939
  function parseQuerySignalOptions(options) {
978
940
  if (!options || typeof options !== 'object') {
@@ -984,27 +946,8 @@ function parseQuerySignalOptions(options) {
984
946
  const { root, ...signalOptions } = options;
985
947
  return { root, signalOptions };
986
948
  }
987
- function normalizeQueryParamsForHash(params) {
988
- if (!isCompatEnv())
989
- return params;
990
- return cloneQueryParamsCompat(params);
991
- }
992
- // Racer compat: keep query keys with undefined values by normalizing them to null
993
- // instead of dropping them via JSON serialization.
994
- function cloneQueryParamsCompat(value) {
995
- if (value === undefined)
996
- return null;
997
- if (value == null || typeof value !== 'object')
998
- return value;
999
- if (Array.isArray(value))
1000
- return value.map(item => cloneQueryParamsCompat(item));
1001
- const object = {};
1002
- for (const key in value) {
1003
- if (Object.prototype.hasOwnProperty.call(value, key)) {
1004
- object[key] = cloneQueryParamsCompat(value[key]);
1005
- }
1006
- }
1007
- return object;
949
+ function normalizeQueryParamsForHash(collectionName, params) {
950
+ return params;
1008
951
  }
1009
952
  function createPendingDestroyEntry() {
1010
953
  let resolvePending;
@@ -14,8 +14,12 @@ export type RootSignalRuntime = SignalBaseInstance & {
14
14
  [ROOT]?: RootSignalRuntime;
15
15
  [ROOT_ID]?: string;
16
16
  };
17
+ export type RootCloseCallback = (err?: unknown) => void;
17
18
  export declare function getRootSignal({ rootFunction, fetchOnly, rootId, ...options }?: RootSignalOptions): RootSignalRuntime;
18
19
  export declare function getRoot(signal: RootSignalRuntime | undefined): RootSignalRuntime | undefined;
20
+ export declare function closeRootSignalAsync(signal: RootSignalRuntime | undefined): Promise<void>;
21
+ export declare function closeRootSignal(signal: RootSignalRuntime | undefined): Promise<void>;
22
+ export declare function closeRootSignal(signal: RootSignalRuntime | undefined, callback?: RootCloseCallback): void;
19
23
  export declare function getRootFetchOnly(rootOrRootId: RootSignalRuntime | string | undefined): boolean;
20
24
  export declare function getRootTransportMode(rootOrRootId: RootSignalRuntime | string | undefined, intent?: RootTransportIntent): RootTransportIntent;
21
25
  export declare function registerRootFinalizer($root: RootSignalRuntime | undefined): void;
package/dist/orm/Root.js CHANGED
@@ -43,6 +43,22 @@ export function getRoot(signal) {
43
43
  else
44
44
  return undefined;
45
45
  }
46
+ export function closeRootSignalAsync(signal) {
47
+ const $root = getRoot(signal) || signal;
48
+ const rootId = $root?.[ROOT_ID];
49
+ unregisterRootFinalizer($root);
50
+ return disposeRootContext(rootId);
51
+ }
52
+ export function closeRootSignal(signal, callback) {
53
+ const promise = closeRootSignalAsync(signal);
54
+ if (!callback)
55
+ return promise;
56
+ promise
57
+ .then(() => callback?.())
58
+ .catch(err => {
59
+ callback(err);
60
+ });
61
+ }
46
62
  export function getRootFetchOnly(rootOrRootId) {
47
63
  const $root = typeof rootOrRootId === 'string'
48
64
  ? undefined
@@ -1,4 +1,3 @@
1
- import SignalCompat from './Compat/SignalCompat.js';
2
1
  import type { SignalConstructor } from './types/signal.js';
3
2
  export type { FromJsonSchema, InferZodSchema, JsonSchema, JsonSchemaObject, ZodLikeSchema } from './types/jsonSchema.js';
4
3
  export type { ComputedQueryParamsInput, QueryParams, QueryParamsInput } from './types/query.js';
@@ -7,6 +6,5 @@ export type { AppendPath, JoinPath, PathSegment, SignalPath, WildcardPathSegment
7
6
  export type { AggregationSignal, AnySignal, ArraySignal, CollectionAggregationSignal, CollectionDocument, CollectionDocumentModel, CollectionQuerySignal, CollectionSignal, CollectionSignalFromSpec, CollectionSpec, DocumentSignal, JsonSchemaSpec, MaybePromise, MaybePromiseSubResult, PublicSignal, LocalSignalFactory, RegisteredAggregationInput, RuntimeSignalConstructor, RuntimeSignalInstance, QuerySignal, RootCollections, RootSignal, SignalBaseInstance, SignalChild, SignalChildren, SignalClass, SignalConstructor, SignalForKind, SignalKind, SignalInstance, SignalModelConstructor, PrivateSignalFromSpec, RootPrivateCollections, SubResult, TypedAggregationInput, TypedAggregationSignal, TypedSignal, ZodSchemaSpec } from './types/signal.js';
8
7
  export type { CollectionsFromManifest, ModelEntry, ModelManifest, PathModelsFromManifest, PrivateCollectionsFromManifest } from './types/modelManifest.js';
9
8
  export { Signal, SEGMENTS, ARRAY_METHOD, GET, GETTERS, DEFAULT_GETTERS, regularBindings, extremelyLateBindings, isPublicCollectionSignal, isPublicDocumentSignal, isPublicCollection, isPrivateCollection } from './SignalBase.js';
10
- export { SignalCompat };
11
9
  declare const DefaultSignal: SignalConstructor;
12
10
  export default DefaultSignal;
@@ -1,7 +1,4 @@
1
1
  import { Signal } from "./SignalBase.js";
2
- import SignalCompat from './Compat/SignalCompat.js';
3
- import { isCompatEnv } from './compatEnv.js';
4
2
  export { Signal, SEGMENTS, ARRAY_METHOD, GET, GETTERS, DEFAULT_GETTERS, regularBindings, extremelyLateBindings, isPublicCollectionSignal, isPublicDocumentSignal, isPublicCollection, isPrivateCollection } from "./SignalBase.js";
5
- export { SignalCompat };
6
- const DefaultSignal = (isCompatEnv() ? SignalCompat : Signal);
3
+ const DefaultSignal = Signal;
7
4
  export default DefaultSignal;