@objectstack/objectql 7.2.0 → 7.3.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
@@ -50,8 +50,10 @@ module.exports = __toCommonJS(index_exports);
50
50
 
51
51
  // src/registry.ts
52
52
  var import_data = require("@objectstack/spec/data");
53
+ var import_types = require("@objectstack/types");
53
54
  var import_kernel = require("@objectstack/spec/kernel");
54
55
  var import_ui = require("@objectstack/spec/ui");
56
+ var import_shared = require("@objectstack/spec/shared");
55
57
  var RESERVED_NAMESPACES = /* @__PURE__ */ new Set(["base", "system"]);
56
58
  var DEFAULT_OWNER_PRIORITY = 100;
57
59
  var DEFAULT_EXTENDER_PRIORITY = 200;
@@ -176,10 +178,19 @@ var SchemaRegistry = class {
176
178
  // ==========================================
177
179
  /** Type → Name/ID → MetadataItem */
178
180
  this.metadata = /* @__PURE__ */ new Map();
181
+ /**
182
+ * Package ids that must be installed in a DISABLED state. Seeded once at
183
+ * boot (from persisted state) BEFORE any package registration so that every
184
+ * registration path — boot artifact, marketplace rehydrate, local import —
185
+ * honors persisted disable state uniformly without a fragile post-boot
186
+ * re-application hook. See {@link setInitialDisabledPackageIds} and
187
+ * {@link installPackage}.
188
+ */
189
+ this.initialDisabledPackageIds = /* @__PURE__ */ new Set();
179
190
  if (options.multiTenant !== void 0) {
180
191
  this.multiTenant = options.multiTenant;
181
192
  } else {
182
- this.multiTenant = String(process.env.OS_MULTI_TENANT ?? "false").toLowerCase() !== "false";
193
+ this.multiTenant = String((0, import_types.readEnvWithDeprecation)("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
183
194
  }
184
195
  }
185
196
  get logLevel() {
@@ -192,6 +203,14 @@ var SchemaRegistry = class {
192
203
  if (this._logLevel === "silent" || this._logLevel === "error" || this._logLevel === "warn") return;
193
204
  console.log(msg);
194
205
  }
206
+ /**
207
+ * Seed the set of package ids that should be installed disabled. Call this
208
+ * before package registration begins; later `installPackage` calls for these
209
+ * ids land in the `disabled` state. Replaces any previously seeded set.
210
+ */
211
+ setInitialDisabledPackageIds(ids) {
212
+ this.initialDisabledPackageIds = new Set(ids);
213
+ }
195
214
  // ==========================================
196
215
  // Namespace Management
197
216
  // ==========================================
@@ -281,6 +300,7 @@ var SchemaRegistry = class {
281
300
  contributors.splice(idx, 1);
282
301
  }
283
302
  }
303
+ (0, import_shared.applyProtection)(schema, { packageId });
284
304
  const contributor = {
285
305
  packageId,
286
306
  namespace: namespace || "",
@@ -428,9 +448,7 @@ var SchemaRegistry = class {
428
448
  }
429
449
  const collection = this.metadata.get(type);
430
450
  const baseName = String(item[keyField]);
431
- if (packageId) {
432
- item._packageId = packageId;
433
- }
451
+ (0, import_shared.applyProtection)(item, { packageId });
434
452
  try {
435
453
  this.validate(type, item);
436
454
  } catch (e) {
@@ -518,10 +536,23 @@ var SchemaRegistry = class {
518
536
  return this.getAllObjects(packageId);
519
537
  }
520
538
  const items = Array.from(this.metadata.get(type)?.values() || []);
539
+ let result = items;
521
540
  if (packageId) {
522
- return items.filter((item) => item._packageId === packageId);
541
+ result = result.filter((item) => item._packageId === packageId);
523
542
  }
524
- return items;
543
+ if (type !== "package") {
544
+ result = result.filter((item) => !this.isPackageDisabled(item?._packageId));
545
+ }
546
+ return result;
547
+ }
548
+ /**
549
+ * Whether a package has been explicitly disabled. Unknown packages and
550
+ * items with no owning package are treated as enabled.
551
+ */
552
+ isPackageDisabled(packageId) {
553
+ if (!packageId) return false;
554
+ const pkg = this.getPackage(packageId);
555
+ return pkg?.enabled === false || pkg?.status === "disabled";
525
556
  }
526
557
  /**
527
558
  * Get all registered metadata types (Kinds)
@@ -538,12 +569,14 @@ var SchemaRegistry = class {
538
569
  // ==========================================
539
570
  installPackage(manifest, settings) {
540
571
  const now = (/* @__PURE__ */ new Date()).toISOString();
572
+ const disabled = this.initialDisabledPackageIds.has(manifest.id);
541
573
  const pkg = {
542
574
  manifest,
543
- status: "installed",
544
- enabled: true,
575
+ status: disabled ? "disabled" : "installed",
576
+ enabled: !disabled,
545
577
  installedAt: now,
546
578
  updatedAt: now,
579
+ ...disabled ? { statusChangedAt: now } : {},
547
580
  settings
548
581
  };
549
582
  if (manifest.namespace) {
@@ -679,10 +712,14 @@ var SchemaRegistry = class {
679
712
  }
680
713
  };
681
714
 
715
+ // src/protocol.ts
716
+ var import_types3 = require("@objectstack/types");
717
+
682
718
  // src/sys-metadata-repository.ts
683
719
  var import_metadata_core = require("@objectstack/metadata-core");
720
+ var import_types2 = require("@objectstack/types");
684
721
  var import_kernel2 = require("@objectstack/spec/kernel");
685
- var import_shared = require("@objectstack/spec/shared");
722
+ var import_shared2 = require("@objectstack/spec/shared");
686
723
  var OVERLAY_ALLOWED_TYPES = new Set(
687
724
  import_kernel2.DEFAULT_METADATA_TYPE_REGISTRY.filter((e) => e.allowOrgOverride).map((e) => e.type)
688
725
  );
@@ -695,14 +732,14 @@ var RUNTIME_CREATE_ALLOWED_TYPES = new Set(
695
732
  var _envWritableMetadataTypes = null;
696
733
  function envWritableMetadataTypes() {
697
734
  if (_envWritableMetadataTypes !== null) return _envWritableMetadataTypes;
698
- const raw = typeof process !== "undefined" && process?.env?.OBJECTSTACK_METADATA_WRITABLE || "";
735
+ const raw = (0, import_types2.readEnvWithDeprecation)("OS_METADATA_WRITABLE", "OBJECTSTACK_METADATA_WRITABLE") || "";
699
736
  const set = /* @__PURE__ */ new Set();
700
737
  for (const tok of raw.split(",")) {
701
738
  const t = tok.trim();
702
739
  if (!t) continue;
703
- const singular = import_shared.PLURAL_TO_SINGULAR[t] ?? t;
740
+ const singular = import_shared2.PLURAL_TO_SINGULAR[t] ?? t;
704
741
  set.add(singular);
705
- const plural = import_shared.SINGULAR_TO_PLURAL[singular];
742
+ const plural = import_shared2.SINGULAR_TO_PLURAL[singular];
706
743
  if (plural) set.add(plural);
707
744
  }
708
745
  _envWritableMetadataTypes = set;
@@ -825,6 +862,12 @@ var SysMetadataRepository = class {
825
862
  version,
826
863
  updated_at: now
827
864
  };
865
+ if (existing) {
866
+ const existingPkg = existing.package_id ?? null;
867
+ parentRowData.package_id = existingPkg ?? opts.packageId ?? null;
868
+ } else {
869
+ parentRowData.package_id = opts.packageId ?? null;
870
+ }
828
871
  if (existing) {
829
872
  const existingId = existing.id;
830
873
  if (existingId === void 0) {
@@ -1222,12 +1265,12 @@ var SysMetadataRepository = class {
1222
1265
  * at `(type, name)`. In that case we accept types with
1223
1266
  * `allowRuntimeCreate: true`, even when `allowOrgOverride` is false.
1224
1267
  *
1225
- * The env-var escape hatch (`OBJECTSTACK_METADATA_WRITABLE`) still
1268
+ * The env-var escape hatch (`OS_METADATA_WRITABLE`) still
1226
1269
  * applies to BOTH intents, so operators can opt into artifact
1227
1270
  * overrides at runtime for emergency fixes.
1228
1271
  */
1229
1272
  assertAllowed(type, intent = "override-artifact") {
1230
- const singular = import_shared.PLURAL_TO_SINGULAR[type] ?? type;
1273
+ const singular = import_shared2.PLURAL_TO_SINGULAR[type] ?? type;
1231
1274
  const allowedByRegistry = OVERLAY_ALLOWED_TYPES.has(singular) || OVERLAY_ALLOWED_TYPES.has(type);
1232
1275
  if (allowedByRegistry) return;
1233
1276
  if (intent === "runtime-only") {
@@ -1247,7 +1290,7 @@ var SysMetadataRepository = class {
1247
1290
  const code = intent === "runtime-only" ? "not_creatable" : "not_overridable";
1248
1291
  const detail = intent === "runtime-only" ? `'${type}' has neither allowOrgOverride nor allowRuntimeCreate in the registry. ` : `'${type}' is not allowOrgOverride in the registry. `;
1249
1292
  const err = new Error(
1250
- `[${code}] ${detail}Overlay-allowed: ${Array.from(new Set(allowed)).join(", ") || "(none)"}. Set OBJECTSTACK_METADATA_WRITABLE to enable additional types at runtime.`
1293
+ `[${code}] ${detail}Overlay-allowed: ${Array.from(new Set(allowed)).join(", ") || "(none)"}. Set OS_METADATA_WRITABLE to enable additional types at runtime.`
1251
1294
  );
1252
1295
  err.code = code;
1253
1296
  err.status = 403;
@@ -1355,7 +1398,7 @@ var SysMetadataRepository = class {
1355
1398
  // src/protocol.ts
1356
1399
  var import_metadata_core2 = require("@objectstack/metadata-core");
1357
1400
  var import_data2 = require("@objectstack/spec/data");
1358
- var import_shared3 = require("@objectstack/spec/shared");
1401
+ var import_shared4 = require("@objectstack/spec/shared");
1359
1402
  var import_system = require("@objectstack/spec/system");
1360
1403
  var import_kernel4 = require("@objectstack/spec/kernel");
1361
1404
  var import_kernel5 = require("@objectstack/spec/kernel");
@@ -1363,9 +1406,9 @@ var import_zod = require("zod");
1363
1406
 
1364
1407
  // src/metadata-diagnostics.ts
1365
1408
  var import_kernel3 = require("@objectstack/spec/kernel");
1366
- var import_shared2 = require("@objectstack/spec/shared");
1409
+ var import_shared3 = require("@objectstack/spec/shared");
1367
1410
  function computeMetadataDiagnostics(type, item) {
1368
- const singular = import_shared2.PLURAL_TO_SINGULAR[type] ?? type;
1411
+ const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
1369
1412
  const schema = (0, import_kernel3.getMetadataTypeSchema)(singular);
1370
1413
  if (!schema) return void 0;
1371
1414
  if (item === null || item === void 0 || typeof item !== "object") {
@@ -1603,7 +1646,7 @@ var HAND_CRAFTED_SCHEMAS = {
1603
1646
  }
1604
1647
  };
1605
1648
  function resolveOverlaySchema(type, _item) {
1606
- const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
1649
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
1607
1650
  return (0, import_kernel4.getMetadataTypeSchema)(singular) ?? null;
1608
1651
  }
1609
1652
  function mergeArtifactProtection(item, artifactItem) {
@@ -1614,6 +1657,8 @@ function mergeArtifactProtection(item, artifactItem) {
1614
1657
  const out = { ...item };
1615
1658
  if (a._lock !== void 0) out._lock = a._lock;
1616
1659
  if (a._lockReason !== void 0) out._lockReason = a._lockReason;
1660
+ if (a._lockDocsUrl !== void 0) out._lockDocsUrl = a._lockDocsUrl;
1661
+ if (a._lockSource !== void 0) out._lockSource = a._lockSource;
1617
1662
  if (a._packageId !== void 0) out._packageId = a._packageId;
1618
1663
  if (a._packageVersion !== void 0) out._packageVersion = a._packageVersion;
1619
1664
  if (a._provenance !== void 0) out._provenance = a._provenance;
@@ -2044,7 +2089,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2044
2089
  import_kernel4.DEFAULT_METADATA_TYPE_REGISTRY.map((e) => [e.type, e])
2045
2090
  );
2046
2091
  const entries = allTypes.map((type) => {
2047
- const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
2092
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
2048
2093
  const zodSchema = (0, import_kernel4.getMetadataTypeSchema)(singular);
2049
2094
  const schema = (zodSchema ? toJsonSchemaSafe(zodSchema) : void 0) ?? HAND_CRAFTED_SCHEMAS[singular];
2050
2095
  const form = TYPE_TO_FORM[singular];
@@ -2125,10 +2170,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2125
2170
  }
2126
2171
  const items = Array.isArray(listed?.items) ? listed.items : Array.isArray(listed) ? listed : [];
2127
2172
  const pkgSet = /* @__PURE__ */ new Set();
2173
+ let lockedCount = 0;
2128
2174
  for (const item of items) {
2129
2175
  scannedItems += 1;
2130
2176
  const pkg = item?._packageId ?? null;
2131
2177
  if (pkg) pkgSet.add(pkg);
2178
+ const lock = item?._lock;
2179
+ if (lock && lock !== "none") lockedCount += 1;
2132
2180
  const diag = item?._diagnostics ?? computeMetadataDiagnostics(t, item);
2133
2181
  if (!diag) continue;
2134
2182
  if (diag.valid && !includeWarnings) continue;
@@ -2139,7 +2187,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2139
2187
  diagnostics: diag
2140
2188
  });
2141
2189
  }
2142
- stats[t] = { count: items.length, packages: [...pkgSet].sort() };
2190
+ stats[t] = { count: items.length, locked: lockedCount, packages: [...pkgSet].sort() };
2143
2191
  }
2144
2192
  return {
2145
2193
  entries,
@@ -2155,13 +2203,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2155
2203
  if (this.environmentId === void 0) {
2156
2204
  items = [...this.engine.registry.listItems(request.type, packageId)];
2157
2205
  if (items.length === 0) {
2158
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2206
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2159
2207
  if (alt) items = [...this.engine.registry.listItems(alt, packageId)];
2160
2208
  }
2161
2209
  } else {
2162
2210
  items = [...this.engine.registry.listItems(request.type, packageId)];
2163
2211
  if (items.length === 0) {
2164
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2212
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2165
2213
  if (alt) items = [...this.engine.registry.listItems(alt, packageId)];
2166
2214
  }
2167
2215
  }
@@ -2173,13 +2221,13 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2173
2221
  state: "active",
2174
2222
  organization_id: oid
2175
2223
  };
2176
- if (packageId) whereClause._packageId = packageId;
2224
+ if (packageId) whereClause.package_id = packageId;
2177
2225
  let rs = await this.engine.find("sys_metadata", { where: whereClause });
2178
2226
  if (!rs || rs.length === 0) {
2179
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2227
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2180
2228
  if (alt) {
2181
2229
  const altWhere = { type: alt, state: "active", organization_id: oid };
2182
- if (packageId) altWhere._packageId = packageId;
2230
+ if (packageId) altWhere.package_id = packageId;
2183
2231
  rs = await this.engine.find("sys_metadata", { where: altWhere });
2184
2232
  }
2185
2233
  }
@@ -2202,6 +2250,10 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2202
2250
  for (const record of records) {
2203
2251
  const data = typeof record.metadata === "string" ? JSON.parse(record.metadata) : record.metadata;
2204
2252
  if (data && typeof data === "object" && "name" in data) {
2253
+ const recPkg = record.package_id ?? void 0;
2254
+ if (recPkg && data._packageId === void 0) {
2255
+ data._packageId = recPkg;
2256
+ }
2205
2257
  byName.set(data.name, data);
2206
2258
  }
2207
2259
  if (this.environmentId === void 0) {
@@ -2241,6 +2293,11 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2241
2293
  }
2242
2294
  } catch {
2243
2295
  }
2296
+ if (request.type !== "package" && request.type !== "object" && request.type !== "objects") {
2297
+ items = items.filter(
2298
+ (it) => !this.engine.registry.isPackageDisabled(it?._packageId)
2299
+ );
2300
+ }
2244
2301
  return {
2245
2302
  type: request.type,
2246
2303
  items: decorateMetadataItems(
@@ -2269,7 +2326,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2269
2326
  };
2270
2327
  const rec = await this.engine.findOne("sys_metadata", { where });
2271
2328
  if (rec) return rec;
2272
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2329
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2273
2330
  if (alt) {
2274
2331
  const altWhere = {
2275
2332
  type: alt,
@@ -2284,6 +2341,10 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2284
2341
  const record = (orgId ? await findOverlay(orgId) : void 0) ?? await findOverlay(null);
2285
2342
  if (record) {
2286
2343
  item = typeof record.metadata === "string" ? JSON.parse(record.metadata) : record.metadata;
2344
+ const recPkg = record.package_id ?? void 0;
2345
+ if (recPkg && item && typeof item === "object" && item._packageId === void 0) {
2346
+ item._packageId = recPkg;
2347
+ }
2287
2348
  }
2288
2349
  } catch {
2289
2350
  }
@@ -2307,7 +2368,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2307
2368
  if (fromService !== void 0 && fromService !== null) {
2308
2369
  item = fromService;
2309
2370
  } else {
2310
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2371
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2311
2372
  if (alt) {
2312
2373
  const altFromService = await metadataService.get(alt, request.name);
2313
2374
  if (altFromService !== void 0 && altFromService !== null) {
@@ -2322,7 +2383,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2322
2383
  if (item === void 0) {
2323
2384
  item = this.engine.registry.getItem(request.type, request.name);
2324
2385
  if (item === void 0) {
2325
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2386
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2326
2387
  if (alt) item = this.engine.registry.getItem(alt, request.name);
2327
2388
  }
2328
2389
  }
@@ -2340,6 +2401,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2340
2401
  lock: lockState.lock,
2341
2402
  ...lockState.lockReason !== void 0 ? { lockReason: lockState.lockReason } : {},
2342
2403
  ...lockState.lockSource !== void 0 ? { lockSource: lockState.lockSource } : {},
2404
+ ...lockState.lockDocsUrl !== void 0 ? { lockDocsUrl: lockState.lockDocsUrl } : {},
2343
2405
  ...lockState.provenance !== void 0 ? { provenance: lockState.provenance } : {},
2344
2406
  ...lockState.packageId !== void 0 ? { packageId: lockState.packageId } : {},
2345
2407
  ...lockState.packageVersion !== void 0 ? { packageVersion: lockState.packageVersion } : {},
@@ -2371,7 +2433,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2371
2433
  if (metadataService && typeof metadataService.get === "function") {
2372
2434
  let fromService = await metadataService.get(request.type, request.name);
2373
2435
  if (fromService === void 0 || fromService === null) {
2374
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2436
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2375
2437
  if (alt) fromService = await metadataService.get(alt, request.name);
2376
2438
  }
2377
2439
  if (fromService !== void 0 && fromService !== null) code = fromService;
@@ -2381,7 +2443,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2381
2443
  if (code === null) {
2382
2444
  let regItem = this.engine.registry.getItem(request.type, request.name);
2383
2445
  if (regItem === void 0) {
2384
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2446
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2385
2447
  if (alt) regItem = this.engine.registry.getItem(alt, request.name);
2386
2448
  }
2387
2449
  if (regItem !== void 0) code = regItem;
@@ -2398,7 +2460,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2398
2460
  };
2399
2461
  let rec = await this.engine.findOne("sys_metadata", { where });
2400
2462
  if (!rec) {
2401
- const alt = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? import_shared3.SINGULAR_TO_PLURAL[request.type];
2463
+ const alt = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? import_shared4.SINGULAR_TO_PLURAL[request.type];
2402
2464
  if (alt) {
2403
2465
  rec = await this.engine.findOne("sys_metadata", {
2404
2466
  where: { ...where, type: alt }
@@ -2439,6 +2501,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2439
2501
  lock: lockState.lock,
2440
2502
  ...lockState.lockReason !== void 0 ? { lockReason: lockState.lockReason } : {},
2441
2503
  ...lockState.lockSource !== void 0 ? { lockSource: lockState.lockSource } : {},
2504
+ ...lockState.lockDocsUrl !== void 0 ? { lockDocsUrl: lockState.lockDocsUrl } : {},
2442
2505
  ...lockState.provenance !== void 0 ? { provenance: lockState.provenance } : {},
2443
2506
  ...lockState.packageId !== void 0 ? { packageId: lockState.packageId } : {},
2444
2507
  ...lockState.packageVersion !== void 0 ? { packageVersion: lockState.packageVersion } : {},
@@ -2462,7 +2525,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
2462
2525
  * raising, keeping the Studio tab harmless.
2463
2526
  */
2464
2527
  async auditMetaItem(request) {
2465
- const singular = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
2528
+ const singular = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
2466
2529
  const limit = Math.min(
2467
2530
  Math.max(1, request.limit ?? 100),
2468
2531
  500
@@ -3371,14 +3434,14 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3371
3434
  }
3372
3435
  static envWritableTypes() {
3373
3436
  if (this._envWritableTypes !== null) return this._envWritableTypes;
3374
- const raw = typeof process !== "undefined" && process?.env?.OBJECTSTACK_METADATA_WRITABLE || "";
3437
+ const raw = (0, import_types3.readEnvWithDeprecation)("OS_METADATA_WRITABLE", "OBJECTSTACK_METADATA_WRITABLE") || "";
3375
3438
  const set = /* @__PURE__ */ new Set();
3376
3439
  for (const tok of raw.split(",")) {
3377
3440
  const t = tok.trim();
3378
3441
  if (!t) continue;
3379
- const singular = import_shared3.PLURAL_TO_SINGULAR[t] ?? t;
3442
+ const singular = import_shared4.PLURAL_TO_SINGULAR[t] ?? t;
3380
3443
  set.add(singular);
3381
- const plural = import_shared3.SINGULAR_TO_PLURAL[singular];
3444
+ const plural = import_shared4.SINGULAR_TO_PLURAL[singular];
3382
3445
  if (plural) set.add(plural);
3383
3446
  }
3384
3447
  this._envWritableTypes = set;
@@ -3390,7 +3453,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3390
3453
  }
3391
3454
  /** Normalize plural→singular before consulting the allow-list. */
3392
3455
  static isOverlayAllowed(type) {
3393
- const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
3456
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
3394
3457
  if (this.OVERLAY_ALLOWED_TYPES.has(singular) || this.OVERLAY_ALLOWED_TYPES.has(type)) {
3395
3458
  return true;
3396
3459
  }
@@ -3399,7 +3462,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3399
3462
  }
3400
3463
  /** Does this type permit creating brand-new (artifact-free) items? */
3401
3464
  static isRuntimeCreateAllowed(type) {
3402
- const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
3465
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
3403
3466
  if (this.RUNTIME_CREATE_ALLOWED_TYPES.has(singular) || this.RUNTIME_CREATE_ALLOWED_TYPES.has(type)) {
3404
3467
  return true;
3405
3468
  }
@@ -3428,7 +3491,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3428
3491
  if (!registry || typeof registry.getItem !== "function") {
3429
3492
  return false;
3430
3493
  }
3431
- const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
3494
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
3432
3495
  const item = registry.getItem(singular, name) ?? registry.getItem(type, name);
3433
3496
  if (!item || !item._packageId) return false;
3434
3497
  return item._packageId !== "sys_metadata";
@@ -3444,7 +3507,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3444
3507
  lookupArtifactItem(type, name) {
3445
3508
  const registry = this.engine?.registry;
3446
3509
  if (!registry || typeof registry.getItem !== "function") return void 0;
3447
- const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
3510
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
3448
3511
  return registry.getItem(singular, name) ?? registry.getItem(type, name);
3449
3512
  }
3450
3513
  /**
@@ -3460,7 +3523,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3460
3523
  */
3461
3524
  async getEffectiveLock(type, name, organizationId) {
3462
3525
  const registry = this.engine?.registry;
3463
- const singular = import_shared3.PLURAL_TO_SINGULAR[type] ?? type;
3526
+ const singular = import_shared4.PLURAL_TO_SINGULAR[type] ?? type;
3464
3527
  let artifactItem;
3465
3528
  if (registry && typeof registry.getItem === "function") {
3466
3529
  artifactItem = registry.getItem(singular, name) ?? registry.getItem(type, name);
@@ -3504,7 +3567,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3504
3567
  occurred_at: (/* @__PURE__ */ new Date()).toISOString(),
3505
3568
  actor: entry.actor ?? "system",
3506
3569
  source: entry.source ?? "protocol",
3507
- type: import_shared3.PLURAL_TO_SINGULAR[entry.type] ?? entry.type,
3570
+ type: import_shared4.PLURAL_TO_SINGULAR[entry.type] ?? entry.type,
3508
3571
  name: entry.name,
3509
3572
  organization_id: entry.organizationId ?? null,
3510
3573
  operation: entry.operation,
@@ -3617,7 +3680,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3617
3680
  const artifactBacked = this.isArtifactBacked(request.type, request.name);
3618
3681
  if (artifactBacked && !overlayAllowed) {
3619
3682
  const err = new Error(
3620
- `[not_overridable] Metadata item '${request.type}/${request.name}' is provided by a code package and the type has not opted into per-org overlay writes (allowOrgOverride=false). Edit the source artifact and redeploy, or set OBJECTSTACK_METADATA_WRITABLE to grant a runtime escape hatch. See docs/adr/0005-metadata-customization-overlay.md.`
3683
+ `[not_overridable] Metadata item '${request.type}/${request.name}' is provided by a code package and the type has not opted into per-org overlay writes (allowOrgOverride=false). Edit the source artifact and redeploy, or set OS_METADATA_WRITABLE to grant a runtime escape hatch. See docs/adr/0005-metadata-customization-overlay.md.`
3621
3684
  );
3622
3685
  err.code = "not_overridable";
3623
3686
  err.status = 403;
@@ -3641,7 +3704,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3641
3704
  });
3642
3705
  if (lockErr) throw lockErr;
3643
3706
  }
3644
- const singularType = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3707
+ const singularType = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3645
3708
  if (!request.force && (singularType === "object" || singularType === "field")) {
3646
3709
  try {
3647
3710
  const existing = await this.getMetaItem({
@@ -3667,6 +3730,18 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3667
3730
  if (err?.code === "destructive_change") throw err;
3668
3731
  }
3669
3732
  }
3733
+ {
3734
+ const it = request.item;
3735
+ const looksLikeLayeredEnvelope = it && typeof it === "object" && !Array.isArray(it) && "code" in it && "overlay" in it && "overlayScope" in it && "effective" in it;
3736
+ if (looksLikeLayeredEnvelope) {
3737
+ const err = new Error(
3738
+ `[invalid_metadata] ${request.type}/${request.name}: the request body is a layered read envelope ({ code, overlay, overlayScope, effective }), not a metadata body. Unwrap and send the effective/overlay document instead \u2014 the layered shape is read-only (GET ?layers=true) and must never be persisted.`
3739
+ );
3740
+ err.code = "invalid_metadata";
3741
+ err.status = 422;
3742
+ throw err;
3743
+ }
3744
+ }
3670
3745
  {
3671
3746
  const schema = resolveOverlaySchema(request.type, request.item);
3672
3747
  if (schema) {
@@ -3689,7 +3764,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3689
3764
  }
3690
3765
  }
3691
3766
  await this.ensureOverlayIndex();
3692
- const singularTypeForRepo = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3767
+ const singularTypeForRepo = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3693
3768
  const overlayAllowedForRepo = _ObjectStackProtocolImplementation.isOverlayAllowed(singularTypeForRepo);
3694
3769
  const runtimeCreateAllowedForRepo = _ObjectStackProtocolImplementation.isRuntimeCreateAllowed(singularTypeForRepo);
3695
3770
  const useRepoPath = overlayAllowedForRepo || runtimeCreateAllowedForRepo;
@@ -3716,7 +3791,8 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3716
3791
  actor: request.actor ?? "system",
3717
3792
  source: "protocol.saveMetaItem",
3718
3793
  intent,
3719
- state: mode === "draft" ? "draft" : "active"
3794
+ state: mode === "draft" ? "draft" : "active",
3795
+ ...request.packageId !== void 0 ? { packageId: request.packageId } : {}
3720
3796
  });
3721
3797
  if (mode === "publish") {
3722
3798
  this.applyObjectRegistryMutation(request);
@@ -3767,12 +3843,16 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3767
3843
  where: scopedWhere
3768
3844
  });
3769
3845
  if (existing) {
3770
- await this.engine.update("sys_metadata", {
3846
+ const updateRow = {
3771
3847
  metadata: JSON.stringify(request.item),
3772
3848
  updated_at: now,
3773
3849
  version: (existing.version || 0) + 1,
3774
3850
  state: "active"
3775
- }, {
3851
+ };
3852
+ const existingPkg = existing.package_id ?? null;
3853
+ const nextPkg = existingPkg ?? request.packageId ?? null;
3854
+ if (nextPkg !== null) updateRow.package_id = nextPkg;
3855
+ await this.engine.update("sys_metadata", updateRow, {
3776
3856
  where: { id: existing.id }
3777
3857
  });
3778
3858
  } else {
@@ -3792,6 +3872,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3792
3872
  updated_at: now,
3793
3873
  organization_id: orgId
3794
3874
  };
3875
+ if (request.packageId) row.package_id = request.packageId;
3795
3876
  await this.engine.insert("sys_metadata", row);
3796
3877
  }
3797
3878
  return {
@@ -3821,7 +3902,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3821
3902
  * "no history" uniformly.
3822
3903
  */
3823
3904
  async historyMetaItem(request) {
3824
- const singularType = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3905
+ const singularType = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3825
3906
  if (!_ObjectStackProtocolImplementation.isOverlayAllowed(singularType) && !_ObjectStackProtocolImplementation.isRuntimeCreateAllowed(singularType)) {
3826
3907
  return { events: [] };
3827
3908
  }
@@ -3845,7 +3926,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3845
3926
  * when there is nothing to publish.
3846
3927
  */
3847
3928
  async publishMetaItem(request) {
3848
- const singularType = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3929
+ const singularType = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3849
3930
  if (!_ObjectStackProtocolImplementation.isOverlayAllowed(singularType) && !_ObjectStackProtocolImplementation.isRuntimeCreateAllowed(singularType)) {
3850
3931
  const err = new Error(
3851
3932
  `[not_overridable] Metadata type '${request.type}' is not draftable \u2014 no overlay/runtime-create permission.`
@@ -3921,7 +4002,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3921
4002
  err.status = 400;
3922
4003
  throw err;
3923
4004
  }
3924
- const singularType = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
4005
+ const singularType = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3925
4006
  if (!_ObjectStackProtocolImplementation.isOverlayAllowed(singularType) && !_ObjectStackProtocolImplementation.isRuntimeCreateAllowed(singularType)) {
3926
4007
  const err = new Error(
3927
4008
  `[not_overridable] Metadata type '${request.type}' is not revertable \u2014 no overlay/runtime-create permission.`
@@ -3992,7 +4073,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
3992
4073
  * are reported as a single change record.
3993
4074
  */
3994
4075
  async diffMetaItem(request) {
3995
- const singularType = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
4076
+ const singularType = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
3996
4077
  const orgId = request.organizationId ?? null;
3997
4078
  const events = (await this.historyMetaItem({
3998
4079
  type: singularType,
@@ -4094,7 +4175,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4094
4175
  });
4095
4176
  if (lockErr) throw lockErr;
4096
4177
  }
4097
- const singularTypeForRepo = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
4178
+ const singularTypeForRepo = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
4098
4179
  const overlayAllowedForRepoDel = _ObjectStackProtocolImplementation.isOverlayAllowed(singularTypeForRepo);
4099
4180
  const runtimeCreateAllowedForRepoDel = _ObjectStackProtocolImplementation.isRuntimeCreateAllowed(singularTypeForRepo);
4100
4181
  const useRepoPath = overlayAllowedForRepoDel || runtimeCreateAllowedForRepoDel;
@@ -4230,7 +4311,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4230
4311
  for (const record of records) {
4231
4312
  try {
4232
4313
  const data = typeof record.metadata === "string" ? JSON.parse(record.metadata) : record.metadata;
4233
- const normalizedType = import_shared3.PLURAL_TO_SINGULAR[record.type] ?? record.type;
4314
+ const normalizedType = import_shared4.PLURAL_TO_SINGULAR[record.type] ?? record.type;
4234
4315
  if (normalizedType === "object") {
4235
4316
  this.engine.registry.registerObject(data, record.packageId || "sys_metadata");
4236
4317
  } else {
@@ -4264,7 +4345,7 @@ var _ObjectStackProtocolImplementation = class _ObjectStackProtocolImplementatio
4264
4345
  * — the engine never throws.
4265
4346
  */
4266
4347
  async findReferencesToMeta(request) {
4267
- const singularTarget = import_shared3.PLURAL_TO_SINGULAR[request.type] ?? request.type;
4348
+ const singularTarget = import_shared4.PLURAL_TO_SINGULAR[request.type] ?? request.type;
4268
4349
  const targetName = request.name;
4269
4350
  const matchers = REFERENCE_PATHS[singularTarget];
4270
4351
  if (!matchers || matchers.length === 0) {
@@ -4458,13 +4539,13 @@ _ObjectStackProtocolImplementation.OVERLAY_ALLOWED_TYPES = (() => {
4458
4539
  for (const entry of import_kernel4.DEFAULT_METADATA_TYPE_REGISTRY) {
4459
4540
  if (!entry.allowOrgOverride) continue;
4460
4541
  out.add(entry.type);
4461
- const plural = import_shared3.SINGULAR_TO_PLURAL[entry.type];
4542
+ const plural = import_shared4.SINGULAR_TO_PLURAL[entry.type];
4462
4543
  if (plural) out.add(plural);
4463
4544
  }
4464
4545
  return out;
4465
4546
  })();
4466
4547
  /**
4467
- * Phase 3a-env-writable: parse `OBJECTSTACK_METADATA_WRITABLE` once.
4548
+ * Phase 3a-env-writable: parse `OS_METADATA_WRITABLE` once.
4468
4549
  * Comma-separated singular type names. When the env var is set, the
4469
4550
  * listed types get treated as `allowOrgOverride: true` regardless of
4470
4551
  * their static registry entry. This is the runtime escape hatch admins
@@ -4495,7 +4576,7 @@ _ObjectStackProtocolImplementation.STATIC_REGISTRY_TYPES = (() => {
4495
4576
  const out = /* @__PURE__ */ new Set();
4496
4577
  for (const entry of import_kernel4.DEFAULT_METADATA_TYPE_REGISTRY) {
4497
4578
  out.add(entry.type);
4498
- const plural = import_shared3.SINGULAR_TO_PLURAL[entry.type];
4579
+ const plural = import_shared4.SINGULAR_TO_PLURAL[entry.type];
4499
4580
  if (plural) out.add(plural);
4500
4581
  }
4501
4582
  return out;
@@ -4505,7 +4586,7 @@ _ObjectStackProtocolImplementation.RUNTIME_CREATE_ALLOWED_TYPES = (() => {
4505
4586
  for (const entry of import_kernel4.DEFAULT_METADATA_TYPE_REGISTRY) {
4506
4587
  if (!entry.allowRuntimeCreate) continue;
4507
4588
  out.add(entry.type);
4508
- const plural = import_shared3.SINGULAR_TO_PLURAL[entry.type];
4589
+ const plural = import_shared4.SINGULAR_TO_PLURAL[entry.type];
4509
4590
  if (plural) out.add(plural);
4510
4591
  }
4511
4592
  return out;
@@ -4516,7 +4597,7 @@ var ObjectStackProtocolImplementation = _ObjectStackProtocolImplementation;
4516
4597
  var import_kernel6 = require("@objectstack/spec/kernel");
4517
4598
  var import_core = require("@objectstack/core");
4518
4599
  var import_system2 = require("@objectstack/spec/system");
4519
- var import_shared4 = require("@objectstack/spec/shared");
4600
+ var import_shared5 = require("@objectstack/spec/shared");
4520
4601
  var import_formula2 = require("@objectstack/formula");
4521
4602
 
4522
4603
  // src/hook-wrappers.ts
@@ -5769,6 +5850,8 @@ var _ObjectQL = class _ObjectQL {
5769
5850
  "policies",
5770
5851
  // AI Protocol
5771
5852
  "agents",
5853
+ "tools",
5854
+ "skills",
5772
5855
  "ragPipelines",
5773
5856
  // API Protocol
5774
5857
  "apis",
@@ -5787,9 +5870,9 @@ var _ObjectQL = class _ObjectQL {
5787
5870
  const itemName = resolveMetadataItemName(key, item);
5788
5871
  if (itemName) {
5789
5872
  const toRegister = item.name === itemName ? item : { ...item, name: itemName };
5790
- this._registry.registerItem((0, import_shared4.pluralToSingular)(key), toRegister, "name", id);
5873
+ this._registry.registerItem((0, import_shared5.pluralToSingular)(key), toRegister, "name", id);
5791
5874
  } else {
5792
- this.logger.warn(`Skipping ${(0, import_shared4.pluralToSingular)(key)} without a derivable name`, { id });
5875
+ this.logger.warn(`Skipping ${(0, import_shared5.pluralToSingular)(key)} without a derivable name`, { id });
5793
5876
  }
5794
5877
  }
5795
5878
  }
@@ -5916,7 +5999,7 @@ var _ObjectQL = class _ObjectQL {
5916
5999
  const itemName = resolveMetadataItemName(key, item);
5917
6000
  if (itemName) {
5918
6001
  const toRegister = item.name === itemName ? item : { ...item, name: itemName };
5919
- this._registry.registerItem((0, import_shared4.pluralToSingular)(key), toRegister, "name", ownerId);
6002
+ this._registry.registerItem((0, import_shared5.pluralToSingular)(key), toRegister, "name", ownerId);
5920
6003
  }
5921
6004
  }
5922
6005
  }