@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.cjs CHANGED
@@ -1455,8 +1455,15 @@ var _MetadataManager = class _MetadataManager {
1455
1455
  * Stores in-memory registry and persists to database-backed loaders only.
1456
1456
  * FilesystemLoader (protocol 'file:') is read-only for static metadata and
1457
1457
  * should not be written to during runtime registration.
1458
+ *
1459
+ * Announces the write to {@link subscribe} watchers as an `added` /
1460
+ * `changed` {@link MetadataWatchEvent}, so consumers that cache metadata
1461
+ * (ObjectQL's SchemaRegistry bridge, the HMR SSE stream) refresh instead of
1462
+ * serving the pre-write definition until restart. Pass `{ notify: false }`
1463
+ * for bulk ingest that announces by other means — read
1464
+ * {@link MetadataWriteOptions.notify} before doing so.
1458
1465
  */
1459
- async register(type, name, data) {
1466
+ async register(type, name, data, options) {
1460
1467
  if (this.config.persistence?.writable === false) {
1461
1468
  const msg = `MetadataManager is read-only (persistence.writable=false); refusing to register ${type}/${name}`;
1462
1469
  if (this.config.validation?.throwOnError) {
@@ -1465,6 +1472,7 @@ var _MetadataManager = class _MetadataManager {
1465
1472
  this.logger.warn(msg);
1466
1473
  return;
1467
1474
  }
1475
+ const existed = this.registry.get(type)?.has(name) ?? false;
1468
1476
  if (!this.registry.has(type)) {
1469
1477
  this.registry.set(type, /* @__PURE__ */ new Map());
1470
1478
  }
@@ -1494,6 +1502,16 @@ var _MetadataManager = class _MetadataManager {
1494
1502
  this.logger.warn(`Failed to publish metadata event`, { type, name, error });
1495
1503
  }
1496
1504
  }
1505
+ if (options?.notify !== false) {
1506
+ this.notifyWatchers(type, {
1507
+ type: existed ? "changed" : "added",
1508
+ metadataType: type,
1509
+ name,
1510
+ path: "",
1511
+ data,
1512
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1513
+ });
1514
+ }
1497
1515
  }
1498
1516
  /**
1499
1517
  * Register a metadata item into the in-memory registry ONLY, never persisting
@@ -1503,6 +1521,13 @@ var _MetadataManager = class _MetadataManager {
1503
1521
  * Addendum) declared in `*.datasource.ts` and owned by source control. Writing
1504
1522
  * them through `register()` would persist them to `sys_metadata` and create
1505
1523
  * drift between the artefact and the DB; this method avoids that.
1524
+ *
1525
+ * Deliberately silent: it does NOT announce to {@link subscribe} watchers.
1526
+ * This is a boot-time seeding primitive for artefacts that source control
1527
+ * owns — callers that mutate metadata mid-run want {@link register}, which
1528
+ * announces. If you add a mid-run caller here, announce the change yourself
1529
+ * (as the artifact reload path does via `metadata:reloaded`) or its
1530
+ * consumers will read the pre-write definition until restart.
1506
1531
  */
1507
1532
  registerInMemory(type, name, data) {
1508
1533
  if (!this.registry.has(type)) {
@@ -1565,8 +1590,13 @@ var _MetadataManager = class _MetadataManager {
1565
1590
  /**
1566
1591
  * Unregister/remove a metadata item by type and name.
1567
1592
  * Deletes from database-backed loaders only (same rationale as register()).
1593
+ *
1594
+ * Announces the removal to {@link subscribe} watchers as a `deleted`
1595
+ * {@link MetadataWatchEvent} — the delete half of the {@link register}
1596
+ * contract. Pass `{ notify: false }` only for teardown that announces by
1597
+ * other means.
1568
1598
  */
1569
- async unregister(type, name) {
1599
+ async unregister(type, name, options) {
1570
1600
  const typeStore = this.registry.get(type);
1571
1601
  if (typeStore) {
1572
1602
  typeStore.delete(name);
@@ -1602,6 +1632,16 @@ var _MetadataManager = class _MetadataManager {
1602
1632
  this.logger.warn(`Failed to publish metadata event`, { type, name, error });
1603
1633
  }
1604
1634
  }
1635
+ if (options?.notify !== false) {
1636
+ this.notifyWatchers(type, {
1637
+ type: "deleted",
1638
+ metadataType: type,
1639
+ name,
1640
+ path: "",
1641
+ data: void 0,
1642
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1643
+ });
1644
+ }
1605
1645
  }
1606
1646
  /**
1607
1647
  * Check if a metadata item exists
@@ -1938,16 +1978,20 @@ var _MetadataManager = class _MetadataManager {
1938
1978
  // Bulk Operations
1939
1979
  // ==========================================
1940
1980
  /**
1941
- * Register multiple metadata items in a single batch
1981
+ * Register multiple metadata items in a single batch.
1982
+ *
1983
+ * Announces one event per item, like {@link register}. Pass
1984
+ * `{ notify: false }` when the batch is boot-time ingest or when the caller
1985
+ * announces the whole set once — see {@link MetadataWriteOptions.notify}.
1942
1986
  */
1943
1987
  async bulkRegister(items, options) {
1944
- const { continueOnError = false } = options ?? {};
1988
+ const { continueOnError = false, notify } = options ?? {};
1945
1989
  let succeeded = 0;
1946
1990
  let failed = 0;
1947
1991
  const errors = [];
1948
1992
  for (const item of items) {
1949
1993
  try {
1950
- await this.register(item.type, item.name, item.data);
1994
+ await this.register(item.type, item.name, item.data, { notify });
1951
1995
  succeeded++;
1952
1996
  } catch (e) {
1953
1997
  failed++;
@@ -1967,15 +2011,17 @@ var _MetadataManager = class _MetadataManager {
1967
2011
  };
1968
2012
  }
1969
2013
  /**
1970
- * Unregister multiple metadata items in a single batch
2014
+ * Unregister multiple metadata items in a single batch.
2015
+ *
2016
+ * Announces one `deleted` event per item, like {@link unregister}.
1971
2017
  */
1972
- async bulkUnregister(items) {
2018
+ async bulkUnregister(items, options) {
1973
2019
  let succeeded = 0;
1974
2020
  let failed = 0;
1975
2021
  const errors = [];
1976
2022
  for (const item of items) {
1977
2023
  try {
1978
- await this.unregister(item.type, item.name);
2024
+ await this.unregister(item.type, item.name, options);
1979
2025
  succeeded++;
1980
2026
  } catch (e) {
1981
2027
  failed++;
@@ -3489,6 +3535,14 @@ var MetadataPlugin = class {
3489
3535
  /**
3490
3536
  * Parse raw artifact JSON (envelope or bare definition) and register all
3491
3537
  * metadata items into the MetadataManager.
3538
+ *
3539
+ * Registers with `{ notify: false }` — one announcement per artifact, not
3540
+ * one per item. Both callers cover the whole set already: the boot load
3541
+ * runs before consumers have cached anything, and the reload path
3542
+ * (`_reloadAndAnnounce`) fires `metadata:reloaded` carrying the parsed
3543
+ * artifact once the ingest is complete. Announcing here too would emit N
3544
+ * duplicate events per reload, each racing the batch that is still
3545
+ * landing.
3492
3546
  */
3493
3547
  async _parseAndRegisterArtifact(ctx, raw, label) {
3494
3548
  const { EnvironmentArtifactSchema } = await import("@objectstack/spec/cloud");
@@ -3515,6 +3569,7 @@ var MetadataPlugin = class {
3515
3569
  });
3516
3570
  metadata = def;
3517
3571
  }
3572
+ this.lastParsedMetadata = metadata;
3518
3573
  const memLoader = new MemoryLoader();
3519
3574
  const manifestPackageId = metadata?.manifest?.id ?? metadata?.id ?? void 0;
3520
3575
  const manifestVersion = metadata?.manifest?.version ?? metadata?.version ?? void 0;
@@ -3531,7 +3586,7 @@ var MetadataPlugin = class {
3531
3586
  packageVersion: manifestVersion
3532
3587
  });
3533
3588
  await memLoader.save("view", viewObject, item);
3534
- await this.manager.register("view", viewObject, item);
3589
+ await this.manager.register("view", viewObject, item, { notify: false });
3535
3590
  totalRegistered++;
3536
3591
  for (const vi of (0, import_spec2.expandViewContainer)(viewObject, item)) {
3537
3592
  for (const w of vi._diagnostics?.warnings ?? []) {
@@ -3542,7 +3597,7 @@ var MetadataPlugin = class {
3542
3597
  packageVersion: manifestVersion
3543
3598
  });
3544
3599
  await memLoader.save("view", vi.name, vi);
3545
- await this.manager.register("view", vi.name, vi);
3600
+ await this.manager.register("view", vi.name, vi, { notify: false });
3546
3601
  totalRegistered++;
3547
3602
  }
3548
3603
  continue;
@@ -3559,7 +3614,7 @@ var MetadataPlugin = class {
3559
3614
  packageVersion: manifestVersion
3560
3615
  });
3561
3616
  await memLoader.save(metaType, name, item);
3562
- await this.manager.register(metaType, name, item);
3617
+ await this.manager.register(metaType, name, item, { notify: false });
3563
3618
  totalRegistered++;
3564
3619
  }
3565
3620
  }
@@ -3583,7 +3638,7 @@ var MetadataPlugin = class {
3583
3638
  async _reloadAndAnnounce(ctx, src, changed) {
3584
3639
  await this._loadFromLocalFile(ctx, src.path, src.fetchTimeoutMs);
3585
3640
  try {
3586
- await ctx.trigger("metadata:reloaded", { changed });
3641
+ await ctx.trigger("metadata:reloaded", { changed, metadata: this.lastParsedMetadata });
3587
3642
  } catch (e) {
3588
3643
  ctx.logger.warn("[MetadataPlugin] metadata:reloaded subscriber failed", { error: e?.message });
3589
3644
  }
@@ -3648,7 +3703,7 @@ var MetadataPlugin = class {
3648
3703
  (0, import_shared.applyProtection)(meta, {
3649
3704
  packageId: this.options.packageId
3650
3705
  });
3651
- await this.manager.register(entry.type, meta.name, item);
3706
+ await this.manager.register(entry.type, meta.name, item, { notify: false });
3652
3707
  }
3653
3708
  }
3654
3709
  ctx.logger.info(`Loaded ${items.length} ${entry.type} from file system`);