@objectstack/metadata 15.1.1 → 16.0.0-rc.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/node.js CHANGED
@@ -1410,8 +1410,15 @@ var _MetadataManager = class _MetadataManager {
1410
1410
  * Stores in-memory registry and persists to database-backed loaders only.
1411
1411
  * FilesystemLoader (protocol 'file:') is read-only for static metadata and
1412
1412
  * should not be written to during runtime registration.
1413
- */
1414
- async register(type, name, data) {
1413
+ *
1414
+ * Announces the write to {@link subscribe} watchers as an `added` /
1415
+ * `changed` {@link MetadataWatchEvent}, so consumers that cache metadata
1416
+ * (ObjectQL's SchemaRegistry bridge, the HMR SSE stream) refresh instead of
1417
+ * serving the pre-write definition until restart. Pass `{ notify: false }`
1418
+ * for bulk ingest that announces by other means — read
1419
+ * {@link MetadataWriteOptions.notify} before doing so.
1420
+ */
1421
+ async register(type, name, data, options) {
1415
1422
  if (this.config.persistence?.writable === false) {
1416
1423
  const msg = `MetadataManager is read-only (persistence.writable=false); refusing to register ${type}/${name}`;
1417
1424
  if (this.config.validation?.throwOnError) {
@@ -1420,6 +1427,7 @@ var _MetadataManager = class _MetadataManager {
1420
1427
  this.logger.warn(msg);
1421
1428
  return;
1422
1429
  }
1430
+ const existed = this.registry.get(type)?.has(name) ?? false;
1423
1431
  if (!this.registry.has(type)) {
1424
1432
  this.registry.set(type, /* @__PURE__ */ new Map());
1425
1433
  }
@@ -1449,6 +1457,16 @@ var _MetadataManager = class _MetadataManager {
1449
1457
  this.logger.warn(`Failed to publish metadata event`, { type, name, error });
1450
1458
  }
1451
1459
  }
1460
+ if (options?.notify !== false) {
1461
+ this.notifyWatchers(type, {
1462
+ type: existed ? "changed" : "added",
1463
+ metadataType: type,
1464
+ name,
1465
+ path: "",
1466
+ data,
1467
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1468
+ });
1469
+ }
1452
1470
  }
1453
1471
  /**
1454
1472
  * Register a metadata item into the in-memory registry ONLY, never persisting
@@ -1458,6 +1476,13 @@ var _MetadataManager = class _MetadataManager {
1458
1476
  * Addendum) declared in `*.datasource.ts` and owned by source control. Writing
1459
1477
  * them through `register()` would persist them to `sys_metadata` and create
1460
1478
  * drift between the artefact and the DB; this method avoids that.
1479
+ *
1480
+ * Deliberately silent: it does NOT announce to {@link subscribe} watchers.
1481
+ * This is a boot-time seeding primitive for artefacts that source control
1482
+ * owns — callers that mutate metadata mid-run want {@link register}, which
1483
+ * announces. If you add a mid-run caller here, announce the change yourself
1484
+ * (as the artifact reload path does via `metadata:reloaded`) or its
1485
+ * consumers will read the pre-write definition until restart.
1461
1486
  */
1462
1487
  registerInMemory(type, name, data) {
1463
1488
  if (!this.registry.has(type)) {
@@ -1520,8 +1545,13 @@ var _MetadataManager = class _MetadataManager {
1520
1545
  /**
1521
1546
  * Unregister/remove a metadata item by type and name.
1522
1547
  * Deletes from database-backed loaders only (same rationale as register()).
1548
+ *
1549
+ * Announces the removal to {@link subscribe} watchers as a `deleted`
1550
+ * {@link MetadataWatchEvent} — the delete half of the {@link register}
1551
+ * contract. Pass `{ notify: false }` only for teardown that announces by
1552
+ * other means.
1523
1553
  */
1524
- async unregister(type, name) {
1554
+ async unregister(type, name, options) {
1525
1555
  const typeStore = this.registry.get(type);
1526
1556
  if (typeStore) {
1527
1557
  typeStore.delete(name);
@@ -1557,6 +1587,16 @@ var _MetadataManager = class _MetadataManager {
1557
1587
  this.logger.warn(`Failed to publish metadata event`, { type, name, error });
1558
1588
  }
1559
1589
  }
1590
+ if (options?.notify !== false) {
1591
+ this.notifyWatchers(type, {
1592
+ type: "deleted",
1593
+ metadataType: type,
1594
+ name,
1595
+ path: "",
1596
+ data: void 0,
1597
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1598
+ });
1599
+ }
1560
1600
  }
1561
1601
  /**
1562
1602
  * Check if a metadata item exists
@@ -1893,16 +1933,20 @@ var _MetadataManager = class _MetadataManager {
1893
1933
  // Bulk Operations
1894
1934
  // ==========================================
1895
1935
  /**
1896
- * Register multiple metadata items in a single batch
1936
+ * Register multiple metadata items in a single batch.
1937
+ *
1938
+ * Announces one event per item, like {@link register}. Pass
1939
+ * `{ notify: false }` when the batch is boot-time ingest or when the caller
1940
+ * announces the whole set once — see {@link MetadataWriteOptions.notify}.
1897
1941
  */
1898
1942
  async bulkRegister(items, options) {
1899
- const { continueOnError = false } = options ?? {};
1943
+ const { continueOnError = false, notify } = options ?? {};
1900
1944
  let succeeded = 0;
1901
1945
  let failed = 0;
1902
1946
  const errors = [];
1903
1947
  for (const item of items) {
1904
1948
  try {
1905
- await this.register(item.type, item.name, item.data);
1949
+ await this.register(item.type, item.name, item.data, { notify });
1906
1950
  succeeded++;
1907
1951
  } catch (e) {
1908
1952
  failed++;
@@ -1922,15 +1966,17 @@ var _MetadataManager = class _MetadataManager {
1922
1966
  };
1923
1967
  }
1924
1968
  /**
1925
- * Unregister multiple metadata items in a single batch
1969
+ * Unregister multiple metadata items in a single batch.
1970
+ *
1971
+ * Announces one `deleted` event per item, like {@link unregister}.
1926
1972
  */
1927
- async bulkUnregister(items) {
1973
+ async bulkUnregister(items, options) {
1928
1974
  let succeeded = 0;
1929
1975
  let failed = 0;
1930
1976
  const errors = [];
1931
1977
  for (const item of items) {
1932
1978
  try {
1933
- await this.unregister(item.type, item.name);
1979
+ await this.unregister(item.type, item.name, options);
1934
1980
  succeeded++;
1935
1981
  } catch (e) {
1936
1982
  failed++;
@@ -3450,6 +3496,14 @@ var MetadataPlugin = class {
3450
3496
  /**
3451
3497
  * Parse raw artifact JSON (envelope or bare definition) and register all
3452
3498
  * metadata items into the MetadataManager.
3499
+ *
3500
+ * Registers with `{ notify: false }` — one announcement per artifact, not
3501
+ * one per item. Both callers cover the whole set already: the boot load
3502
+ * runs before consumers have cached anything, and the reload path
3503
+ * (`_reloadAndAnnounce`) fires `metadata:reloaded` carrying the parsed
3504
+ * artifact once the ingest is complete. Announcing here too would emit N
3505
+ * duplicate events per reload, each racing the batch that is still
3506
+ * landing.
3453
3507
  */
3454
3508
  async _parseAndRegisterArtifact(ctx, raw, label) {
3455
3509
  const { EnvironmentArtifactSchema } = await import("@objectstack/spec/cloud");
@@ -3476,6 +3530,7 @@ var MetadataPlugin = class {
3476
3530
  });
3477
3531
  metadata = def;
3478
3532
  }
3533
+ this.lastParsedMetadata = metadata;
3479
3534
  const memLoader = new MemoryLoader();
3480
3535
  const manifestPackageId = metadata?.manifest?.id ?? metadata?.id ?? void 0;
3481
3536
  const manifestVersion = metadata?.manifest?.version ?? metadata?.version ?? void 0;
@@ -3492,7 +3547,7 @@ var MetadataPlugin = class {
3492
3547
  packageVersion: manifestVersion
3493
3548
  });
3494
3549
  await memLoader.save("view", viewObject, item);
3495
- await this.manager.register("view", viewObject, item);
3550
+ await this.manager.register("view", viewObject, item, { notify: false });
3496
3551
  totalRegistered++;
3497
3552
  for (const vi of expandViewContainer2(viewObject, item)) {
3498
3553
  for (const w of vi._diagnostics?.warnings ?? []) {
@@ -3503,7 +3558,7 @@ var MetadataPlugin = class {
3503
3558
  packageVersion: manifestVersion
3504
3559
  });
3505
3560
  await memLoader.save("view", vi.name, vi);
3506
- await this.manager.register("view", vi.name, vi);
3561
+ await this.manager.register("view", vi.name, vi, { notify: false });
3507
3562
  totalRegistered++;
3508
3563
  }
3509
3564
  continue;
@@ -3520,7 +3575,7 @@ var MetadataPlugin = class {
3520
3575
  packageVersion: manifestVersion
3521
3576
  });
3522
3577
  await memLoader.save(metaType, name, item);
3523
- await this.manager.register(metaType, name, item);
3578
+ await this.manager.register(metaType, name, item, { notify: false });
3524
3579
  totalRegistered++;
3525
3580
  }
3526
3581
  }
@@ -3544,7 +3599,7 @@ var MetadataPlugin = class {
3544
3599
  async _reloadAndAnnounce(ctx, src, changed) {
3545
3600
  await this._loadFromLocalFile(ctx, src.path, src.fetchTimeoutMs);
3546
3601
  try {
3547
- await ctx.trigger("metadata:reloaded", { changed });
3602
+ await ctx.trigger("metadata:reloaded", { changed, metadata: this.lastParsedMetadata });
3548
3603
  } catch (e) {
3549
3604
  ctx.logger.warn("[MetadataPlugin] metadata:reloaded subscriber failed", { error: e?.message });
3550
3605
  }
@@ -3609,7 +3664,7 @@ var MetadataPlugin = class {
3609
3664
  applyProtection(meta, {
3610
3665
  packageId: this.options.packageId
3611
3666
  });
3612
- await this.manager.register(entry.type, meta.name, item);
3667
+ await this.manager.register(entry.type, meta.name, item, { notify: false });
3613
3668
  }
3614
3669
  }
3615
3670
  ctx.logger.info(`Loaded ${items.length} ${entry.type} from file system`);