@powerhousedao/shared 6.1.0 → 6.2.0-dev.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.
Files changed (92) hide show
  1. package/dist/analytics/index.d.ts +1 -1
  2. package/dist/clis/args/access-token.mjs +1 -1
  3. package/dist/clis/args/common-BQ2pvhCr.d.mts.map +1 -1
  4. package/dist/clis/args/{common-DPYlcz-d.mjs → common-fPNESurz.mjs} +4 -9
  5. package/dist/clis/args/{common-DPYlcz-d.mjs.map → common-fPNESurz.mjs.map} +1 -1
  6. package/dist/clis/args/common.mjs +1 -1
  7. package/dist/clis/args/connect.d.mts +219 -13
  8. package/dist/clis/args/connect.d.mts.map +1 -1
  9. package/dist/clis/args/connect.mjs +138 -4
  10. package/dist/clis/args/connect.mjs.map +1 -1
  11. package/dist/clis/args/{generate-BJPBa0mK.mjs → generate-CTTdiwMD.mjs} +2 -2
  12. package/dist/clis/args/{generate-BJPBa0mK.mjs.map → generate-CTTdiwMD.mjs.map} +1 -1
  13. package/dist/clis/args/generate.mjs +1 -1
  14. package/dist/clis/args/{help-rztSuf9S.mjs → help-CfBzQJpL.mjs} +3 -3
  15. package/dist/clis/args/{help-rztSuf9S.mjs.map → help-CfBzQJpL.mjs.map} +1 -1
  16. package/dist/clis/args/help.mjs +1 -1
  17. package/dist/clis/args/index.d.mts +3 -3
  18. package/dist/clis/args/index.mjs +5 -5
  19. package/dist/clis/args/init.mjs +1 -1
  20. package/dist/clis/args/inspect.mjs +1 -1
  21. package/dist/clis/args/install.mjs +1 -1
  22. package/dist/clis/args/list.mjs +1 -1
  23. package/dist/clis/args/login.mjs +1 -1
  24. package/dist/clis/args/migrate.mjs +1 -1
  25. package/dist/clis/args/publish.mjs +1 -1
  26. package/dist/clis/args/registry.mjs +1 -1
  27. package/dist/clis/args/{service-qS4yFF2I.d.mts → service-DbbCQSks.d.mts} +3 -3
  28. package/dist/clis/args/service-DbbCQSks.d.mts.map +1 -0
  29. package/dist/clis/args/service.d.mts +1 -1
  30. package/dist/clis/args/service.mjs +1 -1
  31. package/dist/clis/args/switchboard.mjs +1 -1
  32. package/dist/clis/args/uninstall.mjs +1 -1
  33. package/dist/clis/args/unpublish.mjs +1 -1
  34. package/dist/clis/args/vetra.mjs +1 -1
  35. package/dist/clis/constants.d.mts +54 -1
  36. package/dist/clis/constants.d.mts.map +1 -1
  37. package/dist/clis/index.d.mts +681 -15
  38. package/dist/clis/index.d.mts.map +1 -1
  39. package/dist/clis/index.mjs +534 -10
  40. package/dist/clis/index.mjs.map +1 -1
  41. package/dist/config-loader-DORViRnN.js +144 -0
  42. package/dist/config-loader-DORViRnN.js.map +1 -0
  43. package/dist/connect/config-loader.d.ts +78 -0
  44. package/dist/connect/config-loader.d.ts.map +1 -0
  45. package/dist/connect/config-loader.js +2 -0
  46. package/dist/connect/index.d.ts +287 -257
  47. package/dist/connect/index.d.ts.map +1 -1
  48. package/dist/connect/index.js +258 -106
  49. package/dist/connect/index.js.map +1 -1
  50. package/dist/connect/json-adapter.d.ts +24 -0
  51. package/dist/connect/json-adapter.d.ts.map +1 -0
  52. package/dist/connect/json-adapter.js +28 -0
  53. package/dist/connect/json-adapter.js.map +1 -0
  54. package/dist/{constants-xNwF0jSl.d.ts → constants-C_EQX4DY.d.ts} +1 -1
  55. package/dist/constants-C_EQX4DY.d.ts.map +1 -0
  56. package/dist/constants.d.ts +1 -1
  57. package/dist/document-drive/index.d.ts +2 -2
  58. package/dist/document-drive/index.d.ts.map +1 -1
  59. package/dist/document-model/index.d.ts +4 -4
  60. package/dist/document-model/index.js +1 -1
  61. package/dist/document-model/mock.d.ts +1 -1
  62. package/dist/document-model/utils.d.ts +2 -2
  63. package/dist/document-model/utils.js +1 -1
  64. package/dist/{index-C_iVZe7f.d.ts → index-CQDIrK1k.d.ts} +1 -1
  65. package/dist/index-CQDIrK1k.d.ts.map +1 -0
  66. package/dist/{index-C2dRwmuW.d.ts → index-DalC_-i7.d.ts} +2 -2
  67. package/dist/{index-C2dRwmuW.d.ts.map → index-DalC_-i7.d.ts.map} +1 -1
  68. package/dist/index.d.ts +7 -6
  69. package/dist/{mock-Cgn-VBF_.d.ts → mock-CbrXTFOF.d.ts} +1 -1
  70. package/dist/{mock-Cgn-VBF_.d.ts.map → mock-CbrXTFOF.d.ts.map} +1 -1
  71. package/dist/processors/index.d.ts +1 -1
  72. package/dist/registry/index.d.ts +2 -1
  73. package/dist/registry/index.d.ts.map +1 -1
  74. package/dist/{types-BFDlQkXZ.d.ts → types-C1in4fl3.d.ts} +1 -1
  75. package/dist/{types-BFDlQkXZ.d.ts.map → types-C1in4fl3.d.ts.map} +1 -1
  76. package/dist/{actions-BqyQ1_K7.d.ts → types-CC6ib3_2.d.ts} +1327 -1327
  77. package/dist/types-CC6ib3_2.d.ts.map +1 -0
  78. package/dist/{types-DA_0pilk.d.ts → types-CVqmv94G.d.ts} +3 -109
  79. package/dist/types-CVqmv94G.d.ts.map +1 -0
  80. package/dist/types-Daq_zHP_.d.ts +160 -0
  81. package/dist/types-Daq_zHP_.d.ts.map +1 -0
  82. package/dist/{utils-CJF4w5Bp.d.ts → utils-BEByNOHo.d.ts} +1 -1
  83. package/dist/utils-BEByNOHo.d.ts.map +1 -0
  84. package/dist/{utils-bCWnsmtD.js → utils-DKOFCM0Q.js} +1 -1
  85. package/dist/{utils-bCWnsmtD.js.map → utils-DKOFCM0Q.js.map} +1 -1
  86. package/package.json +5 -3
  87. package/dist/actions-BqyQ1_K7.d.ts.map +0 -1
  88. package/dist/clis/args/service-qS4yFF2I.d.mts.map +0 -1
  89. package/dist/constants-xNwF0jSl.d.ts.map +0 -1
  90. package/dist/index-C_iVZe7f.d.ts.map +0 -1
  91. package/dist/types-DA_0pilk.d.ts.map +0 -1
  92. package/dist/utils-CJF4w5Bp.d.ts.map +0 -1
@@ -1,3 +1,5 @@
1
+ import { i as buildRuntimeConfig, n as deepMerge, r as DEFAULT_CONNECT_CONFIG, t as ConfigLoader } from "../config-loader-DORViRnN.js";
2
+ import { JsonConfigAdapter } from "./json-adapter.js";
1
3
  import { z } from "zod";
2
4
  //#region connect/env-config.ts
3
5
  /**
@@ -9,97 +11,39 @@ const booleanString = z.union([z.boolean(), z.enum(["true", "false"])]).transfor
9
11
  return val === "true";
10
12
  });
11
13
  /**
12
- * Coerces string values to number.
13
- */
14
- const numberString = z.union([z.number(), z.string()]).transform((val) => {
15
- if (typeof val === "number") return val;
16
- return parseInt(val, 10);
17
- });
18
- /**
19
14
  * Build-time configuration schema
20
15
  */
21
16
  const buildEnvSchema = z.object({
22
- PH_CONFIG_PATH: z.string().optional(),
23
17
  PH_PACKAGES: z.string().optional(),
24
18
  PH_LOCAL_PACKAGE: z.string().optional(),
25
- PH_DISABLE_LOCAL_PACKAGE: booleanString.default(false),
26
- PH_WATCH_TIMEOUT: numberString.default(300),
27
19
  PH_SENTRY_AUTH_TOKEN: z.string().optional(),
28
20
  PH_SENTRY_ORG: z.string().optional(),
29
21
  PH_SENTRY_PROJECT: z.string().optional()
30
22
  });
31
23
  /**
32
- * Application configuration schema
24
+ * Connect runtime values (anything in `PHConnectRuntimeConfig`) are NOT
25
+ * settable from env vars. They live in `powerhouse.config.json` and are
26
+ * overridden via `ph connect build --<field>` or `ph connect config
27
+ * --<field>`.
28
+ *
29
+ * What stays env-driven below is non-runtime: build metadata, Sentry
30
+ * credentials, analytics processor toggles, etc.
33
31
  */
34
32
  const appConfigSchema = z.object({
35
33
  PH_CONNECT_VERSION: z.string().default("unknown"),
36
- PH_CONNECT_LOG_LEVEL: z.enum([
37
- "debug",
38
- "info",
39
- "warn",
40
- "error"
41
- ]).default("info"),
42
- PH_CONNECT_REQUIRES_HARD_REFRESH: booleanString.default(true),
43
- PH_CONNECT_WARN_OUTDATED_APP: booleanString.default(false),
44
- PH_CONNECT_STUDIO_MODE: booleanString.default(false),
45
- PH_CONNECT_BASE_PATH: z.string().optional(),
46
- PH_CONNECT_DEFAULT_DRIVES_URL: z.string().optional(),
47
- PH_CONNECT_PACKAGES: z.string().optional(),
48
- PH_CONNECT_PACKAGES_REGISTRY: z.string().optional(),
49
- PH_CONNECT_DRIVES_PRESERVE_STRATEGY: z.string().optional(),
50
- PH_CONNECT_VERSION_CHECK_INTERVAL: numberString.default(3600 * 1e3),
51
- PH_CONNECT_CLI_VERSION: z.string().optional(),
52
- PH_CONNECT_FILE_UPLOAD_OPERATIONS_CHUNK_SIZE: numberString.default(50)
53
- });
54
- /**
55
- * Feature flags and UI configuration schema
56
- */
57
- const featureFlagsSchema = z.object({
58
- PH_CONNECT_DISABLE_ADD_DRIVE: booleanString.default(false),
59
- PH_CONNECT_SEARCH_BAR_ENABLED: booleanString.default(false),
60
- PH_CONNECT_HIDE_DOCUMENT_MODEL_SELECTION_SETTINGS: booleanString.default(true),
61
- PH_CONNECT_ENABLED_EDITORS: z.string().optional(),
62
- PH_CONNECT_DISABLED_EDITORS: z.string().default("powerhouse/document-drive"),
63
- PH_CONNECT_GA_TRACKING_ID: z.string().optional(),
64
- PH_CONNECT_EXTERNAL_PACKAGES_DISABLED: booleanString.default(false)
34
+ PH_CONNECT_CLI_VERSION: z.string().optional()
65
35
  });
66
36
  /**
67
- * Drives configuration schema
37
+ * Analytics processor configuration schema. These are non-runtime feature
38
+ * toggles for the analytics subsystem — they don't live in the runtime
39
+ * schema and stay env-driven.
68
40
  */
69
- const drivesConfigSchema = z.object({
70
- PH_CONNECT_PUBLIC_DRIVES_ENABLED: booleanString.default(true),
71
- PH_CONNECT_DISABLE_ADD_PUBLIC_DRIVES: booleanString.default(false),
72
- PH_CONNECT_DISABLE_DELETE_PUBLIC_DRIVES: booleanString.default(false),
73
- PH_CONNECT_CLOUD_DRIVES_ENABLED: booleanString.default(true),
74
- PH_CONNECT_DISABLE_ADD_CLOUD_DRIVES: booleanString.default(false),
75
- PH_CONNECT_DISABLE_DELETE_CLOUD_DRIVES: booleanString.default(false),
76
- PH_CONNECT_LOCAL_DRIVES_ENABLED: booleanString.default(true),
77
- PH_CONNECT_DISABLE_ADD_LOCAL_DRIVES: booleanString.default(false),
78
- PH_CONNECT_DISABLE_DELETE_LOCAL_DRIVES: booleanString.default(false)
79
- });
80
- /**
81
- * Analytics processor configuration schema
82
- */
83
- const analyticsProcessorsConfigSchema = z.object({
84
- PH_CONNECT_ANALYTICS_ENABLED: booleanString.default(true),
85
- PH_CONNECT_ANALYTICS_DATABASE_NAME: z.string().optional(),
86
- PH_CONNECT_ANALYTICS_DATABASE_WORKER_DISABLED: booleanString.default(true),
41
+ const processorsConfigSchema = z.object({
87
42
  PH_CONNECT_DIFF_ANALYTICS_ENABLED: booleanString.default(false),
88
43
  PH_CONNECT_DRIVE_ANALYTICS_ENABLED: booleanString.default(true),
89
44
  PH_CONNECT_EXTERNAL_ANALYTICS_PROCESSORS_ENABLED: booleanString.default(true)
90
45
  });
91
46
  /**
92
- * Relational DB processor configuration schema
93
- */
94
- const relationalProcessorsConfigSchema = z.object({
95
- PH_CONNECT_RELATIONAL_PROCESSORS_ENABLED: booleanString.default(true),
96
- PH_CONNECT_EXTERNAL_RELATIONAL_PROCESSORS_ENABLED: booleanString.default(true)
97
- });
98
- const processorsConfigSchema = z.object({
99
- PH_CONNECT_PROCESSORS_ENABLED: booleanString.default(true),
100
- PH_CONNECT_EXTERNAL_PROCESSORS_ENABLED: booleanString.default(true)
101
- }).extend(analyticsProcessorsConfigSchema.shape).extend(relationalProcessorsConfigSchema.shape);
102
- /**
103
47
  * OpenPanel analytics configuration schema
104
48
  */
105
49
  const openPanelConfigSchema = z.object({
@@ -109,26 +53,11 @@ const openPanelConfigSchema = z.object({
109
53
  PH_CONNECT_OPENPANEL_TRACK_OPERATIONS: booleanString.default(true)
110
54
  });
111
55
  /**
112
- * Sentry error tracking configuration schema
113
- */
114
- const sentryConfigSchema = z.object({
115
- PH_CONNECT_SENTRY_RELEASE: z.string().optional(),
116
- PH_CONNECT_SENTRY_DSN: z.string().optional(),
117
- PH_CONNECT_SENTRY_ENV: z.string().default("dev"),
118
- PH_CONNECT_SENTRY_TRACING_ENABLED: booleanString.default(false)
119
- });
120
- /**
121
- * Renown authentication configuration schema
122
- */
123
- const renownConfigSchema = z.object({
124
- PH_CONNECT_RENOWN_URL: z.string().default("https://www.renown.id"),
125
- PH_CONNECT_RENOWN_NETWORK_ID: z.string().default("eip155"),
126
- PH_CONNECT_RENOWN_CHAIN_ID: numberString.default(1)
127
- });
128
- /**
129
- * Complete runtime environment schema (all PH_CONNECT_* vars)
56
+ * Complete runtime environment schema (all PH_CONNECT_* vars). Only
57
+ * build-metadata + analytics-processor toggles live here; all Connect
58
+ * runtime config lives in `powerhouse.config.json`.
130
59
  */
131
- const runtimeEnvSchema = appConfigSchema.extend(featureFlagsSchema.shape).extend(drivesConfigSchema.shape).extend(processorsConfigSchema.shape).extend(openPanelConfigSchema.shape).extend(sentryConfigSchema.shape).extend(renownConfigSchema.shape);
60
+ const runtimeEnvSchema = appConfigSchema.extend(processorsConfigSchema.shape).extend(openPanelConfigSchema.shape);
132
61
  /**
133
62
  * Complete environment schema (build + runtime)
134
63
  */
@@ -172,9 +101,8 @@ function mergeEnvSources(options, keys, schema) {
172
101
  /**
173
102
  * Loads and validates environment variables with priority:
174
103
  * 1. process.env (highest)
175
- * 2. options
176
- * 3. fileEnv
177
- * 4. defaults from schema (lowest)
104
+ * 2. fileEnv
105
+ * 3. defaults from schema (lowest)
178
106
  *
179
107
  * @param options - Environment sources in priority order
180
108
  * @returns Validated and typed environment configuration
@@ -184,7 +112,9 @@ function loadConnectEnv(options = {}) {
184
112
  return connectEnvSchema.parse(merged);
185
113
  }
186
114
  /**
187
- * Loads only runtime environment variables
115
+ * Loads only runtime environment variables (build metadata + Sentry +
116
+ * analytics-processor toggles — everything in the Connect runtime schema
117
+ * is sourced from powerhouse.config.json, not env).
188
118
  *
189
119
  * @param options - Environment sources in priority order
190
120
  * @returns Validated runtime environment configuration
@@ -194,16 +124,6 @@ function loadRuntimeEnv(options = {}) {
194
124
  return runtimeEnvSchema.parse(merged);
195
125
  }
196
126
  /**
197
- * Loads only build-time environment variables
198
- *
199
- * @param options - Environment sources in priority order
200
- * @returns Validated build environment configuration
201
- */
202
- function loadBuildEnv(options = {}) {
203
- const merged = mergeEnvSources(options, new Set(Object.keys(buildEnvSchema.shape)), buildEnvSchema);
204
- return buildEnvSchema.parse(merged);
205
- }
206
- /**
207
127
  * Safely sets Connect environment variables with validation.
208
128
  * Invalid values will log a warning and be skipped.
209
129
  *
@@ -212,9 +132,8 @@ function loadBuildEnv(options = {}) {
212
132
  * @example
213
133
  * ```ts
214
134
  * setConnectEnv({
215
- * PH_CONNECT_LOG_LEVEL: "debug",
216
135
  * PH_CONNECT_VERSION: "1.2.3",
217
- * PH_CONNECT_STUDIO_MODE: true,
136
+ * PH_CONNECT_SENTRY_DSN: "https://…",
218
137
  * });
219
138
  * ```
220
139
  */
@@ -257,7 +176,240 @@ function normalizeBasePath(basePath) {
257
176
  if (!normalized.endsWith("/")) normalized = `${normalized}/`;
258
177
  return normalized;
259
178
  }
179
+ /**
180
+ * Base storage namespace for a Connect instance served at the root of an
181
+ * origin. Kept as a literal so root deployments resolve to a byte-identical
182
+ * value with no migration.
183
+ */
184
+ const ROOT_STORAGE_NAMESPACE = "reactor";
185
+ /**
186
+ * Derives the origin-scoped storage namespace from a Connect base path.
187
+ *
188
+ * Connect instances served under different path prefixes of the same origin
189
+ * (e.g. behind a reverse proxy) otherwise share all origin-scoped browser
190
+ * storage (PGlite data dirs, IndexedDB). This produces a deterministic,
191
+ * collision-free namespace per distinct prefix that is valid as an
192
+ * IndexedDB database name.
193
+ *
194
+ * - root base path ("/" or unset) -> "reactor" (byte-identical to the legacy
195
+ * key, so existing root deployments keep their data with zero migration)
196
+ * - any non-root base path -> "reactor--<slug>", e.g.
197
+ * "/reactor-project/vetra-studio/" -> "reactor--reactor-project-vetra-studio"
198
+ *
199
+ * @param basePath - The Connect base path (env.PH_CONNECT_BASE_PATH ||
200
+ * import.meta.env.BASE_URL); normalized internally.
201
+ * @returns The storage namespace.
202
+ *
203
+ * @example
204
+ * getStorageNamespace('/') // 'reactor'
205
+ * getStorageNamespace('/reactor-project/vetra-studio/') // 'reactor--reactor-project-vetra-studio'
206
+ */
207
+ function getStorageNamespace(basePath) {
208
+ const normalized = normalizeBasePath(basePath);
209
+ if (normalized === "/") return ROOT_STORAGE_NAMESPACE;
210
+ return `${ROOT_STORAGE_NAMESPACE}--${normalized.slice(1, -1).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "default"}`;
211
+ }
212
+ //#endregion
213
+ //#region connect/schema-fragments.ts
214
+ const powerhousePackageSchema = {
215
+ type: "object",
216
+ additionalProperties: false,
217
+ required: ["packageName"],
218
+ properties: {
219
+ packageName: {
220
+ type: "string",
221
+ description: "Fully qualified npm package name (e.g. @scope/name)."
222
+ },
223
+ version: {
224
+ type: "string",
225
+ description: "Exact version (registry providers) or omit to take latest."
226
+ },
227
+ provider: {
228
+ type: "string",
229
+ enum: [
230
+ "npm",
231
+ "github",
232
+ "local",
233
+ "registry"
234
+ ],
235
+ description: "Where Connect should resolve the package from at runtime."
236
+ },
237
+ url: {
238
+ type: "string",
239
+ description: "Override URL for non-registry providers (e.g. github tarball)."
240
+ }
241
+ }
242
+ };
243
+ const driveSectionSchema = {
244
+ type: "object",
245
+ additionalProperties: false,
246
+ description: "Visibility and add/delete affordances for a drive section in the sidebar.",
247
+ properties: {
248
+ enabled: {
249
+ type: "boolean",
250
+ description: "When false, the section is hidden in the sidebar.",
251
+ default: true
252
+ },
253
+ allowAdd: {
254
+ type: "boolean",
255
+ description: "When false, the section's 'add drive' affordance is hidden.",
256
+ default: true
257
+ },
258
+ allowDelete: {
259
+ type: "boolean",
260
+ description: "When false, drives in this section cannot be deleted from the UI.",
261
+ default: true
262
+ }
263
+ }
264
+ };
265
+ const phConnectRuntimeConfigSchema = {
266
+ type: "object",
267
+ additionalProperties: false,
268
+ description: "Connect-specific UI customisations. All fields optional; omit the section entirely for default behaviour.",
269
+ properties: {
270
+ branding: {
271
+ type: "object",
272
+ additionalProperties: false,
273
+ description: "App identity and visual branding.",
274
+ properties: {
275
+ appName: {
276
+ type: "string",
277
+ description: "Browser tab title and any in-app brand text. Defaults to 'Powerhouse Connect'."
278
+ },
279
+ homeBackground: {
280
+ type: ["string", "null"],
281
+ description: "Hero image on the empty home screen. URL or path to override; null or omitted uses the bundled default image."
282
+ }
283
+ }
284
+ },
285
+ app: {
286
+ type: "object",
287
+ additionalProperties: false,
288
+ description: "Top-level Connect application behaviour.",
289
+ properties: {
290
+ logLevel: {
291
+ type: "string",
292
+ enum: [
293
+ "debug",
294
+ "info",
295
+ "warn",
296
+ "error"
297
+ ],
298
+ description: "Log level applied by Connect's logger at boot. Affects browser-side output only.",
299
+ default: "info"
300
+ },
301
+ basePath: {
302
+ type: "string",
303
+ description: "Base path Connect is mounted under (e.g. '/connect' for subpath deploys). Normalised at runtime to start and end with '/'. Defaults to the build-time BASE_URL.",
304
+ default: "/"
305
+ }
306
+ }
307
+ },
308
+ packages: {
309
+ type: "object",
310
+ additionalProperties: false,
311
+ description: "Runtime behaviour for the Connect package manager (separate from top-level `packages[]`, which lists which packages to load).",
312
+ properties: {
313
+ externalEnabled: {
314
+ type: "boolean",
315
+ description: "When false, Connect refuses to load any package that wasn't bundled at build time. Affirmative replacement for the legacy PH_CONNECT_EXTERNAL_PACKAGES_DISABLED env var.",
316
+ default: true
317
+ },
318
+ liveReload: {
319
+ type: "boolean",
320
+ description: "When true, Connect subscribes to the static-mode `/__packages` SSE channel so live publishes flow into the running tab without a page reload. Only works under hosting that serves this channel (e.g. ph-clint static mode).",
321
+ default: false
322
+ }
323
+ }
324
+ },
325
+ drives: {
326
+ type: "object",
327
+ additionalProperties: false,
328
+ description: "Default-drive and add-drive UI behaviour.",
329
+ properties: {
330
+ allowAddDrive: {
331
+ type: "boolean",
332
+ description: "When false, the SPA hides the 'add drive' affordance entirely (top-level). Per-section overrides live in `sections.{remote,local}.allowAdd`.",
333
+ default: true
334
+ },
335
+ defaultDrives: {
336
+ type: "array",
337
+ description: "Drives the SPA auto-connects to on first load. Each must specify a URL; name and icon are optional overrides.",
338
+ default: [],
339
+ items: {
340
+ type: "object",
341
+ additionalProperties: false,
342
+ required: ["url"],
343
+ properties: {
344
+ url: { type: "string" },
345
+ name: { type: ["string", "null"] },
346
+ icon: { type: ["string", "null"] }
347
+ }
348
+ }
349
+ },
350
+ preserveStrategy: {
351
+ type: "string",
352
+ enum: ["preserve-all", "preserve-by-url-and-detach"],
353
+ description: "Strategy applied when defaultDrives change between deploys. 'preserve-all' keeps user-added drives untouched; 'preserve-by-url-and-detach' detaches removed default drives. No schema default — opt-in only."
354
+ },
355
+ sections: {
356
+ type: "object",
357
+ additionalProperties: false,
358
+ description: "Per-section visibility and affordance toggles. `remote` covers what was historically split into 'public' + 'cloud'; `local` is browser-local drives.",
359
+ properties: {
360
+ remote: driveSectionSchema,
361
+ local: driveSectionSchema
362
+ }
363
+ }
364
+ }
365
+ },
366
+ renown: {
367
+ type: "object",
368
+ additionalProperties: false,
369
+ description: "Renown identity / authentication coordinates.",
370
+ properties: {
371
+ url: {
372
+ type: "string",
373
+ description: "Renown auth service URL.",
374
+ default: "https://www.renown.id"
375
+ },
376
+ networkId: {
377
+ type: "string",
378
+ description: "CAIP-2 network namespace (e.g. 'eip155').",
379
+ default: "eip155"
380
+ },
381
+ chainId: {
382
+ type: "number",
383
+ description: "CAIP-2 chain reference within the network namespace.",
384
+ default: 1
385
+ }
386
+ }
387
+ },
388
+ sentry: {
389
+ type: "object",
390
+ additionalProperties: false,
391
+ description: "Sentry error-tracking coordinates. Set `dsn` to enable Sentry; leave `dsn` null to disable. The Sentry release tag stays build-time (stamped via Vite's `define` from WORKSPACE_VERSION) so it always matches the sourcemaps uploaded by CI.",
392
+ properties: {
393
+ dsn: {
394
+ type: ["string", "null"],
395
+ description: "Sentry DSN URL. `null` disables Sentry entirely; the SPA never loads the Sentry SDK chunk.",
396
+ default: null
397
+ },
398
+ env: {
399
+ type: "string",
400
+ description: "Sentry environment label, surfaced as the `environment` tag on every event.",
401
+ default: "dev"
402
+ },
403
+ tracing: {
404
+ type: "boolean",
405
+ description: "Enable Sentry performance tracing.",
406
+ default: false
407
+ }
408
+ }
409
+ }
410
+ }
411
+ };
260
412
  //#endregion
261
- export { connectEnvSchema, loadBuildEnv, loadConnectEnv, loadRuntimeEnv, normalizeBasePath, runtimeEnvSchema, setConnectEnv };
413
+ export { ConfigLoader, DEFAULT_CONNECT_CONFIG, JsonConfigAdapter, ROOT_STORAGE_NAMESPACE, buildRuntimeConfig, connectEnvSchema, deepMerge, getStorageNamespace, loadConnectEnv, loadRuntimeEnv, normalizeBasePath, phConnectRuntimeConfigSchema, powerhousePackageSchema, runtimeEnvSchema, setConnectEnv };
262
414
 
263
415
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../connect/env-config.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Coerces string values to boolean.\n * Accepts: \"true\", \"false\", true, false\n */\nconst booleanString = z\n .union([z.boolean(), z.enum([\"true\", \"false\"])])\n .transform((val) => {\n if (typeof val === \"boolean\") return val;\n return val === \"true\";\n });\n\n/**\n * Coerces string values to number.\n */\nconst numberString = z.union([z.number(), z.string()]).transform((val) => {\n if (typeof val === \"number\") return val;\n return parseInt(val, 10);\n});\n\n// ============================================================================\n// Build-time Environment Variables\n// ============================================================================\n\n/**\n * Build-time configuration schema\n */\nconst buildEnvSchema = z.object({\n /**\n * Path to powerhouse config file\n * @default \"powerhouse.config.json\"\n */\n PH_CONFIG_PATH: z.string().optional(),\n\n /**\n * Comma-separated list of package names to load\n * @example \"package1,package2\"\n */\n PH_PACKAGES: z.string().optional(),\n\n /**\n * Path to local package to load during development\n */\n PH_LOCAL_PACKAGE: z.string().optional(),\n\n /**\n * Disable loading of local package\n * @default false\n */\n PH_DISABLE_LOCAL_PACKAGE: booleanString.default(false),\n\n /**\n * Amount of time to wait before a file is considered changed\n * @default 300\n */\n PH_WATCH_TIMEOUT: numberString.default(300),\n\n /**\n * Sentry authentication token for uploading source maps\n */\n PH_SENTRY_AUTH_TOKEN: z.string().optional(),\n\n /**\n * Sentry organization slug\n */\n PH_SENTRY_ORG: z.string().optional(),\n\n /**\n * Sentry project slug\n */\n PH_SENTRY_PROJECT: z.string().optional(),\n});\n\n// ============================================================================\n// Application Configuration\n// ============================================================================\n\n/**\n * Application configuration schema\n */\nconst appConfigSchema = z.object({\n /**\n * Application version number\n * @default \"unknown\"\n */\n PH_CONNECT_VERSION: z.string().default(\"unknown\"),\n\n /**\n * Log level for the application\n * @default \"info\"\n */\n PH_CONNECT_LOG_LEVEL: z\n .enum([\"debug\", \"info\", \"warn\", \"error\"])\n .default(\"info\"),\n\n /**\n * Whether app requires hard refresh on updates\n * @default true\n */\n PH_CONNECT_REQUIRES_HARD_REFRESH: booleanString.default(true),\n\n /**\n * Show warning when app version is outdated\n * @default false\n */\n PH_CONNECT_WARN_OUTDATED_APP: booleanString.default(false),\n\n /**\n * Enable studio mode features\n * @default false\n */\n PH_CONNECT_STUDIO_MODE: booleanString.default(false),\n\n /**\n * Base path for the Connect router, defaults to import.meta.env.BASE_URL\n */\n PH_CONNECT_BASE_PATH: z.string().optional(),\n\n /**\n * Default drives URL to load on startup\n */\n PH_CONNECT_DEFAULT_DRIVES_URL: z.string().optional(),\n /*\n * Names of packages to load in connect\n */\n PH_CONNECT_PACKAGES: z.string().optional(),\n /**\n * URL(s) of the packages registry CDN endpoint.\n * Supports comma-separated URLs for multiple registries.\n * @example \"http://localhost:8080/-/cdn/\"\n * @example \"https://registry.powerhouse.io/-/cdn/,http://localhost:8080/-/cdn/\"\n */\n PH_CONNECT_PACKAGES_REGISTRY: z.string().optional(),\n\n /**\n * Strategy for preserving drives\n */\n PH_CONNECT_DRIVES_PRESERVE_STRATEGY: z.string().optional(),\n\n /**\n * Interval in milliseconds to check for version updates\n * @default 3600000 (1 hour)\n */\n PH_CONNECT_VERSION_CHECK_INTERVAL: numberString.default(60 * 60 * 1000),\n\n /**\n * CLI version number\n */\n PH_CONNECT_CLI_VERSION: z.string().optional(),\n\n /**\n * Chunk size for file upload operations\n * @default 50\n */\n PH_CONNECT_FILE_UPLOAD_OPERATIONS_CHUNK_SIZE: numberString.default(50),\n});\n\n// ============================================================================\n// Feature Flags & UI Configuration\n// ============================================================================\n\n/**\n * Feature flags and UI configuration schema\n */\nconst featureFlagsSchema = z.object({\n /**\n * Hide the \"Add Drive\" button completely\n * @default false\n */\n PH_CONNECT_DISABLE_ADD_DRIVE: booleanString.default(false),\n\n /**\n * Show search bar in the UI\n * @default false\n */\n PH_CONNECT_SEARCH_BAR_ENABLED: booleanString.default(false),\n\n /**\n * Hide document model selection in settings\n * @default true\n */\n PH_CONNECT_HIDE_DOCUMENT_MODEL_SELECTION_SETTINGS:\n booleanString.default(true),\n\n /**\n * Comma-separated list of enabled editor types\n * Use \"*\" to enable all editors\n * @example \"editor1,editor2\" or \"*\"\n */\n PH_CONNECT_ENABLED_EDITORS: z.string().optional(),\n\n /**\n * Comma-separated list of disabled editor types\n * @default \"powerhouse/document-drive\"\n */\n PH_CONNECT_DISABLED_EDITORS: z.string().default(\"powerhouse/document-drive\"),\n\n /**\n * Google Analytics tracking ID\n */\n PH_CONNECT_GA_TRACKING_ID: z.string().optional(),\n\n /**\n * Disable loading of external packages\n * @default false\n */\n PH_CONNECT_EXTERNAL_PACKAGES_DISABLED: booleanString.default(false),\n});\n\n// ============================================================================\n// Drives Configuration\n// ============================================================================\n\n/**\n * Drives configuration schema\n */\nconst drivesConfigSchema = z.object({\n /**\n * Enable public drives section\n * @default true\n */\n PH_CONNECT_PUBLIC_DRIVES_ENABLED: booleanString.default(true),\n\n /**\n * Allow adding public drives\n * @default true\n */\n PH_CONNECT_DISABLE_ADD_PUBLIC_DRIVES: booleanString.default(false),\n\n /**\n * Allow deleting public drives\n * @default true\n */\n PH_CONNECT_DISABLE_DELETE_PUBLIC_DRIVES: booleanString.default(false),\n\n /**\n * Enable cloud drives section\n * @default true\n */\n PH_CONNECT_CLOUD_DRIVES_ENABLED: booleanString.default(true),\n\n /**\n * Allow adding cloud drives\n * @default true\n */\n PH_CONNECT_DISABLE_ADD_CLOUD_DRIVES: booleanString.default(false),\n\n /**\n * Allow deleting cloud drives\n * @default true\n */\n PH_CONNECT_DISABLE_DELETE_CLOUD_DRIVES: booleanString.default(false),\n\n /**\n * Enable local drives section\n * @default true\n */\n PH_CONNECT_LOCAL_DRIVES_ENABLED: booleanString.default(true),\n\n /**\n * Allow adding local drives\n * @default true\n */\n PH_CONNECT_DISABLE_ADD_LOCAL_DRIVES: booleanString.default(false),\n\n /**\n * Allow deleting local drives\n * @default true\n */\n PH_CONNECT_DISABLE_DELETE_LOCAL_DRIVES: booleanString.default(false),\n});\n\n// ============================================================================\n// Analytics Processor Configuration\n// ============================================================================\n\n/**\n * Analytics processor configuration schema\n */\nconst analyticsProcessorsConfigSchema = z.object({\n /**\n * Enable analytics\n * @default true\n */\n PH_CONNECT_ANALYTICS_ENABLED: booleanString.default(true),\n\n /**\n * Name of the analytics database\n * Defaults to basename + \":analytics\"\n */\n PH_CONNECT_ANALYTICS_DATABASE_NAME: z.string().optional(),\n\n /**\n * Disable analytics database worker\n * @default false\n */\n PH_CONNECT_ANALYTICS_DATABASE_WORKER_DISABLED: booleanString.default(true),\n\n /**\n * Enable diff analytics tracking\n * @default false\n */\n PH_CONNECT_DIFF_ANALYTICS_ENABLED: booleanString.default(false),\n\n /**\n * Enable drive analytics tracking\n * @default true\n */\n PH_CONNECT_DRIVE_ANALYTICS_ENABLED: booleanString.default(true),\n\n /**\n * Enable external analytics processors\n * @default true\n */\n PH_CONNECT_EXTERNAL_ANALYTICS_PROCESSORS_ENABLED: booleanString.default(true),\n});\n\n/**\n * Relational DB processor configuration schema\n */\nconst relationalProcessorsConfigSchema = z.object({\n /**\n * Enable relational processors\n * @default true\n */\n PH_CONNECT_RELATIONAL_PROCESSORS_ENABLED: booleanString.default(true),\n\n /**\n * Enable external relational processors\n * @default true\n */\n PH_CONNECT_EXTERNAL_RELATIONAL_PROCESSORS_ENABLED:\n booleanString.default(true),\n});\n\n/**\n * External processors configuration schema\n */\nconst processorsBaseConfigSchema = z.object({\n /**\n * Enable processors\n * @default true\n */\n PH_CONNECT_PROCESSORS_ENABLED: booleanString.default(true),\n\n /**\n * Enable external processors\n * @default true\n */\n PH_CONNECT_EXTERNAL_PROCESSORS_ENABLED: booleanString.default(true),\n});\n\nconst processorsConfigSchema = processorsBaseConfigSchema\n .extend(analyticsProcessorsConfigSchema.shape)\n .extend(relationalProcessorsConfigSchema.shape);\n\n// ============================================================================\n// OpenPanel Configuration\n// ============================================================================\n\n/**\n * OpenPanel analytics configuration schema\n */\nconst openPanelConfigSchema = z.object({\n /**\n * OpenPanel client ID. When unset, the OpenPanel subsystem is a no-op.\n */\n PH_CONNECT_OPENPANEL_CLIENT_ID: z.string().optional(),\n\n /**\n * OpenPanel API URL override. Defaults to the OpenPanel cloud when unset.\n */\n PH_CONNECT_OPENPANEL_API_URL: z.string().optional(),\n\n /**\n * Track UI events via the useOpenPanel() hook\n * @default true\n */\n PH_CONNECT_OPENPANEL_TRACK_UI_EVENTS: booleanString.default(true),\n\n /**\n * Track document operations via the OpenPanel processor\n * @default true\n */\n PH_CONNECT_OPENPANEL_TRACK_OPERATIONS: booleanString.default(true),\n});\n\n// ============================================================================\n// Sentry Configuration\n// ============================================================================\n\n/**\n * Sentry error tracking configuration schema\n */\nconst sentryConfigSchema = z.object({\n /**\n * Sentry release identifier\n * Defaults to app version\n */\n PH_CONNECT_SENTRY_RELEASE: z.string().optional(),\n\n /**\n * Sentry DSN for error reporting\n */\n PH_CONNECT_SENTRY_DSN: z.string().optional(),\n\n /**\n * Sentry environment name\n * @default \"prod\"\n */\n PH_CONNECT_SENTRY_ENV: z.string().default(\"dev\"),\n\n /**\n * Enable Sentry performance tracing\n * @default false\n */\n PH_CONNECT_SENTRY_TRACING_ENABLED: booleanString.default(false),\n});\n\n// ============================================================================\n// Renown Configuration\n// ============================================================================\n\n/**\n * Renown authentication configuration schema\n */\nconst renownConfigSchema = z.object({\n /**\n * Renown authentication service URL\n * @default \"https://www.renown.id\"\n */\n PH_CONNECT_RENOWN_URL: z.string().default(\"https://www.renown.id\"),\n\n /**\n * Renown network ID\n * @default \"eip155\"\n */\n PH_CONNECT_RENOWN_NETWORK_ID: z.string().default(\"eip155\"),\n\n /**\n * Renown chain ID\n * @default 1\n */\n PH_CONNECT_RENOWN_CHAIN_ID: numberString.default(1),\n});\n\n// ============================================================================\n// Combined Schemas\n// ============================================================================\n\n/**\n * Complete runtime environment schema (all PH_CONNECT_* vars)\n */\nexport const runtimeEnvSchema = appConfigSchema\n .extend(featureFlagsSchema.shape)\n .extend(drivesConfigSchema.shape)\n .extend(processorsConfigSchema.shape)\n .extend(openPanelConfigSchema.shape)\n .extend(sentryConfigSchema.shape)\n .extend(renownConfigSchema.shape);\n\n/**\n * Complete environment schema (build + runtime)\n */\nexport const connectEnvSchema = buildEnvSchema.extend(runtimeEnvSchema.shape);\n\n/**\n * Inferred TypeScript types from schemas\n */\nexport type ConnectBuildEnv = z.infer<typeof buildEnvSchema>;\nexport type ConnectRuntimeEnv = z.infer<typeof runtimeEnvSchema>;\nexport type ConnectEnv = z.infer<typeof connectEnvSchema>;\n\n// ============================================================================\n// Environment Loading Functions\n// ============================================================================\n\n/**\n * Options for loading environment variables\n */\nexport interface LoadEnvOptions {\n /**\n * Environment variables from process.env (highest priority)\n */\n processEnv?: Record<string, string | undefined>;\n /**\n * Environment variables from .env file (lowest priority)\n */\n fileEnv?: Record<string, string | undefined>;\n}\n\n/**\n * Internal helper to merge environment sources with priority.\n * Validates each value and falls back to next priority if invalid.\n */\nfunction mergeEnvSources(\n options: LoadEnvOptions,\n keys: Set<string>,\n schema: z.ZodObject<Record<string, z.ZodTypeAny>>,\n): Record<string, unknown> {\n const { processEnv = {}, fileEnv = {} } = options;\n const merged: Record<string, unknown> = {};\n\n // Apply priority: fileEnv < optionsEnv < processEnv\n for (const key of keys) {\n const sources = [\n { name: \"process.env\", value: processEnv[key] },\n { name: \"fileEnv\", value: fileEnv[key] },\n ];\n\n // Try each source in priority order\n for (const source of sources) {\n const value = source.value;\n if (value === undefined || value === \"\") continue;\n\n // Try to validate just this field\n try {\n const fieldSchema = schema.shape[key];\n if (fieldSchema) {\n fieldSchema.parse(value);\n merged[key] = value;\n break; // Successfully validated, use this value\n }\n // No schema for this key, accept it\n console.warn(`Unknown environment variable: '${key}'`);\n merged[key] = value;\n break;\n } catch {\n // Validation failed, log warning and try next source\n const valueStr =\n value === null\n ? \"null\"\n : typeof value === \"object\"\n ? JSON.stringify(value)\n : (value as string);\n console.warn(\n `Invalid value for ${key} from ${source.name}: ${valueStr}. Trying next source.`,\n );\n }\n }\n }\n\n return merged;\n}\n\n/**\n * Loads and validates environment variables with priority:\n * 1. process.env (highest)\n * 2. options\n * 3. fileEnv\n * 4. defaults from schema (lowest)\n *\n * @param options - Environment sources in priority order\n * @returns Validated and typed environment configuration\n */\nexport function loadConnectEnv(options: LoadEnvOptions = {}): ConnectEnv {\n const allKeys = new Set([\n ...Object.keys(buildEnvSchema.shape),\n ...Object.keys(runtimeEnvSchema.shape),\n ]);\n\n const merged = mergeEnvSources(options, allKeys, connectEnvSchema);\n return connectEnvSchema.parse(merged);\n}\n\n/**\n * Loads only runtime environment variables\n *\n * @param options - Environment sources in priority order\n * @returns Validated runtime environment configuration\n */\nexport function loadRuntimeEnv(\n options: LoadEnvOptions = {},\n): ConnectRuntimeEnv {\n const allKeys = new Set(Object.keys(runtimeEnvSchema.shape));\n const merged = mergeEnvSources(options, allKeys, runtimeEnvSchema);\n return runtimeEnvSchema.parse(merged);\n}\n\n/**\n * Loads only build-time environment variables\n *\n * @param options - Environment sources in priority order\n * @returns Validated build environment configuration\n */\nexport function loadBuildEnv(options: LoadEnvOptions = {}): ConnectBuildEnv {\n const allKeys = new Set(Object.keys(buildEnvSchema.shape));\n const merged = mergeEnvSources(options, allKeys, buildEnvSchema);\n return buildEnvSchema.parse(merged);\n}\n\n/**\n * Safely sets Connect environment variables with validation.\n * Invalid values will log a warning and be skipped.\n *\n * @param values - Type-safe object with key-value pairs to set\n *\n * @example\n * ```ts\n * setConnectEnv({\n * PH_CONNECT_LOG_LEVEL: \"debug\",\n * PH_CONNECT_VERSION: \"1.2.3\",\n * PH_CONNECT_STUDIO_MODE: true,\n * });\n * ```\n */\nexport function setConnectEnv(values: Partial<ConnectEnv>): void {\n for (const [key, value] of Object.entries(values)) {\n // Check if key exists in schema\n const fieldSchema =\n connectEnvSchema.shape[key as keyof typeof connectEnvSchema.shape];\n\n if (!fieldSchema) {\n console.warn(\n `Unknown environment variable: ${key}. Variable not set. Valid keys: ${Object.keys(connectEnvSchema.shape).join(\", \")}`,\n );\n continue;\n }\n\n try {\n // Validate the value\n fieldSchema.parse(value);\n\n // Set the value (convert to string for process.env compatibility)\n process.env[key] = String(value);\n } catch (error) {\n console.warn(\n `Invalid value for ${key}: ${String(value)}. Validation failed.`,\n error,\n );\n }\n }\n}\n\n/**\n * Normalizes a base path to ensure it:\n * - Starts with a forward slash (/)\n * - Ends with a forward slash (/)\n * - Has no relative path prefix (.)\n *\n * @param basePath - The base path to normalize\n * @returns The normalized base path\n *\n * @example\n * normalizeBasePath('/app') // '/app/'\n * normalizeBasePath('./app/') // '/app/'\n * normalizeBasePath('app') // '/app/'\n * normalizeBasePath('/') // '/'\n * normalizeBasePath('') // '/'\n */\nexport function normalizeBasePath(basePath: string): string {\n if (!basePath) {\n return \"/\";\n }\n\n let normalized = basePath;\n\n // Remove relative path prefix\n if (normalized.startsWith(\".\")) {\n normalized = normalized.slice(1);\n }\n\n // Ensure it starts with a forward slash\n if (!normalized.startsWith(\"/\")) {\n normalized = `/${normalized}`;\n }\n\n // Ensure it ends with a forward slash\n if (!normalized.endsWith(\"/\")) {\n normalized = `${normalized}/`;\n }\n\n return normalized;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../connect/env-config.ts","../../connect/schema-fragments.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Coerces string values to boolean.\n * Accepts: \"true\", \"false\", true, false\n */\nconst booleanString = z\n .union([z.boolean(), z.enum([\"true\", \"false\"])])\n .transform((val) => {\n if (typeof val === \"boolean\") return val;\n return val === \"true\";\n });\n\n// ============================================================================\n// Build-time Environment Variables\n// ============================================================================\n\n/**\n * Build-time configuration schema\n */\nconst buildEnvSchema = z.object({\n /**\n * Comma-separated list of package names to load\n * @example \"package1,package2\"\n */\n PH_PACKAGES: z.string().optional(),\n\n /**\n * Path to local package to load during development\n */\n PH_LOCAL_PACKAGE: z.string().optional(),\n\n /**\n * Sentry authentication token for uploading source maps\n */\n PH_SENTRY_AUTH_TOKEN: z.string().optional(),\n\n /**\n * Sentry organization slug\n */\n PH_SENTRY_ORG: z.string().optional(),\n\n /**\n * Sentry project slug\n */\n PH_SENTRY_PROJECT: z.string().optional(),\n});\n\n// ============================================================================\n// Application Configuration (build metadata only)\n// ============================================================================\n\n/**\n * Connect runtime values (anything in `PHConnectRuntimeConfig`) are NOT\n * settable from env vars. They live in `powerhouse.config.json` and are\n * overridden via `ph connect build --<field>` or `ph connect config\n * --<field>`.\n *\n * What stays env-driven below is non-runtime: build metadata, Sentry\n * credentials, analytics processor toggles, etc.\n */\nconst appConfigSchema = z.object({\n /**\n * Application version number (build metadata stamp)\n * @default \"unknown\"\n */\n PH_CONNECT_VERSION: z.string().default(\"unknown\"),\n\n /**\n * CLI version number (build metadata stamp)\n */\n PH_CONNECT_CLI_VERSION: z.string().optional(),\n});\n\n// ============================================================================\n// Analytics Processor Configuration\n// ============================================================================\n\n/**\n * Analytics processor configuration schema. These are non-runtime feature\n * toggles for the analytics subsystem — they don't live in the runtime\n * schema and stay env-driven.\n */\nconst processorsConfigSchema = z.object({\n /**\n * Enable diff analytics tracking\n * @default false\n */\n PH_CONNECT_DIFF_ANALYTICS_ENABLED: booleanString.default(false),\n\n /**\n * Enable drive analytics tracking\n * @default true\n */\n PH_CONNECT_DRIVE_ANALYTICS_ENABLED: booleanString.default(true),\n\n /**\n * Enable external analytics processors\n * @default true\n */\n PH_CONNECT_EXTERNAL_ANALYTICS_PROCESSORS_ENABLED: booleanString.default(true),\n});\n\n// ============================================================================\n// OpenPanel Configuration\n// ============================================================================\n\n/**\n * OpenPanel analytics configuration schema\n */\nconst openPanelConfigSchema = z.object({\n /**\n * OpenPanel client ID. When unset, the OpenPanel subsystem is a no-op.\n */\n PH_CONNECT_OPENPANEL_CLIENT_ID: z.string().optional(),\n\n /**\n * OpenPanel API URL override. Defaults to the OpenPanel cloud when unset.\n */\n PH_CONNECT_OPENPANEL_API_URL: z.string().optional(),\n\n /**\n * Track UI events via the useOpenPanel() hook\n * @default true\n */\n PH_CONNECT_OPENPANEL_TRACK_UI_EVENTS: booleanString.default(true),\n\n /**\n * Track document operations via the OpenPanel processor\n * @default true\n */\n PH_CONNECT_OPENPANEL_TRACK_OPERATIONS: booleanString.default(true),\n});\n\n// ============================================================================\n// Combined Schemas\n// ============================================================================\n\n/**\n * Complete runtime environment schema (all PH_CONNECT_* vars). Only\n * build-metadata + analytics-processor toggles live here; all Connect\n * runtime config lives in `powerhouse.config.json`.\n */\nexport const runtimeEnvSchema = appConfigSchema\n .extend(processorsConfigSchema.shape)\n .extend(openPanelConfigSchema.shape);\n\n/**\n * Complete environment schema (build + runtime)\n */\nexport const connectEnvSchema = buildEnvSchema.extend(runtimeEnvSchema.shape);\n\n/**\n * Inferred TypeScript types from schemas\n */\nexport type ConnectBuildEnv = z.infer<typeof buildEnvSchema>;\nexport type ConnectRuntimeEnv = z.infer<typeof runtimeEnvSchema>;\nexport type ConnectEnv = z.infer<typeof connectEnvSchema>;\n\n// ============================================================================\n// Environment Loading Functions\n// ============================================================================\n\n/**\n * Options for loading environment variables\n */\nexport interface LoadEnvOptions {\n /**\n * Environment variables from process.env (highest priority)\n */\n processEnv?: Record<string, string | undefined>;\n /**\n * Environment variables from .env file (lowest priority)\n */\n fileEnv?: Record<string, string | undefined>;\n}\n\n/**\n * Internal helper to merge environment sources with priority.\n * Validates each value and falls back to next priority if invalid.\n */\nfunction mergeEnvSources(\n options: LoadEnvOptions,\n keys: Set<string>,\n schema: z.ZodObject<Record<string, z.ZodTypeAny>>,\n): Record<string, unknown> {\n const { processEnv = {}, fileEnv = {} } = options;\n const merged: Record<string, unknown> = {};\n\n // Apply priority: fileEnv < processEnv\n for (const key of keys) {\n const sources = [\n { name: \"process.env\", value: processEnv[key] },\n { name: \"fileEnv\", value: fileEnv[key] },\n ];\n\n // Try each source in priority order\n for (const source of sources) {\n const value = source.value;\n if (value === undefined || value === \"\") continue;\n\n // Try to validate just this field\n try {\n const fieldSchema = schema.shape[key];\n if (fieldSchema) {\n fieldSchema.parse(value);\n merged[key] = value;\n break; // Successfully validated, use this value\n }\n // No schema for this key, accept it\n console.warn(`Unknown environment variable: '${key}'`);\n merged[key] = value;\n break;\n } catch {\n // Validation failed, log warning and try next source\n const valueStr =\n value === null\n ? \"null\"\n : typeof value === \"object\"\n ? JSON.stringify(value)\n : (value as string);\n console.warn(\n `Invalid value for ${key} from ${source.name}: ${valueStr}. Trying next source.`,\n );\n }\n }\n }\n\n return merged;\n}\n\n/**\n * Loads and validates environment variables with priority:\n * 1. process.env (highest)\n * 2. fileEnv\n * 3. defaults from schema (lowest)\n *\n * @param options - Environment sources in priority order\n * @returns Validated and typed environment configuration\n */\nexport function loadConnectEnv(options: LoadEnvOptions = {}): ConnectEnv {\n const allKeys = new Set([\n ...Object.keys(buildEnvSchema.shape),\n ...Object.keys(runtimeEnvSchema.shape),\n ]);\n\n const merged = mergeEnvSources(options, allKeys, connectEnvSchema);\n return connectEnvSchema.parse(merged);\n}\n\n/**\n * Loads only runtime environment variables (build metadata + Sentry +\n * analytics-processor toggles — everything in the Connect runtime schema\n * is sourced from powerhouse.config.json, not env).\n *\n * @param options - Environment sources in priority order\n * @returns Validated runtime environment configuration\n */\nexport function loadRuntimeEnv(\n options: LoadEnvOptions = {},\n): ConnectRuntimeEnv {\n const allKeys = new Set(Object.keys(runtimeEnvSchema.shape));\n const merged = mergeEnvSources(options, allKeys, runtimeEnvSchema);\n return runtimeEnvSchema.parse(merged);\n}\n\n/**\n * Safely sets Connect environment variables with validation.\n * Invalid values will log a warning and be skipped.\n *\n * @param values - Type-safe object with key-value pairs to set\n *\n * @example\n * ```ts\n * setConnectEnv({\n * PH_CONNECT_VERSION: \"1.2.3\",\n * PH_CONNECT_SENTRY_DSN: \"https://…\",\n * });\n * ```\n */\nexport function setConnectEnv(values: Partial<ConnectEnv>): void {\n for (const [key, value] of Object.entries(values)) {\n // Check if key exists in schema\n const fieldSchema =\n connectEnvSchema.shape[key as keyof typeof connectEnvSchema.shape];\n\n if (!fieldSchema) {\n console.warn(\n `Unknown environment variable: ${key}. Variable not set. Valid keys: ${Object.keys(connectEnvSchema.shape).join(\", \")}`,\n );\n continue;\n }\n\n try {\n // Validate the value\n fieldSchema.parse(value);\n\n // Set the value (convert to string for process.env compatibility)\n process.env[key] = String(value);\n } catch (error) {\n console.warn(\n `Invalid value for ${key}: ${String(value)}. Validation failed.`,\n error,\n );\n }\n }\n}\n\n/**\n * Normalizes a base path to ensure it:\n * - Starts with a forward slash (/)\n * - Ends with a forward slash (/)\n * - Has no relative path prefix (.)\n *\n * @param basePath - The base path to normalize\n * @returns The normalized base path\n *\n * @example\n * normalizeBasePath('/app') // '/app/'\n * normalizeBasePath('./app/') // '/app/'\n * normalizeBasePath('app') // '/app/'\n * normalizeBasePath('/') // '/'\n * normalizeBasePath('') // '/'\n */\nexport function normalizeBasePath(basePath: string): string {\n if (!basePath) {\n return \"/\";\n }\n\n let normalized = basePath;\n\n // Remove relative path prefix\n if (normalized.startsWith(\".\")) {\n normalized = normalized.slice(1);\n }\n\n // Ensure it starts with a forward slash\n if (!normalized.startsWith(\"/\")) {\n normalized = `/${normalized}`;\n }\n\n // Ensure it ends with a forward slash\n if (!normalized.endsWith(\"/\")) {\n normalized = `${normalized}/`;\n }\n\n return normalized;\n}\n\n/**\n * Base storage namespace for a Connect instance served at the root of an\n * origin. Kept as a literal so root deployments resolve to a byte-identical\n * value with no migration.\n */\nexport const ROOT_STORAGE_NAMESPACE = \"reactor\";\n\n/**\n * Derives the origin-scoped storage namespace from a Connect base path.\n *\n * Connect instances served under different path prefixes of the same origin\n * (e.g. behind a reverse proxy) otherwise share all origin-scoped browser\n * storage (PGlite data dirs, IndexedDB). This produces a deterministic,\n * collision-free namespace per distinct prefix that is valid as an\n * IndexedDB database name.\n *\n * - root base path (\"/\" or unset) -> \"reactor\" (byte-identical to the legacy\n * key, so existing root deployments keep their data with zero migration)\n * - any non-root base path -> \"reactor--<slug>\", e.g.\n * \"/reactor-project/vetra-studio/\" -> \"reactor--reactor-project-vetra-studio\"\n *\n * @param basePath - The Connect base path (env.PH_CONNECT_BASE_PATH ||\n * import.meta.env.BASE_URL); normalized internally.\n * @returns The storage namespace.\n *\n * @example\n * getStorageNamespace('/') // 'reactor'\n * getStorageNamespace('/reactor-project/vetra-studio/') // 'reactor--reactor-project-vetra-studio'\n */\nexport function getStorageNamespace(basePath: string): string {\n const normalized = normalizeBasePath(basePath);\n if (normalized === \"/\") {\n return ROOT_STORAGE_NAMESPACE;\n }\n const slug = normalized\n .slice(1, -1)\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n // A non-root base path whose slug normalizes to nothing (e.g. \"/-/\") must\n // not collapse into the root namespace and share its storage.\n return `${ROOT_STORAGE_NAMESPACE}--${slug || \"default\"}`;\n}\n","// Single source of truth for JSON Schema shapes shared between the source\n// PowerhouseConfig schema (packages/shared/clis/source-config-schema.ts) and\n// the runtime RuntimePowerhouseConfig schema\n// (packages/builder-tools/connect-utils/runtime-config-schema.ts).\n//\n// When a shared shape changes, edit it here — both schemas pick it up.\n\nexport const powerhousePackageSchema = {\n type: \"object\",\n additionalProperties: false,\n required: [\"packageName\"],\n properties: {\n packageName: {\n type: \"string\",\n description: \"Fully qualified npm package name (e.g. @scope/name).\",\n },\n version: {\n type: \"string\",\n description: \"Exact version (registry providers) or omit to take latest.\",\n },\n provider: {\n type: \"string\",\n enum: [\"npm\", \"github\", \"local\", \"registry\"],\n description: \"Where Connect should resolve the package from at runtime.\",\n },\n url: {\n type: \"string\",\n description:\n \"Override URL for non-registry providers (e.g. github tarball).\",\n },\n },\n} as const;\n\n// Reusable shape for `connect.drives.sections.{remote,local}` — three\n// affirmative-named toggles per section. The legacy public+cloud sections\n// have been collapsed into a single `remote`.\nconst driveSectionSchema = {\n type: \"object\",\n additionalProperties: false,\n description:\n \"Visibility and add/delete affordances for a drive section in the sidebar.\",\n properties: {\n enabled: {\n type: \"boolean\",\n description: \"When false, the section is hidden in the sidebar.\",\n default: true,\n },\n allowAdd: {\n type: \"boolean\",\n description:\n \"When false, the section's 'add drive' affordance is hidden.\",\n default: true,\n },\n allowDelete: {\n type: \"boolean\",\n description:\n \"When false, drives in this section cannot be deleted from the UI.\",\n default: true,\n },\n },\n} as const;\n\nexport const phConnectRuntimeConfigSchema = {\n type: \"object\",\n additionalProperties: false,\n description:\n \"Connect-specific UI customisations. All fields optional; omit the section entirely for default behaviour.\",\n properties: {\n branding: {\n type: \"object\",\n additionalProperties: false,\n description: \"App identity and visual branding.\",\n properties: {\n appName: {\n type: \"string\",\n description:\n \"Browser tab title and any in-app brand text. Defaults to 'Powerhouse Connect'.\",\n },\n homeBackground: {\n type: [\"string\", \"null\"],\n description:\n \"Hero image on the empty home screen. URL or path to override; null or omitted uses the bundled default image.\",\n },\n },\n },\n app: {\n type: \"object\",\n additionalProperties: false,\n description: \"Top-level Connect application behaviour.\",\n properties: {\n logLevel: {\n type: \"string\",\n enum: [\"debug\", \"info\", \"warn\", \"error\"],\n description:\n \"Log level applied by Connect's logger at boot. Affects browser-side output only.\",\n default: \"info\",\n },\n basePath: {\n type: \"string\",\n description:\n \"Base path Connect is mounted under (e.g. '/connect' for subpath deploys). Normalised at runtime to start and end with '/'. Defaults to the build-time BASE_URL.\",\n default: \"/\",\n },\n },\n },\n packages: {\n type: \"object\",\n additionalProperties: false,\n description:\n \"Runtime behaviour for the Connect package manager (separate from top-level `packages[]`, which lists which packages to load).\",\n properties: {\n externalEnabled: {\n type: \"boolean\",\n description:\n \"When false, Connect refuses to load any package that wasn't bundled at build time. Affirmative replacement for the legacy PH_CONNECT_EXTERNAL_PACKAGES_DISABLED env var.\",\n default: true,\n },\n liveReload: {\n type: \"boolean\",\n description:\n \"When true, Connect subscribes to the static-mode `/__packages` SSE channel so live publishes flow into the running tab without a page reload. Only works under hosting that serves this channel (e.g. ph-clint static mode).\",\n default: false,\n },\n },\n },\n drives: {\n type: \"object\",\n additionalProperties: false,\n description: \"Default-drive and add-drive UI behaviour.\",\n properties: {\n allowAddDrive: {\n type: \"boolean\",\n description:\n \"When false, the SPA hides the 'add drive' affordance entirely (top-level). Per-section overrides live in `sections.{remote,local}.allowAdd`.\",\n default: true,\n },\n defaultDrives: {\n type: \"array\",\n description:\n \"Drives the SPA auto-connects to on first load. Each must specify a URL; name and icon are optional overrides.\",\n default: [],\n items: {\n type: \"object\",\n additionalProperties: false,\n required: [\"url\"],\n properties: {\n url: { type: \"string\" },\n name: { type: [\"string\", \"null\"] },\n icon: { type: [\"string\", \"null\"] },\n },\n },\n },\n preserveStrategy: {\n type: \"string\",\n enum: [\"preserve-all\", \"preserve-by-url-and-detach\"],\n description:\n \"Strategy applied when defaultDrives change between deploys. 'preserve-all' keeps user-added drives untouched; 'preserve-by-url-and-detach' detaches removed default drives. No schema default — opt-in only.\",\n },\n sections: {\n type: \"object\",\n additionalProperties: false,\n description:\n \"Per-section visibility and affordance toggles. `remote` covers what was historically split into 'public' + 'cloud'; `local` is browser-local drives.\",\n properties: {\n remote: driveSectionSchema,\n local: driveSectionSchema,\n },\n },\n },\n },\n renown: {\n type: \"object\",\n additionalProperties: false,\n description: \"Renown identity / authentication coordinates.\",\n properties: {\n url: {\n type: \"string\",\n description: \"Renown auth service URL.\",\n default: \"https://www.renown.id\",\n },\n networkId: {\n type: \"string\",\n description: \"CAIP-2 network namespace (e.g. 'eip155').\",\n default: \"eip155\",\n },\n chainId: {\n type: \"number\",\n description: \"CAIP-2 chain reference within the network namespace.\",\n default: 1,\n },\n },\n },\n sentry: {\n type: \"object\",\n additionalProperties: false,\n description:\n \"Sentry error-tracking coordinates. Set `dsn` to enable Sentry; leave `dsn` null to disable. The Sentry release tag stays build-time (stamped via Vite's `define` from WORKSPACE_VERSION) so it always matches the sourcemaps uploaded by CI.\",\n properties: {\n dsn: {\n type: [\"string\", \"null\"],\n description:\n \"Sentry DSN URL. `null` disables Sentry entirely; the SPA never loads the Sentry SDK chunk.\",\n default: null,\n },\n env: {\n type: \"string\",\n description:\n \"Sentry environment label, surfaced as the `environment` tag on every event.\",\n default: \"dev\",\n },\n tracing: {\n type: \"boolean\",\n description: \"Enable Sentry performance tracing.\",\n default: false,\n },\n },\n },\n },\n} as const;\n"],"mappings":"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AAM;KACN,aACE;KACF,SAAS;KACV;IACD,YAAY;KACV,MAAM;KACN,aACE;KACF,SAAS;KACV;IACF;GACF;EACD,QAAQ;GACN,MAAM;GACN,sBAAsB;GACtB,aAAa;GACb,YAAY;IACV,eAAe;KACb,MAAM;KACN,aACE;KACF,SAAS;KACV;IACD,eAAe;KACb,MAAM;KACN,aACE;KACF,SAAS,EAAE;KACX,OAAO;MACL,MAAM;MACN,sBAAsB;MACtB,UAAU,CAAC,MAAM;MACjB,YAAY;OACV,KAAK,EAAE,MAAM,UAAU;OACvB,MAAM,EAAE,MAAM,CAAC,UAAU,OAAO,EAAE;OAClC,MAAM,EAAE,MAAM,CAAC,UAAU,OAAO,EAAE;OACnC;MACF;KACF;IACD,kBAAkB;KAChB,MAAM;KACN,MAAM,CAAC,gBAAgB,6BAA6B;KACpD,aACE;KACH;IACD,UAAU;KACR,MAAM;KACN,sBAAsB;KACtB,aACE;KACF,YAAY;MACV,QAAQ;MACR,OAAO;MACR;KACF;IACF;GACF;EACD,QAAQ;GACN,MAAM;GACN,sBAAsB;GACtB,aAAa;GACb,YAAY;IACV,KAAK;KACH,MAAM;KACN,aAAa;KACb,SAAS;KACV;IACD,WAAW;KACT,MAAM;KACN,aAAa;KACb,SAAS;KACV;IACD,SAAS;KACP,MAAM;KACN,aAAa;KACb,SAAS;KACV;IACF;GACF;EACD,QAAQ;GACN,MAAM;GACN,sBAAsB;GACtB,aACE;GACF,YAAY;IACV,KAAK;KACH,MAAM,CAAC,UAAU,OAAO;KACxB,aACE;KACF,SAAS;KACV;IACD,KAAK;KACH,MAAM;KACN,aACE;KACF,SAAS;KACV;IACD,SAAS;KACP,MAAM;KACN,aAAa;KACb,SAAS;KACV;IACF;GACF;EACF;CACF"}
@@ -0,0 +1,24 @@
1
+ import { ConfigAdapter, ConfigShape } from "./config-loader.js";
2
+
3
+ //#region connect/json-adapter.d.ts
4
+ type JsonConfigAdapterOptions = {
5
+ /**
6
+ * URL or filesystem path to the JSON file.
7
+ *
8
+ * Defaults to "powerhouse.config.json" (relative). In the browser the
9
+ * relative URL resolves against the page's base URL; in Node it resolves
10
+ * against the process working directory. CLI callers should pass an
11
+ * absolute path discovered via project-root detection.
12
+ */
13
+ path?: string;
14
+ };
15
+ declare class JsonConfigAdapter implements ConfigAdapter {
16
+ readonly source: string;
17
+ private readonly path;
18
+ constructor(options?: JsonConfigAdapterOptions);
19
+ read(): Promise<unknown>;
20
+ write(next: ConfigShape): Promise<void>;
21
+ }
22
+ //#endregion
23
+ export { JsonConfigAdapter, JsonConfigAdapterOptions };
24
+ //# sourceMappingURL=json-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-adapter.d.ts","names":[],"sources":["../../connect/json-adapter.ts"],"mappings":";;;KAgBY,wBAAA;;;;AAAZ;;;;;EASE,IAAA;AAAA;AAAA,cAGW,iBAAA,YAA6B,aAAA;EAAA,SAC/B,MAAA;EAAA,iBACQ,IAAA;cAEL,OAAA,GAAS,wBAAA;EAKf,IAAA,CAAA,GAAQ,OAAA;EAeR,KAAA,CAAM,IAAA,EAAM,WAAA,GAAc,OAAA;AAAA"}
@@ -0,0 +1,28 @@
1
+ //#region connect/json-adapter.ts
2
+ var JsonConfigAdapter = class {
3
+ source;
4
+ path;
5
+ constructor(options = {}) {
6
+ this.path = options.path ?? "powerhouse.config.json";
7
+ this.source = `json:${this.path}`;
8
+ }
9
+ async read() {
10
+ if (typeof window !== "undefined") {
11
+ const res = await fetch(this.path);
12
+ if (!res.ok) throw new Error(`JsonConfigAdapter: failed to fetch ${this.path}: ${res.status} ${res.statusText}`);
13
+ return await res.json();
14
+ }
15
+ const { readFile } = await import("node:fs/promises");
16
+ const raw = await readFile(this.path, "utf-8");
17
+ return JSON.parse(raw);
18
+ }
19
+ async write(next) {
20
+ const fs = await import("node:fs/promises").catch(() => null);
21
+ if (!fs) throw new Error("JsonConfigAdapter: writes require the Node filesystem (node:fs/promises is unavailable in this environment).");
22
+ await fs.writeFile(this.path, `${JSON.stringify(next, null, 2)}\n`, "utf-8");
23
+ }
24
+ };
25
+ //#endregion
26
+ export { JsonConfigAdapter };
27
+
28
+ //# sourceMappingURL=json-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-adapter.js","names":[],"sources":["../../connect/json-adapter.ts"],"sourcesContent":["// Single JSON-file adapter that works in both browser and Node.\n//\n// - read(): in the browser uses `fetch` (resolves the path against the page's\n// base URL); in Node dynamically imports `node:fs/promises` and reads from\n// disk. The dynamic import keeps `node:fs` out of the browser bundle's\n// static import graph — bundlers see no top-level Node imports, so the\n// adapter can be re-exported safely from the shared barrel.\n//\n// - write(): always writes to the local filesystem. Only the Node CLI ever\n// calls write — the browser SPA cannot mutate a static file served from\n// the deployed origin. If `write()` is called in the browser the dynamic\n// import of `node:fs/promises` resolves to undefined and we throw with an\n// actionable message.\n\nimport type { ConfigAdapter, ConfigShape } from \"./config-loader.js\";\n\nexport type JsonConfigAdapterOptions = {\n /**\n * URL or filesystem path to the JSON file.\n *\n * Defaults to \"powerhouse.config.json\" (relative). In the browser the\n * relative URL resolves against the page's base URL; in Node it resolves\n * against the process working directory. CLI callers should pass an\n * absolute path discovered via project-root detection.\n */\n path?: string;\n};\n\nexport class JsonConfigAdapter implements ConfigAdapter {\n readonly source: string;\n private readonly path: string;\n\n constructor(options: JsonConfigAdapterOptions = {}) {\n this.path = options.path ?? \"powerhouse.config.json\";\n this.source = `json:${this.path}`;\n }\n\n async read(): Promise<unknown> {\n if (typeof window !== \"undefined\") {\n const res = await fetch(this.path);\n if (!res.ok) {\n throw new Error(\n `JsonConfigAdapter: failed to fetch ${this.path}: ${res.status} ${res.statusText}`,\n );\n }\n return (await res.json()) as unknown;\n }\n const { readFile } = await import(\"node:fs/promises\");\n const raw = await readFile(this.path, \"utf-8\");\n return JSON.parse(raw) as unknown;\n }\n\n async write(next: ConfigShape): Promise<void> {\n const fs = await import(\"node:fs/promises\").catch(() => null);\n if (!fs) {\n throw new Error(\n \"JsonConfigAdapter: writes require the Node filesystem (node:fs/promises is unavailable in this environment).\",\n );\n }\n await fs.writeFile(\n this.path,\n `${JSON.stringify(next, null, 2)}\\n`,\n \"utf-8\",\n );\n }\n}\n"],"mappings":";AA4BA,IAAa,oBAAb,MAAwD;CACtD;CACA;CAEA,YAAY,UAAoC,EAAE,EAAE;AAClD,OAAK,OAAO,QAAQ,QAAQ;AAC5B,OAAK,SAAS,QAAQ,KAAK;;CAG7B,MAAM,OAAyB;AAC7B,MAAI,OAAO,WAAW,aAAa;GACjC,MAAM,MAAM,MAAM,MAAM,KAAK,KAAK;AAClC,OAAI,CAAC,IAAI,GACP,OAAM,IAAI,MACR,sCAAsC,KAAK,KAAK,IAAI,IAAI,OAAO,GAAG,IAAI,aACvE;AAEH,UAAQ,MAAM,IAAI,MAAM;;EAE1B,MAAM,EAAE,aAAa,MAAM,OAAO;EAClC,MAAM,MAAM,MAAM,SAAS,KAAK,MAAM,QAAQ;AAC9C,SAAO,KAAK,MAAM,IAAI;;CAGxB,MAAM,MAAM,MAAkC;EAC5C,MAAM,KAAK,MAAM,OAAO,oBAAoB,YAAY,KAAK;AAC7D,MAAI,CAAC,GACH,OAAM,IAAI,MACR,+GACD;AAEH,QAAM,GAAG,UACP,KAAK,MACL,GAAG,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC,KACjC,QACD"}
@@ -5,4 +5,4 @@ declare const APPS_DEPENDENCIES: string[];
5
5
  declare const ALL_POWERHOUSE_DEPENDENCIES: string[];
6
6
  //#endregion
7
7
  export { PACKAGES_DEPENDENCIES as i, APPS_DEPENDENCIES as n, CLIS_DEPENDENCIES as r, ALL_POWERHOUSE_DEPENDENCIES as t };
8
- //# sourceMappingURL=constants-xNwF0jSl.d.ts.map
8
+ //# sourceMappingURL=constants-C_EQX4DY.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants-C_EQX4DY.d.ts","names":[],"sources":["../constants.ts"],"mappings":";cAAa,qBAAA;AAAA,cA6BA,iBAAA;AAAA,cACA,iBAAA;AAAA,cAKA,2BAAA"}
@@ -1,2 +1,2 @@
1
- import { i as PACKAGES_DEPENDENCIES, n as APPS_DEPENDENCIES, r as CLIS_DEPENDENCIES, t as ALL_POWERHOUSE_DEPENDENCIES } from "./constants-xNwF0jSl.js";
1
+ import { i as PACKAGES_DEPENDENCIES, n as APPS_DEPENDENCIES, r as CLIS_DEPENDENCIES, t as ALL_POWERHOUSE_DEPENDENCIES } from "./constants-C_EQX4DY.js";
2
2
  export { ALL_POWERHOUSE_DEPENDENCIES, APPS_DEPENDENCIES, CLIS_DEPENDENCIES, PACKAGES_DEPENDENCIES };