@objectstack/metadata 4.0.2 → 4.0.4

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
@@ -1039,6 +1039,16 @@ var MetadataManager = class {
1039
1039
  this.registerLoader(dbLoader);
1040
1040
  this.logger.info("DatabaseLoader configured", { datasource: this.config.datasource, tableName });
1041
1041
  }
1042
+ /**
1043
+ * Set the realtime service for publishing metadata change events.
1044
+ * Should be called after kernel resolves the realtime service.
1045
+ *
1046
+ * @param service - An IRealtimeService instance for event publishing
1047
+ */
1048
+ setRealtimeService(service) {
1049
+ this.realtimeService = service;
1050
+ this.logger.info("RealtimeService configured for metadata events");
1051
+ }
1042
1052
  /**
1043
1053
  * Register a new metadata loader (data source)
1044
1054
  */
@@ -1051,7 +1061,9 @@ var MetadataManager = class {
1051
1061
  // ==========================================
1052
1062
  /**
1053
1063
  * Register/save a metadata item by type
1054
- * Stores in-memory registry and persists to writable loaders (if configured)
1064
+ * Stores in-memory registry and persists to database-backed loaders only.
1065
+ * FilesystemLoader (protocol 'file:') is read-only for static metadata and
1066
+ * should not be written to during runtime registration.
1055
1067
  */
1056
1068
  async register(type, name, data) {
1057
1069
  if (!this.registry.has(type)) {
@@ -1059,10 +1071,29 @@ var MetadataManager = class {
1059
1071
  }
1060
1072
  this.registry.get(type).set(name, data);
1061
1073
  for (const loader of this.loaders.values()) {
1062
- if (loader.save) {
1074
+ if (loader.save && loader.contract.protocol === "datasource:" && loader.contract.capabilities.write) {
1063
1075
  await loader.save(type, name, data);
1064
1076
  }
1065
1077
  }
1078
+ if (this.realtimeService) {
1079
+ const event = {
1080
+ type: `metadata.${type}.created`,
1081
+ object: type,
1082
+ payload: {
1083
+ metadataType: type,
1084
+ name,
1085
+ definition: data,
1086
+ packageId: data?.packageId
1087
+ },
1088
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1089
+ };
1090
+ try {
1091
+ await this.realtimeService.publish(event);
1092
+ this.logger.debug(`Published metadata.${type}.created event`, { name });
1093
+ } catch (error) {
1094
+ this.logger.warn(`Failed to publish metadata event`, { type, name, error });
1095
+ }
1096
+ }
1066
1097
  }
1067
1098
  /**
1068
1099
  * Get a metadata item by type and name.
@@ -1103,7 +1134,8 @@ var MetadataManager = class {
1103
1134
  return Array.from(items.values());
1104
1135
  }
1105
1136
  /**
1106
- * Unregister/remove a metadata item by type and name
1137
+ * Unregister/remove a metadata item by type and name.
1138
+ * Deletes from database-backed loaders only (same rationale as register()).
1107
1139
  */
1108
1140
  async unregister(type, name) {
1109
1141
  const typeStore = this.registry.get(type);
@@ -1114,6 +1146,7 @@ var MetadataManager = class {
1114
1146
  }
1115
1147
  }
1116
1148
  for (const loader of this.loaders.values()) {
1149
+ if (loader.contract.protocol !== "datasource:" || !loader.contract.capabilities.write) continue;
1117
1150
  if (typeof loader.delete === "function") {
1118
1151
  try {
1119
1152
  await loader.delete(type, name);
@@ -1122,6 +1155,23 @@ var MetadataManager = class {
1122
1155
  }
1123
1156
  }
1124
1157
  }
1158
+ if (this.realtimeService) {
1159
+ const event = {
1160
+ type: `metadata.${type}.deleted`,
1161
+ object: type,
1162
+ payload: {
1163
+ metadataType: type,
1164
+ name
1165
+ },
1166
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1167
+ };
1168
+ try {
1169
+ await this.realtimeService.publish(event);
1170
+ this.logger.debug(`Published metadata.${type}.deleted event`, { name });
1171
+ } catch (error) {
1172
+ this.logger.warn(`Failed to publish metadata event`, { type, name, error });
1173
+ }
1174
+ }
1125
1175
  }
1126
1176
  /**
1127
1177
  * Check if a metadata item exists
@@ -2467,6 +2517,7 @@ var MetadataPlugin = class {
2467
2517
  watch: this.options.watch
2468
2518
  });
2469
2519
  ctx.registerService("metadata", this.manager);
2520
+ console.log("[MetadataPlugin] Registered metadata service, has getRegisteredTypes:", typeof this.manager.getRegisteredTypes);
2470
2521
  try {
2471
2522
  ctx.getService("manifest").register({
2472
2523
  id: "com.objectstack.metadata",
@@ -2510,6 +2561,52 @@ var MetadataPlugin = class {
2510
2561
  totalItems: totalLoaded,
2511
2562
  registeredTypes: sortedTypes.length
2512
2563
  });
2564
+ let driverBridged = false;
2565
+ try {
2566
+ const ql = ctx.getService("objectql");
2567
+ if (ql) {
2568
+ const tableName = this.manager["config"]?.tableName ?? "sys_metadata";
2569
+ const driver = ql.getDriverForObject?.(tableName);
2570
+ if (driver) {
2571
+ ctx.logger.info("[MetadataPlugin] Bridging driver to MetadataManager via ObjectQL routing", {
2572
+ tableName,
2573
+ driver: driver.name
2574
+ });
2575
+ this.manager.setDatabaseDriver(driver);
2576
+ driverBridged = true;
2577
+ } else {
2578
+ ctx.logger.debug("[MetadataPlugin] ObjectQL could not resolve driver for metadata table", { tableName });
2579
+ }
2580
+ }
2581
+ } catch {
2582
+ }
2583
+ if (!driverBridged) {
2584
+ try {
2585
+ const services = ctx.getServices();
2586
+ for (const [serviceName, service] of services) {
2587
+ if (serviceName.startsWith("driver.") && service) {
2588
+ ctx.logger.info("[MetadataPlugin] Bridging driver to MetadataManager (fallback: first driver)", {
2589
+ driverService: serviceName
2590
+ });
2591
+ this.manager.setDatabaseDriver(service);
2592
+ break;
2593
+ }
2594
+ }
2595
+ } catch (e) {
2596
+ ctx.logger.debug("[MetadataPlugin] No driver service found", { error: e.message });
2597
+ }
2598
+ }
2599
+ try {
2600
+ const realtimeService = ctx.getService("realtime");
2601
+ if (realtimeService && typeof realtimeService === "object" && "publish" in realtimeService) {
2602
+ ctx.logger.info("[MetadataPlugin] Bridging realtime service to MetadataManager for event publishing");
2603
+ this.manager.setRealtimeService(realtimeService);
2604
+ }
2605
+ } catch (e) {
2606
+ ctx.logger.debug("[MetadataPlugin] No realtime service found \u2014 metadata events will not be published", {
2607
+ error: e.message
2608
+ });
2609
+ }
2513
2610
  };
2514
2611
  this.options = {
2515
2612
  watch: true,