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.js CHANGED
@@ -1163,6 +1163,19 @@ var init_DocumentQueryTranslator = __esm({
1163
1163
 
1164
1164
  // src/models/metaSync.ts
1165
1165
  import * as Y from "yjs";
1166
+ function inferFieldType(value) {
1167
+ if (value instanceof Y.Map) return "stringset";
1168
+ switch (typeof value) {
1169
+ case "string":
1170
+ return "string";
1171
+ case "number":
1172
+ return "number";
1173
+ case "boolean":
1174
+ return "boolean";
1175
+ default:
1176
+ return null;
1177
+ }
1178
+ }
1166
1179
  function registerFunctionDefault(fn, name) {
1167
1180
  KNOWN_FUNCTION_DEFAULTS.set(fn, name);
1168
1181
  }
@@ -1174,6 +1187,11 @@ function encodeDefault(value) {
1174
1187
  }
1175
1188
  return value;
1176
1189
  }
1190
+ function clearMetaSyncCache(yDoc) {
1191
+ if (yDoc) {
1192
+ _syncedCache.delete(yDoc);
1193
+ }
1194
+ }
1177
1195
  function syncModelMeta(yDoc, modelName, schema) {
1178
1196
  let synced = _syncedCache.get(yDoc);
1179
1197
  if (synced?.has(modelName)) return;
@@ -1249,6 +1267,23 @@ function syncRelationshipMeta(relsMap, relName, relConfig) {
1249
1267
  }
1250
1268
  }
1251
1269
  }
1270
+ function syncInferredMeta(yDoc, modelName, recordData) {
1271
+ const meta = yDoc.getMap(`_meta_${modelName}`);
1272
+ for (const [fieldName, value] of Object.entries(recordData)) {
1273
+ if (fieldName.startsWith("_")) continue;
1274
+ let fieldMeta = meta.get(fieldName);
1275
+ if (!fieldMeta) {
1276
+ fieldMeta = new Y.Map();
1277
+ meta.set(fieldName, fieldMeta);
1278
+ }
1279
+ if (!fieldMeta.has("type")) {
1280
+ const inferredType = inferFieldType(value);
1281
+ if (inferredType) {
1282
+ fieldMeta.set("type", inferredType);
1283
+ }
1284
+ }
1285
+ }
1286
+ }
1252
1287
  function setIfChanged(map, key, value) {
1253
1288
  if (map.get(key) !== value) {
1254
1289
  map.set(key, value);
@@ -1577,11 +1612,11 @@ var init_ModelRegistry = __esm({
1577
1612
  init_relationshipManager();
1578
1613
  ModelRegistry = class _ModelRegistry {
1579
1614
  static instance;
1580
- // Stores globally registered model classes by their name (from @Model decorator)
1615
+ // Stores globally registered model classes by their name
1581
1616
  models = /* @__PURE__ */ new Map();
1582
- // Stores options for globally registered models (from @Model decorator)
1617
+ // Stores options for globally registered models
1583
1618
  modelOptions = /* @__PURE__ */ new Map();
1584
- // Stores fields for globally registered models (from @Model decorator, or a static getter on class)
1619
+ // Stores fields for globally registered models (or a static getter on class)
1585
1620
  // For simplicity, let's assume fields can be derived or are less critical for this registry part
1586
1621
  // private modelFields: Map<string, Map<string, FieldOptions>> = new Map();
1587
1622
  // Holds the subset of models explicitly set for the current initialization session
@@ -1599,7 +1634,7 @@ var init_ModelRegistry = __esm({
1599
1634
  registerModel(modelClass, options, fields) {
1600
1635
  if (!options.name) {
1601
1636
  throw new Error(
1602
- `[ModelRegistry] Model class is missing a name in its @Model options. Ensure the @Model decorator includes a 'name' property.`
1637
+ `[ModelRegistry] Model class is missing a name in its options. Ensure the schema passed to defineModelSchema/createModelClass/attachAndRegisterModel includes a 'name' property.`
1603
1638
  );
1604
1639
  }
1605
1640
  if (this.models.has(options.name)) {
@@ -1643,7 +1678,7 @@ var init_ModelRegistry = __esm({
1643
1678
  }
1644
1679
  return infos;
1645
1680
  }
1646
- // Helper to get model name from class (assuming static property from @Model decorator)
1681
+ // Helper to get model name from class (set by attachAndRegisterModel/createModelClass)
1647
1682
  getModelNameFromClass(modelClass) {
1648
1683
  return modelClass.modelName;
1649
1684
  }
@@ -1654,13 +1689,13 @@ var init_ModelRegistry = __esm({
1654
1689
  const modelName = this.getModelNameFromClass(modelClass);
1655
1690
  if (!modelName) {
1656
1691
  console.warn(
1657
- `[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.`
1692
+ `[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.`
1658
1693
  );
1659
1694
  return;
1660
1695
  }
1661
1696
  if (!this.models.has(modelName) || this.models.get(modelName) !== modelClass) {
1662
1697
  console.warn(
1663
- `[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.`
1698
+ `[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.`
1664
1699
  );
1665
1700
  return;
1666
1701
  }
@@ -1690,7 +1725,7 @@ var init_ModelRegistry = __esm({
1690
1725
  } else {
1691
1726
  this.activeSessionModels = null;
1692
1727
  console.log(
1693
- "[ModelRegistry] No explicit models specified for session (undefined), will use all decorator-registered models."
1728
+ "[ModelRegistry] No explicit models specified for session (undefined), will use all globally registered models."
1694
1729
  );
1695
1730
  }
1696
1731
  this.validateSessionModels();
@@ -1701,7 +1736,7 @@ var init_ModelRegistry = __esm({
1701
1736
  const modelsToInitialize = this.activeSessionModels || this.models;
1702
1737
  if (modelsToInitialize.size === 0) {
1703
1738
  console.warn(
1704
- "[ModelRegistry] No models to initialize (either no explicit models set for session or no models globally registered via @Model decorator)."
1739
+ "[ModelRegistry] No models to initialize (either no explicit models set for session or no models globally registered via attachAndRegisterModel)."
1705
1740
  );
1706
1741
  return;
1707
1742
  }
@@ -1732,7 +1767,7 @@ var init_ModelRegistry = __esm({
1732
1767
  const modelsToInitialize = this.activeSessionModels || this.models;
1733
1768
  if (modelsToInitialize.size === 0) {
1734
1769
  Logger.warn(
1735
- "[ModelRegistry] No models to initialize for document (either no explicit models set for session or no models globally registered via @Model decorator)."
1770
+ "[ModelRegistry] No models to initialize for document (either no explicit models set for session or no models globally registered via attachAndRegisterModel)."
1736
1771
  );
1737
1772
  return;
1738
1773
  }
@@ -1770,7 +1805,7 @@ var init_ModelRegistry = __esm({
1770
1805
  const modelsToCleanup = this.activeSessionModels || this.models;
1771
1806
  if (modelsToCleanup.size === 0) {
1772
1807
  console.warn(
1773
- "[ModelRegistry] No models to cleanup for document (either no explicit models set for session or no models globally registered via @Model decorator)."
1808
+ "[ModelRegistry] No models to cleanup for document (either no explicit models set for session or no models globally registered via attachAndRegisterModel)."
1774
1809
  );
1775
1810
  return;
1776
1811
  }
@@ -2534,7 +2569,7 @@ var init_BaseModel = __esm({
2534
2569
  getDocumentId() {
2535
2570
  return this._metaDocId;
2536
2571
  }
2537
- // id is now a plain property. Subclasses will define it with @Field.
2572
+ // id is a plain property. Subclasses define it via defineModelSchema.
2538
2573
  id;
2539
2574
  type;
2540
2575
  // This should be the modelName from ModelOptions
@@ -3081,7 +3116,7 @@ var init_BaseModel = __esm({
3081
3116
  const verboseEnabled = Logger.getLogLevel() >= 5 /* VERBOSE */;
3082
3117
  if (!schema || !schema.options || !schema.options.name || !schema.resolvedUniqueConstraints) {
3083
3118
  throw new Error(
3084
- `[${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?`
3119
+ `[${this.name}] Model schema is not registered, missing options, or missing resolvedUniqueConstraints. Did you forget to call attachAndRegisterModel (or autoRegisterModel) for this model?`
3085
3120
  );
3086
3121
  }
3087
3122
  const modelName = schema.options.name;
@@ -5479,131 +5514,6 @@ var init_BaseModel = __esm({
5479
5514
  init_BaseModel();
5480
5515
  init_ModelRegistry();
5481
5516
 
5482
- // src/models/decorators.ts
5483
- init_ModelRegistry();
5484
- init_BaseModel();
5485
- init_sql();
5486
- var SCHEMA_FIELDS_PROPERTY = "_jsbaoSchemaFields";
5487
- function Field(options) {
5488
- return function(target, propertyKey) {
5489
- const fieldName = String(propertyKey);
5490
- const modelConstructor = target.constructor || target;
5491
- assertValidIdentifier(
5492
- fieldName,
5493
- `[Field Decorator] Invalid field name on ${modelConstructor?.name || "unknown"}`
5494
- );
5495
- if (!modelConstructor) {
5496
- console.error(
5497
- "[Field Decorator] Could not determine model constructor for field:",
5498
- fieldName,
5499
- "Target:",
5500
- target
5501
- );
5502
- throw new Error(
5503
- `Failed to resolve model constructor for field '${fieldName}'.`
5504
- );
5505
- }
5506
- if (!Object.prototype.hasOwnProperty.call(
5507
- modelConstructor,
5508
- SCHEMA_FIELDS_PROPERTY
5509
- )) {
5510
- modelConstructor[SCHEMA_FIELDS_PROPERTY] = /* @__PURE__ */ new Map();
5511
- }
5512
- modelConstructor[SCHEMA_FIELDS_PROPERTY].set(
5513
- fieldName,
5514
- options
5515
- );
5516
- Logger.debug(
5517
- `[Field Decorator] Staged field "${fieldName}" for class ${modelConstructor.name}:`,
5518
- options
5519
- );
5520
- };
5521
- }
5522
- function Model(options) {
5523
- return function(targetClass) {
5524
- Logger.debug(
5525
- `[Model Decorator] Registering model:`,
5526
- targetClass.name,
5527
- options
5528
- );
5529
- assertValidIdentifier(
5530
- options.name,
5531
- `[Model Decorator] Invalid model name for ${targetClass.name}`
5532
- );
5533
- const registry = ModelRegistry.getInstance();
5534
- targetClass.modelName = options.name;
5535
- targetClass.getSchema = () => {
5536
- const combinedFields = /* @__PURE__ */ new Map();
5537
- const hierarchyStack = [];
5538
- let currentEvalClass = targetClass;
5539
- while (currentEvalClass && currentEvalClass.prototype) {
5540
- hierarchyStack.push(currentEvalClass);
5541
- const parentPrototype = Object.getPrototypeOf(
5542
- currentEvalClass.prototype
5543
- );
5544
- currentEvalClass = parentPrototype ? parentPrototype.constructor : null;
5545
- if (currentEvalClass === Object) break;
5546
- }
5547
- for (let i = hierarchyStack.length - 1; i >= 0; i--) {
5548
- const cls = hierarchyStack[i];
5549
- if (Object.prototype.hasOwnProperty.call(cls, SCHEMA_FIELDS_PROPERTY)) {
5550
- const fieldsForClass = cls[SCHEMA_FIELDS_PROPERTY];
5551
- fieldsForClass.forEach((fieldOpts, fieldName) => {
5552
- combinedFields.set(fieldName, fieldOpts);
5553
- });
5554
- }
5555
- }
5556
- const resolvedUniqueConstraints = [];
5557
- combinedFields.forEach((fieldOpts, fieldName) => {
5558
- if (fieldOpts.unique) {
5559
- const constraintName = `${options.name}_${fieldName}_unique`;
5560
- resolvedUniqueConstraints.push({
5561
- name: constraintName,
5562
- fields: [fieldName]
5563
- });
5564
- }
5565
- });
5566
- if (options.uniqueConstraints) {
5567
- options.uniqueConstraints.forEach(
5568
- (constraintConfig) => {
5569
- const allFieldsExist = constraintConfig.fields.every(
5570
- (f) => combinedFields.has(f)
5571
- );
5572
- if (!allFieldsExist) {
5573
- console.warn(
5574
- `[Model Decorator] Unique constraint "${constraintConfig.name}" for model "${options.name}" specifies non-existent fields. Skipping.`
5575
- );
5576
- return;
5577
- }
5578
- if (resolvedUniqueConstraints.some(
5579
- (rc) => rc.name === constraintConfig.name
5580
- )) {
5581
- console.warn(
5582
- `[Model Decorator] Duplicate unique constraint name "${constraintConfig.name}" in model "${options.name}".`
5583
- );
5584
- }
5585
- resolvedUniqueConstraints.push({
5586
- name: constraintConfig.name,
5587
- fields: constraintConfig.fields
5588
- });
5589
- }
5590
- );
5591
- }
5592
- return {
5593
- class: targetClass,
5594
- options,
5595
- fields: combinedFields,
5596
- resolvedUniqueConstraints
5597
- };
5598
- };
5599
- const directFieldsForThisClass = Object.prototype.hasOwnProperty.call(
5600
- targetClass,
5601
- SCHEMA_FIELDS_PROPERTY
5602
- ) ? targetClass[SCHEMA_FIELDS_PROPERTY] : /* @__PURE__ */ new Map();
5603
- registry.registerModel(targetClass, options, directFieldsForThisClass);
5604
- };
5605
- }
5606
-
5607
5517
  // src/engines/DatabaseEngine.ts
5608
5518
  var DatabaseEngine = class {
5609
5519
  createTable(_modelName, _schema, _options) {
@@ -6510,14 +6420,334 @@ function attachAndRegisterModel(modelClass, schema) {
6510
6420
  const runtimeShape = attachSchemaToClass(modelClass, schema);
6511
6421
  autoRegisterModel(modelClass, runtimeShape);
6512
6422
  }
6423
+
6424
+ // src/utils/yDocSchema.ts
6425
+ import * as Y3 from "yjs";
6426
+ function discoverSchema(yDoc) {
6427
+ const models = {};
6428
+ const metaNames = /* @__PURE__ */ new Set();
6429
+ for (const key of yDoc.share.keys()) {
6430
+ if (!key.startsWith("_meta_")) continue;
6431
+ const map = materializeMap(yDoc, key);
6432
+ if (!map) continue;
6433
+ const modelName = key.slice("_meta_".length);
6434
+ metaNames.add(modelName);
6435
+ models[modelName] = readModelMeta(map);
6436
+ }
6437
+ for (const key of yDoc.share.keys()) {
6438
+ if (key.startsWith("_")) continue;
6439
+ if (metaNames.has(key)) continue;
6440
+ const map = materializeMap(yDoc, key);
6441
+ if (!map || map.size === 0) continue;
6442
+ const inferred = inferModelFromData(map);
6443
+ if (inferred) models[key] = inferred;
6444
+ }
6445
+ return { models };
6446
+ }
6447
+ function discoverModelNames(yDoc) {
6448
+ const names = [];
6449
+ for (const key of yDoc.share.keys()) {
6450
+ if (key.startsWith("_")) continue;
6451
+ const map = materializeMap(yDoc, key);
6452
+ if (map) names.push(key);
6453
+ }
6454
+ return names.sort();
6455
+ }
6456
+ function materializeMap(yDoc, key) {
6457
+ try {
6458
+ const map = yDoc.getMap(key);
6459
+ return map instanceof Y3.Map ? map : null;
6460
+ } catch {
6461
+ return null;
6462
+ }
6463
+ }
6464
+ function readModelMeta(metaMap) {
6465
+ const fields = {};
6466
+ let constraints;
6467
+ let relationships;
6468
+ for (const [key, value] of metaMap.entries()) {
6469
+ if (key === "_constraints" && value instanceof Y3.Map) {
6470
+ constraints = readConstraints(value);
6471
+ } else if (key === "_relationships" && value instanceof Y3.Map) {
6472
+ relationships = readRelationships(value);
6473
+ } else if (value instanceof Y3.Map) {
6474
+ fields[key] = readFieldMeta(value);
6475
+ }
6476
+ }
6477
+ const model = { fields };
6478
+ if (constraints && Object.keys(constraints).length > 0) {
6479
+ model.constraints = constraints;
6480
+ }
6481
+ if (relationships && Object.keys(relationships).length > 0) {
6482
+ model.relationships = relationships;
6483
+ }
6484
+ return model;
6485
+ }
6486
+ function readFieldMeta(fieldMap) {
6487
+ const field = { type: fieldMap.get("type") ?? "unknown" };
6488
+ if (fieldMap.get("indexed") === true) field.indexed = true;
6489
+ if (fieldMap.get("unique") === true) field.unique = true;
6490
+ if (fieldMap.get("required") === true) field.required = true;
6491
+ if (fieldMap.get("autoAssign") === true) field.autoAssign = true;
6492
+ const def = fieldMap.get("default");
6493
+ if (def !== void 0) field.default = def;
6494
+ const maxLength = fieldMap.get("maxLength");
6495
+ if (maxLength !== void 0) field.maxLength = maxLength;
6496
+ const maxCount = fieldMap.get("maxCount");
6497
+ if (maxCount !== void 0) field.maxCount = maxCount;
6498
+ return field;
6499
+ }
6500
+ function inferModelFromData(dataMap) {
6501
+ const fields = {};
6502
+ let sampled = 0;
6503
+ for (const [_recordId, recordValue] of dataMap.entries()) {
6504
+ if (!(recordValue instanceof Y3.Map)) continue;
6505
+ if (++sampled > 5) break;
6506
+ for (const [fieldName, value] of recordValue.entries()) {
6507
+ if (fieldName.startsWith("_")) continue;
6508
+ if (fields[fieldName]) continue;
6509
+ const type = inferTypeFromValue(value);
6510
+ if (type) fields[fieldName] = { type };
6511
+ }
6512
+ }
6513
+ if (Object.keys(fields).length === 0) return null;
6514
+ return { fields };
6515
+ }
6516
+ function inferTypeFromValue(value) {
6517
+ if (value instanceof Y3.Map) return "stringset";
6518
+ switch (typeof value) {
6519
+ case "string":
6520
+ return "string";
6521
+ case "number":
6522
+ return "number";
6523
+ case "boolean":
6524
+ return "boolean";
6525
+ default:
6526
+ return null;
6527
+ }
6528
+ }
6529
+ function readConstraints(constraintsMap) {
6530
+ const out = {};
6531
+ for (const [name, value] of constraintsMap.entries()) {
6532
+ if (!(value instanceof Y3.Map)) continue;
6533
+ let fields = [];
6534
+ const rawFields = value.get("fields");
6535
+ if (typeof rawFields === "string") {
6536
+ try {
6537
+ fields = JSON.parse(rawFields);
6538
+ } catch {
6539
+ }
6540
+ }
6541
+ out[name] = {
6542
+ type: value.get("type") ?? "unknown",
6543
+ fields
6544
+ };
6545
+ }
6546
+ return out;
6547
+ }
6548
+ function readRelationships(relsMap) {
6549
+ const out = {};
6550
+ for (const [name, value] of relsMap.entries()) {
6551
+ if (!(value instanceof Y3.Map)) continue;
6552
+ const rel = {};
6553
+ for (const [k, v] of value.entries()) {
6554
+ rel[k] = v;
6555
+ }
6556
+ out[name] = rel;
6557
+ }
6558
+ return out;
6559
+ }
6560
+ var CAMEL_TO_SNAKE = {
6561
+ autoAssign: "auto_assign",
6562
+ maxLength: "max_length",
6563
+ maxCount: "max_count",
6564
+ relatedIdField: "related_id_field",
6565
+ joinModel: "join_model",
6566
+ joinModelLocalField: "join_model_local_field",
6567
+ joinModelRelatedField: "join_model_related_field",
6568
+ joinModelOrderByField: "join_model_order_by_field",
6569
+ joinModelOrderDirection: "join_model_order_direction",
6570
+ orderByField: "order_by_field",
6571
+ orderDirection: "order_direction"
6572
+ };
6573
+ function toSnake(key) {
6574
+ return CAMEL_TO_SNAKE[key] ?? key;
6575
+ }
6576
+ function tomlValue(v) {
6577
+ if (typeof v === "string") {
6578
+ return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
6579
+ }
6580
+ return String(v);
6581
+ }
6582
+ function schemaToToml(schema) {
6583
+ const lines = [];
6584
+ for (const [modelName, model] of Object.entries(schema.models)) {
6585
+ if (lines.length > 0) lines.push("", "");
6586
+ lines.push(`[models.${modelName}]`);
6587
+ for (const [fieldName, field] of Object.entries(model.fields)) {
6588
+ lines.push("");
6589
+ lines.push(`[models.${modelName}.fields.${fieldName}]`);
6590
+ lines.push(`type = ${tomlValue(field.type)}`);
6591
+ if (field.autoAssign) lines.push("auto_assign = true");
6592
+ if (field.indexed) lines.push("indexed = true");
6593
+ if (field.unique) lines.push("unique = true");
6594
+ if (field.required) lines.push("required = true");
6595
+ if (field.maxLength !== void 0) lines.push(`max_length = ${field.maxLength}`);
6596
+ if (field.maxCount !== void 0) lines.push(`max_count = ${field.maxCount}`);
6597
+ if (field.default !== void 0) lines.push(`default = ${tomlValue(field.default)}`);
6598
+ }
6599
+ if (model.relationships) {
6600
+ for (const [relName, rel] of Object.entries(model.relationships)) {
6601
+ lines.push("");
6602
+ lines.push(`[models.${modelName}.relationships.${relName}]`);
6603
+ for (const [k, v] of Object.entries(rel)) {
6604
+ if (v === void 0) continue;
6605
+ lines.push(`${toSnake(k)} = ${tomlValue(v)}`);
6606
+ }
6607
+ }
6608
+ }
6609
+ if (model.constraints) {
6610
+ for (const [cName, c] of Object.entries(model.constraints)) {
6611
+ lines.push("");
6612
+ lines.push(`[[models.${modelName}.unique_constraints]]`);
6613
+ lines.push(`name = ${tomlValue(cName)}`);
6614
+ lines.push(`fields = [${c.fields.map((f) => tomlValue(f)).join(", ")}]`);
6615
+ }
6616
+ }
6617
+ }
6618
+ lines.push("");
6619
+ return lines.join("\n");
6620
+ }
6621
+
6622
+ // src/models/tomlLoader.ts
6623
+ import { parse as parseToml } from "smol-toml";
6624
+ var VALID_FIELD_TYPES = /* @__PURE__ */ new Set([
6625
+ "string",
6626
+ "number",
6627
+ "boolean",
6628
+ "date",
6629
+ "id",
6630
+ "stringset"
6631
+ ]);
6632
+ function parseFieldOptions(raw) {
6633
+ if (!raw.type || !VALID_FIELD_TYPES.has(raw.type)) {
6634
+ throw new Error(
6635
+ `Invalid field type "${raw.type}". Must be one of: ${[...VALID_FIELD_TYPES].join(", ")}`
6636
+ );
6637
+ }
6638
+ const opts = { type: raw.type };
6639
+ if (raw.indexed === true) opts.indexed = true;
6640
+ if (raw.unique === true) opts.unique = true;
6641
+ if (raw.required === true) opts.required = true;
6642
+ if (raw.auto_assign === true) opts.autoAssign = true;
6643
+ if (raw.max_length !== void 0) opts.maxLength = raw.max_length;
6644
+ if (raw.max_count !== void 0) opts.maxCount = raw.max_count;
6645
+ if (raw.default !== void 0) opts.default = raw.default;
6646
+ return opts;
6647
+ }
6648
+ function requireField(raw, field, context) {
6649
+ if (!raw[field]) {
6650
+ throw new Error(`Relationship ${context}: missing required field "${field}"`);
6651
+ }
6652
+ }
6653
+ function parseRelationship(raw) {
6654
+ const type = raw.type;
6655
+ if (type === "refersTo") {
6656
+ requireField(raw, "model", "refersTo");
6657
+ requireField(raw, "related_id_field", "refersTo");
6658
+ return {
6659
+ type: "refersTo",
6660
+ model: raw.model,
6661
+ relatedIdField: raw.related_id_field
6662
+ };
6663
+ }
6664
+ if (type === "hasMany") {
6665
+ requireField(raw, "model", "hasMany");
6666
+ requireField(raw, "related_id_field", "hasMany");
6667
+ const rel = {
6668
+ type: "hasMany",
6669
+ model: raw.model,
6670
+ relatedIdField: raw.related_id_field
6671
+ };
6672
+ if (raw.order_by_field) rel.orderByField = raw.order_by_field;
6673
+ if (raw.order_direction) rel.orderDirection = raw.order_direction;
6674
+ return rel;
6675
+ }
6676
+ if (type === "hasManyThrough") {
6677
+ requireField(raw, "model", "hasManyThrough");
6678
+ requireField(raw, "join_model", "hasManyThrough");
6679
+ requireField(raw, "join_model_local_field", "hasManyThrough");
6680
+ requireField(raw, "join_model_related_field", "hasManyThrough");
6681
+ const rel = {
6682
+ type: "hasManyThrough",
6683
+ model: raw.model,
6684
+ joinModel: raw.join_model,
6685
+ joinModelLocalField: raw.join_model_local_field,
6686
+ joinModelRelatedField: raw.join_model_related_field
6687
+ };
6688
+ if (raw.join_model_order_by_field)
6689
+ rel.joinModelOrderByField = raw.join_model_order_by_field;
6690
+ if (raw.join_model_order_direction)
6691
+ rel.joinModelOrderDirection = raw.join_model_order_direction;
6692
+ return rel;
6693
+ }
6694
+ throw new Error(`Unknown relationship type: ${type}`);
6695
+ }
6696
+ function loadSchemaFromTomlString(tomlString) {
6697
+ const parsed = parseToml(tomlString);
6698
+ const models = parsed.models;
6699
+ if (!models || typeof models !== "object") {
6700
+ throw new Error("TOML schema must have a [models] section");
6701
+ }
6702
+ const schemas = [];
6703
+ for (const [modelName, modelDef] of Object.entries(models)) {
6704
+ const fields = {};
6705
+ if (modelDef.fields) {
6706
+ for (const [fieldName, fieldDef] of Object.entries(modelDef.fields)) {
6707
+ fields[fieldName] = parseFieldOptions(fieldDef);
6708
+ }
6709
+ }
6710
+ let relationships;
6711
+ if (modelDef.relationships) {
6712
+ relationships = {};
6713
+ for (const [relName, relDef] of Object.entries(
6714
+ modelDef.relationships
6715
+ )) {
6716
+ relationships[relName] = parseRelationship(relDef);
6717
+ }
6718
+ }
6719
+ let uniqueConstraints;
6720
+ if (modelDef.unique_constraints) {
6721
+ uniqueConstraints = [];
6722
+ for (const raw of modelDef.unique_constraints) {
6723
+ uniqueConstraints.push({
6724
+ name: raw.name,
6725
+ fields: [...raw.fields]
6726
+ });
6727
+ }
6728
+ }
6729
+ schemas.push(
6730
+ defineModelSchema({
6731
+ name: modelName,
6732
+ fields,
6733
+ options: {
6734
+ uniqueConstraints,
6735
+ relationships
6736
+ }
6737
+ })
6738
+ );
6739
+ }
6740
+ return schemas;
6741
+ }
6742
+
6743
+ // src/browser.ts
6744
+ init_metaSync();
6513
6745
  export {
6514
6746
  BaseModel2 as BaseModel,
6515
6747
  DatabaseEngine,
6516
6748
  BrowserDatabaseFactory as DatabaseFactory,
6517
- Field,
6518
6749
  LogLevel,
6519
6750
  Logger,
6520
- Model,
6521
6751
  ModelRegistry,
6522
6752
  RecordNotFoundError,
6523
6753
  SqljsEngine,
@@ -6526,13 +6756,22 @@ export {
6526
6756
  attachAndRegisterModel,
6527
6757
  attachSchemaToClass,
6528
6758
  autoRegisterModel,
6759
+ clearMetaSyncCache,
6529
6760
  createModelClass,
6530
6761
  defineModelSchema,
6531
6762
  detectEnvironment,
6763
+ discoverModelNames,
6764
+ discoverSchema,
6532
6765
  features,
6533
6766
  generateULID,
6767
+ inferFieldType,
6534
6768
  initJsBao,
6535
6769
  isBrowser,
6536
6770
  isNode,
6537
- resetJsBao
6771
+ loadSchemaFromTomlString,
6772
+ registerFunctionDefault,
6773
+ resetJsBao,
6774
+ schemaToToml,
6775
+ syncInferredMeta,
6776
+ syncModelMeta
6538
6777
  };