@fjall/util 20.0.0 → 21.1.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 (47) hide show
  1. package/dist/.build-source-hash +25 -14
  2. package/dist/.minified +1 -1
  3. package/dist/atomicTempNaming.d.ts +26 -0
  4. package/dist/atomicTempNaming.js +1 -0
  5. package/dist/aws/costAllocationTags.d.ts +18 -0
  6. package/dist/aws/costAllocationTags.js +1 -1
  7. package/dist/aws/index.d.ts +1 -1
  8. package/dist/aws/index.js +1 -1
  9. package/dist/config.d.ts +28 -14
  10. package/dist/config.js +2 -2
  11. package/dist/configPaths.d.ts +22 -0
  12. package/dist/configPaths.js +1 -0
  13. package/dist/fjallHome.d.ts +78 -0
  14. package/dist/fjallHome.js +1 -0
  15. package/dist/fsHelpers.d.ts +9 -0
  16. package/dist/fsHelpers.js +1 -1
  17. package/dist/index.d.ts +7 -1
  18. package/dist/index.js +1 -1
  19. package/dist/logRotation.d.ts +42 -0
  20. package/dist/logRotation.js +1 -0
  21. package/dist/migration/clickhouseFrameworkUsers.d.ts +80 -0
  22. package/dist/migration/clickhouseFrameworkUsers.js +1 -0
  23. package/dist/migration/clickhouseFrameworkUsers.test.d.ts +1 -0
  24. package/dist/migration/clickhouseFrameworkUsers.test.js +1 -0
  25. package/dist/migration/constants.d.ts +29 -7
  26. package/dist/migration/constants.js +1 -1
  27. package/dist/migration/controlPlaneActivity.d.ts +58 -0
  28. package/dist/migration/controlPlaneActivity.js +2 -0
  29. package/dist/migration/index.d.ts +5 -1
  30. package/dist/migration/index.js +1 -1
  31. package/dist/migration/schemaGateExit.d.ts +63 -0
  32. package/dist/migration/schemaGateExit.js +1 -0
  33. package/dist/migration/sleepAbortable.d.ts +10 -0
  34. package/dist/migration/sleepAbortable.js +1 -0
  35. package/dist/patterns/frameworkPatterns.d.ts +151 -0
  36. package/dist/patterns/frameworkPatterns.js +1 -0
  37. package/dist/patterns/index.d.ts +2 -1
  38. package/dist/patterns/index.js +1 -1
  39. package/dist/patterns/patternTypes.d.ts +29 -0
  40. package/dist/patterns/patternTypes.js +1 -1
  41. package/dist/scaffold/ensureGitignore.d.ts +18 -0
  42. package/dist/scaffold/ensureGitignore.js +9 -0
  43. package/dist/scaffold/gitignore.d.ts +47 -0
  44. package/dist/scaffold/gitignore.js +35 -0
  45. package/dist/securityHelpers.d.ts +1 -1
  46. package/dist/securityHelpers.js +1 -1
  47. package/package.json +9 -1
@@ -9,19 +9,20 @@
9
9
  "package.json",
10
10
  "tsconfig.json"
11
11
  ],
12
- "hash": "a0a493b8832688e4bc7a72eea503c17e90d177fbbdf80d407eaa571a83d6d6a3",
12
+ "hash": "3cd4016b6ba53a403e092a115897c084755ae5791ecbb7812d771635c0e9bd67",
13
13
  "files": {
14
14
  "src/async/concurrency.ts": "3c7ebe0222a720f9",
15
15
  "src/async/singleton.ts": "7bcc21b0fb920561",
16
16
  "src/async/sleep.ts": "df52b17675ec3ed2",
17
+ "src/atomicTempNaming.ts": "d08f34bdb062be6f",
17
18
  "src/aws/CloudFormationFailureAnalyser.ts": "4e68b353171edd31",
18
19
  "src/aws/cloudformationTypes.ts": "e43bab9c96a21856",
19
- "src/aws/costAllocationTags.ts": "102100b3df7d428e",
20
+ "src/aws/costAllocationTags.ts": "8b60ac5b62a68a9d",
20
21
  "src/aws/deployProgress.ts": "be09dedb4deb9a7a",
21
22
  "src/aws/driftSuspects.ts": "5400dc05ebd6c977",
22
23
  "src/aws/errors.ts": "5addfa6bb2d1456a",
23
24
  "src/aws/failureAnalysisCategories.ts": "85ab1632d8069273",
24
- "src/aws/index.ts": "d1b45a75d7fb8e28",
25
+ "src/aws/index.ts": "ba6c3c8c913e4789",
25
26
  "src/aws/infraTags.ts": "6b1e65bf7119f32c",
26
27
  "src/aws/ipamTags.ts": "ac19ecd6c36b3bc2",
27
28
  "src/aws/maskFailureAnalysis.ts": "ae11250412cd6fd8",
@@ -32,7 +33,8 @@
32
33
  "src/cdkToolchain.ts": "a6b996c60b87d644",
33
34
  "src/cfn/physicalNameProperties.ts": "35d3c6f28079c593",
34
35
  "src/clickhouse.ts": "655c74cdba292c29",
35
- "src/config.ts": "11c577414a91c542",
36
+ "src/config.ts": "2c4174dabed881ed",
37
+ "src/configPaths.ts": "afcc2e4ceb6652a0",
36
38
  "src/constructMap.ts": "b81fc8e90015467f",
37
39
  "src/deploy/approvalTokenOutput.ts": "4be7b52825d88a37",
38
40
  "src/devSubstrate/entrypoint.ts": "0526b88258174aa6",
@@ -66,10 +68,11 @@
66
68
  "src/errors/absence.ts": "390fea350ffbb4e5",
67
69
  "src/failure/deploymentFailure.ts": "5824db1d97d01838",
68
70
  "src/failure/extractErrorWindow.ts": "ca41f90946fa939c",
69
- "src/fsHelpers.ts": "0869d9739d523572",
71
+ "src/fjallHome.ts": "d7c48a6444e21699",
72
+ "src/fsHelpers.ts": "4dd3877b3953c6a9",
70
73
  "src/fsScan.ts": "feb187758481443f",
71
74
  "src/httpKeepAlive.ts": "c8fe4b118ef4c79f",
72
- "src/index.ts": "34a9bb9a33ef1680",
75
+ "src/index.ts": "7dd522de0cf1aca0",
73
76
  "src/infra/backupVault.ts": "661678a6dfb0b648",
74
77
  "src/infra/connectionsWire.ts": "e3afa3ba95a531d8",
75
78
  "src/infra/deployArtefacts.ts": "235ac21dd3ccf0b2",
@@ -79,17 +82,22 @@
79
82
  "src/infra/regions.ts": "26b80d7cea05454c",
80
83
  "src/infra/tokenScopes.ts": "88c6a1f0da3fa491",
81
84
  "src/insights/computePatternFingerprint.ts": "b5d3a4704f42cc1f",
85
+ "src/logRotation.ts": "4039ae64980f80b5",
82
86
  "src/logger.ts": "865ec4ec62a9a588",
83
87
  "src/manifest/index.ts": "bfa2930556c2f8ad",
84
88
  "src/manifest/io.ts": "915ab602ac92d126",
85
89
  "src/manifest/schemas.ts": "21dce8ba66b1230f",
86
90
  "src/mcpProtocol/index.ts": "55df3209915a5043",
91
+ "src/migration/clickhouseFrameworkUsers.ts": "4bd55a96d4fddff4",
87
92
  "src/migration/clickhouseSqlUsers.ts": "c916e148367715bb",
88
93
  "src/migration/compareSchemaVersion.ts": "1c9247e722ec5d5b",
89
- "src/migration/constants.ts": "fa7b53cc1e15a245",
90
- "src/migration/index.ts": "fc1f4a461d637766",
94
+ "src/migration/constants.ts": "6a1481ac5f62b5d7",
95
+ "src/migration/controlPlaneActivity.ts": "c7ba33958f9fcbcc",
96
+ "src/migration/index.ts": "1c4090534fbaf61c",
91
97
  "src/migration/pickLatestClickHouseMigration.ts": "a5b4a00ba63522cb",
92
98
  "src/migration/pickLatestPrismaMigration.ts": "cbddc2950f4d4c85",
99
+ "src/migration/schemaGateExit.ts": "53f26d02b798a475",
100
+ "src/migration/sleepAbortable.ts": "71c7e7cc59406e2a",
93
101
  "src/migration/verifyExpectedSchemaVersion.ts": "cd583329d771a047",
94
102
  "src/naming/accountNameCollision.ts": "2dc8b278ff039220",
95
103
  "src/naming/caseConversion.ts": "8b8984f2b58b8ab7",
@@ -98,8 +106,9 @@
98
106
  "src/naming/targetExportNames.ts": "bab26b7c0243fafa",
99
107
  "src/onboarding/index.ts": "7999117c5a7a18d1",
100
108
  "src/onboarding/versionCurrency.ts": "19695f38b09cfc46",
101
- "src/patterns/index.ts": "9f024b45c2e225b0",
102
- "src/patterns/patternTypes.ts": "6e0aff0443bcb770",
109
+ "src/patterns/frameworkPatterns.ts": "0f843cb043eb11fc",
110
+ "src/patterns/index.ts": "41142efdd3b2711b",
111
+ "src/patterns/patternTypes.ts": "a50d9004645abc0c",
103
112
  "src/patterns/staticSiteForms.ts": "86ffcf142d9a8eac",
104
113
  "src/repo/appPath.ts": "9aa0d01262b88e65",
105
114
  "src/repo/findInfrastructurePaths.ts": "dd1245f5d4004dd5",
@@ -110,13 +119,15 @@
110
119
  "src/repo/scanLocalRepository.ts": "c7bc76201622a7a5",
111
120
  "src/repo/scanTypes.ts": "1fda805a7d8de93b",
112
121
  "src/resourceCategorisation.ts": "a140d1b3cb38be33",
122
+ "src/scaffold/ensureGitignore.ts": "230253a19bbf092c",
123
+ "src/scaffold/gitignore.ts": "87c66797a4bd05f2",
113
124
  "src/secrets.ts": "50258d463e4e67c3",
114
- "src/securityHelpers.ts": "2632215f57e1528c",
125
+ "src/securityHelpers.ts": "81ba6146cf6fcefb",
115
126
  "src/targets.ts": "126280f0a5762e21",
116
127
  "../scripts/minify-dist.mjs": "6b2e4b0df8aec601",
117
- "package.json": "e6b55e0cbbcafa56",
128
+ "package.json": "da75ad74e9acae9c",
118
129
  "tsconfig.json": "db759831ad95f396"
119
130
  },
120
- "outputHash": "5d297fd2a4b1eb5849301e75fd57cf8b1f47a2c32b3b828c446b4be862ca27fe",
121
- "outputFileCount": 211
131
+ "outputHash": "6286cd5069962e57b14e7a8b535b6862c7e8d9618cc4d0395239e2fb5013ef8d",
132
+ "outputFileCount": 235
122
133
  }
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 105 files minified at 2026-08-24T18:04:48.133Z
1
+ 117 files minified at 2026-08-28T12:40:07.188Z
@@ -0,0 +1,26 @@
1
+ /**
2
+ * How atomic-write temp files are named.
3
+ *
4
+ * Deliberately its own module with no imports: two very different consumers
5
+ * need it, and neither should have to drag the other's dependencies in.
6
+ * `fsHelpers` builds real temp paths from it; `scaffold/gitignore` derives
7
+ * the ignore globs that cover those paths after a hard kill. Putting the
8
+ * policy in `fsHelpers` makes every consumer of the ignore constants depend
9
+ * transitively on an I/O module — which breaks any test that mocks
10
+ * `fsHelpers` wholesale, for no reason connected to what it was testing.
11
+ *
12
+ * They must agree. A temp name the ignore rule does not match is a file
13
+ * that lands in a customer's `git status` and, with `git add -A`, in their
14
+ * history.
15
+ */
16
+ /** The suffix every atomic-write temp file ends with. */
17
+ export declare const ATOMIC_TMP_SUFFIX = ".tmp";
18
+ /**
19
+ * The glob covering a file's atomic-write temp files, in `.gitignore`
20
+ * spelling.
21
+ *
22
+ * The `*` is not decoration: temp names carry a random infix so concurrent
23
+ * writers cannot collide on one, which means a literal `<name>.tmp` entry
24
+ * matches nothing the writers actually produce.
25
+ */
26
+ export declare function atomicTmpGlob(fileGlob: string): string;
@@ -0,0 +1 @@
1
+ var p=Object.defineProperty;var o=(t,n)=>p(t,"name",{value:n,configurable:!0});const r=".tmp";function e(t){return`${t}.*${r}`}o(e,"atomicTmpGlob");export{r as ATOMIC_TMP_SUFFIX,e as atomicTmpGlob};
@@ -32,3 +32,21 @@ export declare const COST_ALLOCATION_TAGS: {
32
32
  * management (root) account and stage-less governance resources.
33
33
  */
34
34
  export declare const DEFAULT_COST_ALLOCATION_ENVIRONMENT: "management";
35
+ /** SDK tag shape (`{ Key, Value }`) accepted by `CreateRepositoryCommand`. */
36
+ export interface EcrCreateTag {
37
+ readonly Key: string;
38
+ readonly Value: string;
39
+ }
40
+ /**
41
+ * Cost-allocation tag set for SDK-created ECR repositories (the buildx
42
+ * registry-cache repos and the schema-gate mirror repo — everything ECR the
43
+ * CDK constructs do NOT synthesise). The service value is the repository name:
44
+ * it is the one identity every creation path shares byte-identically, which
45
+ * matters for the cache repos — the `fjall build` provisioner
46
+ * (`@fjall/cli` EcrRepositoryService) and the deploy-path provisioner
47
+ * (`@fjall/deploy-core` ensureBuildCacheRepository) both create the SAME
48
+ * physical repo, so their tag sets must not drift. No environment tag: these
49
+ * repos are account-scoped and shared across every stage in the account.
50
+ * Tags apply on create only — already-existing repos are never retro-tagged.
51
+ */
52
+ export declare function ecrCreateRepositoryTags(repositoryName: string): EcrCreateTag[];
@@ -1 +1 @@
1
- const o={ENVIRONMENT:"fjall:costAllocation:environment",SERVICE:"fjall:costAllocation:service",DOMAIN:"fjall:costAllocation:domain",OWNER:"fjall:costAllocation:owner"},l="management";export{o as COST_ALLOCATION_TAGS,l as DEFAULT_COST_ALLOCATION_ENVIRONMENT};
1
+ var l=Object.defineProperty;var t=(o,e)=>l(o,"name",{value:e,configurable:!0});const n={ENVIRONMENT:"fjall:costAllocation:environment",SERVICE:"fjall:costAllocation:service",DOMAIN:"fjall:costAllocation:domain",OWNER:"fjall:costAllocation:owner"},c="management";function r(o){return[{Key:n.SERVICE,Value:o}]}t(r,"ecrCreateRepositoryTags");export{n as COST_ALLOCATION_TAGS,c as DEFAULT_COST_ALLOCATION_ENVIRONMENT,r as ecrCreateRepositoryTags};
@@ -7,5 +7,5 @@ export { maskFailureAnalysis } from "./maskFailureAnalysis.js";
7
7
  export { classifyDriftSuspectEvents, findCurrentOperationStart, isDriftSuspectReason, isOperationOpeningEvent, type DriftSuspectEvent } from "./driftSuspects.js";
8
8
  export { IPAM_OPERATIONS_POOL_TAG_KEY, formatIpamPairTagValue } from "./ipamTags.js";
9
9
  export { SDK_PRE_EMPTY_TAG_KEY } from "./infraTags.js";
10
- export { COST_ALLOCATION_TAGS, DEFAULT_COST_ALLOCATION_ENVIRONMENT } from "./costAllocationTags.js";
10
+ export { COST_ALLOCATION_TAGS, DEFAULT_COST_ALLOCATION_ENVIRONMENT, ecrCreateRepositoryTags, type EcrCreateTag } from "./costAllocationTags.js";
11
11
  export { ACCOUNT_MONITORING_ROLE_NAME } from "./monitoringRole.js";
package/dist/aws/index.js CHANGED
@@ -1 +1 @@
1
- import{AWSError as e,NoRolesFoundError as t,InvalidCredentialsError as E,SSOTokenExpiredError as i,MissingRegionError as s,ProfileNotFoundError as n,CommandError as A,isAWSError as O,isNoRolesFoundError as _,isSSOUnauthorizedError as a}from"./errors.js";import{STACK_NOT_FOUND_PATTERN as S,CDK_NO_STACKS_MATCH as p,isResourceEvent as f}from"./cloudformationTypes.js";import{countResourceProgress as N,formatElapsed as C}from"./deployProgress.js";import{CloudFormationFailureAnalyser as R}from"./CloudFormationFailureAnalyser.js";import{FAILURE_ANALYSIS_CATEGORIES as x}from"./failureAnalysisCategories.js";import{maskFailureAnalysis as d}from"./maskFailureAnalysis.js";import{classifyDriftSuspectEvents as L,findCurrentOperationStart as P,isDriftSuspectReason as M,isOperationOpeningEvent as c}from"./driftSuspects.js";import{IPAM_OPERATIONS_POOL_TAG_KEY as K,formatIpamPairTagValue as g}from"./ipamTags.js";import{SDK_PRE_EMPTY_TAG_KEY as U}from"./infraTags.js";import{COST_ALLOCATION_TAGS as Y,DEFAULT_COST_ALLOCATION_ENVIRONMENT as y}from"./costAllocationTags.js";import{ACCOUNT_MONITORING_ROLE_NAME as V}from"./monitoringRole.js";export{V as ACCOUNT_MONITORING_ROLE_NAME,e as AWSError,p as CDK_NO_STACKS_MATCH,Y as COST_ALLOCATION_TAGS,R as CloudFormationFailureAnalyser,A as CommandError,y as DEFAULT_COST_ALLOCATION_ENVIRONMENT,x as FAILURE_ANALYSIS_CATEGORIES,K as IPAM_OPERATIONS_POOL_TAG_KEY,E as InvalidCredentialsError,s as MissingRegionError,t as NoRolesFoundError,n as ProfileNotFoundError,U as SDK_PRE_EMPTY_TAG_KEY,i as SSOTokenExpiredError,S as STACK_NOT_FOUND_PATTERN,L as classifyDriftSuspectEvents,N as countResourceProgress,P as findCurrentOperationStart,C as formatElapsed,g as formatIpamPairTagValue,O as isAWSError,M as isDriftSuspectReason,_ as isNoRolesFoundError,c as isOperationOpeningEvent,f as isResourceEvent,a as isSSOUnauthorizedError,d as maskFailureAnalysis};
1
+ import{AWSError as e,NoRolesFoundError as t,InvalidCredentialsError as E,SSOTokenExpiredError as s,MissingRegionError as i,ProfileNotFoundError as a,CommandError as n,isAWSError as A,isNoRolesFoundError as O,isSSOUnauthorizedError as _}from"./errors.js";import{STACK_NOT_FOUND_PATTERN as p,CDK_NO_STACKS_MATCH as S,isResourceEvent as f}from"./cloudformationTypes.js";import{countResourceProgress as N,formatElapsed as C}from"./deployProgress.js";import{CloudFormationFailureAnalyser as u}from"./CloudFormationFailureAnalyser.js";import{FAILURE_ANALYSIS_CATEGORIES as x}from"./failureAnalysisCategories.js";import{maskFailureAnalysis as d}from"./maskFailureAnalysis.js";import{classifyDriftSuspectEvents as L,findCurrentOperationStart as P,isDriftSuspectReason as c,isOperationOpeningEvent as M}from"./driftSuspects.js";import{IPAM_OPERATIONS_POOL_TAG_KEY as D,formatIpamPairTagValue as K}from"./ipamTags.js";import{SDK_PRE_EMPTY_TAG_KEY as U}from"./infraTags.js";import{COST_ALLOCATION_TAGS as y,DEFAULT_COST_ALLOCATION_ENVIRONMENT as Y,ecrCreateRepositoryTags as k}from"./costAllocationTags.js";import{ACCOUNT_MONITORING_ROLE_NAME as W}from"./monitoringRole.js";export{W as ACCOUNT_MONITORING_ROLE_NAME,e as AWSError,S as CDK_NO_STACKS_MATCH,y as COST_ALLOCATION_TAGS,u as CloudFormationFailureAnalyser,n as CommandError,Y as DEFAULT_COST_ALLOCATION_ENVIRONMENT,x as FAILURE_ANALYSIS_CATEGORIES,D as IPAM_OPERATIONS_POOL_TAG_KEY,E as InvalidCredentialsError,i as MissingRegionError,t as NoRolesFoundError,a as ProfileNotFoundError,U as SDK_PRE_EMPTY_TAG_KEY,s as SSOTokenExpiredError,p as STACK_NOT_FOUND_PATTERN,L as classifyDriftSuspectEvents,N as countResourceProgress,k as ecrCreateRepositoryTags,P as findCurrentOperationStart,C as formatElapsed,K as formatIpamPairTagValue,A as isAWSError,c as isDriftSuspectReason,O as isNoRolesFoundError,M as isOperationOpeningEvent,f as isResourceEvent,_ as isSSOUnauthorizedError,d as maskFailureAnalysis};
package/dist/config.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import { type Result } from "./docker/result.js";
3
3
  import { type AccountTier } from "./environments.js";
4
+ export { LOCAL_CONFIG_DIRNAME, LOCAL_CONFIG_FILENAME, ROOT_CONFIG_FILENAME } from "./configPaths.js";
4
5
  /**
5
6
  * The Fjall root config filename. Single source of truth — the repo-root marker
6
7
  * in findRepoRoot.ts MUST match this exactly or root detection diverges. Only
7
8
  * this exact name is discovered; sibling `.old` / `.backup` copies are inert.
8
9
  */
9
- export declare const ROOT_CONFIG_FILENAME = "fjall-config.json";
10
10
  /**
11
11
  * Backup Vault Lock modes for an account's DisasterRecovery vault.
12
12
  * See decisions/2026-06-03-backup-vault-lock-mode-by-intent.md.
@@ -196,17 +196,6 @@ export declare const RootConfigReadSchema: z.ZodObject<{
196
196
  }, z.core.$strict>>>>>;
197
197
  }, z.core.$strip>;
198
198
  export type RootConfigRead = z.infer<typeof RootConfigReadSchema>;
199
- /**
200
- * Local, NON-COMMITTED per-checkout state (`.fjall/local.json`, gitignored),
201
- * co-located with fjall-config.json. Holds the developer's active deployment
202
- * target: it lives here rather than in the committed fjall-config.json so a
203
- * committed value can never silently re-aim someone else's deploy or a CI
204
- * pipeline (the ci-deploy misdeploy fix). A legacy `activeTarget` in
205
- * fjall-config.json is read only to warn-and-migrate, never to resolve a
206
- * target.
207
- */
208
- export declare const LOCAL_CONFIG_DIRNAME = ".fjall";
209
- export declare const LOCAL_CONFIG_FILENAME = "local.json";
210
199
  /**
211
200
  * Canonical serialiser for the root fjall-config.json - the single source of
212
201
  * truth for the file's on-disk shape. Both `Config.saveConfig` and the webapp
@@ -330,13 +319,38 @@ export declare class Config {
330
319
  * and hot-path resolution never re-hits disk; writes flush through it.
331
320
  */
332
321
  private localConfigCache;
322
+ /**
323
+ * Directory of the project this instance is bound to, or null when it is
324
+ * bound to none. SINGLE SOURCE for every path derived from the project
325
+ * root.
326
+ *
327
+ * `fjall-config.json` and `.fjall/local.json` MUST resolve to the same
328
+ * root. They previously derived it independently and disagreed by one
329
+ * level — `saveConfig` defaulted to `<cwd>/fjall`, `localConfigFile` to
330
+ * `<cwd>` — so an unbound instance (first `fjall connect`, before the
331
+ * project marker exists) wrote them to different roots and the local
332
+ * write was invisible to every later read.
333
+ */
334
+ private resolveProjectDirectory;
335
+ /**
336
+ * Absolute path of `.fjall/local.json`, or null when this instance is not
337
+ * bound to a project. Never falls back to `process.cwd()`: per-checkout
338
+ * state anchored to the shell's working directory lands somewhere no
339
+ * later read looks.
340
+ */
333
341
  private localConfigFile;
334
342
  private loadLocalConfig;
343
+ /**
344
+ * Persist `.fjall/local.json`. Fails — rather than inventing a location —
345
+ * when the instance is not bound to a project: a write anchored to the
346
+ * shell's cwd is indistinguishable from success to the caller and
347
+ * invisible to every subsequent read.
348
+ */
335
349
  private writeLocalConfig;
336
350
  private static warnLegacyActiveTargetOnce;
337
351
  getActiveTarget(): string | undefined;
338
- setActiveTarget(name: string): void;
339
- clearActiveTarget(): void;
352
+ setActiveTarget(name: string): Result<void, Error>;
353
+ clearActiveTarget(): Result<void, Error>;
340
354
  getDomains(): DomainConfig[];
341
355
  setDomains(domains: DomainConfig[]): void;
342
356
  addDomain(domain: DomainConfig): void;
package/dist/config.js CHANGED
@@ -1,2 +1,2 @@
1
- var b=Object.defineProperty;var h=(u,e)=>b(u,"name",{value:e,configurable:!0});import*as a from"fs";import*as g from"path";import{z as l}from"zod";import{CapacityIdentityConfigSchema as j}from"./capacityIdentity.js";import{failure as p,success as T}from"./docker/result.js";import{getErrorMessage as S}from"./errorUtils.js";import{logger as E}from"./logger.js";import{maskSensitiveOutput as C}from"./securityHelpers.js";const x=10,w="fjall-config.json",W=["compliance","governance","none"],Y=["enforced","off"],Z=["centralised","off"],H=["account","draining","org"],q="managementEvents",z="organisationManagementEvents",V=["active","draining","removed"],X="FjallTrailBucketName",Q="FjallTrailKeyArn",ee="OrganisationTrailBucketName",k=l.object({name:l.string(),type:l.enum(["apex","delegated"]),parentDomain:l.string().optional(),account:l.string().optional(),region:l.string().optional()}).strict(),A=l.object({activeTarget:l.string().optional(),domains:l.array(k).optional(),capacityIdentity:j.optional()}).strict(),L=l.object({activeTarget:l.string().optional(),domains:l.array(k).optional(),capacityIdentity:j.optional()}),N=".fjall",_="local.json",$=l.object({activeTarget:l.string().optional()});function I(u={}){return JSON.stringify(u,null,2)}h(I,"serialiseRootConfig");const D=A.keyof().options;function R(u,e,n){const t=e[n];t!==void 0&&(u[n]=t)}h(R,"copyDefinedKey");function F(u,e){if(e===void 0)return!1;const n=new Set([...Object.keys(u),...Object.keys(e)]);for(const t of n)if(u[t]!==e[t])return!1;return!0}h(F,"domainEntriesEqual");class d{static{h(this,"Config")}rootConfig;configPath=null;loadFailed=!1;parseDegraded=!1;loadedSnapshot={};constructor(e,n){this.rootConfig=e??{},this.configPath=n??null}static findConfigDirectory(e){let n=e!==void 0&&e!==""?e:process.cwd();for(let t=0;t<x;t++){const o=g.join(n,"fjall"),r=g.join(o,w);if(a.existsSync(r))return o;const i=g.join(n,w);if(a.existsSync(i))return n;const c=g.dirname(n);if(c===n)break;n=c}return null}static loadConfigFile(e){try{return a.accessSync(e,a.constants.R_OK),a.readFileSync(e,{encoding:"utf8"})}catch(n){return E.warn("Config",`Config file at ${e} could not be read; using defaults`,{file:e,error:C(S(n))}),null}}static loadConfig(e){const n=d.findConfigDirectory(e);if(!n)return new d;const t=g.join(n,w),o=d.loadConfigFile(t);if(o===null){const f=new d(void 0,t);return f.loadFailed=!0,f}let r,i=!1;if(o!==""){let f;try{f=JSON.parse(o)}catch(s){throw d.formatZodError(s,w)}const y=A.safeParse(f);if(y.success)r=y.data;else{const s=L.safeParse(f);r=s.success?s.data:{},i=!s.success,s.success?E.warn("Config","fjall-config.json contains keys this version does not recognise (only activeTarget, domains and capacityIdentity are read). They were most likely written by a newer fjall version \u2014 leave them in place; saves preserve them verbatim.",{file:t}):E.warn("Config","fjall-config.json has a malformed activeTarget, domains or capacityIdentity value, so its contents were ignored for this run \u2014 any capacity-identity pins it holds will NOT apply (a pinned stack deploys unpinned and is blocked by the rename gate). Fix the file by hand; do NOT regenerate it, which would discard the pins.",{file:t})}}const c=new d(r,t);return c.parseDegraded=i,c.loadedSnapshot=structuredClone(c.rootConfig),c}static formatZodError(e,n){if(e instanceof l.ZodError&&e.issues.length>0){const r=e.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join("; ");return new Error(`Failed to parse ${n}: ${r}`)}const o=(e instanceof Error?e.message:String(e)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${n}: ${o}`)}saveConfig(){let e=this.configPath;if(!e){const c=d.findConfigDirectory()||g.join(process.cwd(),"fjall");e=g.join(c,w)}if(this.loadFailed)return p(new Error(`Refusing to save ${e}: the file exists but could not be read when this config loaded, so saving would replace its contents with state that never included them. Fix the file permissions (e.g. chmod u+rw ${e}) and retry.`));const n=g.dirname(e);try{a.mkdirSync(n,{recursive:!0})}catch(c){return p(new Error(`Cannot create config directory ${n}: ${C(S(c))}`))}const t=d.assertWritable(e,n);if(!t.success)return t;const o=this.mergeWithDisk(e);if(!o.success)return o;const r=I(o.data),i=`${e}.tmp-${process.pid}`;try{a.writeFileSync(i,r,{mode:384}),a.renameSync(i,e)}catch(c){return p(new Error(`Failed to save ${e}: ${C(S(c))}`))}return T(void 0)}static assertWritable(e,n){if(a.existsSync(e))try{a.accessSync(e,a.constants.W_OK)}catch{return p(new Error(`Cannot save ${e}: the file is read-only. Make it writable (e.g. chmod u+w ${e}) and retry.`))}try{a.accessSync(n,a.constants.W_OK)}catch{return p(new Error(`Cannot save ${e}: the directory ${n} is not writable. Make it writable (e.g. chmod u+w ${n}) and retry.`))}return T(void 0)}mergeWithDisk(e){const n=d.readDiskConfigForMerge(e);if(n.kind==="unmergeable")return p(new Error(`Refusing to save ${e}: ${n.reason}. Writing now would keep only this session's state and drop everything else the file carries (including keys written by other fjall versions). Fix or remove the file and retry.`));if(n.kind==="absent")return T(this.rootConfig);const t=n.disk,o={...t.foreign,...t.known};for(const i of D)i!=="domains"&&this.sessionChangedKey(i)&&(this.rootConfig[i]===void 0?delete o[i]:R(o,this.rootConfig,i));const r=this.mergeDomains(t.known.domains);return r!==void 0?o.domains=r:delete o.domains,T(o)}sessionChangedKey(e){return JSON.stringify(this.rootConfig[e])!==JSON.stringify(this.loadedSnapshot[e])}mergeDomains(e){const n=this.rootConfig.domains,t=this.loadedSnapshot.domains??[];if(n===void 0&&t.length===0)return e;const o=h(s=>s.toLowerCase(),"norm"),r=n??[],i=new Map(t.map(s=>[o(s.name),s])),c=new Map(r.map(s=>[o(s.name),s])),f=[],y=new Set;for(const s of e??[]){const m=o(s.name);y.add(m);const v=c.get(m),O=i.get(m);if(v!==void 0&&!F(v,O)){f.push(v);continue}v===void 0&&O!==void 0||f.push(s)}for(const s of r){const m=o(s.name);y.has(m)||F(s,i.get(m))||f.push(s)}return f}static readDiskConfigForMerge(e){if(!a.existsSync(e))return{kind:"absent"};let n;try{const r=a.readFileSync(e,{encoding:"utf8"});if(r==="")return{kind:"absent"};n=JSON.parse(r)}catch(r){return{kind:"unmergeable",reason:`the existing file could not be read or parsed as JSON (${C(S(r))})`}}const t=L.safeParse(n);if(!t.success){const r=t.error.issues.map(i=>`${i.path.join(".")}: ${i.message}`).join("; ");return{kind:"unmergeable",reason:`a recognised key in the existing file is malformed (${C(r)})`}}const o={};if(typeof n=="object"&&n!==null){const r=D;for(const[i,c]of Object.entries(n))r.includes(i)||(o[i]=c)}return{kind:"ok",disk:{known:t.data,foreign:o}}}static getConfigDirectory(e){return d.findConfigDirectory(e)}getConfigPath(){return this.configPath}isContentUnavailable(){return this.loadFailed||this.parseDegraded}static warnedLegacyActiveTarget=!1;localConfigCache;localConfigFile(){const e=this.configPath!==null?g.dirname(this.configPath):process.cwd();return g.join(e,N,_)}loadLocalConfig(){if(this.localConfigCache===void 0)try{const e=a.readFileSync(this.localConfigFile(),{encoding:"utf8"}),n=$.safeParse(JSON.parse(e));this.localConfigCache=n.success?n.data:{}}catch{this.localConfigCache={}}return this.localConfigCache}writeLocalConfig(e){const n=this.localConfigFile();a.mkdirSync(g.dirname(n),{recursive:!0}),a.writeFileSync(n,JSON.stringify(e,null,2)+`
2
- `,{encoding:"utf8"}),this.localConfigCache=e}static warnLegacyActiveTargetOnce(){d.warnedLegacyActiveTarget||(d.warnedLegacyActiveTarget=!0,E.warn("Config","`activeTarget` in fjall-config.json is deprecated and ignored: a committed target must never re-aim a deploy or CI pipeline. Run `fjall target set <name>` to store it locally in .fjall/local.json, then remove `activeTarget` from the committed fjall-config.json."))}getActiveTarget(){const e=this.loadLocalConfig().activeTarget;if(e!==void 0)return e;this.rootConfig.activeTarget!==void 0&&d.warnLegacyActiveTargetOnce()}setActiveTarget(e){const n=this.loadLocalConfig();n.activeTarget=e,this.writeLocalConfig(n)}clearActiveTarget(){const e=this.loadLocalConfig();delete e.activeTarget,this.writeLocalConfig(e)}getDomains(){return this.rootConfig.domains??[]}setDomains(e){this.rootConfig.domains=e}addDomain(e){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(e)}getDomain(e){return this.rootConfig.domains?.find(n=>n.name.toLowerCase()===e.toLowerCase())}removeDomain(e){if(!this.rootConfig.domains)return!1;const n=this.rootConfig.domains.findIndex(t=>t.name.toLowerCase()===e.toLowerCase());return n===-1?!1:(this.rootConfig.domains.splice(n,1),!0)}}export{q as ACCOUNT_TRAIL_NAME,V as ACCOUNT_TRAIL_STATES,d as Config,k as DomainConfigSchema,N as LOCAL_CONFIG_DIRNAME,_ as LOCAL_CONFIG_FILENAME,z as ORGANISATION_TRAIL_NAME,ee as ORG_TRAIL_BUCKET_OUTPUT_KEY,Z as ROOT_ACCESS_MANAGEMENT_MODES,w as ROOT_CONFIG_FILENAME,L as RootConfigReadSchema,A as RootConfigSchema,Y as S3_BPA_MODES,X as TRAIL_BUCKET_OUTPUT_KEY,Q as TRAIL_KEY_ARN_OUTPUT_KEY,H as TRAIL_LIFECYCLE_STATES,W as VAULT_LOCK_MODES,I as serialiseRootConfig};
1
+ var F=Object.defineProperty;var p=(u,e)=>F(u,"name",{value:e,configurable:!0});import*as a from"fs";import*as d from"path";import{z as l}from"zod";import{CapacityIdentityConfigSchema as A}from"./capacityIdentity.js";import{failure as m,success as w}from"./docker/result.js";import{getErrorMessage as E}from"./errorUtils.js";import{logger as O}from"./logger.js";import{maskSensitiveOutput as y}from"./securityHelpers.js";import{ensureGitignoreEntries as I}from"./scaffold/ensureGitignore.js";import{FJALL_MANAGED_STATE_DIR_ENTRIES as D,FJALL_PROJECT_GITIGNORE_HEADER as R,LOCAL_CONFIG_GITIGNORE_ENTRY as b,LOCAL_STATE_GITIGNORE_MARKER as $}from"./scaffold/gitignore.js";import{LOCAL_CONFIG_DIRNAME as x,LOCAL_CONFIG_FILENAME as M,ROOT_CONFIG_FILENAME as T}from"./configPaths.js";import{LOCAL_CONFIG_DIRNAME as de,LOCAL_CONFIG_FILENAME as ge,ROOT_CONFIG_FILENAME as ue}from"./configPaths.js";const G=10,Q=["compliance","governance","none"],ee=["enforced","off"],te=["centralised","off"],ne=["account","draining","org"],oe="managementEvents",re="organisationManagementEvents",ie=["active","draining","removed"],se="FjallTrailBucketName",ae="FjallTrailKeyArn",ce="OrganisationTrailBucketName",j=l.object({name:l.string(),type:l.enum(["apex","delegated"]),parentDomain:l.string().optional(),account:l.string().optional(),region:l.string().optional()}).strict(),L=l.object({activeTarget:l.string().optional(),domains:l.array(j).optional(),capacityIdentity:A.optional()}).strict(),_=l.object({activeTarget:l.string().optional(),domains:l.array(j).optional(),capacityIdentity:A.optional()}),P=l.object({activeTarget:l.string().optional()});function K(u={}){return JSON.stringify(u,null,2)}p(K,"serialiseRootConfig");const N=L.keyof().options;function J(u,e,t){const n=e[t];n!==void 0&&(u[t]=n)}p(J,"copyDefinedKey");function k(u,e){if(e===void 0)return!1;const t=new Set([...Object.keys(u),...Object.keys(e)]);for(const n of t)if(u[n]!==e[n])return!1;return!0}p(k,"domainEntriesEqual");class f{static{p(this,"Config")}rootConfig;configPath=null;loadFailed=!1;parseDegraded=!1;loadedSnapshot={};constructor(e,t){this.rootConfig=e??{},this.configPath=t??null}static findConfigDirectory(e){let t=e!==void 0&&e!==""?e:process.cwd();for(let n=0;n<G;n++){const o=d.join(t,"fjall"),i=d.join(o,T);if(a.existsSync(i))return o;const r=d.join(t,T);if(a.existsSync(r))return t;const c=d.dirname(t);if(c===t)break;t=c}return null}static loadConfigFile(e){try{return a.accessSync(e,a.constants.R_OK),a.readFileSync(e,{encoding:"utf8"})}catch(t){return O.warn("Config",`Config file at ${e} could not be read; using defaults`,{file:e,error:y(E(t))}),null}}static loadConfig(e){const t=f.findConfigDirectory(e);if(!t)return new f;const n=d.join(t,T),o=f.loadConfigFile(n);if(o===null){const g=new f(void 0,n);return g.loadFailed=!0,g}let i,r=!1;if(o!==""){let g;try{g=JSON.parse(o)}catch(s){throw f.formatZodError(s,T)}const C=L.safeParse(g);if(C.success)i=C.data;else{const s=_.safeParse(g);i=s.success?s.data:{},r=!s.success,s.success?O.warn("Config","fjall-config.json contains keys this version does not recognise (only activeTarget, domains and capacityIdentity are read). They were most likely written by a newer fjall version \u2014 leave them in place; saves preserve them verbatim.",{file:n}):O.warn("Config","fjall-config.json has a malformed activeTarget, domains or capacityIdentity value, so its contents were ignored for this run \u2014 any capacity-identity pins it holds will NOT apply (a pinned stack deploys unpinned and is blocked by the rename gate). Fix the file by hand; do NOT regenerate it, which would discard the pins.",{file:n})}}const c=new f(i,n);return c.parseDegraded=r,c.loadedSnapshot=structuredClone(c.rootConfig),c}static formatZodError(e,t){if(e instanceof l.ZodError&&e.issues.length>0){const i=e.issues.map(r=>`${r.path.join(".")}: ${r.message}`).join("; ");return new Error(`Failed to parse ${t}: ${i}`)}const o=(e instanceof Error?e.message:String(e)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${t}: ${o}`)}saveConfig(){const e=d.join(this.resolveProjectDirectory()??d.join(process.cwd(),"fjall"),T);if(this.loadFailed)return m(new Error(`Refusing to save ${e}: the file exists but could not be read when this config loaded, so saving would replace its contents with state that never included them. Fix the file permissions (e.g. chmod u+rw ${e}) and retry.`));const t=d.dirname(e);try{a.mkdirSync(t,{recursive:!0})}catch(c){return m(new Error(`Cannot create config directory ${t}: ${y(E(c))}`))}const n=f.assertWritable(e,t);if(!n.success)return n;const o=this.mergeWithDisk(e);if(!o.success)return o;const i=K(o.data),r=`${e}.tmp-${process.pid}`;try{a.writeFileSync(r,i,{mode:384}),a.renameSync(r,e)}catch(c){return m(new Error(`Failed to save ${e}: ${y(E(c))}`))}return this.configPath=e,w(void 0)}static assertWritable(e,t){if(a.existsSync(e))try{a.accessSync(e,a.constants.W_OK)}catch{return m(new Error(`Cannot save ${e}: the file is read-only. Make it writable (e.g. chmod u+w ${e}) and retry.`))}try{a.accessSync(t,a.constants.W_OK)}catch{return m(new Error(`Cannot save ${e}: the directory ${t} is not writable. Make it writable (e.g. chmod u+w ${t}) and retry.`))}return w(void 0)}mergeWithDisk(e){const t=f.readDiskConfigForMerge(e);if(t.kind==="unmergeable")return m(new Error(`Refusing to save ${e}: ${t.reason}. Writing now would keep only this session's state and drop everything else the file carries (including keys written by other fjall versions). Fix or remove the file and retry.`));if(t.kind==="absent")return w(this.rootConfig);const n=t.disk,o={...n.foreign,...n.known};for(const r of N)r!=="domains"&&this.sessionChangedKey(r)&&(this.rootConfig[r]===void 0?delete o[r]:J(o,this.rootConfig,r));const i=this.mergeDomains(n.known.domains);return i!==void 0?o.domains=i:delete o.domains,w(o)}sessionChangedKey(e){return JSON.stringify(this.rootConfig[e])!==JSON.stringify(this.loadedSnapshot[e])}mergeDomains(e){const t=this.rootConfig.domains,n=this.loadedSnapshot.domains??[];if(t===void 0&&n.length===0)return e;const o=p(s=>s.toLowerCase(),"norm"),i=t??[],r=new Map(n.map(s=>[o(s.name),s])),c=new Map(i.map(s=>[o(s.name),s])),g=[],C=new Set;for(const s of e??[]){const h=o(s.name);C.add(h);const v=c.get(h),S=r.get(h);if(v!==void 0&&!k(v,S)){g.push(v);continue}v===void 0&&S!==void 0||g.push(s)}for(const s of i){const h=o(s.name);C.has(h)||k(s,r.get(h))||g.push(s)}return g}static readDiskConfigForMerge(e){if(!a.existsSync(e))return{kind:"absent"};let t;try{const i=a.readFileSync(e,{encoding:"utf8"});if(i==="")return{kind:"absent"};t=JSON.parse(i)}catch(i){return{kind:"unmergeable",reason:`the existing file could not be read or parsed as JSON (${y(E(i))})`}}const n=_.safeParse(t);if(!n.success){const i=n.error.issues.map(r=>`${r.path.join(".")}: ${r.message}`).join("; ");return{kind:"unmergeable",reason:`a recognised key in the existing file is malformed (${y(i)})`}}const o={};if(typeof t=="object"&&t!==null){const i=N;for(const[r,c]of Object.entries(t))i.includes(r)||(o[r]=c)}return{kind:"ok",disk:{known:n.data,foreign:o}}}static getConfigDirectory(e){return f.findConfigDirectory(e)}getConfigPath(){return this.configPath}isContentUnavailable(){return this.loadFailed||this.parseDegraded}static warnedLegacyActiveTarget=!1;localConfigCache;resolveProjectDirectory(){return this.configPath!==null?d.dirname(this.configPath):f.findConfigDirectory()}localConfigFile(){const e=this.resolveProjectDirectory();return e===null?null:d.join(e,x,M)}loadLocalConfig(){if(this.localConfigCache===void 0){const e=this.localConfigFile();if(e===null)return this.localConfigCache={};try{const t=a.readFileSync(e,{encoding:"utf8"}),n=P.safeParse(JSON.parse(t));this.localConfigCache=n.success?n.data:{}}catch{this.localConfigCache={}}}return this.localConfigCache}writeLocalConfig(e){const t=this.localConfigFile();if(t===null)return m(new Error("Cannot persist local state: no fjall-config.json was found from this directory, so there is no project to anchor `.fjall/local.json` to. Run this from inside a fjall project, or run `fjall create account` / `fjall create app` first."));try{a.mkdirSync(d.dirname(t),{recursive:!0});const n=`${t}.tmp-${process.pid}`;a.writeFileSync(n,JSON.stringify(e,null,2)+`
2
+ `,{encoding:"utf8"}),a.renameSync(n,t),I(d.dirname(d.dirname(t)),[b,...D],{header:R,marker:$})}catch(n){return m(new Error(`Failed to write ${t}: ${y(E(n))}`))}return this.localConfigCache=e,w(void 0)}static warnLegacyActiveTargetOnce(){f.warnedLegacyActiveTarget||(f.warnedLegacyActiveTarget=!0,O.warn("Config","`activeTarget` in fjall-config.json is deprecated and ignored: a committed target must never re-aim a deploy or CI pipeline. Run `fjall target set <name>` to store it locally in .fjall/local.json, then remove `activeTarget` from the committed fjall-config.json."))}getActiveTarget(){const e=this.loadLocalConfig().activeTarget;if(e!==void 0)return e;this.rootConfig.activeTarget!==void 0&&f.warnLegacyActiveTargetOnce()}setActiveTarget(e){const t=this.loadLocalConfig();return t.activeTarget=e,this.writeLocalConfig(t)}clearActiveTarget(){const e=this.loadLocalConfig();return delete e.activeTarget,this.writeLocalConfig(e)}getDomains(){return this.rootConfig.domains??[]}setDomains(e){this.rootConfig.domains=e}addDomain(e){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(e)}getDomain(e){return this.rootConfig.domains?.find(t=>t.name.toLowerCase()===e.toLowerCase())}removeDomain(e){if(!this.rootConfig.domains)return!1;const t=this.rootConfig.domains.findIndex(n=>n.name.toLowerCase()===e.toLowerCase());return t===-1?!1:(this.rootConfig.domains.splice(t,1),!0)}}export{oe as ACCOUNT_TRAIL_NAME,ie as ACCOUNT_TRAIL_STATES,f as Config,j as DomainConfigSchema,de as LOCAL_CONFIG_DIRNAME,ge as LOCAL_CONFIG_FILENAME,re as ORGANISATION_TRAIL_NAME,ce as ORG_TRAIL_BUCKET_OUTPUT_KEY,te as ROOT_ACCESS_MANAGEMENT_MODES,ue as ROOT_CONFIG_FILENAME,_ as RootConfigReadSchema,L as RootConfigSchema,ee as S3_BPA_MODES,se as TRAIL_BUCKET_OUTPUT_KEY,ae as TRAIL_KEY_ARN_OUTPUT_KEY,ne as TRAIL_LIFECYCLE_STATES,Q as VAULT_LOCK_MODES,K as serialiseRootConfig};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Filesystem names for Fjall project state.
3
+ *
4
+ * A dependency-free leaf module on purpose: the scaffold's ignore policy
5
+ * derives its entries from these constants, and `config.ts` consumes that
6
+ * policy when it writes local state. Declaring them here breaks what would
7
+ * otherwise be an import cycle between the two — one that fails at module
8
+ * init with a TDZ `ReferenceError`, not at typecheck.
9
+ */
10
+ /** Committed project marker + anchor. Never gitignored: it carries `capacityIdentity`. */
11
+ export declare const ROOT_CONFIG_FILENAME = "fjall-config.json";
12
+ /**
13
+ * Local, NON-COMMITTED per-checkout state (`.fjall/local.json`, gitignored),
14
+ * co-located with fjall-config.json. Holds the developer's active deployment
15
+ * target: it lives here rather than in the committed fjall-config.json so a
16
+ * committed value can never silently re-aim someone else's deploy or a CI
17
+ * pipeline (the ci-deploy misdeploy fix). A legacy `activeTarget` in
18
+ * fjall-config.json is read only to warn-and-migrate, never to resolve a
19
+ * target.
20
+ */
21
+ export declare const LOCAL_CONFIG_DIRNAME = ".fjall";
22
+ export declare const LOCAL_CONFIG_FILENAME = "local.json";
@@ -0,0 +1 @@
1
+ const o="fjall-config.json",O=".fjall",l="local.json";export{O as LOCAL_CONFIG_DIRNAME,l as LOCAL_CONFIG_FILENAME,o as ROOT_CONFIG_FILENAME};
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The root of Fjall's per-user state — credentials, caches, journals, logs.
3
+ *
4
+ * A dependency-free leaf module, like its project-local sibling
5
+ * `configPaths.ts`. That one names state that lives beside a checkout; this
6
+ * one names state that lives beside the *operator*.
7
+ *
8
+ * ## Why this is a seam and not a constant
9
+ *
10
+ * `~/.fjall/auth.json` holds exactly one API key, so the CLI can be logged
11
+ * into exactly one organisation at a time. Anyone who works across two — a
12
+ * platform operator with a production org and a sandbox, an agency with a
13
+ * client per org, or us dogfooding a fresh signup against our own production
14
+ * account — has to overwrite the credential to switch, and overwrite it back
15
+ * to switch again. There is no verb for that and no warning when it happens:
16
+ * `login` simply replaces the file. Concurrent shells make it worse, because
17
+ * the second login silently re-aims the first shell's next command.
18
+ *
19
+ * `FJALL_CONFIG_DIR` makes the whole state root relocatable, so two
20
+ * organisations are two directories and a shell decides which one it is in:
21
+ *
22
+ * ```sh
23
+ * FJALL_CONFIG_DIR=~/.fjall-sandbox fjall login
24
+ * ```
25
+ *
26
+ * It is deliberately the *root*, not a per-file override. Credentials, the
27
+ * connection cache, the org-config cache, the app-id cache and the drift
28
+ * journals are all keyed to one organisation; letting them be redirected
29
+ * independently would allow a coherent-looking mix of two.
30
+ */
31
+ /** Env var relocating the whole state root. Absolute or relative to cwd. */
32
+ export declare const FJALL_CONFIG_DIR_ENV = "FJALL_CONFIG_DIR";
33
+ /** Directory name under `$HOME` when the env var is unset. */
34
+ export declare const FJALL_HOME_DIRNAME = ".fjall";
35
+ /**
36
+ * Absolute path to the state root.
37
+ *
38
+ * Resolved on every call rather than captured at module load: the env var is
39
+ * read by a command that may have been imported long before the process
40
+ * decided which organisation it is acting for, and a module-level `const`
41
+ * would freeze the answer at import time — which is exactly why the three
42
+ * caches that used to capture it could never have honoured an override.
43
+ *
44
+ * An empty value is treated as unset. Shells, CI runners and compose
45
+ * env-files all export `X=` freely, and a path is a *data* env var: the empty
46
+ * string is invalid input, not a request to write state into `/`.
47
+ */
48
+ export declare function fjallHomeDir(): string;
49
+ /** A path inside the state root — `fjallStatePath("auth.json")`. */
50
+ export declare function fjallStatePath(...segments: string[]): string;
51
+ /**
52
+ * The credential file.
53
+ *
54
+ * Named here rather than at each reader because there are two of them in
55
+ * different packages — the CLI writes it on `login`, the MCP server reads it
56
+ * to answer a tool call — and they used to agree about the path only by
57
+ * coincidence, each joining `homedir()` with the same two string literals.
58
+ * Nothing would have failed at typecheck if one of them had moved.
59
+ */
60
+ export declare const FJALL_CREDENTIALS_FILENAME = "auth.json";
61
+ export declare function fjallCredentialsPath(): string;
62
+ /**
63
+ * Env var relocating logs alone, without moving the rest of the state root.
64
+ *
65
+ * The narrower override, and it wins: logs are routinely redirected on their
66
+ * own — a CI artefact path, a tmpdir in tests — by someone who does not mean
67
+ * to move the credential alongside them.
68
+ */
69
+ export declare const FJALL_LOG_DIR_ENV = "FJALL_LOG_DIR";
70
+ /**
71
+ * The log directory.
72
+ *
73
+ * Two packages write here — the CLI's file logger and the infrastructure
74
+ * package's validation JSONL — and they each used to re-implement this exact
75
+ * precedence. Nothing linked them: a change to one would have split the log
76
+ * stream in half with nothing failing at typecheck.
77
+ */
78
+ export declare function fjallLogDir(): string;
@@ -0,0 +1 @@
1
+ var i=Object.defineProperty;var r=(o,f)=>i(o,"name",{value:f,configurable:!0});import{homedir as L}from"node:os";import{join as t,resolve as e}from"node:path";const u="FJALL_CONFIG_DIR",c=".fjall";function s(){const o=process.env[u];return o!==void 0&&o!==""?e(o):t(L(),c)}r(s,"fjallHomeDir");function n(...o){return t(s(),...o)}r(n,"fjallStatePath");const _="auth.json";function F(){return n(_)}r(F,"fjallCredentialsPath");const l="FJALL_LOG_DIR";function I(){const o=process.env[l];return o!==void 0&&o!==""?e(o):n("logs")}r(I,"fjallLogDir");export{u as FJALL_CONFIG_DIR_ENV,_ as FJALL_CREDENTIALS_FILENAME,c as FJALL_HOME_DIRNAME,l as FJALL_LOG_DIR_ENV,F as fjallCredentialsPath,s as fjallHomeDir,I as fjallLogDir,n as fjallStatePath};
@@ -17,3 +17,12 @@ export interface AtomicWriteOptions {
17
17
  * never a partial write.
18
18
  */
19
19
  export declare function atomicWrite(filePath: string, contents: string | Uint8Array, options?: AtomicWriteOptions): void;
20
+ /**
21
+ * `atomicWrite` for callers already on the async fs API.
22
+ *
23
+ * Exists so async writers do not hand-roll their own tmp+rename: before it,
24
+ * three writers of the per-checkout state file each invented a different
25
+ * temp-name shape, and both the `.gitignore` rule and the destroy-time
26
+ * cleanup sweep were written against only one of them.
27
+ */
28
+ export declare function atomicWriteAsync(filePath: string, contents: string | Uint8Array, options?: AtomicWriteOptions): Promise<void>;
package/dist/fsHelpers.js CHANGED
@@ -1 +1 @@
1
- var m=Object.defineProperty;var n=(t,r)=>m(t,"name",{value:r,configurable:!0});import{access as s,constants as f}from"fs/promises";import{renameSync as p,unlinkSync as u,writeFileSync as y}from"node:fs";import{randomBytes as h}from"node:crypto";async function x(t){try{return await s(t,f.F_OK),!0}catch(r){if(r instanceof Error&&"code"in r&&r.code==="ENOENT")return!1;throw r}}n(x,"fileExists");function S(t,r,e={}){const o=`${t}.${h(6).toString("hex")}.tmp`,c=e.mode??420;try{y(o,r,{mode:c}),p(o,t)}catch(a){try{u(o)}catch(i){e.onCleanupError?.(i)}throw a}}n(S,"atomicWrite");export{S as atomicWrite,x as fileExists};
1
+ var s=Object.defineProperty;var c=(r,t)=>s(r,"name",{value:t,configurable:!0});import{access as u,constants as p,rename as y,unlink as f,writeFile as h}from"fs/promises";import{renameSync as w,unlinkSync as l,writeFileSync as E}from"node:fs";import{randomBytes as d}from"node:crypto";import{ATOMIC_TMP_SUFFIX as x}from"./atomicTempNaming.js";async function _(r){try{return await u(r,p.F_OK),!0}catch(t){if(t instanceof Error&&"code"in t&&t.code==="ENOENT")return!1;throw t}}c(_,"fileExists");function m(r){return`${r}.${d(6).toString("hex")}${x}`}c(m,"atomicTmpPath");function $(r,t,o={}){const n=m(r),e=o.mode??420;try{E(n,t,{mode:e}),w(n,r)}catch(a){try{l(n)}catch(i){o.onCleanupError?.(i)}throw a}}c($,"atomicWrite");async function k(r,t,o={}){const n=m(r),e=o.mode??420;try{await h(n,t,{mode:e}),await y(n,r)}catch(a){try{await f(n)}catch(i){o.onCleanupError?.(i)}throw a}}c(k,"atomicWriteAsync");export{$ as atomicWrite,k as atomicWriteAsync,_ as fileExists};
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export { CAPACITY_SLOT_PATTERN, CAPACITY_SLOT_MAX_LENGTH, DEFAULT_CAPACITY_SLOT,
8
8
  export { findAccountNameCollision, type AccountNameCollision } from "./naming/accountNameCollision.js";
9
9
  export { defaultConnectedAccountName, suffixedAccountName, REGION_SHORT_CODES, findTrailingRegionShortCode, regionSuffixRejectionMessage } from "./naming/connectedAccountName.js";
10
10
  export { normaliseError, getErrorMessage, hasErrorCode, getErrorCode, getErrorStack, formatErrorString } from "./errorUtils.js";
11
+ export { FJALL_CONFIG_DIR_ENV, FJALL_CREDENTIALS_FILENAME, FJALL_HOME_DIRNAME, FJALL_LOG_DIR_ENV, fjallCredentialsPath, fjallHomeDir, fjallLogDir, fjallStatePath } from "./fjallHome.js";
11
12
  export { singleton } from "./async/singleton.js";
12
13
  export { DANGEROUS_ENV_VARS, filterDangerousEnvVars, MASKED_VALUE_MARKER, maskSensitiveOutput, parseShellArgs, REDACTED_KEY_SENTINEL, SCOPED_TOKEN_REGEX } from "./securityHelpers.js";
13
14
  export { sleep } from "./async/sleep.js";
@@ -29,11 +30,16 @@ export { RESERVED_APP_NAMES, type ReservedAppName, RESERVED_APP_NAME_MESSAGE, is
29
30
  export { deriveContentHashTag, CONTENT_HASH_TAG_PATTERN } from "./infra/deriveContentHashTag.js";
30
31
  export { DEPLOY_MODES, DeployModeSchema, type DeployMode, IMAGE_TAG_PATTERN, ImageTagSchema, type ImageTag, ServiceArtefactSchema, type ServiceArtefact, ServiceArtefactsSchema, type ServiceArtefacts, ARTEFACT_OUTPUT_FIELDS, type ArtefactOutputField, artefactOutputKey } from "./infra/deployArtefacts.js";
31
32
  export { MIGRATION_SNAPSHOT_NAME_PREFIX, EXPECTED_SCHEMA_VERSION_ENV, EXPECTED_SCHEMA_VERSION_TOOL_ENV, EXPECTED_CH_SCHEMA_VERSION_ENV, SCHEMA_ADMIN_USER_ENV, SCHEMA_ADMIN_PASSWORD_ENV, PRISMA_MIGRATION_DIR_RE, CLICKHOUSE_MIGRATION_SKIP_RE } from "./migration/constants.js";
33
+ export { SCHEMA_GATE_EXIT, SCHEMA_GATE_EXIT_HINTS, schemaGateExitKind, type SchemaGateExitKind, type SchemaGateExitCode } from "./migration/schemaGateExit.js";
34
+ export { FJALL_SCHEMA_GATE_USER, FJALL_MAINTENANCE_USER, FJALL_CLICKHOUSE_USERS, type FjallClickHouseUser } from "./migration/clickhouseFrameworkUsers.js";
32
35
  export { PHYSICAL_NAME_FALLBACK_PROPERTIES } from "./cfn/physicalNameProperties.js";
33
- export { PATTERN_TYPE_VALUES, type PatternType, PATTERN_TYPES, isPatternType, type PatternArtefact, type PatternStackPlacement, type PatternDescriptor, PATTERN_REGISTRY, patternConstructId, DEPLOYABLE_PATTERN_TYPES, type OpenNextPatternType, OPENNEXT_PATTERN_TYPES, isOpenNextPatternType, STATIC_SITE_ROUTING_VALUES, type StaticSiteRouting } from "./patterns/patternTypes.js";
36
+ export { PATTERN_TYPE_VALUES, type PatternType, PATTERN_TYPES, isPatternType, type PatternArtefact, type PatternStackPlacement, type PatternDescriptor, PATTERN_REGISTRY, patternConstructId, DEPLOYABLE_PATTERN_TYPES, type OpenNextPatternType, OPENNEXT_PATTERN_TYPES, isOpenNextPatternType, STATIC_SITE_ROUTING_VALUES, type StaticSiteRouting, PATTERN_CREATE_INPUT_VALUES, type PatternCreateInput, PATTERN_CREATE_INPUT_FLAGS } from "./patterns/patternTypes.js";
37
+ export { FRAMEWORK_VALUES, type Framework, FRAMEWORKS, isFramework, type DeployablePatternType, type UndeployablePatternType, type PatternRecommendation, FRAMEWORK_PATTERN_RECOMMENDATIONS, recommendPatternForFramework, CREATABLE_FRAMEWORKS, requiredInputsForFramework } from "./patterns/frameworkPatterns.js";
34
38
  export { DEFAULT_FORMS_FROM_LOCAL_PART, defaultFormsFromAddress, defaultFormsCorsOrigin, isAddressAtDomain } from "./patterns/staticSiteForms.js";
35
39
  export { DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION, DEV_SUBSTRATE_PARAMS_FILENAME, DevSubstrateSynthPropsSchema, type DevSubstrateSynthProps, DevSubstrateParamsSchema, type DevSubstrateParams } from "./devSubstrate/params.js";
36
40
  export { DEV_SUBSTRATE_ENTRYPOINT_SOURCE } from "./devSubstrate/entrypoint.js";
37
41
  export { BLESSED_CDK_TOOLCHAIN, type BlessedCdkToolchain } from "./cdkToolchain.js";
38
42
  export { DEPLOYMENT_FAILURE_PHASES, DeploymentFailurePhaseSchema, type DeploymentFailurePhase, DEPLOYMENT_FAULT_ATTRIBUTIONS, DeploymentFaultAttributionSchema, type DeploymentFaultAttribution, DEPLOYMENT_FAILURE_PROVIDER_SOURCES, DeploymentFailureProviderSourceSchema, type DeploymentFailureProviderSource, DEPLOYMENT_FAILURE_CODE_PATTERN, DEPLOYMENT_FAILURE_SCHEMA_VERSION, DEPLOYMENT_FAILURE_LIMITS, DeploymentFailureAnalysisSchema, type DeploymentFailureAnalysis, DeploymentFailureProviderSchema, type DeploymentFailureProvider, DeploymentFailureResourceSchema, type DeploymentFailureResource, DeploymentFailureSchema, type DeploymentFailure, parseDeploymentFailure, DEPLOYMENT_FAILURE_DOCS_BASE_URL, deploymentFailureDocsUrl, DEPLOYMENT_FAULT_COPY, DEPLOYMENT_PROVIDER_LABELS, deriveErrorMessageFromFailure, toDeploymentFailureAnalysis } from "./failure/deploymentFailure.js";
39
43
  export { extractErrorWindow, ERROR_WINDOW_CONTEXT_LINES, type ExtractErrorWindowOptions } from "./failure/extractErrorWindow.js";
44
+ export { FJALL_COMPONENT_GITIGNORE, FJALL_PROJECT_GITIGNORE, FJALL_STATE_GITIGNORE_ENTRIES, FJALL_MANAGED_STATE_DIR_ENTRIES, LOCAL_CONFIG_GITIGNORE_ENTRY } from "./scaffold/gitignore.js";
45
+ export { ensureGitignoreEntries } from "./scaffold/ensureGitignore.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{DNS_APEX as r,getDomainExportNames as _,getDomainStackName as t,getDomainUsEast1CertificatesStackName as o,hostsExportPartName as S,serialiseHostsChunks as T,HOSTS_OUTPUT_MAX_BYTES as A,isManagedDomainBinding as a,DOMAIN_DEPLOY_DEFAULT_PHASE as N}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as n}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as m,TOKEN_STDERR_PREFIX as O}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as C}from"./infra/imageTags.js";import{toPascalCase as I,toKebab as p,toValidDatabaseName as D,toScreamingSnake as L,capitalise as c,getSafeZoneName as M,accountConstructKey as f,hasAsciiStableConstructKey as U}from"./naming/caseConversion.js";import{albDnsExportName as u,albHostedZoneIdExportName as d,cdnDomainExportName as g,bucketWebsiteEndpointExportName as x,bucketWebsiteHostedZoneIdExportName as F}from"./naming/targetExportNames.js";import{CAPACITY_SLOT_PATTERN as V,CAPACITY_SLOT_MAX_LENGTH as Y,DEFAULT_CAPACITY_SLOT as y,CAPACITY_ANCHOR_PATTERN as G,CAPACITY_ANCHOR_MAX_LENGTH as H,CAPACITY_IDENTITY_CONTEXT_KEY as v,CapacityIdentityPinSchema as b,CapacityIdentityWireSchema as K,CapacityIdentityConfigSchema as X,projectCapacityIdentityToTarget as B}from"./capacityIdentity.js";import{findAccountNameCollision as k}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as j,suffixedAccountName as w,REGION_SHORT_CODES as z,findTrailingRegionShortCode as Q,regionSuffixRejectionMessage as q}from"./naming/connectedAccountName.js";import{normaliseError as $,getErrorMessage as ee,hasErrorCode as Ee,getErrorCode as re,getErrorStack as _e,formatErrorString as te}from"./errorUtils.js";import{singleton as Se}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as Ae,filterDangerousEnvVars as ae,MASKED_VALUE_MARKER as Ne,maskSensitiveOutput as Re,parseShellArgs as ne,REDACTED_KEY_SENTINEL as ie,SCOPED_TOKEN_REGEX as me}from"./securityHelpers.js";import{sleep as Pe}from"./async/sleep.js";import{mapSettledWithConcurrency as se}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as pe,STRUCTURAL_ENVIRONMENTS as De,ACCOUNT_STAGES as Le,ACCOUNT_STAGE_LABELS as ce,isAccountStage as Me,ACCOUNT_TIERS as fe,AccountTierSchema as Ue,isAccountTier as le,GOVERNANCE_ACCOUNT_TIERS as ue,isGovernanceTier as de,environmentToTier as ge,stageFromWireEnvironment as xe,accountTier as Fe,resolveSynthEnvironment as he,getEnvironmentLabel as Ve,ACCOUNT_ROLES as Ye}from"./environments.js";import{RESOURCE_CATEGORIES as Ge,categoriseResource as He,getExpectedDuration as ve,getFriendlyResourceType as be}from"./resourceCategorisation.js";import{parseGitRemoteUrl as Xe}from"./repo/gitRemoteParser.js";import{abbreviateRegion as We,AWS_REGIONS_METADATA as ke,DEFAULT_REGION as Ze,getRegionInfo as je,MAX_SECONDARY_REGIONS as we,OPT_IN_REGION_CODES as ze,optInRegionWarning as Qe,regions as qe,suggestRegionForTimezone as Je}from"./infra/regions.js";import{SCOPE_VALUES as eE,MACHINE_ONLY_SCOPES as EE,USER_GRANTABLE_SCOPES as rE,GOVERNANCE_SCOPE_REQUIRED_CODE as _E}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as oE,SECRET_NAME_ERROR as SE,SSM_COMPONENT_PATTERN as TE,SSM_COMPONENT_ERROR as AE,SSM_STANDARD_MAX_VALUE_BYTES as aE,SecretNamespaceSchema as NE,buildNamespaceParts as RE,buildParameterPath as nE,parseParameterPath as iE,isManageablePath as mE,parseDotEnv as OE,escapeDotEnvValue as PE}from"./secrets.js";import{ConnectionWireSchema as sE,ConnectionsListResponseSchema as IE,CONNECTION_PHASES as pE,CONNECTION_TERMINAL_FAILURE_PHASES as DE,CONNECTION_FAILURE_REASONS as LE,EXTERNAL_ID_PATTERN as cE}from"./infra/connectionsWire.js";import{PUBLIC_PACKAGE_NAME as fE,INSTALL_SOURCES as UE,SETUP_COMMANDS as lE,upgradeCommand as uE,SETUP_MODES as dE,SETUP_STEP_IDS as gE,SETUP_STEPS as xE,AGENT_SETUP_PROMPTS as FE,AGENT_INSTALL_COMMAND as hE,SKILL_INSTALL_SEGMENTS as VE,SKILL_INSTALL_FILENAME as YE,SKILL_INSTALL_PATH as yE}from"./onboarding/index.js";import{deriveRegionsFromOrgConfig as HE,deriveTargets as vE,deriveAllTargets as bE,environmentOrTier as KE,findTarget as XE,generateTargetName as BE}from"./targets.js";import{buildAppConfigPath as kE}from"./repo/appPath.js";import{findInfrastructurePaths as jE,findBoundaryPath as wE,isInfrastructureFile as zE}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as qE}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as $E,RESERVED_APP_NAME_MESSAGE as er,isReservedAppName as Er,RESERVED_APP_NAME_SUFFIX as rr,RESERVED_APP_NAME_SUFFIX_MESSAGE as _r,hasReservedAppNameSuffix as tr}from"./naming/reservedAppNames.js";import{deriveContentHashTag as Sr,CONTENT_HASH_TAG_PATTERN as Tr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as ar,DeployModeSchema as Nr,IMAGE_TAG_PATTERN as Rr,ImageTagSchema as nr,ServiceArtefactSchema as ir,ServiceArtefactsSchema as mr,ARTEFACT_OUTPUT_FIELDS as Or,artefactOutputKey as Pr}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as sr,EXPECTED_SCHEMA_VERSION_ENV as Ir,EXPECTED_SCHEMA_VERSION_TOOL_ENV as pr,EXPECTED_CH_SCHEMA_VERSION_ENV as Dr,SCHEMA_ADMIN_USER_ENV as Lr,SCHEMA_ADMIN_PASSWORD_ENV as cr,PRISMA_MIGRATION_DIR_RE as Mr,CLICKHOUSE_MIGRATION_SKIP_RE as fr}from"./migration/constants.js";import{PHYSICAL_NAME_FALLBACK_PROPERTIES as lr}from"./cfn/physicalNameProperties.js";import{PATTERN_TYPE_VALUES as dr,PATTERN_TYPES as gr,isPatternType as xr,PATTERN_REGISTRY as Fr,patternConstructId as hr,DEPLOYABLE_PATTERN_TYPES as Vr,OPENNEXT_PATTERN_TYPES as Yr,isOpenNextPatternType as yr,STATIC_SITE_ROUTING_VALUES as Gr}from"./patterns/patternTypes.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as vr,defaultFormsFromAddress as br,defaultFormsCorsOrigin as Kr,isAddressAtDomain as Xr}from"./patterns/staticSiteForms.js";import{DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION as Wr,DEV_SUBSTRATE_PARAMS_FILENAME as kr,DevSubstrateSynthPropsSchema as Zr,DevSubstrateParamsSchema as jr}from"./devSubstrate/params.js";import{DEV_SUBSTRATE_ENTRYPOINT_SOURCE as zr}from"./devSubstrate/entrypoint.js";import{BLESSED_CDK_TOOLCHAIN as qr}from"./cdkToolchain.js";import{DEPLOYMENT_FAILURE_PHASES as $r,DeploymentFailurePhaseSchema as e_,DEPLOYMENT_FAULT_ATTRIBUTIONS as E_,DeploymentFaultAttributionSchema as r_,DEPLOYMENT_FAILURE_PROVIDER_SOURCES as __,DeploymentFailureProviderSourceSchema as t_,DEPLOYMENT_FAILURE_CODE_PATTERN as o_,DEPLOYMENT_FAILURE_SCHEMA_VERSION as S_,DEPLOYMENT_FAILURE_LIMITS as T_,DeploymentFailureAnalysisSchema as A_,DeploymentFailureProviderSchema as a_,DeploymentFailureResourceSchema as N_,DeploymentFailureSchema as R_,parseDeploymentFailure as n_,DEPLOYMENT_FAILURE_DOCS_BASE_URL as i_,deploymentFailureDocsUrl as m_,DEPLOYMENT_FAULT_COPY as O_,DEPLOYMENT_PROVIDER_LABELS as P_,deriveErrorMessageFromFailure as C_,toDeploymentFailureAnalysis as s_}from"./failure/deploymentFailure.js";import{extractErrorWindow as p_,ERROR_WINDOW_CONTEXT_LINES as D_}from"./failure/extractErrorWindow.js";export{Ye as ACCOUNT_ROLES,Le as ACCOUNT_STAGES,pe as ACCOUNT_STAGES_WITH_ROOT,ce as ACCOUNT_STAGE_LABELS,fe as ACCOUNT_TIERS,hE as AGENT_INSTALL_COMMAND,FE as AGENT_SETUP_PROMPTS,m as APPROVAL_TOKEN_OUTPUT_PREFIX,Or as ARTEFACT_OUTPUT_FIELDS,ke as AWS_REGIONS_METADATA,Ue as AccountTierSchema,n as BACKUP_VAULT_NAME,qr as BLESSED_CDK_TOOLCHAIN,H as CAPACITY_ANCHOR_MAX_LENGTH,G as CAPACITY_ANCHOR_PATTERN,v as CAPACITY_IDENTITY_CONTEXT_KEY,Y as CAPACITY_SLOT_MAX_LENGTH,V as CAPACITY_SLOT_PATTERN,fr as CLICKHOUSE_MIGRATION_SKIP_RE,LE as CONNECTION_FAILURE_REASONS,pE as CONNECTION_PHASES,DE as CONNECTION_TERMINAL_FAILURE_PHASES,Tr as CONTENT_HASH_TAG_PATTERN,X as CapacityIdentityConfigSchema,b as CapacityIdentityPinSchema,K as CapacityIdentityWireSchema,sE as ConnectionWireSchema,IE as ConnectionsListResponseSchema,Ae as DANGEROUS_ENV_VARS,y as DEFAULT_CAPACITY_SLOT,vr as DEFAULT_FORMS_FROM_LOCAL_PART,Ze as DEFAULT_REGION,Vr as DEPLOYABLE_PATTERN_TYPES,o_ as DEPLOYMENT_FAILURE_CODE_PATTERN,i_ as DEPLOYMENT_FAILURE_DOCS_BASE_URL,T_ as DEPLOYMENT_FAILURE_LIMITS,$r as DEPLOYMENT_FAILURE_PHASES,__ as DEPLOYMENT_FAILURE_PROVIDER_SOURCES,S_ as DEPLOYMENT_FAILURE_SCHEMA_VERSION,E_ as DEPLOYMENT_FAULT_ATTRIBUTIONS,O_ as DEPLOYMENT_FAULT_COPY,P_ as DEPLOYMENT_PROVIDER_LABELS,ar as DEPLOY_MODES,zr as DEV_SUBSTRATE_ENTRYPOINT_SOURCE,kr as DEV_SUBSTRATE_PARAMS_FILENAME,Wr as DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION,r as DNS_APEX,N as DOMAIN_DEPLOY_DEFAULT_PHASE,Nr as DeployModeSchema,A_ as DeploymentFailureAnalysisSchema,e_ as DeploymentFailurePhaseSchema,a_ as DeploymentFailureProviderSchema,t_ as DeploymentFailureProviderSourceSchema,N_ as DeploymentFailureResourceSchema,R_ as DeploymentFailureSchema,r_ as DeploymentFaultAttributionSchema,jr as DevSubstrateParamsSchema,Zr as DevSubstrateSynthPropsSchema,D_ as ERROR_WINDOW_CONTEXT_LINES,Dr as EXPECTED_CH_SCHEMA_VERSION_ENV,Ir as EXPECTED_SCHEMA_VERSION_ENV,pr as EXPECTED_SCHEMA_VERSION_TOOL_ENV,cE as EXTERNAL_ID_PATTERN,ue as GOVERNANCE_ACCOUNT_TIERS,_E as GOVERNANCE_SCOPE_REQUIRED_CODE,A as HOSTS_OUTPUT_MAX_BYTES,Rr as IMAGE_TAG_PATTERN,UE as INSTALL_SOURCES,nr as ImageTagSchema,EE as MACHINE_ONLY_SCOPES,Ne as MASKED_VALUE_MARKER,we as MAX_SECONDARY_REGIONS,sr as MIGRATION_SNAPSHOT_NAME_PREFIX,Yr as OPENNEXT_PATTERN_TYPES,ze as OPT_IN_REGION_CODES,Fr as PATTERN_REGISTRY,gr as PATTERN_TYPES,dr as PATTERN_TYPE_VALUES,lr as PHYSICAL_NAME_FALLBACK_PROPERTIES,Mr as PRISMA_MIGRATION_DIR_RE,fE as PUBLIC_PACKAGE_NAME,ie as REDACTED_KEY_SENTINEL,z as REGION_SHORT_CODES,$E as RESERVED_APP_NAMES,er as RESERVED_APP_NAME_MESSAGE,rr as RESERVED_APP_NAME_SUFFIX,_r as RESERVED_APP_NAME_SUFFIX_MESSAGE,Ge as RESOURCE_CATEGORIES,cr as SCHEMA_ADMIN_PASSWORD_ENV,Lr as SCHEMA_ADMIN_USER_ENV,me as SCOPED_TOKEN_REGEX,eE as SCOPE_VALUES,SE as SECRET_NAME_ERROR,oE as SECRET_NAME_PATTERN,lE as SETUP_COMMANDS,dE as SETUP_MODES,xE as SETUP_STEPS,gE as SETUP_STEP_IDS,YE as SKILL_INSTALL_FILENAME,yE as SKILL_INSTALL_PATH,VE as SKILL_INSTALL_SEGMENTS,AE as SSM_COMPONENT_ERROR,TE as SSM_COMPONENT_PATTERN,aE as SSM_STANDARD_MAX_VALUE_BYTES,Gr as STATIC_SITE_ROUTING_VALUES,De as STRUCTURAL_ENVIRONMENTS,NE as SecretNamespaceSchema,ir as ServiceArtefactSchema,mr as ServiceArtefactsSchema,O as TOKEN_STDERR_PREFIX,rE as USER_GRANTABLE_SCOPES,We as abbreviateRegion,f as accountConstructKey,Fe as accountTier,u as albDnsExportName,d as albHostedZoneIdExportName,Pr as artefactOutputKey,x as bucketWebsiteEndpointExportName,F as bucketWebsiteHostedZoneIdExportName,kE as buildAppConfigPath,RE as buildNamespaceParts,nE as buildParameterPath,c as capitalise,He as categoriseResource,g as cdnDomainExportName,j as defaultConnectedAccountName,Kr as defaultFormsCorsOrigin,br as defaultFormsFromAddress,m_ as deploymentFailureDocsUrl,bE as deriveAllTargets,Sr as deriveContentHashTag,C_ as deriveErrorMessageFromFailure,HE as deriveRegionsFromOrgConfig,vE as deriveTargets,KE as environmentOrTier,ge as environmentToTier,PE as escapeDotEnvValue,p_ as extractErrorWindow,ae as filterDangerousEnvVars,k as findAccountNameCollision,wE as findBoundaryPath,jE as findInfrastructurePaths,XE as findTarget,Q as findTrailingRegionShortCode,te as formatErrorString,BE as generateTargetName,_ as getDomainExportNames,t as getDomainStackName,o as getDomainUsEast1CertificatesStackName,Ve as getEnvironmentLabel,re as getErrorCode,ee as getErrorMessage,_e as getErrorStack,ve as getExpectedDuration,be as getFriendlyResourceType,je as getRegionInfo,M as getSafeZoneName,U as hasAsciiStableConstructKey,Ee as hasErrorCode,tr as hasReservedAppNameSuffix,S as hostsExportPartName,C as imageTagParameterName,qE as inferContainerFromCandidates,Me as isAccountStage,le as isAccountTier,Xr as isAddressAtDomain,de as isGovernanceTier,zE as isInfrastructureFile,mE as isManageablePath,a as isManagedDomainBinding,yr as isOpenNextPatternType,xr as isPatternType,Er as isReservedAppName,se as mapSettledWithConcurrency,Re as maskSensitiveOutput,$ as normaliseError,Qe as optInRegionWarning,n_ as parseDeploymentFailure,OE as parseDotEnv,Xe as parseGitRemoteUrl,iE as parseParameterPath,ne as parseShellArgs,hr as patternConstructId,B as projectCapacityIdentityToTarget,q as regionSuffixRejectionMessage,qe as regions,he as resolveSynthEnvironment,T as serialiseHostsChunks,Se as singleton,Pe as sleep,xe as stageFromWireEnvironment,w as suffixedAccountName,Je as suggestRegionForTimezone,s_ as toDeploymentFailureAnalysis,p as toKebab,I as toPascalCase,L as toScreamingSnake,D as toValidDatabaseName,uE as upgradeCommand};
1
+ import{DNS_APEX as r,getDomainExportNames as _,getDomainStackName as o,getDomainUsEast1CertificatesStackName as t,hostsExportPartName as A,serialiseHostsChunks as T,HOSTS_OUTPUT_MAX_BYTES as S,isManagedDomainBinding as a,DOMAIN_DEPLOY_DEFAULT_PHASE as N}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as i}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as O,TOKEN_STDERR_PREFIX as m}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as I}from"./infra/imageTags.js";import{toPascalCase as L,toKebab as s,toValidDatabaseName as p,toScreamingSnake as D,capitalise as M,getSafeZoneName as c,accountConstructKey as f,hasAsciiStableConstructKey as F}from"./naming/caseConversion.js";import{albDnsExportName as l,albHostedZoneIdExportName as u,cdnDomainExportName as d,bucketWebsiteEndpointExportName as x,bucketWebsiteHostedZoneIdExportName as g}from"./naming/targetExportNames.js";import{CAPACITY_SLOT_PATTERN as h,CAPACITY_SLOT_MAX_LENGTH as H,DEFAULT_CAPACITY_SLOT as V,CAPACITY_ANCHOR_PATTERN as Y,CAPACITY_ANCHOR_MAX_LENGTH as y,CAPACITY_IDENTITY_CONTEXT_KEY as K,CapacityIdentityPinSchema as v,CapacityIdentityWireSchema as X,CapacityIdentityConfigSchema as b,projectCapacityIdentityToTarget as B}from"./capacityIdentity.js";import{findAccountNameCollision as J}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as j,suffixedAccountName as w,REGION_SHORT_CODES as Z,findTrailingRegionShortCode as q,regionSuffixRejectionMessage as z}from"./naming/connectedAccountName.js";import{normaliseError as $,getErrorMessage as ee,hasErrorCode as Ee,getErrorCode as re,getErrorStack as _e,formatErrorString as oe}from"./errorUtils.js";import{FJALL_CONFIG_DIR_ENV as Ae,FJALL_CREDENTIALS_FILENAME as Te,FJALL_HOME_DIRNAME as Se,FJALL_LOG_DIR_ENV as ae,fjallCredentialsPath as Ne,fjallHomeDir as Re,fjallLogDir as ie,fjallStatePath as ne}from"./fjallHome.js";import{singleton as me}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as Ie,filterDangerousEnvVars as Pe,MASKED_VALUE_MARKER as Le,maskSensitiveOutput as se,parseShellArgs as pe,REDACTED_KEY_SENTINEL as De,SCOPED_TOKEN_REGEX as Me}from"./securityHelpers.js";import{sleep as fe}from"./async/sleep.js";import{mapSettledWithConcurrency as Ue}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as ue,STRUCTURAL_ENVIRONMENTS as de,ACCOUNT_STAGES as xe,ACCOUNT_STAGE_LABELS as ge,isAccountStage as Ge,ACCOUNT_TIERS as he,AccountTierSchema as He,isAccountTier as Ve,GOVERNANCE_ACCOUNT_TIERS as Ye,isGovernanceTier as ye,environmentToTier as Ke,stageFromWireEnvironment as ve,accountTier as Xe,resolveSynthEnvironment as be,getEnvironmentLabel as Be,ACCOUNT_ROLES as We}from"./environments.js";import{RESOURCE_CATEGORIES as ke,categoriseResource as je,getExpectedDuration as we,getFriendlyResourceType as Ze}from"./resourceCategorisation.js";import{parseGitRemoteUrl as ze}from"./repo/gitRemoteParser.js";import{abbreviateRegion as $e,AWS_REGIONS_METADATA as eE,DEFAULT_REGION as EE,getRegionInfo as rE,MAX_SECONDARY_REGIONS as _E,OPT_IN_REGION_CODES as oE,optInRegionWarning as tE,regions as AE,suggestRegionForTimezone as TE}from"./infra/regions.js";import{SCOPE_VALUES as aE,MACHINE_ONLY_SCOPES as NE,USER_GRANTABLE_SCOPES as RE,GOVERNANCE_SCOPE_REQUIRED_CODE as iE}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as OE,SECRET_NAME_ERROR as mE,SSM_COMPONENT_PATTERN as CE,SSM_COMPONENT_ERROR as IE,SSM_STANDARD_MAX_VALUE_BYTES as PE,SecretNamespaceSchema as LE,buildNamespaceParts as sE,buildParameterPath as pE,parseParameterPath as DE,isManageablePath as ME,parseDotEnv as cE,escapeDotEnvValue as fE}from"./secrets.js";import{ConnectionWireSchema as UE,ConnectionsListResponseSchema as lE,CONNECTION_PHASES as uE,CONNECTION_TERMINAL_FAILURE_PHASES as dE,CONNECTION_FAILURE_REASONS as xE,EXTERNAL_ID_PATTERN as gE}from"./infra/connectionsWire.js";import{PUBLIC_PACKAGE_NAME as hE,INSTALL_SOURCES as HE,SETUP_COMMANDS as VE,upgradeCommand as YE,SETUP_MODES as yE,SETUP_STEP_IDS as KE,SETUP_STEPS as vE,AGENT_SETUP_PROMPTS as XE,AGENT_INSTALL_COMMAND as bE,SKILL_INSTALL_SEGMENTS as BE,SKILL_INSTALL_FILENAME as WE,SKILL_INSTALL_PATH as JE}from"./onboarding/index.js";import{deriveRegionsFromOrgConfig as jE,deriveTargets as wE,deriveAllTargets as ZE,environmentOrTier as qE,findTarget as zE,generateTargetName as QE}from"./targets.js";import{buildAppConfigPath as er}from"./repo/appPath.js";import{findInfrastructurePaths as rr,findBoundaryPath as _r,isInfrastructureFile as or}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as Ar}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as Sr,RESERVED_APP_NAME_MESSAGE as ar,isReservedAppName as Nr,RESERVED_APP_NAME_SUFFIX as Rr,RESERVED_APP_NAME_SUFFIX_MESSAGE as ir,hasReservedAppNameSuffix as nr}from"./naming/reservedAppNames.js";import{deriveContentHashTag as mr,CONTENT_HASH_TAG_PATTERN as Cr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as Pr,DeployModeSchema as Lr,IMAGE_TAG_PATTERN as sr,ImageTagSchema as pr,ServiceArtefactSchema as Dr,ServiceArtefactsSchema as Mr,ARTEFACT_OUTPUT_FIELDS as cr,artefactOutputKey as fr}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as Ur,EXPECTED_SCHEMA_VERSION_ENV as lr,EXPECTED_SCHEMA_VERSION_TOOL_ENV as ur,EXPECTED_CH_SCHEMA_VERSION_ENV as dr,SCHEMA_ADMIN_USER_ENV as xr,SCHEMA_ADMIN_PASSWORD_ENV as gr,PRISMA_MIGRATION_DIR_RE as Gr,CLICKHOUSE_MIGRATION_SKIP_RE as hr}from"./migration/constants.js";import{SCHEMA_GATE_EXIT as Vr,SCHEMA_GATE_EXIT_HINTS as Yr,schemaGateExitKind as yr}from"./migration/schemaGateExit.js";import{FJALL_SCHEMA_GATE_USER as vr,FJALL_MAINTENANCE_USER as Xr,FJALL_CLICKHOUSE_USERS as br}from"./migration/clickhouseFrameworkUsers.js";import{PHYSICAL_NAME_FALLBACK_PROPERTIES as Wr}from"./cfn/physicalNameProperties.js";import{PATTERN_TYPE_VALUES as kr,PATTERN_TYPES as jr,isPatternType as wr,PATTERN_REGISTRY as Zr,patternConstructId as qr,DEPLOYABLE_PATTERN_TYPES as zr,OPENNEXT_PATTERN_TYPES as Qr,isOpenNextPatternType as $r,STATIC_SITE_ROUTING_VALUES as e_,PATTERN_CREATE_INPUT_VALUES as E_,PATTERN_CREATE_INPUT_FLAGS as r_}from"./patterns/patternTypes.js";import{FRAMEWORK_VALUES as o_,FRAMEWORKS as t_,isFramework as A_,FRAMEWORK_PATTERN_RECOMMENDATIONS as T_,recommendPatternForFramework as S_,CREATABLE_FRAMEWORKS as a_,requiredInputsForFramework as N_}from"./patterns/frameworkPatterns.js";import{DEFAULT_FORMS_FROM_LOCAL_PART as i_,defaultFormsFromAddress as n_,defaultFormsCorsOrigin as O_,isAddressAtDomain as m_}from"./patterns/staticSiteForms.js";import{DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION as I_,DEV_SUBSTRATE_PARAMS_FILENAME as P_,DevSubstrateSynthPropsSchema as L_,DevSubstrateParamsSchema as s_}from"./devSubstrate/params.js";import{DEV_SUBSTRATE_ENTRYPOINT_SOURCE as D_}from"./devSubstrate/entrypoint.js";import{BLESSED_CDK_TOOLCHAIN as c_}from"./cdkToolchain.js";import{DEPLOYMENT_FAILURE_PHASES as F_,DeploymentFailurePhaseSchema as U_,DEPLOYMENT_FAULT_ATTRIBUTIONS as l_,DeploymentFaultAttributionSchema as u_,DEPLOYMENT_FAILURE_PROVIDER_SOURCES as d_,DeploymentFailureProviderSourceSchema as x_,DEPLOYMENT_FAILURE_CODE_PATTERN as g_,DEPLOYMENT_FAILURE_SCHEMA_VERSION as G_,DEPLOYMENT_FAILURE_LIMITS as h_,DeploymentFailureAnalysisSchema as H_,DeploymentFailureProviderSchema as V_,DeploymentFailureResourceSchema as Y_,DeploymentFailureSchema as y_,parseDeploymentFailure as K_,DEPLOYMENT_FAILURE_DOCS_BASE_URL as v_,deploymentFailureDocsUrl as X_,DEPLOYMENT_FAULT_COPY as b_,DEPLOYMENT_PROVIDER_LABELS as B_,deriveErrorMessageFromFailure as W_,toDeploymentFailureAnalysis as J_}from"./failure/deploymentFailure.js";import{extractErrorWindow as j_,ERROR_WINDOW_CONTEXT_LINES as w_}from"./failure/extractErrorWindow.js";import{FJALL_COMPONENT_GITIGNORE as q_,FJALL_PROJECT_GITIGNORE as z_,FJALL_STATE_GITIGNORE_ENTRIES as Q_,FJALL_MANAGED_STATE_DIR_ENTRIES as $_,LOCAL_CONFIG_GITIGNORE_ENTRY as eo}from"./scaffold/gitignore.js";import{ensureGitignoreEntries as ro}from"./scaffold/ensureGitignore.js";export{We as ACCOUNT_ROLES,xe as ACCOUNT_STAGES,ue as ACCOUNT_STAGES_WITH_ROOT,ge as ACCOUNT_STAGE_LABELS,he as ACCOUNT_TIERS,bE as AGENT_INSTALL_COMMAND,XE as AGENT_SETUP_PROMPTS,O as APPROVAL_TOKEN_OUTPUT_PREFIX,cr as ARTEFACT_OUTPUT_FIELDS,eE as AWS_REGIONS_METADATA,He as AccountTierSchema,i as BACKUP_VAULT_NAME,c_ as BLESSED_CDK_TOOLCHAIN,y as CAPACITY_ANCHOR_MAX_LENGTH,Y as CAPACITY_ANCHOR_PATTERN,K as CAPACITY_IDENTITY_CONTEXT_KEY,H as CAPACITY_SLOT_MAX_LENGTH,h as CAPACITY_SLOT_PATTERN,hr as CLICKHOUSE_MIGRATION_SKIP_RE,xE as CONNECTION_FAILURE_REASONS,uE as CONNECTION_PHASES,dE as CONNECTION_TERMINAL_FAILURE_PHASES,Cr as CONTENT_HASH_TAG_PATTERN,a_ as CREATABLE_FRAMEWORKS,b as CapacityIdentityConfigSchema,v as CapacityIdentityPinSchema,X as CapacityIdentityWireSchema,UE as ConnectionWireSchema,lE as ConnectionsListResponseSchema,Ie as DANGEROUS_ENV_VARS,V as DEFAULT_CAPACITY_SLOT,i_ as DEFAULT_FORMS_FROM_LOCAL_PART,EE as DEFAULT_REGION,zr as DEPLOYABLE_PATTERN_TYPES,g_ as DEPLOYMENT_FAILURE_CODE_PATTERN,v_ as DEPLOYMENT_FAILURE_DOCS_BASE_URL,h_ as DEPLOYMENT_FAILURE_LIMITS,F_ as DEPLOYMENT_FAILURE_PHASES,d_ as DEPLOYMENT_FAILURE_PROVIDER_SOURCES,G_ as DEPLOYMENT_FAILURE_SCHEMA_VERSION,l_ as DEPLOYMENT_FAULT_ATTRIBUTIONS,b_ as DEPLOYMENT_FAULT_COPY,B_ as DEPLOYMENT_PROVIDER_LABELS,Pr as DEPLOY_MODES,D_ as DEV_SUBSTRATE_ENTRYPOINT_SOURCE,P_ as DEV_SUBSTRATE_PARAMS_FILENAME,I_ as DEV_SUBSTRATE_PARAMS_SCHEMA_VERSION,r as DNS_APEX,N as DOMAIN_DEPLOY_DEFAULT_PHASE,Lr as DeployModeSchema,H_ as DeploymentFailureAnalysisSchema,U_ as DeploymentFailurePhaseSchema,V_ as DeploymentFailureProviderSchema,x_ as DeploymentFailureProviderSourceSchema,Y_ as DeploymentFailureResourceSchema,y_ as DeploymentFailureSchema,u_ as DeploymentFaultAttributionSchema,s_ as DevSubstrateParamsSchema,L_ as DevSubstrateSynthPropsSchema,w_ as ERROR_WINDOW_CONTEXT_LINES,dr as EXPECTED_CH_SCHEMA_VERSION_ENV,lr as EXPECTED_SCHEMA_VERSION_ENV,ur as EXPECTED_SCHEMA_VERSION_TOOL_ENV,gE as EXTERNAL_ID_PATTERN,br as FJALL_CLICKHOUSE_USERS,q_ as FJALL_COMPONENT_GITIGNORE,Ae as FJALL_CONFIG_DIR_ENV,Te as FJALL_CREDENTIALS_FILENAME,Se as FJALL_HOME_DIRNAME,ae as FJALL_LOG_DIR_ENV,Xr as FJALL_MAINTENANCE_USER,$_ as FJALL_MANAGED_STATE_DIR_ENTRIES,z_ as FJALL_PROJECT_GITIGNORE,vr as FJALL_SCHEMA_GATE_USER,Q_ as FJALL_STATE_GITIGNORE_ENTRIES,t_ as FRAMEWORKS,T_ as FRAMEWORK_PATTERN_RECOMMENDATIONS,o_ as FRAMEWORK_VALUES,Ye as GOVERNANCE_ACCOUNT_TIERS,iE as GOVERNANCE_SCOPE_REQUIRED_CODE,S as HOSTS_OUTPUT_MAX_BYTES,sr as IMAGE_TAG_PATTERN,HE as INSTALL_SOURCES,pr as ImageTagSchema,eo as LOCAL_CONFIG_GITIGNORE_ENTRY,NE as MACHINE_ONLY_SCOPES,Le as MASKED_VALUE_MARKER,_E as MAX_SECONDARY_REGIONS,Ur as MIGRATION_SNAPSHOT_NAME_PREFIX,Qr as OPENNEXT_PATTERN_TYPES,oE as OPT_IN_REGION_CODES,r_ as PATTERN_CREATE_INPUT_FLAGS,E_ as PATTERN_CREATE_INPUT_VALUES,Zr as PATTERN_REGISTRY,jr as PATTERN_TYPES,kr as PATTERN_TYPE_VALUES,Wr as PHYSICAL_NAME_FALLBACK_PROPERTIES,Gr as PRISMA_MIGRATION_DIR_RE,hE as PUBLIC_PACKAGE_NAME,De as REDACTED_KEY_SENTINEL,Z as REGION_SHORT_CODES,Sr as RESERVED_APP_NAMES,ar as RESERVED_APP_NAME_MESSAGE,Rr as RESERVED_APP_NAME_SUFFIX,ir as RESERVED_APP_NAME_SUFFIX_MESSAGE,ke as RESOURCE_CATEGORIES,gr as SCHEMA_ADMIN_PASSWORD_ENV,xr as SCHEMA_ADMIN_USER_ENV,Vr as SCHEMA_GATE_EXIT,Yr as SCHEMA_GATE_EXIT_HINTS,Me as SCOPED_TOKEN_REGEX,aE as SCOPE_VALUES,mE as SECRET_NAME_ERROR,OE as SECRET_NAME_PATTERN,VE as SETUP_COMMANDS,yE as SETUP_MODES,vE as SETUP_STEPS,KE as SETUP_STEP_IDS,WE as SKILL_INSTALL_FILENAME,JE as SKILL_INSTALL_PATH,BE as SKILL_INSTALL_SEGMENTS,IE as SSM_COMPONENT_ERROR,CE as SSM_COMPONENT_PATTERN,PE as SSM_STANDARD_MAX_VALUE_BYTES,e_ as STATIC_SITE_ROUTING_VALUES,de as STRUCTURAL_ENVIRONMENTS,LE as SecretNamespaceSchema,Dr as ServiceArtefactSchema,Mr as ServiceArtefactsSchema,m as TOKEN_STDERR_PREFIX,RE as USER_GRANTABLE_SCOPES,$e as abbreviateRegion,f as accountConstructKey,Xe as accountTier,l as albDnsExportName,u as albHostedZoneIdExportName,fr as artefactOutputKey,x as bucketWebsiteEndpointExportName,g as bucketWebsiteHostedZoneIdExportName,er as buildAppConfigPath,sE as buildNamespaceParts,pE as buildParameterPath,M as capitalise,je as categoriseResource,d as cdnDomainExportName,j as defaultConnectedAccountName,O_ as defaultFormsCorsOrigin,n_ as defaultFormsFromAddress,X_ as deploymentFailureDocsUrl,ZE as deriveAllTargets,mr as deriveContentHashTag,W_ as deriveErrorMessageFromFailure,jE as deriveRegionsFromOrgConfig,wE as deriveTargets,ro as ensureGitignoreEntries,qE as environmentOrTier,Ke as environmentToTier,fE as escapeDotEnvValue,j_ as extractErrorWindow,Pe as filterDangerousEnvVars,J as findAccountNameCollision,_r as findBoundaryPath,rr as findInfrastructurePaths,zE as findTarget,q as findTrailingRegionShortCode,Ne as fjallCredentialsPath,Re as fjallHomeDir,ie as fjallLogDir,ne as fjallStatePath,oe as formatErrorString,QE as generateTargetName,_ as getDomainExportNames,o as getDomainStackName,t as getDomainUsEast1CertificatesStackName,Be as getEnvironmentLabel,re as getErrorCode,ee as getErrorMessage,_e as getErrorStack,we as getExpectedDuration,Ze as getFriendlyResourceType,rE as getRegionInfo,c as getSafeZoneName,F as hasAsciiStableConstructKey,Ee as hasErrorCode,nr as hasReservedAppNameSuffix,A as hostsExportPartName,I as imageTagParameterName,Ar as inferContainerFromCandidates,Ge as isAccountStage,Ve as isAccountTier,m_ as isAddressAtDomain,A_ as isFramework,ye as isGovernanceTier,or as isInfrastructureFile,ME as isManageablePath,a as isManagedDomainBinding,$r as isOpenNextPatternType,wr as isPatternType,Nr as isReservedAppName,Ue as mapSettledWithConcurrency,se as maskSensitiveOutput,$ as normaliseError,tE as optInRegionWarning,K_ as parseDeploymentFailure,cE as parseDotEnv,ze as parseGitRemoteUrl,DE as parseParameterPath,pe as parseShellArgs,qr as patternConstructId,B as projectCapacityIdentityToTarget,S_ as recommendPatternForFramework,z as regionSuffixRejectionMessage,AE as regions,N_ as requiredInputsForFramework,be as resolveSynthEnvironment,yr as schemaGateExitKind,T as serialiseHostsChunks,me as singleton,fe as sleep,ve as stageFromWireEnvironment,w as suffixedAccountName,TE as suggestRegionForTimezone,J_ as toDeploymentFailureAnalysis,s as toKebab,L as toPascalCase,D as toScreamingSnake,p as toValidDatabaseName,YE as upgradeCommand};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Size-bounded log files: rotate `x.jsonl` -> `x.1.jsonl` -> … -> delete.
3
+ *
4
+ * Lives in `@fjall/util` because three packages write persistent logs into
5
+ * the same state root and only one of them had a bound. The CLI's logger
6
+ * owned this class privately; `components/infrastructure` could not reach
7
+ * it across the package boundary, so its validation log had no cap at all
8
+ * and grew to hundreds of megabytes on a developer machine over one release
9
+ * cycle. A rotation policy that only one of several writers can reach is
10
+ * not a policy.
11
+ */
12
+ /** Construction options. */
13
+ export interface FileRotatorOptions {
14
+ maxFiles: number;
15
+ }
16
+ export declare class FileRotator {
17
+ private maxFiles;
18
+ constructor(options: FileRotatorOptions);
19
+ /**
20
+ * Check if a file needs rotation based on size
21
+ */
22
+ needsRotation(filePath: string, maxFileSize: number): boolean;
23
+ /** Rotate log files: current -> .1 -> .2 -> delete oldest */
24
+ rotate(filePath: string): void;
25
+ /** Check if rotation is needed and perform it if so */
26
+ rotateIfNeeded(filePath: string, maxFileSize: number): boolean;
27
+ /** Get all rotated file paths for a given log file */
28
+ getRotatedFiles(filePath: string): string[];
29
+ /** Clean up all log files (main and rotated) */
30
+ cleanAll(filePath: string): void;
31
+ }
32
+ /**
33
+ * The bound every Fjall log file shares.
34
+ *
35
+ * Coupled values: the CLI's `LOGGER_DEFAULTS` and the infrastructure
36
+ * validation log both derive from here, so a change to the retention budget
37
+ * cannot apply to one writer and silently miss the other.
38
+ */
39
+ export declare const LOG_ROTATION_DEFAULTS: {
40
+ readonly MAX_FILE_SIZE: number;
41
+ readonly MAX_FILES: 5;
42
+ };
@@ -0,0 +1 @@
1
+ var S=Object.defineProperty;var l=(u,t)=>S(u,"name",{value:t,configurable:!0});import{existsSync as o,renameSync as $,unlinkSync as d,statSync as h,mkdirSync as R}from"fs";import{dirname as x,basename as f,extname as F,join as i}from"path";class _{static{l(this,"FileRotator")}maxFiles;constructor(t){this.maxFiles=t.maxFiles}needsRotation(t,s){try{return o(t)?h(t).size>s:!1}catch{return!1}}rotate(t){try{const s=x(t);if(!o(s)){R(s,{recursive:!0});return}if(!o(t))return;const e=F(t),r=f(t,e),a=i(s,`${r}.${this.maxFiles-1}${e}`);o(a)&&d(a);for(let n=this.maxFiles-2;n>=1;n--){const m=i(s,`${r}.${n}${e}`),y=i(s,`${r}.${n+1}${e}`);o(m)&&$(m,y)}const c=i(s,`${r}.1${e}`);$(t,c)}catch{}}rotateIfNeeded(t,s){return this.needsRotation(t,s)?(this.rotate(t),!0):!1}getRotatedFiles(t){const s=[],e=x(t),r=F(t),a=f(t,r);o(t)&&s.push(t);for(let c=1;c<this.maxFiles;c++){const n=i(e,`${a}.${c}${r}`);if(o(n))s.push(n);else break}return s}cleanAll(t){const s=this.getRotatedFiles(t);for(const e of s)try{d(e)}catch{}}}const b={MAX_FILE_SIZE:10*1024*1024,MAX_FILES:5};export{_ as FileRotator,b as LOG_ROTATION_DEFAULTS};