teamplay 0.4.0-alpha.77 → 0.4.0-alpha.79

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.
@@ -13,7 +13,7 @@ import { publicOnly, fetchOnly, setFetchOnly } from '../connection.js'
13
13
  import { docSubscriptions } from '../Doc.js'
14
14
  import { IS_QUERY, getQuerySignal, querySubscriptions } from '../Query.js'
15
15
  import { IS_AGGREGATION, aggregationSubscriptions, getAggregationSignal } from '../Aggregation.js'
16
- import { getIdFieldsForSegments, isIdFieldPath, normalizeIdFields, isPlainObject } from '../idFields.js'
16
+ import { getIdFieldsForSegments, isIdFieldPath, isPublicDocPath, normalizeIdFields, isPlainObject } from '../idFields.js'
17
17
  import {
18
18
  del as _del,
19
19
  setReplace as _setReplace,
@@ -1015,7 +1015,7 @@ function setReplacePrivateCompatSync ($signal, value) {
1015
1015
  if (segments.length === 0) throw Error('Can\'t set the root signal data')
1016
1016
  const idFields = getIdFieldsForSegments(segments)
1017
1017
  if (isIdFieldPath(segments, idFields)) return
1018
- if (segments.length === 2) {
1018
+ if (isPublicDocPath(segments)) {
1019
1019
  value = normalizeIdFields(value, idFields, segments[1])
1020
1020
  }
1021
1021
  _setReplace(segments, value)
@@ -1065,7 +1065,7 @@ async function setReplaceOnSignal ($signal, value) {
1065
1065
  if (segments.length === 0) throw Error('Can\'t set the root signal data')
1066
1066
  const idFields = getIdFieldsForSegments(segments)
1067
1067
  if (isIdFieldPath(segments, idFields)) return
1068
- if (segments.length === 2) {
1068
+ if (isPublicDocPath(segments)) {
1069
1069
  value = normalizeIdFields(value, idFields, segments[1])
1070
1070
  }
1071
1071
  if (isPublicCollection(segments[0])) {
package/orm/SignalBase.js CHANGED
@@ -45,7 +45,15 @@ import { IS_QUERY, HASH, QUERIES } from './Query.js'
45
45
  import { AGGREGATIONS, IS_AGGREGATION, getAggregationCollectionName, getAggregationDocId } from './Aggregation.js'
46
46
  import { ROOT_FUNCTION, getRoot } from './Root.js'
47
47
  import { publicOnly } from './connection.js'
48
- import { DEFAULT_ID_FIELDS, getIdFieldsForSegments, isIdFieldPath, normalizeIdFields } from './idFields.js'
48
+ import {
49
+ DEFAULT_ID_FIELDS,
50
+ getIdFieldsForSegments,
51
+ isIdFieldPath,
52
+ isPublicDocPath,
53
+ normalizeIdFields,
54
+ prepareAddPayload,
55
+ resolveAddDocId
56
+ } from './idFields.js'
49
57
  import { isCompatEnv } from './compatEnv.js'
50
58
  import { resolveRefSegmentsSafe, resolveRefSignalSafe } from './Compat/refFallback.js'
51
59
  import { compatStartOnRoot, compatStopOnRoot, joinScopePath } from './Compat/startStopCompat.js'
@@ -262,7 +270,7 @@ export class Signal extends Function {
262
270
  if (this[SEGMENTS].length === 0) throw Error('Can\'t set the root signal data')
263
271
  const idFields = getIdFieldsForSegments(this[SEGMENTS])
264
272
  if (isIdFieldPath(this[SEGMENTS], idFields)) return
265
- if (this[SEGMENTS].length === 2) {
273
+ if (isPublicDocPath(this[SEGMENTS])) {
266
274
  value = normalizeIdFields(value, idFields, this[SEGMENTS][1])
267
275
  }
268
276
  if (isPublicCollection(this[SEGMENTS][0])) {
@@ -424,24 +432,9 @@ export class Signal extends Function {
424
432
 
425
433
  async add (value) {
426
434
  if (arguments.length > 1) throw Error('Signal.add() expects a single argument')
427
- if (!value || typeof value !== 'object') throw Error('Signal.add() expects an object argument')
428
- const hasId = value.id != null
429
- const hasUnderscoreId = value._id != null
430
- if (hasId && hasUnderscoreId && value.id !== value._id) {
431
- throw Error(
432
- `Signal.add() got conflicting "id" (${JSON.stringify(value.id)}) and "_id" (${JSON.stringify(value._id)})`
433
- )
434
- }
435
- let id = value.id ?? value._id
436
- id ??= uuid()
435
+ const id = resolveAddDocId(value, uuid)
437
436
  const idFields = getIdFieldsForSegments([this[SEGMENTS][0], id])
438
- if (idFields.includes('_id')) value._id = id
439
- if (idFields.includes('id')) {
440
- value.id = id
441
- } else if (value.id === id) {
442
- delete value.id
443
- }
444
- await this[id].set(value)
437
+ await this[id].set(prepareAddPayload(value, idFields, id))
445
438
  return id
446
439
  }
447
440
 
package/orm/dataTree.js CHANGED
@@ -3,7 +3,7 @@ import jsonDiff from 'json0-ot-diff'
3
3
  import diffMatchPatch from 'diff-match-patch'
4
4
  import { getConnection } from './connection.js'
5
5
  import setDiffDeep from '../utils/setDiffDeep.js'
6
- import { getIdFieldsForSegments, injectIdFields, stripIdFields, isPlainObject } from './idFields.js'
6
+ import { getIdFieldsForSegments, injectIdFields, stripIdFields, isPlainObject, isIdFieldPath } from './idFields.js'
7
7
  import { emitModelChange, isModelEventsEnabled } from './Compat/modelEvents.js'
8
8
  import { isSilentContextActive } from './Compat/silentContext.js'
9
9
  import { isCompatEnv } from './compatEnv.js'
@@ -158,7 +158,7 @@ export async function setPublicDoc (segments, value, deleteValue = false) {
158
158
  if (docId === 'undefined') throw Error(ERRORS.publicDocIdUndefined(segments))
159
159
  if (!(collection && docId)) throw Error(ERRORS.publicDoc(segments))
160
160
  const idFields = getIdFieldsForSegments([collection, docId])
161
- if (segments.length >= 3 && idFields.includes(segments[segments.length - 1])) return
161
+ if (isIdFieldPath(segments, idFields)) return
162
162
  const doc = getConnection().get(collection, docId)
163
163
  let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompatDocData: true })
164
164
  if (!docState.exists && segments.length > 2) {
@@ -177,7 +177,10 @@ export async function setPublicDoc (segments, value, deleteValue = false) {
177
177
  value = undefined
178
178
  } else {
179
179
  value = JSON.parse(JSON.stringify(value))
180
- value = stripIdFields(value, idFields)
180
+ // Only strip doc identity fields when writing the whole doc.
181
+ // Nested payloads like `fields.fieldId.media = { id: ... }` must preserve
182
+ // their own `id/_id` keys.
183
+ if (segments.length === 2) value = stripIdFields(value, idFields)
181
184
  }
182
185
  if (segments.length === 2 && !docState.exists) {
183
186
  // > create a new doc. Full doc data is provided
@@ -247,7 +250,7 @@ export async function setPublicDocReplace (segments, value) {
247
250
  if (docId === 'undefined') throw Error(ERRORS.publicDocIdUndefined(segments))
248
251
  if (!(collection && docId)) throw Error(ERRORS.publicDoc(segments))
249
252
  const idFields = getIdFieldsForSegments([collection, docId])
250
- if (segments.length >= 3 && idFields.includes(segments[segments.length - 1])) return
253
+ if (isIdFieldPath(segments, idFields)) return
251
254
  const doc = getConnection().get(collection, docId)
252
255
  let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateCompatDocData: true })
253
256
  if (!docState.exists && segments.length > 2) {
@@ -263,7 +266,9 @@ export async function setPublicDocReplace (segments, value) {
263
266
  value = raw(value)
264
267
  if (value != null) {
265
268
  value = JSON.parse(JSON.stringify(value))
266
- value = stripIdFields(value, idFields)
269
+ // Same contract as setPublicDoc(): only doc-root writes should strip the
270
+ // identity fields of the target document itself.
271
+ if (segments.length === 2) value = stripIdFields(value, idFields)
267
272
  }
268
273
 
269
274
  if (!docState.exists) {
@@ -296,7 +301,9 @@ export async function setPublicDocReplace (segments, value) {
296
301
 
297
302
  const relativePath = segments.slice(2)
298
303
  const previous = getRaw(segments)
299
- const normalizedPrevious = normalizeUndefined(stripIdFields(previous, idFields))
304
+ const normalizedPrevious = normalizeUndefined(
305
+ relativePath.length === 0 ? stripIdFields(previous, idFields) : previous
306
+ )
300
307
  const normalizedValue = normalizeUndefined(value)
301
308
  let op
302
309
  if (relativePath.length === 0) {
package/orm/idFields.js CHANGED
@@ -50,8 +50,39 @@ export function stripIdFields (value, idFields) {
50
50
  return next
51
51
  }
52
52
 
53
+ export function resolveAddDocId (value, getDefaultId) {
54
+ if (!value || typeof value !== 'object') throw Error('Signal.add() expects an object argument')
55
+ const hasId = value.id != null
56
+ const hasUnderscoreId = value._id != null
57
+ if (hasId && hasUnderscoreId && value.id !== value._id) {
58
+ throw Error(
59
+ `Signal.add() got conflicting "id" (${JSON.stringify(value.id)}) and "_id" (${JSON.stringify(value._id)})`
60
+ )
61
+ }
62
+ return value.id ?? value._id ?? getDefaultId()
63
+ }
64
+
65
+ export function prepareAddPayload (value, idFields, docId) {
66
+ if (idFields.includes('_id')) value._id = docId
67
+ if (idFields.includes('id')) {
68
+ value.id = docId
69
+ } else if (value.id === docId) {
70
+ delete value.id
71
+ }
72
+ return value
73
+ }
74
+
75
+ export function isPublicDocPath (segments) {
76
+ if (!Array.isArray(segments) || segments.length !== 2) return false
77
+ const [collection, docId] = segments
78
+ if (typeof collection !== 'string' || !collection) return false
79
+ if (collection[0] === '_' || collection[0] === '$') return false
80
+ return docId != null
81
+ }
82
+
53
83
  export function isIdFieldPath (segments, idFields) {
54
- if (segments.length < 3) return false
55
- const last = segments[segments.length - 1]
84
+ if (!Array.isArray(segments) || segments.length !== 3) return false
85
+ if (!isPublicDocPath(segments.slice(0, 2))) return false
86
+ const last = segments[2]
56
87
  return idFields.includes(last)
57
88
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamplay",
3
- "version": "0.4.0-alpha.77",
3
+ "version": "0.4.0-alpha.79",
4
4
  "description": "Full-stack signals ORM with multiplayer",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -83,5 +83,5 @@
83
83
  ]
84
84
  },
85
85
  "license": "MIT",
86
- "gitHead": "53f8b825a4c028c7b853d335402e402dbdd287af"
86
+ "gitHead": "d01896f3f43e3ef7a96a514ae7b870041fee2ed4"
87
87
  }