@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.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
@@ -1267,6 +1313,7 @@ var init_app_plugin = __esm({
1267
1313
  "src/app-plugin.ts"() {
1268
1314
  "use strict";
1269
1315
  init_seed_loader();
1316
+ init_package_state_store();
1270
1317
  init_quickjs_runner();
1271
1318
  init_body_runner();
1272
1319
  AppPlugin = class {
@@ -1292,6 +1339,24 @@ var init_app_plugin = __esm({
1292
1339
  console.warn(
1293
1340
  `[AppPlugin:init] appId=${appId} keys=${Object.keys(servicePayload).join(",")} flows=${Array.isArray(servicePayload.flows) ? servicePayload.flows.length : "n/a"}`
1294
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
+ }
1295
1360
  ctx.getService("manifest").register(servicePayload);
1296
1361
  };
1297
1362
  this.start = async (ctx) => {
@@ -1836,6 +1901,170 @@ var init_app_plugin = __esm({
1836
1901
  }
1837
1902
  });
1838
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
+
1839
2068
  // src/cloud/platform-sso.ts
1840
2069
  var platform_sso_exports = {};
1841
2070
  __export(platform_sso_exports, {
@@ -2240,173 +2469,19 @@ var Runtime = class {
2240
2469
  }
2241
2470
  };
2242
2471
 
2243
- // src/standalone-stack.ts
2244
- init_load_artifact_bundle();
2245
- import { resolve as resolvePath2 } from "path";
2246
- import { mkdirSync } from "fs";
2247
- import { homedir } from "os";
2248
- import { z } from "zod";
2249
- import { readEnvWithDeprecation as readEnvWithDeprecation2 } from "@objectstack/types";
2250
- function resolveObjectStackHome() {
2251
- const raw = process.env.OS_HOME?.trim();
2252
- if (raw && raw.length > 0) {
2253
- if (raw.startsWith("~")) return resolvePath2(homedir(), raw.slice(1).replace(/^[/\\]/, ""));
2254
- return resolvePath2(raw);
2255
- }
2256
- return resolvePath2(homedir(), ".objectstack");
2257
- }
2258
- var StandaloneStackConfigSchema = z.object({
2259
- databaseUrl: z.string().optional(),
2260
- databaseAuthToken: z.string().optional(),
2261
- databaseDriver: z.enum(["sqlite", "sqlite-wasm", "memory", "postgres", "mongodb"]).optional(),
2262
- environmentId: z.string().optional(),
2263
- artifactPath: z.string().optional(),
2264
- /**
2265
- * Project root directory. When set (typically by the CLI after locating
2266
- * `objectstack.config.ts`), the default sqlite database is placed under
2267
- * `<projectRoot>/.objectstack/data/standalone.db` instead of the global
2268
- * `~/.objectstack/data/standalone.db`. This keeps per-project data
2269
- * scoped to the project folder so different examples / apps don't
2270
- * share a single database by accident.
2271
- *
2272
- * Explicit `databaseUrl` / `OS_DATABASE_URL` / `OS_HOME` still take
2273
- * precedence over this default.
2274
- */
2275
- projectRoot: z.string().optional()
2276
- });
2277
- function detectDriverFromUrl(dbUrl) {
2278
- if (/^memory:\/\//i.test(dbUrl)) return "memory";
2279
- if (/^(postgres(ql)?|pg):\/\//i.test(dbUrl)) return "postgres";
2280
- if (/^mongodb(\+srv)?:\/\//i.test(dbUrl)) return "mongodb";
2281
- if (/^wasm-sqlite:\/\//i.test(dbUrl)) return "sqlite-wasm";
2282
- if (/\.wasm\.db$/i.test(dbUrl)) return "sqlite-wasm";
2283
- if (/^file:/i.test(dbUrl)) return "sqlite";
2284
- if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(dbUrl)) return "sqlite";
2285
- throw new Error(
2286
- `[StandaloneStack] Unsupported database URL scheme: ${dbUrl}. Supported schemes: memory://, postgres://, pg://, mongodb://, mongodb+srv://, file:`
2287
- );
2288
- }
2289
- async function createStandaloneStack(config) {
2290
- const cfg = StandaloneStackConfigSchema.parse(config ?? {});
2291
- const { ObjectQLPlugin } = await import("@objectstack/objectql");
2292
- const { MetadataPlugin } = await import("@objectstack/metadata");
2293
- const { DriverPlugin: DriverPlugin2 } = await Promise.resolve().then(() => (init_driver_plugin(), driver_plugin_exports));
2294
- const { AppPlugin: AppPlugin2 } = await Promise.resolve().then(() => (init_app_plugin(), app_plugin_exports));
2295
- const cwd = process.cwd();
2296
- const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? "proj_local";
2297
- const artifactPathInput = cfg.artifactPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath2(cwd, "dist/objectstack.json");
2298
- const artifactPath = isHttpUrl(artifactPathInput) ? artifactPathInput : artifactPathInput.startsWith("/") ? artifactPathInput : resolvePath2(cwd, artifactPathInput);
2299
- 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")}`);
2300
- const explicitDriver = cfg.databaseDriver ?? process.env.OS_DATABASE_DRIVER?.trim();
2301
- const dbDriver = explicitDriver ?? detectDriverFromUrl(dbUrl);
2302
- let driverPlugin;
2303
- if (dbDriver === "memory") {
2304
- const { InMemoryDriver } = await import("@objectstack/driver-memory");
2305
- driverPlugin = new DriverPlugin2(new InMemoryDriver());
2306
- } else if (dbDriver === "postgres") {
2307
- const { SqlDriver } = await import("@objectstack/driver-sql");
2308
- driverPlugin = new DriverPlugin2(
2309
- new SqlDriver({
2310
- client: "pg",
2311
- connection: dbUrl,
2312
- pool: { min: 0, max: 5 }
2313
- })
2314
- );
2315
- } else if (dbDriver === "mongodb") {
2316
- let MongoDBDriver;
2317
- try {
2318
- ({ MongoDBDriver } = await import("@objectstack/driver-mongodb"));
2319
- } catch (err) {
2320
- throw new Error(
2321
- `[StandaloneStack] mongodb URL detected but @objectstack/driver-mongodb is not installed. Add it as a dependency or pass an explicit driverPlugin. (${err?.message ?? err})`
2322
- );
2323
- }
2324
- driverPlugin = new DriverPlugin2(new MongoDBDriver({ url: dbUrl }));
2325
- } else if (dbDriver === "sqlite-wasm") {
2326
- const { SqliteWasmDriver } = await import("@objectstack/driver-sqlite-wasm");
2327
- const filename = dbUrl.replace(/^wasm-sqlite:(\/\/)?/i, "").replace(/^file:(\/\/)?/i, "");
2328
- if (filename && filename !== ":memory:") {
2329
- mkdirSync(resolvePath2(filename, ".."), { recursive: true });
2330
- }
2331
- driverPlugin = new DriverPlugin2(
2332
- new SqliteWasmDriver({
2333
- filename: filename || ":memory:",
2334
- persist: filename && filename !== ":memory:" ? "on-write" : void 0
2335
- })
2336
- );
2337
- } else {
2338
- const { SqlDriver } = await import("@objectstack/driver-sql");
2339
- const filename = dbUrl.replace(/^file:(\/\/)?/, "");
2340
- if (!filename || /^[a-z][a-z0-9+.-]*:\/\//i.test(filename)) {
2341
- throw new Error(
2342
- `[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.`
2343
- );
2344
- }
2345
- mkdirSync(resolvePath2(filename, ".."), { recursive: true });
2346
- driverPlugin = new DriverPlugin2(
2347
- new SqlDriver({
2348
- client: "better-sqlite3",
2349
- connection: { filename },
2350
- useNullAsDefault: true
2351
- })
2352
- );
2353
- }
2354
- const artifactBundle = await loadArtifactBundle(artifactPath, {
2355
- tag: "[StandaloneStack]",
2356
- unwrapEnvelope: true
2357
- });
2358
- if (artifactBundle) {
2359
- const flowsCount = Array.isArray(artifactBundle?.flows) ? artifactBundle.flows.length : "n/a";
2360
- console.warn(
2361
- `[StandaloneStack] artifact loaded: path=${artifactPath} keys=${Object.keys(artifactBundle).join(",")} flows=${flowsCount}`
2362
- );
2363
- }
2364
- const plugins = [
2365
- driverPlugin,
2366
- new MetadataPlugin({
2367
- // Source-file scanner OFF — declarative metadata is loaded
2368
- // from the compiled artifact, not from yaml/json files on
2369
- // disk. Scanning would also recursively watch the project
2370
- // root (incl. node_modules), which is expensive and prone
2371
- // to EMFILE.
2372
- watch: false,
2373
- // Artifact-file HMR ON in non-production so edits to
2374
- // `*.view.ts` / `*.flow.ts` (which the CLI dev-mode watcher
2375
- // recompiles into `dist/objectstack.json`) are picked up by
2376
- // the running server WITHOUT requiring a manual restart.
2377
- // Uses polling under the hood (see plugin.ts) to avoid
2378
- // `fs.watch` EMFILE on macOS / busy dev hosts.
2379
- artifactWatch: process.env.NODE_ENV !== "production",
2380
- environmentId,
2381
- artifactSource: { mode: "local-file", path: artifactPath }
2382
- }),
2383
- new ObjectQLPlugin({ environmentId })
2384
- ];
2385
- if (artifactBundle) plugins.push(new AppPlugin2(artifactBundle));
2386
- const requires = Array.isArray(artifactBundle?.requires) ? artifactBundle.requires.filter((c) => typeof c === "string") : void 0;
2387
- const objects = Array.isArray(artifactBundle?.objects) ? artifactBundle.objects : void 0;
2388
- const manifest = artifactBundle?.manifest;
2389
- return {
2390
- plugins,
2391
- api: {
2392
- enableProjectScoping: false,
2393
- projectResolution: "none"
2394
- },
2395
- ...requires ? { requires } : {},
2396
- ...objects ? { objects } : {},
2397
- ...manifest ? { manifest } : {}
2398
- };
2399
- }
2472
+ // src/index.ts
2473
+ init_standalone_stack();
2400
2474
 
2401
2475
  // src/default-host.ts
2402
- import { resolve as resolvePath3 } from "path";
2403
- import { existsSync, mkdirSync as mkdirSync2, writeFileSync } from "fs";
2476
+ init_standalone_stack();
2404
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";
2405
2480
  function resolveDefaultArtifactPath(explicitPath, cwd = process.cwd()) {
2406
2481
  const candidate = explicitPath ?? process.env.OS_ARTIFACT_PATH ?? resolvePath3(cwd, "dist/objectstack.json");
2407
2482
  if (isHttpUrl(candidate)) return candidate;
2408
2483
  if (explicitPath || process.env.OS_ARTIFACT_PATH) return candidate;
2409
- return existsSync(candidate) ? candidate : void 0;
2484
+ return existsSync2(candidate) ? candidate : void 0;
2410
2485
  }
2411
2486
  async function createDefaultHostConfig(options = {}) {
2412
2487
  const { requireArtifact = true, ...standaloneOpts } = options;
@@ -2419,9 +2494,9 @@ async function createDefaultHostConfig(options = {}) {
2419
2494
  if (!resolvedArtifact && !requireArtifact) {
2420
2495
  const home = resolveObjectStackHome();
2421
2496
  const stubPath = resolvePath3(home, "dist/objectstack.json");
2422
- if (!existsSync(stubPath)) {
2423
- mkdirSync2(resolvePath3(stubPath, ".."), { recursive: true });
2424
- writeFileSync(
2497
+ if (!existsSync2(stubPath)) {
2498
+ mkdirSync3(resolvePath3(stubPath, ".."), { recursive: true });
2499
+ writeFileSync2(
2425
2500
  stubPath,
2426
2501
  JSON.stringify(
2427
2502
  {
@@ -2458,10 +2533,11 @@ init_app_plugin();
2458
2533
  init_seed_loader();
2459
2534
 
2460
2535
  // src/http-dispatcher.ts
2536
+ init_package_state_store();
2461
2537
  import { getEnv, resolveLocale } from "@objectstack/core";
2462
2538
  import { readEnvWithDeprecation as readEnvWithDeprecation3 } from "@objectstack/types";
2463
2539
  import { CoreServiceName } from "@objectstack/spec/system";
2464
- import { pluralToSingular } from "@objectstack/spec/shared";
2540
+ import { pluralToSingular, PLURAL_TO_SINGULAR } from "@objectstack/spec/shared";
2465
2541
 
2466
2542
  // src/security/resolve-execution-context.ts
2467
2543
  function readHeader(headers, name) {
@@ -3316,7 +3392,7 @@ var _HttpDispatcher = class _HttpDispatcher {
3316
3392
  if (protocol && typeof protocol.saveMetaItem === "function") {
3317
3393
  try {
3318
3394
  const organizationId = await this.resolveActiveOrganizationId(_context);
3319
- const result = await protocol.saveMetaItem({ type, name, item: body, organizationId });
3395
+ const result = await protocol.saveMetaItem({ type, name, item: body, organizationId, ...packageId ? { packageId } : {} });
3320
3396
  return { handled: true, response: this.success(result) };
3321
3397
  } catch (e) {
3322
3398
  return { handled: true, response: this.error(e.message, 400) };
@@ -3656,12 +3732,22 @@ var _HttpDispatcher = class _HttpDispatcher {
3656
3732
  const id = decodeURIComponent(parts[0]);
3657
3733
  const pkg = registry.enablePackage(id);
3658
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
+ }
3659
3740
  return { handled: true, response: this.success(pkg) };
3660
3741
  }
3661
3742
  if (parts.length === 2 && parts[1] === "disable" && m === "PATCH") {
3662
3743
  const id = decodeURIComponent(parts[0]);
3663
3744
  const pkg = registry.disablePackage(id);
3664
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
+ }
3665
3751
  return { handled: true, response: this.success(pkg) };
3666
3752
  }
3667
3753
  if (parts.length === 2 && parts[1] === "publish" && m === "POST") {
@@ -3682,6 +3768,14 @@ var _HttpDispatcher = class _HttpDispatcher {
3682
3768
  }
3683
3769
  return { handled: true, response: this.error("Metadata service not available", 503) };
3684
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
+ }
3685
3779
  if (parts.length === 1 && m === "GET") {
3686
3780
  const id = decodeURIComponent(parts[0]);
3687
3781
  const pkg = registry.getPackage(id);
@@ -3699,6 +3793,83 @@ var _HttpDispatcher = class _HttpDispatcher {
3699
3793
  }
3700
3794
  return { handled: false };
3701
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
+ }
3702
3873
  /**
3703
3874
  * Cloud / Environment Control-Plane routes.
3704
3875
  *
@@ -6291,6 +6462,14 @@ function createDispatcherPlugin(config = {}) {
6291
6462
  errorResponse(err, res);
6292
6463
  }
6293
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
+ });
6294
6473
  server.get(`${prefix}/packages/:id`, async (req, res) => {
6295
6474
  try {
6296
6475
  const result = await dispatcher.handlePackages(`/${req.params.id}`, "GET", {}, req.query, { request: req });
@@ -8387,7 +8566,7 @@ var AuthProxyPlugin = class {
8387
8566
  };
8388
8567
 
8389
8568
  // src/cloud/cloud-url.ts
8390
- var DEFAULT_CLOUD_URL = "https://cloud.objectos.app";
8569
+ var DEFAULT_CLOUD_URL = "https://cloud.objectos.ai";
8391
8570
  function resolveCloudUrl(explicit) {
8392
8571
  const raw = (explicit ?? process.env.OS_CLOUD_URL ?? "").trim();
8393
8572
  const lower = raw.toLowerCase();
@@ -9062,8 +9241,8 @@ async function createObjectOSStack(config) {
9062
9241
  }
9063
9242
 
9064
9243
  // src/cloud/marketplace-install-local-plugin.ts
9065
- import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
9066
- 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";
9067
9246
  import { readEnvWithDeprecation as readEnvWithDeprecation5 } from "@objectstack/types";
9068
9247
  var ROUTE_BASE = "/api/v1/marketplace/install-local";
9069
9248
  var DEFAULT_DIR = ".objectstack/installed-packages";
@@ -9139,9 +9318,6 @@ var MarketplaceInstallLocalPlugin = class {
9139
9318
  }
9140
9319
  };
9141
9320
  this.handleInstall = async (c, ctx) => {
9142
- if (!this.cloudUrl) {
9143
- return c.json({ success: false, error: { code: "marketplace_unavailable", message: "OS_CLOUD_URL not configured." } }, 503);
9144
- }
9145
9321
  const userId = await this.requireAuthenticatedUser(c, ctx);
9146
9322
  if (!userId) {
9147
9323
  return c.json({ success: false, error: { code: "unauthorized", message: "Authentication required to install packages." } }, 401);
@@ -9151,69 +9327,87 @@ var MarketplaceInstallLocalPlugin = class {
9151
9327
  body = await c.req.json();
9152
9328
  } catch {
9153
9329
  }
9154
- const packageId = String(body?.packageId ?? "").trim();
9155
- const versionId = String(body?.versionId ?? "latest").trim() || "latest";
9156
- if (!packageId) {
9157
- return c.json({ success: false, error: { code: "bad_request", message: "packageId is required." } }, 400);
9158
- }
9159
- let payload;
9160
- const publicBase = resolveMarketplacePublicBaseUrl();
9161
- const fetchAttempts = [];
9162
- 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
+ }
9163
9361
  fetchAttempts.push({
9164
- label: "public-r2",
9165
- 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`
9166
9364
  });
9167
- }
9168
- fetchAttempts.push({
9169
- label: "cloud",
9170
- url: `${this.cloudUrl}/api/v1/marketplace/packages/${encodeURIComponent(packageId)}/versions/${encodeURIComponent(versionId)}/manifest`
9171
- });
9172
- let lastErrStatus = 0;
9173
- let lastErrText = "";
9174
- for (const attempt of fetchAttempts) {
9175
- try {
9176
- const resp = await fetch(attempt.url, { headers: { "Accept": "application/json" } });
9177
- if (!resp.ok) {
9178
- lastErrStatus = resp.status;
9179
- lastErrText = (await resp.text().catch(() => "")).slice(0, 200);
9180
- if (attempt.label === "public-r2" && resp.status === 404) {
9181
- ctx.logger?.info?.(`[MarketplaceInstallLocal] public-r2 miss for ${packageId}@${versionId}, falling back to cloud`);
9182
- 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;
9183
9382
  }
9184
- if (attempt.label === "public-r2" && resp.status >= 500) {
9185
- 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`);
9186
9389
  continue;
9187
9390
  }
9188
- break;
9189
- }
9190
- payload = await resp.json();
9191
- lastErrStatus = 0;
9192
- break;
9193
- } catch (err) {
9194
- if (attempt.label === "public-r2") {
9195
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] public-r2 fetch error: ${err?.message ?? err}, falling back to cloud`);
9196
- continue;
9391
+ return c.json({
9392
+ success: false,
9393
+ error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9394
+ }, 502);
9197
9395
  }
9396
+ }
9397
+ if (!payload) {
9198
9398
  return c.json({
9199
9399
  success: false,
9200
- error: { code: "cloud_fetch_failed", message: err?.message ?? String(err) }
9201
- }, 502);
9400
+ error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9401
+ }, lastErrStatus === 404 ? 404 : 502);
9202
9402
  }
9403
+ const data = payload?.data ?? payload;
9404
+ manifest = data?.manifest;
9405
+ resolvedVersionId = String(data?.version_id ?? versionId);
9406
+ version = String(data?.version ?? "unknown");
9203
9407
  }
9204
- if (!payload) {
9205
- return c.json({
9206
- success: false,
9207
- error: { code: "cloud_fetch_failed", message: `Cloud returned ${lastErrStatus}: ${lastErrText}` }
9208
- }, lastErrStatus === 404 ? 404 : 502);
9209
- }
9210
- const data = payload?.data ?? payload;
9211
- const manifest = data?.manifest;
9212
- const resolvedVersionId = String(data?.version_id ?? versionId);
9213
- const version = String(data?.version ?? "unknown");
9214
9408
  const manifestId = String(manifest?.id ?? manifest?.name ?? "");
9215
9409
  if (!manifest || !manifestId) {
9216
- 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);
9217
9411
  }
9218
9412
  const conflict = this.findConflict(ctx, manifestId);
9219
9413
  if (conflict === "user-code") {
@@ -9225,6 +9419,18 @@ var MarketplaceInstallLocalPlugin = class {
9225
9419
  }
9226
9420
  }, 409);
9227
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
+ }
9228
9434
  const entry = {
9229
9435
  packageId,
9230
9436
  versionId: resolvedVersionId,
@@ -9236,20 +9442,14 @@ var MarketplaceInstallLocalPlugin = class {
9236
9442
  withSampleData: false
9237
9443
  };
9238
9444
  try {
9239
- mkdirSync3(this.storageDir, { recursive: true });
9240
- 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");
9241
9447
  } catch (err) {
9242
9448
  return c.json({
9243
9449
  success: false,
9244
9450
  error: { code: "storage_failed", message: `Failed to persist manifest: ${err?.message ?? err}` }
9245
9451
  }, 500);
9246
9452
  }
9247
- try {
9248
- const manifestService = ctx.getService("manifest");
9249
- manifestService.register(manifest);
9250
- } catch (err) {
9251
- ctx.logger?.warn?.(`[MarketplaceInstallLocal] hot-register failed for ${manifestId} (will load on next restart): ${err?.message ?? err}`);
9252
- }
9253
9453
  try {
9254
9454
  const ql = ctx.getService("objectql");
9255
9455
  if (ql && typeof ql.syncSchemas === "function") {
@@ -9263,7 +9463,7 @@ var MarketplaceInstallLocalPlugin = class {
9263
9463
  if (seededSummary.seeded.mode === "inline" && (seededSummary.seeded.inserted ?? 0) + (seededSummary.seeded.updated ?? 0) > 0) {
9264
9464
  entry.withSampleData = true;
9265
9465
  try {
9266
- 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");
9267
9467
  } catch {
9268
9468
  }
9269
9469
  }
@@ -9310,8 +9510,8 @@ var MarketplaceInstallLocalPlugin = class {
9310
9510
  if (!manifestId) {
9311
9511
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9312
9512
  }
9313
- const file = join(this.storageDir, safeFilename(manifestId));
9314
- if (!existsSync2(file)) {
9513
+ const file = join2(this.storageDir, safeFilename(manifestId));
9514
+ if (!existsSync3(file)) {
9315
9515
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9316
9516
  }
9317
9517
  try {
@@ -9338,7 +9538,7 @@ var MarketplaceInstallLocalPlugin = class {
9338
9538
  * (refuse to avoid silently overwriting authored code)
9339
9539
  */
9340
9540
  this.findConflict = (ctx, manifestId) => {
9341
- if (existsSync2(join(this.storageDir, safeFilename(manifestId)))) {
9541
+ if (existsSync3(join2(this.storageDir, safeFilename(manifestId)))) {
9342
9542
  return "marketplace";
9343
9543
  }
9344
9544
  try {
@@ -9380,13 +9580,13 @@ var MarketplaceInstallLocalPlugin = class {
9380
9580
  if (!manifestId) {
9381
9581
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9382
9582
  }
9383
- const file = join(this.storageDir, safeFilename(manifestId));
9384
- if (!existsSync2(file)) {
9583
+ const file = join2(this.storageDir, safeFilename(manifestId));
9584
+ if (!existsSync3(file)) {
9385
9585
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9386
9586
  }
9387
9587
  let entry;
9388
9588
  try {
9389
- entry = JSON.parse(readFileSync(file, "utf8"));
9589
+ entry = JSON.parse(readFileSync2(file, "utf8"));
9390
9590
  } catch (err) {
9391
9591
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9392
9592
  }
@@ -9402,7 +9602,7 @@ var MarketplaceInstallLocalPlugin = class {
9402
9602
  }
9403
9603
  try {
9404
9604
  entry.withSampleData = true;
9405
- writeFileSync2(file, JSON.stringify(entry, null, 2), "utf8");
9605
+ writeFileSync3(file, JSON.stringify(entry, null, 2), "utf8");
9406
9606
  } catch {
9407
9607
  }
9408
9608
  return c.json({
@@ -9434,13 +9634,13 @@ var MarketplaceInstallLocalPlugin = class {
9434
9634
  if (!manifestId) {
9435
9635
  return c.json({ success: false, error: { code: "bad_request", message: "manifestId path param required." } }, 400);
9436
9636
  }
9437
- const file = join(this.storageDir, safeFilename(manifestId));
9438
- if (!existsSync2(file)) {
9637
+ const file = join2(this.storageDir, safeFilename(manifestId));
9638
+ if (!existsSync3(file)) {
9439
9639
  return c.json({ success: false, error: { code: "not_found", message: `No marketplace install for ${manifestId}.` } }, 404);
9440
9640
  }
9441
9641
  let entry;
9442
9642
  try {
9443
- entry = JSON.parse(readFileSync(file, "utf8"));
9643
+ entry = JSON.parse(readFileSync2(file, "utf8"));
9444
9644
  } catch (err) {
9445
9645
  return c.json({ success: false, error: { code: "storage_failed", message: `Failed to read manifest cache: ${err?.message ?? err}` } }, 500);
9446
9646
  }
@@ -9489,7 +9689,7 @@ var MarketplaceInstallLocalPlugin = class {
9489
9689
  }
9490
9690
  try {
9491
9691
  entry.withSampleData = false;
9492
- writeFileSync2(file, JSON.stringify(entry, null, 2), "utf8");
9692
+ writeFileSync3(file, JSON.stringify(entry, null, 2), "utf8");
9493
9693
  } catch {
9494
9694
  }
9495
9695
  ctx.logger?.info?.(`[MarketplaceInstallLocal] purged ${manifestId}: deleted=${deleted} skipped=${skipped} errors=${errors}`);
@@ -9688,12 +9888,12 @@ var MarketplaceInstallLocalPlugin = class {
9688
9888
  return null;
9689
9889
  };
9690
9890
  this.readAll = () => {
9691
- if (!existsSync2(this.storageDir)) return [];
9891
+ if (!existsSync3(this.storageDir)) return [];
9692
9892
  const out = [];
9693
9893
  for (const name of readdirSync(this.storageDir)) {
9694
9894
  if (!name.endsWith(".json")) continue;
9695
9895
  try {
9696
- const raw = readFileSync(join(this.storageDir, name), "utf8");
9896
+ const raw = readFileSync2(join2(this.storageDir, name), "utf8");
9697
9897
  out.push(JSON.parse(raw));
9698
9898
  } catch {
9699
9899
  }