js-bao 0.5.1 → 0.5.2

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.
@@ -100,6 +100,201 @@ var init_yjsValues = __esm({
100
100
  }
101
101
  });
102
102
 
103
+ // src/models/writeLifecycle.ts
104
+ function assertNever(x) {
105
+ throw new Error(`Unhandled field type: ${String(x)}`);
106
+ }
107
+ function fieldWriteKind(type) {
108
+ switch (type) {
109
+ case "string":
110
+ case "number":
111
+ case "boolean":
112
+ case "date":
113
+ case "id":
114
+ return "scalar";
115
+ case "stringset":
116
+ return "stringset";
117
+ default:
118
+ return assertNever(type);
119
+ }
120
+ }
121
+ function isKnownFieldType(type) {
122
+ return KNOWN_FIELD_TYPES.has(type);
123
+ }
124
+ function ensureStringSetYMap(rm, fieldName) {
125
+ const nested = rm.get(fieldName);
126
+ if (nested instanceof Y2.Map) return nested;
127
+ const fresh = new Y2.Map();
128
+ if (nested && typeof nested === "object") {
129
+ for (const [member, marker] of Object.entries(
130
+ nested
131
+ )) {
132
+ if (Boolean(marker)) fresh.set(member, true);
133
+ }
134
+ }
135
+ rm.set(fieldName, fresh);
136
+ return fresh;
137
+ }
138
+ function applyStringSetDelta(target, delta) {
139
+ if (delta.clear) {
140
+ for (const member of Array.from(target.keys())) target.delete(member);
141
+ }
142
+ if (delta.remove) {
143
+ for (const member of delta.remove) target.delete(String(member));
144
+ }
145
+ if (delta.add) {
146
+ for (const member of delta.add) {
147
+ const key = String(member);
148
+ if (target.get(key) !== true) target.set(key, true);
149
+ }
150
+ }
151
+ }
152
+ function replaceStringSet(rm, fieldName, members) {
153
+ const target = ensureStringSetYMap(rm, fieldName);
154
+ const desired = /* @__PURE__ */ new Set();
155
+ for (const member of members) desired.add(String(member));
156
+ for (const existing of Array.from(target.keys())) {
157
+ if (!desired.has(existing)) target.delete(existing);
158
+ }
159
+ for (const member of desired) {
160
+ if (target.get(member) !== true) target.set(member, true);
161
+ }
162
+ }
163
+ function applyStringSetChange(recordYMap, fieldName, change) {
164
+ const target = ensureStringSetYMap(recordYMap, fieldName);
165
+ applyStringSetDelta(target, {
166
+ add: change.additions,
167
+ remove: change.removals
168
+ });
169
+ }
170
+ function parseStringSetOp(value) {
171
+ if (value === null || typeof value !== "object" || Array.isArray(value) || value instanceof Y2.AbstractType) {
172
+ return null;
173
+ }
174
+ const keys = Object.keys(value);
175
+ const opKeys = keys.filter((k) => k.startsWith("$"));
176
+ if (opKeys.length === 0) return null;
177
+ const known = /* @__PURE__ */ new Set(["$add", "$remove", "$clear"]);
178
+ const unknown = keys.filter((k) => !known.has(k));
179
+ if (unknown.length > 0) {
180
+ throw new Error(
181
+ `Invalid stringset op: unexpected key(s) [${unknown.join(", ")}]. Only $add, $remove and $clear are supported.`
182
+ );
183
+ }
184
+ const obj = value;
185
+ const toMembers = (raw, opName) => {
186
+ if (raw === void 0) return [];
187
+ if (!Array.isArray(raw)) {
188
+ throw new Error(`Invalid stringset op: ${opName} must be an array.`);
189
+ }
190
+ return raw.map((m) => String(m));
191
+ };
192
+ return {
193
+ add: toMembers(obj.$add, "$add"),
194
+ remove: toMembers(obj.$remove, "$remove"),
195
+ clear: obj.$clear === true
196
+ };
197
+ }
198
+ function writeField(rm, declaredType, key, value, modelName) {
199
+ const kind = declaredType && isKnownFieldType(declaredType) ? fieldWriteKind(declaredType) : "scalar";
200
+ if (Array.isArray(value)) {
201
+ if (kind !== "stringset") {
202
+ throw new Error(
203
+ `Cannot write array value to field "${key}" on model "${modelName}": its declared type could not be resolved to a collection (stringset). Collection fields require schema metadata in the document (_meta_${modelName}); the model must be saved by a client at least once before a workflow writes one of its collection fields.`
204
+ );
205
+ }
206
+ replaceStringSet(rm, key, value);
207
+ return;
208
+ }
209
+ const op = parseStringSetOp(value);
210
+ if (op) {
211
+ if (kind !== "stringset") {
212
+ throw new Error(
213
+ `Cannot apply a stringset op ({ $add/$remove/$clear }) to field "${key}" on model "${modelName}": its declared type is ${declaredType ? `"${declaredType}"` : "unresolved"}, not a collection (stringset). Op-objects are only valid for stringset / refersToMany fields with schema metadata (_meta_${modelName}).`
214
+ );
215
+ }
216
+ applyStringSetDelta(ensureStringSetYMap(rm, key), op);
217
+ return;
218
+ }
219
+ if (kind === "stringset") {
220
+ throw new Error(
221
+ `Field "${key}" on model "${modelName}" is a stringset and requires an array (replace) or { $add/$remove/$clear } (delta) value; received ${value === null ? "null" : typeof value}.`
222
+ );
223
+ }
224
+ rm.set(key, value);
225
+ }
226
+ function registerFunctionDefaultGenerator(name, fn) {
227
+ FUNCTION_DEFAULT_GENERATORS.set(name, fn);
228
+ }
229
+ function decodeFunctionDefault(name) {
230
+ return FUNCTION_DEFAULT_GENERATORS.get(name);
231
+ }
232
+ function resolveDefaultValue(rawDefault, opts = {}) {
233
+ if (typeof rawDefault === "function") return rawDefault();
234
+ if (typeof rawDefault === "string" && rawDefault.startsWith("$")) {
235
+ if (rawDefault.startsWith("$$")) return rawDefault.slice(1);
236
+ const name = rawDefault.slice(1);
237
+ const gen = opts.decode?.(name) ?? decodeFunctionDefault(name);
238
+ if (!gen) {
239
+ throw new Error(
240
+ `Unknown function default "${rawDefault}" for field "${opts.fieldName ?? "?"}"${opts.modelName ? ` on model "${opts.modelName}"` : ""}: no generator is registered for "${name}". Register it via registerFunctionDefaultGenerator("${name}", fn) so the server can populate the field the same way the client does.`
241
+ );
242
+ }
243
+ return gen();
244
+ }
245
+ return rawDefault;
246
+ }
247
+ function applyDefaultsFromSchema(fields, data, opts = {}) {
248
+ for (const [fieldName, field] of Object.entries(fields)) {
249
+ if (fieldName === "id") continue;
250
+ if (!field || field.default === void 0) continue;
251
+ if (field.default === UNKNOWN_FUNCTION_DEFAULT) {
252
+ continue;
253
+ }
254
+ if (Object.prototype.hasOwnProperty.call(data, fieldName) && data[fieldName] !== void 0) {
255
+ continue;
256
+ }
257
+ data[fieldName] = resolveDefaultValue(field.default, {
258
+ fieldName,
259
+ modelName: opts.modelName,
260
+ decode: opts.decodeFunctionDefault
261
+ });
262
+ }
263
+ return data;
264
+ }
265
+ function applyAutoStampsFromSchema(fields, data, opts) {
266
+ const { isNew, now } = opts;
267
+ for (const [fieldName, field] of Object.entries(fields)) {
268
+ const stamp = field?.autoStamp;
269
+ if (!stamp) continue;
270
+ const explicit = Object.prototype.hasOwnProperty.call(data, fieldName) && data[fieldName] !== null && data[fieldName] !== void 0;
271
+ if (explicit) continue;
272
+ if (stamp === "create" && !isNew) continue;
273
+ data[fieldName] = now;
274
+ }
275
+ return data;
276
+ }
277
+ var Y2, import_ulid, KNOWN_FIELD_TYPE_MAP, KNOWN_FIELD_TYPES, FUNCTION_DEFAULT_GENERATORS, UNKNOWN_FUNCTION_DEFAULT;
278
+ var init_writeLifecycle = __esm({
279
+ "src/models/writeLifecycle.ts"() {
280
+ "use strict";
281
+ Y2 = __toESM(require("yjs"), 1);
282
+ import_ulid = require("ulid");
283
+ KNOWN_FIELD_TYPE_MAP = {
284
+ string: true,
285
+ number: true,
286
+ boolean: true,
287
+ date: true,
288
+ id: true,
289
+ stringset: true
290
+ };
291
+ KNOWN_FIELD_TYPES = new Set(Object.keys(KNOWN_FIELD_TYPE_MAP));
292
+ FUNCTION_DEFAULT_GENERATORS = /* @__PURE__ */ new Map();
293
+ registerFunctionDefaultGenerator("generate_ulid", () => (0, import_ulid.ulid)());
294
+ UNKNOWN_FUNCTION_DEFAULT = "$unknown_function";
295
+ }
296
+ });
297
+
103
298
  // src/models/metaSync.ts
104
299
  function inferFieldType(value) {
105
300
  if (isStringSetYMap(value)) return "stringset";
@@ -121,7 +316,10 @@ function encodeDefault(value) {
121
316
  if (value === void 0 || value === null) return void 0;
122
317
  if (typeof value === "function") {
123
318
  const name = KNOWN_FUNCTION_DEFAULTS.get(value);
124
- return name ? `$${name}` : "$unknown_function";
319
+ return name ? `$${name}` : UNKNOWN_FUNCTION_DEFAULT;
320
+ }
321
+ if (typeof value === "string" && value.startsWith("$")) {
322
+ return `$${value}`;
125
323
  }
126
324
  return value;
127
325
  }
@@ -147,7 +345,7 @@ function syncModelMeta(yDoc, modelName, schema) {
147
345
  if (compoundConstraints.length > 0) {
148
346
  let constraints = meta.get("_constraints");
149
347
  if (!constraints) {
150
- constraints = new Y2.Map();
348
+ constraints = new Y3.Map();
151
349
  meta.set("_constraints", constraints);
152
350
  }
153
351
  for (const constraint of compoundConstraints) {
@@ -158,7 +356,7 @@ function syncModelMeta(yDoc, modelName, schema) {
158
356
  if (relationships && Object.keys(relationships).length > 0) {
159
357
  let rels = meta.get("_relationships");
160
358
  if (!rels) {
161
- rels = new Y2.Map();
359
+ rels = new Y3.Map();
162
360
  meta.set("_relationships", rels);
163
361
  }
164
362
  for (const [relName, relConfig] of Object.entries(relationships)) {
@@ -170,7 +368,7 @@ function syncModelMeta(yDoc, modelName, schema) {
170
368
  function syncFieldMeta(metaMap, fieldName, fieldOpts) {
171
369
  let fieldMeta = metaMap.get(fieldName);
172
370
  if (!fieldMeta) {
173
- fieldMeta = new Y2.Map();
371
+ fieldMeta = new Y3.Map();
174
372
  metaMap.set(fieldName, fieldMeta);
175
373
  }
176
374
  setIfChanged(fieldMeta, "type", fieldOpts.type);
@@ -187,7 +385,7 @@ function syncFieldMeta(metaMap, fieldName, fieldOpts) {
187
385
  function syncConstraintMeta(constraintsMap, constraint) {
188
386
  let cMeta = constraintsMap.get(constraint.name);
189
387
  if (!cMeta) {
190
- cMeta = new Y2.Map();
388
+ cMeta = new Y3.Map();
191
389
  constraintsMap.set(constraint.name, cMeta);
192
390
  }
193
391
  setIfChanged(cMeta, "type", "unique");
@@ -197,7 +395,7 @@ function syncConstraintMeta(constraintsMap, constraint) {
197
395
  function syncRelationshipMeta(relsMap, relName, relConfig) {
198
396
  let relMeta = relsMap.get(relName);
199
397
  if (!relMeta) {
200
- relMeta = new Y2.Map();
398
+ relMeta = new Y3.Map();
201
399
  relsMap.set(relName, relMeta);
202
400
  }
203
401
  for (const [key, value] of Object.entries(relConfig)) {
@@ -212,7 +410,7 @@ function syncInferredMeta(yDoc, modelName, recordData) {
212
410
  if (fieldName.startsWith("_")) continue;
213
411
  let fieldMeta = meta.get(fieldName);
214
412
  if (!fieldMeta) {
215
- fieldMeta = new Y2.Map();
413
+ fieldMeta = new Y3.Map();
216
414
  meta.set(fieldName, fieldMeta);
217
415
  }
218
416
  if (!fieldMeta.has("type")) {
@@ -228,34 +426,63 @@ function setIfChanged(map, key, value) {
228
426
  map.set(key, value);
229
427
  }
230
428
  }
231
- var Y2, KNOWN_FUNCTION_DEFAULTS, _syncedCache;
429
+ var Y3, KNOWN_FUNCTION_DEFAULTS, _syncedCache;
232
430
  var init_metaSync = __esm({
233
431
  "src/models/metaSync.ts"() {
234
432
  "use strict";
235
- Y2 = __toESM(require("yjs"), 1);
433
+ Y3 = __toESM(require("yjs"), 1);
236
434
  init_yjsValues();
435
+ init_writeLifecycle();
237
436
  KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
238
437
  _syncedCache = /* @__PURE__ */ new WeakMap();
239
438
  }
240
439
  });
241
440
 
441
+ // src/utils/uniqueIndex.ts
442
+ function buildUniqueKey(recordData, fields) {
443
+ const keyParts = [];
444
+ for (const field of fields) {
445
+ const value = recordData instanceof Y4.Map ? recordData.get(field) : recordData[field];
446
+ if (value === null || value === void 0) {
447
+ return null;
448
+ }
449
+ keyParts.push(String(value));
450
+ }
451
+ return keyParts.join("|");
452
+ }
453
+ function uniqueIndexMapName(modelName, constraintName) {
454
+ return `_uniqueIdx_${modelName}_${constraintName}`;
455
+ }
456
+ function fieldUniqueConstraintName(modelName, fieldName) {
457
+ return `${modelName}_${fieldName}_unique`;
458
+ }
459
+ var Y4;
460
+ var init_uniqueIndex = __esm({
461
+ "src/utils/uniqueIndex.ts"() {
462
+ "use strict";
463
+ Y4 = __toESM(require("yjs"), 1);
464
+ }
465
+ });
466
+
242
467
  // src/models/BaseModel.ts
243
468
  function generateULID() {
244
- return (0, import_ulid.ulid)();
469
+ return (0, import_ulid2.ulid)();
245
470
  }
246
- var Y3, import_ulid, Logger;
471
+ var Y5, import_ulid2, Logger;
247
472
  var init_BaseModel = __esm({
248
473
  "src/models/BaseModel.ts"() {
249
474
  "use strict";
250
- Y3 = __toESM(require("yjs"), 1);
251
- import_ulid = require("ulid");
475
+ Y5 = __toESM(require("yjs"), 1);
476
+ import_ulid2 = require("ulid");
252
477
  init_StringSet();
253
478
  init_documentTypes();
254
479
  init_DocumentQueryTranslator();
255
480
  init_CursorManager();
256
481
  init_sql();
257
482
  init_metaSync();
483
+ init_writeLifecycle();
258
484
  init_yjsValues();
485
+ init_uniqueIndex();
259
486
  Logger = class {
260
487
  static _logLevel = 1 /* ERROR */;
261
488
  static _logCallback = null;
@@ -349,19 +576,36 @@ var init_ModelRegistry = __esm({
349
576
  var cloudflare_exports = {};
350
577
  __export(cloudflare_exports, {
351
578
  DOClientEngine: () => DOClientEngine,
579
+ applyAutoStampsFromSchema: () => applyAutoStampsFromSchema,
580
+ applyDefaultsFromSchema: () => applyDefaultsFromSchema,
581
+ applyStringSetChange: () => applyStringSetChange,
582
+ applyStringSetDelta: () => applyStringSetDelta,
583
+ assertNever: () => assertNever,
584
+ buildUniqueKey: () => buildUniqueKey,
352
585
  clearMetaSyncCache: () => clearMetaSyncCache,
353
586
  connectDoDb: () => connectDoDb,
587
+ decodeFunctionDefault: () => decodeFunctionDefault,
354
588
  discoverModelNames: () => discoverModelNames,
355
589
  discoverSchema: () => discoverSchema,
590
+ ensureStringSetYMap: () => ensureStringSetYMap,
591
+ fieldUniqueConstraintName: () => fieldUniqueConstraintName,
592
+ fieldWriteKind: () => fieldWriteKind,
356
593
  getActiveDOEngine: () => getActiveDOEngine,
357
594
  inferFieldType: () => inferFieldType,
358
595
  initJsBaoDO: () => initJsBaoDO,
596
+ isKnownFieldType: () => isKnownFieldType,
359
597
  loadSchemaFromTomlString: () => loadSchemaFromTomlString,
598
+ parseStringSetOp: () => parseStringSetOp,
360
599
  registerFunctionDefault: () => registerFunctionDefault,
600
+ registerFunctionDefaultGenerator: () => registerFunctionDefaultGenerator,
601
+ replaceStringSet: () => replaceStringSet,
361
602
  resetJsBaoDO: () => resetJsBaoDO,
603
+ resolveDefaultValue: () => resolveDefaultValue,
362
604
  schemaToToml: () => schemaToToml,
363
605
  syncInferredMeta: () => syncInferredMeta,
364
- syncModelMeta: () => syncModelMeta
606
+ syncModelMeta: () => syncModelMeta,
607
+ uniqueIndexMapName: () => uniqueIndexMapName,
608
+ writeField: () => writeField
365
609
  });
366
610
  module.exports = __toCommonJS(cloudflare_exports);
367
611
 
@@ -1242,7 +1486,7 @@ function connectDoDb(options) {
1242
1486
  }
1243
1487
 
1244
1488
  // src/utils/yDocSchema.ts
1245
- var Y4 = __toESM(require("yjs"), 1);
1489
+ var Y6 = __toESM(require("yjs"), 1);
1246
1490
  init_yjsValues();
1247
1491
  function discoverSchema(yDoc) {
1248
1492
  const models = {};
@@ -1277,7 +1521,7 @@ function discoverModelNames(yDoc) {
1277
1521
  function materializeMap(yDoc, key) {
1278
1522
  try {
1279
1523
  const map = yDoc.getMap(key);
1280
- return map instanceof Y4.Map ? map : null;
1524
+ return map instanceof Y6.Map ? map : null;
1281
1525
  } catch {
1282
1526
  return null;
1283
1527
  }
@@ -1287,11 +1531,11 @@ function readModelMeta(metaMap) {
1287
1531
  let constraints;
1288
1532
  let relationships;
1289
1533
  for (const [key, value] of metaMap.entries()) {
1290
- if (key === "_constraints" && value instanceof Y4.Map) {
1534
+ if (key === "_constraints" && value instanceof Y6.Map) {
1291
1535
  constraints = readConstraints(value);
1292
- } else if (key === "_relationships" && value instanceof Y4.Map) {
1536
+ } else if (key === "_relationships" && value instanceof Y6.Map) {
1293
1537
  relationships = readRelationships(value);
1294
- } else if (value instanceof Y4.Map) {
1538
+ } else if (value instanceof Y6.Map) {
1295
1539
  fields[key] = readFieldMeta(value);
1296
1540
  }
1297
1541
  }
@@ -1326,7 +1570,7 @@ function inferModelFromData(dataMap) {
1326
1570
  const fields = {};
1327
1571
  let sampled = 0;
1328
1572
  for (const [_recordId, recordValue] of dataMap.entries()) {
1329
- if (!(recordValue instanceof Y4.Map)) continue;
1573
+ if (!(recordValue instanceof Y6.Map)) continue;
1330
1574
  if (++sampled > 5) break;
1331
1575
  for (const [fieldName, value] of recordValue.entries()) {
1332
1576
  if (fieldName.startsWith("_")) continue;
@@ -1354,7 +1598,7 @@ function inferTypeFromValue(value) {
1354
1598
  function readConstraints(constraintsMap) {
1355
1599
  const out = {};
1356
1600
  for (const [name, value] of constraintsMap.entries()) {
1357
- if (!(value instanceof Y4.Map)) continue;
1601
+ if (!(value instanceof Y6.Map)) continue;
1358
1602
  let fields = [];
1359
1603
  const rawFields = value.get("fields");
1360
1604
  if (typeof rawFields === "string") {
@@ -1373,7 +1617,7 @@ function readConstraints(constraintsMap) {
1373
1617
  function readRelationships(relsMap) {
1374
1618
  const out = {};
1375
1619
  for (const [name, value] of relsMap.entries()) {
1376
- if (!(value instanceof Y4.Map)) continue;
1620
+ if (!(value instanceof Y6.Map)) continue;
1377
1621
  const rel = {};
1378
1622
  for (const [k, v] of value.entries()) {
1379
1623
  rel[k] = v;
@@ -1452,6 +1696,7 @@ var import_smol_toml = require("smol-toml");
1452
1696
  // src/models/schema.ts
1453
1697
  init_BaseModel();
1454
1698
  init_ModelRegistry();
1699
+ init_uniqueIndex();
1455
1700
  function defineModelSchema(input) {
1456
1701
  const { name, fields } = input;
1457
1702
  const options = {
@@ -1494,7 +1739,7 @@ function resolveUniqueConstraints(modelName, fields, customConstraints) {
1494
1739
  for (const [fieldName, options] of fields.entries()) {
1495
1740
  if (options.unique) {
1496
1741
  resolved.push({
1497
- name: `${modelName}_${fieldName}_unique`,
1742
+ name: fieldUniqueConstraintName(modelName, fieldName),
1498
1743
  fields: [fieldName]
1499
1744
  });
1500
1745
  }
@@ -1740,4 +1985,6 @@ function loadSchemaFromTomlString(tomlString, options = {}) {
1740
1985
  }
1741
1986
 
1742
1987
  // src/cloudflare.ts
1988
+ init_uniqueIndex();
1743
1989
  init_metaSync();
1990
+ init_writeLifecycle();