teamplay 0.3.25 → 0.3.27

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/orm/Signal.js CHANGED
@@ -179,6 +179,25 @@ export default class Signal extends Function {
179
179
  }
180
180
  }
181
181
 
182
+ async assign (value) {
183
+ if (arguments.length > 1) throw Error('Signal.assign() expects a single argument')
184
+ if (this[SEGMENTS].length === 0) throw Error('Can\'t assign to the root signal data')
185
+ if (!value) return
186
+ if (typeof value !== 'object') throw Error('Signal.assign() expects an object argument, got: ' + typeof value)
187
+ const promises = []
188
+ // use Object.keys() to avoid setting inherited properties
189
+ for (const key of Object.keys(value)) {
190
+ let promise
191
+ if (value[key] != null) {
192
+ promise = this[key].set(value[key])
193
+ } else {
194
+ promise = this[key].del()
195
+ }
196
+ promises.push(promise)
197
+ }
198
+ await Promise.all(promises)
199
+ }
200
+
182
201
  // TODO: implement a json0 operation for push
183
202
  async push (value) {
184
203
  if (arguments.length > 1) throw Error('Signal.push() expects a single argument')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamplay",
3
- "version": "0.3.25",
3
+ "version": "0.3.27",
4
4
  "description": "Full-stack signals ORM with multiplayer",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -17,18 +17,18 @@
17
17
  },
18
18
  "scripts": {
19
19
  "test": "npm run test-server && npm run test-client",
20
- "test-server": "node --expose-gc -r ./test/_init.cjs --test",
21
- "test-server-only": "node --expose-gc -r ./test/_init.cjs --test --test-only",
20
+ "test-server": "NODE_OPTIONS=\"--expose-gc\" mocha 'test/[!_]*.js'",
21
+ "test-server-only": "NODE_OPTIONS=\"--expose-gc\" mocha --grep '@only' 'test/[!_]*.js'",
22
22
  "test-client": "NODE_OPTIONS=\"$NODE_OPTIONS --expose-gc --experimental-vm-modules\" jest"
23
23
  },
24
24
  "dependencies": {
25
25
  "@nx-js/observer-util": "^4.1.3",
26
- "@teamplay/backend": "^0.3.25",
27
- "@teamplay/cache": "^0.3.25",
28
- "@teamplay/channel": "^0.3.25",
29
- "@teamplay/debug": "^0.3.25",
30
- "@teamplay/schema": "^0.3.25",
31
- "@teamplay/utils": "^0.3.25",
26
+ "@teamplay/backend": "^0.3.27",
27
+ "@teamplay/cache": "^0.3.27",
28
+ "@teamplay/channel": "^0.3.27",
29
+ "@teamplay/debug": "^0.3.27",
30
+ "@teamplay/schema": "^0.3.27",
31
+ "@teamplay/utils": "^0.3.27",
32
32
  "diff-match-patch": "^1.0.5",
33
33
  "events": "^3.3.0",
34
34
  "json0-ot-diff": "^1.1.2",
@@ -41,6 +41,7 @@
41
41
  "@testing-library/react": "^15.0.7",
42
42
  "jest": "^29.7.0",
43
43
  "jest-environment-jsdom": "^29.7.0",
44
+ "mocha": "^11.0.1",
44
45
  "react": "^18.3.1",
45
46
  "react-dom": "^18.3.1"
46
47
  },
@@ -63,5 +64,5 @@
63
64
  ]
64
65
  },
65
66
  "license": "MIT",
66
- "gitHead": "25f17014ec88230ab668efe1d25c933e61d82c1f"
67
+ "gitHead": "4a3fbec77123972874cb03bf5197983fe69f1118"
67
68
  }
@@ -31,6 +31,7 @@ export default function wrapIntoSuspense ({
31
31
  stateVersion: Symbol(), // eslint-disable-line symbol-description
32
32
  onStoreChange: undefined,
33
33
  scheduledUpdatePromise: undefined,
34
+ hasPendingUpdate: false,
34
35
  cache: new Map(),
35
36
  scheduleUpdate: promise => {
36
37
  if (!promise?.then) throw Error('scheduleUpdate() expects a promise')
@@ -47,6 +48,12 @@ export default function wrapIntoSuspense ({
47
48
  adm.stateVersion = Symbol() // eslint-disable-line symbol-description
48
49
  onStoreChange()
49
50
  }
51
+ // If there was a pending update before subscribe was called, trigger it asynchronously
52
+ // to avoid updating during the subscribe/render phase
53
+ if (adm.hasPendingUpdate) {
54
+ adm.hasPendingUpdate = false
55
+ queueMicrotask(() => adm.onStoreChange())
56
+ }
50
57
  return () => destroyAdm(adm)
51
58
  },
52
59
  getSnapshot () {
@@ -64,7 +71,14 @@ export default function wrapIntoSuspense ({
64
71
  componentId,
65
72
  createdAt: Date.now(),
66
73
  defer,
67
- triggerUpdate: () => adm.onStoreChange?.(),
74
+ triggerUpdate: () => {
75
+ if (adm.onStoreChange) {
76
+ adm.onStoreChange()
77
+ } else {
78
+ // Save pending update - subscribe not called yet (e.g., from useEffect/useLayoutEffect)
79
+ adm.hasPendingUpdate = true
80
+ }
81
+ },
68
82
  scheduleUpdate: promise => adm.scheduleUpdate?.(promise),
69
83
  cache: {
70
84
  get: key => adm.cache?.get(key),