@objectstack/runtime 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
@@ -702,6 +702,52 @@ var init_seed_loader = __esm({
702
702
  }
703
703
  });
704
704
 
705
+ // src/package-state-store.ts
706
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
707
+ import { dirname as dirname2, join } from "path";
708
+ function sanitizeEnvironmentId(environmentId) {
709
+ const raw = (environmentId ?? process.env.OS_ENVIRONMENT_ID ?? DEFAULT_ENVIRONMENT_ID).trim();
710
+ const safe = raw.replace(/[^a-zA-Z0-9._-]/g, "_");
711
+ return safe.length > 0 ? safe : DEFAULT_ENVIRONMENT_ID;
712
+ }
713
+ function stateFilePath(environmentId) {
714
+ return join(resolveObjectStackHome(), "package-state", `${sanitizeEnvironmentId(environmentId)}.json`);
715
+ }
716
+ function readState(environmentId) {
717
+ const file = stateFilePath(environmentId);
718
+ if (!existsSync(file)) return {};
719
+ try {
720
+ const parsed = JSON.parse(readFileSync(file, "utf8"));
721
+ return parsed && typeof parsed === "object" ? parsed : {};
722
+ } catch {
723
+ return {};
724
+ }
725
+ }
726
+ function writeState(environmentId, state) {
727
+ const file = stateFilePath(environmentId);
728
+ mkdirSync(dirname2(file), { recursive: true });
729
+ writeFileSync(file, `${JSON.stringify(state, null, 2)}
730
+ `, "utf8");
731
+ }
732
+ function loadDisabledPackageIds(environmentId) {
733
+ const disabled = readState(environmentId).disabled;
734
+ return new Set(Array.isArray(disabled) ? disabled.filter((id) => typeof id === "string") : []);
735
+ }
736
+ function setPackageDisabled(environmentId, packageId, disabled) {
737
+ const ids = loadDisabledPackageIds(environmentId);
738
+ if (disabled) ids.add(packageId);
739
+ else ids.delete(packageId);
740
+ writeState(environmentId, { disabled: Array.from(ids).sort() });
741
+ }
742
+ var DEFAULT_ENVIRONMENT_ID;
743
+ var init_package_state_store = __esm({
744
+ "src/package-state-store.ts"() {
745
+ "use strict";
746
+ init_standalone_stack();
747
+ DEFAULT_ENVIRONMENT_ID = "default";
748
+ }
749
+ });
750
+
705
751
  // src/sandbox/quickjs-runner.ts
706
752
  import {
707
753
  newAsyncContext
@@ -1202,6 +1248,7 @@ __export(app_plugin_exports, {
1202
1248
  collectBundleFunctions: () => collectBundleFunctions,
1203
1249
  collectBundleHooks: () => collectBundleHooks
1204
1250
  });
1251
+ import { readEnvWithDeprecation } from "@objectstack/types";
1205
1252
  function collectBundleHooks(bundle) {
1206
1253
  const out = [];
1207
1254
  const seen = /* @__PURE__ */ new Set();
@@ -1266,6 +1313,7 @@ var init_app_plugin = __esm({
1266
1313
  "src/app-plugin.ts"() {
1267
1314
  "use strict";
1268
1315
  init_seed_loader();
1316
+ init_package_state_store();
1269
1317
  init_quickjs_runner();
1270
1318
  init_body_runner();
1271
1319
  AppPlugin = class {
@@ -1291,6 +1339,24 @@ var init_app_plugin = __esm({
1291
1339
  console.warn(
1292
1340
  `[AppPlugin:init] appId=${appId} keys=${Object.keys(servicePayload).join(",")} flows=${Array.isArray(servicePayload.flows) ? servicePayload.flows.length : "n/a"}`
1293
1341
  );
1342
+ try {
1343
+ const ql = ctx.getService("objectql");
1344
+ const setter = ql?.registry?.setInitialDisabledPackageIds;
1345
+ if (typeof setter === "function") {
1346
+ const disabled = loadDisabledPackageIds(this.projectContext?.environmentId);
1347
+ if (disabled.size > 0) {
1348
+ setter.call(ql.registry, disabled);
1349
+ ctx.logger.info("[AppPlugin] seeded persisted disabled packages", {
1350
+ environmentId: this.projectContext?.environmentId,
1351
+ disabled: Array.from(disabled)
1352
+ });
1353
+ }
1354
+ }
1355
+ } catch (err) {
1356
+ ctx.logger.warn("[AppPlugin] failed to seed persisted package state", {
1357
+ error: err?.message ?? String(err)
1358
+ });
1359
+ }
1294
1360
  ctx.getService("manifest").register(servicePayload);
1295
1361
  };
1296
1362
  this.start = async (ctx) => {
@@ -1591,7 +1657,7 @@ var init_app_plugin = __esm({
1591
1657
  } catch (e) {
1592
1658
  ctx.logger.warn("[Seeder] Failed to register seed-datasets/seed-replayer service", { error: e?.message });
1593
1659
  }
1594
- const multiTenant = String(process.env.OS_MULTI_TENANT ?? "false").toLowerCase() !== "false";
1660
+ const multiTenant = String(readEnvWithDeprecation("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
1595
1661
  if (multiTenant) {
1596
1662
  ctx.logger.info("[Seeder] multi-tenant mode \u2014 skipping inline seed; per-org replay will run on sys_organization insert");
1597
1663
  } else {
@@ -1835,6 +1901,170 @@ var init_app_plugin = __esm({
1835
1901
  }
1836
1902
  });
1837
1903
 
1904
+ // src/standalone-stack.ts
1905
+ import { resolve as resolvePath2 } from "path";
1906
+ import { mkdirSync as mkdirSync2 } from "fs";
1907
+ import { homedir } from "os";
1908
+ import { z } from "zod";
1909
+ import { readEnvWithDeprecation as readEnvWithDeprecation2 } from "@objectstack/types";
1910
+ function resolveObjectStackHome() {
1911
+ const raw = process.env.OS_HOME?.trim();
1912
+ if (raw && raw.length > 0) {
1913
+ if (raw.startsWith("~")) return resolvePath2(homedir(), raw.slice(1).replace(/^[/\\]/, ""));
1914
+ return resolvePath2(raw);
1915
+ }
1916
+ return resolvePath2(homedir(), ".objectstack");
1917
+ }
1918
+ function detectDriverFromUrl(dbUrl) {
1919
+ if (/^memory:\/\//i.test(dbUrl)) return "memory";
1920
+ if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return "postgres";
1921
+ if (/^mongodb(\+srv)?:\/\//i.test(dbUrl)) return "mongodb";
1922
+ if (/^wasm-sqlite:\/\//i.test(dbUrl)) return "sqlite-wasm";
1923
+ if (/\.wasm\.db$/i.test(dbUrl)) return "sqlite-wasm";
1924
+ if (/^file:/i.test(dbUrl)) return "sqlite";
1925
+ if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(dbUrl)) return "sqlite";
1926
+ throw new Error(
1927
+ `[StandaloneStack] Unsupported database URL scheme: ${dbUrl}. Supported schemes: memory://, postgres://, pg://, mongodb://, mongodb+srv://, file:`
1928
+ );
1929
+ }
1930
+ async function createStandaloneStack(config) {
1931
+ const cfg = StandaloneStackConfigSchema.parse(config ?? {});
1932
+ const { ObjectQLPlugin } = await import("@objectstack/objectql");
1933
+ const { MetadataPlugin } = await import("@objectstack/metadata");
1934
+ const { DriverPlugin: DriverPlugin2 } = await Promise.resolve().then(() => (init_driver_plugin(), driver_plugin_exports));
1935
+ const { AppPlugin: AppPlugin2 } = await Promise.resolve().then(() => (init_app_plugin(), app_plugin_exports));
1936
+ const cwd = process.cwd();
1937
+ const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
1938
+ const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath2(cwd, "dist/objectstack.json");
1939
+ const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : resolvePath2(cwd, artifactPathInput);
1940
+ const dbUrl = cfg.databaseUrl ?? readEnvWithDeprecation2("OS_DATABASE_URL", "DATABASE_URL")?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}` : cfg.projectRoot ? `file:${resolvePath2(cfg.projectRoot, ".objectstack/data/standalone.db")}` : `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}`);
1941
+ const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
1942
+ const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
1943
+ let driverPlugin;
1944
+ if (dbDriver === "memory") {
1945
+ const { InMemoryDriver } = await import("@objectstack/driver-memory");
1946
+ driverPlugin = new DriverPlugin2(new InMemoryDriver());
1947
+ } else if (dbDriver === "postgres") {
1948
+ const { SqlDriver } = await import("@objectstack/driver-sql");
1949
+ driverPlugin = new DriverPlugin2(
1950
+ new SqlDriver({
1951
+ client: "pg",
1952
+ connection: dbUrl,
1953
+ pool: { min: 0, max: 5 }
1954
+ })
1955
+ );
1956
+ } else if (dbDriver === "mongodb") {
1957
+ let MongoDBDriver;
1958
+ try {
1959
+ ({ MongoDBDriver } = await import("@objectstack/driver-mongodb"));
1960
+ } catch (err) {
1961
+ throw new Error(
1962
+ `[StandaloneStack] mongodb URL detected but @objectstack/driver-mongodb is not installed. Add it as a dependency or pass an explicit driverPlugin. (${err?.message ?? err})`
1963
+ );
1964
+ }
1965
+ driverPlugin = new DriverPlugin2(new MongoDBDriver({ url: dbUrl }));
1966
+ } else if (dbDriver === "sqlite-wasm") {
1967
+ const { SqliteWasmDriver } = await import("@objectstack/driver-sqlite-wasm");
1968
+ const filename = dbUrl.replace(/^wasm-sqlite:(\/\/)?/i, "").replace(/^file:(\/\/)?/i, "");
1969
+ if (filename && filename !== ":memory:") {
1970
+ mkdirSync2(resolvePath2(filename, ".."), { recursive: true });
1971
+ }
1972
+ driverPlugin = new DriverPlugin2(
1973
+ new SqliteWasmDriver({
1974
+ filename: filename || ":memory:",
1975
+ persist: filename && filename !== ":memory:" ? "on-write" : void 0
1976
+ })
1977
+ );
1978
+ } else {
1979
+ const { SqlDriver } = await import("@objectstack/driver-sql");
1980
+ const filename = dbUrl.replace(/^file:(\/\/)?/, "");
1981
+ if (!filename || /^[a-z][a-z0-9+.-]*:\/\//i.test(filename)) {
1982
+ throw new Error(
1983
+ `[StandaloneStack] sqlite driver was selected but the URL does not look like a file path: "${dbUrl}". Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.`
1984
+ );
1985
+ }
1986
+ mkdirSync2(resolvePath2(filename, ".."), { recursive: true });
1987
+ driverPlugin = new DriverPlugin2(
1988
+ new SqlDriver({
1989
+ client: "better-sqlite3",
1990
+ connection: { filename },
1991
+ useNullAsDefault: true
1992
+ })
1993
+ );
1994
+ }
1995
+ const artifactBundle = await loadArtifactBundle(artifactPath, {
1996
+ tag: "[StandaloneStack]",
1997
+ unwrapEnvelope: true
1998
+ });
1999
+ if (artifactBundle) {
2000
+ const flowsCount = Array.isArray(artifactBundle?.flows) ? artifactBundle.flows.length : "n/a";
2001
+ console.warn(
2002
+ `[StandaloneStack] artifact loaded: path=${artifactPath} keys=${Object.keys(artifactBundle).join(",")} flows=${flowsCount}`
2003
+ );
2004
+ }
2005
+ const plugins = [
2006
+ driverPlugin,
2007
+ new MetadataPlugin({
2008
+ // Source-file scanner OFF — declarative metadata is loaded
2009
+ // from the compiled artifact, not from yaml/json files on
2010
+ // disk. Scanning would also recursively watch the project
2011
+ // root (incl. node_modules), which is expensive and prone
2012
+ // to EMFILE.
2013
+ watch: false,
2014
+ // Artifact-file HMR ON in non-production so edits to
2015
+ // `*.view.ts` / `*.flow.ts` (which the CLI dev-mode watcher
2016
+ // recompiles into `dist/objectstack.json`) are picked up by
2017
+ // the running server WITHOUT requiring a manual restart.
2018
+ // Uses polling under the hood (see plugin.ts) to avoid
2019
+ // `fs.watch` EMFILE on macOS / busy dev hosts.
2020
+ artifactWatch: process.env.NODE_ENV !== "production",
2021
+ environmentId,
2022
+ artifactSource: { mode: "local-file", path: artifactPath }
2023
+ }),
2024
+ new ObjectQLPlugin({ environmentId })
2025
+ ];
2026
+ if (artifactBundle) plugins.push(new AppPlugin2(artifactBundle));
2027
+ const requires = Array.isArray(artifactBundle?.requires) ? artifactBundle.requires.filter((c) => typeof c === "string") : void 0;
2028
+ const objects = Array.isArray(artifactBundle?.objects) ? artifactBundle.objects : void 0;
2029
+ const manifest = artifactBundle?.manifest;
2030
+ return {
2031
+ plugins,
2032
+ api: {
2033
+ enableProjectScoping: false,
2034
+ projectResolution: "none"
2035
+ },
2036
+ ...requires ? { requires } : {},
2037
+ ...objects ? { objects } : {},
2038
+ ...manifest ? { manifest } : {}
2039
+ };
2040
+ }
2041
+ var StandaloneStackConfigSchema;
2042
+ var init_standalone_stack = __esm({
2043
+ "src/standalone-stack.ts"() {
2044
+ "use strict";
2045
+ init_load_artifact_bundle();
2046
+ StandaloneStackConfigSchema = z.object({
2047
+ databaseUrl: z.string().optional(),
2048
+ databaseAuthToken: z.string().optional(),
2049
+ databaseDriver: z.enum(["sqlite", "sqlite-wasm", "memory", "postgres", "mongodb"]).optional(),
2050
+ environmentId: z.string().optional(),
2051
+ artifactPath: z.string().optional(),
2052
+ /**
2053
+ * Project root directory. When set (typically by the CLI after locating
2054
+ * `objectstack.config.ts`), the default sqlite database is placed under
2055
+ * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2056
+ * `~/.objectstack/data/standalone.db`. This keeps per-project data
2057
+ * scoped to the project folder so different examples / apps don't
2058
+ * share a single database by accident.
2059
+ *
2060
+ * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2061
+ * precedence over this default.
2062
+ */
2063
+ projectRoot: z.string().optional()
2064
+ });
2065
+ }
2066
+ });
2067
+
1838
2068
  // src/cloud/platform-sso.ts
1839
2069
  var platform_sso_exports = {};
1840
2070
  __export(platform_sso_exports, {
@@ -2239,172 +2469,19 @@ var Runtime = class {
2239
2469
  }
2240
2470
  };
2241
2471
 
2242
- // src/standalone-stack.ts
2243
- init_load_artifact_bundle();
2244
- import { resolve as resolvePath2 } from "path";
2245
- import { mkdirSync } from "fs";
2246
- import { homedir } from "os";
2247
- import { z } from "zod";
2248
- function resolveObjectStackHome() {
2249
- const raw = process.env.OS_HOME?.trim();
2250
- if (raw && raw.length > 0) {
2251
- if (raw.startsWith("~")) return resolvePath2(homedir(), raw.slice(1).replace(/^[/\\]/, ""));
2252
- return resolvePath2(raw);
2253
- }
2254
- return resolvePath2(homedir(), ".objectstack");
2255
- }
2256
- var StandaloneStackConfigSchema = z.object({
2257
- databaseUrl: z.string().optional(),
2258
- databaseAuthToken: z.string().optional(),
2259
- databaseDriver: z.enum(["sqlite", "sqlite-wasm", "memory", "postgres", "mongodb"]).optional(),
2260
- environmentId: z.string().optional(),
2261
- artifactPath: z.string().optional(),
2262
- /**
2263
- * Project root directory. When set (typically by the CLI after locating
2264
- * `objectstack.config.ts`), the default sqlite database is placed under
2265
- * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2266
- * `~/.objectstack/data/standalone.db`. This keeps per-project data
2267
- * scoped to the project folder so different examples / apps don't
2268
- * share a single database by accident.
2269
- *
2270
- * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2271
- * precedence over this default.
2272
- */
2273
- projectRoot: z.string().optional()
2274
- });
2275
- function detectDriverFromUrl(dbUrl) {
2276
- if (/^memory:\/\//i.test(dbUrl)) return "memory";
2277
- if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return "postgres";
2278
- if (/^mongodb(\+srv)?:\/\//i.test(dbUrl)) return "mongodb";
2279
- if (/^wasm-sqlite:\/\//i.test(dbUrl)) return "sqlite-wasm";
2280
- if (/\.wasm\.db$/i.test(dbUrl)) return "sqlite-wasm";
2281
- if (/^file:/i.test(dbUrl)) return "sqlite";
2282
- if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(dbUrl)) return "sqlite";
2283
- throw new Error(
2284
- `[StandaloneStack] Unsupported database URL scheme: ${dbUrl}. Supported schemes: memory://, postgres://, pg://, mongodb://, mongodb+srv://, file:`
2285
- );
2286
- }
2287
- async function createStandaloneStack(config) {
2288
- const cfg = StandaloneStackConfigSchema.parse(config ?? {});
2289
- const { ObjectQLPlugin } = await import("@objectstack/objectql");
2290
- const { MetadataPlugin } = await import("@objectstack/metadata");
2291
- const { DriverPlugin: DriverPlugin2 } = await Promise.resolve().then(() => (init_driver_plugin(), driver_plugin_exports));
2292
- const { AppPlugin: AppPlugin2 } = await Promise.resolve().then(() => (init_app_plugin(), app_plugin_exports));
2293
- const cwd = process.cwd();
2294
- const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
2295
- const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath2(cwd, "dist/objectstack.json");
2296
- const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : resolvePath2(cwd, artifactPathInput);
2297
- const dbUrl = cfg.databaseUrl ?? process.env.OS_DATABASE_URL?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}` : cfg.projectRoot ? `file:${resolvePath2(cfg.projectRoot, ".objectstack/data/standalone.db")}` : `file:${resolvePath2(resolveObjectStackHome(), "data/standalone.db")}`);
2298
- const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
2299
- const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
2300
- let driverPlugin;
2301
- if (dbDriver === "memory") {
2302
- const { InMemoryDriver } = await import("@objectstack/driver-memory");
2303
- driverPlugin = new DriverPlugin2(new InMemoryDriver());
2304
- } else if (dbDriver === "postgres") {
2305
- const { SqlDriver } = await import("@objectstack/driver-sql");
2306
- driverPlugin = new DriverPlugin2(
2307
- new SqlDriver({
2308
- client: "pg",
2309
- connection: dbUrl,
2310
- pool: { min: 0, max: 5 }
2311
- })
2312
- );
2313
- } else if (dbDriver === "mongodb") {
2314
- let MongoDBDriver;
2315
- try {
2316
- ({ MongoDBDriver } = await import("@objectstack/driver-mongodb"));
2317
- } catch (err) {
2318
- throw new Error(
2319
- `[StandaloneStack] mongodb URL detected but @objectstack/driver-mongodb is not installed. Add it as a dependency or pass an explicit driverPlugin. (${err?.message ?? err})`
2320
- );
2321
- }
2322
- driverPlugin = new DriverPlugin2(new MongoDBDriver({ url: dbUrl }));
2323
- } else if (dbDriver === "sqlite-wasm") {
2324
- const { SqliteWasmDriver } = await import("@objectstack/driver-sqlite-wasm");
2325
- const filename = dbUrl.replace(/^wasm-sqlite:(\/\/)?/i, "").replace(/^file:(\/\/)?/i, "");
2326
- if (filename && filename !== ":memory:") {
2327
- mkdirSync(resolvePath2(filename, ".."), { recursive: true });
2328
- }
2329
- driverPlugin = new DriverPlugin2(
2330
- new SqliteWasmDriver({
2331
- filename: filename || ":memory:",
2332
- persist: filename && filename !== ":memory:" ? "on-write" : void 0
2333
- })
2334
- );
2335
- } else {
2336
- const { SqlDriver } = await import("@objectstack/driver-sql");
2337
- const filename = dbUrl.replace(/^file:(\/\/)?/, "");
2338
- if (!filename || /^[a-z][a-z0-9+.-]*:\/\//i.test(filename)) {
2339
- throw new Error(
2340
- `[StandaloneStack] sqlite driver was selected but the URL does not look like a file path: "${dbUrl}". Use file:/path/to/db.sqlite, or set OS_DATABASE_DRIVER explicitly.`
2341
- );
2342
- }
2343
- mkdirSync(resolvePath2(filename, ".."), { recursive: true });
2344
- driverPlugin = new DriverPlugin2(
2345
- new SqlDriver({
2346
- client: "better-sqlite3",
2347
- connection: { filename },
2348
- useNullAsDefault: true
2349
- })
2350
- );
2351
- }
2352
- const artifactBundle = await loadArtifactBundle(artifactPath, {
2353
- tag: "[StandaloneStack]",
2354
- unwrapEnvelope: true
2355
- });
2356
- if (artifactBundle) {
2357
- const flowsCount = Array.isArray(artifactBundle?.flows) ? artifactBundle.flows.length : "n/a";
2358
- console.warn(
2359
- `[StandaloneStack] artifact loaded: path=${artifactPath} keys=${Object.keys(artifactBundle).join(",")} flows=${flowsCount}`
2360
- );
2361
- }
2362
- const plugins = [
2363
- driverPlugin,
2364
- new MetadataPlugin({
2365
- // Source-file scanner OFF — declarative metadata is loaded
2366
- // from the compiled artifact, not from yaml/json files on
2367
- // disk. Scanning would also recursively watch the project
2368
- // root (incl. node_modules), which is expensive and prone
2369
- // to EMFILE.
2370
- watch: false,
2371
- // Artifact-file HMR ON in non-production so edits to
2372
- // `*.view.ts` / `*.flow.ts` (which the CLI dev-mode watcher
2373
- // recompiles into `dist/objectstack.json`) are picked up by
2374
- // the running server WITHOUT requiring a manual restart.
2375
- // Uses polling under the hood (see plugin.ts) to avoid
2376
- // `fs.watch` EMFILE on macOS / busy dev hosts.
2377
- artifactWatch: process.env.NODE_ENV !== "production",
2378
- environmentId,
2379
- artifactSource: { mode: "local-file", path: artifactPath }
2380
- }),
2381
- new ObjectQLPlugin({ environmentId })
2382
- ];
2383
- if (artifactBundle) plugins.push(new AppPlugin2(artifactBundle));
2384
- const requires = Array.isArray(artifactBundle?.requires) ? artifactBundle.requires.filter((c) => typeof c === "string") : void 0;
2385
- const objects = Array.isArray(artifactBundle?.objects) ? artifactBundle.objects : void 0;
2386
- const manifest = artifactBundle?.manifest;
2387
- return {
2388
- plugins,
2389
- api: {
2390
- enableProjectScoping: false,
2391
- projectResolution: "none"
2392
- },
2393
- ...requires ? { requires } : {},
2394
- ...objects ? { objects } : {},
2395
- ...manifest ? { manifest } : {}
2396
- };
2397
- }
2472
+ // src/index.ts
2473
+ init_standalone_stack();
2398
2474
 
2399
2475
  // src/default-host.ts
2400
- import { resolve as resolvePath3 } from "path";
2401
- import { existsSync, mkdirSync as mkdirSync2, writeFileSync } from "fs";
2476
+ init_standalone_stack();
2402
2477
  init_load_artifact_bundle();
2478
+ import { resolve as resolvePath3 } from "path";
2479
+ import { existsSync as existsSync2, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
2403
2480
  function resolveDefaultArtifactPath(explicitPath, cwd = process.cwd()) {
2404
2481
  const candidate = explicitPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath3(cwd, "dist/objectstack.json");
2405
2482
  if (isHttpUrl(candidate)) return candidate;
2406
2483
  if (explicitPath || process.env.OS_ARTIFACT_PATH) return candidate;
2407
- return existsSync(candidate) ? candidate : void 0;
2484
+ return existsSync2(candidate) ? candidate : void 0;
2408
2485
  }
2409
2486
  async function createDefaultHostConfig(options = {}) {
2410
2487
  const { requireArtifact = true, ...standaloneOpts } = options;
@@ -2417,9 +2494,9 @@ async function createDefaultHostConfig(options = {}) {
2417
2494
  if (!resolvedArtifact && !requireArtifact) {
2418
2495
  const home = resolveObjectStackHome();
2419
2496
  const stubPath = resolvePath3(home, "dist/objectstack.json");
2420
- if (!existsSync(stubPath)) {
2421
- mkdirSync2(resolvePath3(stubPath, ".."), { recursive: true });
2422
- writeFileSync(
2497
+ if (!existsSync2(stubPath)) {
2498
+ mkdirSync3(resolvePath3(stubPath, ".."), { recursive: true });
2499
+ writeFileSync2(
2423
2500
  stubPath,
2424
2501
  JSON.stringify(
2425
2502
  {
@@ -2456,9 +2533,11 @@ init_app_plugin();
2456
2533
  init_seed_loader();
2457
2534
 
2458
2535
  // src/http-dispatcher.ts
2536
+ init_package_state_store();
2459
2537
  import { getEnv, resolveLocale } from "@objectstack/core";
2538
+ import { readEnvWithDeprecation as readEnvWithDeprecation3 } from "@objectstack/types";
2460
2539
  import { CoreServiceName } from "@objectstack/spec/system";
2461
- import { pluralToSingular } from "@objectstack/spec/shared";
2540
+ import { pluralToSingular, PLURAL_TO_SINGULAR } from "@objectstack/spec/shared";
2462
2541
 
2463
2542
  // src/security/resolve-execution-context.ts
2464
2543
  function readHeader(headers, name) {
@@ -3313,7 +3392,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3313
3392
  if (protocol && typeof protocol.saveMetaItem === "function") {
3314
3393
  try {
3315
3394
  const organizationId = await this.resolveActiveOrganizationId(_context);
3316
- const result = await protocol.saveMetaItem({ type, name, item: body, organizationId });
3395
+ const result = await protocol.saveMetaItem({ type, name, item: body, organizationId, ...packageId ? { packageId } : {} });
3317
3396
  return { handled: true, response: this.success(result) };
3318
3397
  } catch (e) {
3319
3398
  return { handled: true, response: this.error(e.message, 400) };
@@ -3653,12 +3732,22 @@ var _HttpDispatcher = class _HttpDispatcher {
3653
3732
  const id = decodeURIComponent(parts[0]);
3654
3733
  const pkg = registry.enablePackage(id);
3655
3734
  if (!pkg) return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3735
+ try {
3736
+ setPackageDisabled(_context?.environmentId, id, false);
3737
+ } catch (err) {
3738
+ console.warn("[handlePackages] failed to persist enable state", { id, error: err?.message });
3739
+ }
3656
3740
  return { handled: true, response: this.success(pkg) };
3657
3741
  }
3658
3742
  if (parts.length === 2 && parts[1] === "disable" && m === "PATCH") {
3659
3743
  const id = decodeURIComponent(parts[0]);
3660
3744
  const pkg = registry.disablePackage(id);
3661
3745
  if (!pkg) return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3746
+ try {
3747
+ setPackageDisabled(_context?.environmentId, id, true);
3748
+ } catch (err) {
3749
+ console.warn("[handlePackages] failed to persist disable state", { id, error: err?.message });
3750
+ }
3662
3751
  return { handled: true, response: this.success(pkg) };
3663
3752
  }
3664
3753
  if (parts.length === 2 && parts[1] === "publish" && m === "POST") {
@@ -3679,6 +3768,14 @@ var _HttpDispatcher = class _HttpDispatcher {
3679
3768
  }
3680
3769
  return { handled: true, response: this.error("Metadata service not available", 503) };
3681
3770
  }
3771
+ if (parts.length === 2 && parts[1] === "export" && m === "GET") {
3772
+ const id = decodeURIComponent(parts[0]);
3773
+ const manifest = await this.assemblePackageManifest(id, registry, _context);
3774
+ if (!manifest) {
3775
+ return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3776
+ }
3777
+ return { handled: true, response: this.success(manifest) };
3778
+ }
3682
3779
  if (parts.length === 1 && m === "GET") {
3683
3780
  const id = decodeURIComponent(parts[0]);
3684
3781
  const pkg = registry.getPackage(id);
@@ -3696,6 +3793,83 @@ var _HttpDispatcher = class _HttpDispatcher {
3696
3793
  }
3697
3794
  return { handled: false };
3698
3795
  }
3796
+ /**
3797
+ * Assemble a portable, offline-installable package manifest from the
3798
+ * `sys_metadata` overlay rows bound to `packageId`.
3799
+ *
3800
+ * The resulting shape mirrors what `marketplace-install-local` →
3801
+ * `manifestService.register()` → `engine.registerApp()` consumes:
3802
+ * `{ id, name, version, objects:[…], views:[…], flows:[…], … }`
3803
+ * where each category key is the PLURAL manifest name and its value is
3804
+ * an array of clean metadata bodies (provenance decorations stripped).
3805
+ *
3806
+ * Only the metadata categories that `registerApp` can actually consume
3807
+ * are exported. `datasources` and `emailTemplates` are intentionally
3808
+ * excluded (not registered by the import path). `tools` / `skills` ARE
3809
+ * round-tripped: they are registered by `registerApp` on import and
3810
+ * surfaced by `getMetaItems('tool' | 'skill')` on export.
3811
+ *
3812
+ * @returns the manifest object, or `null` if the package id is unknown
3813
+ * AND has no overlay-authored metadata.
3814
+ */
3815
+ async assemblePackageManifest(packageId, registry, context) {
3816
+ const protocol = await this.resolveService("protocol");
3817
+ if (!protocol || typeof protocol.getMetaItems !== "function") return null;
3818
+ const organizationId = await this.resolveActiveOrganizationId(context);
3819
+ const PROVENANCE_KEYS = /* @__PURE__ */ new Set([
3820
+ "_packageId",
3821
+ "_packageVersionId",
3822
+ "_provenance",
3823
+ "_state",
3824
+ "_version",
3825
+ "_organizationId",
3826
+ "_source",
3827
+ "_id",
3828
+ "_rowId"
3829
+ ]);
3830
+ const clean = (item) => {
3831
+ if (!item || typeof item !== "object") return item;
3832
+ const out = {};
3833
+ for (const [k, v] of Object.entries(item)) {
3834
+ if (k.startsWith("_") || PROVENANCE_KEYS.has(k)) continue;
3835
+ out[k] = v;
3836
+ }
3837
+ return out;
3838
+ };
3839
+ const exportPluralKeys = Object.keys(PLURAL_TO_SINGULAR).filter(
3840
+ (k) => k !== "datasources" && k !== "emailTemplates"
3841
+ );
3842
+ const manifest = {};
3843
+ let total = 0;
3844
+ for (const plural of exportPluralKeys) {
3845
+ const singular = PLURAL_TO_SINGULAR[plural];
3846
+ let items = [];
3847
+ try {
3848
+ const res = await protocol.getMetaItems({ type: singular, packageId, organizationId });
3849
+ items = Array.isArray(res?.items) ? res.items : [];
3850
+ } catch {
3851
+ continue;
3852
+ }
3853
+ if (items.length === 0) continue;
3854
+ manifest[plural] = items.map(clean);
3855
+ total += items.length;
3856
+ }
3857
+ const pkg = (() => {
3858
+ try {
3859
+ return registry?.getPackage?.(packageId);
3860
+ } catch {
3861
+ return void 0;
3862
+ }
3863
+ })();
3864
+ if (total === 0 && !pkg) return null;
3865
+ manifest.id = packageId;
3866
+ manifest.name = pkg?.manifest?.name ?? pkg?.name ?? packageId;
3867
+ manifest.version = pkg?.manifest?.version ?? pkg?.version ?? "1.0.0";
3868
+ if (pkg?.manifest?.label ?? pkg?.label) {
3869
+ manifest.label = pkg?.manifest?.label ?? pkg?.label;
3870
+ }
3871
+ return manifest;
3872
+ }
3699
3873
  /**
3700
3874
  * Cloud / Environment Control-Plane routes.
3701
3875
  *
@@ -3947,7 +4121,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3947
4121
  }
3948
4122
  }
3949
4123
  if (parts.length === 3 && parts[0] === "admin" && parts[1] === "platform-sso" && parts[2] === "backfill" && m === "POST") {
3950
- const baseSecret = (process.env.OS_AUTH_SECRET ?? process.env.AUTH_SECRET ?? "").trim();
4124
+ const baseSecret = (readEnvWithDeprecation3("OS_AUTH_SECRET", ["AUTH_SECRET", "BETTER_AUTH_SECRET"]) ?? "").trim();
3951
4125
  if (!baseSecret) {
3952
4126
  return { handled: true, response: this.error("OS_AUTH_SECRET not configured on this worker", 503) };
3953
4127
  }
@@ -4137,7 +4311,7 @@ var _HttpDispatcher = class _HttpDispatcher {
4137
4311
  });
4138
4312
  try {
4139
4313
  const { seedPlatformSsoClient: seedPlatformSsoClient2 } = await Promise.resolve().then(() => (init_platform_sso(), platform_sso_exports));
4140
- const baseSecret = (process.env.OS_AUTH_SECRET ?? process.env.AUTH_SECRET ?? "").trim();
4314
+ const baseSecret = (readEnvWithDeprecation3("OS_AUTH_SECRET", ["AUTH_SECRET", "BETTER_AUTH_SECRET"]) ?? "").trim();
4141
4315
  if (baseSecret) {
4142
4316
  await seedPlatformSsoClient2({
4143
4317
  ql,
@@ -6288,6 +6462,14 @@ function createDispatcherPlugin(config = {}) {
6288
6462
  errorResponse(err, res);
6289
6463
  }
6290
6464
  });
6465
+ server.get(`${prefix}/packages/:id/export`, async (req, res) => {
6466
+ try {
6467
+ const result = await dispatcher.handlePackages(`/${req.params.id}/export`, "GET", {}, req.query, { request: req });
6468
+ sendResult(result, res);
6469
+ } catch (err) {
6470
+ errorResponse(err, res);
6471
+ }
6472
+ });
6291
6473
  server.get(`${prefix}/packages/:id`, async (req, res) => {
6292
6474
  try {
6293
6475
  const result = await dispatcher.handlePackages(`/${req.params.id}`, "GET", {}, req.query, { request: req });
@@ -7607,6 +7789,7 @@ init_driver_plugin();
7607
7789
  init_app_plugin();
7608
7790
  import { createHmac as createHmac2 } from "crypto";
7609
7791
  import { ObjectKernel as ObjectKernel3 } from "@objectstack/core";
7792
+ import { readEnvWithDeprecation as readEnvWithDeprecation4 } from "@objectstack/types";
7610
7793
 
7611
7794
  // src/cloud/capability-loader.ts
7612
7795
  var CAPABILITY_PROVIDERS = {
@@ -7744,7 +7927,7 @@ var ArtifactKernelFactory = class {
7744
7927
  this.envRegistry = config.envRegistry;
7745
7928
  this.logger = config.logger ?? console;
7746
7929
  this.kernelConfig = config.kernelConfig;
7747
- this.authBaseSecret = (config.authBaseSecret ?? process.env.OS_AUTH_SECRET ?? process.env.AUTH_SECRET ?? "").trim();
7930
+ this.authBaseSecret = (config.authBaseSecret ?? readEnvWithDeprecation4("OS_AUTH_SECRET", ["AUTH_SECRET", "BETTER_AUTH_SECRET"]) ?? "").trim();
7748
7931
  }
7749
7932
  async create(environmentId) {
7750
7933
  let cached = this.envRegistry.peekById(environmentId);
@@ -7857,7 +8040,7 @@ var ArtifactKernelFactory = class {
7857
8040
  this.logger.warn?.("[ArtifactKernelFactory] OS_AUTH_SECRET not set \u2014 per-project AuthPlugin skipped (auth endpoints will return 404)", { environmentId });
7858
8041
  }
7859
8042
  try {
7860
- const multiTenant = String(process.env.OS_MULTI_TENANT ?? "false").toLowerCase() !== "false";
8043
+ const multiTenant = String(readEnvWithDeprecation4("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
7861
8044
  if (multiTenant) {
7862
8045
  try {
7863
8046
  const { OrgScopingPlugin } = await import("@objectstack/plugin-org-scoping");
@@ -8383,7 +8566,7 @@ var AuthProxyPlugin = class {
8383
8566
  };
8384
8567
 
8385
8568
  // src/cloud/cloud-url.ts
8386
- var DEFAULT_CLOUD_URL = "https://cloud.objectos.app";
8569
+ var DEFAULT_CLOUD_URL = "https://cloud.objectos.ai";
8387
8570
  function resolveCloudUrl(explicit) {
8388
8571
  const raw = (explicit ?? process.env.OS_CLOUD_URL ?? "").trim();
8389
8572
  const lower = raw.toLowerCase();
@@ -9058,8 +9241,9 @@ async function createObjectOSStack(config) {
9058
9241
  }
9059
9242
 
9060
9243
  // src/cloud/marketplace-install-local-plugin.ts
9061
- import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
9062
- import { join, resolve } from "path";
9244
+ import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync2, readdirSync, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
9245
+ import { join as join2, resolve } from "path";
9246
+ import { readEnvWithDeprecation as readEnvWithDeprecation5 } from "@objectstack/types";
9063
9247
  var ROUTE_BASE = "/api/v1/marketplace/install-local";
9064
9248
  var DEFAULT_DIR = ".objectstack/installed-packages";
9065
9249
  function safeFilename(manifestId) {
@@ -9134,9 +9318,6 @@ var MarketplaceInstallLocalPlugin = class {
9134
9318
  }
9135
9319
  };
9136
9320
  this.handleInstall = async (c, ctx) => {
9137
- if (!this.cloudUrl) {
9138
- return c.json({ success: false, error: { code: "marketplace_unavailable", message: "OS_CLOUD_URL not configured." } }, 503);
9139
- }
9140
9321
  const userId = await this.requireAuthenticatedUser(c, ctx);
9141
9322
  if (!userId) {
9142
9323
  return c.json({ success: false, error: { code: "unauthorized", message: "Authentication required to install packages." } }, 401);
@@ -9146,69 +9327,87 @@ var MarketplaceInstallLocalPlugin = class {
9146
9327
  body = await c.req.json();
9147
9328
  } catch {
9148
9329
  }
9149
- const packageId = String(body?.packageId ?? "").trim();
9150
- const versionId = String(body?.versionId ?? "latest").trim() || "latest";
9151
- if (!packageId) {
9152
- return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
9153
- }
9154
- let payload;
9155
- const publicBase = resolveMarketplacePublicBaseUrl();
9156
- const fetchAttempts = [];
9157
- if (publicBase) {
9330
+ const inlineManifest = body?.manifest && typeof body.manifest === "object" ? body.manifest : null;
9331
+ let manifest;
9332
+ let resolvedVersionId;
9333
+ let version;
9334
+ let packageId;
9335
+ if (inlineManifest) {
9336
+ manifest = inlineManifest;
9337
+ packageId = String(manifest.id ?? manifest.name ?? "").trim();
9338
+ version = String(manifest.version ?? "unknown");
9339
+ resolvedVersionId = String(body?.versionId ?? version);
9340
+ if (!packageId) {
9341
+ return c.json({ success: false, error: { code: "invalid_manifest", message: 'Inline manifest must have an "id" or "name".' } }, 400);
9342
+ }
9343
+ } else {
9344
+ if (!this.cloudUrl) {
9345
+ return c.json({ success: false, error: { code: "marketplace_unavailable", message: "OS_CLOUD_URL not configured." } }, 503);
9346
+ }
9347
+ packageId = String(body?.packageId ?? "").trim();
9348
+ const versionId = String(body?.versionId ?? "latest").trim() || "latest";
9349
+ if (!packageId) {
9350
+ return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
9351
+ }
9352
+ let payload;
9353
+ const publicBase = resolveMarketplacePublicBaseUrl();
9354
+ const fetchAttempts = [];
9355
+ if (publicBase) {
9356
+ fetchAttempts.push({
9357
+ label: "public-r2",
9358
+ url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
9359
+ });
9360
+ }
9158
9361
  fetchAttempts.push({
9159
- label: "public-r2",
9160
- url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
9362
+ label: "cloud",
9363
+ url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
9161
9364
  });
9162
- }
9163
- fetchAttempts.push({
9164
- label: "cloud",
9165
- url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
9166
- });
9167
- let lastErrStatus = 0;
9168
- let lastErrText = "";
9169
- for (const attempt of fetchAttempts) {
9170
- try {
9171
- const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
9172
- if (!resp.ok) {
9173
- lastErrStatus = resp.status;
9174
- lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
9175
- if (attempt.label === "public-r2" && resp.status === 404) {
9176
- ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
9177
- continue;
9365
+ let lastErrStatus = 0;
9366
+ let lastErrText = "";
9367
+ for (const attempt of fetchAttempts) {
9368
+ try {
9369
+ const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
9370
+ if (!resp.ok) {
9371
+ lastErrStatus = resp.status;
9372
+ lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
9373
+ if (attempt.label === "public-r2" && resp.status === 404) {
9374
+ ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
9375
+ continue;
9376
+ }
9377
+ if (attempt.label === "public-r2" && resp.status >= 500) {
9378
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
9379
+ continue;
9380
+ }
9381
+ break;
9178
9382
  }
9179
- if (attempt.label === "public-r2" && resp.status >= 500) {
9180
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
9383
+ payload = await resp.json();
9384
+ lastErrStatus = 0;
9385
+ break;
9386
+ } catch (err) {
9387
+ if (attempt.label === "public-r2") {
9388
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
9181
9389
  continue;
9182
9390
  }
9183
- break;
9184
- }
9185
- payload = await resp.json();
9186
- lastErrStatus = 0;
9187
- break;
9188
- } catch (err) {
9189
- if (attempt.label === "public-r2") {
9190
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
9191
- continue;
9391
+ return c.json({
9392
+ success: false,
9393
+ error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9394
+ }, 502);
9192
9395
  }
9396
+ }
9397
+ if (!payload) {
9193
9398
  return c.json({
9194
9399
  success: false,
9195
- error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9196
- }, 502);
9400
+ error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9401
+ }, lastErrStatus === 404 ? 404 : 502);
9197
9402
  }
9403
+ const data = payload?.data ?? payload;
9404
+ manifest = data?.manifest;
9405
+ resolvedVersionId = String(data?.version_id ?? versionId);
9406
+ version = String(data?.version ?? "unknown");
9198
9407
  }
9199
- if (!payload) {
9200
- return c.json({
9201
- success: false,
9202
- error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9203
- }, lastErrStatus === 404 ? 404 : 502);
9204
- }
9205
- const data = payload?.data ?? payload;
9206
- const manifest = data?.manifest;
9207
- const resolvedVersionId = String(data?.version_id ?? versionId);
9208
- const version = String(data?.version ?? "unknown");
9209
9408
  const manifestId = String(manifest?.id ?? manifest?.name ?? "");
9210
9409
  if (!manifest || !manifestId) {
9211
- return c.json({ success: false, error: { code: "invalid_manifest", message: "Cloud returned an invalid manifest payload." } }, 502);
9410
+ return c.json({ success: false, error: { code: "invalid_manifest", message: "Invalid manifest payload." } }, inlineManifest ? 400 : 502);
9212
9411
  }
9213
9412
  const conflict = this.findConflict(ctx, manifestId);
9214
9413
  if (conflict === "user-code") {
@@ -9220,6 +9419,18 @@ var MarketplaceInstallLocalPlugin = class {
9220
9419
  }
9221
9420
  }, 409);
9222
9421
  }
9422
+ try {
9423
+ const manifestService = ctx.getService("manifest");
9424
+ manifestService.register(manifest);
9425
+ } catch (err) {
9426
+ if (inlineManifest) {
9427
+ return c.json({
9428
+ success: false,
9429
+ error: { code: "register_failed", message: `Failed to register imported manifest: ${err?.message ?? err}` }
9430
+ }, 422);
9431
+ }
9432
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] hot-register failed for ${manifestId} (will load on next restart): ${err?.message ?? err}`);
9433
+ }
9223
9434
  const entry = {
9224
9435
  packageId,
9225
9436
  versionId: resolvedVersionId,
@@ -9231,20 +9442,14 @@ var MarketplaceInstallLocalPlugin = class {
9231
9442
  withSampleData: false
9232
9443
  };
9233
9444
  try {
9234
- mkdirSync3(this.storageDir, { recursive: true });
9235
- writeFileSync2(join(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9445
+ mkdirSync4(this.storageDir, { recursive: true });
9446
+ writeFileSync3(join2(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9236
9447
  } catch (err) {
9237
9448
  return c.json({
9238
9449
  success: false,
9239
9450
  error: { code: "storage_failed", message: `Failed to persist manifest: ${err?.message ?? err}` }
9240
9451
  }, 500);
9241
9452
  }
9242
- try {
9243
- const manifestService = ctx.getService("manifest");
9244
- manifestService.register(manifest);
9245
- } catch (err) {
9246
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] hot-register failed for ${manifestId} (will load on next restart): ${err?.message ?? err}`);
9247
- }
9248
9453
  try {
9249
9454
  const ql = ctx.getService("objectql");
9250
9455
  if (ql && typeof ql.syncSchemas === "function") {
@@ -9258,7 +9463,7 @@ var MarketplaceInstallLocalPlugin = class {
9258
9463
  if (seededSummary.seeded.mode === "inline" && (seededSummary.seeded.inserted ?? 0) + (seededSummary.seeded.updated ?? 0) > 0) {
9259
9464
  entry.withSampleData = true;
9260
9465
  try {
9261
- writeFileSync2(join(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9466
+ writeFileSync3(join2(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9262
9467
  } catch {
9263
9468
  }
9264
9469
  }
@@ -9305,8 +9510,8 @@ var MarketplaceInstallLocalPlugin = class {
9305
9510
  if (!manifestId) {
9306
9511
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9307
9512
  }
9308
- const file = join(this.storageDir, safeFilename(manifestId));
9309
- if (!existsSync2(file)) {
9513
+ const file = join2(this.storageDir, safeFilename(manifestId));
9514
+ if (!existsSync3(file)) {
9310
9515
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9311
9516
  }
9312
9517
  try {
@@ -9333,7 +9538,7 @@ var MarketplaceInstallLocalPlugin = class {
9333
9538
  * (refuse to avoid silently overwriting authored code)
9334
9539
  */
9335
9540
  this.findConflict = (ctx, manifestId) => {
9336
- if (existsSync2(join(this.storageDir, safeFilename(manifestId)))) {
9541
+ if (existsSync3(join2(this.storageDir, safeFilename(manifestId)))) {
9337
9542
  return "marketplace";
9338
9543
  }
9339
9544
  try {
@@ -9375,13 +9580,13 @@ var MarketplaceInstallLocalPlugin = class {
9375
9580
  if (!manifestId) {
9376
9581
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9377
9582
  }
9378
- const file = join(this.storageDir, safeFilename(manifestId));
9379
- if (!existsSync2(file)) {
9583
+ const file = join2(this.storageDir, safeFilename(manifestId));
9584
+ if (!existsSync3(file)) {
9380
9585
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9381
9586
  }
9382
9587
  let entry;
9383
9588
  try {
9384
- entry = JSON.parse(readFileSync(file, "utf8"));
9589
+ entry = JSON.parse(readFileSync2(file, "utf8"));
9385
9590
  } catch (err) {
9386
9591
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9387
9592
  }
@@ -9397,7 +9602,7 @@ var MarketplaceInstallLocalPlugin = class {
9397
9602
  }
9398
9603
  try {
9399
9604
  entry.withSampleData = true;
9400
- writeFileSync2(file, JSON.stringify(entry, null, 2), "utf8");
9605
+ writeFileSync3(file, JSON.stringify(entry, null, 2), "utf8");
9401
9606
  } catch {
9402
9607
  }
9403
9608
  return c.json({
@@ -9429,13 +9634,13 @@ var MarketplaceInstallLocalPlugin = class {
9429
9634
  if (!manifestId) {
9430
9635
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9431
9636
  }
9432
- const file = join(this.storageDir, safeFilename(manifestId));
9433
- if (!existsSync2(file)) {
9637
+ const file = join2(this.storageDir, safeFilename(manifestId));
9638
+ if (!existsSync3(file)) {
9434
9639
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9435
9640
  }
9436
9641
  let entry;
9437
9642
  try {
9438
- entry = JSON.parse(readFileSync(file, "utf8"));
9643
+ entry = JSON.parse(readFileSync2(file, "utf8"));
9439
9644
  } catch (err) {
9440
9645
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9441
9646
  }
@@ -9484,7 +9689,7 @@ var MarketplaceInstallLocalPlugin = class {
9484
9689
  }
9485
9690
  try {
9486
9691
  entry.withSampleData = false;
9487
- writeFileSync2(file, JSON.stringify(entry, null, 2), "utf8");
9692
+ writeFileSync3(file, JSON.stringify(entry, null, 2), "utf8");
9488
9693
  } catch {
9489
9694
  }
9490
9695
  ctx.logger?.info?.(`[MarketplaceInstallLocal] purged ${manifestId}: deleted=${deleted} skipped=${skipped} errors=${errors}`);
@@ -9582,7 +9787,7 @@ var MarketplaceInstallLocalPlugin = class {
9582
9787
  }
9583
9788
  }
9584
9789
  if (opts.seedNow && datasets.length > 0) {
9585
- const multiTenant = String(process.env.OS_MULTI_TENANT ?? "false").toLowerCase() !== "false";
9790
+ const multiTenant = String(readEnvWithDeprecation5("OS_MULTI_ORG_ENABLED", "OS_MULTI_TENANT") ?? "false").toLowerCase() !== "false";
9586
9791
  try {
9587
9792
  const ql = ctx.getService("objectql");
9588
9793
  let metadata;
@@ -9683,12 +9888,12 @@ var MarketplaceInstallLocalPlugin = class {
9683
9888
  return null;
9684
9889
  };
9685
9890
  this.readAll = () => {
9686
- if (!existsSync2(this.storageDir)) return [];
9891
+ if (!existsSync3(this.storageDir)) return [];
9687
9892
  const out = [];
9688
9893
  for (const name of readdirSync(this.storageDir)) {
9689
9894
  if (!name.endsWith(".json")) continue;
9690
9895
  try {
9691
- const raw = readFileSync(join(this.storageDir, name), "utf8");
9896
+ const raw = readFileSync2(join2(this.storageDir, name), "utf8");
9692
9897
  out.push(JSON.parse(raw));
9693
9898
  } catch {
9694
9899
  }
@@ -9733,6 +9938,7 @@ import {
9733
9938
  createRestApiPlugin
9734
9939
  } from "@objectstack/rest";
9735
9940
  export * from "@objectstack/core";
9941
+ import { readEnvWithDeprecation as readEnvWithDeprecation6, _resetEnvDeprecationWarnings } from "@objectstack/types";
9736
9942
  export {
9737
9943
  AppPlugin,
9738
9944
  ArtifactApiClient,
@@ -9770,6 +9976,7 @@ export {
9770
9976
  SandboxError,
9771
9977
  SeedLoaderService,
9772
9978
  UnimplementedScriptRunner,
9979
+ _resetEnvDeprecationWarnings,
9773
9980
  actionBodyRunnerFactory,
9774
9981
  backfillPlatformSsoClients,
9775
9982
  buildPlatformSsoRedirectUri,
@@ -9794,6 +10001,7 @@ export {
9794
10001
  mergeRuntimeModule,
9795
10002
  parseTraceparent,
9796
10003
  readArtifactSource,
10004
+ readEnvWithDeprecation6 as readEnvWithDeprecation,
9797
10005
  resolveCloudUrl,
9798
10006
  resolveDefaultArtifactPath,
9799
10007
  resolveErrorReporter,