js-bao 0.3.0 → 0.4.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.
package/dist/browser.cjs CHANGED
@@ -1184,6 +1184,19 @@ var init_DocumentQueryTranslator = __esm({
1184
1184
  });
1185
1185
 
1186
1186
  // src/models/metaSync.ts
1187
+ function inferFieldType(value) {
1188
+ if (value instanceof Y.Map) return "stringset";
1189
+ switch (typeof value) {
1190
+ case "string":
1191
+ return "string";
1192
+ case "number":
1193
+ return "number";
1194
+ case "boolean":
1195
+ return "boolean";
1196
+ default:
1197
+ return null;
1198
+ }
1199
+ }
1187
1200
  function registerFunctionDefault(fn, name) {
1188
1201
  KNOWN_FUNCTION_DEFAULTS.set(fn, name);
1189
1202
  }
@@ -1195,6 +1208,11 @@ function encodeDefault(value) {
1195
1208
  }
1196
1209
  return value;
1197
1210
  }
1211
+ function clearMetaSyncCache(yDoc) {
1212
+ if (yDoc) {
1213
+ _syncedCache.delete(yDoc);
1214
+ }
1215
+ }
1198
1216
  function syncModelMeta(yDoc, modelName, schema) {
1199
1217
  let synced = _syncedCache.get(yDoc);
1200
1218
  if (synced?.has(modelName)) return;
@@ -1270,6 +1288,23 @@ function syncRelationshipMeta(relsMap, relName, relConfig) {
1270
1288
  }
1271
1289
  }
1272
1290
  }
1291
+ function syncInferredMeta(yDoc, modelName, recordData) {
1292
+ const meta = yDoc.getMap(`_meta_${modelName}`);
1293
+ for (const [fieldName, value] of Object.entries(recordData)) {
1294
+ if (fieldName.startsWith("_")) continue;
1295
+ let fieldMeta = meta.get(fieldName);
1296
+ if (!fieldMeta) {
1297
+ fieldMeta = new Y.Map();
1298
+ meta.set(fieldName, fieldMeta);
1299
+ }
1300
+ if (!fieldMeta.has("type")) {
1301
+ const inferredType = inferFieldType(value);
1302
+ if (inferredType) {
1303
+ fieldMeta.set("type", inferredType);
1304
+ }
1305
+ }
1306
+ }
1307
+ }
1273
1308
  function setIfChanged(map, key, value) {
1274
1309
  if (map.get(key) !== value) {
1275
1310
  map.set(key, value);
@@ -1599,11 +1634,11 @@ var init_ModelRegistry = __esm({
1599
1634
  init_relationshipManager();
1600
1635
  ModelRegistry = class _ModelRegistry {
1601
1636
  static instance;
1602
- // Stores globally registered model classes by their name (from @Model decorator)
1637
+ // Stores globally registered model classes by their name
1603
1638
  models = /* @__PURE__ */ new Map();
1604
- // Stores options for globally registered models (from @Model decorator)
1639
+ // Stores options for globally registered models
1605
1640
  modelOptions = /* @__PURE__ */ new Map();
1606
- // Stores fields for globally registered models (from @Model decorator, or a static getter on class)
1641
+ // Stores fields for globally registered models (or a static getter on class)
1607
1642
  // For simplicity, let's assume fields can be derived or are less critical for this registry part
1608
1643
  // private modelFields: Map<string, Map<string, FieldOptions>> = new Map();
1609
1644
  // Holds the subset of models explicitly set for the current initialization session
@@ -1621,7 +1656,7 @@ var init_ModelRegistry = __esm({
1621
1656
  registerModel(modelClass, options, fields) {
1622
1657
  if (!options.name) {
1623
1658
  throw new Error(
1624
- `[ModelRegistry] Model class is missing a name in its @Model options. Ensure the @Model decorator includes a 'name' property.`
1659
+ `[ModelRegistry] Model class is missing a name in its options. Ensure the schema passed to defineModelSchema/createModelClass/attachAndRegisterModel includes a 'name' property.`
1625
1660
  );
1626
1661
  }
1627
1662
  if (this.models.has(options.name)) {
@@ -1665,7 +1700,7 @@ var init_ModelRegistry = __esm({
1665
1700
  }
1666
1701
  return infos;
1667
1702
  }
1668
- // Helper to get model name from class (assuming static property from @Model decorator)
1703
+ // Helper to get model name from class (set by attachAndRegisterModel/createModelClass)
1669
1704
  getModelNameFromClass(modelClass) {
1670
1705
  return modelClass.modelName;
1671
1706
  }
@@ -1676,13 +1711,13 @@ var init_ModelRegistry = __esm({
1676
1711
  const modelName = this.getModelNameFromClass(modelClass);
1677
1712
  if (!modelName) {
1678
1713
  console.warn(
1679
- `[ModelRegistry] A model class provided to setExplicitModelsForSession does not have a static 'modelName' property or it's undefined. It will be ignored. Ensure @Model decorator sets this.`
1714
+ `[ModelRegistry] A model class provided to setExplicitModelsForSession does not have a static 'modelName' property or it's undefined. It will be ignored. Ensure attachAndRegisterModel (or createModelClass) was called for this model.`
1680
1715
  );
1681
1716
  return;
1682
1717
  }
1683
1718
  if (!this.models.has(modelName) || this.models.get(modelName) !== modelClass) {
1684
1719
  console.warn(
1685
- `[ModelRegistry] Model class with name ${modelName} provided to setExplicitModelsForSession was not found in the global decorator-based registry or does not match. It will be ignored. Ensure the model file is imported and the @Model decorator has run correctly.`
1720
+ `[ModelRegistry] Model class with name ${modelName} provided to setExplicitModelsForSession was not found in the global registry or does not match. It will be ignored. Ensure the model file is imported and attachAndRegisterModel (or createModelClass) has run.`
1686
1721
  );
1687
1722
  return;
1688
1723
  }
@@ -1712,7 +1747,7 @@ var init_ModelRegistry = __esm({
1712
1747
  } else {
1713
1748
  this.activeSessionModels = null;
1714
1749
  console.log(
1715
- "[ModelRegistry] No explicit models specified for session (undefined), will use all decorator-registered models."
1750
+ "[ModelRegistry] No explicit models specified for session (undefined), will use all globally registered models."
1716
1751
  );
1717
1752
  }
1718
1753
  this.validateSessionModels();
@@ -1723,7 +1758,7 @@ var init_ModelRegistry = __esm({
1723
1758
  const modelsToInitialize = this.activeSessionModels || this.models;
1724
1759
  if (modelsToInitialize.size === 0) {
1725
1760
  console.warn(
1726
- "[ModelRegistry] No models to initialize (either no explicit models set for session or no models globally registered via @Model decorator)."
1761
+ "[ModelRegistry] No models to initialize (either no explicit models set for session or no models globally registered via attachAndRegisterModel)."
1727
1762
  );
1728
1763
  return;
1729
1764
  }
@@ -1754,7 +1789,7 @@ var init_ModelRegistry = __esm({
1754
1789
  const modelsToInitialize = this.activeSessionModels || this.models;
1755
1790
  if (modelsToInitialize.size === 0) {
1756
1791
  Logger.warn(
1757
- "[ModelRegistry] No models to initialize for document (either no explicit models set for session or no models globally registered via @Model decorator)."
1792
+ "[ModelRegistry] No models to initialize for document (either no explicit models set for session or no models globally registered via attachAndRegisterModel)."
1758
1793
  );
1759
1794
  return;
1760
1795
  }
@@ -1792,7 +1827,7 @@ var init_ModelRegistry = __esm({
1792
1827
  const modelsToCleanup = this.activeSessionModels || this.models;
1793
1828
  if (modelsToCleanup.size === 0) {
1794
1829
  console.warn(
1795
- "[ModelRegistry] No models to cleanup for document (either no explicit models set for session or no models globally registered via @Model decorator)."
1830
+ "[ModelRegistry] No models to cleanup for document (either no explicit models set for session or no models globally registered via attachAndRegisterModel)."
1796
1831
  );
1797
1832
  return;
1798
1833
  }
@@ -2556,7 +2591,7 @@ var init_BaseModel = __esm({
2556
2591
  getDocumentId() {
2557
2592
  return this._metaDocId;
2558
2593
  }
2559
- // id is now a plain property. Subclasses will define it with @Field.
2594
+ // id is a plain property. Subclasses define it via defineModelSchema.
2560
2595
  id;
2561
2596
  type;
2562
2597
  // This should be the modelName from ModelOptions
@@ -3103,7 +3138,7 @@ var init_BaseModel = __esm({
3103
3138
  const verboseEnabled = Logger.getLogLevel() >= 5 /* VERBOSE */;
3104
3139
  if (!schema || !schema.options || !schema.options.name || !schema.resolvedUniqueConstraints) {
3105
3140
  throw new Error(
3106
- `[${this.name}] Model schema is not registered, missing options, or missing resolvedUniqueConstraints. Did you forget to use the @Model decorator or has the schema structure changed?`
3141
+ `[${this.name}] Model schema is not registered, missing options, or missing resolvedUniqueConstraints. Did you forget to call attachAndRegisterModel (or autoRegisterModel) for this model?`
3107
3142
  );
3108
3143
  }
3109
3144
  const modelName = schema.options.name;
@@ -5503,10 +5538,8 @@ __export(browser_exports, {
5503
5538
  BaseModel: () => BaseModel2,
5504
5539
  DatabaseEngine: () => DatabaseEngine,
5505
5540
  DatabaseFactory: () => BrowserDatabaseFactory,
5506
- Field: () => Field,
5507
5541
  LogLevel: () => LogLevel,
5508
5542
  Logger: () => Logger,
5509
- Model: () => Model,
5510
5543
  ModelRegistry: () => ModelRegistry,
5511
5544
  RecordNotFoundError: () => RecordNotFoundError,
5512
5545
  SqljsEngine: () => SqljsEngine,
@@ -5515,145 +5548,29 @@ __export(browser_exports, {
5515
5548
  attachAndRegisterModel: () => attachAndRegisterModel,
5516
5549
  attachSchemaToClass: () => attachSchemaToClass,
5517
5550
  autoRegisterModel: () => autoRegisterModel,
5551
+ clearMetaSyncCache: () => clearMetaSyncCache,
5518
5552
  createModelClass: () => createModelClass,
5519
5553
  defineModelSchema: () => defineModelSchema,
5520
5554
  detectEnvironment: () => detectEnvironment,
5555
+ discoverModelNames: () => discoverModelNames,
5556
+ discoverSchema: () => discoverSchema,
5521
5557
  features: () => features,
5522
5558
  generateULID: () => generateULID,
5559
+ inferFieldType: () => inferFieldType,
5523
5560
  initJsBao: () => initJsBao,
5524
5561
  isBrowser: () => isBrowser,
5525
5562
  isNode: () => isNode,
5526
- resetJsBao: () => resetJsBao
5563
+ loadSchemaFromTomlString: () => loadSchemaFromTomlString,
5564
+ registerFunctionDefault: () => registerFunctionDefault,
5565
+ resetJsBao: () => resetJsBao,
5566
+ schemaToToml: () => schemaToToml,
5567
+ syncInferredMeta: () => syncInferredMeta,
5568
+ syncModelMeta: () => syncModelMeta
5527
5569
  });
5528
5570
  module.exports = __toCommonJS(browser_exports);
5529
5571
  init_BaseModel();
5530
5572
  init_ModelRegistry();
5531
5573
 
5532
- // src/models/decorators.ts
5533
- init_ModelRegistry();
5534
- init_BaseModel();
5535
- init_sql();
5536
- var SCHEMA_FIELDS_PROPERTY = "_jsbaoSchemaFields";
5537
- function Field(options) {
5538
- return function(target, propertyKey) {
5539
- const fieldName = String(propertyKey);
5540
- const modelConstructor = target.constructor || target;
5541
- assertValidIdentifier(
5542
- fieldName,
5543
- `[Field Decorator] Invalid field name on ${modelConstructor?.name || "unknown"}`
5544
- );
5545
- if (!modelConstructor) {
5546
- console.error(
5547
- "[Field Decorator] Could not determine model constructor for field:",
5548
- fieldName,
5549
- "Target:",
5550
- target
5551
- );
5552
- throw new Error(
5553
- `Failed to resolve model constructor for field '${fieldName}'.`
5554
- );
5555
- }
5556
- if (!Object.prototype.hasOwnProperty.call(
5557
- modelConstructor,
5558
- SCHEMA_FIELDS_PROPERTY
5559
- )) {
5560
- modelConstructor[SCHEMA_FIELDS_PROPERTY] = /* @__PURE__ */ new Map();
5561
- }
5562
- modelConstructor[SCHEMA_FIELDS_PROPERTY].set(
5563
- fieldName,
5564
- options
5565
- );
5566
- Logger.debug(
5567
- `[Field Decorator] Staged field "${fieldName}" for class ${modelConstructor.name}:`,
5568
- options
5569
- );
5570
- };
5571
- }
5572
- function Model(options) {
5573
- return function(targetClass) {
5574
- Logger.debug(
5575
- `[Model Decorator] Registering model:`,
5576
- targetClass.name,
5577
- options
5578
- );
5579
- assertValidIdentifier(
5580
- options.name,
5581
- `[Model Decorator] Invalid model name for ${targetClass.name}`
5582
- );
5583
- const registry = ModelRegistry.getInstance();
5584
- targetClass.modelName = options.name;
5585
- targetClass.getSchema = () => {
5586
- const combinedFields = /* @__PURE__ */ new Map();
5587
- const hierarchyStack = [];
5588
- let currentEvalClass = targetClass;
5589
- while (currentEvalClass && currentEvalClass.prototype) {
5590
- hierarchyStack.push(currentEvalClass);
5591
- const parentPrototype = Object.getPrototypeOf(
5592
- currentEvalClass.prototype
5593
- );
5594
- currentEvalClass = parentPrototype ? parentPrototype.constructor : null;
5595
- if (currentEvalClass === Object) break;
5596
- }
5597
- for (let i = hierarchyStack.length - 1; i >= 0; i--) {
5598
- const cls = hierarchyStack[i];
5599
- if (Object.prototype.hasOwnProperty.call(cls, SCHEMA_FIELDS_PROPERTY)) {
5600
- const fieldsForClass = cls[SCHEMA_FIELDS_PROPERTY];
5601
- fieldsForClass.forEach((fieldOpts, fieldName) => {
5602
- combinedFields.set(fieldName, fieldOpts);
5603
- });
5604
- }
5605
- }
5606
- const resolvedUniqueConstraints = [];
5607
- combinedFields.forEach((fieldOpts, fieldName) => {
5608
- if (fieldOpts.unique) {
5609
- const constraintName = `${options.name}_${fieldName}_unique`;
5610
- resolvedUniqueConstraints.push({
5611
- name: constraintName,
5612
- fields: [fieldName]
5613
- });
5614
- }
5615
- });
5616
- if (options.uniqueConstraints) {
5617
- options.uniqueConstraints.forEach(
5618
- (constraintConfig) => {
5619
- const allFieldsExist = constraintConfig.fields.every(
5620
- (f) => combinedFields.has(f)
5621
- );
5622
- if (!allFieldsExist) {
5623
- console.warn(
5624
- `[Model Decorator] Unique constraint "${constraintConfig.name}" for model "${options.name}" specifies non-existent fields. Skipping.`
5625
- );
5626
- return;
5627
- }
5628
- if (resolvedUniqueConstraints.some(
5629
- (rc) => rc.name === constraintConfig.name
5630
- )) {
5631
- console.warn(
5632
- `[Model Decorator] Duplicate unique constraint name "${constraintConfig.name}" in model "${options.name}".`
5633
- );
5634
- }
5635
- resolvedUniqueConstraints.push({
5636
- name: constraintConfig.name,
5637
- fields: constraintConfig.fields
5638
- });
5639
- }
5640
- );
5641
- }
5642
- return {
5643
- class: targetClass,
5644
- options,
5645
- fields: combinedFields,
5646
- resolvedUniqueConstraints
5647
- };
5648
- };
5649
- const directFieldsForThisClass = Object.prototype.hasOwnProperty.call(
5650
- targetClass,
5651
- SCHEMA_FIELDS_PROPERTY
5652
- ) ? targetClass[SCHEMA_FIELDS_PROPERTY] : /* @__PURE__ */ new Map();
5653
- registry.registerModel(targetClass, options, directFieldsForThisClass);
5654
- };
5655
- }
5656
-
5657
5574
  // src/engines/DatabaseEngine.ts
5658
5575
  var DatabaseEngine = class {
5659
5576
  createTable(_modelName, _schema, _options) {
@@ -5693,7 +5610,7 @@ var DatabaseEngine = class {
5693
5610
  };
5694
5611
 
5695
5612
  // src/engines/SqljsEngine.ts
5696
- var import_sql5 = __toESM(require("sql.js"), 1);
5613
+ var import_sql4 = __toESM(require("sql.js"), 1);
5697
5614
  init_BaseModel();
5698
5615
  var import_async_mutex = require("async-mutex");
5699
5616
  init_sql();
@@ -5770,7 +5687,7 @@ var SqljsEngine = class _SqljsEngine {
5770
5687
  "[SqljsEngine] Attempting to load SQL.js WASM from:",
5771
5688
  locateFileConfig("sql-wasm.wasm")
5772
5689
  );
5773
- _SqljsEngine.SQL = await (0, import_sql5.default)({
5690
+ _SqljsEngine.SQL = await (0, import_sql4.default)({
5774
5691
  locateFile: locateFileConfig
5775
5692
  });
5776
5693
  Logger.info("[SqljsEngine] SQL.js WASM loaded successfully.");
@@ -6560,3 +6477,325 @@ function attachAndRegisterModel(modelClass, schema) {
6560
6477
  const runtimeShape = attachSchemaToClass(modelClass, schema);
6561
6478
  autoRegisterModel(modelClass, runtimeShape);
6562
6479
  }
6480
+
6481
+ // src/utils/yDocSchema.ts
6482
+ var Y3 = __toESM(require("yjs"), 1);
6483
+ function discoverSchema(yDoc) {
6484
+ const models = {};
6485
+ const metaNames = /* @__PURE__ */ new Set();
6486
+ for (const key of yDoc.share.keys()) {
6487
+ if (!key.startsWith("_meta_")) continue;
6488
+ const map = materializeMap(yDoc, key);
6489
+ if (!map) continue;
6490
+ const modelName = key.slice("_meta_".length);
6491
+ metaNames.add(modelName);
6492
+ models[modelName] = readModelMeta(map);
6493
+ }
6494
+ for (const key of yDoc.share.keys()) {
6495
+ if (key.startsWith("_")) continue;
6496
+ if (metaNames.has(key)) continue;
6497
+ const map = materializeMap(yDoc, key);
6498
+ if (!map || map.size === 0) continue;
6499
+ const inferred = inferModelFromData(map);
6500
+ if (inferred) models[key] = inferred;
6501
+ }
6502
+ return { models };
6503
+ }
6504
+ function discoverModelNames(yDoc) {
6505
+ const names = [];
6506
+ for (const key of yDoc.share.keys()) {
6507
+ if (key.startsWith("_")) continue;
6508
+ const map = materializeMap(yDoc, key);
6509
+ if (map) names.push(key);
6510
+ }
6511
+ return names.sort();
6512
+ }
6513
+ function materializeMap(yDoc, key) {
6514
+ try {
6515
+ const map = yDoc.getMap(key);
6516
+ return map instanceof Y3.Map ? map : null;
6517
+ } catch {
6518
+ return null;
6519
+ }
6520
+ }
6521
+ function readModelMeta(metaMap) {
6522
+ const fields = {};
6523
+ let constraints;
6524
+ let relationships;
6525
+ for (const [key, value] of metaMap.entries()) {
6526
+ if (key === "_constraints" && value instanceof Y3.Map) {
6527
+ constraints = readConstraints(value);
6528
+ } else if (key === "_relationships" && value instanceof Y3.Map) {
6529
+ relationships = readRelationships(value);
6530
+ } else if (value instanceof Y3.Map) {
6531
+ fields[key] = readFieldMeta(value);
6532
+ }
6533
+ }
6534
+ const model = { fields };
6535
+ if (constraints && Object.keys(constraints).length > 0) {
6536
+ model.constraints = constraints;
6537
+ }
6538
+ if (relationships && Object.keys(relationships).length > 0) {
6539
+ model.relationships = relationships;
6540
+ }
6541
+ return model;
6542
+ }
6543
+ function readFieldMeta(fieldMap) {
6544
+ const field = { type: fieldMap.get("type") ?? "unknown" };
6545
+ if (fieldMap.get("indexed") === true) field.indexed = true;
6546
+ if (fieldMap.get("unique") === true) field.unique = true;
6547
+ if (fieldMap.get("required") === true) field.required = true;
6548
+ if (fieldMap.get("autoAssign") === true) field.autoAssign = true;
6549
+ const def = fieldMap.get("default");
6550
+ if (def !== void 0) field.default = def;
6551
+ const maxLength = fieldMap.get("maxLength");
6552
+ if (maxLength !== void 0) field.maxLength = maxLength;
6553
+ const maxCount = fieldMap.get("maxCount");
6554
+ if (maxCount !== void 0) field.maxCount = maxCount;
6555
+ return field;
6556
+ }
6557
+ function inferModelFromData(dataMap) {
6558
+ const fields = {};
6559
+ let sampled = 0;
6560
+ for (const [_recordId, recordValue] of dataMap.entries()) {
6561
+ if (!(recordValue instanceof Y3.Map)) continue;
6562
+ if (++sampled > 5) break;
6563
+ for (const [fieldName, value] of recordValue.entries()) {
6564
+ if (fieldName.startsWith("_")) continue;
6565
+ if (fields[fieldName]) continue;
6566
+ const type = inferTypeFromValue(value);
6567
+ if (type) fields[fieldName] = { type };
6568
+ }
6569
+ }
6570
+ if (Object.keys(fields).length === 0) return null;
6571
+ return { fields };
6572
+ }
6573
+ function inferTypeFromValue(value) {
6574
+ if (value instanceof Y3.Map) return "stringset";
6575
+ switch (typeof value) {
6576
+ case "string":
6577
+ return "string";
6578
+ case "number":
6579
+ return "number";
6580
+ case "boolean":
6581
+ return "boolean";
6582
+ default:
6583
+ return null;
6584
+ }
6585
+ }
6586
+ function readConstraints(constraintsMap) {
6587
+ const out = {};
6588
+ for (const [name, value] of constraintsMap.entries()) {
6589
+ if (!(value instanceof Y3.Map)) continue;
6590
+ let fields = [];
6591
+ const rawFields = value.get("fields");
6592
+ if (typeof rawFields === "string") {
6593
+ try {
6594
+ fields = JSON.parse(rawFields);
6595
+ } catch {
6596
+ }
6597
+ }
6598
+ out[name] = {
6599
+ type: value.get("type") ?? "unknown",
6600
+ fields
6601
+ };
6602
+ }
6603
+ return out;
6604
+ }
6605
+ function readRelationships(relsMap) {
6606
+ const out = {};
6607
+ for (const [name, value] of relsMap.entries()) {
6608
+ if (!(value instanceof Y3.Map)) continue;
6609
+ const rel = {};
6610
+ for (const [k, v] of value.entries()) {
6611
+ rel[k] = v;
6612
+ }
6613
+ out[name] = rel;
6614
+ }
6615
+ return out;
6616
+ }
6617
+ var CAMEL_TO_SNAKE = {
6618
+ autoAssign: "auto_assign",
6619
+ maxLength: "max_length",
6620
+ maxCount: "max_count",
6621
+ relatedIdField: "related_id_field",
6622
+ joinModel: "join_model",
6623
+ joinModelLocalField: "join_model_local_field",
6624
+ joinModelRelatedField: "join_model_related_field",
6625
+ joinModelOrderByField: "join_model_order_by_field",
6626
+ joinModelOrderDirection: "join_model_order_direction",
6627
+ orderByField: "order_by_field",
6628
+ orderDirection: "order_direction"
6629
+ };
6630
+ function toSnake(key) {
6631
+ return CAMEL_TO_SNAKE[key] ?? key;
6632
+ }
6633
+ function tomlValue(v) {
6634
+ if (typeof v === "string") {
6635
+ return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
6636
+ }
6637
+ return String(v);
6638
+ }
6639
+ function schemaToToml(schema) {
6640
+ const lines = [];
6641
+ for (const [modelName, model] of Object.entries(schema.models)) {
6642
+ if (lines.length > 0) lines.push("", "");
6643
+ lines.push(`[models.${modelName}]`);
6644
+ for (const [fieldName, field] of Object.entries(model.fields)) {
6645
+ lines.push("");
6646
+ lines.push(`[models.${modelName}.fields.${fieldName}]`);
6647
+ lines.push(`type = ${tomlValue(field.type)}`);
6648
+ if (field.autoAssign) lines.push("auto_assign = true");
6649
+ if (field.indexed) lines.push("indexed = true");
6650
+ if (field.unique) lines.push("unique = true");
6651
+ if (field.required) lines.push("required = true");
6652
+ if (field.maxLength !== void 0) lines.push(`max_length = ${field.maxLength}`);
6653
+ if (field.maxCount !== void 0) lines.push(`max_count = ${field.maxCount}`);
6654
+ if (field.default !== void 0) lines.push(`default = ${tomlValue(field.default)}`);
6655
+ }
6656
+ if (model.relationships) {
6657
+ for (const [relName, rel] of Object.entries(model.relationships)) {
6658
+ lines.push("");
6659
+ lines.push(`[models.${modelName}.relationships.${relName}]`);
6660
+ for (const [k, v] of Object.entries(rel)) {
6661
+ if (v === void 0) continue;
6662
+ lines.push(`${toSnake(k)} = ${tomlValue(v)}`);
6663
+ }
6664
+ }
6665
+ }
6666
+ if (model.constraints) {
6667
+ for (const [cName, c] of Object.entries(model.constraints)) {
6668
+ lines.push("");
6669
+ lines.push(`[[models.${modelName}.unique_constraints]]`);
6670
+ lines.push(`name = ${tomlValue(cName)}`);
6671
+ lines.push(`fields = [${c.fields.map((f) => tomlValue(f)).join(", ")}]`);
6672
+ }
6673
+ }
6674
+ }
6675
+ lines.push("");
6676
+ return lines.join("\n");
6677
+ }
6678
+
6679
+ // src/models/tomlLoader.ts
6680
+ var import_smol_toml = require("smol-toml");
6681
+ var VALID_FIELD_TYPES = /* @__PURE__ */ new Set([
6682
+ "string",
6683
+ "number",
6684
+ "boolean",
6685
+ "date",
6686
+ "id",
6687
+ "stringset"
6688
+ ]);
6689
+ function parseFieldOptions(raw) {
6690
+ if (!raw.type || !VALID_FIELD_TYPES.has(raw.type)) {
6691
+ throw new Error(
6692
+ `Invalid field type "${raw.type}". Must be one of: ${[...VALID_FIELD_TYPES].join(", ")}`
6693
+ );
6694
+ }
6695
+ const opts = { type: raw.type };
6696
+ if (raw.indexed === true) opts.indexed = true;
6697
+ if (raw.unique === true) opts.unique = true;
6698
+ if (raw.required === true) opts.required = true;
6699
+ if (raw.auto_assign === true) opts.autoAssign = true;
6700
+ if (raw.max_length !== void 0) opts.maxLength = raw.max_length;
6701
+ if (raw.max_count !== void 0) opts.maxCount = raw.max_count;
6702
+ if (raw.default !== void 0) opts.default = raw.default;
6703
+ return opts;
6704
+ }
6705
+ function requireField(raw, field, context) {
6706
+ if (!raw[field]) {
6707
+ throw new Error(`Relationship ${context}: missing required field "${field}"`);
6708
+ }
6709
+ }
6710
+ function parseRelationship(raw) {
6711
+ const type = raw.type;
6712
+ if (type === "refersTo") {
6713
+ requireField(raw, "model", "refersTo");
6714
+ requireField(raw, "related_id_field", "refersTo");
6715
+ return {
6716
+ type: "refersTo",
6717
+ model: raw.model,
6718
+ relatedIdField: raw.related_id_field
6719
+ };
6720
+ }
6721
+ if (type === "hasMany") {
6722
+ requireField(raw, "model", "hasMany");
6723
+ requireField(raw, "related_id_field", "hasMany");
6724
+ const rel = {
6725
+ type: "hasMany",
6726
+ model: raw.model,
6727
+ relatedIdField: raw.related_id_field
6728
+ };
6729
+ if (raw.order_by_field) rel.orderByField = raw.order_by_field;
6730
+ if (raw.order_direction) rel.orderDirection = raw.order_direction;
6731
+ return rel;
6732
+ }
6733
+ if (type === "hasManyThrough") {
6734
+ requireField(raw, "model", "hasManyThrough");
6735
+ requireField(raw, "join_model", "hasManyThrough");
6736
+ requireField(raw, "join_model_local_field", "hasManyThrough");
6737
+ requireField(raw, "join_model_related_field", "hasManyThrough");
6738
+ const rel = {
6739
+ type: "hasManyThrough",
6740
+ model: raw.model,
6741
+ joinModel: raw.join_model,
6742
+ joinModelLocalField: raw.join_model_local_field,
6743
+ joinModelRelatedField: raw.join_model_related_field
6744
+ };
6745
+ if (raw.join_model_order_by_field)
6746
+ rel.joinModelOrderByField = raw.join_model_order_by_field;
6747
+ if (raw.join_model_order_direction)
6748
+ rel.joinModelOrderDirection = raw.join_model_order_direction;
6749
+ return rel;
6750
+ }
6751
+ throw new Error(`Unknown relationship type: ${type}`);
6752
+ }
6753
+ function loadSchemaFromTomlString(tomlString) {
6754
+ const parsed = (0, import_smol_toml.parse)(tomlString);
6755
+ const models = parsed.models;
6756
+ if (!models || typeof models !== "object") {
6757
+ throw new Error("TOML schema must have a [models] section");
6758
+ }
6759
+ const schemas = [];
6760
+ for (const [modelName, modelDef] of Object.entries(models)) {
6761
+ const fields = {};
6762
+ if (modelDef.fields) {
6763
+ for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
6764
+ fields[fieldName] = parseFieldOptions(fieldDef);
6765
+ }
6766
+ }
6767
+ let relationships;
6768
+ if (modelDef.relationships) {
6769
+ relationships = {};
6770
+ for (const [relName, relDef] of Object.entries(
6771
+ modelDef.relationships
6772
+ )) {
6773
+ relationships[relName] = parseRelationship(relDef);
6774
+ }
6775
+ }
6776
+ let uniqueConstraints;
6777
+ if (modelDef.unique_constraints) {
6778
+ uniqueConstraints = [];
6779
+ for (const raw of modelDef.unique_constraints) {
6780
+ uniqueConstraints.push({
6781
+ name: raw.name,
6782
+ fields: [...raw.fields]
6783
+ });
6784
+ }
6785
+ }
6786
+ schemas.push(
6787
+ defineModelSchema({
6788
+ name: modelName,
6789
+ fields,
6790
+ options: {
6791
+ uniqueConstraints,
6792
+ relationships
6793
+ }
6794
+ })
6795
+ );
6796
+ }
6797
+ return schemas;
6798
+ }
6799
+
6800
+ // src/browser.ts
6801
+ init_metaSync();