@objectstack/objectql 9.3.0 → 9.4.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.js CHANGED
@@ -332,6 +332,19 @@ var init_seed_loader = __esm({
332
332
  if (records && records.length > 0) {
333
333
  return String(records[0].id || records[0]._id);
334
334
  }
335
+ if (targetField !== "id") {
336
+ const byId = { id: value };
337
+ if (organizationId) byId.organization_id = organizationId;
338
+ const idMatch = await this.engine.find(targetObject, {
339
+ where: byId,
340
+ fields: ["id"],
341
+ limit: 1,
342
+ context: { isSystem: true }
343
+ });
344
+ if (idMatch && idMatch.length > 0) {
345
+ return String(idMatch[0].id || idMatch[0]._id);
346
+ }
347
+ }
335
348
  } catch {
336
349
  }
337
350
  return null;
@@ -950,18 +963,16 @@ function applySystemFields(schema, opts) {
950
963
  fields: { ...additions, ...schema.fields ?? {} }
951
964
  };
952
965
  }
953
- var SYS_METADATA_OWNER = "sys_metadata";
954
- function isRealPackage(pkg) {
955
- return typeof pkg === "string" && pkg.length > 0 && pkg !== SYS_METADATA_OWNER;
966
+ function isShareableNamespace(ns) {
967
+ return RESERVED_NAMESPACES.has(ns) || ns === "sys";
956
968
  }
957
- var MetadataCollisionError = class extends Error {
958
- constructor(type, name, existingPackageId, incomingPackageId) {
969
+ var NamespaceConflictError = class extends Error {
970
+ constructor(namespace, existingPackageId, incomingPackageId) {
959
971
  super(
960
- `Cross-package metadata collision: ${type}/${name} is registered by package "${existingPackageId}" and package "${incomingPackageId}". Bare-named ${type} metadata has no package coordinate in the registry, so the second registration would silently shadow the first (last-write-wins at read time). Rename one of them (a namespace prefix such as "<namespace>_${name}" is recommended), or, if this is a deliberate migration, set OS_METADATA_COLLISION=warn to downgrade to a warning. See ADR-0048.`
972
+ `Namespace conflict: namespace "${namespace}" is already owned by package "${existingPackageId}", so package "${incomingPackageId}" cannot be installed alongside it. A namespace is the mandatory prefix of every object name (e.g. "${namespace}_account") and the container that scopes a package's UI metadata, so it must be unique per installation. Choose a different namespace for "${incomingPackageId}", or uninstall "${existingPackageId}" first. If this is a deliberate migration, set OS_METADATA_COLLISION=warn to downgrade to a warning. See ADR-0048.`
961
973
  );
962
- this.name = "MetadataCollisionError";
963
- this.type = type;
964
- this.name_ = name;
974
+ this.name = "NamespaceConflictError";
975
+ this.namespace = namespace;
965
976
  this.existingPackageId = existingPackageId;
966
977
  this.incomingPackageId = incomingPackageId;
967
978
  }
@@ -1317,17 +1328,6 @@ var SchemaRegistry = class {
1317
1328
  if (collection.has(storageKey)) {
1318
1329
  this.log(`[Registry] Overwriting ${type}: ${storageKey}`);
1319
1330
  }
1320
- if (isRealPackage(packageId)) {
1321
- const conflictOwner = this.findOtherPackageOwner(collection, baseName, packageId);
1322
- if (conflictOwner) {
1323
- const err = new MetadataCollisionError(type, baseName, conflictOwner, packageId);
1324
- if (this.collisionPolicy === "warn") {
1325
- console.warn(`[Registry] ${err.message}`);
1326
- } else {
1327
- throw err;
1328
- }
1329
- }
1330
- }
1331
1331
  if (packageId && collection.has(baseName)) {
1332
1332
  const dbOnly = collection.get(baseName);
1333
1333
  if (dbOnly && !dbOnly._packageId) {
@@ -1339,22 +1339,6 @@ var SchemaRegistry = class {
1339
1339
  collection.set(storageKey, item);
1340
1340
  this.log(`[Registry] Registered ${type}: ${storageKey}`);
1341
1341
  }
1342
- /**
1343
- * Find a code package OTHER than `incoming` that already owns `baseName` in
1344
- * `collection` (ADR-0048 cross-package collision detection). Scans the live
1345
- * collection — like {@link getItem} / {@link unregisterItem} — so it always
1346
- * reflects current state with no parallel index to drift across
1347
- * reset/unregister. Returns the conflicting owner's package id, or undefined
1348
- * when the name is free or only held by the same package / a runtime overlay.
1349
- */
1350
- findOtherPackageOwner(collection, baseName, incoming) {
1351
- for (const [key, item] of collection) {
1352
- if (key !== baseName && !key.endsWith(`:${baseName}`)) continue;
1353
- const owner = item?._packageId;
1354
- if (isRealPackage(owner) && owner !== incoming) return owner;
1355
- }
1356
- return void 0;
1357
- }
1358
1342
  /**
1359
1343
  * Validate Metadata against Spec Zod Schemas
1360
1344
  */
@@ -1397,9 +1381,23 @@ var SchemaRegistry = class {
1397
1381
  console.warn(`[Registry] Attempted to unregister non-existent ${type}: ${name}`);
1398
1382
  }
1399
1383
  /**
1400
- * Universal Get Method
1384
+ * Universal Get Method.
1385
+ *
1386
+ * ADR-0048 §3.3 — *package-scoped* resolution. When `currentPackageId` is
1387
+ * given (the package the caller is resolving within — known from the route /
1388
+ * `activeApp._packageId`), a bare name resolves to *that package's* item
1389
+ * before any cross-package fallback, so two packages shipping e.g.
1390
+ * `page/home` no longer resolve by registration order (first-match-wins).
1391
+ * Because package ids are globally unique this is unambiguous. Omitting
1392
+ * `currentPackageId` preserves the legacy resolution exactly (backward
1393
+ * compatible) and is best-effort: it returns the first match.
1394
+ *
1395
+ * Precedence (highest first):
1396
+ * 1. bare-key runtime/DB overlay (ADR-0005 sanctioned override) — unchanged
1397
+ * 2. the `currentPackageId` composite entry (prefer-local)
1398
+ * 3. first composite match (legacy first-registered-wins fallback)
1401
1399
  */
1402
- getItem(type, name) {
1400
+ getItem(type, name, currentPackageId) {
1403
1401
  if (type === "object" || type === "objects") {
1404
1402
  return this.getObject(name);
1405
1403
  }
@@ -1407,6 +1405,10 @@ var SchemaRegistry = class {
1407
1405
  if (!collection) return void 0;
1408
1406
  const direct = collection.get(name);
1409
1407
  if (direct) return direct;
1408
+ if (currentPackageId) {
1409
+ const local = collection.get(`${currentPackageId}:${name}`);
1410
+ if (local) return local;
1411
+ }
1410
1412
  for (const [key, item] of collection) {
1411
1413
  if (key.endsWith(`:${name}`)) {
1412
1414
  return item;
@@ -1428,13 +1430,17 @@ var SchemaRegistry = class {
1428
1430
  * it (that masking is exactly the "registry pollution" bug where a
1429
1431
  * locked app's `_lock` read back as undefined after a PUT+GET).
1430
1432
  */
1431
- getArtifactItem(type, name) {
1433
+ getArtifactItem(type, name, currentPackageId) {
1432
1434
  if (type === "object" || type === "objects") {
1433
1435
  const obj = this.getObject(name);
1434
1436
  return obj && obj._packageId && obj._packageId !== "sys_metadata" ? obj : void 0;
1435
1437
  }
1436
1438
  const collection = this.metadata.get(type);
1437
1439
  if (!collection) return void 0;
1440
+ if (currentPackageId) {
1441
+ const local = collection.get(`${currentPackageId}:${name}`);
1442
+ if (local && local._packageId && local._packageId !== "sys_metadata") return local;
1443
+ }
1438
1444
  for (const [key, item] of collection) {
1439
1445
  if (key !== name && key.endsWith(`:${name}`)) {
1440
1446
  const it = item;
@@ -1518,6 +1524,20 @@ var SchemaRegistry = class {
1518
1524
  // Package Management
1519
1525
  // ==========================================
1520
1526
  installPackage(manifest, settings) {
1527
+ if (manifest.namespace && !isShareableNamespace(manifest.namespace)) {
1528
+ const conflictOwner = this.getNamespaceOwners(manifest.namespace).find(
1529
+ (owner) => owner !== manifest.id
1530
+ );
1531
+ if (conflictOwner) {
1532
+ if (this.collisionPolicy === "warn") {
1533
+ console.warn(
1534
+ `[Registry] Namespace conflict (downgraded to warning via OS_METADATA_COLLISION=warn): namespace "${manifest.namespace}" is already owned by "${conflictOwner}"; installing "${manifest.id}" anyway. See ADR-0048.`
1535
+ );
1536
+ } else {
1537
+ throw new NamespaceConflictError(manifest.namespace, conflictOwner, manifest.id);
1538
+ }
1539
+ }
1540
+ }
1521
1541
  const now = (/* @__PURE__ */ new Date()).toISOString();
1522
1542
  const disabled = this.initialDisabledPackageIds.has(manifest.id);
1523
1543
  const pkg = {
@@ -1595,8 +1615,8 @@ var SchemaRegistry = class {
1595
1615
  registerApp(app, packageId) {
1596
1616
  this.registerItem("app", app, "name", packageId);
1597
1617
  }
1598
- getApp(name) {
1599
- const app = this.getItem("app", name);
1618
+ getApp(name, currentPackageId) {
1619
+ const app = this.getItem("app", name, currentPackageId);
1600
1620
  if (!app) return app;
1601
1621
  return this.applyNavContributions(app);
1602
1622
  }
@@ -1816,7 +1836,7 @@ var SysMetadataRepository = class {
1816
1836
  this.assertOpen();
1817
1837
  const state = opts?.state ?? "active";
1818
1838
  const row = await this.engine.findOne("sys_metadata", {
1819
- where: this.whereFor(ref, state)
1839
+ where: this.whereFor(ref, state, opts && "packageId" in opts ? opts.packageId ?? null : void 0)
1820
1840
  });
1821
1841
  if (!row) return null;
1822
1842
  return this.rowToItem(ref, row);
@@ -1865,7 +1885,7 @@ var SysMetadataRepository = class {
1865
1885
  const hash = (0, import_metadata_core.hashSpec)(body);
1866
1886
  const result = await this.withTxn(async (ctx) => {
1867
1887
  const existing = await this.engine.findOne("sys_metadata", {
1868
- where: this.whereFor(ref, state),
1888
+ where: this.whereFor(ref, state, opts.packageId ?? null),
1869
1889
  context: ctx
1870
1890
  });
1871
1891
  const existingHash = existing?.checksum ?? null;
@@ -2349,13 +2369,15 @@ var SysMetadataRepository = class {
2349
2369
  err.status = 403;
2350
2370
  throw err;
2351
2371
  }
2352
- whereFor(ref, state = "active") {
2353
- return {
2372
+ whereFor(ref, state = "active", packageId) {
2373
+ const where = {
2354
2374
  type: ref.type,
2355
2375
  name: ref.name,
2356
2376
  organization_id: this.organizationId,
2357
2377
  state
2358
2378
  };
2379
+ if (packageId !== void 0) where.package_id = packageId;
2380
+ return where;
2359
2381
  }
2360
2382
  fullRef(ref) {
2361
2383
  return {
@@ -3042,8 +3064,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3042
3064
  await exec("DROP INDEX IF EXISTS idx_sys_metadata_overlay_active");
3043
3065
  } catch {
3044
3066
  }
3045
- const partialSql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id) WHERE state = 'active'";
3046
- const fallbackSql = "CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id)";
3067
+ const partialSql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id, COALESCE(package_id, '')) WHERE state = 'active'";
3068
+ const fallbackSql = "CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id, package_id)";
3047
3069
  try {
3048
3070
  await exec(partialSql);
3049
3071
  } catch (err) {
@@ -3055,7 +3077,11 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3055
3077
  }
3056
3078
  }
3057
3079
  }
3058
- const draftPartialSql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_draft ON sys_metadata (type, name, organization_id) WHERE state = 'draft'";
3080
+ try {
3081
+ await exec("DROP INDEX IF EXISTS idx_sys_metadata_overlay_draft");
3082
+ } catch {
3083
+ }
3084
+ const draftPartialSql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_draft ON sys_metadata (type, name, organization_id, COALESCE(package_id, '')) WHERE state = 'draft'";
3059
3085
  try {
3060
3086
  await exec(draftPartialSql);
3061
3087
  } catch (err) {
@@ -3063,7 +3089,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3063
3089
  if (/partial|where clause|syntax/i.test(msg)) {
3064
3090
  try {
3065
3091
  await exec(
3066
- "CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_draft ON sys_metadata (type, name, organization_id)"
3092
+ "CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_draft ON sys_metadata (type, name, organization_id, package_id)"
3067
3093
  );
3068
3094
  } catch {
3069
3095
  }
@@ -3464,7 +3490,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3464
3490
  items.map((it) => {
3465
3491
  const a = this.lookupArtifactItem(
3466
3492
  request.type,
3467
- it?.name
3493
+ it?.name,
3494
+ packageId ?? it?._packageId
3468
3495
  );
3469
3496
  return mergeArtifactProtection(it, a);
3470
3497
  })
@@ -3478,16 +3505,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3478
3505
  if (request.previewDrafts && readState !== "draft") {
3479
3506
  try {
3480
3507
  const findDraft = async (oid) => {
3481
- const rec = await this.engine.findOne("sys_metadata", {
3482
- where: { type: request.type, name: request.name, state: "draft", organization_id: oid }
3483
- });
3508
+ const lookup = async (t) => {
3509
+ const base = {
3510
+ type: t,
3511
+ name: request.name,
3512
+ state: "draft",
3513
+ organization_id: oid
3514
+ };
3515
+ if (request.packageId) {
3516
+ const scoped = await this.engine.findOne("sys_metadata", {
3517
+ where: { ...base, package_id: request.packageId }
3518
+ });
3519
+ if (scoped) return scoped;
3520
+ return await this.engine.findOne("sys_metadata", {
3521
+ where: { ...base, package_id: null }
3522
+ });
3523
+ }
3524
+ return await this.engine.findOne("sys_metadata", { where: base });
3525
+ };
3526
+ const rec = await lookup(request.type);
3484
3527
  if (rec) return rec;
3485
3528
  const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3486
- if (alt) {
3487
- return await this.engine.findOne("sys_metadata", {
3488
- where: { type: alt, name: request.name, state: "draft", organization_id: oid }
3489
- });
3490
- }
3529
+ if (alt) return await lookup(alt);
3491
3530
  return void 0;
3492
3531
  };
3493
3532
  const draftRec = (orgId ? await findDraft(orgId) : void 0) ?? await findDraft(null);
@@ -3505,24 +3544,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3505
3544
  }
3506
3545
  try {
3507
3546
  const findOverlay = async (oid) => {
3508
- const where = {
3509
- type: request.type,
3510
- name: request.name,
3511
- state: readState,
3512
- organization_id: oid
3513
- };
3514
- const rec = await this.engine.findOne("sys_metadata", { where });
3515
- if (rec) return rec;
3516
- const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3517
- if (alt) {
3518
- const altWhere = {
3519
- type: alt,
3547
+ const lookup = async (t) => {
3548
+ const base = {
3549
+ type: t,
3520
3550
  name: request.name,
3521
3551
  state: readState,
3522
3552
  organization_id: oid
3523
3553
  };
3524
- return await this.engine.findOne("sys_metadata", { where: altWhere });
3525
- }
3554
+ if (request.packageId) {
3555
+ const scoped = await this.engine.findOne("sys_metadata", {
3556
+ where: { ...base, package_id: request.packageId }
3557
+ });
3558
+ if (scoped) return scoped;
3559
+ return await this.engine.findOne("sys_metadata", {
3560
+ where: { ...base, package_id: null }
3561
+ });
3562
+ }
3563
+ return await this.engine.findOne("sys_metadata", { where: base });
3564
+ };
3565
+ const rec = await lookup(request.type);
3566
+ if (rec) return rec;
3567
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3568
+ if (alt) return await lookup(alt);
3526
3569
  return void 0;
3527
3570
  };
3528
3571
  const record = (orgId ? await findOverlay(orgId) : void 0) ?? await findOverlay(null);
@@ -3551,13 +3594,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3551
3594
  const services = this.getServicesRegistry?.();
3552
3595
  const metadataService = services?.get("metadata");
3553
3596
  if (metadataService && typeof metadataService.get === "function") {
3554
- const fromService = await metadataService.get(request.type, request.name);
3597
+ const fromService = await metadataService.get(request.type, request.name, request.packageId);
3555
3598
  if (fromService !== void 0 && fromService !== null) {
3556
3599
  item = fromService;
3557
3600
  } else {
3558
3601
  const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3559
3602
  if (alt) {
3560
- const altFromService = await metadataService.get(alt, request.name);
3603
+ const altFromService = await metadataService.get(alt, request.name, request.packageId);
3561
3604
  if (altFromService !== void 0 && altFromService !== null) {
3562
3605
  item = altFromService;
3563
3606
  }
@@ -3568,16 +3611,16 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3568
3611
  }
3569
3612
  }
3570
3613
  if (item === void 0) {
3571
- item = this.engine.registry.getItem(request.type, request.name);
3614
+ item = this.engine.registry.getItem(request.type, request.name, request.packageId);
3572
3615
  if (item === void 0) {
3573
3616
  const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3574
- if (alt) item = this.engine.registry.getItem(alt, request.name);
3617
+ if (alt) item = this.engine.registry.getItem(alt, request.name, request.packageId);
3575
3618
  }
3576
3619
  }
3577
3620
  if ((request.type === "app" || request.type === "apps") && item) {
3578
3621
  item = this.engine.registry.applyNavContributions(item);
3579
3622
  }
3580
- const artifactItem = this.lookupArtifactItem(request.type, request.name);
3623
+ const artifactItem = this.lookupArtifactItem(request.type, request.name, request.packageId);
3581
3624
  let decorated = decorateMetadataItem(
3582
3625
  request.type,
3583
3626
  mergeArtifactProtection(item, artifactItem)
@@ -3645,20 +3688,20 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3645
3688
  const services = this.getServicesRegistry?.();
3646
3689
  const metadataService = services?.get("metadata");
3647
3690
  if (metadataService && typeof metadataService.get === "function") {
3648
- let fromService = await metadataService.get(request.type, request.name);
3691
+ let fromService = await metadataService.get(request.type, request.name, request.packageId);
3649
3692
  if (fromService === void 0 || fromService === null) {
3650
3693
  const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3651
- if (alt) fromService = await metadataService.get(alt, request.name);
3694
+ if (alt) fromService = await metadataService.get(alt, request.name, request.packageId);
3652
3695
  }
3653
3696
  if (fromService !== void 0 && fromService !== null) code = fromService;
3654
3697
  }
3655
3698
  } catch {
3656
3699
  }
3657
3700
  if (code === null) {
3658
- let regItem = this.lookupArtifactItem(request.type, request.name) ?? this.engine.registry.getItem(request.type, request.name);
3701
+ let regItem = this.lookupArtifactItem(request.type, request.name, request.packageId) ?? this.engine.registry.getItem(request.type, request.name, request.packageId);
3659
3702
  if (regItem === void 0) {
3660
3703
  const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3661
- if (alt) regItem = this.engine.registry.getItem(alt, request.name);
3704
+ if (alt) regItem = this.engine.registry.getItem(alt, request.name, request.packageId);
3662
3705
  }
3663
3706
  if (regItem !== void 0) code = regItem;
3664
3707
  }
@@ -3666,20 +3709,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3666
3709
  let overlayScope = null;
3667
3710
  try {
3668
3711
  const findOverlay = async (oid) => {
3669
- const where = {
3670
- type: request.type,
3671
- name: request.name,
3672
- state: "active",
3673
- organization_id: oid
3712
+ const lookup = async (t) => {
3713
+ const base = {
3714
+ type: t,
3715
+ name: request.name,
3716
+ state: "active",
3717
+ organization_id: oid
3718
+ };
3719
+ if (request.packageId) {
3720
+ const scoped = await this.engine.findOne("sys_metadata", {
3721
+ where: { ...base, package_id: request.packageId }
3722
+ });
3723
+ if (scoped) return scoped;
3724
+ return await this.engine.findOne("sys_metadata", {
3725
+ where: { ...base, package_id: null }
3726
+ });
3727
+ }
3728
+ return await this.engine.findOne("sys_metadata", { where: base });
3674
3729
  };
3675
- let rec = await this.engine.findOne("sys_metadata", { where });
3730
+ let rec = await lookup(request.type);
3676
3731
  if (!rec) {
3677
3732
  const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
3678
- if (alt) {
3679
- rec = await this.engine.findOne("sys_metadata", {
3680
- where: { ...where, type: alt }
3681
- });
3682
- }
3733
+ if (alt) rec = await lookup(alt);
3683
3734
  }
3684
3735
  return rec;
3685
3736
  };
@@ -4711,15 +4762,15 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4711
4762
  * type and its singular/plural twin. Returns `undefined` when the
4712
4763
  * registry is unavailable or the item is not artifact-backed.
4713
4764
  */
4714
- lookupArtifactItem(type, name) {
4765
+ lookupArtifactItem(type, name, currentPackageId) {
4715
4766
  const registry = this.engine?.registry;
4716
4767
  if (!registry) return void 0;
4717
4768
  const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
4718
4769
  if (typeof registry.getArtifactItem === "function") {
4719
- return registry.getArtifactItem(singular, name) ?? registry.getArtifactItem(type, name);
4770
+ return registry.getArtifactItem(singular, name, currentPackageId) ?? registry.getArtifactItem(type, name, currentPackageId);
4720
4771
  }
4721
4772
  if (typeof registry.getItem !== "function") return void 0;
4722
- const item = registry.getItem(singular, name) ?? registry.getItem(type, name);
4773
+ const item = registry.getItem(singular, name, currentPackageId) ?? registry.getItem(type, name, currentPackageId);
4723
4774
  if (!item || !item._packageId || item._packageId === "sys_metadata") {
4724
4775
  return void 0;
4725
4776
  }
@@ -5085,7 +5136,10 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
5085
5136
  if (request.parentVersion !== void 0) {
5086
5137
  parentVersion = request.parentVersion;
5087
5138
  } else {
5088
- const current = await repo.get(ref, { state: mode === "draft" ? "draft" : "active" });
5139
+ const current = await repo.get(ref, {
5140
+ state: mode === "draft" ? "draft" : "active",
5141
+ packageId: request.packageId ?? null
5142
+ });
5089
5143
  parentVersion = current?.hash ?? null;
5090
5144
  }
5091
5145
  try {
@@ -9507,10 +9561,16 @@ var MetadataFacade = class {
9507
9561
  }
9508
9562
  }
9509
9563
  /**
9510
- * Get a metadata item by type and name
9511
- */
9512
- async get(type, name) {
9513
- const item = this.registry.getItem(type, name);
9564
+ * Get a metadata item by type and name.
9565
+ *
9566
+ * `currentPackageId` (ADR-0048) opts into package-scoped resolution: when two
9567
+ * installed packages ship an item of the same `type`/`name`, the registry
9568
+ * prefers the one owned by `currentPackageId` (composite key
9569
+ * `${packageId}:${name}`) before falling back to first-match. Omit it for the
9570
+ * legacy context-free lookup.
9571
+ */
9572
+ async get(type, name, currentPackageId) {
9573
+ const item = this.registry.getItem(type, name, currentPackageId);
9514
9574
  return item?.content ?? item;
9515
9575
  }
9516
9576
  /**
@@ -9584,6 +9644,7 @@ var ObjectQLPlugin = class {
9584
9644
  */
9585
9645
  this.startupTimeout = 12e4;
9586
9646
  this.skipSchemaSync = false;
9647
+ this.hydrateMetadataFromDb = false;
9587
9648
  /** Unsubscribe handles for metadata-event subscriptions (ADR-0008 PR-7). */
9588
9649
  this.metadataUnsubscribes = [];
9589
9650
  this.init = async (ctx) => {
@@ -9708,7 +9769,7 @@ var ObjectQLPlugin = class {
9708
9769
  } else {
9709
9770
  await this.syncRegisteredSchemas(ctx);
9710
9771
  }
9711
- if (this.environmentId === void 0) {
9772
+ if (this.environmentId === void 0 || this.hydrateMetadataFromDb) {
9712
9773
  await this.restoreMetadataFromDb(ctx);
9713
9774
  } else {
9714
9775
  ctx.logger.info("Project kernel \u2014 skipping sys_metadata hydration (metadata sourced from artifact)");
@@ -9750,6 +9811,7 @@ var ObjectQLPlugin = class {
9750
9811
  this.startupTimeout = opts.startupTimeout;
9751
9812
  }
9752
9813
  this.skipSchemaSync = typeof opts.skipSchemaSync === "boolean" ? opts.skipSchemaSync : process.env.OS_SKIP_SCHEMA_SYNC === "1";
9814
+ this.hydrateMetadataFromDb = opts.hydrateMetadataFromDb === true;
9753
9815
  }
9754
9816
  /**
9755
9817
  * Subscribe to `object` metadata events from the metadata service and