js-bao 0.5.0 → 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.
@@ -84,9 +84,220 @@ var init_DocumentQueryTranslator = __esm({
84
84
  }
85
85
  });
86
86
 
87
+ // src/utils/yjsValues.ts
88
+ function isStringSetYMap(value) {
89
+ if (!(value instanceof Y.Map)) return false;
90
+ for (const v of value.values()) {
91
+ if (v !== true) return false;
92
+ }
93
+ return true;
94
+ }
95
+ var Y;
96
+ var init_yjsValues = __esm({
97
+ "src/utils/yjsValues.ts"() {
98
+ "use strict";
99
+ Y = __toESM(require("yjs"), 1);
100
+ }
101
+ });
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
+
87
298
  // src/models/metaSync.ts
88
299
  function inferFieldType(value) {
89
- if (value instanceof Y.Map) return "stringset";
300
+ if (isStringSetYMap(value)) return "stringset";
90
301
  switch (typeof value) {
91
302
  case "string":
92
303
  return "string";
@@ -105,7 +316,10 @@ function encodeDefault(value) {
105
316
  if (value === void 0 || value === null) return void 0;
106
317
  if (typeof value === "function") {
107
318
  const name = KNOWN_FUNCTION_DEFAULTS.get(value);
108
- return name ? `$${name}` : "$unknown_function";
319
+ return name ? `$${name}` : UNKNOWN_FUNCTION_DEFAULT;
320
+ }
321
+ if (typeof value === "string" && value.startsWith("$")) {
322
+ return `$${value}`;
109
323
  }
110
324
  return value;
111
325
  }
@@ -131,7 +345,7 @@ function syncModelMeta(yDoc, modelName, schema) {
131
345
  if (compoundConstraints.length > 0) {
132
346
  let constraints = meta.get("_constraints");
133
347
  if (!constraints) {
134
- constraints = new Y.Map();
348
+ constraints = new Y3.Map();
135
349
  meta.set("_constraints", constraints);
136
350
  }
137
351
  for (const constraint of compoundConstraints) {
@@ -142,7 +356,7 @@ function syncModelMeta(yDoc, modelName, schema) {
142
356
  if (relationships && Object.keys(relationships).length > 0) {
143
357
  let rels = meta.get("_relationships");
144
358
  if (!rels) {
145
- rels = new Y.Map();
359
+ rels = new Y3.Map();
146
360
  meta.set("_relationships", rels);
147
361
  }
148
362
  for (const [relName, relConfig] of Object.entries(relationships)) {
@@ -154,7 +368,7 @@ function syncModelMeta(yDoc, modelName, schema) {
154
368
  function syncFieldMeta(metaMap, fieldName, fieldOpts) {
155
369
  let fieldMeta = metaMap.get(fieldName);
156
370
  if (!fieldMeta) {
157
- fieldMeta = new Y.Map();
371
+ fieldMeta = new Y3.Map();
158
372
  metaMap.set(fieldName, fieldMeta);
159
373
  }
160
374
  setIfChanged(fieldMeta, "type", fieldOpts.type);
@@ -162,6 +376,7 @@ function syncFieldMeta(metaMap, fieldName, fieldOpts) {
162
376
  if (fieldOpts.unique) setIfChanged(fieldMeta, "unique", true);
163
377
  if (fieldOpts.required) setIfChanged(fieldMeta, "required", true);
164
378
  if (fieldOpts.autoAssign) setIfChanged(fieldMeta, "autoAssign", true);
379
+ if (fieldOpts.autoStamp) setIfChanged(fieldMeta, "autoStamp", fieldOpts.autoStamp);
165
380
  if (fieldOpts.maxLength !== void 0) setIfChanged(fieldMeta, "maxLength", fieldOpts.maxLength);
166
381
  if (fieldOpts.maxCount !== void 0) setIfChanged(fieldMeta, "maxCount", fieldOpts.maxCount);
167
382
  const encoded = encodeDefault(fieldOpts.default);
@@ -170,7 +385,7 @@ function syncFieldMeta(metaMap, fieldName, fieldOpts) {
170
385
  function syncConstraintMeta(constraintsMap, constraint) {
171
386
  let cMeta = constraintsMap.get(constraint.name);
172
387
  if (!cMeta) {
173
- cMeta = new Y.Map();
388
+ cMeta = new Y3.Map();
174
389
  constraintsMap.set(constraint.name, cMeta);
175
390
  }
176
391
  setIfChanged(cMeta, "type", "unique");
@@ -180,7 +395,7 @@ function syncConstraintMeta(constraintsMap, constraint) {
180
395
  function syncRelationshipMeta(relsMap, relName, relConfig) {
181
396
  let relMeta = relsMap.get(relName);
182
397
  if (!relMeta) {
183
- relMeta = new Y.Map();
398
+ relMeta = new Y3.Map();
184
399
  relsMap.set(relName, relMeta);
185
400
  }
186
401
  for (const [key, value] of Object.entries(relConfig)) {
@@ -195,7 +410,7 @@ function syncInferredMeta(yDoc, modelName, recordData) {
195
410
  if (fieldName.startsWith("_")) continue;
196
411
  let fieldMeta = meta.get(fieldName);
197
412
  if (!fieldMeta) {
198
- fieldMeta = new Y.Map();
413
+ fieldMeta = new Y3.Map();
199
414
  meta.set(fieldName, fieldMeta);
200
415
  }
201
416
  if (!fieldMeta.has("type")) {
@@ -211,32 +426,63 @@ function setIfChanged(map, key, value) {
211
426
  map.set(key, value);
212
427
  }
213
428
  }
214
- var Y, KNOWN_FUNCTION_DEFAULTS, _syncedCache;
429
+ var Y3, KNOWN_FUNCTION_DEFAULTS, _syncedCache;
215
430
  var init_metaSync = __esm({
216
431
  "src/models/metaSync.ts"() {
217
432
  "use strict";
218
- Y = __toESM(require("yjs"), 1);
433
+ Y3 = __toESM(require("yjs"), 1);
434
+ init_yjsValues();
435
+ init_writeLifecycle();
219
436
  KNOWN_FUNCTION_DEFAULTS = /* @__PURE__ */ new WeakMap();
220
437
  _syncedCache = /* @__PURE__ */ new WeakMap();
221
438
  }
222
439
  });
223
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
+
224
467
  // src/models/BaseModel.ts
225
468
  function generateULID() {
226
- return (0, import_ulid.ulid)();
469
+ return (0, import_ulid2.ulid)();
227
470
  }
228
- var Y2, import_ulid, Logger;
471
+ var Y5, import_ulid2, Logger;
229
472
  var init_BaseModel = __esm({
230
473
  "src/models/BaseModel.ts"() {
231
474
  "use strict";
232
- Y2 = __toESM(require("yjs"), 1);
233
- import_ulid = require("ulid");
475
+ Y5 = __toESM(require("yjs"), 1);
476
+ import_ulid2 = require("ulid");
234
477
  init_StringSet();
235
478
  init_documentTypes();
236
479
  init_DocumentQueryTranslator();
237
480
  init_CursorManager();
238
481
  init_sql();
239
482
  init_metaSync();
483
+ init_writeLifecycle();
484
+ init_yjsValues();
485
+ init_uniqueIndex();
240
486
  Logger = class {
241
487
  static _logLevel = 1 /* ERROR */;
242
488
  static _logCallback = null;
@@ -330,19 +576,36 @@ var init_ModelRegistry = __esm({
330
576
  var cloudflare_exports = {};
331
577
  __export(cloudflare_exports, {
332
578
  DOClientEngine: () => DOClientEngine,
579
+ applyAutoStampsFromSchema: () => applyAutoStampsFromSchema,
580
+ applyDefaultsFromSchema: () => applyDefaultsFromSchema,
581
+ applyStringSetChange: () => applyStringSetChange,
582
+ applyStringSetDelta: () => applyStringSetDelta,
583
+ assertNever: () => assertNever,
584
+ buildUniqueKey: () => buildUniqueKey,
333
585
  clearMetaSyncCache: () => clearMetaSyncCache,
334
586
  connectDoDb: () => connectDoDb,
587
+ decodeFunctionDefault: () => decodeFunctionDefault,
335
588
  discoverModelNames: () => discoverModelNames,
336
589
  discoverSchema: () => discoverSchema,
590
+ ensureStringSetYMap: () => ensureStringSetYMap,
591
+ fieldUniqueConstraintName: () => fieldUniqueConstraintName,
592
+ fieldWriteKind: () => fieldWriteKind,
337
593
  getActiveDOEngine: () => getActiveDOEngine,
338
594
  inferFieldType: () => inferFieldType,
339
595
  initJsBaoDO: () => initJsBaoDO,
596
+ isKnownFieldType: () => isKnownFieldType,
340
597
  loadSchemaFromTomlString: () => loadSchemaFromTomlString,
598
+ parseStringSetOp: () => parseStringSetOp,
341
599
  registerFunctionDefault: () => registerFunctionDefault,
600
+ registerFunctionDefaultGenerator: () => registerFunctionDefaultGenerator,
601
+ replaceStringSet: () => replaceStringSet,
342
602
  resetJsBaoDO: () => resetJsBaoDO,
603
+ resolveDefaultValue: () => resolveDefaultValue,
343
604
  schemaToToml: () => schemaToToml,
344
605
  syncInferredMeta: () => syncInferredMeta,
345
- syncModelMeta: () => syncModelMeta
606
+ syncModelMeta: () => syncModelMeta,
607
+ uniqueIndexMapName: () => uniqueIndexMapName,
608
+ writeField: () => writeField
346
609
  });
347
610
  module.exports = __toCommonJS(cloudflare_exports);
348
611
 
@@ -1223,7 +1486,8 @@ function connectDoDb(options) {
1223
1486
  }
1224
1487
 
1225
1488
  // src/utils/yDocSchema.ts
1226
- var Y3 = __toESM(require("yjs"), 1);
1489
+ var Y6 = __toESM(require("yjs"), 1);
1490
+ init_yjsValues();
1227
1491
  function discoverSchema(yDoc) {
1228
1492
  const models = {};
1229
1493
  const metaNames = /* @__PURE__ */ new Set();
@@ -1257,7 +1521,7 @@ function discoverModelNames(yDoc) {
1257
1521
  function materializeMap(yDoc, key) {
1258
1522
  try {
1259
1523
  const map = yDoc.getMap(key);
1260
- return map instanceof Y3.Map ? map : null;
1524
+ return map instanceof Y6.Map ? map : null;
1261
1525
  } catch {
1262
1526
  return null;
1263
1527
  }
@@ -1267,11 +1531,11 @@ function readModelMeta(metaMap) {
1267
1531
  let constraints;
1268
1532
  let relationships;
1269
1533
  for (const [key, value] of metaMap.entries()) {
1270
- if (key === "_constraints" && value instanceof Y3.Map) {
1534
+ if (key === "_constraints" && value instanceof Y6.Map) {
1271
1535
  constraints = readConstraints(value);
1272
- } else if (key === "_relationships" && value instanceof Y3.Map) {
1536
+ } else if (key === "_relationships" && value instanceof Y6.Map) {
1273
1537
  relationships = readRelationships(value);
1274
- } else if (value instanceof Y3.Map) {
1538
+ } else if (value instanceof Y6.Map) {
1275
1539
  fields[key] = readFieldMeta(value);
1276
1540
  }
1277
1541
  }
@@ -1290,6 +1554,10 @@ function readFieldMeta(fieldMap) {
1290
1554
  if (fieldMap.get("unique") === true) field.unique = true;
1291
1555
  if (fieldMap.get("required") === true) field.required = true;
1292
1556
  if (fieldMap.get("autoAssign") === true) field.autoAssign = true;
1557
+ const autoStamp = fieldMap.get("autoStamp");
1558
+ if (typeof autoStamp === "string" && (autoStamp === "create" || autoStamp === "update" || autoStamp === "both")) {
1559
+ field.autoStamp = autoStamp;
1560
+ }
1293
1561
  const def = fieldMap.get("default");
1294
1562
  if (def !== void 0) field.default = def;
1295
1563
  const maxLength = fieldMap.get("maxLength");
@@ -1302,7 +1570,7 @@ function inferModelFromData(dataMap) {
1302
1570
  const fields = {};
1303
1571
  let sampled = 0;
1304
1572
  for (const [_recordId, recordValue] of dataMap.entries()) {
1305
- if (!(recordValue instanceof Y3.Map)) continue;
1573
+ if (!(recordValue instanceof Y6.Map)) continue;
1306
1574
  if (++sampled > 5) break;
1307
1575
  for (const [fieldName, value] of recordValue.entries()) {
1308
1576
  if (fieldName.startsWith("_")) continue;
@@ -1315,7 +1583,7 @@ function inferModelFromData(dataMap) {
1315
1583
  return { fields };
1316
1584
  }
1317
1585
  function inferTypeFromValue(value) {
1318
- if (value instanceof Y3.Map) return "stringset";
1586
+ if (isStringSetYMap(value)) return "stringset";
1319
1587
  switch (typeof value) {
1320
1588
  case "string":
1321
1589
  return "string";
@@ -1330,7 +1598,7 @@ function inferTypeFromValue(value) {
1330
1598
  function readConstraints(constraintsMap) {
1331
1599
  const out = {};
1332
1600
  for (const [name, value] of constraintsMap.entries()) {
1333
- if (!(value instanceof Y3.Map)) continue;
1601
+ if (!(value instanceof Y6.Map)) continue;
1334
1602
  let fields = [];
1335
1603
  const rawFields = value.get("fields");
1336
1604
  if (typeof rawFields === "string") {
@@ -1349,7 +1617,7 @@ function readConstraints(constraintsMap) {
1349
1617
  function readRelationships(relsMap) {
1350
1618
  const out = {};
1351
1619
  for (const [name, value] of relsMap.entries()) {
1352
- if (!(value instanceof Y3.Map)) continue;
1620
+ if (!(value instanceof Y6.Map)) continue;
1353
1621
  const rel = {};
1354
1622
  for (const [k, v] of value.entries()) {
1355
1623
  rel[k] = v;
@@ -1360,6 +1628,7 @@ function readRelationships(relsMap) {
1360
1628
  }
1361
1629
  var CAMEL_TO_SNAKE = {
1362
1630
  autoAssign: "auto_assign",
1631
+ autoStamp: "auto_stamp",
1363
1632
  maxLength: "max_length",
1364
1633
  maxCount: "max_count",
1365
1634
  relatedIdField: "related_id_field",
@@ -1390,6 +1659,7 @@ function schemaToToml(schema) {
1390
1659
  lines.push(`[models.${modelName}.fields.${fieldName}]`);
1391
1660
  lines.push(`type = ${tomlValue(field.type)}`);
1392
1661
  if (field.autoAssign) lines.push("auto_assign = true");
1662
+ if (field.autoStamp) lines.push(`auto_stamp = ${tomlValue(field.autoStamp)}`);
1393
1663
  if (field.indexed) lines.push("indexed = true");
1394
1664
  if (field.unique) lines.push("unique = true");
1395
1665
  if (field.required) lines.push("required = true");
@@ -1426,6 +1696,7 @@ var import_smol_toml = require("smol-toml");
1426
1696
  // src/models/schema.ts
1427
1697
  init_BaseModel();
1428
1698
  init_ModelRegistry();
1699
+ init_uniqueIndex();
1429
1700
  function defineModelSchema(input) {
1430
1701
  const { name, fields } = input;
1431
1702
  const options = {
@@ -1468,7 +1739,7 @@ function resolveUniqueConstraints(modelName, fields, customConstraints) {
1468
1739
  for (const [fieldName, options] of fields.entries()) {
1469
1740
  if (options.unique) {
1470
1741
  resolved.push({
1471
- name: `${modelName}_${fieldName}_unique`,
1742
+ name: fieldUniqueConstraintName(modelName, fieldName),
1472
1743
  fields: [fieldName]
1473
1744
  });
1474
1745
  }
@@ -1513,10 +1784,13 @@ var KNOWN_FIELD_KEYS = /* @__PURE__ */ new Set([
1513
1784
  "unique",
1514
1785
  "required",
1515
1786
  "auto_assign",
1787
+ "auto_stamp",
1516
1788
  "max_length",
1517
1789
  "max_count",
1518
- "default"
1790
+ "default",
1791
+ "enum"
1519
1792
  ]);
1793
+ var VALID_AUTO_STAMP_VALUES = /* @__PURE__ */ new Set(["create", "update", "both"]);
1520
1794
  var KNOWN_MODEL_KEYS = /* @__PURE__ */ new Set([
1521
1795
  "fields",
1522
1796
  "relationships",
@@ -1558,9 +1832,37 @@ function parseFieldOptions(raw, context, strict) {
1558
1832
  if (raw.unique === true) opts.unique = true;
1559
1833
  if (raw.required === true) opts.required = true;
1560
1834
  if (raw.auto_assign === true) opts.autoAssign = true;
1835
+ if (raw.auto_stamp !== void 0) {
1836
+ if (typeof raw.auto_stamp !== "string" || !VALID_AUTO_STAMP_VALUES.has(raw.auto_stamp)) {
1837
+ throw new Error(
1838
+ `${context}: invalid auto_stamp value "${raw.auto_stamp}". Must be one of: ${[
1839
+ ...VALID_AUTO_STAMP_VALUES
1840
+ ].join(", ")}`
1841
+ );
1842
+ }
1843
+ opts.autoStamp = raw.auto_stamp;
1844
+ }
1561
1845
  if (raw.max_length !== void 0) opts.maxLength = raw.max_length;
1562
1846
  if (raw.max_count !== void 0) opts.maxCount = raw.max_count;
1563
1847
  if (raw.default !== void 0) opts.default = raw.default;
1848
+ if (raw.enum !== void 0) {
1849
+ if (raw.type !== "string") {
1850
+ throw new Error(
1851
+ `${context}: \`enum\` is only valid on a "string" field, not "${raw.type}".`
1852
+ );
1853
+ }
1854
+ if (!Array.isArray(raw.enum) || raw.enum.length === 0) {
1855
+ throw new Error(
1856
+ `${context}: \`enum\` must be a non-empty array of strings.`
1857
+ );
1858
+ }
1859
+ if (!raw.enum.every((v) => typeof v === "string")) {
1860
+ throw new Error(
1861
+ `${context}: \`enum\` values must all be strings.`
1862
+ );
1863
+ }
1864
+ opts.enum = [...raw.enum];
1865
+ }
1564
1866
  return opts;
1565
1867
  }
1566
1868
  function requireField(raw, field, context) {
@@ -1683,4 +1985,6 @@ function loadSchemaFromTomlString(tomlString, options = {}) {
1683
1985
  }
1684
1986
 
1685
1987
  // src/cloudflare.ts
1988
+ init_uniqueIndex();
1686
1989
  init_metaSync();
1990
+ init_writeLifecycle();