@fjall/util 2.9.1 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 59 files minified at 2026-06-02T21:42:36.870Z
1
+ 59 files minified at 2026-06-09T10:15:26.341Z
package/dist/Config.d.ts CHANGED
@@ -1,8 +1,34 @@
1
1
  import { z } from "zod";
2
+ import { type AccountTier } from "./environments.js";
3
+ /**
4
+ * Backup Vault Lock modes for an account's DisasterRecovery vault.
5
+ * See decisions/2026-06-03-backup-vault-lock-mode-by-intent.md.
6
+ */
7
+ export declare const VAULT_LOCK_MODES: readonly ["compliance", "governance", "none"];
8
+ export type VaultLockMode = (typeof VAULT_LOCK_MODES)[number];
9
+ /**
10
+ * Account-level S3 Block Public Access posture. Fjall observes-and-flags public
11
+ * buckets through the posture layer rather than hard-blocking, so enforcement is
12
+ * off by default; "enforced" opts an account into all four account-level flags.
13
+ */
14
+ export declare const S3_BPA_MODES: readonly ["enforced", "off"];
15
+ export type S3BpaMode = (typeof S3_BPA_MODES)[number];
2
16
  export type ProviderAccount = {
3
17
  id: string;
4
18
  name: string;
5
- environment: string;
19
+ /**
20
+ * Workload STAGE — null for structural accounts (organisation/platform tiers
21
+ * carry no workload stage). Read the structural axis from `tier`, never from
22
+ * this field.
23
+ */
24
+ environment: string | null;
25
+ /**
26
+ * Structural TIER (organisation/platform/account). Optional for wire
27
+ * back-compat: old configs omit it and readers fall back to decoding
28
+ * `environment` via `accountTier()`. Producers (webapp buildOrgConfigPayload)
29
+ * emit it explicitly so the tier no longer rides on the environment string.
30
+ */
31
+ tier?: AccountTier;
6
32
  managed?: boolean;
7
33
  oidcRoleArn?: string;
8
34
  /**
@@ -11,6 +37,21 @@ export type ProviderAccount = {
11
37
  * lookup (accountId+region), so it must be stamped before cascade deploy.
12
38
  */
13
39
  region?: string;
40
+ /**
41
+ * Backup Vault Lock mode for this account's DisasterRecovery vault. Defaults
42
+ * to "governance" (lock-protected but removable by privileged IAM).
43
+ * "compliance" is permanently immutable after a 3-day cooling-off and
44
+ * requires acknowledgeImmutableVaultLock. "none" disables the lock.
45
+ */
46
+ vaultLock?: VaultLockMode;
47
+ /** Explicit acknowledgement that vaultLock: "compliance" is irreversible. */
48
+ acknowledgeImmutableVaultLock?: boolean;
49
+ /**
50
+ * Account-level S3 Block Public Access posture. Absent ⇒ "off" — Fjall does
51
+ * not enforce account-level BPA (the posture layer flags exposed buckets
52
+ * instead). "enforced" sets all four account-level public-access flags true.
53
+ */
54
+ s3BlockPublicAccess?: S3BpaMode;
14
55
  };
15
56
  export type Profile = {
16
57
  type: "sso" | "oidc";
package/dist/Config.js CHANGED
@@ -1 +1 @@
1
- import*as r from"fs";import*as s from"path";import{z as e}from"zod";import{logger as g}from"./logger.js";const l=10,m=e.object({name:e.string(),type:e.enum(["apex","delegated"]),parentDomain:e.string().optional(),account:e.string().optional()}).strict(),d=e.object({activeTarget:e.string().optional(),domains:e.array(m).optional()}).strict();class a{rootConfig;configPath=null;constructor(o,t){this.rootConfig=o??{},this.configPath=t??null}static findConfigDirectory(){let o=process.cwd();for(let t=0;t<l;t++){const n=s.join(o,"fjall"),i=s.join(n,"fjall-config.json");if(r.existsSync(i))return n;const c=s.join(o,"fjall-config.json");if(r.existsSync(c))return o;const f=s.dirname(o);if(f===o)break;o=f}return null}static loadConfigFile(o){try{return r.accessSync(o,r.constants.R_OK|r.constants.W_OK),r.readFileSync(o,{encoding:"utf8"})}catch(t){return g.debug("Config","Config file not accessible",{file:o,error:t instanceof Error?t.message:String(t)}),null}}static loadConfig(){const o=a.findConfigDirectory();if(!o)return new a;const t=s.join(o,"fjall-config.json"),n=a.loadConfigFile(t);let i;if(n)try{i=d.parse(JSON.parse(n))}catch(c){throw a.formatZodError(c,"fjall-config.json")}return new a(i,t)}static formatZodError(o,t){if(o instanceof e.ZodError&&o.issues.length>0){const c=o.issues.map(f=>`${f.path.join(".")}: ${f.message}`).join("; ");return new Error(`Failed to parse ${t}: ${c}`)}const i=(o instanceof Error?o.message:String(o)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${t}: ${i}`)}saveConfig(){let o=this.configPath;if(!o){const c=a.findConfigDirectory()||s.join(process.cwd(),"fjall");o=s.join(c,"fjall-config.json")}const t=s.dirname(o);r.mkdirSync(t,{recursive:!0});const n=JSON.stringify(this.rootConfig,null,2),i=`${o}.tmp`;r.writeFileSync(i,n,{mode:384}),r.renameSync(i,o)}static getConfigDirectory(){return a.findConfigDirectory()}getActiveTarget(){return this.rootConfig.activeTarget}setActiveTarget(o){this.rootConfig.activeTarget=o}clearActiveTarget(){this.rootConfig.activeTarget=void 0}getDomains(){return this.rootConfig.domains??[]}setDomains(o){this.rootConfig.domains=o}addDomain(o){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(o)}getDomain(o){return this.rootConfig.domains?.find(t=>t.name.toLowerCase()===o.toLowerCase())}removeDomain(o){if(!this.rootConfig.domains)return!1;const t=this.rootConfig.domains.findIndex(n=>n.name.toLowerCase()===o.toLowerCase());return t===-1?!1:(this.rootConfig.domains.splice(t,1),!0)}}export{a as Config,d as RootConfigSchema};
1
+ import*as r from"fs";import*as s from"path";import{z as e}from"zod";import{logger as g}from"./logger.js";const l=10,h=["compliance","governance","none"],p=["enforced","off"],m=e.object({name:e.string(),type:e.enum(["apex","delegated"]),parentDomain:e.string().optional(),account:e.string().optional()}).strict(),d=e.object({activeTarget:e.string().optional(),domains:e.array(m).optional()}).strict();class a{rootConfig;configPath=null;constructor(o,t){this.rootConfig=o??{},this.configPath=t??null}static findConfigDirectory(){let o=process.cwd();for(let t=0;t<l;t++){const n=s.join(o,"fjall"),i=s.join(n,"fjall-config.json");if(r.existsSync(i))return n;const c=s.join(o,"fjall-config.json");if(r.existsSync(c))return o;const f=s.dirname(o);if(f===o)break;o=f}return null}static loadConfigFile(o){try{return r.accessSync(o,r.constants.R_OK|r.constants.W_OK),r.readFileSync(o,{encoding:"utf8"})}catch(t){return g.debug("Config","Config file not accessible",{file:o,error:t instanceof Error?t.message:String(t)}),null}}static loadConfig(){const o=a.findConfigDirectory();if(!o)return new a;const t=s.join(o,"fjall-config.json"),n=a.loadConfigFile(t);let i;if(n)try{i=d.parse(JSON.parse(n))}catch(c){throw a.formatZodError(c,"fjall-config.json")}return new a(i,t)}static formatZodError(o,t){if(o instanceof e.ZodError&&o.issues.length>0){const c=o.issues.map(f=>`${f.path.join(".")}: ${f.message}`).join("; ");return new Error(`Failed to parse ${t}: ${c}`)}const i=(o instanceof Error?o.message:String(o)).replace(/\n/g," ").substring(0,500);return new Error(`Failed to parse ${t}: ${i}`)}saveConfig(){let o=this.configPath;if(!o){const c=a.findConfigDirectory()||s.join(process.cwd(),"fjall");o=s.join(c,"fjall-config.json")}const t=s.dirname(o);r.mkdirSync(t,{recursive:!0});const n=JSON.stringify(this.rootConfig,null,2),i=`${o}.tmp`;r.writeFileSync(i,n,{mode:384}),r.renameSync(i,o)}static getConfigDirectory(){return a.findConfigDirectory()}getActiveTarget(){return this.rootConfig.activeTarget}setActiveTarget(o){this.rootConfig.activeTarget=o}clearActiveTarget(){this.rootConfig.activeTarget=void 0}getDomains(){return this.rootConfig.domains??[]}setDomains(o){this.rootConfig.domains=o}addDomain(o){this.rootConfig.domains||(this.rootConfig.domains=[]),this.rootConfig.domains.push(o)}getDomain(o){return this.rootConfig.domains?.find(t=>t.name.toLowerCase()===o.toLowerCase())}removeDomain(o){if(!this.rootConfig.domains)return!1;const t=this.rootConfig.domains.findIndex(n=>n.name.toLowerCase()===o.toLowerCase());return t===-1?!1:(this.rootConfig.domains.splice(t,1),!0)}}export{a as Config,d as RootConfigSchema,p as S3_BPA_MODES,h as VAULT_LOCK_MODES};
@@ -1,13 +1,17 @@
1
1
  /**
2
- * Standard environment constants shared across CLI, webapp, and deploy-core.
3
- *
4
- * "root" is implicit always derived from role === "organisation",
5
- * not user-selectable.
2
+ * Environment + account-axis constants shared across CLI, webapp, and
3
+ * deploy-core. Two independent axes live here: the workload STAGE
4
+ * ([[ACCOUNT_STAGES]]) and the structural TIER ([[ACCOUNT_TIERS]]). "root" is
5
+ * NOT a stage — it is the management-account TIER, derived from
6
+ * role === "organisation" and never user-selectable.
6
7
  */
7
- export declare const STANDARD_ENVIRONMENTS: readonly ["production", "staging", "development", "platform", "compliance"];
8
- export type StandardEnvironment = (typeof STANDARD_ENVIRONMENTS)[number];
9
- /** Type guard: checks whether a string is a valid standard environment. */
10
- export declare function isValidEnvironment(value: string): value is StandardEnvironment;
8
+ import { z } from "zod";
9
+ export declare const ACCOUNT_STAGES: readonly ["production", "staging", "development", "platform", "compliance"];
10
+ export type AccountStage = (typeof ACCOUNT_STAGES)[number];
11
+ /** Human-readable labels for each workload stage. */
12
+ export declare const ACCOUNT_STAGE_LABELS: Record<AccountStage, string>;
13
+ /** Type guard: checks whether a string is a user-selectable workload stage. */
14
+ export declare function isAccountStage(value: string): value is AccountStage;
11
15
  /**
12
16
  * Structural environments used for cascade account partitioning.
13
17
  * These are not user-selectable — "root" is implicit (management account),
@@ -18,18 +22,33 @@ export declare const STRUCTURAL_ENVIRONMENTS: {
18
22
  readonly PLATFORM: "platform";
19
23
  };
20
24
  /**
21
- * Wire-format environment list including the implicit "root" value.
22
- * Use this for schemas and validators that accept a system-assigned root
23
- * environment (e.g. quick-create when called after `fjall create org`,
24
- * and the public org-config API). User-facing pickers should still use
25
- * STANDARD_ENVIRONMENTS "root" is set by context, not chosen.
25
+ * Wire-tolerance vocabulary: the workload stages PLUS the structural "root"
26
+ * marker. Ingress schemas that face out-of-version CLIs or the org-config
27
+ * GET→PUT round-trip accept this superset, then decode "root" → null at
28
+ * PERSISTENCE via [[stageFromWireEnvironment]] (the DB never stores structural
29
+ * root). NOT a user-facing picker vocabulary pickers use ACCOUNT_STAGES.
30
+ * Retained through the old-CLI drain; wire-rejection of "root" is deferred to a
31
+ * future follow-up. See decisions/2026-06-07-account-tier-vs-stage-separation.md.
26
32
  */
27
- export declare const STANDARD_ENVIRONMENTS_WITH_ROOT: readonly ["production", "staging", "development", "platform", "compliance", "root"];
28
- export type StandardEnvironmentWithRoot = (typeof STANDARD_ENVIRONMENTS_WITH_ROOT)[number];
29
- /** Human-readable labels for each standard environment. */
30
- export declare const ENVIRONMENT_LABELS: Record<StandardEnvironment, string>;
33
+ export declare const ACCOUNT_STAGES_WITH_ROOT: readonly ["production", "staging", "development", "platform", "compliance", "root"];
34
+ export type AccountStageWithRoot = (typeof ACCOUNT_STAGES_WITH_ROOT)[number];
31
35
  /** Returns the human-readable label for an environment, with capitalised fallback. */
32
36
  export declare function getEnvironmentLabel(env: string): string;
37
+ /**
38
+ * Structural TIER axis: an account's role in the organisation. Independent of
39
+ * the workload STAGE axis ([[ACCOUNT_STAGES]]) — a tier is never derived from a
40
+ * stage and vice versa. Same literals as [[ACCOUNT_ROLES]], which `satisfies`
41
+ * this type so the two cannot drift.
42
+ */
43
+ export declare const ACCOUNT_TIERS: readonly ["organisation", "platform", "account"];
44
+ export type AccountTier = (typeof ACCOUNT_TIERS)[number];
45
+ export declare const AccountTierSchema: z.ZodEnum<{
46
+ platform: "platform";
47
+ organisation: "organisation";
48
+ account: "account";
49
+ }>;
50
+ /** Type guard: checks whether a string is a valid account tier. */
51
+ export declare function isAccountTier(value: string): value is AccountTier;
33
52
  /**
34
53
  * AWS account roles in the wire format used across the CLI, webapp API
35
54
  * responses, and the Prisma `AccountRole` enum. This is the SINGLE SOURCE
@@ -40,14 +59,36 @@ export declare function getEnvironmentLabel(env: string): string;
40
59
  * a new role here without updating Prisma fails the parity test; renaming
41
60
  * a value here propagates structurally to the webapp.
42
61
  *
43
- * Coupling: `environment` and `role` move together via
44
- * `environmentToRole`/`roleToEnvironment` in
45
- * `webapp/app/.server/utils/orgConfigHelpers.ts`. See
46
- * [[STRUCTURAL_ENVIRONMENTS]] for the env-side equivalent.
62
+ * Independence: `role` (TIER) and `environment` (STAGE) are independent axes.
63
+ * Inbound wire values that still carry a structural environment are decoded via
64
+ * [[environmentToTier]] / [[stageFromWireEnvironment]] — nothing derives one
65
+ * axis from the other on a write. See [[STRUCTURAL_ENVIRONMENTS]].
47
66
  */
48
67
  export declare const ACCOUNT_ROLES: {
49
68
  readonly ORGANISATION: "organisation";
50
69
  readonly PLATFORM: "platform";
51
70
  readonly ACCOUNT: "account";
52
71
  };
53
- export type AccountRole = (typeof ACCOUNT_ROLES)[keyof typeof ACCOUNT_ROLES];
72
+ /**
73
+ * Decode an inbound wire `environment` to its structural TIER. The wire stays
74
+ * superset-tolerant: out-of-version CLIs and the post-`fjall create org`
75
+ * connect still submit "root"/"platform" as an environment. This is the only
76
+ * sanctioned environment→tier derivation — write paths must NOT re-derive a
77
+ * role from a stage. See decisions/2026-06-07-account-tier-vs-stage-separation.md.
78
+ */
79
+ export declare function environmentToTier(environment: string | null | undefined): AccountTier;
80
+ /**
81
+ * Decode an inbound wire `environment` to its workload STAGE, or null. "root"
82
+ * (the management account — no workloads), empty, null, or any unknown string
83
+ * yields null. "platform" is a real stage and passes through unchanged.
84
+ */
85
+ export declare function stageFromWireEnvironment(environment: string | null | undefined): AccountStage | null;
86
+ /**
87
+ * Canonical TIER accessor for deploy-core/CLI/MCP readers: prefer the explicit
88
+ * `tier` wire field, falling back to decoding a legacy structural environment.
89
+ * Replaces scattered `environment === STRUCTURAL_ENVIRONMENTS.*` comparisons.
90
+ */
91
+ export declare function accountTier(acc: {
92
+ tier?: AccountTier | null;
93
+ environment?: string | null;
94
+ }): AccountTier;
@@ -1 +1 @@
1
- const t=["production","staging","development","platform","compliance"];function n(o){return t.includes(o)}const e={ROOT:"root",PLATFORM:"platform"},p=[...t,e.ROOT],r={production:"Production",staging:"Staging",development:"Development",platform:"Platform",compliance:"Compliance"};function c(o){return n(o)?r[o]:o.charAt(0).toUpperCase()+o.slice(1)}const i={ORGANISATION:"organisation",PLATFORM:"platform",ACCOUNT:"account"};export{i as ACCOUNT_ROLES,r as ENVIRONMENT_LABELS,t as STANDARD_ENVIRONMENTS,p as STANDARD_ENVIRONMENTS_WITH_ROOT,e as STRUCTURAL_ENVIRONMENTS,c as getEnvironmentLabel,n as isValidEnvironment};
1
+ import{z as c}from"zod";const r=["production","staging","development","platform","compliance"],i={production:"Production",staging:"Staging",development:"Development",platform:"Platform",compliance:"Compliance"},T=new Set(r);function n(t){return T.has(t)}const o={ROOT:"root",PLATFORM:"platform"},O=[...r,o.ROOT];function A(t){return n(t)?i[t]:t.charAt(0).toUpperCase()+t.slice(1)}const e=["organisation","platform","account"],l=c.enum(e),a=new Set(e);function s(t){return a.has(t)}const C={ORGANISATION:"organisation",PLATFORM:"platform",ACCOUNT:"account"};function p(t){return t===o.ROOT?"organisation":t===o.PLATFORM?"platform":"account"}function S(t){return t==null||t===""||t===o.ROOT?null:n(t)?t:null}function f(t){return t.tier??p(t.environment)}export{C as ACCOUNT_ROLES,r as ACCOUNT_STAGES,O as ACCOUNT_STAGES_WITH_ROOT,i as ACCOUNT_STAGE_LABELS,e as ACCOUNT_TIERS,l as AccountTierSchema,o as STRUCTURAL_ENVIRONMENTS,f as accountTier,p as environmentToTier,A as getEnvironmentLabel,n as isAccountStage,s as isAccountTier,S as stageFromWireEnvironment};
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export { singleton } from "./singleton.js";
6
6
  export { DANGEROUS_ENV_VARS, filterDangerousEnvVars, maskSensitiveOutput, parseShellArgs } from "./securityHelpers.js";
7
7
  export { sleep } from "./sleep.js";
8
8
  export { mapSettledWithConcurrency } from "./concurrency.js";
9
- export { STANDARD_ENVIRONMENTS, STANDARD_ENVIRONMENTS_WITH_ROOT, STRUCTURAL_ENVIRONMENTS, type StandardEnvironment, type StandardEnvironmentWithRoot, isValidEnvironment, ENVIRONMENT_LABELS, getEnvironmentLabel, ACCOUNT_ROLES, type AccountRole } from "./environments.js";
9
+ export { ACCOUNT_STAGES_WITH_ROOT, STRUCTURAL_ENVIRONMENTS, ACCOUNT_STAGES, ACCOUNT_STAGE_LABELS, isAccountStage, ACCOUNT_TIERS, type AccountTier, AccountTierSchema, isAccountTier, environmentToTier, stageFromWireEnvironment, accountTier, type AccountStageWithRoot, type AccountStage, getEnvironmentLabel, ACCOUNT_ROLES } from "./environments.js";
10
10
  export { RESOURCE_CATEGORIES, type ResourceCategory, categoriseResource, getExpectedDuration, getFriendlyResourceType } from "./resourceCategorisation.js";
11
11
  export { parseGitRemoteUrl, type GitProvider, type ParsedGitRemote } from "./gitRemoteParser.js";
12
12
  export { abbreviateRegion } from "./regions.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{DNS_APEX as o,getDomainExportNames as t}from"./domainExports.js";import{toPascalCase as a,toKebab as i,toValidDatabaseName as n,toScreamingSnake as S,capitalise as N,getSafeZoneName as _,accountConstructKey as s,hasAsciiStableConstructKey as m}from"./caseConversion.js";import{findAccountNameCollision as A}from"./accountNameCollision.js";import{normaliseError as f,getErrorMessage as C,hasErrorCode as g,getErrorCode as T,getErrorStack as O,formatErrorString as I}from"./errorUtils.js";import{singleton as l}from"./singleton.js";import{DANGEROUS_ENV_VARS as c,filterDangerousEnvVars as V,maskSensitiveOutput as D,parseShellArgs as M}from"./securityHelpers.js";import{sleep as P}from"./sleep.js";import{mapSettledWithConcurrency as H}from"./concurrency.js";import{STANDARD_ENVIRONMENTS as b,STANDARD_ENVIRONMENTS_WITH_ROOT as h,STRUCTURAL_ENVIRONMENTS as L,isValidEnvironment as y,ENVIRONMENT_LABELS as G,getEnvironmentLabel as F,ACCOUNT_ROLES as K}from"./environments.js";import{RESOURCE_CATEGORIES as k,categoriseResource as W,getExpectedDuration as B,getFriendlyResourceType as Z}from"./resourceCategorisation.js";import{parseGitRemoteUrl as q}from"./gitRemoteParser.js";import{abbreviateRegion as z}from"./regions.js";import{SCOPE_VALUES as Q}from"./tokenScopes.js";import{deriveRegionsFromOrgConfig as $,deriveTargets as ee,deriveAllTargets as re,findTarget as oe,generateTargetName as te}from"./targets.js";import{buildAppConfigPath as ae}from"./appPath.js";import{findInfrastructurePaths as ne,findBoundaryPath as Se,isInfrastructureFile as Ne}from"./findInfrastructurePaths.js";import{inferContainerFromCandidates as se}from"./inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as Re,isReservedAppName as Ae}from"./reservedAppNames.js";import{deriveContentHashTag as fe}from"./deriveContentHashTag.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as ge,EXPECTED_SCHEMA_VERSION_ENV as Te,EXPECTED_SCHEMA_VERSION_TOOL_ENV as Oe,EXPECTED_CH_SCHEMA_VERSION_ENV as Ie,SCHEMA_ADMIN_USER_ENV as xe,SCHEMA_ADMIN_PASSWORD_ENV as le,PRISMA_MIGRATION_DIR_RE as de,CLICKHOUSE_MIGRATION_SKIP_RE as ce}from"./migration/constants.js";export{K as ACCOUNT_ROLES,ce as CLICKHOUSE_MIGRATION_SKIP_RE,c as DANGEROUS_ENV_VARS,o as DNS_APEX,G as ENVIRONMENT_LABELS,Ie as EXPECTED_CH_SCHEMA_VERSION_ENV,Te as EXPECTED_SCHEMA_VERSION_ENV,Oe as EXPECTED_SCHEMA_VERSION_TOOL_ENV,ge as MIGRATION_SNAPSHOT_NAME_PREFIX,de as PRISMA_MIGRATION_DIR_RE,Re as RESERVED_APP_NAMES,k as RESOURCE_CATEGORIES,le as SCHEMA_ADMIN_PASSWORD_ENV,xe as SCHEMA_ADMIN_USER_ENV,Q as SCOPE_VALUES,b as STANDARD_ENVIRONMENTS,h as STANDARD_ENVIRONMENTS_WITH_ROOT,L as STRUCTURAL_ENVIRONMENTS,z as abbreviateRegion,s as accountConstructKey,ae as buildAppConfigPath,N as capitalise,W as categoriseResource,re as deriveAllTargets,fe as deriveContentHashTag,$ as deriveRegionsFromOrgConfig,ee as deriveTargets,V as filterDangerousEnvVars,A as findAccountNameCollision,Se as findBoundaryPath,ne as findInfrastructurePaths,oe as findTarget,I as formatErrorString,te as generateTargetName,t as getDomainExportNames,F as getEnvironmentLabel,T as getErrorCode,C as getErrorMessage,O as getErrorStack,B as getExpectedDuration,Z as getFriendlyResourceType,_ as getSafeZoneName,m as hasAsciiStableConstructKey,g as hasErrorCode,se as inferContainerFromCandidates,Ne as isInfrastructureFile,Ae as isReservedAppName,y as isValidEnvironment,H as mapSettledWithConcurrency,D as maskSensitiveOutput,f as normaliseError,q as parseGitRemoteUrl,M as parseShellArgs,l as singleton,P as sleep,i as toKebab,a as toPascalCase,S as toScreamingSnake,n as toValidDatabaseName};
1
+ import{DNS_APEX as o,getDomainExportNames as t}from"./domainExports.js";import{toPascalCase as a,toKebab as n,toValidDatabaseName as i,toScreamingSnake as S,capitalise as _,getSafeZoneName as m,accountConstructKey as s,hasAsciiStableConstructKey as A}from"./caseConversion.js";import{findAccountNameCollision as T}from"./accountNameCollision.js";import{normaliseError as N,getErrorMessage as f,hasErrorCode as R,getErrorCode as c,getErrorStack as g,formatErrorString as O}from"./errorUtils.js";import{singleton as I}from"./singleton.js";import{DANGEROUS_ENV_VARS as l,filterDangerousEnvVars as d,maskSensitiveOutput as P,parseShellArgs as M}from"./securityHelpers.js";import{sleep as D}from"./sleep.js";import{mapSettledWithConcurrency as v}from"./concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as h,STRUCTURAL_ENVIRONMENTS as G,ACCOUNT_STAGES as b,ACCOUNT_STAGE_LABELS as L,isAccountStage as y,ACCOUNT_TIERS as F,AccountTierSchema as K,isAccountTier as X,environmentToTier as W,stageFromWireEnvironment as k,accountTier as B,getEnvironmentLabel as Z,ACCOUNT_ROLES as j}from"./environments.js";import{RESOURCE_CATEGORIES as w,categoriseResource as z,getExpectedDuration as J,getFriendlyResourceType as Q}from"./resourceCategorisation.js";import{parseGitRemoteUrl as $}from"./gitRemoteParser.js";import{abbreviateRegion as re}from"./regions.js";import{SCOPE_VALUES as te}from"./tokenScopes.js";import{deriveRegionsFromOrgConfig as ae,deriveTargets as ne,deriveAllTargets as ie,findTarget as Se,generateTargetName as _e}from"./targets.js";import{buildAppConfigPath as se}from"./appPath.js";import{findInfrastructurePaths as Ce,findBoundaryPath as Te,isInfrastructureFile as pe}from"./findInfrastructurePaths.js";import{inferContainerFromCandidates as fe}from"./inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as ce,isReservedAppName as ge}from"./reservedAppNames.js";import{deriveContentHashTag as xe}from"./deriveContentHashTag.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as ue,EXPECTED_SCHEMA_VERSION_ENV as le,EXPECTED_SCHEMA_VERSION_TOOL_ENV as de,EXPECTED_CH_SCHEMA_VERSION_ENV as Pe,SCHEMA_ADMIN_USER_ENV as Me,SCHEMA_ADMIN_PASSWORD_ENV as Ve,PRISMA_MIGRATION_DIR_RE as De,CLICKHOUSE_MIGRATION_SKIP_RE as Ue}from"./migration/constants.js";export{j as ACCOUNT_ROLES,b as ACCOUNT_STAGES,h as ACCOUNT_STAGES_WITH_ROOT,L as ACCOUNT_STAGE_LABELS,F as ACCOUNT_TIERS,K as AccountTierSchema,Ue as CLICKHOUSE_MIGRATION_SKIP_RE,l as DANGEROUS_ENV_VARS,o as DNS_APEX,Pe as EXPECTED_CH_SCHEMA_VERSION_ENV,le as EXPECTED_SCHEMA_VERSION_ENV,de as EXPECTED_SCHEMA_VERSION_TOOL_ENV,ue as MIGRATION_SNAPSHOT_NAME_PREFIX,De as PRISMA_MIGRATION_DIR_RE,ce as RESERVED_APP_NAMES,w as RESOURCE_CATEGORIES,Ve as SCHEMA_ADMIN_PASSWORD_ENV,Me as SCHEMA_ADMIN_USER_ENV,te as SCOPE_VALUES,G as STRUCTURAL_ENVIRONMENTS,re as abbreviateRegion,s as accountConstructKey,B as accountTier,se as buildAppConfigPath,_ as capitalise,z as categoriseResource,ie as deriveAllTargets,xe as deriveContentHashTag,ae as deriveRegionsFromOrgConfig,ne as deriveTargets,W as environmentToTier,d as filterDangerousEnvVars,T as findAccountNameCollision,Te as findBoundaryPath,Ce as findInfrastructurePaths,Se as findTarget,O as formatErrorString,_e as generateTargetName,t as getDomainExportNames,Z as getEnvironmentLabel,c as getErrorCode,f as getErrorMessage,g as getErrorStack,J as getExpectedDuration,Q as getFriendlyResourceType,m as getSafeZoneName,A as hasAsciiStableConstructKey,R as hasErrorCode,fe as inferContainerFromCandidates,y as isAccountStage,X as isAccountTier,pe as isInfrastructureFile,ge as isReservedAppName,v as mapSettledWithConcurrency,P as maskSensitiveOutput,N as normaliseError,$ as parseGitRemoteUrl,M as parseShellArgs,I as singleton,D as sleep,k as stageFromWireEnvironment,n as toKebab,a as toPascalCase,S as toScreamingSnake,i as toValidDatabaseName};
@@ -76,6 +76,7 @@ declare const ManifestServiceSchema: z.ZodObject<{
76
76
  containerPort: z.ZodOptional<z.ZodNumber>;
77
77
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
78
78
  ssmSecretsPath: z.ZodOptional<z.ZodString>;
79
+ importedSecretNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
79
80
  }, z.core.$strict>;
80
81
  export type ManifestService = z.infer<typeof ManifestServiceSchema>;
81
82
  declare const ManifestPatternSchema: z.ZodObject<{
@@ -94,6 +95,7 @@ declare const ManifestLambdaSchema: z.ZodObject<{
94
95
  name: z.ZodString;
95
96
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
96
97
  ssmSecretsPath: z.ZodOptional<z.ZodString>;
98
+ importedSecretNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
97
99
  }, z.core.$strict>;
98
100
  export type ManifestLambda = z.infer<typeof ManifestLambdaSchema>;
99
101
  declare const ManifestStackHashSchema: z.ZodObject<{
@@ -133,11 +135,13 @@ export declare const FjallManifestSchema: z.ZodObject<{
133
135
  containerPort: z.ZodOptional<z.ZodNumber>;
134
136
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
135
137
  ssmSecretsPath: z.ZodOptional<z.ZodString>;
138
+ importedSecretNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
136
139
  }, z.core.$strict>>;
137
140
  lambdas: z.ZodArray<z.ZodObject<{
138
141
  name: z.ZodString;
139
142
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
140
143
  ssmSecretsPath: z.ZodOptional<z.ZodString>;
144
+ importedSecretNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
141
145
  }, z.core.$strict>>;
142
146
  pattern: z.ZodOptional<z.ZodObject<{
143
147
  type: z.ZodEnum<{
@@ -1 +1 @@
1
- import{z as t}from"zod";const h="fjall-manifest.json",u=1,s=t.object({path:t.string(),context:t.string().min(1,"context cannot be empty").optional(),target:t.string().min(1,"target cannot be empty").optional(),buildArgs:t.record(t.string(),t.string()).optional()}).strict(),b=s.partial();function S(e,n){if(n===void 0)return e;const r=n.context??e.context,a=n.target??e.target,o=n.buildArgs??e.buildArgs;return{path:n.path??e.path,...r!==void 0&&{context:r},...a!==void 0&&{target:a},...o!==void 0&&{buildArgs:o}}}const c=t.object({name:t.string(),clusterName:t.string().optional(),docker:s.optional(),containerPort:t.number().optional(),secrets:t.array(t.string()).optional(),ssmSecretsPath:t.string().optional()}).strict(),i=t.object({type:t.enum(["payload"]),name:t.string(),source:t.string()}).strict(),p=t.object({repositoryName:t.string()}).strict(),g=t.object({name:t.string(),secrets:t.array(t.string()).optional(),ssmSecretsPath:t.string().optional()}).strict(),m=t.object({templateHash:t.string(),synthTimestamp:t.string()}).strict(),l=t.object({constructPath:t.string().max(512),group:t.string().max(128),resourceType:t.string().max(256)}).strict(),x=t.object({version:t.literal(u),generatedAt:t.string(),appName:t.string(),services:t.array(c),lambdas:t.array(g),pattern:i.optional(),ecr:p.optional(),stacks:t.record(t.string(),m),resourceMap:t.record(t.string(),l).optional()}).strict();export{b as DockerBuildPartialSchema,s as DockerBuildSchema,h as FJALL_MANIFEST_FILENAME,x as FjallManifestSchema,u as MANIFEST_SCHEMA_VERSION,p as ManifestEcrSchema,g as ManifestLambdaSchema,i as ManifestPatternSchema,c as ManifestServiceSchema,m as ManifestStackHashSchema,l as ResourceMapEntrySchema,S as mergeDockerBuild};
1
+ import{z as t}from"zod";const h="fjall-manifest.json",d=1,s=t.object({path:t.string(),context:t.string().min(1,"context cannot be empty").optional(),target:t.string().min(1,"target cannot be empty").optional(),buildArgs:t.record(t.string(),t.string()).optional()}).strict(),S=s.partial();function b(e,r){if(r===void 0)return e;const n=r.context??e.context,a=r.target??e.target,o=r.buildArgs??e.buildArgs;return{path:r.path??e.path,...n!==void 0&&{context:n},...a!==void 0&&{target:a},...o!==void 0&&{buildArgs:o}}}const c=t.object({name:t.string(),clusterName:t.string().optional(),docker:s.optional(),containerPort:t.number().optional(),secrets:t.array(t.string()).optional(),ssmSecretsPath:t.string().optional(),importedSecretNames:t.array(t.string()).optional()}).strict(),i=t.object({type:t.enum(["payload"]),name:t.string(),source:t.string()}).strict(),p=t.object({repositoryName:t.string()}).strict(),g=t.object({name:t.string(),secrets:t.array(t.string()).optional(),ssmSecretsPath:t.string().optional(),importedSecretNames:t.array(t.string()).optional()}).strict(),m=t.object({templateHash:t.string(),synthTimestamp:t.string()}).strict(),l=t.object({constructPath:t.string().max(512),group:t.string().max(128),resourceType:t.string().max(256)}).strict(),x=t.object({version:t.literal(d),generatedAt:t.string(),appName:t.string(),services:t.array(c),lambdas:t.array(g),pattern:i.optional(),ecr:p.optional(),stacks:t.record(t.string(),m),resourceMap:t.record(t.string(),l).optional()}).strict();export{S as DockerBuildPartialSchema,s as DockerBuildSchema,h as FJALL_MANIFEST_FILENAME,x as FjallManifestSchema,d as MANIFEST_SCHEMA_VERSION,p as ManifestEcrSchema,g as ManifestLambdaSchema,i as ManifestPatternSchema,c as ManifestServiceSchema,m as ManifestStackHashSchema,l as ResourceMapEntrySchema,b as mergeDockerBuild};
@@ -173,7 +173,7 @@ export declare const RegistryActionSchema: z.ZodObject<{
173
173
  export type ScaffoldRegistryAction = z.infer<typeof RegistryActionSchema>;
174
174
  export declare const TargetAccountSchema: z.ZodObject<{
175
175
  name: z.ZodString;
176
- environment: z.ZodString;
176
+ environment: z.ZodNullable<z.ZodString>;
177
177
  source: z.ZodString;
178
178
  }, z.core.$strict>;
179
179
  export type TargetAccount = z.infer<typeof TargetAccountSchema>;
@@ -189,11 +189,11 @@ export declare const ResolvedInputsSchema: z.ZodObject<{
189
189
  }>>;
190
190
  patternDomain: z.ZodOptional<z.ZodString>;
191
191
  network: z.ZodOptional<z.ZodEnum<{
192
+ none: "none";
192
193
  lightweight: "lightweight";
193
194
  standard: "standard";
194
195
  resilient: "resilient";
195
196
  enterprise: "enterprise";
196
- none: "none";
197
197
  }>>;
198
198
  template: z.ZodOptional<z.ZodString>;
199
199
  docker: z.ZodOptional<z.ZodObject<{
@@ -225,11 +225,11 @@ export declare const ScaffoldPlanSchema: z.ZodObject<{
225
225
  }>>;
226
226
  patternDomain: z.ZodOptional<z.ZodString>;
227
227
  network: z.ZodOptional<z.ZodEnum<{
228
+ none: "none";
228
229
  lightweight: "lightweight";
229
230
  standard: "standard";
230
231
  resilient: "resilient";
231
232
  enterprise: "enterprise";
232
- none: "none";
233
233
  }>>;
234
234
  template: z.ZodOptional<z.ZodString>;
235
235
  docker: z.ZodOptional<z.ZodObject<{
@@ -247,12 +247,12 @@ export declare const ScaffoldPlanSchema: z.ZodObject<{
247
247
  }, z.core.$strict>;
248
248
  targetAccount: z.ZodNullable<z.ZodObject<{
249
249
  name: z.ZodString;
250
- environment: z.ZodString;
250
+ environment: z.ZodNullable<z.ZodString>;
251
251
  source: z.ZodString;
252
252
  }, z.core.$strict>>;
253
253
  targetAccountCandidates: z.ZodArray<z.ZodObject<{
254
254
  name: z.ZodString;
255
- environment: z.ZodString;
255
+ environment: z.ZodNullable<z.ZodString>;
256
256
  source: z.ZodString;
257
257
  }, z.core.$strict>>;
258
258
  filesToWrite: z.ZodArray<z.ZodObject<{
@@ -1 +1 @@
1
- import{z as t}from"zod";const p=2,f={AUTHENTICATION_REQUIRED:"AUTHENTICATION_REQUIRED",VALIDATION_ERROR:"VALIDATION_ERROR",INTERNAL_ERROR:"INTERNAL_ERROR",INVALID_SUBCOMMAND:"INVALID_SUBCOMMAND",INVALID_FRAME:"INVALID_FRAME"},a=1e3,e=t.literal(p),l=t.enum(["completed","error","skipped"]),g=t.object({v:e,kind:t.literal("step.start"),stepId:t.string().min(1),name:t.string().min(1),index:t.number().int().min(0),total:t.number().int().min(1)}).strict(),u=t.object({v:e,kind:t.literal("step.complete"),stepId:t.string().min(1),name:t.string().min(1),status:l,index:t.number().int().min(0),total:t.number().int().min(1),errorMessage:t.string().optional()}).strict(),d=t.object({v:e,kind:t.literal("warning"),message:t.string().min(1)}).strict(),b=t.object({code:t.string().min(1),message:t.string().min(1),details:t.record(t.string(),t.unknown()).optional()}).strict(),h=t.object({v:e,kind:t.literal("error"),error:b}).strict(),R=t.object({v:e,kind:t.literal("result"),data:t.unknown()}).strict(),A=t.object({v:e,kind:t.literal("auth.browser.required"),url:t.string().url(),externalId:t.string().min(1),region:t.string().min(1),environment:t.string().min(1),reason:t.string().min(1)}).strict(),S=t.object({v:e,kind:t.literal("auth.browser.complete"),awsAccountId:t.string().min(1),accountName:t.string().min(1),roleArn:t.string().min(1)}).strict(),I=t.discriminatedUnion("kind",[g,u,d,h,R,A,S]),s=t.object({path:t.string().min(1),sizeBytes:t.number().int().nonnegative(),collisionMode:t.enum(["create","overwrite"])}).strict(),c=t.object({type:t.enum(["register-application","create-activity","auto-link-repository","writeback-config-path"]),description:t.string().min(1)}).strict(),x=t.enum(["tinkerer","lightweight","standard","resilient","enterprise"]),k=t.enum(["lightweight","standard","resilient","enterprise","none"]),m=t.object({name:t.string().min(1),environment:t.string().min(1),source:t.string().min(1)}).strict(),E=t.object({name:t.string().min(1),pattern:t.string().min(1).optional(),patternTier:x.optional(),patternDomain:t.string().min(1).optional(),network:k.optional(),template:t.string().min(1).optional(),docker:t.object({path:t.string().min(1).optional(),context:t.string().min(1).optional(),target:t.string().min(1).optional()}).strict().optional(),git:t.boolean().optional(),github:t.boolean().optional(),repoVisibility:t.enum(["private","public"]).optional(),intent:t.string().max(a).optional()}).strict(),T=t.object({planId:t.string().regex(/^[0-9a-f]{32}$/),normalisedPath:t.string().min(1),resolvedInputs:E,targetAccount:m.nullable(),targetAccountCandidates:t.array(m),filesToWrite:t.array(s),npmPackages:t.array(t.string().min(1)),registryActions:t.array(c),patternUnsupportedForDryRun:t.boolean().optional(),intent:t.string().max(a).optional(),framework:t.string().min(1).optional(),summary:t.string().min(1)}).strict(),N=t.object({filesToWrite:t.array(s),npmPackages:t.array(t.string().min(1)),registryActions:t.array(c),patternUnsupportedForDryRun:t.boolean().optional()}).strict(),j=t.object({path:t.string().min(1),name:t.string().min(1),mode:t.enum(["application","pattern"]),dependenciesInstalled:t.boolean().optional(),warning:t.string().optional(),dryRunArtefacts:N.optional()}).strict(),v=t.object({step:t.string().min(1),current:t.number().int().nonnegative(),total:t.number().int().positive().optional(),message:t.string().min(1)}).strict();function w(n){let o;try{o=JSON.parse(n)}catch(i){return{ok:!1,reason:"json",raw:n,error:i instanceof Error?i.message:String(i)}}const r=I.safeParse(o);return r.success?{ok:!0,frame:r.data}:{ok:!1,reason:"schema",raw:n,error:r.error.message}}export{S as AuthBrowserCompleteFrameSchema,A as AuthBrowserRequiredFrameSchema,N as DryRunArtefactsSchema,h as ErrorFrameSchema,s as FileToWriteSchema,a as INTENT_MAX_LENGTH,f as MCP_ERROR_CODES,p as MCP_PROTOCOL_VERSION,I as McpProtocolFrameSchema,c as RegistryActionSchema,E as ResolvedInputsSchema,R as ResultFrameSchema,T as ScaffoldPlanSchema,v as ScaffoldProgressFrameSchema,j as ScaffoldResultDataSchema,u as StepCompleteFrameSchema,g as StepStartFrameSchema,m as TargetAccountSchema,d as WarningFrameSchema,w as parseFrame};
1
+ import{z as t}from"zod";const l=2,f={AUTHENTICATION_REQUIRED:"AUTHENTICATION_REQUIRED",VALIDATION_ERROR:"VALIDATION_ERROR",INTERNAL_ERROR:"INTERNAL_ERROR",INVALID_SUBCOMMAND:"INVALID_SUBCOMMAND",INVALID_FRAME:"INVALID_FRAME"},a=1e3,e=t.literal(l),p=t.enum(["completed","error","skipped"]),g=t.object({v:e,kind:t.literal("step.start"),stepId:t.string().min(1),name:t.string().min(1),index:t.number().int().min(0),total:t.number().int().min(1)}).strict(),u=t.object({v:e,kind:t.literal("step.complete"),stepId:t.string().min(1),name:t.string().min(1),status:p,index:t.number().int().min(0),total:t.number().int().min(1),errorMessage:t.string().optional()}).strict(),d=t.object({v:e,kind:t.literal("warning"),message:t.string().min(1)}).strict(),b=t.object({code:t.string().min(1),message:t.string().min(1),details:t.record(t.string(),t.unknown()).optional()}).strict(),h=t.object({v:e,kind:t.literal("error"),error:b}).strict(),R=t.object({v:e,kind:t.literal("result"),data:t.unknown()}).strict(),A=t.object({v:e,kind:t.literal("auth.browser.required"),url:t.string().url(),externalId:t.string().min(1),region:t.string().min(1),environment:t.string().min(1),reason:t.string().min(1)}).strict(),S=t.object({v:e,kind:t.literal("auth.browser.complete"),awsAccountId:t.string().min(1),accountName:t.string().min(1),roleArn:t.string().min(1)}).strict(),I=t.discriminatedUnion("kind",[g,u,d,h,R,A,S]),s=t.object({path:t.string().min(1),sizeBytes:t.number().int().nonnegative(),collisionMode:t.enum(["create","overwrite"])}).strict(),c=t.object({type:t.enum(["register-application","create-activity","auto-link-repository","writeback-config-path"]),description:t.string().min(1)}).strict(),x=t.enum(["tinkerer","lightweight","standard","resilient","enterprise"]),k=t.enum(["lightweight","standard","resilient","enterprise","none"]),m=t.object({name:t.string().min(1),environment:t.string().min(1).nullable(),source:t.string().min(1)}).strict(),E=t.object({name:t.string().min(1),pattern:t.string().min(1).optional(),patternTier:x.optional(),patternDomain:t.string().min(1).optional(),network:k.optional(),template:t.string().min(1).optional(),docker:t.object({path:t.string().min(1).optional(),context:t.string().min(1).optional(),target:t.string().min(1).optional()}).strict().optional(),git:t.boolean().optional(),github:t.boolean().optional(),repoVisibility:t.enum(["private","public"]).optional(),intent:t.string().max(a).optional()}).strict(),T=t.object({planId:t.string().regex(/^[0-9a-f]{32}$/),normalisedPath:t.string().min(1),resolvedInputs:E,targetAccount:m.nullable(),targetAccountCandidates:t.array(m),filesToWrite:t.array(s),npmPackages:t.array(t.string().min(1)),registryActions:t.array(c),patternUnsupportedForDryRun:t.boolean().optional(),intent:t.string().max(a).optional(),framework:t.string().min(1).optional(),summary:t.string().min(1)}).strict(),N=t.object({filesToWrite:t.array(s),npmPackages:t.array(t.string().min(1)),registryActions:t.array(c),patternUnsupportedForDryRun:t.boolean().optional()}).strict(),j=t.object({path:t.string().min(1),name:t.string().min(1),mode:t.enum(["application","pattern"]),dependenciesInstalled:t.boolean().optional(),warning:t.string().optional(),dryRunArtefacts:N.optional()}).strict(),v=t.object({step:t.string().min(1),current:t.number().int().nonnegative(),total:t.number().int().positive().optional(),message:t.string().min(1)}).strict();function w(n){let o;try{o=JSON.parse(n)}catch(i){return{ok:!1,reason:"json",raw:n,error:i instanceof Error?i.message:String(i)}}const r=I.safeParse(o);return r.success?{ok:!0,frame:r.data}:{ok:!1,reason:"schema",raw:n,error:r.error.message}}export{S as AuthBrowserCompleteFrameSchema,A as AuthBrowserRequiredFrameSchema,N as DryRunArtefactsSchema,h as ErrorFrameSchema,s as FileToWriteSchema,a as INTENT_MAX_LENGTH,f as MCP_ERROR_CODES,l as MCP_PROTOCOL_VERSION,I as McpProtocolFrameSchema,c as RegistryActionSchema,E as ResolvedInputsSchema,R as ResultFrameSchema,T as ScaffoldPlanSchema,v as ScaffoldProgressFrameSchema,j as ScaffoldResultDataSchema,u as StepCompleteFrameSchema,g as StepStartFrameSchema,m as TargetAccountSchema,d as WarningFrameSchema,w as parseFrame};
@@ -1 +1 @@
1
- const n=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_DEBUG","NODE_PRESERVE_SYMLINKS","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","LD_BIND_NOW","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PERL5LIB","PERL5OPT","RUBYLIB","RUBYOPT","HOME","XDG_CONFIG_HOME","AWS_SHARED_CREDENTIALS_FILE","AWS_CONFIG_FILE","SHELL","BASH_ENV","ENV","ZDOTDIR"]);function i(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!n.has(t.toUpperCase())))}const c=/fjall_ak_[A-Z2-7]{16}\.[A-Z2-7]{40}/,l=/fjall_ak_[A-Z2-7]{16}\.[A-Z2-7]{40}/g;function o(e){return e.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----(?:[^"\\]|\\[\\nrt"])*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/(\w+:\/\/[^:]+:)[^@]+(@)/gi,"$1***$2").replace(/(?<![a-zA-Z])(password|passwd|secret|api[_-]?key|token|auth|credential)([=:])["']?[^\s"']+/gi,"$1$2***").replace(/\b(ghu_|ghs_|ghp_|gho_|github_pat_)[A-Za-z0-9_]+/g,"$1***").replace(/(?<=Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi,"***").replace(/\b(AKIA|ASIA)[A-Z0-9]{12,}\b/g,"$1***").replace(/(?<=AWS_SECRET_ACCESS_KEY=|SecretAccessKey[=:]\s*|"secretAccessKey":\s*")[A-Za-z0-9/+=]{40,}/g,"***").replace(/(arn:aws[^:]*:[^:]*:[^:]*:)(\d{12})(:[^\s]*)/g,"$1***$3").replace(/(?<="(aws)?[Ss]essionToken":\s*")[^"]+/g,"***").replace(/(?<="(internal[Aa]piKey|fjallCallbackToken)":\s*")[^"]+/g,"***").replace(l,"fjall_ak_***")}function D(e){const t=[];let E="",r=!1,A=!1,_=!1,s=!1;for(const a of e){if(_){E+=a,_=!1;continue}if(a==="\\"&&!r){_=!0;continue}if(a==="'"&&!A){r=!r,s=!0;continue}if(a==='"'&&!r){A=!A,s=!0;continue}if(a===" "&&!r&&!A){(E||s)&&(t.push(E),E="",s=!1);continue}E+=a}if(r||A)throw new Error(`Unbalanced ${r?"single":"double"} quote in command: ${e.slice(0,80)}`);if(_)throw new Error(`Trailing backslash in command: ${e.slice(0,80)}`);return(E||s)&&t.push(E),t}export{n as DANGEROUS_ENV_VARS,c as SCOPED_TOKEN_REGEX,i as filterDangerousEnvVars,o as maskSensitiveOutput,D as parseShellArgs};
1
+ const n=new Set(["NODE_OPTIONS","NODE_PATH","NODE_EXTRA_CA_CERTS","NODE_DEBUG","NODE_PRESERVE_SYMLINKS","LD_PRELOAD","LD_LIBRARY_PATH","LD_AUDIT","LD_BIND_NOW","DYLD_INSERT_LIBRARIES","DYLD_LIBRARY_PATH","DYLD_FRAMEWORK_PATH","PYTHONPATH","PYTHONSTARTUP","PERL5LIB","PERL5OPT","RUBYLIB","RUBYOPT","HOME","XDG_CONFIG_HOME","AWS_SHARED_CREDENTIALS_FILE","AWS_CONFIG_FILE","SHELL","BASH_ENV","ENV","ZDOTDIR"]);function c(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!n.has(t.toUpperCase())))}const i=/fjall_ak_[A-Z2-7]{16}\.[A-Z2-7]{40}/,l=/fjall_ak_[A-Z2-7]{16}\.[A-Z2-7]{40}/g;function o(e){return e.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----(?:[^"\\]|\\[\\nrt"])*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,"-----BEGIN [REDACTED] PRIVATE KEY-----...-----END [REDACTED] PRIVATE KEY-----").replace(/(\w+:\/\/[^:]+:)[^@]+(@)/gi,"$1***$2").replace(/(?<![a-zA-Z])(password|passwd|secret|api[_-]?key|token|auth|credential)([=:])["']?[^\s"']+/gi,"$1$2***").replace(/\b(ghu_|ghs_|ghp_|gho_|github_pat_)[A-Za-z0-9_]+/g,"$1***").replace(/\b(sk|rk)_(live|test)_[A-Za-z0-9]{8,}/g,"$1_$2_***").replace(/\bwhsec_[A-Za-z0-9]{8,}/g,"whsec_***").replace(/(?<=Authorization:\s*Bearer\s+)[A-Za-z0-9._~+/=-]+/gi,"***").replace(/\b(AKIA|ASIA)[A-Z0-9]{12,}\b/g,"$1***").replace(/(?<=AWS_SECRET_ACCESS_KEY=|SecretAccessKey[=:]\s*|"secretAccessKey":\s*")[A-Za-z0-9/+=]{40,}/g,"***").replace(/(arn:aws[^:]*:[^:]*:[^:]*:)(\d{12})(:[^\s]*)/g,"$1***$3").replace(/(?<="(aws)?[Ss]essionToken":\s*")[^"]+/g,"***").replace(/(?<="(internal[Aa]piKey|fjallCallbackToken)":\s*")[^"]+/g,"***").replace(l,"fjall_ak_***")}function D(e){const t=[];let E="",r=!1,A=!1,_=!1,s=!1;for(const a of e){if(_){E+=a,_=!1;continue}if(a==="\\"&&!r){_=!0;continue}if(a==="'"&&!A){r=!r,s=!0;continue}if(a==='"'&&!r){A=!A,s=!0;continue}if(a===" "&&!r&&!A){(E||s)&&(t.push(E),E="",s=!1);continue}E+=a}if(r||A)throw new Error(`Unbalanced ${r?"single":"double"} quote in command: ${e.slice(0,80)}`);if(_)throw new Error(`Trailing backslash in command: ${e.slice(0,80)}`);return(E||s)&&t.push(E),t}export{n as DANGEROUS_ENV_VARS,i as SCOPED_TOKEN_REGEX,c as filterDangerousEnvVars,o as maskSensitiveOutput,D as parseShellArgs};
package/dist/targets.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * A "target" is a deployment destination: an account + region combination
5
5
  * with a canonical name derived from org config at runtime.
6
6
  */
7
+ import { type AccountTier } from "./environments.js";
7
8
  /** Structural interface for the region fields on OrgConfig. */
8
9
  export interface OrgConfigRegions {
9
10
  primaryRegion?: string;
@@ -18,7 +19,9 @@ export declare function deriveRegionsFromOrgConfig(config: OrgConfigRegions): st
18
19
  export interface TargetAccount {
19
20
  name: string;
20
21
  id: string;
21
- environment: string;
22
+ /** Workload STAGE — null for structural accounts; read tier from `tier`. */
23
+ environment: string | null;
24
+ tier?: AccountTier;
22
25
  }
23
26
  export interface DerivedTarget {
24
27
  name: string;
package/dist/targets.js CHANGED
@@ -1 +1 @@
1
- import{abbreviateRegion as c}from"./regions.js";function s(e){const r=[e.primaryRegion,...e.secondaryRegions??[],e.disasterRecoveryRegion].filter(t=>t!==void 0);return[...new Set(r)]}function m(e,r){return`${e.toLowerCase()}-${c(r)}`}function u(e,r){const t=[];for(const n of e)if(n.environment!=="root")for(const o of r)t.push({name:m(n.name,o),accountName:n.name,accountId:n.id,environment:n.environment,region:o});return t.sort((n,o)=>{const i=n.environment.localeCompare(o.environment);if(i!==0)return i;const a=n.accountName.localeCompare(o.accountName);return a!==0?a:n.region.localeCompare(o.region)})}function f(e){return u(e.providerAccounts,s(e))}function p(e,r){if(r.length===0)return e;const t=new Set([e.primaryRegion,e.disasterRecoveryRegion].filter(Boolean)),n=r.filter(o=>!t.has(o));return{...e,secondaryRegions:n.length>0?n:void 0}}function g(e,r){return e.find(t=>t.name===r)}export{f as deriveAllTargets,s as deriveRegionsFromOrgConfig,u as deriveTargets,g as findTarget,m as generateTargetName,p as mergeSecondaryRegions};
1
+ import{abbreviateRegion as s}from"./regions.js";import{accountTier as c}from"./environments.js";function m(e){const r=[e.primaryRegion,...e.secondaryRegions??[],e.disasterRecoveryRegion].filter(t=>t!==void 0);return[...new Set(r)]}function u(e,r){return`${e.toLowerCase()}-${s(r)}`}function f(e,r){const t=[];for(const n of e){if(c(n)==="organisation")continue;const o=n.environment??c(n);for(const i of r)t.push({name:u(n.name,i),accountName:n.name,accountId:n.id,environment:o,region:i})}return t.sort((n,o)=>{const i=n.environment.localeCompare(o.environment);if(i!==0)return i;const a=n.accountName.localeCompare(o.accountName);return a!==0?a:n.region.localeCompare(o.region)})}function p(e){return f(e.providerAccounts,m(e))}function v(e,r){if(r.length===0)return e;const t=new Set([e.primaryRegion,e.disasterRecoveryRegion].filter(Boolean)),n=r.filter(o=>!t.has(o));return{...e,secondaryRegions:n.length>0?n:void 0}}function l(e,r){return e.find(t=>t.name===r)}export{p as deriveAllTargets,m as deriveRegionsFromOrgConfig,f as deriveTargets,l as findTarget,u as generateTargetName,v as mergeSecondaryRegions};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "2.9.1",
3
+ "version": "2.12.0",
4
4
  "description": "Common utility methods",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -117,5 +117,5 @@
117
117
  "engines": {
118
118
  "node": ">=22.0.0"
119
119
  },
120
- "gitHead": "a97423cf3df727994364a0907fa2b5c544a86b0d"
120
+ "gitHead": "dca39a47da956d3d94c689dd782fe285d711d25e"
121
121
  }