@objectstack/objectql 4.0.1 → 4.0.2

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.mjs CHANGED
@@ -53,36 +53,45 @@ var SchemaRegistry = class {
53
53
  // ==========================================
54
54
  /**
55
55
  * Register a namespace for a package.
56
- * Enforces namespace uniqueness within the instance.
57
- *
58
- * @throws Error if namespace is already registered to a different package
56
+ * Multiple packages can share the same namespace (e.g. 'sys').
59
57
  */
60
58
  static registerNamespace(namespace, packageId) {
61
59
  if (!namespace) return;
62
- const existing = this.namespaceRegistry.get(namespace);
63
- if (existing && existing !== packageId) {
64
- throw new Error(
65
- `Namespace "${namespace}" is already registered to package "${existing}". Package "${packageId}" cannot use the same namespace.`
66
- );
60
+ let owners = this.namespaceRegistry.get(namespace);
61
+ if (!owners) {
62
+ owners = /* @__PURE__ */ new Set();
63
+ this.namespaceRegistry.set(namespace, owners);
67
64
  }
68
- this.namespaceRegistry.set(namespace, packageId);
65
+ owners.add(packageId);
69
66
  this.log(`[Registry] Registered namespace: ${namespace} \u2192 ${packageId}`);
70
67
  }
71
68
  /**
72
69
  * Unregister a namespace when a package is uninstalled.
73
70
  */
74
71
  static unregisterNamespace(namespace, packageId) {
75
- const existing = this.namespaceRegistry.get(namespace);
76
- if (existing === packageId) {
77
- this.namespaceRegistry.delete(namespace);
78
- this.log(`[Registry] Unregistered namespace: ${namespace}`);
72
+ const owners = this.namespaceRegistry.get(namespace);
73
+ if (owners) {
74
+ owners.delete(packageId);
75
+ if (owners.size === 0) {
76
+ this.namespaceRegistry.delete(namespace);
77
+ }
78
+ this.log(`[Registry] Unregistered namespace: ${namespace} \u2190 ${packageId}`);
79
79
  }
80
80
  }
81
81
  /**
82
- * Get the package that owns a namespace.
82
+ * Get the packages that use a namespace.
83
83
  */
84
84
  static getNamespaceOwner(namespace) {
85
- return this.namespaceRegistry.get(namespace);
85
+ const owners = this.namespaceRegistry.get(namespace);
86
+ if (!owners || owners.size === 0) return void 0;
87
+ return owners.values().next().value;
88
+ }
89
+ /**
90
+ * Get all packages that share a namespace.
91
+ */
92
+ static getNamespaceOwners(namespace) {
93
+ const owners = this.namespaceRegistry.get(namespace);
94
+ return owners ? Array.from(owners) : [];
86
95
  }
87
96
  // ==========================================
88
97
  // Object Registration (Ownership Model)
@@ -494,7 +503,7 @@ SchemaRegistry._logLevel = "info";
494
503
  SchemaRegistry.objectContributors = /* @__PURE__ */ new Map();
495
504
  /** FQN → Merged ServiceObject (cached, invalidated on changes) */
496
505
  SchemaRegistry.mergedObjectCache = /* @__PURE__ */ new Map();
497
- /** Namespace → PackageId (ensures namespace uniqueness) */
506
+ /** Namespace → Set<PackageId> (multiple packages can share a namespace) */
498
507
  SchemaRegistry.namespaceRegistry = /* @__PURE__ */ new Map();
499
508
  // ==========================================
500
509
  // Generic metadata storage (non-object types)
@@ -636,15 +645,18 @@ var ObjectStackProtocolImplementation = class {
636
645
  };
637
646
  }
638
647
  async getMetaItems(request) {
639
- let items = SchemaRegistry.listItems(request.type);
648
+ const { packageId } = request;
649
+ let items = SchemaRegistry.listItems(request.type, packageId);
640
650
  if (items.length === 0) {
641
651
  const alt = request.type.endsWith("s") ? request.type.slice(0, -1) : request.type + "s";
642
- items = SchemaRegistry.listItems(alt);
652
+ items = SchemaRegistry.listItems(alt, packageId);
643
653
  }
644
654
  if (items.length === 0) {
645
655
  try {
656
+ const whereClause = { type: request.type, state: "active" };
657
+ if (packageId) whereClause._packageId = packageId;
646
658
  const allRecords = await this.engine.find("sys_metadata", {
647
- where: { type: request.type, state: "active" }
659
+ where: whereClause
648
660
  });
649
661
  if (allRecords && allRecords.length > 0) {
650
662
  items = allRecords.map((record) => {
@@ -872,10 +884,7 @@ var ObjectStackProtocolImplementation = class {
872
884
  const records = await this.engine.find(request.object, options);
873
885
  return {
874
886
  object: request.object,
875
- value: records,
876
- // OData compatibility
877
887
  records,
878
- // Legacy
879
888
  total: records.length,
880
889
  hasMore: false
881
890
  };
@@ -2680,38 +2689,18 @@ var ObjectQLPlugin = class {
2680
2689
  this.ql = new ObjectQL(hostCtx);
2681
2690
  }
2682
2691
  ctx.registerService("objectql", this.ql);
2683
- let hasMetadata = false;
2684
- let metadataProvider = "objectql";
2685
- try {
2686
- if (ctx.getService("metadata")) {
2687
- hasMetadata = true;
2688
- metadataProvider = "external";
2689
- }
2690
- } catch (e) {
2691
- }
2692
- if (!hasMetadata) {
2693
- try {
2694
- const metadataFacade = new MetadataFacade();
2695
- ctx.registerService("metadata", metadataFacade);
2696
- ctx.logger.info("MetadataFacade registered as metadata service", {
2697
- mode: "in-memory",
2698
- features: ["registry", "fast-lookup"]
2692
+ ctx.registerService("data", this.ql);
2693
+ const ql = this.ql;
2694
+ ctx.registerService("manifest", {
2695
+ register: (manifest) => {
2696
+ ql.registerApp(manifest);
2697
+ ctx.logger.debug("Manifest registered via manifest service", {
2698
+ id: manifest.id || manifest.name
2699
2699
  });
2700
- } catch (e) {
2701
- if (!e.message?.includes("already registered")) {
2702
- throw e;
2703
- }
2704
2700
  }
2705
- } else {
2706
- ctx.logger.info("External metadata service detected", {
2707
- provider: metadataProvider,
2708
- mode: "will-sync-in-start-phase"
2709
- });
2710
- }
2711
- ctx.registerService("data", this.ql);
2701
+ });
2712
2702
  ctx.logger.info("ObjectQL engine registered", {
2713
- services: ["objectql", "data"],
2714
- metadataProvider
2703
+ services: ["objectql", "data", "manifest"]
2715
2704
  });
2716
2705
  const protocolShim = new ObjectStackProtocolImplementation(
2717
2706
  this.ql,
@@ -2724,7 +2713,7 @@ var ObjectQLPlugin = class {
2724
2713
  ctx.logger.info("ObjectQL engine starting...");
2725
2714
  try {
2726
2715
  const metadataService = ctx.getService("metadata");
2727
- if (metadataService && !(metadataService instanceof MetadataFacade) && this.ql) {
2716
+ if (metadataService && typeof metadataService.loadMany === "function" && this.ql) {
2728
2717
  await this.loadMetadataFromService(metadataService, ctx);
2729
2718
  }
2730
2719
  } catch (e) {
@@ -2738,8 +2727,11 @@ var ObjectQLPlugin = class {
2738
2727
  ctx.logger.debug("Discovered and registered driver service", { serviceName: name });
2739
2728
  }
2740
2729
  if (name.startsWith("app.")) {
2730
+ ctx.logger.warn(
2731
+ `[DEPRECATED] Service "${name}" uses legacy app.* convention. Migrate to ctx.getService('manifest').register(data).`
2732
+ );
2741
2733
  this.ql.registerApp(service);
2742
- ctx.logger.debug("Discovered and registered app service", { serviceName: name });
2734
+ ctx.logger.debug("Discovered and registered app service (legacy)", { serviceName: name });
2743
2735
  }
2744
2736
  }
2745
2737
  }