@fjall/util 2.23.1 → 2.25.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
- 73 files minified at 2026-07-02T12:17:29.289Z
1
+ 75 files minified at 2026-07-06T11:56:15.602Z
@@ -0,0 +1,21 @@
1
+ export interface StaleCdkTmpdir {
2
+ readonly path: string;
3
+ readonly sizeBytes: number;
4
+ readonly mtime: Date;
5
+ }
6
+ export interface FindOptions {
7
+ /** Base tmpdir to scan. Defaults to os.tmpdir(); overridden by tests. */
8
+ readonly tmpdirPath?: string;
9
+ /** Minimum age before a dir is reported. Defaults to 24h. */
10
+ readonly maxAgeMs?: number;
11
+ }
12
+ export interface CleanupResult {
13
+ readonly removed: number;
14
+ readonly failed: number;
15
+ readonly bytesReclaimed: number;
16
+ }
17
+ export declare function findStaleCdkTmpdirs(options?: FindOptions): Promise<StaleCdkTmpdir[]>;
18
+ export declare function removeStaleCdkTmpdirs(dirs: readonly StaleCdkTmpdir[]): Promise<CleanupResult>;
19
+ /** Find + remove in one call — the shape vitest teardown reapers consume. */
20
+ export declare function cleanupStaleCdkTmpdirs(options?: FindOptions): Promise<CleanupResult>;
21
+ export declare function formatBytes(bytes: number): string;
@@ -0,0 +1 @@
1
+ import{readdir as d,stat as l,rm as h}from"fs/promises";import{tmpdir as w}from"os";import{join as m}from"path";import{logger as g}from"./logger.js";const B="cdkTmpdirCleanup";function o(e,t,r={}){g.debug(B,e,{error:t instanceof Error?t.message:String(t),...r})}const T="cdk.out",x=1440*60*1e3;async function u(e){let t=0,r;try{r=await d(e,{withFileTypes:!0})}catch(i){return o("readdir failed",i,{path:e}),0}for(const i of r){const a=m(e,i.name);if(i.isDirectory())t+=await u(a);else if(i.isFile())try{const n=await l(a);t+=n.size}catch(n){o("stat failed",n,{path:a})}}return t}async function D(e={}){const t=e.tmpdirPath??w(),r=e.maxAgeMs??x,i=Date.now()-r;let a;try{a=await d(t)}catch(s){return o("tmpdir readdir failed",s,{root:t}),[]}const n=[];for(const s of a){if(!s.startsWith(T))continue;const c=m(t,s);let f;try{f=await l(c)}catch(y){o("stat failed",y,{path:c});continue}if(!f.isDirectory()||f.mtimeMs>i)continue;const p=await u(c);n.push({path:c,sizeBytes:p,mtime:f.mtime})}return n}async function M(e){let t=0,r=0,i=0;for(const a of e)try{await h(a.path,{recursive:!0,force:!0}),t+=1,i+=a.sizeBytes}catch(n){o("rm failed",n,{path:a.path}),r+=1}return{removed:t,failed:r,bytesReclaimed:i}}async function E(e={}){const t=await D(e);return M(t)}function F(e){const t=["B","KB","MB","GB","TB"];let r=e,i=0;for(;r>=1024&&i<t.length-1;)r/=1024,i+=1;return`${r.toFixed(r<10?2:1)} ${t[i]}`}export{E as cleanupStaleCdkTmpdirs,D as findStaleCdkTmpdirs,F as formatBytes,M as removeStaleCdkTmpdirs};
package/dist/config.d.ts CHANGED
@@ -25,12 +25,8 @@ export type S3BpaMode = (typeof S3_BPA_MODES)[number];
25
25
  * 2026-06-10-centralised-root-access-default-on). Absent ⇒ "centralised"
26
26
  * (default-on); "off" maps to OrgSetupConfig.skipRootAccessManagement at the
27
27
  * adapter boundaries (CLI buildOrgSetupConfig, webapp setup route). The
28
- * webapp carries a twin of this pair at
29
- * webapp/app/.server/constants/rootAccess.ts.
30
- * TODO 2026-06-11, owner: paul — tracked in
31
- * aiDocs/plans/tasks/2026-06-11-root-access-p2-t11-org-config-field-fjall.md:
32
- * once a published @fjall/util ships this tuple, convert the webapp twin into
33
- * a re-export from "@fjall/util/config" (TRAIL_LIFECYCLE_STATES precedent).
28
+ * webapp re-exports this tuple at webapp/app/.server/constants/rootAccess.ts
29
+ * (P2-T11, TRAIL_LIFECYCLE_STATES precedent).
34
30
  */
35
31
  export declare const ROOT_ACCESS_MANAGEMENT_MODES: readonly ["centralised", "off"];
36
32
  export type RootAccessManagementMode = (typeof ROOT_ACCESS_MANAGEMENT_MODES)[number];
@@ -9,3 +9,10 @@
9
9
  * silently. `@fjall/util` is the lowest common dependency of both.
10
10
  */
11
11
  export declare const APPROVAL_TOKEN_OUTPUT_PREFIX = "Approval token: ";
12
+ /**
13
+ * The exact stderr prefix the CLI prints minted scoped tokens under
14
+ * (`fjall ci setup` / `fjall ci token create` / `fjall user token create`)
15
+ * and the MCP `apply_ci_setup` handler parses to capture the one-time value.
16
+ * Same cross-package print/parse contract as APPROVAL_TOKEN_OUTPUT_PREFIX.
17
+ */
18
+ export declare const TOKEN_STDERR_PREFIX = "Token: ";
@@ -1 +1 @@
1
- const o="Approval token: ";export{o as APPROVAL_TOKEN_OUTPUT_PREFIX};
1
+ const o="Approval token: ",T="Token: ";export{o as APPROVAL_TOKEN_OUTPUT_PREFIX,T as TOKEN_STDERR_PREFIX};
package/dist/index.d.ts CHANGED
@@ -1,20 +1,20 @@
1
1
  export { DNS_APEX, getDomainExportNames, type ManagedDomainExports } from "./infra/domainExports.js";
2
2
  export { BACKUP_VAULT_NAME } from "./infra/backupVault.js";
3
- export { APPROVAL_TOKEN_OUTPUT_PREFIX } from "./deploy/approvalTokenOutput.js";
3
+ export { APPROVAL_TOKEN_OUTPUT_PREFIX, TOKEN_STDERR_PREFIX } from "./deploy/approvalTokenOutput.js";
4
4
  export { imageTagParameterName } from "./infra/imageTags.js";
5
5
  export { toPascalCase, toKebab, toValidDatabaseName, toScreamingSnake, capitalise, getSafeZoneName, accountConstructKey, hasAsciiStableConstructKey } from "./naming/caseConversion.js";
6
6
  export { findAccountNameCollision, type AccountNameCollision } from "./naming/accountNameCollision.js";
7
7
  export { defaultConnectedAccountName, suffixedAccountName, REGION_SHORT_CODES, findTrailingRegionShortCode, regionSuffixRejectionMessage } from "./naming/connectedAccountName.js";
8
8
  export { normaliseError, getErrorMessage, hasErrorCode, getErrorCode, getErrorStack, formatErrorString } from "./errorUtils.js";
9
9
  export { singleton } from "./async/singleton.js";
10
- export { DANGEROUS_ENV_VARS, filterDangerousEnvVars, maskSensitiveOutput, parseShellArgs } from "./securityHelpers.js";
10
+ export { DANGEROUS_ENV_VARS, filterDangerousEnvVars, maskSensitiveOutput, parseShellArgs, SCOPED_TOKEN_REGEX } from "./securityHelpers.js";
11
11
  export { sleep } from "./async/sleep.js";
12
12
  export { mapSettledWithConcurrency } from "./async/concurrency.js";
13
13
  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";
14
14
  export { RESOURCE_CATEGORIES, type ResourceCategory, categoriseResource, getExpectedDuration, getFriendlyResourceType } from "./resourceCategorisation.js";
15
15
  export { parseGitRemoteUrl, type GitProvider, type ParsedGitRemote } from "./repo/gitRemoteParser.js";
16
16
  export { abbreviateRegion, AWS_REGIONS_METADATA, DEFAULT_REGION, getRegionInfo, MAX_SECONDARY_REGIONS, OPT_IN_REGION_CODES, optInRegionWarning, regions, suggestRegionForTimezone, type RegionCode, type RegionInfo } from "./infra/regions.js";
17
- export { SCOPE_VALUES, type TokenScope } from "./infra/tokenScopes.js";
17
+ export { SCOPE_VALUES, MACHINE_ONLY_SCOPES, USER_GRANTABLE_SCOPES, type TokenScope } from "./infra/tokenScopes.js";
18
18
  export { SECRET_NAME_PATTERN, SECRET_NAME_ERROR, SSM_COMPONENT_PATTERN, SSM_COMPONENT_ERROR, SSM_STANDARD_MAX_VALUE_BYTES, SecretNamespaceSchema, type SecretNamespace, buildNamespaceParts, buildParameterPath, parseParameterPath, isManageablePath, parseDotEnv, escapeDotEnvValue } from "./secrets.js";
19
19
  export { ConnectionWireSchema, type ConnectionWire, ConnectionsListResponseSchema, type ConnectionsListResponse } from "./infra/connectionsWire.js";
20
20
  export { deriveRegionsFromOrgConfig, deriveTargets, deriveAllTargets, environmentOrTier, findTarget, generateTargetName, type OrgConfigRegions, type TargetAccount, type DerivedTarget } from "./targets.js";
@@ -23,5 +23,6 @@ export { type ScanPath } from "./repo/scanTypes.js";
23
23
  export { findInfrastructurePaths, findBoundaryPath, isInfrastructureFile, type MarkerEntry, type FindInfrastructurePathsOptions } from "./repo/findInfrastructurePaths.js";
24
24
  export { inferContainerFromCandidates } from "./repo/inferContainerFromCandidates.js";
25
25
  export { RESERVED_APP_NAMES, type ReservedAppName, RESERVED_APP_NAME_MESSAGE, isReservedAppName } from "./naming/reservedAppNames.js";
26
- export { deriveContentHashTag } from "./infra/deriveContentHashTag.js";
26
+ export { deriveContentHashTag, CONTENT_HASH_TAG_PATTERN } from "./infra/deriveContentHashTag.js";
27
+ 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";
27
28
  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";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{DNS_APEX as o,getDomainExportNames as t}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as a}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as i}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as _}from"./infra/imageTags.js";import{toPascalCase as m,toKebab as R,toValidDatabaseName as s,toScreamingSnake as N,capitalise as T,getSafeZoneName as C,accountConstructKey as p,hasAsciiStableConstructKey as O}from"./naming/caseConversion.js";import{findAccountNameCollision as c}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as P,suffixedAccountName as I,REGION_SHORT_CODES as u,findTrailingRegionShortCode as x,regionSuffixRejectionMessage as M}from"./naming/connectedAccountName.js";import{normaliseError as l,getErrorMessage as D,hasErrorCode as V,getErrorCode as U,getErrorStack as h,formatErrorString as G}from"./errorUtils.js";import{singleton as L}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as H,filterDangerousEnvVars as F,maskSensitiveOutput as X,parseShellArgs as K}from"./securityHelpers.js";import{sleep as y}from"./async/sleep.js";import{mapSettledWithConcurrency as k}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as j,STRUCTURAL_ENVIRONMENTS as z,ACCOUNT_STAGES as Z,ACCOUNT_STAGE_LABELS as q,isAccountStage as w,ACCOUNT_TIERS as J,AccountTierSchema as Q,isAccountTier as $,environmentToTier as ee,stageFromWireEnvironment as re,accountTier as oe,getEnvironmentLabel as te,ACCOUNT_ROLES as Ee}from"./environments.js";import{RESOURCE_CATEGORIES as ne,categoriseResource as ie,getExpectedDuration as Se,getFriendlyResourceType as _e}from"./resourceCategorisation.js";import{parseGitRemoteUrl as me}from"./repo/gitRemoteParser.js";import{abbreviateRegion as se,AWS_REGIONS_METADATA as Ne,DEFAULT_REGION as Te,getRegionInfo as Ce,MAX_SECONDARY_REGIONS as pe,OPT_IN_REGION_CODES as Oe,optInRegionWarning as fe,regions as ce,suggestRegionForTimezone as ge}from"./infra/regions.js";import{SCOPE_VALUES as Ie}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as xe,SECRET_NAME_ERROR as Me,SSM_COMPONENT_PATTERN as de,SSM_COMPONENT_ERROR as le,SSM_STANDARD_MAX_VALUE_BYTES as De,SecretNamespaceSchema as Ve,buildNamespaceParts as Ue,buildParameterPath as he,parseParameterPath as Ge,isManageablePath as ve,parseDotEnv as Le,escapeDotEnvValue as be}from"./secrets.js";import{ConnectionWireSchema as Fe,ConnectionsListResponseSchema as Xe}from"./infra/connectionsWire.js";import{deriveRegionsFromOrgConfig as We,deriveTargets as ye,deriveAllTargets as Be,environmentOrTier as ke,findTarget as Ye,generateTargetName as je}from"./targets.js";import{buildAppConfigPath as Ze}from"./repo/appPath.js";import{findInfrastructurePaths as we,findBoundaryPath as Je,isInfrastructureFile as Qe}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as er}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as or,RESERVED_APP_NAME_MESSAGE as tr,isReservedAppName as Er}from"./naming/reservedAppNames.js";import{deriveContentHashTag as nr}from"./infra/deriveContentHashTag.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as Sr,EXPECTED_SCHEMA_VERSION_ENV as _r,EXPECTED_SCHEMA_VERSION_TOOL_ENV as Ar,EXPECTED_CH_SCHEMA_VERSION_ENV as mr,SCHEMA_ADMIN_USER_ENV as Rr,SCHEMA_ADMIN_PASSWORD_ENV as sr,PRISMA_MIGRATION_DIR_RE as Nr,CLICKHOUSE_MIGRATION_SKIP_RE as Tr}from"./migration/constants.js";export{Ee as ACCOUNT_ROLES,Z as ACCOUNT_STAGES,j as ACCOUNT_STAGES_WITH_ROOT,q as ACCOUNT_STAGE_LABELS,J as ACCOUNT_TIERS,i as APPROVAL_TOKEN_OUTPUT_PREFIX,Ne as AWS_REGIONS_METADATA,Q as AccountTierSchema,a as BACKUP_VAULT_NAME,Tr as CLICKHOUSE_MIGRATION_SKIP_RE,Fe as ConnectionWireSchema,Xe as ConnectionsListResponseSchema,H as DANGEROUS_ENV_VARS,Te as DEFAULT_REGION,o as DNS_APEX,mr as EXPECTED_CH_SCHEMA_VERSION_ENV,_r as EXPECTED_SCHEMA_VERSION_ENV,Ar as EXPECTED_SCHEMA_VERSION_TOOL_ENV,pe as MAX_SECONDARY_REGIONS,Sr as MIGRATION_SNAPSHOT_NAME_PREFIX,Oe as OPT_IN_REGION_CODES,Nr as PRISMA_MIGRATION_DIR_RE,u as REGION_SHORT_CODES,or as RESERVED_APP_NAMES,tr as RESERVED_APP_NAME_MESSAGE,ne as RESOURCE_CATEGORIES,sr as SCHEMA_ADMIN_PASSWORD_ENV,Rr as SCHEMA_ADMIN_USER_ENV,Ie as SCOPE_VALUES,Me as SECRET_NAME_ERROR,xe as SECRET_NAME_PATTERN,le as SSM_COMPONENT_ERROR,de as SSM_COMPONENT_PATTERN,De as SSM_STANDARD_MAX_VALUE_BYTES,z as STRUCTURAL_ENVIRONMENTS,Ve as SecretNamespaceSchema,se as abbreviateRegion,p as accountConstructKey,oe as accountTier,Ze as buildAppConfigPath,Ue as buildNamespaceParts,he as buildParameterPath,T as capitalise,ie as categoriseResource,P as defaultConnectedAccountName,Be as deriveAllTargets,nr as deriveContentHashTag,We as deriveRegionsFromOrgConfig,ye as deriveTargets,ke as environmentOrTier,ee as environmentToTier,be as escapeDotEnvValue,F as filterDangerousEnvVars,c as findAccountNameCollision,Je as findBoundaryPath,we as findInfrastructurePaths,Ye as findTarget,x as findTrailingRegionShortCode,G as formatErrorString,je as generateTargetName,t as getDomainExportNames,te as getEnvironmentLabel,U as getErrorCode,D as getErrorMessage,h as getErrorStack,Se as getExpectedDuration,_e as getFriendlyResourceType,Ce as getRegionInfo,C as getSafeZoneName,O as hasAsciiStableConstructKey,V as hasErrorCode,_ as imageTagParameterName,er as inferContainerFromCandidates,w as isAccountStage,$ as isAccountTier,Qe as isInfrastructureFile,ve as isManageablePath,Er as isReservedAppName,k as mapSettledWithConcurrency,X as maskSensitiveOutput,l as normaliseError,fe as optInRegionWarning,Le as parseDotEnv,me as parseGitRemoteUrl,Ge as parseParameterPath,K as parseShellArgs,M as regionSuffixRejectionMessage,ce as regions,L as singleton,y as sleep,re as stageFromWireEnvironment,I as suffixedAccountName,ge as suggestRegionForTimezone,R as toKebab,m as toPascalCase,N as toScreamingSnake,s as toValidDatabaseName};
1
+ import{DNS_APEX as o,getDomainExportNames as t}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as a}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as _,TOKEN_STDERR_PREFIX as n}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as i}from"./infra/imageTags.js";import{toPascalCase as R,toKebab as m,toValidDatabaseName as N,toScreamingSnake as s,capitalise as O,getSafeZoneName as C,accountConstructKey as c,hasAsciiStableConstructKey as f}from"./naming/caseConversion.js";import{findAccountNameCollision as g}from"./naming/accountNameCollision.js";import{defaultConnectedAccountName as I,suffixedAccountName as M,REGION_SHORT_CODES as u,findTrailingRegionShortCode as x,regionSuffixRejectionMessage as D}from"./naming/connectedAccountName.js";import{normaliseError as l,getErrorMessage as U,hasErrorCode as h,getErrorCode as G,getErrorStack as V,formatErrorString as L}from"./errorUtils.js";import{singleton as H}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as b,filterDangerousEnvVars as K,maskSensitiveOutput as X,parseShellArgs as y,SCOPED_TOKEN_REGEX as W}from"./securityHelpers.js";import{sleep as Y}from"./async/sleep.js";import{mapSettledWithConcurrency as j}from"./async/concurrency.js";import{ACCOUNT_STAGES_WITH_ROOT as Z,STRUCTURAL_ENVIRONMENTS as q,ACCOUNT_STAGES as w,ACCOUNT_STAGE_LABELS as J,isAccountStage as Q,ACCOUNT_TIERS as $,AccountTierSchema as ee,isAccountTier as re,environmentToTier as oe,stageFromWireEnvironment as te,accountTier as Ee,getEnvironmentLabel as ae,ACCOUNT_ROLES as Se}from"./environments.js";import{RESOURCE_CATEGORIES as ne,categoriseResource as Ae,getExpectedDuration as ie,getFriendlyResourceType as Te}from"./resourceCategorisation.js";import{parseGitRemoteUrl as me}from"./repo/gitRemoteParser.js";import{abbreviateRegion as se,AWS_REGIONS_METADATA as Oe,DEFAULT_REGION as Ce,getRegionInfo as ce,MAX_SECONDARY_REGIONS as fe,OPT_IN_REGION_CODES as pe,optInRegionWarning as ge,regions as Pe,suggestRegionForTimezone as Ie}from"./infra/regions.js";import{SCOPE_VALUES as ue,MACHINE_ONLY_SCOPES as xe,USER_GRANTABLE_SCOPES as De}from"./infra/tokenScopes.js";import{SECRET_NAME_PATTERN as le,SECRET_NAME_ERROR as Ue,SSM_COMPONENT_PATTERN as he,SSM_COMPONENT_ERROR as Ge,SSM_STANDARD_MAX_VALUE_BYTES as Ve,SecretNamespaceSchema as Le,buildNamespaceParts as ve,buildParameterPath as He,parseParameterPath as Fe,isManageablePath as be,parseDotEnv as Ke,escapeDotEnvValue as Xe}from"./secrets.js";import{ConnectionWireSchema as We,ConnectionsListResponseSchema as Be}from"./infra/connectionsWire.js";import{deriveRegionsFromOrgConfig as ke,deriveTargets as je,deriveAllTargets as ze,environmentOrTier as Ze,findTarget as qe,generateTargetName as we}from"./targets.js";import{buildAppConfigPath as Qe}from"./repo/appPath.js";import{findInfrastructurePaths as er,findBoundaryPath as rr,isInfrastructureFile as or}from"./repo/findInfrastructurePaths.js";import{inferContainerFromCandidates as Er}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as Sr,RESERVED_APP_NAME_MESSAGE as _r,isReservedAppName as nr}from"./naming/reservedAppNames.js";import{deriveContentHashTag as ir,CONTENT_HASH_TAG_PATTERN as Tr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as mr,DeployModeSchema as Nr,IMAGE_TAG_PATTERN as sr,ImageTagSchema as Or,ServiceArtefactSchema as Cr,ServiceArtefactsSchema as cr,ARTEFACT_OUTPUT_FIELDS as fr,artefactOutputKey as pr}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as Pr,EXPECTED_SCHEMA_VERSION_ENV as Ir,EXPECTED_SCHEMA_VERSION_TOOL_ENV as Mr,EXPECTED_CH_SCHEMA_VERSION_ENV as ur,SCHEMA_ADMIN_USER_ENV as xr,SCHEMA_ADMIN_PASSWORD_ENV as Dr,PRISMA_MIGRATION_DIR_RE as dr,CLICKHOUSE_MIGRATION_SKIP_RE as lr}from"./migration/constants.js";export{Se as ACCOUNT_ROLES,w as ACCOUNT_STAGES,Z as ACCOUNT_STAGES_WITH_ROOT,J as ACCOUNT_STAGE_LABELS,$ as ACCOUNT_TIERS,_ as APPROVAL_TOKEN_OUTPUT_PREFIX,fr as ARTEFACT_OUTPUT_FIELDS,Oe as AWS_REGIONS_METADATA,ee as AccountTierSchema,a as BACKUP_VAULT_NAME,lr as CLICKHOUSE_MIGRATION_SKIP_RE,Tr as CONTENT_HASH_TAG_PATTERN,We as ConnectionWireSchema,Be as ConnectionsListResponseSchema,b as DANGEROUS_ENV_VARS,Ce as DEFAULT_REGION,mr as DEPLOY_MODES,o as DNS_APEX,Nr as DeployModeSchema,ur as EXPECTED_CH_SCHEMA_VERSION_ENV,Ir as EXPECTED_SCHEMA_VERSION_ENV,Mr as EXPECTED_SCHEMA_VERSION_TOOL_ENV,sr as IMAGE_TAG_PATTERN,Or as ImageTagSchema,xe as MACHINE_ONLY_SCOPES,fe as MAX_SECONDARY_REGIONS,Pr as MIGRATION_SNAPSHOT_NAME_PREFIX,pe as OPT_IN_REGION_CODES,dr as PRISMA_MIGRATION_DIR_RE,u as REGION_SHORT_CODES,Sr as RESERVED_APP_NAMES,_r as RESERVED_APP_NAME_MESSAGE,ne as RESOURCE_CATEGORIES,Dr as SCHEMA_ADMIN_PASSWORD_ENV,xr as SCHEMA_ADMIN_USER_ENV,W as SCOPED_TOKEN_REGEX,ue as SCOPE_VALUES,Ue as SECRET_NAME_ERROR,le as SECRET_NAME_PATTERN,Ge as SSM_COMPONENT_ERROR,he as SSM_COMPONENT_PATTERN,Ve as SSM_STANDARD_MAX_VALUE_BYTES,q as STRUCTURAL_ENVIRONMENTS,Le as SecretNamespaceSchema,Cr as ServiceArtefactSchema,cr as ServiceArtefactsSchema,n as TOKEN_STDERR_PREFIX,De as USER_GRANTABLE_SCOPES,se as abbreviateRegion,c as accountConstructKey,Ee as accountTier,pr as artefactOutputKey,Qe as buildAppConfigPath,ve as buildNamespaceParts,He as buildParameterPath,O as capitalise,Ae as categoriseResource,I as defaultConnectedAccountName,ze as deriveAllTargets,ir as deriveContentHashTag,ke as deriveRegionsFromOrgConfig,je as deriveTargets,Ze as environmentOrTier,oe as environmentToTier,Xe as escapeDotEnvValue,K as filterDangerousEnvVars,g as findAccountNameCollision,rr as findBoundaryPath,er as findInfrastructurePaths,qe as findTarget,x as findTrailingRegionShortCode,L as formatErrorString,we as generateTargetName,t as getDomainExportNames,ae as getEnvironmentLabel,G as getErrorCode,U as getErrorMessage,V as getErrorStack,ie as getExpectedDuration,Te as getFriendlyResourceType,ce as getRegionInfo,C as getSafeZoneName,f as hasAsciiStableConstructKey,h as hasErrorCode,i as imageTagParameterName,Er as inferContainerFromCandidates,Q as isAccountStage,re as isAccountTier,or as isInfrastructureFile,be as isManageablePath,nr as isReservedAppName,j as mapSettledWithConcurrency,X as maskSensitiveOutput,l as normaliseError,ge as optInRegionWarning,Ke as parseDotEnv,me as parseGitRemoteUrl,Fe as parseParameterPath,y as parseShellArgs,D as regionSuffixRejectionMessage,Pe as regions,H as singleton,Y as sleep,te as stageFromWireEnvironment,M as suffixedAccountName,Ie as suggestRegionForTimezone,m as toKebab,R as toPascalCase,s as toScreamingSnake,N as toValidDatabaseName};
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Shared deploy artefact contract — the single source of truth for the
3
+ * engine→consumer wire shapes that describe WHAT a deploy produced.
4
+ *
5
+ * Three coupled surfaces import from here so none can drift:
6
+ * - `@fjall/deploy-core` — emits `ServiceArtefact[]` on `DeployResult`
7
+ * and derives its per-service output keys via `artefactOutputKey`
8
+ * - `@fjall/cli` — `commandSchemas` re-exports `ImageTagSchema` for
9
+ * `--image-tag` validation
10
+ * - webapp worker — parses the per-service outputs and (Phase 1b)
11
+ * consumes `ServiceArtefact[]` for Release persistence
12
+ *
13
+ * The output-key contract (`artefactOutputKey`) reproduces the historical
14
+ * inline `${serviceName}TaskDefinition` / `${serviceName}ImageTag` / …
15
+ * template literals byte-identically; the regression pins in
16
+ * `util/src/__tests__/deployArtefacts.test.ts` freeze that wire format.
17
+ */
18
+ import { z } from "zod";
19
+ export declare const DEPLOY_MODES: readonly ["full", "code-only", "rollback", "restart"];
20
+ export declare const DeployModeSchema: z.ZodEnum<{
21
+ full: "full";
22
+ "code-only": "code-only";
23
+ rollback: "rollback";
24
+ restart: "restart";
25
+ }>;
26
+ export type DeployMode = z.infer<typeof DeployModeSchema>;
27
+ /**
28
+ * Single source for image-tag validation (previously declared 3×: CLI
29
+ * commandSchemas inline regex, webapp IMAGE_TAG_PATTERN, deploymentHelpers
30
+ * inline copy). Matches Docker tag grammar as fjall constrains it.
31
+ */
32
+ export declare const IMAGE_TAG_PATTERN: RegExp;
33
+ export declare const ImageTagSchema: z.ZodString;
34
+ export type ImageTag = z.infer<typeof ImageTagSchema>;
35
+ /**
36
+ * One rolled-out (or pushed) service image identity.
37
+ *
38
+ * `imageDigest` and `taskDefinitionArn` are optional for honesty, not
39
+ * convenience: the code-only rollout falls back to tag pinning when ECR
40
+ * digest resolution fails, and the full-deploy path resolves the live task
41
+ * definition best-effort AFTER CloudFormation has rolled the service —
42
+ * neither may invent placeholder values. `previousTaskDefinitionArn` exists
43
+ * only where an explicit RegisterTaskDefinition rollout captured it.
44
+ * `ecrRepositoryArn` is absent for non-ECR registries.
45
+ */
46
+ export declare const ServiceArtefactSchema: z.ZodObject<{
47
+ serviceName: z.ZodString;
48
+ imageTag: z.ZodString;
49
+ imageDigest: z.ZodOptional<z.ZodString>;
50
+ imageUri: z.ZodString;
51
+ ecrRepositoryArn: z.ZodOptional<z.ZodString>;
52
+ taskDefinitionArn: z.ZodOptional<z.ZodString>;
53
+ previousTaskDefinitionArn: z.ZodOptional<z.ZodString>;
54
+ }, z.core.$strict>;
55
+ export type ServiceArtefact = z.infer<typeof ServiceArtefactSchema>;
56
+ export declare const ServiceArtefactsSchema: z.ZodArray<z.ZodObject<{
57
+ serviceName: z.ZodString;
58
+ imageTag: z.ZodString;
59
+ imageDigest: z.ZodOptional<z.ZodString>;
60
+ imageUri: z.ZodString;
61
+ ecrRepositoryArn: z.ZodOptional<z.ZodString>;
62
+ taskDefinitionArn: z.ZodOptional<z.ZodString>;
63
+ previousTaskDefinitionArn: z.ZodOptional<z.ZodString>;
64
+ }, z.core.$strict>>;
65
+ export type ServiceArtefacts = z.infer<typeof ServiceArtefactsSchema>;
66
+ /**
67
+ * The six per-service output-key suffixes the deploy engine emits and the
68
+ * webapp worker parses (`webapp/scripts/deploymentJobHandler/imageRollout.ts`).
69
+ * Order matters only for readers; the VALUES are a wire contract.
70
+ */
71
+ export declare const ARTEFACT_OUTPUT_FIELDS: readonly ["TaskDefinition", "PreviousTaskDefinition", "ImageTag", "ImageUri", "EcrRepositoryArn", "ImageDigest"];
72
+ export type ArtefactOutputField = (typeof ARTEFACT_OUTPUT_FIELDS)[number];
73
+ /**
74
+ * Derive the per-service deploy output key — MUST stay byte-identical to the
75
+ * historical `${serviceName}${field}` template literals (the worker
76
+ * slices the `serviceName` back off the `TaskDefinition`-suffixed keys).
77
+ */
78
+ export declare function artefactOutputKey(serviceName: string, field: ArtefactOutputField): string;
@@ -0,0 +1 @@
1
+ import{z as t}from"zod";const r=["full","code-only","rollback","restart"],c=t.enum(r),n=/^[a-zA-Z0-9._-]+$/,o=t.string().min(1).max(128).regex(n),a=t.object({serviceName:t.string().min(1),imageTag:o,imageDigest:t.string().min(1).optional(),imageUri:t.string().min(1),ecrRepositoryArn:t.string().min(1).optional(),taskDefinitionArn:t.string().min(1).optional(),previousTaskDefinitionArn:t.string().min(1).optional()}).strict(),m=t.array(a),g=["TaskDefinition","PreviousTaskDefinition","ImageTag","ImageUri","EcrRepositoryArn","ImageDigest"];function p(e,i){return`${e}${i}`}export{g as ARTEFACT_OUTPUT_FIELDS,r as DEPLOY_MODES,c as DeployModeSchema,n as IMAGE_TAG_PATTERN,o as ImageTagSchema,a as ServiceArtefactSchema,m as ServiceArtefactsSchema,p as artefactOutputKey};
@@ -31,4 +31,11 @@ export type Result<T, E = Error> = {
31
31
  success: false;
32
32
  error: E;
33
33
  };
34
+ /**
35
+ * Matches a tag synthesised by {@link deriveContentHashTag} — coupled to its
36
+ * `${stem}-sha-${prefix}` output shape (code-quality.md § "Coupled values").
37
+ * Consumers selecting a content-hash tag from a live tag list (e.g. the
38
+ * restart orchestrator) MUST use this rather than re-encoding the shape.
39
+ */
40
+ export declare const CONTENT_HASH_TAG_PATTERN: RegExp;
34
41
  export declare function deriveContentHashTag(digest: string, serviceName: string, target?: string): Result<string, Error>;
@@ -1 +1 @@
1
- function d(e){return{success:!0,data:e}}function t(e){return{success:!1,error:e}}const a="sha256:",o=12;function f(e,u,i){if(!e.startsWith(a))return t(new Error(`expected sha256:... digest, got ${e.slice(0,32)}`));const r=e.slice(a.length);if(r.length<o)return t(new Error(`digest hex payload too short (need >=${o} chars, got ${r.length})`));const n=u.trim();if(n==="")return t(new Error("serviceName must be a non-empty string"));let s;if(i!==void 0){const c=i.trim();if(c==="")return t(new Error("target, when supplied, must be a non-empty string; omit the argument instead"));s=c.toLowerCase()}const h=r.slice(0,o).toLowerCase(),m=s!==void 0?`${n.toLowerCase()}-${s}`:n.toLowerCase();return d(`${m}-sha-${h}`)}export{f as deriveContentHashTag};
1
+ function m(e){return{success:!0,data:e}}function t(e){return{success:!1,error:e}}const c="sha256:",r=12,d=new RegExp(`-sha-[0-9a-f]{${r}}$`);function g(e,u,i){if(!e.startsWith(c))return t(new Error(`expected sha256:... digest, got ${e.slice(0,32)}`));const n=e.slice(c.length);if(n.length<r)return t(new Error(`digest hex payload too short (need >=${r} chars, got ${n.length})`));const s=u.trim();if(s==="")return t(new Error("serviceName must be a non-empty string"));let o;if(i!==void 0){const a=i.trim();if(a==="")return t(new Error("target, when supplied, must be a non-empty string; omit the argument instead"));o=a.toLowerCase()}const h=n.slice(0,r).toLowerCase(),f=o!==void 0?`${s.toLowerCase()}-${o}`:s.toLowerCase();return m(`${f}-sha-${h}`)}export{d as CONTENT_HASH_TAG_PATTERN,g as deriveContentHashTag};
@@ -7,5 +7,9 @@
7
7
  * a scope the CLI did not know how to request, or vice versa. Both
8
8
  * consumers now import `SCOPE_VALUES` / `TokenScope` from here.
9
9
  */
10
- export declare const SCOPE_VALUES: readonly ["read", "write", "deploy", "secrets:read", "secrets:write", "destroy", "admin", "applications:read", "applications:deploy"];
10
+ export declare const SCOPE_VALUES: readonly ["read", "write", "deploy", "secrets:read", "secrets:write", "destroy", "admin", "applications:read", "applications:deploy", "deploy:oidc:mint"];
11
11
  export type TokenScope = (typeof SCOPE_VALUES)[number];
12
+ /** Scopes only a machine principal may hold — never a user-minted token. */
13
+ export declare const MACHINE_ONLY_SCOPES: readonly TokenScope[];
14
+ /** Scopes a user `*` grant expands to (excludes `admin` + machine-only). */
15
+ export declare const USER_GRANTABLE_SCOPES: readonly TokenScope[];
@@ -1 +1 @@
1
- const e=["read","write","deploy","secrets:read","secrets:write","destroy","admin","applications:read","applications:deploy"];export{e as SCOPE_VALUES};
1
+ const r=["read","write","deploy","secrets:read","secrets:write","destroy","admin","applications:read","applications:deploy","deploy:oidc:mint"],s={read:"user",write:"user",deploy:"user","secrets:read":"user","secrets:write":"user",destroy:"user",admin:"admin","applications:read":"user","applications:deploy":"user","deploy:oidc:mint":"machine"},t=r.filter(e=>s[e]==="machine"),i=r.filter(e=>s[e]==="user");export{t as MACHINE_ONLY_SCOPES,r as SCOPE_VALUES,i as USER_GRANTABLE_SCOPES};
@@ -12,6 +12,15 @@
12
12
  * customer-owned application sharing that name would collide structurally
13
13
  * with the organisation entry under `[container/]fjall/fjall/infrastructure.ts`.
14
14
  *
15
+ * `"organisation"` / `"platform"` / `"account"` are the org-tier deploy
16
+ * targets (deploy-core `ORGANISATION_TYPES` — the coupled SSoT; a deploy-core
17
+ * parity test pins the subset relation, since util sits below deploy-core and
18
+ * cannot import it). Deploy consumers classify a deploy as org-level from the
19
+ * target NAME alone (`fjall deploy account`, the worker's org-level gate), so
20
+ * an application sharing one of these names would be mis-classified as an
21
+ * org-tier deploy — bypassing the app-scoped session policy and injecting org
22
+ * identity into synth.
23
+ *
15
24
  * **Boundary with `isReservedSlug`** — `webapp/app/.server/utils/reservedSlugs.ts`
16
25
  * guards organisation slugs (URL-scoped, webapp-only). This list is
17
26
  * application-scoped and ships from `@fjall/util` for cross-system reuse
@@ -21,14 +30,14 @@
21
30
  * before testing, so `"Fjall"`, `"FJALL"`, and `"fjALL"` all reject
22
31
  * identically.
23
32
  */
24
- export declare const RESERVED_APP_NAMES: readonly ["fjall"];
33
+ export declare const RESERVED_APP_NAMES: readonly ["fjall", "organisation", "platform", "account"];
25
34
  export type ReservedAppName = (typeof RESERVED_APP_NAMES)[number];
26
35
  /**
27
36
  * Canonical user-facing rejection message for a reserved application name.
28
37
  * Shared by every create surface (the CLI `CreateApplicationSchema`, the webapp
29
38
  * create route, the webapp scaffold schema) so the wording cannot drift.
30
39
  */
31
- export declare const RESERVED_APP_NAME_MESSAGE = "The name 'fjall' is reserved for organisation-tier configuration.";
40
+ export declare const RESERVED_APP_NAME_MESSAGE = "This application name is reserved for Fjall's organisation-tier infrastructure.";
32
41
  /**
33
42
  * Case-insensitive membership check. The canonical entrypoint — consumers
34
43
  * MUST route through this helper rather than calling `.includes(name.toLowerCase())`
@@ -1 +1 @@
1
- const o=["fjall"],r="The name 'fjall' is reserved for organisation-tier configuration.";function n(e){return o.includes(e.toLowerCase())}export{o as RESERVED_APP_NAMES,r as RESERVED_APP_NAME_MESSAGE,n as isReservedAppName};
1
+ const r=["fjall","organisation","platform","account"],o="This application name is reserved for Fjall's organisation-tier infrastructure.";function t(e){return r.includes(e.toLowerCase())}export{r as RESERVED_APP_NAMES,o as RESERVED_APP_NAME_MESSAGE,t as isReservedAppName};
@@ -20,9 +20,12 @@ export declare const DANGEROUS_ENV_VARS: Set<string>;
20
20
  */
21
21
  export declare function filterDangerousEnvVars(env: Record<string, string | undefined>): Record<string, string | undefined>;
22
22
  /**
23
- * Matches the FULL scoped agent token: prefix (16 base32) + separator (.) + secret (40 base32).
23
+ * Matches the FULL agent token: prefix (16 base32) + separator (.) + secret (40 base32),
24
+ * for both scoped-family kinds — `fjall_ak_` (scoped) and `fjall_dk_` (deploy).
24
25
  * Base32 alphabet: A-Z2-7. The `.` separator MUST be included or the secret leaks unmasked.
25
- * Single source of truth — all masking call sites import this.
26
+ * Single source of truth — all masking call sites import this. Coupled to the prefix
27
+ * SSoT `AGENT_TOKEN_PREFIXES` at webapp/app/.server/models/auth/agent-token-kind.ts —
28
+ * a new token kind there MUST extend this alternation.
26
29
  *
27
30
  * Public form has NO `g` flag — `.test()` consumers must not share `lastIndex` across calls.
28
31
  * The global form lives in `SCOPED_TOKEN_GLOBAL_REGEX` below for the iteration site.
@@ -33,7 +36,8 @@ export declare const SCOPED_TOKEN_REGEX: RegExp;
33
36
  * Patterns: postgres://user:pass@host, password=xxx, secret=xxx, apikey=xxx,
34
37
  * GitHub tokens (ghu_/ghs_/ghp_/gho_/github_pat_), bare AWS access-key IDs
35
38
  * (AKIA-prefixed and ASIA-prefixed), AWS secret keys (env, INI, and JSON key
36
- * spellings), session tokens, ARN account IDs, scoped agent tokens.
39
+ * spellings), session tokens, ARN account IDs, agent tokens (`fjall_ak_`
40
+ * scoped, `fjall_dk_` deploy).
37
41
  *
38
42
  * Single source of truth — consumer loggers (CLI, worker, webapp) MUST
39
43
  * NOT re-implement these patterns inline. See
@@ -1 +1 @@
1
- const A=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 l(e){return Object.fromEntries(Object.entries(e).filter(([r])=>!A.has(r.toUpperCase())))}const i=/fjall_ak_[A-Z2-7]{16}\.[A-Z2-7]{40}/,c=/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\s*=\s*["']?|SecretAccessKey[=:]\s*|"(aws)?secretAccessKey":\s*"|"aws_secret_access_key":\s*")[A-Za-z0-9/+=]{40,}/gi,"***").replace(/(arn:aws[^:]*:[^:]*:[^:]*:)(\d{12})(:[^\s]*)/g,"$1***$3").replace(/(?<="(aws)?sessionToken":\s*"|"aws_session_token":\s*")[^"]+/gi,"***").replace(/(?<=aws_session_token\s*[=:]\s*["']?|SessionToken[=:]\s*["']?)[^\s"']+/gi,"***").replace(/(?<="(internal[Aa]piKey|fjallCallbackToken)":\s*")[^"]+/g,"***").replace(c,"fjall_ak_***")}function D(e){const r=[];let s="",E=!1,_=!1,n=!1,t=!1;for(const a of e){if(n){s+=a,n=!1;continue}if(a==="\\"&&!E){n=!0;continue}if(a==="'"&&!_){E=!E,t=!0;continue}if(a==='"'&&!E){_=!_,t=!0;continue}if(a===" "&&!E&&!_){(s||t)&&(r.push(s),s="",t=!1);continue}s+=a}if(E||_)throw new Error(`Unbalanced ${E?"single":"double"} quote in command: ${e.slice(0,80)}`);if(n)throw new Error(`Trailing backslash in command: ${e.slice(0,80)}`);return(s||t)&&r.push(s),r}export{A as DANGEROUS_ENV_VARS,i as SCOPED_TOKEN_REGEX,l as filterDangerousEnvVars,o as maskSensitiveOutput,D as parseShellArgs};
1
+ const A=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(([r])=>!A.has(r.toUpperCase())))}const l=/fjall_(?:ak|dk)_[A-Z2-7]{16}\.[A-Z2-7]{40}/,c=/(fjall_(?:ak|dk)_)[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\s*=\s*["']?|SecretAccessKey[=:]\s*|"(aws)?secretAccessKey":\s*"|"aws_secret_access_key":\s*")[A-Za-z0-9/+=]{40,}/gi,"***").replace(/(arn:aws[^:]*:[^:]*:[^:]*:)(\d{12})(:[^\s]*)/g,"$1***$3").replace(/(?<="(aws)?sessionToken":\s*"|"aws_session_token":\s*")[^"]+/gi,"***").replace(/(?<=aws_session_token\s*[=:]\s*["']?|SessionToken[=:]\s*["']?)[^\s"']+/gi,"***").replace(/(?<="(internal[Aa]piKey|fjallCallbackToken)":\s*")[^"]+/g,"***").replace(c,"$1***")}function D(e){const r=[];let s="",E=!1,t=!1,n=!1,_=!1;for(const a of e){if(n){s+=a,n=!1;continue}if(a==="\\"&&!E){n=!0;continue}if(a==="'"&&!t){E=!E,_=!0;continue}if(a==='"'&&!E){t=!t,_=!0;continue}if(a===" "&&!E&&!t){(s||_)&&(r.push(s),s="",_=!1);continue}s+=a}if(E||t)throw new Error(`Unbalanced ${E?"single":"double"} quote in command: ${e.slice(0,80)}`);if(n)throw new Error(`Trailing backslash in command: ${e.slice(0,80)}`);return(s||_)&&r.push(s),r}export{A as DANGEROUS_ENV_VARS,l as SCOPED_TOKEN_REGEX,i as filterDangerousEnvVars,o as maskSensitiveOutput,D as parseShellArgs};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "2.23.1",
3
+ "version": "2.25.0",
4
4
  "description": "Common utility methods",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -42,6 +42,10 @@
42
42
  "types": "./dist/fsHelpers.d.ts",
43
43
  "default": "./dist/fsHelpers.js"
44
44
  },
45
+ "./cdkTmpdirCleanup": {
46
+ "types": "./dist/cdkTmpdirCleanup.d.ts",
47
+ "default": "./dist/cdkTmpdirCleanup.js"
48
+ },
45
49
  "./migration": {
46
50
  "types": "./dist/migration/index.d.ts",
47
51
  "default": "./dist/migration/index.js"
@@ -121,5 +125,5 @@
121
125
  "engines": {
122
126
  "node": ">=22.0.0"
123
127
  },
124
- "gitHead": "749133c6c5cfe24a09a401869f2193c7d177a324"
128
+ "gitHead": "7c1a329184064aefa557c2c09de0965c4f8cd4fb"
125
129
  }