@objectstack/runtime 7.2.1 → 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.cjs CHANGED
@@ -726,6 +726,52 @@ var init_seed_loader = __esm({
726
726
  }
727
727
  });
728
728
 
729
+ // src/package-state-store.ts
730
+ function sanitizeEnvironmentId(environmentId) {
731
+ const raw = (environmentId ?? process.env.OS_ENVIRONMENT_ID ?? DEFAULT_ENVIRONMENT_ID).trim();
732
+ const safe = raw.replace(/[^a-zA-Z0-9._-]/g, "_");
733
+ return safe.length > 0 ? safe : DEFAULT_ENVIRONMENT_ID;
734
+ }
735
+ function stateFilePath(environmentId) {
736
+ return (0, import_node_path2.join)(resolveObjectStackHome(), "package-state", `${sanitizeEnvironmentId(environmentId)}.json`);
737
+ }
738
+ function readState(environmentId) {
739
+ const file = stateFilePath(environmentId);
740
+ if (!(0, import_node_fs.existsSync)(file)) return {};
741
+ try {
742
+ const parsed = JSON.parse((0, import_node_fs.readFileSync)(file, "utf8"));
743
+ return parsed && typeof parsed === "object" ? parsed : {};
744
+ } catch {
745
+ return {};
746
+ }
747
+ }
748
+ function writeState(environmentId, state) {
749
+ const file = stateFilePath(environmentId);
750
+ (0, import_node_fs.mkdirSync)((0, import_node_path2.dirname)(file), { recursive: true });
751
+ (0, import_node_fs.writeFileSync)(file, `${JSON.stringify(state, null, 2)}
752
+ `, "utf8");
753
+ }
754
+ function loadDisabledPackageIds(environmentId) {
755
+ const disabled = readState(environmentId).disabled;
756
+ return new Set(Array.isArray(disabled) ? disabled.filter((id) => typeof id === "string") : []);
757
+ }
758
+ function setPackageDisabled(environmentId, packageId, disabled) {
759
+ const ids = loadDisabledPackageIds(environmentId);
760
+ if (disabled) ids.add(packageId);
761
+ else ids.delete(packageId);
762
+ writeState(environmentId, { disabled: Array.from(ids).sort() });
763
+ }
764
+ var import_node_fs, import_node_path2, DEFAULT_ENVIRONMENT_ID;
765
+ var init_package_state_store = __esm({
766
+ "src/package-state-store.ts"() {
767
+ "use strict";
768
+ import_node_fs = require("fs");
769
+ import_node_path2 = require("path");
770
+ init_standalone_stack();
771
+ DEFAULT_ENVIRONMENT_ID = "default";
772
+ }
773
+ });
774
+
729
775
  // src/sandbox/quickjs-runner.ts
730
776
  function installApiMethod(vm, parent, method, objectName, ctx, caps, required, origin) {
731
777
  const fn = vm.newAsyncifiedFunction(method, async (...argHandles) => {
@@ -1290,6 +1336,7 @@ var init_app_plugin = __esm({
1290
1336
  "use strict";
1291
1337
  import_types = require("@objectstack/types");
1292
1338
  init_seed_loader();
1339
+ init_package_state_store();
1293
1340
  init_quickjs_runner();
1294
1341
  init_body_runner();
1295
1342
  AppPlugin = class {
@@ -1315,6 +1362,24 @@ var init_app_plugin = __esm({
1315
1362
  console.warn(
1316
1363
  `[AppPlugin:init] appId=${appId} keys=${Object.keys(servicePayload).join(",")} flows=${Array.isArray(servicePayload.flows) ? servicePayload.flows.length : "n/a"}`
1317
1364
  );
1365
+ try {
1366
+ const ql = ctx.getService("objectql");
1367
+ const setter = ql?.registry?.setInitialDisabledPackageIds;
1368
+ if (typeof setter === "function") {
1369
+ const disabled = loadDisabledPackageIds(this.projectContext?.environmentId);
1370
+ if (disabled.size > 0) {
1371
+ setter.call(ql.registry, disabled);
1372
+ ctx.logger.info("[AppPlugin] seeded persisted disabled packages", {
1373
+ environmentId: this.projectContext?.environmentId,
1374
+ disabled: Array.from(disabled)
1375
+ });
1376
+ }
1377
+ }
1378
+ } catch (err) {
1379
+ ctx.logger.warn("[AppPlugin] failed to seed persisted package state", {
1380
+ error: err?.message ?? String(err)
1381
+ });
1382
+ }
1318
1383
  ctx.getService("manifest").register(servicePayload);
1319
1384
  };
1320
1385
  this.start = async (ctx) => {
@@ -1859,6 +1924,170 @@ var init_app_plugin = __esm({
1859
1924
  }
1860
1925
  });
1861
1926
 
1927
+ // src/standalone-stack.ts
1928
+ function resolveObjectStackHome() {
1929
+ const raw = process.env.OS_HOME?.trim();
1930
+ if (raw && raw.length > 0) {
1931
+ if (raw.startsWith("~")) return (0, import_node_path3.resolve)((0, import_node_os.homedir)(), raw.slice(1).replace(/^[/\\]/, ""));
1932
+ return (0, import_node_path3.resolve)(raw);
1933
+ }
1934
+ return (0, import_node_path3.resolve)((0, import_node_os.homedir)(), ".objectstack");
1935
+ }
1936
+ function detectDriverFromUrl(dbUrl) {
1937
+ if (/^memory:\/\//i.test(dbUrl)) return "memory";
1938
+ if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return "postgres";
1939
+ if (/^mongodb(\+srv)?:\/\//i.test(dbUrl)) return "mongodb";
1940
+ if (/^wasm-sqlite:\/\//i.test(dbUrl)) return "sqlite-wasm";
1941
+ if (/\.wasm\.db$/i.test(dbUrl)) return "sqlite-wasm";
1942
+ if (/^file:/i.test(dbUrl)) return "sqlite";
1943
+ if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(dbUrl)) return "sqlite";
1944
+ throw new Error(
1945
+ `[StandaloneStack] Unsupported database URL scheme: ${dbUrl}. Supported schemes: memory://, postgres://, pg://, mongodb://, mongodb+srv://, file:`
1946
+ );
1947
+ }
1948
+ async function createStandaloneStack(config) {
1949
+ const cfg = StandaloneStackConfigSchema.parse(config ?? {});
1950
+ const { ObjectQLPlugin } = await import("@objectstack/objectql");
1951
+ const { MetadataPlugin } = await import("@objectstack/metadata");
1952
+ const { DriverPlugin: DriverPlugin2 } = await Promise.resolve().then(() => (init_driver_plugin(), driver_plugin_exports));
1953
+ const { AppPlugin: AppPlugin2 } = await Promise.resolve().then(() => (init_app_plugin(), app_plugin_exports));
1954
+ const cwd = process.cwd();
1955
+ const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
1956
+ const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path3.resolve)(cwd, "dist/objectstack.json");
1957
+ const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : (0, import_node_path3.resolve)(cwd, artifactPathInput);
1958
+ const dbUrl = cfg.databaseUrl ?? (0, import_types2.readEnvWithDeprecation)("OS_DATABASE_URL", "DATABASE_URL")?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${(0, import_node_path3.resolve)(resolveObjectStackHome(), "data/standalone.db")}` : cfg.projectRoot ? `file:${(0, import_node_path3.resolve)(cfg.projectRoot, ".objectstack/data/standalone.db")}` : `file:${(0, import_node_path3.resolve)(resolveObjectStackHome(), "data/standalone.db")}`);
1959
+ const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
1960
+ const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
1961
+ let driverPlugin;
1962
+ if (dbDriver === "memory") {
1963
+ const { InMemoryDriver } = await import("@objectstack/driver-memory");
1964
+ driverPlugin = new DriverPlugin2(new InMemoryDriver());
1965
+ } else if (dbDriver === "postgres") {
1966
+ const { SqlDriver } = await import("@objectstack/driver-sql");
1967
+ driverPlugin = new DriverPlugin2(
1968
+ new SqlDriver({
1969
+ client: "pg",
1970
+ connection: dbUrl,
1971
+ pool: { min: 0, max: 5 }
1972
+ })
1973
+ );
1974
+ } else if (dbDriver === "mongodb") {
1975
+ let MongoDBDriver;
1976
+ try {
1977
+ ({ MongoDBDriver } = await import("@objectstack/driver-mongodb"));
1978
+ } catch (err) {
1979
+ throw new Error(
1980
+ `[StandaloneStack] mongodb URL detected but @objectstack/driver-mongodb is not installed. Add it as a dependency or pass an explicit driverPlugin. (${err?.message ?? err})`
1981
+ );
1982
+ }
1983
+ driverPlugin = new DriverPlugin2(new MongoDBDriver({ url: dbUrl }));
1984
+ } else if (dbDriver === "sqlite-wasm") {
1985
+ const { SqliteWasmDriver } = await import("@objectstack/driver-sqlite-wasm");
1986
+ const filename = dbUrl.replace(/^wasm-sqlite:(\/\/)?/i, "").replace(/^file:(\/\/)?/i, "");
1987
+ if (filename && filename !== ":memory:") {
1988
+ (0, import_node_fs2.mkdirSync)((0, import_node_path3.resolve)(filename, ".."), { recursive: true });
1989
+ }
1990
+ driverPlugin = new DriverPlugin2(
1991
+ new SqliteWasmDriver({
1992
+ filename: filename || ":memory:",
1993
+ persist: filename && filename !== ":memory:" ? "on-write" : void 0
1994
+ })
1995
+ );
1996
+ } else {
1997
+ const { SqlDriver } = await import("@objectstack/driver-sql");
1998
+ const filename = dbUrl.replace(/^file:(\/\/)?/, "");
1999
+ if (!filename || /^[a-z][a-z0-9+.-]*:\/\//i.test(filename)) {
2000
+ throw new Error(
2001
+ `[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.`
2002
+ );
2003
+ }
2004
+ (0, import_node_fs2.mkdirSync)((0, import_node_path3.resolve)(filename, ".."), { recursive: true });
2005
+ driverPlugin = new DriverPlugin2(
2006
+ new SqlDriver({
2007
+ client: "better-sqlite3",
2008
+ connection: { filename },
2009
+ useNullAsDefault: true
2010
+ })
2011
+ );
2012
+ }
2013
+ const artifactBundle = await loadArtifactBundle(artifactPath, {
2014
+ tag: "[StandaloneStack]",
2015
+ unwrapEnvelope: true
2016
+ });
2017
+ if (artifactBundle) {
2018
+ const flowsCount = Array.isArray(artifactBundle?.flows) ? artifactBundle.flows.length : "n/a";
2019
+ console.warn(
2020
+ `[StandaloneStack] artifact loaded: path=${artifactPath} keys=${Object.keys(artifactBundle).join(",")} flows=${flowsCount}`
2021
+ );
2022
+ }
2023
+ const plugins = [
2024
+ driverPlugin,
2025
+ new MetadataPlugin({
2026
+ // Source-file scanner OFF — declarative metadata is loaded
2027
+ // from the compiled artifact, not from yaml/json files on
2028
+ // disk. Scanning would also recursively watch the project
2029
+ // root (incl. node_modules), which is expensive and prone
2030
+ // to EMFILE.
2031
+ watch: false,
2032
+ // Artifact-file HMR ON in non-production so edits to
2033
+ // `*.view.ts` / `*.flow.ts` (which the CLI dev-mode watcher
2034
+ // recompiles into `dist/objectstack.json`) are picked up by
2035
+ // the running server WITHOUT requiring a manual restart.
2036
+ // Uses polling under the hood (see plugin.ts) to avoid
2037
+ // `fs.watch` EMFILE on macOS / busy dev hosts.
2038
+ artifactWatch: process.env.NODE_ENV !== "production",
2039
+ environmentId,
2040
+ artifactSource: { mode: "local-file", path: artifactPath }
2041
+ }),
2042
+ new ObjectQLPlugin({ environmentId })
2043
+ ];
2044
+ if (artifactBundle) plugins.push(new AppPlugin2(artifactBundle));
2045
+ const requires = Array.isArray(artifactBundle?.requires) ? artifactBundle.requires.filter((c) => typeof c === "string") : void 0;
2046
+ const objects = Array.isArray(artifactBundle?.objects) ? artifactBundle.objects : void 0;
2047
+ const manifest = artifactBundle?.manifest;
2048
+ return {
2049
+ plugins,
2050
+ api: {
2051
+ enableProjectScoping: false,
2052
+ projectResolution: "none"
2053
+ },
2054
+ ...requires ? { requires } : {},
2055
+ ...objects ? { objects } : {},
2056
+ ...manifest ? { manifest } : {}
2057
+ };
2058
+ }
2059
+ var import_node_path3, import_node_fs2, import_node_os, import_zod, import_types2, StandaloneStackConfigSchema;
2060
+ var init_standalone_stack = __esm({
2061
+ "src/standalone-stack.ts"() {
2062
+ "use strict";
2063
+ import_node_path3 = require("path");
2064
+ import_node_fs2 = require("fs");
2065
+ import_node_os = require("os");
2066
+ import_zod = require("zod");
2067
+ import_types2 = require("@objectstack/types");
2068
+ init_load_artifact_bundle();
2069
+ StandaloneStackConfigSchema = import_zod.z.object({
2070
+ databaseUrl: import_zod.z.string().optional(),
2071
+ databaseAuthToken: import_zod.z.string().optional(),
2072
+ databaseDriver: import_zod.z.enum(["sqlite", "sqlite-wasm", "memory", "postgres", "mongodb"]).optional(),
2073
+ environmentId: import_zod.z.string().optional(),
2074
+ artifactPath: import_zod.z.string().optional(),
2075
+ /**
2076
+ * Project root directory. When set (typically by the CLI after locating
2077
+ * `objectstack.config.ts`), the default sqlite database is placed under
2078
+ * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2079
+ * `~/.objectstack/data/standalone.db`. This keeps per-project data
2080
+ * scoped to the project folder so different examples / apps don't
2081
+ * share a single database by accident.
2082
+ *
2083
+ * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2084
+ * precedence over this default.
2085
+ */
2086
+ projectRoot: import_zod.z.string().optional()
2087
+ });
2088
+ }
2089
+ });
2090
+
1862
2091
  // src/cloud/platform-sso.ts
1863
2092
  var platform_sso_exports = {};
1864
2093
  __export(platform_sso_exports, {
@@ -2333,173 +2562,19 @@ var Runtime = class {
2333
2562
  }
2334
2563
  };
2335
2564
 
2336
- // src/standalone-stack.ts
2337
- var import_node_path2 = require("path");
2338
- var import_node_fs = require("fs");
2339
- var import_node_os = require("os");
2340
- var import_zod = require("zod");
2341
- var import_types2 = require("@objectstack/types");
2342
- init_load_artifact_bundle();
2343
- function resolveObjectStackHome() {
2344
- const raw = process.env.OS_HOME?.trim();
2345
- if (raw && raw.length > 0) {
2346
- if (raw.startsWith("~")) return (0, import_node_path2.resolve)((0, import_node_os.homedir)(), raw.slice(1).replace(/^[/\\]/, ""));
2347
- return (0, import_node_path2.resolve)(raw);
2348
- }
2349
- return (0, import_node_path2.resolve)((0, import_node_os.homedir)(), ".objectstack");
2350
- }
2351
- var StandaloneStackConfigSchema = import_zod.z.object({
2352
- databaseUrl: import_zod.z.string().optional(),
2353
- databaseAuthToken: import_zod.z.string().optional(),
2354
- databaseDriver: import_zod.z.enum(["sqlite", "sqlite-wasm", "memory", "postgres", "mongodb"]).optional(),
2355
- environmentId: import_zod.z.string().optional(),
2356
- artifactPath: import_zod.z.string().optional(),
2357
- /**
2358
- * Project root directory. When set (typically by the CLI after locating
2359
- * `objectstack.config.ts`), the default sqlite database is placed under
2360
- * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2361
- * `~/.objectstack/data/standalone.db`. This keeps per-project data
2362
- * scoped to the project folder so different examples / apps don't
2363
- * share a single database by accident.
2364
- *
2365
- * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2366
- * precedence over this default.
2367
- */
2368
- projectRoot: import_zod.z.string().optional()
2369
- });
2370
- function detectDriverFromUrl(dbUrl) {
2371
- if (/^memory:\/\//i.test(dbUrl)) return "memory";
2372
- if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return "postgres";
2373
- if (/^mongodb(\+srv)?:\/\//i.test(dbUrl)) return "mongodb";
2374
- if (/^wasm-sqlite:\/\//i.test(dbUrl)) return "sqlite-wasm";
2375
- if (/\.wasm\.db$/i.test(dbUrl)) return "sqlite-wasm";
2376
- if (/^file:/i.test(dbUrl)) return "sqlite";
2377
- if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(dbUrl)) return "sqlite";
2378
- throw new Error(
2379
- `[StandaloneStack] Unsupported database URL scheme: ${dbUrl}. Supported schemes: memory://, postgres://, pg://, mongodb://, mongodb+srv://, file:`
2380
- );
2381
- }
2382
- async function createStandaloneStack(config) {
2383
- const cfg = StandaloneStackConfigSchema.parse(config ?? {});
2384
- const { ObjectQLPlugin } = await import("@objectstack/objectql");
2385
- const { MetadataPlugin } = await import("@objectstack/metadata");
2386
- const { DriverPlugin: DriverPlugin2 } = await Promise.resolve().then(() => (init_driver_plugin(), driver_plugin_exports));
2387
- const { AppPlugin: AppPlugin2 } = await Promise.resolve().then(() => (init_app_plugin(), app_plugin_exports));
2388
- const cwd = process.cwd();
2389
- const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
2390
- const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path2.resolve)(cwd, "dist/objectstack.json");
2391
- const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : (0, import_node_path2.resolve)(cwd, artifactPathInput);
2392
- const dbUrl = cfg.databaseUrl ?? (0, import_types2.readEnvWithDeprecation)("OS_DATABASE_URL", "DATABASE_URL")?.trim() ?? process.env.TURSO_DATABASE_URL?.trim() ?? (process.env.OS_HOME?.trim() ? `file:${(0, import_node_path2.resolve)(resolveObjectStackHome(), "data/standalone.db")}` : cfg.projectRoot ? `file:${(0, import_node_path2.resolve)(cfg.projectRoot, ".objectstack/data/standalone.db")}` : `file:${(0, import_node_path2.resolve)(resolveObjectStackHome(), "data/standalone.db")}`);
2393
- const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
2394
- const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
2395
- let driverPlugin;
2396
- if (dbDriver === "memory") {
2397
- const { InMemoryDriver } = await import("@objectstack/driver-memory");
2398
- driverPlugin = new DriverPlugin2(new InMemoryDriver());
2399
- } else if (dbDriver === "postgres") {
2400
- const { SqlDriver } = await import("@objectstack/driver-sql");
2401
- driverPlugin = new DriverPlugin2(
2402
- new SqlDriver({
2403
- client: "pg",
2404
- connection: dbUrl,
2405
- pool: { min: 0, max: 5 }
2406
- })
2407
- );
2408
- } else if (dbDriver === "mongodb") {
2409
- let MongoDBDriver;
2410
- try {
2411
- ({ MongoDBDriver } = await import("@objectstack/driver-mongodb"));
2412
- } catch (err) {
2413
- throw new Error(
2414
- `[StandaloneStack] mongodb URL detected but @objectstack/driver-mongodb is not installed. Add it as a dependency or pass an explicit driverPlugin. (${err?.message ?? err})`
2415
- );
2416
- }
2417
- driverPlugin = new DriverPlugin2(new MongoDBDriver({ url: dbUrl }));
2418
- } else if (dbDriver === "sqlite-wasm") {
2419
- const { SqliteWasmDriver } = await import("@objectstack/driver-sqlite-wasm");
2420
- const filename = dbUrl.replace(/^wasm-sqlite:(\/\/)?/i, "").replace(/^file:(\/\/)?/i, "");
2421
- if (filename && filename !== ":memory:") {
2422
- (0, import_node_fs.mkdirSync)((0, import_node_path2.resolve)(filename, ".."), { recursive: true });
2423
- }
2424
- driverPlugin = new DriverPlugin2(
2425
- new SqliteWasmDriver({
2426
- filename: filename || ":memory:",
2427
- persist: filename && filename !== ":memory:" ? "on-write" : void 0
2428
- })
2429
- );
2430
- } else {
2431
- const { SqlDriver } = await import("@objectstack/driver-sql");
2432
- const filename = dbUrl.replace(/^file:(\/\/)?/, "");
2433
- if (!filename || /^[a-z][a-z0-9+.-]*:\/\//i.test(filename)) {
2434
- throw new Error(
2435
- `[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.`
2436
- );
2437
- }
2438
- (0, import_node_fs.mkdirSync)((0, import_node_path2.resolve)(filename, ".."), { recursive: true });
2439
- driverPlugin = new DriverPlugin2(
2440
- new SqlDriver({
2441
- client: "better-sqlite3",
2442
- connection: { filename },
2443
- useNullAsDefault: true
2444
- })
2445
- );
2446
- }
2447
- const artifactBundle = await loadArtifactBundle(artifactPath, {
2448
- tag: "[StandaloneStack]",
2449
- unwrapEnvelope: true
2450
- });
2451
- if (artifactBundle) {
2452
- const flowsCount = Array.isArray(artifactBundle?.flows) ? artifactBundle.flows.length : "n/a";
2453
- console.warn(
2454
- `[StandaloneStack] artifact loaded: path=${artifactPath} keys=${Object.keys(artifactBundle).join(",")} flows=${flowsCount}`
2455
- );
2456
- }
2457
- const plugins = [
2458
- driverPlugin,
2459
- new MetadataPlugin({
2460
- // Source-file scanner OFF — declarative metadata is loaded
2461
- // from the compiled artifact, not from yaml/json files on
2462
- // disk. Scanning would also recursively watch the project
2463
- // root (incl. node_modules), which is expensive and prone
2464
- // to EMFILE.
2465
- watch: false,
2466
- // Artifact-file HMR ON in non-production so edits to
2467
- // `*.view.ts` / `*.flow.ts` (which the CLI dev-mode watcher
2468
- // recompiles into `dist/objectstack.json`) are picked up by
2469
- // the running server WITHOUT requiring a manual restart.
2470
- // Uses polling under the hood (see plugin.ts) to avoid
2471
- // `fs.watch` EMFILE on macOS / busy dev hosts.
2472
- artifactWatch: process.env.NODE_ENV !== "production",
2473
- environmentId,
2474
- artifactSource: { mode: "local-file", path: artifactPath }
2475
- }),
2476
- new ObjectQLPlugin({ environmentId })
2477
- ];
2478
- if (artifactBundle) plugins.push(new AppPlugin2(artifactBundle));
2479
- const requires = Array.isArray(artifactBundle?.requires) ? artifactBundle.requires.filter((c) => typeof c === "string") : void 0;
2480
- const objects = Array.isArray(artifactBundle?.objects) ? artifactBundle.objects : void 0;
2481
- const manifest = artifactBundle?.manifest;
2482
- return {
2483
- plugins,
2484
- api: {
2485
- enableProjectScoping: false,
2486
- projectResolution: "none"
2487
- },
2488
- ...requires ? { requires } : {},
2489
- ...objects ? { objects } : {},
2490
- ...manifest ? { manifest } : {}
2491
- };
2492
- }
2565
+ // src/index.ts
2566
+ init_standalone_stack();
2493
2567
 
2494
2568
  // src/default-host.ts
2495
- var import_node_path3 = require("path");
2496
- var import_node_fs2 = require("fs");
2569
+ var import_node_path4 = require("path");
2570
+ var import_node_fs3 = require("fs");
2571
+ init_standalone_stack();
2497
2572
  init_load_artifact_bundle();
2498
2573
  function resolveDefaultArtifactPath(explicitPath, cwd = process.cwd()) {
2499
- const candidate = explicitPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path3.resolve)(cwd, "dist/objectstack.json");
2574
+ const candidate = explicitPath ?? process.env.OS_ARTIFACT_PATH ?? (0, import_node_path4.resolve)(cwd, "dist/objectstack.json");
2500
2575
  if (isHttpUrl(candidate)) return candidate;
2501
2576
  if (explicitPath || process.env.OS_ARTIFACT_PATH) return candidate;
2502
- return (0, import_node_fs2.existsSync)(candidate) ? candidate : void 0;
2577
+ return (0, import_node_fs3.existsSync)(candidate) ? candidate : void 0;
2503
2578
  }
2504
2579
  async function createDefaultHostConfig(options = {}) {
2505
2580
  const { requireArtifact = true, ...standaloneOpts } = options;
@@ -2511,10 +2586,10 @@ async function createDefaultHostConfig(options = {}) {
2511
2586
  }
2512
2587
  if (!resolvedArtifact && !requireArtifact) {
2513
2588
  const home = resolveObjectStackHome();
2514
- const stubPath = (0, import_node_path3.resolve)(home, "dist/objectstack.json");
2515
- if (!(0, import_node_fs2.existsSync)(stubPath)) {
2516
- (0, import_node_fs2.mkdirSync)((0, import_node_path3.resolve)(stubPath, ".."), { recursive: true });
2517
- (0, import_node_fs2.writeFileSync)(
2589
+ const stubPath = (0, import_node_path4.resolve)(home, "dist/objectstack.json");
2590
+ if (!(0, import_node_fs3.existsSync)(stubPath)) {
2591
+ (0, import_node_fs3.mkdirSync)((0, import_node_path4.resolve)(stubPath, ".."), { recursive: true });
2592
+ (0, import_node_fs3.writeFileSync)(
2518
2593
  stubPath,
2519
2594
  JSON.stringify(
2520
2595
  {
@@ -2555,6 +2630,7 @@ var import_core2 = require("@objectstack/core");
2555
2630
  var import_types3 = require("@objectstack/types");
2556
2631
  var import_system = require("@objectstack/spec/system");
2557
2632
  var import_shared = require("@objectstack/spec/shared");
2633
+ init_package_state_store();
2558
2634
 
2559
2635
  // src/security/resolve-execution-context.ts
2560
2636
  function readHeader(headers, name) {
@@ -3409,7 +3485,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3409
3485
  if (protocol && typeof protocol.saveMetaItem === "function") {
3410
3486
  try {
3411
3487
  const organizationId = await this.resolveActiveOrganizationId(_context);
3412
- const result = await protocol.saveMetaItem({ type, name, item: body, organizationId });
3488
+ const result = await protocol.saveMetaItem({ type, name, item: body, organizationId, ...packageId ? { packageId } : {} });
3413
3489
  return { handled: true, response: this.success(result) };
3414
3490
  } catch (e) {
3415
3491
  return { handled: true, response: this.error(e.message, 400) };
@@ -3749,12 +3825,22 @@ var _HttpDispatcher = class _HttpDispatcher {
3749
3825
  const id = decodeURIComponent(parts[0]);
3750
3826
  const pkg = registry.enablePackage(id);
3751
3827
  if (!pkg) return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3828
+ try {
3829
+ setPackageDisabled(_context?.environmentId, id, false);
3830
+ } catch (err) {
3831
+ console.warn("[handlePackages] failed to persist enable state", { id, error: err?.message });
3832
+ }
3752
3833
  return { handled: true, response: this.success(pkg) };
3753
3834
  }
3754
3835
  if (parts.length === 2 && parts[1] === "disable" && m === "PATCH") {
3755
3836
  const id = decodeURIComponent(parts[0]);
3756
3837
  const pkg = registry.disablePackage(id);
3757
3838
  if (!pkg) return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3839
+ try {
3840
+ setPackageDisabled(_context?.environmentId, id, true);
3841
+ } catch (err) {
3842
+ console.warn("[handlePackages] failed to persist disable state", { id, error: err?.message });
3843
+ }
3758
3844
  return { handled: true, response: this.success(pkg) };
3759
3845
  }
3760
3846
  if (parts.length === 2 && parts[1] === "publish" && m === "POST") {
@@ -3775,6 +3861,14 @@ var _HttpDispatcher = class _HttpDispatcher {
3775
3861
  }
3776
3862
  return { handled: true, response: this.error("Metadata service not available", 503) };
3777
3863
  }
3864
+ if (parts.length === 2 && parts[1] === "export" && m === "GET") {
3865
+ const id = decodeURIComponent(parts[0]);
3866
+ const manifest = await this.assemblePackageManifest(id, registry, _context);
3867
+ if (!manifest) {
3868
+ return { handled: true, response: this.error(`Package '${id}' not found`, 404) };
3869
+ }
3870
+ return { handled: true, response: this.success(manifest) };
3871
+ }
3778
3872
  if (parts.length === 1 && m === "GET") {
3779
3873
  const id = decodeURIComponent(parts[0]);
3780
3874
  const pkg = registry.getPackage(id);
@@ -3792,6 +3886,83 @@ var _HttpDispatcher = class _HttpDispatcher {
3792
3886
  }
3793
3887
  return { handled: false };
3794
3888
  }
3889
+ /**
3890
+ * Assemble a portable, offline-installable package manifest from the
3891
+ * `sys_metadata` overlay rows bound to `packageId`.
3892
+ *
3893
+ * The resulting shape mirrors what `marketplace-install-local` →
3894
+ * `manifestService.register()` → `engine.registerApp()` consumes:
3895
+ * `{ id, name, version, objects:[…], views:[…], flows:[…], … }`
3896
+ * where each category key is the PLURAL manifest name and its value is
3897
+ * an array of clean metadata bodies (provenance decorations stripped).
3898
+ *
3899
+ * Only the metadata categories that `registerApp` can actually consume
3900
+ * are exported. `datasources` and `emailTemplates` are intentionally
3901
+ * excluded (not registered by the import path). `tools` / `skills` ARE
3902
+ * round-tripped: they are registered by `registerApp` on import and
3903
+ * surfaced by `getMetaItems('tool' | 'skill')` on export.
3904
+ *
3905
+ * @returns the manifest object, or `null` if the package id is unknown
3906
+ * AND has no overlay-authored metadata.
3907
+ */
3908
+ async assemblePackageManifest(packageId, registry, context) {
3909
+ const protocol = await this.resolveService("protocol");
3910
+ if (!protocol || typeof protocol.getMetaItems !== "function") return null;
3911
+ const organizationId = await this.resolveActiveOrganizationId(context);
3912
+ const PROVENANCE_KEYS = /* @__PURE__ */ new Set([
3913
+ "_packageId",
3914
+ "_packageVersionId",
3915
+ "_provenance",
3916
+ "_state",
3917
+ "_version",
3918
+ "_organizationId",
3919
+ "_source",
3920
+ "_id",
3921
+ "_rowId"
3922
+ ]);
3923
+ const clean = (item) => {
3924
+ if (!item || typeof item !== "object") return item;
3925
+ const out = {};
3926
+ for (const [k, v] of Object.entries(item)) {
3927
+ if (k.startsWith("_") || PROVENANCE_KEYS.has(k)) continue;
3928
+ out[k] = v;
3929
+ }
3930
+ return out;
3931
+ };
3932
+ const exportPluralKeys = Object.keys(import_shared.PLURAL_TO_SINGULAR).filter(
3933
+ (k) => k !== "datasources" && k !== "emailTemplates"
3934
+ );
3935
+ const manifest = {};
3936
+ let total = 0;
3937
+ for (const plural of exportPluralKeys) {
3938
+ const singular = import_shared.PLURAL_TO_SINGULAR[plural];
3939
+ let items = [];
3940
+ try {
3941
+ const res = await protocol.getMetaItems({ type: singular, packageId, organizationId });
3942
+ items = Array.isArray(res?.items) ? res.items : [];
3943
+ } catch {
3944
+ continue;
3945
+ }
3946
+ if (items.length === 0) continue;
3947
+ manifest[plural] = items.map(clean);
3948
+ total += items.length;
3949
+ }
3950
+ const pkg = (() => {
3951
+ try {
3952
+ return registry?.getPackage?.(packageId);
3953
+ } catch {
3954
+ return void 0;
3955
+ }
3956
+ })();
3957
+ if (total === 0 && !pkg) return null;
3958
+ manifest.id = packageId;
3959
+ manifest.name = pkg?.manifest?.name ?? pkg?.name ?? packageId;
3960
+ manifest.version = pkg?.manifest?.version ?? pkg?.version ?? "1.0.0";
3961
+ if (pkg?.manifest?.label ?? pkg?.label) {
3962
+ manifest.label = pkg?.manifest?.label ?? pkg?.label;
3963
+ }
3964
+ return manifest;
3965
+ }
3795
3966
  /**
3796
3967
  * Cloud / Environment Control-Plane routes.
3797
3968
  *
@@ -6374,6 +6545,14 @@ function createDispatcherPlugin(config = {}) {
6374
6545
  errorResponse(err, res);
6375
6546
  }
6376
6547
  });
6548
+ server.get(`${prefix}/packages/:id/export`, async (req, res) => {
6549
+ try {
6550
+ const result = await dispatcher.handlePackages(`/${req.params.id}/export`, "GET", {}, req.query, { request: req });
6551
+ sendResult(result, res);
6552
+ } catch (err) {
6553
+ errorResponse(err, res);
6554
+ }
6555
+ });
6377
6556
  server.get(`${prefix}/packages/:id`, async (req, res) => {
6378
6557
  try {
6379
6558
  const result = await dispatcher.handlePackages(`/${req.params.id}`, "GET", {}, req.query, { request: req });
@@ -7481,7 +7660,7 @@ var ArtifactApiClient = class {
7481
7660
  };
7482
7661
 
7483
7662
  // src/cloud/artifact-environment-registry.ts
7484
- var import_node_path4 = require("path");
7663
+ var import_node_path5 = require("path");
7485
7664
  var ArtifactEnvironmentRegistry = class {
7486
7665
  constructor(config) {
7487
7666
  this.hostnameCache = /* @__PURE__ */ new Map();
@@ -7653,7 +7832,7 @@ async function createDriver(driverType, databaseUrl, authToken) {
7653
7832
  case "memory": {
7654
7833
  const { InMemoryDriver } = await import("@objectstack/driver-memory");
7655
7834
  const dbName = databaseUrl.replace(/^memory:\/\//, "").trim();
7656
- const filePath = dbName ? (0, import_node_path4.resolve)(process.cwd(), ".objectstack/data/projects", `${dbName}.json`) : void 0;
7835
+ const filePath = dbName ? (0, import_node_path5.resolve)(process.cwd(), ".objectstack/data/projects", `${dbName}.json`) : void 0;
7657
7836
  return new InMemoryDriver({
7658
7837
  persistence: filePath ? { type: "file", path: filePath } : "file"
7659
7838
  });
@@ -8470,7 +8649,7 @@ var AuthProxyPlugin = class {
8470
8649
  };
8471
8650
 
8472
8651
  // src/cloud/cloud-url.ts
8473
- var DEFAULT_CLOUD_URL = "https://cloud.objectos.app";
8652
+ var DEFAULT_CLOUD_URL = "https://cloud.objectos.ai";
8474
8653
  function resolveCloudUrl(explicit) {
8475
8654
  const raw = (explicit ?? process.env.OS_CLOUD_URL ?? "").trim();
8476
8655
  const lower = raw.toLowerCase();
@@ -8892,11 +9071,11 @@ var RuntimeConfigPlugin = class {
8892
9071
 
8893
9072
  // src/cloud/file-artifact-api-client.ts
8894
9073
  var import_promises2 = require("fs/promises");
8895
- var import_node_path5 = require("path");
9074
+ var import_node_path6 = require("path");
8896
9075
  var FileArtifactApiClient = class {
8897
9076
  constructor(config = {}) {
8898
9077
  const cwd = process.cwd();
8899
- this.artifactPath = (0, import_node_path5.resolve)(
9078
+ this.artifactPath = (0, import_node_path6.resolve)(
8900
9079
  cwd,
8901
9080
  config.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? "dist/objectstack.json"
8902
9081
  );
@@ -8992,7 +9171,7 @@ var FileArtifactApiClient = class {
8992
9171
  }
8993
9172
  defaultLocalSqliteRuntime() {
8994
9173
  const cwd = process.cwd();
8995
- const dbPath = (0, import_node_path5.resolve)(cwd, ".objectstack/data", `${this.environmentId}.db`);
9174
+ const dbPath = (0, import_node_path6.resolve)(cwd, ".objectstack/data", `${this.environmentId}.db`);
8996
9175
  return {
8997
9176
  databaseDriver: "sqlite",
8998
9177
  databaseUrl: `file:${dbPath}`
@@ -9145,8 +9324,8 @@ async function createObjectOSStack(config) {
9145
9324
  }
9146
9325
 
9147
9326
  // src/cloud/marketplace-install-local-plugin.ts
9148
- var import_node_fs3 = require("fs");
9149
- var import_node_path6 = require("path");
9327
+ var import_node_fs4 = require("fs");
9328
+ var import_node_path7 = require("path");
9150
9329
  var import_types5 = require("@objectstack/types");
9151
9330
  var ROUTE_BASE = "/api/v1/marketplace/install-local";
9152
9331
  var DEFAULT_DIR = ".objectstack/installed-packages";
@@ -9222,9 +9401,6 @@ var MarketplaceInstallLocalPlugin = class {
9222
9401
  }
9223
9402
  };
9224
9403
  this.handleInstall = async (c, ctx) => {
9225
- if (!this.cloudUrl) {
9226
- return c.json({ success: false, error: { code: "marketplace_unavailable", message: "OS_CLOUD_URL not configured." } }, 503);
9227
- }
9228
9404
  const userId = await this.requireAuthenticatedUser(c, ctx);
9229
9405
  if (!userId) {
9230
9406
  return c.json({ success: false, error: { code: "unauthorized", message: "Authentication required to install packages." } }, 401);
@@ -9234,69 +9410,87 @@ var MarketplaceInstallLocalPlugin = class {
9234
9410
  body = await c.req.json();
9235
9411
  } catch {
9236
9412
  }
9237
- const packageId = String(body?.packageId ?? "").trim();
9238
- const versionId = String(body?.versionId ?? "latest").trim() || "latest";
9239
- if (!packageId) {
9240
- return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
9241
- }
9242
- let payload;
9243
- const publicBase = resolveMarketplacePublicBaseUrl();
9244
- const fetchAttempts = [];
9245
- if (publicBase) {
9413
+ const inlineManifest = body?.manifest && typeof body.manifest === "object" ? body.manifest : null;
9414
+ let manifest;
9415
+ let resolvedVersionId;
9416
+ let version;
9417
+ let packageId;
9418
+ if (inlineManifest) {
9419
+ manifest = inlineManifest;
9420
+ packageId = String(manifest.id ?? manifest.name ?? "").trim();
9421
+ version = String(manifest.version ?? "unknown");
9422
+ resolvedVersionId = String(body?.versionId ?? version);
9423
+ if (!packageId) {
9424
+ return c.json({ success: false, error: { code: "invalid_manifest", message: 'Inline manifest must have an "id" or "name".' } }, 400);
9425
+ }
9426
+ } else {
9427
+ if (!this.cloudUrl) {
9428
+ return c.json({ success: false, error: { code: "marketplace_unavailable", message: "OS_CLOUD_URL not configured." } }, 503);
9429
+ }
9430
+ packageId = String(body?.packageId ?? "").trim();
9431
+ const versionId = String(body?.versionId ?? "latest").trim() || "latest";
9432
+ if (!packageId) {
9433
+ return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
9434
+ }
9435
+ let payload;
9436
+ const publicBase = resolveMarketplacePublicBaseUrl();
9437
+ const fetchAttempts = [];
9438
+ if (publicBase) {
9439
+ fetchAttempts.push({
9440
+ label: "public-r2",
9441
+ url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
9442
+ });
9443
+ }
9246
9444
  fetchAttempts.push({
9247
- label: "public-r2",
9248
- url: `${publicBase}/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest.json`
9445
+ label: "cloud",
9446
+ url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
9249
9447
  });
9250
- }
9251
- fetchAttempts.push({
9252
- label: "cloud",
9253
- url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
9254
- });
9255
- let lastErrStatus = 0;
9256
- let lastErrText = "";
9257
- for (const attempt of fetchAttempts) {
9258
- try {
9259
- const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
9260
- if (!resp.ok) {
9261
- lastErrStatus = resp.status;
9262
- lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
9263
- if (attempt.label === "public-r2" && resp.status === 404) {
9264
- ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
9265
- continue;
9448
+ let lastErrStatus = 0;
9449
+ let lastErrText = "";
9450
+ for (const attempt of fetchAttempts) {
9451
+ try {
9452
+ const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
9453
+ if (!resp.ok) {
9454
+ lastErrStatus = resp.status;
9455
+ lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
9456
+ if (attempt.label === "public-r2" && resp.status === 404) {
9457
+ ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
9458
+ continue;
9459
+ }
9460
+ if (attempt.label === "public-r2" && resp.status >= 500) {
9461
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
9462
+ continue;
9463
+ }
9464
+ break;
9266
9465
  }
9267
- if (attempt.label === "public-r2" && resp.status >= 500) {
9268
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 ${resp.status}, falling back to cloud`);
9466
+ payload = await resp.json();
9467
+ lastErrStatus = 0;
9468
+ break;
9469
+ } catch (err) {
9470
+ if (attempt.label === "public-r2") {
9471
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
9269
9472
  continue;
9270
9473
  }
9271
- break;
9272
- }
9273
- payload = await resp.json();
9274
- lastErrStatus = 0;
9275
- break;
9276
- } catch (err) {
9277
- if (attempt.label === "public-r2") {
9278
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
9279
- continue;
9474
+ return c.json({
9475
+ success: false,
9476
+ error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9477
+ }, 502);
9280
9478
  }
9479
+ }
9480
+ if (!payload) {
9281
9481
  return c.json({
9282
9482
  success: false,
9283
- error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9284
- }, 502);
9483
+ error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9484
+ }, lastErrStatus === 404 ? 404 : 502);
9285
9485
  }
9486
+ const data = payload?.data ?? payload;
9487
+ manifest = data?.manifest;
9488
+ resolvedVersionId = String(data?.version_id ?? versionId);
9489
+ version = String(data?.version ?? "unknown");
9286
9490
  }
9287
- if (!payload) {
9288
- return c.json({
9289
- success: false,
9290
- error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9291
- }, lastErrStatus === 404 ? 404 : 502);
9292
- }
9293
- const data = payload?.data ?? payload;
9294
- const manifest = data?.manifest;
9295
- const resolvedVersionId = String(data?.version_id ?? versionId);
9296
- const version = String(data?.version ?? "unknown");
9297
9491
  const manifestId = String(manifest?.id ?? manifest?.name ?? "");
9298
9492
  if (!manifest || !manifestId) {
9299
- return c.json({ success: false, error: { code: "invalid_manifest", message: "Cloud returned an invalid manifest payload." } }, 502);
9493
+ return c.json({ success: false, error: { code: "invalid_manifest", message: "Invalid manifest payload." } }, inlineManifest ? 400 : 502);
9300
9494
  }
9301
9495
  const conflict = this.findConflict(ctx, manifestId);
9302
9496
  if (conflict === "user-code") {
@@ -9308,6 +9502,18 @@ var MarketplaceInstallLocalPlugin = class {
9308
9502
  }
9309
9503
  }, 409);
9310
9504
  }
9505
+ try {
9506
+ const manifestService = ctx.getService("manifest");
9507
+ manifestService.register(manifest);
9508
+ } catch (err) {
9509
+ if (inlineManifest) {
9510
+ return c.json({
9511
+ success: false,
9512
+ error: { code: "register_failed", message: `Failed to register imported manifest: ${err?.message ?? err}` }
9513
+ }, 422);
9514
+ }
9515
+ ctx.logger?.warn?.(`[MarketplaceInstallLocal] hot-register failed for ${manifestId} (will load on next restart): ${err?.message ?? err}`);
9516
+ }
9311
9517
  const entry = {
9312
9518
  packageId,
9313
9519
  versionId: resolvedVersionId,
@@ -9319,20 +9525,14 @@ var MarketplaceInstallLocalPlugin = class {
9319
9525
  withSampleData: false
9320
9526
  };
9321
9527
  try {
9322
- (0, import_node_fs3.mkdirSync)(this.storageDir, { recursive: true });
9323
- (0, import_node_fs3.writeFileSync)((0, import_node_path6.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9528
+ (0, import_node_fs4.mkdirSync)(this.storageDir, { recursive: true });
9529
+ (0, import_node_fs4.writeFileSync)((0, import_node_path7.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9324
9530
  } catch (err) {
9325
9531
  return c.json({
9326
9532
  success: false,
9327
9533
  error: { code: "storage_failed", message: `Failed to persist manifest: ${err?.message ?? err}` }
9328
9534
  }, 500);
9329
9535
  }
9330
- try {
9331
- const manifestService = ctx.getService("manifest");
9332
- manifestService.register(manifest);
9333
- } catch (err) {
9334
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] hot-register failed for ${manifestId} (will load on next restart): ${err?.message ?? err}`);
9335
- }
9336
9536
  try {
9337
9537
  const ql = ctx.getService("objectql");
9338
9538
  if (ql && typeof ql.syncSchemas === "function") {
@@ -9346,7 +9546,7 @@ var MarketplaceInstallLocalPlugin = class {
9346
9546
  if (seededSummary.seeded.mode === "inline" && (seededSummary.seeded.inserted ?? 0) + (seededSummary.seeded.updated ?? 0) > 0) {
9347
9547
  entry.withSampleData = true;
9348
9548
  try {
9349
- (0, import_node_fs3.writeFileSync)((0, import_node_path6.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9549
+ (0, import_node_fs4.writeFileSync)((0, import_node_path7.join)(this.storageDir, safeFilename(manifestId)), JSON.stringify(entry, null, 2), "utf8");
9350
9550
  } catch {
9351
9551
  }
9352
9552
  }
@@ -9393,12 +9593,12 @@ var MarketplaceInstallLocalPlugin = class {
9393
9593
  if (!manifestId) {
9394
9594
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9395
9595
  }
9396
- const file = (0, import_node_path6.join)(this.storageDir, safeFilename(manifestId));
9397
- if (!(0, import_node_fs3.existsSync)(file)) {
9596
+ const file = (0, import_node_path7.join)(this.storageDir, safeFilename(manifestId));
9597
+ if (!(0, import_node_fs4.existsSync)(file)) {
9398
9598
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9399
9599
  }
9400
9600
  try {
9401
- (0, import_node_fs3.unlinkSync)(file);
9601
+ (0, import_node_fs4.unlinkSync)(file);
9402
9602
  } catch (err) {
9403
9603
  return c.json({ success: false, error: { code: "storage_failed", message: err?.message ?? String(err) } }, 500);
9404
9604
  }
@@ -9421,7 +9621,7 @@ var MarketplaceInstallLocalPlugin = class {
9421
9621
  * (refuse to avoid silently overwriting authored code)
9422
9622
  */
9423
9623
  this.findConflict = (ctx, manifestId) => {
9424
- if ((0, import_node_fs3.existsSync)((0, import_node_path6.join)(this.storageDir, safeFilename(manifestId)))) {
9624
+ if ((0, import_node_fs4.existsSync)((0, import_node_path7.join)(this.storageDir, safeFilename(manifestId)))) {
9425
9625
  return "marketplace";
9426
9626
  }
9427
9627
  try {
@@ -9463,13 +9663,13 @@ var MarketplaceInstallLocalPlugin = class {
9463
9663
  if (!manifestId) {
9464
9664
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9465
9665
  }
9466
- const file = (0, import_node_path6.join)(this.storageDir, safeFilename(manifestId));
9467
- if (!(0, import_node_fs3.existsSync)(file)) {
9666
+ const file = (0, import_node_path7.join)(this.storageDir, safeFilename(manifestId));
9667
+ if (!(0, import_node_fs4.existsSync)(file)) {
9468
9668
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9469
9669
  }
9470
9670
  let entry;
9471
9671
  try {
9472
- entry = JSON.parse((0, import_node_fs3.readFileSync)(file, "utf8"));
9672
+ entry = JSON.parse((0, import_node_fs4.readFileSync)(file, "utf8"));
9473
9673
  } catch (err) {
9474
9674
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9475
9675
  }
@@ -9485,7 +9685,7 @@ var MarketplaceInstallLocalPlugin = class {
9485
9685
  }
9486
9686
  try {
9487
9687
  entry.withSampleData = true;
9488
- (0, import_node_fs3.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9688
+ (0, import_node_fs4.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9489
9689
  } catch {
9490
9690
  }
9491
9691
  return c.json({
@@ -9517,13 +9717,13 @@ var MarketplaceInstallLocalPlugin = class {
9517
9717
  if (!manifestId) {
9518
9718
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9519
9719
  }
9520
- const file = (0, import_node_path6.join)(this.storageDir, safeFilename(manifestId));
9521
- if (!(0, import_node_fs3.existsSync)(file)) {
9720
+ const file = (0, import_node_path7.join)(this.storageDir, safeFilename(manifestId));
9721
+ if (!(0, import_node_fs4.existsSync)(file)) {
9522
9722
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9523
9723
  }
9524
9724
  let entry;
9525
9725
  try {
9526
- entry = JSON.parse((0, import_node_fs3.readFileSync)(file, "utf8"));
9726
+ entry = JSON.parse((0, import_node_fs4.readFileSync)(file, "utf8"));
9527
9727
  } catch (err) {
9528
9728
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9529
9729
  }
@@ -9572,7 +9772,7 @@ var MarketplaceInstallLocalPlugin = class {
9572
9772
  }
9573
9773
  try {
9574
9774
  entry.withSampleData = false;
9575
- (0, import_node_fs3.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9775
+ (0, import_node_fs4.writeFileSync)(file, JSON.stringify(entry, null, 2), "utf8");
9576
9776
  } catch {
9577
9777
  }
9578
9778
  ctx.logger?.info?.(`[MarketplaceInstallLocal] purged ${manifestId}: deleted=${deleted} skipped=${skipped} errors=${errors}`);
@@ -9771,12 +9971,12 @@ var MarketplaceInstallLocalPlugin = class {
9771
9971
  return null;
9772
9972
  };
9773
9973
  this.readAll = () => {
9774
- if (!(0, import_node_fs3.existsSync)(this.storageDir)) return [];
9974
+ if (!(0, import_node_fs4.existsSync)(this.storageDir)) return [];
9775
9975
  const out = [];
9776
- for (const name of (0, import_node_fs3.readdirSync)(this.storageDir)) {
9976
+ for (const name of (0, import_node_fs4.readdirSync)(this.storageDir)) {
9777
9977
  if (!name.endsWith(".json")) continue;
9778
9978
  try {
9779
- const raw = (0, import_node_fs3.readFileSync)((0, import_node_path6.join)(this.storageDir, name), "utf8");
9979
+ const raw = (0, import_node_fs4.readFileSync)((0, import_node_path7.join)(this.storageDir, name), "utf8");
9780
9980
  out.push(JSON.parse(raw));
9781
9981
  } catch {
9782
9982
  }
@@ -9784,7 +9984,7 @@ var MarketplaceInstallLocalPlugin = class {
9784
9984
  return out;
9785
9985
  };
9786
9986
  this.cloudUrl = resolveCloudUrl(config.controlPlaneUrl);
9787
- this.storageDir = config.storageDir ? (0, import_node_path6.resolve)(config.storageDir) : (0, import_node_path6.resolve)(process.cwd(), DEFAULT_DIR);
9987
+ this.storageDir = config.storageDir ? (0, import_node_path7.resolve)(config.storageDir) : (0, import_node_path7.resolve)(process.cwd(), DEFAULT_DIR);
9788
9988
  }
9789
9989
  };
9790
9990