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