@objectstack/objectql 9.2.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.d.mts +124 -6
- package/dist/index.d.ts +124 -6
- package/dist/index.js +384 -112
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +384 -112
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
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,6 +963,20 @@ function applySystemFields(schema, opts) {
|
|
|
950
963
|
fields: { ...additions, ...schema.fields ?? {} }
|
|
951
964
|
};
|
|
952
965
|
}
|
|
966
|
+
function isShareableNamespace(ns) {
|
|
967
|
+
return RESERVED_NAMESPACES.has(ns) || ns === "sys";
|
|
968
|
+
}
|
|
969
|
+
var NamespaceConflictError = class extends Error {
|
|
970
|
+
constructor(namespace, existingPackageId, incomingPackageId) {
|
|
971
|
+
super(
|
|
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.`
|
|
973
|
+
);
|
|
974
|
+
this.name = "NamespaceConflictError";
|
|
975
|
+
this.namespace = namespace;
|
|
976
|
+
this.existingPackageId = existingPackageId;
|
|
977
|
+
this.incomingPackageId = incomingPackageId;
|
|
978
|
+
}
|
|
979
|
+
};
|
|
953
980
|
var SchemaRegistry = class {
|
|
954
981
|
constructor(options = {}) {
|
|
955
982
|
// ==========================================
|
|
@@ -993,6 +1020,7 @@ var SchemaRegistry = class {
|
|
|
993
1020
|
} else {
|
|
994
1021
|
this.multiTenant = String((0, import_types.readEnvWithDeprecation)("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
|
|
995
1022
|
}
|
|
1023
|
+
this.collisionPolicy = options.collisionPolicy ?? ((process.env.OS_METADATA_COLLISION ?? "").toLowerCase() === "warn" ? "warn" : "error");
|
|
996
1024
|
}
|
|
997
1025
|
get logLevel() {
|
|
998
1026
|
return this._logLevel;
|
|
@@ -1353,9 +1381,23 @@ var SchemaRegistry = class {
|
|
|
1353
1381
|
console.warn(`[Registry] Attempted to unregister non-existent ${type}: ${name}`);
|
|
1354
1382
|
}
|
|
1355
1383
|
/**
|
|
1356
|
-
* 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)
|
|
1357
1399
|
*/
|
|
1358
|
-
getItem(type, name) {
|
|
1400
|
+
getItem(type, name, currentPackageId) {
|
|
1359
1401
|
if (type === "object" || type === "objects") {
|
|
1360
1402
|
return this.getObject(name);
|
|
1361
1403
|
}
|
|
@@ -1363,6 +1405,10 @@ var SchemaRegistry = class {
|
|
|
1363
1405
|
if (!collection) return void 0;
|
|
1364
1406
|
const direct = collection.get(name);
|
|
1365
1407
|
if (direct) return direct;
|
|
1408
|
+
if (currentPackageId) {
|
|
1409
|
+
const local = collection.get(`${currentPackageId}:${name}`);
|
|
1410
|
+
if (local) return local;
|
|
1411
|
+
}
|
|
1366
1412
|
for (const [key, item] of collection) {
|
|
1367
1413
|
if (key.endsWith(`:${name}`)) {
|
|
1368
1414
|
return item;
|
|
@@ -1370,6 +1416,74 @@ var SchemaRegistry = class {
|
|
|
1370
1416
|
}
|
|
1371
1417
|
return void 0;
|
|
1372
1418
|
}
|
|
1419
|
+
/**
|
|
1420
|
+
* Artifact-only lookup (ADR-0010 §3.3). Unlike {@link getItem} — which
|
|
1421
|
+
* returns the plain-key entry first, so a runtime/DB-rehydrated row
|
|
1422
|
+
* registered under the bare name SHADOWS the packaged artifact — this
|
|
1423
|
+
* scans the composite (`<packageId>:<name>`) entries first and only
|
|
1424
|
+
* returns an item whose `_packageId` marks a genuine code package
|
|
1425
|
+
* (truthy and not the `'sys_metadata'` rehydration sentinel).
|
|
1426
|
+
*
|
|
1427
|
+
* This is what the protocol's lock/provenance resolution must use:
|
|
1428
|
+
* the artifact's `_lock` envelope always wins over an overlay, and an
|
|
1429
|
+
* overlay row hydrated into the plain key must never be able to mask
|
|
1430
|
+
* it (that masking is exactly the "registry pollution" bug where a
|
|
1431
|
+
* locked app's `_lock` read back as undefined after a PUT+GET).
|
|
1432
|
+
*/
|
|
1433
|
+
getArtifactItem(type, name, currentPackageId) {
|
|
1434
|
+
if (type === "object" || type === "objects") {
|
|
1435
|
+
const obj = this.getObject(name);
|
|
1436
|
+
return obj && obj._packageId && obj._packageId !== "sys_metadata" ? obj : void 0;
|
|
1437
|
+
}
|
|
1438
|
+
const collection = this.metadata.get(type);
|
|
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
|
+
}
|
|
1444
|
+
for (const [key, item] of collection) {
|
|
1445
|
+
if (key !== name && key.endsWith(`:${name}`)) {
|
|
1446
|
+
const it = item;
|
|
1447
|
+
if (it && it._packageId && it._packageId !== "sys_metadata") return item;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
const direct = collection.get(name);
|
|
1451
|
+
if (direct && direct._packageId && direct._packageId !== "sys_metadata") {
|
|
1452
|
+
return direct;
|
|
1453
|
+
}
|
|
1454
|
+
return void 0;
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* Remove a plain-key runtime shadow so the packaged artifact registered
|
|
1458
|
+
* under a composite key becomes the visible value again. Used by the
|
|
1459
|
+
* metadata reset path (`deleteMetaItem`): deleting the `sys_metadata`
|
|
1460
|
+
* overlay row must also heal the in-memory registry, otherwise the
|
|
1461
|
+
* stale overlay copy keeps shadowing the artifact until restart.
|
|
1462
|
+
*
|
|
1463
|
+
* Deliberately conservative: the plain-key entry is only deleted when a
|
|
1464
|
+
* packaged artifact still exists under a composite key, so the name
|
|
1465
|
+
* stays resolvable afterwards. A runtime-only item (no artifact
|
|
1466
|
+
* backing) is left untouched. Note the plain entry's own `_packageId`
|
|
1467
|
+
* is NOT consulted — the hydration path grafts the artifact envelope
|
|
1468
|
+
* onto the shadow (ADR-0010 §3.3), so a stamped `_packageId` does not
|
|
1469
|
+
* mean the plain entry IS the artifact registration; artifact loaders
|
|
1470
|
+
* always register under a composite key.
|
|
1471
|
+
*/
|
|
1472
|
+
removeRuntimeShadow(type, name) {
|
|
1473
|
+
const collection = this.metadata.get(type);
|
|
1474
|
+
if (!collection || !collection.has(name)) return false;
|
|
1475
|
+
for (const [key, item] of collection) {
|
|
1476
|
+
if (key !== name && key.endsWith(`:${name}`)) {
|
|
1477
|
+
const it = item;
|
|
1478
|
+
if (it && it._packageId && it._packageId !== "sys_metadata") {
|
|
1479
|
+
collection.delete(name);
|
|
1480
|
+
this.log(`[Registry] Removed runtime shadow ${type}: ${name} (artifact ${it._packageId} restored)`);
|
|
1481
|
+
return true;
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
return false;
|
|
1486
|
+
}
|
|
1373
1487
|
/**
|
|
1374
1488
|
* Universal List Method
|
|
1375
1489
|
*/
|
|
@@ -1410,6 +1524,20 @@ var SchemaRegistry = class {
|
|
|
1410
1524
|
// Package Management
|
|
1411
1525
|
// ==========================================
|
|
1412
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
|
+
}
|
|
1413
1541
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1414
1542
|
const disabled = this.initialDisabledPackageIds.has(manifest.id);
|
|
1415
1543
|
const pkg = {
|
|
@@ -1487,8 +1615,8 @@ var SchemaRegistry = class {
|
|
|
1487
1615
|
registerApp(app, packageId) {
|
|
1488
1616
|
this.registerItem("app", app, "name", packageId);
|
|
1489
1617
|
}
|
|
1490
|
-
getApp(name) {
|
|
1491
|
-
const app = this.getItem("app", name);
|
|
1618
|
+
getApp(name, currentPackageId) {
|
|
1619
|
+
const app = this.getItem("app", name, currentPackageId);
|
|
1492
1620
|
if (!app) return app;
|
|
1493
1621
|
return this.applyNavContributions(app);
|
|
1494
1622
|
}
|
|
@@ -1708,7 +1836,7 @@ var SysMetadataRepository = class {
|
|
|
1708
1836
|
this.assertOpen();
|
|
1709
1837
|
const state = opts?.state ?? "active";
|
|
1710
1838
|
const row = await this.engine.findOne("sys_metadata", {
|
|
1711
|
-
where: this.whereFor(ref, state)
|
|
1839
|
+
where: this.whereFor(ref, state, opts && "packageId" in opts ? opts.packageId ?? null : void 0)
|
|
1712
1840
|
});
|
|
1713
1841
|
if (!row) return null;
|
|
1714
1842
|
return this.rowToItem(ref, row);
|
|
@@ -1757,7 +1885,7 @@ var SysMetadataRepository = class {
|
|
|
1757
1885
|
const hash = (0, import_metadata_core.hashSpec)(body);
|
|
1758
1886
|
const result = await this.withTxn(async (ctx) => {
|
|
1759
1887
|
const existing = await this.engine.findOne("sys_metadata", {
|
|
1760
|
-
where: this.whereFor(ref, state),
|
|
1888
|
+
where: this.whereFor(ref, state, opts.packageId ?? null),
|
|
1761
1889
|
context: ctx
|
|
1762
1890
|
});
|
|
1763
1891
|
const existingHash = existing?.checksum ?? null;
|
|
@@ -2241,13 +2369,15 @@ var SysMetadataRepository = class {
|
|
|
2241
2369
|
err.status = 403;
|
|
2242
2370
|
throw err;
|
|
2243
2371
|
}
|
|
2244
|
-
whereFor(ref, state = "active") {
|
|
2245
|
-
|
|
2372
|
+
whereFor(ref, state = "active", packageId) {
|
|
2373
|
+
const where = {
|
|
2246
2374
|
type: ref.type,
|
|
2247
2375
|
name: ref.name,
|
|
2248
2376
|
organization_id: this.organizationId,
|
|
2249
2377
|
state
|
|
2250
2378
|
};
|
|
2379
|
+
if (packageId !== void 0) where.package_id = packageId;
|
|
2380
|
+
return where;
|
|
2251
2381
|
}
|
|
2252
2382
|
fullRef(ref) {
|
|
2253
2383
|
return {
|
|
@@ -2394,6 +2524,48 @@ function decorateMetadataItems(type, items) {
|
|
|
2394
2524
|
if (!Array.isArray(items)) return items;
|
|
2395
2525
|
return items.map((item) => decorateMetadataItem(type, item));
|
|
2396
2526
|
}
|
|
2527
|
+
function fieldMap(objectDef) {
|
|
2528
|
+
const map = /* @__PURE__ */ new Map();
|
|
2529
|
+
const fields = objectDef?.fields;
|
|
2530
|
+
if (Array.isArray(fields)) {
|
|
2531
|
+
for (const f of fields) if (f?.name) map.set(f.name, f);
|
|
2532
|
+
} else if (fields && typeof fields === "object") {
|
|
2533
|
+
for (const [name, f] of Object.entries(fields)) map.set(name, f ?? {});
|
|
2534
|
+
}
|
|
2535
|
+
return map;
|
|
2536
|
+
}
|
|
2537
|
+
function computeViewReferenceDiagnostics(view, objectDef) {
|
|
2538
|
+
const fields = fieldMap(objectDef);
|
|
2539
|
+
const errors = [];
|
|
2540
|
+
const requireField = (name, path) => {
|
|
2541
|
+
if (typeof name !== "string" || !name) return;
|
|
2542
|
+
if (!fields.has(name)) {
|
|
2543
|
+
errors.push({
|
|
2544
|
+
path,
|
|
2545
|
+
message: `Field "${name}" does not exist on the source object`,
|
|
2546
|
+
code: "reference_not_found"
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
};
|
|
2550
|
+
const userFilters = view?.userFilters;
|
|
2551
|
+
userFilters?.fields?.forEach((f, i) => requireField(f?.field, `userFilters.fields.${i}.field`));
|
|
2552
|
+
userFilters?.tabs?.forEach((t, i) => t?.filter?.forEach((r, j) => requireField(r?.field, `userFilters.tabs.${i}.filter.${j}.field`)));
|
|
2553
|
+
view?.tabs?.forEach((t, i) => t?.filter?.forEach((r, j) => requireField(r?.field, `tabs.${i}.filter.${j}.field`)));
|
|
2554
|
+
view?.filterableFields?.forEach((f, i) => requireField(f, `filterableFields.${i}`));
|
|
2555
|
+
const kanban = view?.kanban;
|
|
2556
|
+
if (kanban?.groupByField) {
|
|
2557
|
+
requireField(kanban.groupByField, "kanban.groupByField");
|
|
2558
|
+
const def = fields.get(kanban.groupByField);
|
|
2559
|
+
if (def && def.type && !["select", "multi-select", "boolean", "lookup", "master_detail"].includes(def.type)) {
|
|
2560
|
+
errors.push({
|
|
2561
|
+
path: "kanban.groupByField",
|
|
2562
|
+
message: `Field "${kanban.groupByField}" (type "${def.type}") cannot group a kanban \u2014 use a select-like field`,
|
|
2563
|
+
code: "invalid_binding"
|
|
2564
|
+
});
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
return errors.length ? { valid: false, errors } : { valid: true };
|
|
2568
|
+
}
|
|
2397
2569
|
|
|
2398
2570
|
// src/protocol.ts
|
|
2399
2571
|
var TYPE_TO_FORM = import_system.METADATA_FORM_REGISTRY;
|
|
@@ -2892,8 +3064,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2892
3064
|
await exec("DROP INDEX IF EXISTS idx_sys_metadata_overlay_active");
|
|
2893
3065
|
} catch {
|
|
2894
3066
|
}
|
|
2895
|
-
const partialSql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id) WHERE state = 'active'";
|
|
2896
|
-
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)";
|
|
2897
3069
|
try {
|
|
2898
3070
|
await exec(partialSql);
|
|
2899
3071
|
} catch (err) {
|
|
@@ -2905,7 +3077,11 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2905
3077
|
}
|
|
2906
3078
|
}
|
|
2907
3079
|
}
|
|
2908
|
-
|
|
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'";
|
|
2909
3085
|
try {
|
|
2910
3086
|
await exec(draftPartialSql);
|
|
2911
3087
|
} catch (err) {
|
|
@@ -2913,7 +3089,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2913
3089
|
if (/partial|where clause|syntax/i.test(msg)) {
|
|
2914
3090
|
try {
|
|
2915
3091
|
await exec(
|
|
2916
|
-
"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)"
|
|
2917
3093
|
);
|
|
2918
3094
|
} catch {
|
|
2919
3095
|
}
|
|
@@ -3216,8 +3392,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3216
3392
|
}
|
|
3217
3393
|
byName.set(data.name, data);
|
|
3218
3394
|
}
|
|
3219
|
-
if (this.environmentId === void 0) {
|
|
3220
|
-
this.
|
|
3395
|
+
if (this.environmentId === void 0 && data && typeof data === "object") {
|
|
3396
|
+
const artifact = this.lookupArtifactItem(request.type, data.name);
|
|
3397
|
+
this.engine.registry.registerItem(
|
|
3398
|
+
request.type,
|
|
3399
|
+
mergeArtifactProtection(data, artifact),
|
|
3400
|
+
"name"
|
|
3401
|
+
);
|
|
3221
3402
|
}
|
|
3222
3403
|
}
|
|
3223
3404
|
items = Array.from(byName.values());
|
|
@@ -3309,7 +3490,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3309
3490
|
items.map((it) => {
|
|
3310
3491
|
const a = this.lookupArtifactItem(
|
|
3311
3492
|
request.type,
|
|
3312
|
-
it?.name
|
|
3493
|
+
it?.name,
|
|
3494
|
+
packageId ?? it?._packageId
|
|
3313
3495
|
);
|
|
3314
3496
|
return mergeArtifactProtection(it, a);
|
|
3315
3497
|
})
|
|
@@ -3323,16 +3505,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3323
3505
|
if (request.previewDrafts && readState !== "draft") {
|
|
3324
3506
|
try {
|
|
3325
3507
|
const findDraft = async (oid) => {
|
|
3326
|
-
const
|
|
3327
|
-
|
|
3328
|
-
|
|
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);
|
|
3329
3527
|
if (rec) return rec;
|
|
3330
3528
|
const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
|
|
3331
|
-
if (alt)
|
|
3332
|
-
return await this.engine.findOne("sys_metadata", {
|
|
3333
|
-
where: { type: alt, name: request.name, state: "draft", organization_id: oid }
|
|
3334
|
-
});
|
|
3335
|
-
}
|
|
3529
|
+
if (alt) return await lookup(alt);
|
|
3336
3530
|
return void 0;
|
|
3337
3531
|
};
|
|
3338
3532
|
const draftRec = (orgId ? await findDraft(orgId) : void 0) ?? await findDraft(null);
|
|
@@ -3350,24 +3544,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3350
3544
|
}
|
|
3351
3545
|
try {
|
|
3352
3546
|
const findOverlay = async (oid) => {
|
|
3353
|
-
const
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
state: readState,
|
|
3357
|
-
organization_id: oid
|
|
3358
|
-
};
|
|
3359
|
-
const rec = await this.engine.findOne("sys_metadata", { where });
|
|
3360
|
-
if (rec) return rec;
|
|
3361
|
-
const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
|
|
3362
|
-
if (alt) {
|
|
3363
|
-
const altWhere = {
|
|
3364
|
-
type: alt,
|
|
3547
|
+
const lookup = async (t) => {
|
|
3548
|
+
const base = {
|
|
3549
|
+
type: t,
|
|
3365
3550
|
name: request.name,
|
|
3366
3551
|
state: readState,
|
|
3367
3552
|
organization_id: oid
|
|
3368
3553
|
};
|
|
3369
|
-
|
|
3370
|
-
|
|
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);
|
|
3371
3569
|
return void 0;
|
|
3372
3570
|
};
|
|
3373
3571
|
const record = (orgId ? await findOverlay(orgId) : void 0) ?? await findOverlay(null);
|
|
@@ -3396,13 +3594,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3396
3594
|
const services = this.getServicesRegistry?.();
|
|
3397
3595
|
const metadataService = services?.get("metadata");
|
|
3398
3596
|
if (metadataService && typeof metadataService.get === "function") {
|
|
3399
|
-
const fromService = await metadataService.get(request.type, request.name);
|
|
3597
|
+
const fromService = await metadataService.get(request.type, request.name, request.packageId);
|
|
3400
3598
|
if (fromService !== void 0 && fromService !== null) {
|
|
3401
3599
|
item = fromService;
|
|
3402
3600
|
} else {
|
|
3403
3601
|
const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
|
|
3404
3602
|
if (alt) {
|
|
3405
|
-
const altFromService = await metadataService.get(alt, request.name);
|
|
3603
|
+
const altFromService = await metadataService.get(alt, request.name, request.packageId);
|
|
3406
3604
|
if (altFromService !== void 0 && altFromService !== null) {
|
|
3407
3605
|
item = altFromService;
|
|
3408
3606
|
}
|
|
@@ -3413,20 +3611,44 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3413
3611
|
}
|
|
3414
3612
|
}
|
|
3415
3613
|
if (item === void 0) {
|
|
3416
|
-
item = this.engine.registry.getItem(request.type, request.name);
|
|
3614
|
+
item = this.engine.registry.getItem(request.type, request.name, request.packageId);
|
|
3417
3615
|
if (item === void 0) {
|
|
3418
3616
|
const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
|
|
3419
|
-
if (alt) item = this.engine.registry.getItem(alt, request.name);
|
|
3617
|
+
if (alt) item = this.engine.registry.getItem(alt, request.name, request.packageId);
|
|
3420
3618
|
}
|
|
3421
3619
|
}
|
|
3422
3620
|
if ((request.type === "app" || request.type === "apps") && item) {
|
|
3423
3621
|
item = this.engine.registry.applyNavContributions(item);
|
|
3424
3622
|
}
|
|
3425
|
-
const artifactItem = this.lookupArtifactItem(request.type, request.name);
|
|
3426
|
-
|
|
3623
|
+
const artifactItem = this.lookupArtifactItem(request.type, request.name, request.packageId);
|
|
3624
|
+
let decorated = decorateMetadataItem(
|
|
3427
3625
|
request.type,
|
|
3428
3626
|
mergeArtifactProtection(item, artifactItem)
|
|
3429
3627
|
);
|
|
3628
|
+
if ((request.type === "view" || request.type === "views") && decorated && typeof decorated === "object") {
|
|
3629
|
+
try {
|
|
3630
|
+
const viewDoc = decorated;
|
|
3631
|
+
const sourceObject = viewDoc?.object ?? viewDoc?.data?.object ?? viewDoc?.objectName ?? viewDoc?.list?.data?.object;
|
|
3632
|
+
const objectDef = typeof sourceObject === "string" ? this.engine.registry.getObject(sourceObject) : void 0;
|
|
3633
|
+
if (objectDef) {
|
|
3634
|
+
const refs = computeViewReferenceDiagnostics(viewDoc, objectDef);
|
|
3635
|
+
if (!refs.valid) {
|
|
3636
|
+
const prior = viewDoc._diagnostics;
|
|
3637
|
+
decorated = {
|
|
3638
|
+
...viewDoc,
|
|
3639
|
+
_diagnostics: {
|
|
3640
|
+
valid: false,
|
|
3641
|
+
errors: [
|
|
3642
|
+
...prior && prior.valid === false && Array.isArray(prior.errors) ? prior.errors : [],
|
|
3643
|
+
...refs.errors ?? []
|
|
3644
|
+
]
|
|
3645
|
+
}
|
|
3646
|
+
};
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
} catch {
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3430
3652
|
const artifactBacked = this.isArtifactBacked(request.type, request.name);
|
|
3431
3653
|
const lockState = (0, import_kernel5.resolveLockState)(decorated, artifactBacked);
|
|
3432
3654
|
return {
|
|
@@ -3466,20 +3688,20 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3466
3688
|
const services = this.getServicesRegistry?.();
|
|
3467
3689
|
const metadataService = services?.get("metadata");
|
|
3468
3690
|
if (metadataService && typeof metadataService.get === "function") {
|
|
3469
|
-
let fromService = await metadataService.get(request.type, request.name);
|
|
3691
|
+
let fromService = await metadataService.get(request.type, request.name, request.packageId);
|
|
3470
3692
|
if (fromService === void 0 || fromService === null) {
|
|
3471
3693
|
const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
|
|
3472
|
-
if (alt) fromService = await metadataService.get(alt, request.name);
|
|
3694
|
+
if (alt) fromService = await metadataService.get(alt, request.name, request.packageId);
|
|
3473
3695
|
}
|
|
3474
3696
|
if (fromService !== void 0 && fromService !== null) code = fromService;
|
|
3475
3697
|
}
|
|
3476
3698
|
} catch {
|
|
3477
3699
|
}
|
|
3478
3700
|
if (code === null) {
|
|
3479
|
-
let regItem = 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);
|
|
3480
3702
|
if (regItem === void 0) {
|
|
3481
3703
|
const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
|
|
3482
|
-
if (alt) regItem = this.engine.registry.getItem(alt, request.name);
|
|
3704
|
+
if (alt) regItem = this.engine.registry.getItem(alt, request.name, request.packageId);
|
|
3483
3705
|
}
|
|
3484
3706
|
if (regItem !== void 0) code = regItem;
|
|
3485
3707
|
}
|
|
@@ -3487,20 +3709,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3487
3709
|
let overlayScope = null;
|
|
3488
3710
|
try {
|
|
3489
3711
|
const findOverlay = async (oid) => {
|
|
3490
|
-
const
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
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 });
|
|
3495
3729
|
};
|
|
3496
|
-
let rec = await
|
|
3730
|
+
let rec = await lookup(request.type);
|
|
3497
3731
|
if (!rec) {
|
|
3498
3732
|
const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
|
|
3499
|
-
if (alt)
|
|
3500
|
-
rec = await this.engine.findOne("sys_metadata", {
|
|
3501
|
-
where: { ...where, type: alt }
|
|
3502
|
-
});
|
|
3503
|
-
}
|
|
3733
|
+
if (alt) rec = await lookup(alt);
|
|
3504
3734
|
}
|
|
3505
3735
|
return rec;
|
|
3506
3736
|
};
|
|
@@ -4522,14 +4752,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4522
4752
|
* "authoring a DB-only item" (requires only `allowRuntimeCreate`).
|
|
4523
4753
|
*/
|
|
4524
4754
|
isArtifactBacked(type, name) {
|
|
4525
|
-
|
|
4526
|
-
if (!registry || typeof registry.getItem !== "function") {
|
|
4527
|
-
return false;
|
|
4528
|
-
}
|
|
4529
|
-
const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
|
|
4530
|
-
const item = registry.getItem(singular, name) ?? registry.getItem(type, name);
|
|
4531
|
-
if (!item || !item._packageId) return false;
|
|
4532
|
-
return item._packageId !== "sys_metadata";
|
|
4755
|
+
return this.lookupArtifactItem(type, name) !== void 0;
|
|
4533
4756
|
}
|
|
4534
4757
|
// ───────────────────────────────────────────────────────────────────
|
|
4535
4758
|
// ADR-0010 — metadata protection (Phase 1: L3 item-level lock)
|
|
@@ -4539,11 +4762,19 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4539
4762
|
* type and its singular/plural twin. Returns `undefined` when the
|
|
4540
4763
|
* registry is unavailable or the item is not artifact-backed.
|
|
4541
4764
|
*/
|
|
4542
|
-
lookupArtifactItem(type, name) {
|
|
4765
|
+
lookupArtifactItem(type, name, currentPackageId) {
|
|
4543
4766
|
const registry = this.engine?.registry;
|
|
4544
|
-
if (!registry
|
|
4767
|
+
if (!registry) return void 0;
|
|
4545
4768
|
const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
|
|
4546
|
-
|
|
4769
|
+
if (typeof registry.getArtifactItem === "function") {
|
|
4770
|
+
return registry.getArtifactItem(singular, name, currentPackageId) ?? registry.getArtifactItem(type, name, currentPackageId);
|
|
4771
|
+
}
|
|
4772
|
+
if (typeof registry.getItem !== "function") return void 0;
|
|
4773
|
+
const item = registry.getItem(singular, name, currentPackageId) ?? registry.getItem(type, name, currentPackageId);
|
|
4774
|
+
if (!item || !item._packageId || item._packageId === "sys_metadata") {
|
|
4775
|
+
return void 0;
|
|
4776
|
+
}
|
|
4777
|
+
return item;
|
|
4547
4778
|
}
|
|
4548
4779
|
/**
|
|
4549
4780
|
* Resolve the effective `_lock` for an item by consulting the
|
|
@@ -4557,13 +4788,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4557
4788
|
* scope and the caller is expected to also gate on `environmentId`.
|
|
4558
4789
|
*/
|
|
4559
4790
|
async getEffectiveLock(type, name, organizationId) {
|
|
4560
|
-
const
|
|
4561
|
-
|
|
4562
|
-
let artifactItem;
|
|
4563
|
-
if (registry && typeof registry.getItem === "function") {
|
|
4564
|
-
artifactItem = registry.getItem(singular, name) ?? registry.getItem(type, name);
|
|
4565
|
-
}
|
|
4566
|
-
if (artifactItem && artifactItem._packageId && artifactItem._packageId !== "sys_metadata") {
|
|
4791
|
+
const artifactItem = this.lookupArtifactItem(type, name);
|
|
4792
|
+
if (artifactItem) {
|
|
4567
4793
|
const p = (0, import_kernel5.extractProtection)(artifactItem);
|
|
4568
4794
|
if (p.lock !== "none") {
|
|
4569
4795
|
return { lock: p.lock, lockReason: p.lockReason, lockSource: "artifact" };
|
|
@@ -4704,6 +4930,49 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4704
4930
|
);
|
|
4705
4931
|
}
|
|
4706
4932
|
}
|
|
4933
|
+
/**
|
|
4934
|
+
* Heal the in-memory registry after a metadata reset (overlay-row
|
|
4935
|
+
* delete) on control-plane kernels. Two layers:
|
|
4936
|
+
*
|
|
4937
|
+
* 1. Drop the plain-key runtime shadow so the packaged artifact
|
|
4938
|
+
* (registered under `<packageId>:<name>`) becomes the visible
|
|
4939
|
+
* value again. The shadow is written by the overlay-hydration
|
|
4940
|
+
* paths (`getMetaItems` / `loadMetaFromDb`) and — pre-fix —
|
|
4941
|
+
* survived the reset until restart, leaving stale overlay
|
|
4942
|
+
* content (and a stripped `_lock` envelope) in every
|
|
4943
|
+
* registry-direct read (ADR-0010 §3.3).
|
|
4944
|
+
* 2. When no composite-key artifact exists, fall back to the
|
|
4945
|
+
* MetadataService baseline (FilesystemLoader-sourced types) and
|
|
4946
|
+
* re-register it, preserving the historical refresh behaviour
|
|
4947
|
+
* for items the SchemaRegistry never held as artifacts.
|
|
4948
|
+
*
|
|
4949
|
+
* Best-effort: a failure must never block the delete that already
|
|
4950
|
+
* succeeded; the next full reload fixes the registry anyway.
|
|
4951
|
+
*/
|
|
4952
|
+
async restoreArtifactRegistryView(type, name) {
|
|
4953
|
+
try {
|
|
4954
|
+
const registry = this.engine.registry;
|
|
4955
|
+
let healed = false;
|
|
4956
|
+
if (typeof registry.removeRuntimeShadow === "function") {
|
|
4957
|
+
const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
|
|
4958
|
+
healed = registry.removeRuntimeShadow(singular, name);
|
|
4959
|
+
if (type !== singular) {
|
|
4960
|
+
healed = registry.removeRuntimeShadow(type, name) || healed;
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
if (healed) return;
|
|
4964
|
+
if (this.environmentId !== void 0) return;
|
|
4965
|
+
const services = this.getServicesRegistry?.();
|
|
4966
|
+
const metadataService = services?.get("metadata");
|
|
4967
|
+
if (metadataService && typeof metadataService.get === "function") {
|
|
4968
|
+
const artifactItem = await metadataService.get(type, name);
|
|
4969
|
+
if (artifactItem !== void 0) {
|
|
4970
|
+
this.engine.registry.registerItem(type, artifactItem, "name");
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
} catch {
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4707
4976
|
/**
|
|
4708
4977
|
* Ensure a just-PUBLISHED object's physical table exists so it is usable
|
|
4709
4978
|
* for data CRUD immediately — without a server restart. Registering the
|
|
@@ -4867,7 +5136,10 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4867
5136
|
if (request.parentVersion !== void 0) {
|
|
4868
5137
|
parentVersion = request.parentVersion;
|
|
4869
5138
|
} else {
|
|
4870
|
-
const current = await repo.get(ref, {
|
|
5139
|
+
const current = await repo.get(ref, {
|
|
5140
|
+
state: mode === "draft" ? "draft" : "active",
|
|
5141
|
+
packageId: request.packageId ?? null
|
|
5142
|
+
});
|
|
4871
5143
|
parentVersion = current?.hash ?? null;
|
|
4872
5144
|
}
|
|
4873
5145
|
try {
|
|
@@ -5525,6 +5797,9 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5525
5797
|
const targetState = request.state === "draft" ? "draft" : "active";
|
|
5526
5798
|
const current = await repo.get(ref, { state: targetState });
|
|
5527
5799
|
if (!current) {
|
|
5800
|
+
if (targetState === "active") {
|
|
5801
|
+
await this.restoreArtifactRegistryView(request.type, request.name);
|
|
5802
|
+
}
|
|
5528
5803
|
return {
|
|
5529
5804
|
success: true,
|
|
5530
5805
|
reset: false,
|
|
@@ -5539,18 +5814,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5539
5814
|
intent: this.isArtifactBacked(singularTypeForRepo, request.name) ? "override-artifact" : "runtime-only",
|
|
5540
5815
|
state: targetState
|
|
5541
5816
|
});
|
|
5542
|
-
if (
|
|
5543
|
-
|
|
5544
|
-
const services = this.getServicesRegistry?.();
|
|
5545
|
-
const metadataService = services?.get("metadata");
|
|
5546
|
-
if (metadataService && typeof metadataService.get === "function") {
|
|
5547
|
-
const artifactItem = await metadataService.get(request.type, request.name);
|
|
5548
|
-
if (artifactItem !== void 0) {
|
|
5549
|
-
this.engine.registry.registerItem(request.type, artifactItem, "name");
|
|
5550
|
-
}
|
|
5551
|
-
}
|
|
5552
|
-
} catch {
|
|
5553
|
-
}
|
|
5817
|
+
if (targetState === "active") {
|
|
5818
|
+
await this.restoreArtifactRegistryView(request.type, request.name);
|
|
5554
5819
|
}
|
|
5555
5820
|
if (this.shouldDropStorage(request.type, request.name, request.dropStorage, targetState)) {
|
|
5556
5821
|
await this.dropObjectStorage(singularTypeForRepo, request.name);
|
|
@@ -5609,18 +5874,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5609
5874
|
await this.dropObjectStorage(import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type, request.name);
|
|
5610
5875
|
}
|
|
5611
5876
|
}
|
|
5612
|
-
if (
|
|
5613
|
-
|
|
5614
|
-
const services = this.getServicesRegistry?.();
|
|
5615
|
-
const metadataService = services?.get("metadata");
|
|
5616
|
-
if (metadataService && typeof metadataService.get === "function") {
|
|
5617
|
-
const artifactItem = await metadataService.get(request.type, request.name);
|
|
5618
|
-
if (artifactItem !== void 0) {
|
|
5619
|
-
this.engine.registry.registerItem(request.type, artifactItem, "name");
|
|
5620
|
-
}
|
|
5621
|
-
}
|
|
5622
|
-
} catch {
|
|
5623
|
-
}
|
|
5877
|
+
if (request.state !== "draft") {
|
|
5878
|
+
await this.restoreArtifactRegistryView(request.type, request.name);
|
|
5624
5879
|
}
|
|
5625
5880
|
return {
|
|
5626
5881
|
success: true,
|
|
@@ -5658,7 +5913,12 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5658
5913
|
if (normalizedType === "object") {
|
|
5659
5914
|
this.engine.registry.registerObject(data, record.packageId || "sys_metadata");
|
|
5660
5915
|
} else {
|
|
5661
|
-
this.
|
|
5916
|
+
const artifact = this.lookupArtifactItem(normalizedType, data?.name);
|
|
5917
|
+
this.engine.registry.registerItem(
|
|
5918
|
+
normalizedType,
|
|
5919
|
+
mergeArtifactProtection(data, artifact),
|
|
5920
|
+
"name"
|
|
5921
|
+
);
|
|
5662
5922
|
}
|
|
5663
5923
|
loaded++;
|
|
5664
5924
|
} catch (e) {
|
|
@@ -7625,7 +7885,9 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7625
7885
|
"mappings",
|
|
7626
7886
|
"analyticsCubes",
|
|
7627
7887
|
// Integration Protocol
|
|
7628
|
-
"connectors"
|
|
7888
|
+
"connectors",
|
|
7889
|
+
// System Protocol — package documentation (ADR-0046); inert data
|
|
7890
|
+
"docs"
|
|
7629
7891
|
];
|
|
7630
7892
|
for (const key of metadataArrayKeys) {
|
|
7631
7893
|
const items = manifest[key];
|
|
@@ -7761,7 +8023,8 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7761
8023
|
"hooks",
|
|
7762
8024
|
"mappings",
|
|
7763
8025
|
"analyticsCubes",
|
|
7764
|
-
"connectors"
|
|
8026
|
+
"connectors",
|
|
8027
|
+
"docs"
|
|
7765
8028
|
];
|
|
7766
8029
|
for (const key of metadataArrayKeys) {
|
|
7767
8030
|
const items = plugin[key];
|
|
@@ -9290,17 +9553,24 @@ var MetadataFacade = class {
|
|
|
9290
9553
|
*/
|
|
9291
9554
|
async register(type, name, data) {
|
|
9292
9555
|
const definition = typeof data === "object" && data !== null ? { ...data, name: data.name ?? name } : data;
|
|
9556
|
+
const packageId = definition?._packageId;
|
|
9293
9557
|
if (type === "object") {
|
|
9294
|
-
this.registry.registerItem(type, definition, "name");
|
|
9558
|
+
this.registry.registerItem(type, definition, "name", packageId);
|
|
9295
9559
|
} else {
|
|
9296
|
-
this.registry.registerItem(type, definition, definition.id ? "id" : "name");
|
|
9560
|
+
this.registry.registerItem(type, definition, definition.id ? "id" : "name", packageId);
|
|
9297
9561
|
}
|
|
9298
9562
|
}
|
|
9299
9563
|
/**
|
|
9300
|
-
* Get a metadata item by type and name
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
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);
|
|
9304
9574
|
return item?.content ?? item;
|
|
9305
9575
|
}
|
|
9306
9576
|
/**
|
|
@@ -9374,6 +9644,7 @@ var ObjectQLPlugin = class {
|
|
|
9374
9644
|
*/
|
|
9375
9645
|
this.startupTimeout = 12e4;
|
|
9376
9646
|
this.skipSchemaSync = false;
|
|
9647
|
+
this.hydrateMetadataFromDb = false;
|
|
9377
9648
|
/** Unsubscribe handles for metadata-event subscriptions (ADR-0008 PR-7). */
|
|
9378
9649
|
this.metadataUnsubscribes = [];
|
|
9379
9650
|
this.init = async (ctx) => {
|
|
@@ -9498,7 +9769,7 @@ var ObjectQLPlugin = class {
|
|
|
9498
9769
|
} else {
|
|
9499
9770
|
await this.syncRegisteredSchemas(ctx);
|
|
9500
9771
|
}
|
|
9501
|
-
if (this.environmentId === void 0) {
|
|
9772
|
+
if (this.environmentId === void 0 || this.hydrateMetadataFromDb) {
|
|
9502
9773
|
await this.restoreMetadataFromDb(ctx);
|
|
9503
9774
|
} else {
|
|
9504
9775
|
ctx.logger.info("Project kernel \u2014 skipping sys_metadata hydration (metadata sourced from artifact)");
|
|
@@ -9540,6 +9811,7 @@ var ObjectQLPlugin = class {
|
|
|
9540
9811
|
this.startupTimeout = opts.startupTimeout;
|
|
9541
9812
|
}
|
|
9542
9813
|
this.skipSchemaSync = typeof opts.skipSchemaSync === "boolean" ? opts.skipSchemaSync : process.env.OS_SKIP_SCHEMA_SYNC === "1";
|
|
9814
|
+
this.hydrateMetadataFromDb = opts.hydrateMetadataFromDb === true;
|
|
9543
9815
|
}
|
|
9544
9816
|
/**
|
|
9545
9817
|
* Subscribe to `object` metadata events from the metadata service and
|
|
@@ -9962,7 +10234,7 @@ var ObjectQLPlugin = class {
|
|
|
9962
10234
|
return;
|
|
9963
10235
|
}
|
|
9964
10236
|
if (this.ql?.registry?.registerItem) {
|
|
9965
|
-
this.ql.registry.registerItem(type, item, keyField);
|
|
10237
|
+
this.ql.registry.registerItem(type, item, keyField, item._packageId);
|
|
9966
10238
|
}
|
|
9967
10239
|
});
|
|
9968
10240
|
if (type === "hook" && this.ql && typeof this.ql.bindHooks === "function") {
|