@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.mjs
CHANGED
|
@@ -310,6 +310,19 @@ var init_seed_loader = __esm({
|
|
|
310
310
|
if (records && records.length > 0) {
|
|
311
311
|
return String(records[0].id || records[0]._id);
|
|
312
312
|
}
|
|
313
|
+
if (targetField !== "id") {
|
|
314
|
+
const byId = { id: value };
|
|
315
|
+
if (organizationId) byId.organization_id = organizationId;
|
|
316
|
+
const idMatch = await this.engine.find(targetObject, {
|
|
317
|
+
where: byId,
|
|
318
|
+
fields: ["id"],
|
|
319
|
+
limit: 1,
|
|
320
|
+
context: { isSystem: true }
|
|
321
|
+
});
|
|
322
|
+
if (idMatch && idMatch.length > 0) {
|
|
323
|
+
return String(idMatch[0].id || idMatch[0]._id);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
313
326
|
} catch {
|
|
314
327
|
}
|
|
315
328
|
return null;
|
|
@@ -886,6 +899,20 @@ function applySystemFields(schema, opts) {
|
|
|
886
899
|
fields: { ...additions, ...schema.fields ?? {} }
|
|
887
900
|
};
|
|
888
901
|
}
|
|
902
|
+
function isShareableNamespace(ns) {
|
|
903
|
+
return RESERVED_NAMESPACES.has(ns) || ns === "sys";
|
|
904
|
+
}
|
|
905
|
+
var NamespaceConflictError = class extends Error {
|
|
906
|
+
constructor(namespace, existingPackageId, incomingPackageId) {
|
|
907
|
+
super(
|
|
908
|
+
`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.`
|
|
909
|
+
);
|
|
910
|
+
this.name = "NamespaceConflictError";
|
|
911
|
+
this.namespace = namespace;
|
|
912
|
+
this.existingPackageId = existingPackageId;
|
|
913
|
+
this.incomingPackageId = incomingPackageId;
|
|
914
|
+
}
|
|
915
|
+
};
|
|
889
916
|
var SchemaRegistry = class {
|
|
890
917
|
constructor(options = {}) {
|
|
891
918
|
// ==========================================
|
|
@@ -929,6 +956,7 @@ var SchemaRegistry = class {
|
|
|
929
956
|
} else {
|
|
930
957
|
this.multiTenant = String(readEnvWithDeprecation("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
|
|
931
958
|
}
|
|
959
|
+
this.collisionPolicy = options.collisionPolicy ?? ((process.env.OS_METADATA_COLLISION ?? "").toLowerCase() === "warn" ? "warn" : "error");
|
|
932
960
|
}
|
|
933
961
|
get logLevel() {
|
|
934
962
|
return this._logLevel;
|
|
@@ -1289,9 +1317,23 @@ var SchemaRegistry = class {
|
|
|
1289
1317
|
console.warn(`[Registry] Attempted to unregister non-existent ${type}: ${name}`);
|
|
1290
1318
|
}
|
|
1291
1319
|
/**
|
|
1292
|
-
* Universal Get Method
|
|
1320
|
+
* Universal Get Method.
|
|
1321
|
+
*
|
|
1322
|
+
* ADR-0048 §3.3 — *package-scoped* resolution. When `currentPackageId` is
|
|
1323
|
+
* given (the package the caller is resolving within — known from the route /
|
|
1324
|
+
* `activeApp._packageId`), a bare name resolves to *that package's* item
|
|
1325
|
+
* before any cross-package fallback, so two packages shipping e.g.
|
|
1326
|
+
* `page/home` no longer resolve by registration order (first-match-wins).
|
|
1327
|
+
* Because package ids are globally unique this is unambiguous. Omitting
|
|
1328
|
+
* `currentPackageId` preserves the legacy resolution exactly (backward
|
|
1329
|
+
* compatible) and is best-effort: it returns the first match.
|
|
1330
|
+
*
|
|
1331
|
+
* Precedence (highest first):
|
|
1332
|
+
* 1. bare-key runtime/DB overlay (ADR-0005 sanctioned override) — unchanged
|
|
1333
|
+
* 2. the `currentPackageId` composite entry (prefer-local)
|
|
1334
|
+
* 3. first composite match (legacy first-registered-wins fallback)
|
|
1293
1335
|
*/
|
|
1294
|
-
getItem(type, name) {
|
|
1336
|
+
getItem(type, name, currentPackageId) {
|
|
1295
1337
|
if (type === "object" || type === "objects") {
|
|
1296
1338
|
return this.getObject(name);
|
|
1297
1339
|
}
|
|
@@ -1299,6 +1341,10 @@ var SchemaRegistry = class {
|
|
|
1299
1341
|
if (!collection) return void 0;
|
|
1300
1342
|
const direct = collection.get(name);
|
|
1301
1343
|
if (direct) return direct;
|
|
1344
|
+
if (currentPackageId) {
|
|
1345
|
+
const local = collection.get(`${currentPackageId}:${name}`);
|
|
1346
|
+
if (local) return local;
|
|
1347
|
+
}
|
|
1302
1348
|
for (const [key, item] of collection) {
|
|
1303
1349
|
if (key.endsWith(`:${name}`)) {
|
|
1304
1350
|
return item;
|
|
@@ -1306,6 +1352,74 @@ var SchemaRegistry = class {
|
|
|
1306
1352
|
}
|
|
1307
1353
|
return void 0;
|
|
1308
1354
|
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Artifact-only lookup (ADR-0010 §3.3). Unlike {@link getItem} — which
|
|
1357
|
+
* returns the plain-key entry first, so a runtime/DB-rehydrated row
|
|
1358
|
+
* registered under the bare name SHADOWS the packaged artifact — this
|
|
1359
|
+
* scans the composite (`<packageId>:<name>`) entries first and only
|
|
1360
|
+
* returns an item whose `_packageId` marks a genuine code package
|
|
1361
|
+
* (truthy and not the `'sys_metadata'` rehydration sentinel).
|
|
1362
|
+
*
|
|
1363
|
+
* This is what the protocol's lock/provenance resolution must use:
|
|
1364
|
+
* the artifact's `_lock` envelope always wins over an overlay, and an
|
|
1365
|
+
* overlay row hydrated into the plain key must never be able to mask
|
|
1366
|
+
* it (that masking is exactly the "registry pollution" bug where a
|
|
1367
|
+
* locked app's `_lock` read back as undefined after a PUT+GET).
|
|
1368
|
+
*/
|
|
1369
|
+
getArtifactItem(type, name, currentPackageId) {
|
|
1370
|
+
if (type === "object" || type === "objects") {
|
|
1371
|
+
const obj = this.getObject(name);
|
|
1372
|
+
return obj && obj._packageId && obj._packageId !== "sys_metadata" ? obj : void 0;
|
|
1373
|
+
}
|
|
1374
|
+
const collection = this.metadata.get(type);
|
|
1375
|
+
if (!collection) return void 0;
|
|
1376
|
+
if (currentPackageId) {
|
|
1377
|
+
const local = collection.get(`${currentPackageId}:${name}`);
|
|
1378
|
+
if (local && local._packageId && local._packageId !== "sys_metadata") return local;
|
|
1379
|
+
}
|
|
1380
|
+
for (const [key, item] of collection) {
|
|
1381
|
+
if (key !== name && key.endsWith(`:${name}`)) {
|
|
1382
|
+
const it = item;
|
|
1383
|
+
if (it && it._packageId && it._packageId !== "sys_metadata") return item;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
const direct = collection.get(name);
|
|
1387
|
+
if (direct && direct._packageId && direct._packageId !== "sys_metadata") {
|
|
1388
|
+
return direct;
|
|
1389
|
+
}
|
|
1390
|
+
return void 0;
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Remove a plain-key runtime shadow so the packaged artifact registered
|
|
1394
|
+
* under a composite key becomes the visible value again. Used by the
|
|
1395
|
+
* metadata reset path (`deleteMetaItem`): deleting the `sys_metadata`
|
|
1396
|
+
* overlay row must also heal the in-memory registry, otherwise the
|
|
1397
|
+
* stale overlay copy keeps shadowing the artifact until restart.
|
|
1398
|
+
*
|
|
1399
|
+
* Deliberately conservative: the plain-key entry is only deleted when a
|
|
1400
|
+
* packaged artifact still exists under a composite key, so the name
|
|
1401
|
+
* stays resolvable afterwards. A runtime-only item (no artifact
|
|
1402
|
+
* backing) is left untouched. Note the plain entry's own `_packageId`
|
|
1403
|
+
* is NOT consulted — the hydration path grafts the artifact envelope
|
|
1404
|
+
* onto the shadow (ADR-0010 §3.3), so a stamped `_packageId` does not
|
|
1405
|
+
* mean the plain entry IS the artifact registration; artifact loaders
|
|
1406
|
+
* always register under a composite key.
|
|
1407
|
+
*/
|
|
1408
|
+
removeRuntimeShadow(type, name) {
|
|
1409
|
+
const collection = this.metadata.get(type);
|
|
1410
|
+
if (!collection || !collection.has(name)) return false;
|
|
1411
|
+
for (const [key, item] of collection) {
|
|
1412
|
+
if (key !== name && key.endsWith(`:${name}`)) {
|
|
1413
|
+
const it = item;
|
|
1414
|
+
if (it && it._packageId && it._packageId !== "sys_metadata") {
|
|
1415
|
+
collection.delete(name);
|
|
1416
|
+
this.log(`[Registry] Removed runtime shadow ${type}: ${name} (artifact ${it._packageId} restored)`);
|
|
1417
|
+
return true;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return false;
|
|
1422
|
+
}
|
|
1309
1423
|
/**
|
|
1310
1424
|
* Universal List Method
|
|
1311
1425
|
*/
|
|
@@ -1346,6 +1460,20 @@ var SchemaRegistry = class {
|
|
|
1346
1460
|
// Package Management
|
|
1347
1461
|
// ==========================================
|
|
1348
1462
|
installPackage(manifest, settings) {
|
|
1463
|
+
if (manifest.namespace && !isShareableNamespace(manifest.namespace)) {
|
|
1464
|
+
const conflictOwner = this.getNamespaceOwners(manifest.namespace).find(
|
|
1465
|
+
(owner) => owner !== manifest.id
|
|
1466
|
+
);
|
|
1467
|
+
if (conflictOwner) {
|
|
1468
|
+
if (this.collisionPolicy === "warn") {
|
|
1469
|
+
console.warn(
|
|
1470
|
+
`[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.`
|
|
1471
|
+
);
|
|
1472
|
+
} else {
|
|
1473
|
+
throw new NamespaceConflictError(manifest.namespace, conflictOwner, manifest.id);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1349
1477
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1350
1478
|
const disabled = this.initialDisabledPackageIds.has(manifest.id);
|
|
1351
1479
|
const pkg = {
|
|
@@ -1423,8 +1551,8 @@ var SchemaRegistry = class {
|
|
|
1423
1551
|
registerApp(app, packageId) {
|
|
1424
1552
|
this.registerItem("app", app, "name", packageId);
|
|
1425
1553
|
}
|
|
1426
|
-
getApp(name) {
|
|
1427
|
-
const app = this.getItem("app", name);
|
|
1554
|
+
getApp(name, currentPackageId) {
|
|
1555
|
+
const app = this.getItem("app", name, currentPackageId);
|
|
1428
1556
|
if (!app) return app;
|
|
1429
1557
|
return this.applyNavContributions(app);
|
|
1430
1558
|
}
|
|
@@ -1644,7 +1772,7 @@ var SysMetadataRepository = class {
|
|
|
1644
1772
|
this.assertOpen();
|
|
1645
1773
|
const state = opts?.state ?? "active";
|
|
1646
1774
|
const row = await this.engine.findOne("sys_metadata", {
|
|
1647
|
-
where: this.whereFor(ref, state)
|
|
1775
|
+
where: this.whereFor(ref, state, opts && "packageId" in opts ? opts.packageId ?? null : void 0)
|
|
1648
1776
|
});
|
|
1649
1777
|
if (!row) return null;
|
|
1650
1778
|
return this.rowToItem(ref, row);
|
|
@@ -1693,7 +1821,7 @@ var SysMetadataRepository = class {
|
|
|
1693
1821
|
const hash = hashSpec(body);
|
|
1694
1822
|
const result = await this.withTxn(async (ctx) => {
|
|
1695
1823
|
const existing = await this.engine.findOne("sys_metadata", {
|
|
1696
|
-
where: this.whereFor(ref, state),
|
|
1824
|
+
where: this.whereFor(ref, state, opts.packageId ?? null),
|
|
1697
1825
|
context: ctx
|
|
1698
1826
|
});
|
|
1699
1827
|
const existingHash = existing?.checksum ?? null;
|
|
@@ -2177,13 +2305,15 @@ var SysMetadataRepository = class {
|
|
|
2177
2305
|
err.status = 403;
|
|
2178
2306
|
throw err;
|
|
2179
2307
|
}
|
|
2180
|
-
whereFor(ref, state = "active") {
|
|
2181
|
-
|
|
2308
|
+
whereFor(ref, state = "active", packageId) {
|
|
2309
|
+
const where = {
|
|
2182
2310
|
type: ref.type,
|
|
2183
2311
|
name: ref.name,
|
|
2184
2312
|
organization_id: this.organizationId,
|
|
2185
2313
|
state
|
|
2186
2314
|
};
|
|
2315
|
+
if (packageId !== void 0) where.package_id = packageId;
|
|
2316
|
+
return where;
|
|
2187
2317
|
}
|
|
2188
2318
|
fullRef(ref) {
|
|
2189
2319
|
return {
|
|
@@ -2335,6 +2465,48 @@ function decorateMetadataItems(type, items) {
|
|
|
2335
2465
|
if (!Array.isArray(items)) return items;
|
|
2336
2466
|
return items.map((item) => decorateMetadataItem(type, item));
|
|
2337
2467
|
}
|
|
2468
|
+
function fieldMap(objectDef) {
|
|
2469
|
+
const map = /* @__PURE__ */ new Map();
|
|
2470
|
+
const fields = objectDef?.fields;
|
|
2471
|
+
if (Array.isArray(fields)) {
|
|
2472
|
+
for (const f of fields) if (f?.name) map.set(f.name, f);
|
|
2473
|
+
} else if (fields && typeof fields === "object") {
|
|
2474
|
+
for (const [name, f] of Object.entries(fields)) map.set(name, f ?? {});
|
|
2475
|
+
}
|
|
2476
|
+
return map;
|
|
2477
|
+
}
|
|
2478
|
+
function computeViewReferenceDiagnostics(view, objectDef) {
|
|
2479
|
+
const fields = fieldMap(objectDef);
|
|
2480
|
+
const errors = [];
|
|
2481
|
+
const requireField = (name, path) => {
|
|
2482
|
+
if (typeof name !== "string" || !name) return;
|
|
2483
|
+
if (!fields.has(name)) {
|
|
2484
|
+
errors.push({
|
|
2485
|
+
path,
|
|
2486
|
+
message: `Field "${name}" does not exist on the source object`,
|
|
2487
|
+
code: "reference_not_found"
|
|
2488
|
+
});
|
|
2489
|
+
}
|
|
2490
|
+
};
|
|
2491
|
+
const userFilters = view?.userFilters;
|
|
2492
|
+
userFilters?.fields?.forEach((f, i) => requireField(f?.field, `userFilters.fields.${i}.field`));
|
|
2493
|
+
userFilters?.tabs?.forEach((t, i) => t?.filter?.forEach((r, j) => requireField(r?.field, `userFilters.tabs.${i}.filter.${j}.field`)));
|
|
2494
|
+
view?.tabs?.forEach((t, i) => t?.filter?.forEach((r, j) => requireField(r?.field, `tabs.${i}.filter.${j}.field`)));
|
|
2495
|
+
view?.filterableFields?.forEach((f, i) => requireField(f, `filterableFields.${i}`));
|
|
2496
|
+
const kanban = view?.kanban;
|
|
2497
|
+
if (kanban?.groupByField) {
|
|
2498
|
+
requireField(kanban.groupByField, "kanban.groupByField");
|
|
2499
|
+
const def = fields.get(kanban.groupByField);
|
|
2500
|
+
if (def && def.type && !["select", "multi-select", "boolean", "lookup", "master_detail"].includes(def.type)) {
|
|
2501
|
+
errors.push({
|
|
2502
|
+
path: "kanban.groupByField",
|
|
2503
|
+
message: `Field "${kanban.groupByField}" (type "${def.type}") cannot group a kanban \u2014 use a select-like field`,
|
|
2504
|
+
code: "invalid_binding"
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
return errors.length ? { valid: false, errors } : { valid: true };
|
|
2509
|
+
}
|
|
2338
2510
|
|
|
2339
2511
|
// src/protocol.ts
|
|
2340
2512
|
var TYPE_TO_FORM = METADATA_FORM_REGISTRY;
|
|
@@ -2833,8 +3005,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2833
3005
|
await exec("DROP INDEX IF EXISTS idx_sys_metadata_overlay_active");
|
|
2834
3006
|
} catch {
|
|
2835
3007
|
}
|
|
2836
|
-
const partialSql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id) WHERE state = 'active'";
|
|
2837
|
-
const fallbackSql = "CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id)";
|
|
3008
|
+
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'";
|
|
3009
|
+
const fallbackSql = "CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id, package_id)";
|
|
2838
3010
|
try {
|
|
2839
3011
|
await exec(partialSql);
|
|
2840
3012
|
} catch (err) {
|
|
@@ -2846,7 +3018,11 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2846
3018
|
}
|
|
2847
3019
|
}
|
|
2848
3020
|
}
|
|
2849
|
-
|
|
3021
|
+
try {
|
|
3022
|
+
await exec("DROP INDEX IF EXISTS idx_sys_metadata_overlay_draft");
|
|
3023
|
+
} catch {
|
|
3024
|
+
}
|
|
3025
|
+
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'";
|
|
2850
3026
|
try {
|
|
2851
3027
|
await exec(draftPartialSql);
|
|
2852
3028
|
} catch (err) {
|
|
@@ -2854,7 +3030,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
2854
3030
|
if (/partial|where clause|syntax/i.test(msg)) {
|
|
2855
3031
|
try {
|
|
2856
3032
|
await exec(
|
|
2857
|
-
"CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_draft ON sys_metadata (type, name, organization_id)"
|
|
3033
|
+
"CREATE INDEX IF NOT EXISTS idx_sys_metadata_overlay_draft ON sys_metadata (type, name, organization_id, package_id)"
|
|
2858
3034
|
);
|
|
2859
3035
|
} catch {
|
|
2860
3036
|
}
|
|
@@ -3157,8 +3333,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3157
3333
|
}
|
|
3158
3334
|
byName.set(data.name, data);
|
|
3159
3335
|
}
|
|
3160
|
-
if (this.environmentId === void 0) {
|
|
3161
|
-
this.
|
|
3336
|
+
if (this.environmentId === void 0 && data && typeof data === "object") {
|
|
3337
|
+
const artifact = this.lookupArtifactItem(request.type, data.name);
|
|
3338
|
+
this.engine.registry.registerItem(
|
|
3339
|
+
request.type,
|
|
3340
|
+
mergeArtifactProtection(data, artifact),
|
|
3341
|
+
"name"
|
|
3342
|
+
);
|
|
3162
3343
|
}
|
|
3163
3344
|
}
|
|
3164
3345
|
items = Array.from(byName.values());
|
|
@@ -3250,7 +3431,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3250
3431
|
items.map((it) => {
|
|
3251
3432
|
const a = this.lookupArtifactItem(
|
|
3252
3433
|
request.type,
|
|
3253
|
-
it?.name
|
|
3434
|
+
it?.name,
|
|
3435
|
+
packageId ?? it?._packageId
|
|
3254
3436
|
);
|
|
3255
3437
|
return mergeArtifactProtection(it, a);
|
|
3256
3438
|
})
|
|
@@ -3264,16 +3446,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3264
3446
|
if (request.previewDrafts && readState !== "draft") {
|
|
3265
3447
|
try {
|
|
3266
3448
|
const findDraft = async (oid) => {
|
|
3267
|
-
const
|
|
3268
|
-
|
|
3269
|
-
|
|
3449
|
+
const lookup = async (t) => {
|
|
3450
|
+
const base = {
|
|
3451
|
+
type: t,
|
|
3452
|
+
name: request.name,
|
|
3453
|
+
state: "draft",
|
|
3454
|
+
organization_id: oid
|
|
3455
|
+
};
|
|
3456
|
+
if (request.packageId) {
|
|
3457
|
+
const scoped = await this.engine.findOne("sys_metadata", {
|
|
3458
|
+
where: { ...base, package_id: request.packageId }
|
|
3459
|
+
});
|
|
3460
|
+
if (scoped) return scoped;
|
|
3461
|
+
return await this.engine.findOne("sys_metadata", {
|
|
3462
|
+
where: { ...base, package_id: null }
|
|
3463
|
+
});
|
|
3464
|
+
}
|
|
3465
|
+
return await this.engine.findOne("sys_metadata", { where: base });
|
|
3466
|
+
};
|
|
3467
|
+
const rec = await lookup(request.type);
|
|
3270
3468
|
if (rec) return rec;
|
|
3271
3469
|
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3272
|
-
if (alt)
|
|
3273
|
-
return await this.engine.findOne("sys_metadata", {
|
|
3274
|
-
where: { type: alt, name: request.name, state: "draft", organization_id: oid }
|
|
3275
|
-
});
|
|
3276
|
-
}
|
|
3470
|
+
if (alt) return await lookup(alt);
|
|
3277
3471
|
return void 0;
|
|
3278
3472
|
};
|
|
3279
3473
|
const draftRec = (orgId ? await findDraft(orgId) : void 0) ?? await findDraft(null);
|
|
@@ -3291,24 +3485,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3291
3485
|
}
|
|
3292
3486
|
try {
|
|
3293
3487
|
const findOverlay = async (oid) => {
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
state: readState,
|
|
3298
|
-
organization_id: oid
|
|
3299
|
-
};
|
|
3300
|
-
const rec = await this.engine.findOne("sys_metadata", { where });
|
|
3301
|
-
if (rec) return rec;
|
|
3302
|
-
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3303
|
-
if (alt) {
|
|
3304
|
-
const altWhere = {
|
|
3305
|
-
type: alt,
|
|
3488
|
+
const lookup = async (t) => {
|
|
3489
|
+
const base = {
|
|
3490
|
+
type: t,
|
|
3306
3491
|
name: request.name,
|
|
3307
3492
|
state: readState,
|
|
3308
3493
|
organization_id: oid
|
|
3309
3494
|
};
|
|
3310
|
-
|
|
3311
|
-
|
|
3495
|
+
if (request.packageId) {
|
|
3496
|
+
const scoped = await this.engine.findOne("sys_metadata", {
|
|
3497
|
+
where: { ...base, package_id: request.packageId }
|
|
3498
|
+
});
|
|
3499
|
+
if (scoped) return scoped;
|
|
3500
|
+
return await this.engine.findOne("sys_metadata", {
|
|
3501
|
+
where: { ...base, package_id: null }
|
|
3502
|
+
});
|
|
3503
|
+
}
|
|
3504
|
+
return await this.engine.findOne("sys_metadata", { where: base });
|
|
3505
|
+
};
|
|
3506
|
+
const rec = await lookup(request.type);
|
|
3507
|
+
if (rec) return rec;
|
|
3508
|
+
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3509
|
+
if (alt) return await lookup(alt);
|
|
3312
3510
|
return void 0;
|
|
3313
3511
|
};
|
|
3314
3512
|
const record = (orgId ? await findOverlay(orgId) : void 0) ?? await findOverlay(null);
|
|
@@ -3337,13 +3535,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3337
3535
|
const services = this.getServicesRegistry?.();
|
|
3338
3536
|
const metadataService = services?.get("metadata");
|
|
3339
3537
|
if (metadataService && typeof metadataService.get === "function") {
|
|
3340
|
-
const fromService = await metadataService.get(request.type, request.name);
|
|
3538
|
+
const fromService = await metadataService.get(request.type, request.name, request.packageId);
|
|
3341
3539
|
if (fromService !== void 0 && fromService !== null) {
|
|
3342
3540
|
item = fromService;
|
|
3343
3541
|
} else {
|
|
3344
3542
|
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3345
3543
|
if (alt) {
|
|
3346
|
-
const altFromService = await metadataService.get(alt, request.name);
|
|
3544
|
+
const altFromService = await metadataService.get(alt, request.name, request.packageId);
|
|
3347
3545
|
if (altFromService !== void 0 && altFromService !== null) {
|
|
3348
3546
|
item = altFromService;
|
|
3349
3547
|
}
|
|
@@ -3354,20 +3552,44 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3354
3552
|
}
|
|
3355
3553
|
}
|
|
3356
3554
|
if (item === void 0) {
|
|
3357
|
-
item = this.engine.registry.getItem(request.type, request.name);
|
|
3555
|
+
item = this.engine.registry.getItem(request.type, request.name, request.packageId);
|
|
3358
3556
|
if (item === void 0) {
|
|
3359
3557
|
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3360
|
-
if (alt) item = this.engine.registry.getItem(alt, request.name);
|
|
3558
|
+
if (alt) item = this.engine.registry.getItem(alt, request.name, request.packageId);
|
|
3361
3559
|
}
|
|
3362
3560
|
}
|
|
3363
3561
|
if ((request.type === "app" || request.type === "apps") && item) {
|
|
3364
3562
|
item = this.engine.registry.applyNavContributions(item);
|
|
3365
3563
|
}
|
|
3366
|
-
const artifactItem = this.lookupArtifactItem(request.type, request.name);
|
|
3367
|
-
|
|
3564
|
+
const artifactItem = this.lookupArtifactItem(request.type, request.name, request.packageId);
|
|
3565
|
+
let decorated = decorateMetadataItem(
|
|
3368
3566
|
request.type,
|
|
3369
3567
|
mergeArtifactProtection(item, artifactItem)
|
|
3370
3568
|
);
|
|
3569
|
+
if ((request.type === "view" || request.type === "views") && decorated && typeof decorated === "object") {
|
|
3570
|
+
try {
|
|
3571
|
+
const viewDoc = decorated;
|
|
3572
|
+
const sourceObject = viewDoc?.object ?? viewDoc?.data?.object ?? viewDoc?.objectName ?? viewDoc?.list?.data?.object;
|
|
3573
|
+
const objectDef = typeof sourceObject === "string" ? this.engine.registry.getObject(sourceObject) : void 0;
|
|
3574
|
+
if (objectDef) {
|
|
3575
|
+
const refs = computeViewReferenceDiagnostics(viewDoc, objectDef);
|
|
3576
|
+
if (!refs.valid) {
|
|
3577
|
+
const prior = viewDoc._diagnostics;
|
|
3578
|
+
decorated = {
|
|
3579
|
+
...viewDoc,
|
|
3580
|
+
_diagnostics: {
|
|
3581
|
+
valid: false,
|
|
3582
|
+
errors: [
|
|
3583
|
+
...prior && prior.valid === false && Array.isArray(prior.errors) ? prior.errors : [],
|
|
3584
|
+
...refs.errors ?? []
|
|
3585
|
+
]
|
|
3586
|
+
}
|
|
3587
|
+
};
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
3590
|
+
} catch {
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3371
3593
|
const artifactBacked = this.isArtifactBacked(request.type, request.name);
|
|
3372
3594
|
const lockState = resolveLockState(decorated, artifactBacked);
|
|
3373
3595
|
return {
|
|
@@ -3407,20 +3629,20 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3407
3629
|
const services = this.getServicesRegistry?.();
|
|
3408
3630
|
const metadataService = services?.get("metadata");
|
|
3409
3631
|
if (metadataService && typeof metadataService.get === "function") {
|
|
3410
|
-
let fromService = await metadataService.get(request.type, request.name);
|
|
3632
|
+
let fromService = await metadataService.get(request.type, request.name, request.packageId);
|
|
3411
3633
|
if (fromService === void 0 || fromService === null) {
|
|
3412
3634
|
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3413
|
-
if (alt) fromService = await metadataService.get(alt, request.name);
|
|
3635
|
+
if (alt) fromService = await metadataService.get(alt, request.name, request.packageId);
|
|
3414
3636
|
}
|
|
3415
3637
|
if (fromService !== void 0 && fromService !== null) code = fromService;
|
|
3416
3638
|
}
|
|
3417
3639
|
} catch {
|
|
3418
3640
|
}
|
|
3419
3641
|
if (code === null) {
|
|
3420
|
-
let regItem = this.engine.registry.getItem(request.type, request.name);
|
|
3642
|
+
let regItem = this.lookupArtifactItem(request.type, request.name, request.packageId) ?? this.engine.registry.getItem(request.type, request.name, request.packageId);
|
|
3421
3643
|
if (regItem === void 0) {
|
|
3422
3644
|
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3423
|
-
if (alt) regItem = this.engine.registry.getItem(alt, request.name);
|
|
3645
|
+
if (alt) regItem = this.engine.registry.getItem(alt, request.name, request.packageId);
|
|
3424
3646
|
}
|
|
3425
3647
|
if (regItem !== void 0) code = regItem;
|
|
3426
3648
|
}
|
|
@@ -3428,20 +3650,28 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
3428
3650
|
let overlayScope = null;
|
|
3429
3651
|
try {
|
|
3430
3652
|
const findOverlay = async (oid) => {
|
|
3431
|
-
const
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3653
|
+
const lookup = async (t) => {
|
|
3654
|
+
const base = {
|
|
3655
|
+
type: t,
|
|
3656
|
+
name: request.name,
|
|
3657
|
+
state: "active",
|
|
3658
|
+
organization_id: oid
|
|
3659
|
+
};
|
|
3660
|
+
if (request.packageId) {
|
|
3661
|
+
const scoped = await this.engine.findOne("sys_metadata", {
|
|
3662
|
+
where: { ...base, package_id: request.packageId }
|
|
3663
|
+
});
|
|
3664
|
+
if (scoped) return scoped;
|
|
3665
|
+
return await this.engine.findOne("sys_metadata", {
|
|
3666
|
+
where: { ...base, package_id: null }
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3669
|
+
return await this.engine.findOne("sys_metadata", { where: base });
|
|
3436
3670
|
};
|
|
3437
|
-
let rec = await
|
|
3671
|
+
let rec = await lookup(request.type);
|
|
3438
3672
|
if (!rec) {
|
|
3439
3673
|
const alt = PLURAL_TO_SINGULAR3[request.type] ?? SINGULAR_TO_PLURAL2[request.type];
|
|
3440
|
-
if (alt)
|
|
3441
|
-
rec = await this.engine.findOne("sys_metadata", {
|
|
3442
|
-
where: { ...where, type: alt }
|
|
3443
|
-
});
|
|
3444
|
-
}
|
|
3674
|
+
if (alt) rec = await lookup(alt);
|
|
3445
3675
|
}
|
|
3446
3676
|
return rec;
|
|
3447
3677
|
};
|
|
@@ -4463,14 +4693,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4463
4693
|
* "authoring a DB-only item" (requires only `allowRuntimeCreate`).
|
|
4464
4694
|
*/
|
|
4465
4695
|
isArtifactBacked(type, name) {
|
|
4466
|
-
|
|
4467
|
-
if (!registry || typeof registry.getItem !== "function") {
|
|
4468
|
-
return false;
|
|
4469
|
-
}
|
|
4470
|
-
const singular = PLURAL_TO_SINGULAR3[type] ?? type;
|
|
4471
|
-
const item = registry.getItem(singular, name) ?? registry.getItem(type, name);
|
|
4472
|
-
if (!item || !item._packageId) return false;
|
|
4473
|
-
return item._packageId !== "sys_metadata";
|
|
4696
|
+
return this.lookupArtifactItem(type, name) !== void 0;
|
|
4474
4697
|
}
|
|
4475
4698
|
// ───────────────────────────────────────────────────────────────────
|
|
4476
4699
|
// ADR-0010 — metadata protection (Phase 1: L3 item-level lock)
|
|
@@ -4480,11 +4703,19 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4480
4703
|
* type and its singular/plural twin. Returns `undefined` when the
|
|
4481
4704
|
* registry is unavailable or the item is not artifact-backed.
|
|
4482
4705
|
*/
|
|
4483
|
-
lookupArtifactItem(type, name) {
|
|
4706
|
+
lookupArtifactItem(type, name, currentPackageId) {
|
|
4484
4707
|
const registry = this.engine?.registry;
|
|
4485
|
-
if (!registry
|
|
4708
|
+
if (!registry) return void 0;
|
|
4486
4709
|
const singular = PLURAL_TO_SINGULAR3[type] ?? type;
|
|
4487
|
-
|
|
4710
|
+
if (typeof registry.getArtifactItem === "function") {
|
|
4711
|
+
return registry.getArtifactItem(singular, name, currentPackageId) ?? registry.getArtifactItem(type, name, currentPackageId);
|
|
4712
|
+
}
|
|
4713
|
+
if (typeof registry.getItem !== "function") return void 0;
|
|
4714
|
+
const item = registry.getItem(singular, name, currentPackageId) ?? registry.getItem(type, name, currentPackageId);
|
|
4715
|
+
if (!item || !item._packageId || item._packageId === "sys_metadata") {
|
|
4716
|
+
return void 0;
|
|
4717
|
+
}
|
|
4718
|
+
return item;
|
|
4488
4719
|
}
|
|
4489
4720
|
/**
|
|
4490
4721
|
* Resolve the effective `_lock` for an item by consulting the
|
|
@@ -4498,13 +4729,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4498
4729
|
* scope and the caller is expected to also gate on `environmentId`.
|
|
4499
4730
|
*/
|
|
4500
4731
|
async getEffectiveLock(type, name, organizationId) {
|
|
4501
|
-
const
|
|
4502
|
-
|
|
4503
|
-
let artifactItem;
|
|
4504
|
-
if (registry && typeof registry.getItem === "function") {
|
|
4505
|
-
artifactItem = registry.getItem(singular, name) ?? registry.getItem(type, name);
|
|
4506
|
-
}
|
|
4507
|
-
if (artifactItem && artifactItem._packageId && artifactItem._packageId !== "sys_metadata") {
|
|
4732
|
+
const artifactItem = this.lookupArtifactItem(type, name);
|
|
4733
|
+
if (artifactItem) {
|
|
4508
4734
|
const p = extractProtection(artifactItem);
|
|
4509
4735
|
if (p.lock !== "none") {
|
|
4510
4736
|
return { lock: p.lock, lockReason: p.lockReason, lockSource: "artifact" };
|
|
@@ -4645,6 +4871,49 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4645
4871
|
);
|
|
4646
4872
|
}
|
|
4647
4873
|
}
|
|
4874
|
+
/**
|
|
4875
|
+
* Heal the in-memory registry after a metadata reset (overlay-row
|
|
4876
|
+
* delete) on control-plane kernels. Two layers:
|
|
4877
|
+
*
|
|
4878
|
+
* 1. Drop the plain-key runtime shadow so the packaged artifact
|
|
4879
|
+
* (registered under `<packageId>:<name>`) becomes the visible
|
|
4880
|
+
* value again. The shadow is written by the overlay-hydration
|
|
4881
|
+
* paths (`getMetaItems` / `loadMetaFromDb`) and — pre-fix —
|
|
4882
|
+
* survived the reset until restart, leaving stale overlay
|
|
4883
|
+
* content (and a stripped `_lock` envelope) in every
|
|
4884
|
+
* registry-direct read (ADR-0010 §3.3).
|
|
4885
|
+
* 2. When no composite-key artifact exists, fall back to the
|
|
4886
|
+
* MetadataService baseline (FilesystemLoader-sourced types) and
|
|
4887
|
+
* re-register it, preserving the historical refresh behaviour
|
|
4888
|
+
* for items the SchemaRegistry never held as artifacts.
|
|
4889
|
+
*
|
|
4890
|
+
* Best-effort: a failure must never block the delete that already
|
|
4891
|
+
* succeeded; the next full reload fixes the registry anyway.
|
|
4892
|
+
*/
|
|
4893
|
+
async restoreArtifactRegistryView(type, name) {
|
|
4894
|
+
try {
|
|
4895
|
+
const registry = this.engine.registry;
|
|
4896
|
+
let healed = false;
|
|
4897
|
+
if (typeof registry.removeRuntimeShadow === "function") {
|
|
4898
|
+
const singular = PLURAL_TO_SINGULAR3[type] ?? type;
|
|
4899
|
+
healed = registry.removeRuntimeShadow(singular, name);
|
|
4900
|
+
if (type !== singular) {
|
|
4901
|
+
healed = registry.removeRuntimeShadow(type, name) || healed;
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
if (healed) return;
|
|
4905
|
+
if (this.environmentId !== void 0) return;
|
|
4906
|
+
const services = this.getServicesRegistry?.();
|
|
4907
|
+
const metadataService = services?.get("metadata");
|
|
4908
|
+
if (metadataService && typeof metadataService.get === "function") {
|
|
4909
|
+
const artifactItem = await metadataService.get(type, name);
|
|
4910
|
+
if (artifactItem !== void 0) {
|
|
4911
|
+
this.engine.registry.registerItem(type, artifactItem, "name");
|
|
4912
|
+
}
|
|
4913
|
+
}
|
|
4914
|
+
} catch {
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4648
4917
|
/**
|
|
4649
4918
|
* Ensure a just-PUBLISHED object's physical table exists so it is usable
|
|
4650
4919
|
* for data CRUD immediately — without a server restart. Registering the
|
|
@@ -4808,7 +5077,10 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
4808
5077
|
if (request.parentVersion !== void 0) {
|
|
4809
5078
|
parentVersion = request.parentVersion;
|
|
4810
5079
|
} else {
|
|
4811
|
-
const current = await repo.get(ref, {
|
|
5080
|
+
const current = await repo.get(ref, {
|
|
5081
|
+
state: mode === "draft" ? "draft" : "active",
|
|
5082
|
+
packageId: request.packageId ?? null
|
|
5083
|
+
});
|
|
4812
5084
|
parentVersion = current?.hash ?? null;
|
|
4813
5085
|
}
|
|
4814
5086
|
try {
|
|
@@ -5466,6 +5738,9 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5466
5738
|
const targetState = request.state === "draft" ? "draft" : "active";
|
|
5467
5739
|
const current = await repo.get(ref, { state: targetState });
|
|
5468
5740
|
if (!current) {
|
|
5741
|
+
if (targetState === "active") {
|
|
5742
|
+
await this.restoreArtifactRegistryView(request.type, request.name);
|
|
5743
|
+
}
|
|
5469
5744
|
return {
|
|
5470
5745
|
success: true,
|
|
5471
5746
|
reset: false,
|
|
@@ -5480,18 +5755,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5480
5755
|
intent: this.isArtifactBacked(singularTypeForRepo, request.name) ? "override-artifact" : "runtime-only",
|
|
5481
5756
|
state: targetState
|
|
5482
5757
|
});
|
|
5483
|
-
if (
|
|
5484
|
-
|
|
5485
|
-
const services = this.getServicesRegistry?.();
|
|
5486
|
-
const metadataService = services?.get("metadata");
|
|
5487
|
-
if (metadataService && typeof metadataService.get === "function") {
|
|
5488
|
-
const artifactItem = await metadataService.get(request.type, request.name);
|
|
5489
|
-
if (artifactItem !== void 0) {
|
|
5490
|
-
this.engine.registry.registerItem(request.type, artifactItem, "name");
|
|
5491
|
-
}
|
|
5492
|
-
}
|
|
5493
|
-
} catch {
|
|
5494
|
-
}
|
|
5758
|
+
if (targetState === "active") {
|
|
5759
|
+
await this.restoreArtifactRegistryView(request.type, request.name);
|
|
5495
5760
|
}
|
|
5496
5761
|
if (this.shouldDropStorage(request.type, request.name, request.dropStorage, targetState)) {
|
|
5497
5762
|
await this.dropObjectStorage(singularTypeForRepo, request.name);
|
|
@@ -5550,18 +5815,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5550
5815
|
await this.dropObjectStorage(PLURAL_TO_SINGULAR3[request.type] ?? request.type, request.name);
|
|
5551
5816
|
}
|
|
5552
5817
|
}
|
|
5553
|
-
if (
|
|
5554
|
-
|
|
5555
|
-
const services = this.getServicesRegistry?.();
|
|
5556
|
-
const metadataService = services?.get("metadata");
|
|
5557
|
-
if (metadataService && typeof metadataService.get === "function") {
|
|
5558
|
-
const artifactItem = await metadataService.get(request.type, request.name);
|
|
5559
|
-
if (artifactItem !== void 0) {
|
|
5560
|
-
this.engine.registry.registerItem(request.type, artifactItem, "name");
|
|
5561
|
-
}
|
|
5562
|
-
}
|
|
5563
|
-
} catch {
|
|
5564
|
-
}
|
|
5818
|
+
if (request.state !== "draft") {
|
|
5819
|
+
await this.restoreArtifactRegistryView(request.type, request.name);
|
|
5565
5820
|
}
|
|
5566
5821
|
return {
|
|
5567
5822
|
success: true,
|
|
@@ -5599,7 +5854,12 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
|
|
|
5599
5854
|
if (normalizedType === "object") {
|
|
5600
5855
|
this.engine.registry.registerObject(data, record.packageId || "sys_metadata");
|
|
5601
5856
|
} else {
|
|
5602
|
-
this.
|
|
5857
|
+
const artifact = this.lookupArtifactItem(normalizedType, data?.name);
|
|
5858
|
+
this.engine.registry.registerItem(
|
|
5859
|
+
normalizedType,
|
|
5860
|
+
mergeArtifactProtection(data, artifact),
|
|
5861
|
+
"name"
|
|
5862
|
+
);
|
|
5603
5863
|
}
|
|
5604
5864
|
loaded++;
|
|
5605
5865
|
} catch (e) {
|
|
@@ -7566,7 +7826,9 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7566
7826
|
"mappings",
|
|
7567
7827
|
"analyticsCubes",
|
|
7568
7828
|
// Integration Protocol
|
|
7569
|
-
"connectors"
|
|
7829
|
+
"connectors",
|
|
7830
|
+
// System Protocol — package documentation (ADR-0046); inert data
|
|
7831
|
+
"docs"
|
|
7570
7832
|
];
|
|
7571
7833
|
for (const key of metadataArrayKeys) {
|
|
7572
7834
|
const items = manifest[key];
|
|
@@ -7702,7 +7964,8 @@ var _ObjectQL = class _ObjectQL {
|
|
|
7702
7964
|
"hooks",
|
|
7703
7965
|
"mappings",
|
|
7704
7966
|
"analyticsCubes",
|
|
7705
|
-
"connectors"
|
|
7967
|
+
"connectors",
|
|
7968
|
+
"docs"
|
|
7706
7969
|
];
|
|
7707
7970
|
for (const key of metadataArrayKeys) {
|
|
7708
7971
|
const items = plugin[key];
|
|
@@ -9231,17 +9494,24 @@ var MetadataFacade = class {
|
|
|
9231
9494
|
*/
|
|
9232
9495
|
async register(type, name, data) {
|
|
9233
9496
|
const definition = typeof data === "object" && data !== null ? { ...data, name: data.name ?? name } : data;
|
|
9497
|
+
const packageId = definition?._packageId;
|
|
9234
9498
|
if (type === "object") {
|
|
9235
|
-
this.registry.registerItem(type, definition, "name");
|
|
9499
|
+
this.registry.registerItem(type, definition, "name", packageId);
|
|
9236
9500
|
} else {
|
|
9237
|
-
this.registry.registerItem(type, definition, definition.id ? "id" : "name");
|
|
9501
|
+
this.registry.registerItem(type, definition, definition.id ? "id" : "name", packageId);
|
|
9238
9502
|
}
|
|
9239
9503
|
}
|
|
9240
9504
|
/**
|
|
9241
|
-
* Get a metadata item by type and name
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9505
|
+
* Get a metadata item by type and name.
|
|
9506
|
+
*
|
|
9507
|
+
* `currentPackageId` (ADR-0048) opts into package-scoped resolution: when two
|
|
9508
|
+
* installed packages ship an item of the same `type`/`name`, the registry
|
|
9509
|
+
* prefers the one owned by `currentPackageId` (composite key
|
|
9510
|
+
* `${packageId}:${name}`) before falling back to first-match. Omit it for the
|
|
9511
|
+
* legacy context-free lookup.
|
|
9512
|
+
*/
|
|
9513
|
+
async get(type, name, currentPackageId) {
|
|
9514
|
+
const item = this.registry.getItem(type, name, currentPackageId);
|
|
9245
9515
|
return item?.content ?? item;
|
|
9246
9516
|
}
|
|
9247
9517
|
/**
|
|
@@ -9320,6 +9590,7 @@ var ObjectQLPlugin = class {
|
|
|
9320
9590
|
*/
|
|
9321
9591
|
this.startupTimeout = 12e4;
|
|
9322
9592
|
this.skipSchemaSync = false;
|
|
9593
|
+
this.hydrateMetadataFromDb = false;
|
|
9323
9594
|
/** Unsubscribe handles for metadata-event subscriptions (ADR-0008 PR-7). */
|
|
9324
9595
|
this.metadataUnsubscribes = [];
|
|
9325
9596
|
this.init = async (ctx) => {
|
|
@@ -9444,7 +9715,7 @@ var ObjectQLPlugin = class {
|
|
|
9444
9715
|
} else {
|
|
9445
9716
|
await this.syncRegisteredSchemas(ctx);
|
|
9446
9717
|
}
|
|
9447
|
-
if (this.environmentId === void 0) {
|
|
9718
|
+
if (this.environmentId === void 0 || this.hydrateMetadataFromDb) {
|
|
9448
9719
|
await this.restoreMetadataFromDb(ctx);
|
|
9449
9720
|
} else {
|
|
9450
9721
|
ctx.logger.info("Project kernel \u2014 skipping sys_metadata hydration (metadata sourced from artifact)");
|
|
@@ -9486,6 +9757,7 @@ var ObjectQLPlugin = class {
|
|
|
9486
9757
|
this.startupTimeout = opts.startupTimeout;
|
|
9487
9758
|
}
|
|
9488
9759
|
this.skipSchemaSync = typeof opts.skipSchemaSync === "boolean" ? opts.skipSchemaSync : process.env.OS_SKIP_SCHEMA_SYNC === "1";
|
|
9760
|
+
this.hydrateMetadataFromDb = opts.hydrateMetadataFromDb === true;
|
|
9489
9761
|
}
|
|
9490
9762
|
/**
|
|
9491
9763
|
* Subscribe to `object` metadata events from the metadata service and
|
|
@@ -9908,7 +10180,7 @@ var ObjectQLPlugin = class {
|
|
|
9908
10180
|
return;
|
|
9909
10181
|
}
|
|
9910
10182
|
if (this.ql?.registry?.registerItem) {
|
|
9911
|
-
this.ql.registry.registerItem(type, item, keyField);
|
|
10183
|
+
this.ql.registry.registerItem(type, item, keyField, item._packageId);
|
|
9912
10184
|
}
|
|
9913
10185
|
});
|
|
9914
10186
|
if (type === "hook" && this.ql && typeof this.ql.bindHooks === "function") {
|