@fjall/util 2.25.0 → 2.29.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 +1 -1
- package/dist/aws/CloudFormationFailureAnalyser.d.ts +27 -1
- package/dist/aws/CloudFormationFailureAnalyser.js +1 -1
- package/dist/aws/cloudformationTypes.d.ts +6 -0
- package/dist/aws/driftSuspects.d.ts +54 -0
- package/dist/aws/driftSuspects.js +1 -0
- package/dist/aws/index.d.ts +1 -0
- package/dist/aws/index.js +1 -1
- package/dist/aws/maskFailureAnalysis.js +1 -1
- package/dist/buildConcurrency.d.ts +38 -0
- package/dist/buildConcurrency.js +1 -0
- package/dist/cfn/physicalNameProperties.d.ts +13 -0
- package/dist/cfn/physicalNameProperties.js +1 -0
- package/dist/docker/cacheRepository.d.ts +26 -0
- package/dist/docker/cacheRepository.js +1 -0
- package/dist/docker/dockerCliConstants.d.ts +1 -1
- package/dist/docker/dockerCliConstants.js +1 -1
- package/dist/docker/index.d.ts +1 -0
- package/dist/docker/index.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/naming/reservedAppNames.d.ts +27 -0
- package/dist/naming/reservedAppNames.js +1 -1
- package/package.json +6 -2
package/dist/.minified
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
79 files minified at 2026-07-13T22:21:40.141Z
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ResourceEvent } from "./cloudformationTypes.js";
|
|
2
|
+
import { type DriftSuspectEvent } from "./driftSuspects.js";
|
|
2
3
|
export interface RootCause {
|
|
3
4
|
resource: ResourceEvent;
|
|
4
5
|
reason: string;
|
|
@@ -12,6 +13,13 @@ export interface FailureAnalysis {
|
|
|
12
13
|
summary: string;
|
|
13
14
|
remediation: string[];
|
|
14
15
|
errorPattern?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Resources whose failure carries the out-of-band-deletion shape (Class 1
|
|
18
|
+
* drift): CloudFormation still tracks them but the service reported
|
|
19
|
+
* NotFound. Suspects only — confirmation requires the deploy-core drift
|
|
20
|
+
* probe. Absent when no failure event matches the NotFound anchors.
|
|
21
|
+
*/
|
|
22
|
+
driftSuspects?: DriftSuspectEvent[];
|
|
15
23
|
}
|
|
16
24
|
/**
|
|
17
25
|
* CloudFormationFailureAnalyser provides intelligent analysis of deployment failures
|
|
@@ -19,7 +27,25 @@ export interface FailureAnalysis {
|
|
|
19
27
|
*/
|
|
20
28
|
export declare class CloudFormationFailureAnalyser {
|
|
21
29
|
private knownErrorPatterns;
|
|
22
|
-
|
|
30
|
+
/**
|
|
31
|
+
* `stackName` opts the drift scan into current-operation bounding: the
|
|
32
|
+
* monitor's event history is seeded with the stack's FULL retained event
|
|
33
|
+
* history (~90 days), so an unbounded scan would resurrect suspects from
|
|
34
|
+
* long-past operations that were since cured. Callers whose history is
|
|
35
|
+
* already operation-scoped (callback-fed collections) omit it.
|
|
36
|
+
*/
|
|
37
|
+
analyseFailure(eventHistory: Map<string, ResourceEvent[]>, stackName?: string): FailureAnalysis | null;
|
|
38
|
+
/**
|
|
39
|
+
* Scans EVERY failed event, not failedResources: a wedged resource's
|
|
40
|
+
* UPDATE_FAILED is superseded by its rollback event, so latest-per-resource
|
|
41
|
+
* semantics would drop exactly the wedge. When `stackName` is given, the
|
|
42
|
+
* scan is bounded to events at/after the current operation's opening event;
|
|
43
|
+
* if no opening event is visible the scan yields nothing rather than risk
|
|
44
|
+
* classifying a stale prior-operation failure (fail-safe: a missed hint is
|
|
45
|
+
* recoverable via `fjall drift detect`, a stale suspect self-reinforces
|
|
46
|
+
* through the journal).
|
|
47
|
+
*/
|
|
48
|
+
private classifyDriftSuspects;
|
|
23
49
|
private findFailedResources;
|
|
24
50
|
private findRootCause;
|
|
25
51
|
private categoriseError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
import{classifyDriftSuspectEvents as c,findCurrentOperationStart as d}from"./driftSuspects.js";class f{knownErrorPatterns=[{pattern:/AccessDenied|UnauthorizedOperation|Forbidden/i,category:"permissions",remediation:["Check IAM permissions for the deployment role","Ensure the role has necessary CloudFormation permissions","Verify service-linked roles are created if needed"]},{pattern:/Invalid.*Parameter|ValidationError|Invalid.*Value/i,category:"validation",remediation:["Review parameter values in your CDK code","Check for typos in resource names or ARNs","Ensure all required parameters are provided"]},{pattern:/Limit.*Exceeded|Quota.*Exceeded|Maximum.*reached/i,category:"limit",remediation:["Check AWS service quotas in the Service Quotas console","Request a quota increase if needed","Consider using a different region with available capacity"]},{pattern:/Timeout|Connection.*refused|Network.*unreachable/i,category:"network",remediation:["Check network connectivity and VPC settings","Verify security groups and NACLs","Ensure endpoints are accessible"]},{pattern:/already exists|Duplicate|ConflictException/i,category:"validation",remediation:["Resource with this name already exists","Consider using a different name or deleting the existing resource","Check if you are deploying to the correct account/region"]},{pattern:/Role.*not.*found|Role.*does.*not.*exist/i,category:"dependency",remediation:["Ensure IAM roles are created before dependent resources","Check role names and ARNs are correct","Verify cross-stack references are properly configured"]}];analyseFailure(e,t){const r=this.findFailedResources(e);if(r.length===0)return null;const s=this.findRootCause(r,e),n=this.buildDependencyChain(s.resource,r),i=this.classifyDriftSuspects(e,t),o=this.generateRemediation(s);i.length>0&&o.unshift("One or more resources CloudFormation still tracks appear to have been deleted outside CloudFormation","Run 'fjall drift detect' to confirm the deletion; confirmed deletions are remediated with 'fjall drift repair'");const a=this.generateSummary(s,r);return{rootCause:s,affectedResources:r,dependencyChain:n,summary:a,remediation:o,errorPattern:s.category,...i.length>0?{driftSuspects:i}:{}}}classifyDriftSuspects(e,t){const r=t!==void 0?d(e.get(t)??[],t):null;if(t!==void 0&&r===null)return[];const s=[];for(const n of e.values())for(const i of n)this.isFailedStatus(i.status)&&(r!==null&&i.timestamp.getTime()<r.getTime()||s.push(i));return c(s)}findFailedResources(e){const t=[];for(const[r,s]of e){const n=s[s.length-1];n&&this.isFailedStatus(n.status)&&t.push(n)}return t.sort((r,s)=>r.timestamp.getTime()-s.timestamp.getTime())}findRootCause(e,t){if(e.length===0)return{resource:{logicalId:"Unknown",resourceType:"Unknown",status:"FAILED",timestamp:new Date},reason:"No failed resources found",category:"unknown",isDirectCause:!1};const r=e[0],s=this.categoriseError(r.statusReason||""),n=this.isDirectCause(r,t);return{resource:r,reason:r.statusReason||"Unknown error",category:s,isDirectCause:n}}categoriseError(e){for(const t of this.knownErrorPatterns)if(t.pattern.test(e))return t.category;return"unknown"}isDirectCause(e,t){const r=e.statusReason||"";return r.includes("depends on")||r.includes("referenced by")||r.includes("required by")?!1:!(t.get(e.logicalId)||[]).some(i=>i.status.includes("COMPLETE")&&!i.status.includes("ROLLBACK"))}buildDependencyChain(e,t){const r=[];r.push(`${e.logicalId} (${e.resourceType}) - ROOT CAUSE`);for(const s of t)s.logicalId!==e.logicalId&&((s.statusReason||"").toLowerCase().includes(e.logicalId.toLowerCase())?r.push(` \u2192 ${s.logicalId} (${s.resourceType}) - Failed due to ${e.logicalId}`):r.push(` \u2192 ${s.logicalId} (${s.resourceType})`));return r}generateRemediation(e){const t=[];for(const r of this.knownErrorPatterns)if(r.category===e.category){t.push(...r.remediation);break}return e.resource.resourceType.includes("IAM")?t.push("Review IAM policies and trust relationships"):e.resource.resourceType.includes("Lambda")?t.push("Check Lambda function configuration and runtime"):e.resource.resourceType.includes("ECS")&&t.push("Verify ECS task definition and container configuration"),t.length===0&&t.push("Review the CloudFormation console for detailed error messages","Check the resource configuration in your CDK code","Ensure all dependencies are properly defined"),t}generateSummary(e,t){const r=this.simplifyResourceType(e.resource.resourceType),s=t.length;let n=`Deployment failed: ${r} "${e.resource.logicalId}" `;switch(e.category){case"permissions":n+="failed due to insufficient permissions";break;case"validation":n+="failed validation";break;case"dependency":n+="has missing or invalid dependencies";break;case"limit":n+="exceeded AWS service limits";break;case"network":n+="encountered network issues";break;default:n+="failed to create"}return s>1&&(n+=` (${s-1} dependent resources also failed)`),n}simplifyResourceType(e){return e.replace("AWS::","").replace("::"," ")}isFailedStatus(e){return e.includes("FAILED")}}export{f as CloudFormationFailureAnalyser};
|
|
@@ -13,5 +13,11 @@ export interface ResourceEvent {
|
|
|
13
13
|
group?: string;
|
|
14
14
|
/** CDK construct path (e.g., "/Account/CloudTrail/trail/Resource"). */
|
|
15
15
|
constructPath?: string;
|
|
16
|
+
/**
|
|
17
|
+
* CloudFormation ClientRequestToken for the operation that emitted this event
|
|
18
|
+
* (§5.9 capture-not-stamp). Lets a reconciler correlate an orphaned CFN
|
|
19
|
+
* operation back to its deployment row. Absent on synthetic/initial events.
|
|
20
|
+
*/
|
|
21
|
+
clientRequestToken?: string;
|
|
16
22
|
}
|
|
17
23
|
export declare function isResourceEvent(event: unknown): event is ResourceEvent;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class 1 drift classification — out-of-band deletion suspects.
|
|
3
|
+
*
|
|
4
|
+
* A resource CloudFormation still tracks but which was deleted outside
|
|
5
|
+
* CloudFormation wedges every subsequent update: the service handler returns
|
|
6
|
+
* NotFound and the stack rolls back (the BusinessContinuity CMK incident,
|
|
7
|
+
* account 913524923178). The patterns here are derived from the Phase 0
|
|
8
|
+
* empirical fixtures (`fjall/deploy-core/src/orchestration/drift/__tests__/
|
|
9
|
+
* fixtures/bc-stack-events.json`, captured 2026-07-07): the stable anchors are
|
|
10
|
+
* the registry handler contract marker `HandlerErrorCode: NotFound` and the
|
|
11
|
+
* service message shape `does not exist (Service: …`.
|
|
12
|
+
*
|
|
13
|
+
* Classification is SUSPECTS ONLY — never a confirmed verdict. Confirmation
|
|
14
|
+
* requires a direct per-type probe (deploy-core `driftProbe.ts`); a suspect
|
|
15
|
+
* that cannot be probed stays UNCONFIRMED and remediation is refused
|
|
16
|
+
* (fail-closed: never surgery on a resource not proven dead).
|
|
17
|
+
*/
|
|
18
|
+
import type { ResourceEvent } from "./cloudformationTypes.js";
|
|
19
|
+
/**
|
|
20
|
+
* A resource whose failure event carries the out-of-band-deletion shape.
|
|
21
|
+
* `statusReason` is raw here — the analyser's `maskFailureAnalysis` boundary
|
|
22
|
+
* (or the sink) masks before display/persistence.
|
|
23
|
+
*/
|
|
24
|
+
export interface DriftSuspectEvent {
|
|
25
|
+
logicalId: string;
|
|
26
|
+
resourceType: string;
|
|
27
|
+
physicalId?: string;
|
|
28
|
+
/** The failed status that carried the NotFound shape (e.g. UPDATE_FAILED). */
|
|
29
|
+
failedStatus: string;
|
|
30
|
+
statusReason: string;
|
|
31
|
+
}
|
|
32
|
+
/** True when a failure reason carries the out-of-band-deletion shape. */
|
|
33
|
+
export declare function isDriftSuspectReason(statusReason: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* True for the stack-level event that opens a CloudFormation operation —
|
|
36
|
+
* the shared boundary for "current operation only" scans (the deploy-core
|
|
37
|
+
* last-operation event walk and the failure analyser's drift scan).
|
|
38
|
+
*/
|
|
39
|
+
export declare function isOperationOpeningEvent(event: ResourceEvent, stackName: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Timestamp of the most recent operation-opening event for `stackName`, or
|
|
42
|
+
* null when none is visible. Server-clock consistent with event timestamps,
|
|
43
|
+
* so callers can bound scans without local-clock skew.
|
|
44
|
+
*/
|
|
45
|
+
export declare function findCurrentOperationStart(events: readonly ResourceEvent[], stackName: string): Date | null;
|
|
46
|
+
/**
|
|
47
|
+
* Extract out-of-band-deletion suspects from failure events. Callers pass
|
|
48
|
+
* EVERY failed event in the operation, not just each resource's latest — a
|
|
49
|
+
* wedged resource's UPDATE_FAILED is typically superseded by a later
|
|
50
|
+
* UPDATE_ROLLBACK_* event, so latest-event-per-resource semantics would drop
|
|
51
|
+
* exactly the suspects this classifier exists to find. Deduplicated by
|
|
52
|
+
* logicalId (first match wins).
|
|
53
|
+
*/
|
|
54
|
+
export declare function classifyDriftSuspectEvents(events: readonly ResourceEvent[]): DriftSuspectEvent[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=new Set(["UPDATE_FAILED","DELETE_FAILED"]),i=[/HandlerErrorCode:\s*NotFound\b/,/does not exist \(Service:/i,/\b(?:ResourceNotFoundException|NotFoundException|NoSuchBucket|NoSuchEntity)\b/],c=/Resource (?:creation|update) cancelled/i;function u(e){return c.test(e)?!1:i.some(s=>s.test(e))}const a="AWS::CloudFormation::Stack",r=new Set(["CREATE_IN_PROGRESS","UPDATE_IN_PROGRESS","DELETE_IN_PROGRESS","IMPORT_IN_PROGRESS"]),E="User Initiated";function S(e,s){return e.resourceType===a&&e.logicalId===s&&r.has(e.status)&&e.statusReason!==void 0&&e.statusReason.includes(E)}function d(e,s){let n=null;for(const t of e)S(t,s)&&(n===null||t.timestamp.getTime()>n.getTime())&&(n=t.timestamp);return n}function R(e){const s=[],n=new Set;for(const t of e)n.has(t.logicalId)||o.has(t.status)&&(t.statusReason===void 0||t.statusReason===""||u(t.statusReason)&&(n.add(t.logicalId),s.push({logicalId:t.logicalId,resourceType:t.resourceType,...t.physicalId!==void 0&&t.physicalId!==""?{physicalId:t.physicalId}:{},failedStatus:t.status,statusReason:t.statusReason})));return s}export{R as classifyDriftSuspectEvents,d as findCurrentOperationStart,u as isDriftSuspectReason,S as isOperationOpeningEvent};
|
package/dist/aws/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { STACK_NOT_FOUND_PATTERN, CDK_NO_STACKS_MATCH, type ResourceEvent, isRes
|
|
|
3
3
|
export { type ResourceProgressCounts, countResourceProgress, formatElapsed } from "./deployProgress.js";
|
|
4
4
|
export { CloudFormationFailureAnalyser, type RootCause, type FailureAnalysis } from "./CloudFormationFailureAnalyser.js";
|
|
5
5
|
export { maskFailureAnalysis } from "./maskFailureAnalysis.js";
|
|
6
|
+
export { classifyDriftSuspectEvents, findCurrentOperationStart, isDriftSuspectReason, isOperationOpeningEvent, type DriftSuspectEvent } from "./driftSuspects.js";
|
|
6
7
|
export { IPAM_OPERATIONS_POOL_TAG_KEY, formatIpamPairTagValue } from "./ipamTags.js";
|
|
7
8
|
export { SDK_PRE_EMPTY_TAG_KEY } from "./infraTags.js";
|
|
8
9
|
export { ACCOUNT_MONITORING_ROLE_NAME } from "./monitoringRole.js";
|
package/dist/aws/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AWSError as e,NoRolesFoundError as
|
|
1
|
+
import{AWSError as e,NoRolesFoundError as t,InvalidCredentialsError as i,SSOTokenExpiredError as s,MissingRegionError as n,ProfileNotFoundError as E,CommandError as a,isAWSError as p,isNoRolesFoundError as _,isSSOUnauthorizedError as f}from"./errors.js";import{STACK_NOT_FOUND_PATTERN as O,CDK_NO_STACKS_MATCH as u,isResourceEvent as A}from"./cloudformationTypes.js";import{countResourceProgress as T,formatElapsed as l}from"./deployProgress.js";import{CloudFormationFailureAnalyser as d}from"./CloudFormationFailureAnalyser.js";import{maskFailureAnalysis as x}from"./maskFailureAnalysis.js";import{classifyDriftSuspectEvents as P,findCurrentOperationStart as F,isDriftSuspectReason as c,isOperationOpeningEvent as I}from"./driftSuspects.js";import{IPAM_OPERATIONS_POOL_TAG_KEY as M,formatIpamPairTagValue as g}from"./ipamTags.js";import{SDK_PRE_EMPTY_TAG_KEY as v}from"./infraTags.js";import{ACCOUNT_MONITORING_ROLE_NAME as G}from"./monitoringRole.js";export{G as ACCOUNT_MONITORING_ROLE_NAME,e as AWSError,u as CDK_NO_STACKS_MATCH,d as CloudFormationFailureAnalyser,a as CommandError,M as IPAM_OPERATIONS_POOL_TAG_KEY,i as InvalidCredentialsError,n as MissingRegionError,t as NoRolesFoundError,E as ProfileNotFoundError,v as SDK_PRE_EMPTY_TAG_KEY,s as SSOTokenExpiredError,O as STACK_NOT_FOUND_PATTERN,P as classifyDriftSuspectEvents,T as countResourceProgress,F as findCurrentOperationStart,l as formatElapsed,g as formatIpamPairTagValue,p as isAWSError,c as isDriftSuspectReason,_ as isNoRolesFoundError,I as isOperationOpeningEvent,A as isResourceEvent,f as isSSOUnauthorizedError,x as maskFailureAnalysis};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{maskSensitiveOutput as
|
|
1
|
+
import{maskSensitiveOutput as t}from"../securityHelpers.js";function r(e){return e.statusReason===void 0?e:{...e,statusReason:t(e.statusReason)}}function u(e){return{...e,statusReason:t(e.statusReason)}}function n(e){const s={...e.rootCause,reason:t(e.rootCause.reason),resource:r(e.rootCause.resource)};return{...e,rootCause:s,affectedResources:e.affectedResources.map(r),...e.driftSuspects!==void 0?{driftSuspects:e.driftSuspects.map(u)}:{}}}export{n as maskFailureAnalysis};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Result } from "./docker/result.js";
|
|
2
|
+
export interface RunWithBoundedConcurrencyOptions {
|
|
3
|
+
/**
|
|
4
|
+
* When true, stop issuing new jobs after the first failure. The orchestrator
|
|
5
|
+
* is responsible for owning the AbortController and signalling in-flight jobs.
|
|
6
|
+
*/
|
|
7
|
+
abortOnFirstFailure?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Optional abort signal: once aborted, the runner stops issuing NEW jobs.
|
|
10
|
+
* In-flight jobs are not cancelled — the orchestrator owns the
|
|
11
|
+
* AbortController and is responsible for signalling them (typically via a
|
|
12
|
+
* closure over the same signal inside each job factory).
|
|
13
|
+
*/
|
|
14
|
+
abortSignal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Run a list of async jobs with a bounded number in-flight at any tick.
|
|
18
|
+
*
|
|
19
|
+
* Returns results in INPUT order (job N's result lives at index N) regardless
|
|
20
|
+
* of completion order. Slots for jobs never issued (abort or first-failure
|
|
21
|
+
* stop) are left `undefined` — the return type is honest about the holes.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runWithBoundedConcurrency<T>(jobs: ReadonlyArray<() => Promise<T>>, concurrency: number, opts?: RunWithBoundedConcurrencyOptions): Promise<Array<Result<T, Error> | undefined>>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the per-orchestrator-run build concurrency from the
|
|
26
|
+
* `FJALL_BUILD_CONCURRENCY` environment variable, clamped to `[1, serviceCount]`.
|
|
27
|
+
*
|
|
28
|
+
* The env-var contract is shared by every build surface (`fjall build` via
|
|
29
|
+
* `@fjall/cli` and `fjall deploy` via `@fjall/deploy-core`) — this module is
|
|
30
|
+
* the single source so the two paths cannot drift.
|
|
31
|
+
*
|
|
32
|
+
* - Empty-string env values are rejected (per robustness-standards.md
|
|
33
|
+
* § "Environment Variable Truthy Checks").
|
|
34
|
+
* - Non-integer / non-positive values fall back to the default.
|
|
35
|
+
* - When `serviceCount === 0`, returns `1` (no jobs would be issued anyway).
|
|
36
|
+
* - The default is CPU-aware (see `defaultBuildConcurrency`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveBuildConcurrency(serviceCount: number): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import p from"os";import{success as y,failure as x}from"./docker/result.js";async function F(r,e,o={}){const t=r.length,i=new Array(t);if(t===0)return i;const l=Math.max(1,Math.min(e,t)),u=o.abortOnFirstFailure===!0;let c=0,s=!1;async function d(){for(;;){if(u&&s||o.abortSignal?.aborted===!0)return;const n=c;if(n>=t)return;c=n+1;const h=r[n];try{const a=await h();i[n]=y(a)}catch(a){const m=a instanceof Error?a:new Error(String(a));i[n]=x(m),u&&(s=!0)}}}const f=[];for(let n=0;n<l;n++)f.push(d());return await Promise.all(f),i}function w(r){const e=p.cpus().length;return Math.min(r,Math.max(2,Math.floor(e/2)))}function g(r){if(r<=0)return 1;const e=process.env.FJALL_BUILD_CONCURRENCY;let o=w(r);if(e!==void 0&&e!==""){const t=parseInt(e,10);Number.isInteger(t)&&t>0&&(o=t)}return Math.max(1,Math.min(o,r))}export{g as resolveBuildConcurrency,F as runWithBoundedConcurrency};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback map for pinned-name detection: CloudFormation resource types whose
|
|
3
|
+
* user-settable NAMING property cannot be derived from the registry schema's
|
|
4
|
+
* `primaryIdentifier` — the identifier is a generated attribute (ARN, URL, ID)
|
|
5
|
+
* that never appears in a template's Properties.
|
|
6
|
+
*
|
|
7
|
+
* Consulted by @fjall/deploy-core's pinned-name detector AFTER the
|
|
8
|
+
* primaryIdentifier derivation fails to yield a template property. Keep this
|
|
9
|
+
* map small: types whose primaryIdentifier IS the naming property
|
|
10
|
+
* (DBInstanceIdentifier, TableName, BucketName, RepositoryName, …) must NOT be
|
|
11
|
+
* added here.
|
|
12
|
+
*/
|
|
13
|
+
export declare const PHYSICAL_NAME_FALLBACK_PROPERTIES: Readonly<Record<string, string>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={"AWS::SecretsManager::Secret":"Name","AWS::SQS::Queue":"QueueName","AWS::SNS::Topic":"TopicName"};export{e as PHYSICAL_NAME_FALLBACK_PROPERTIES};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derivation for the buildx registry-cache ECR repository that sits beside an
|
|
3
|
+
* app's image repository. Both the `fjall build` provisioner
|
|
4
|
+
* (`@fjall/cli` EcrBuildOrchestrator) and the deploy-path provisioner
|
|
5
|
+
* (`@fjall/deploy-core` dockerBuildHelper) address the SAME physical repo, so
|
|
6
|
+
* the name derivation and the lifecycle retention live here — a re-implemented
|
|
7
|
+
* `\`${name}-cache\`` at either site is silent drift against a shared AWS
|
|
8
|
+
* resource (see code-quality.md § "Runtime resource names must match the CDK
|
|
9
|
+
* construct's derivation" — same rule, orchestrator↔orchestrator seam).
|
|
10
|
+
*/
|
|
11
|
+
/** `<repositoryName>-cache`; `repositoryName` is the kebab-case app repo name. */
|
|
12
|
+
export declare function buildCacheRepositoryName(repositoryName: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Days before untagged cache layers expire. Buildx registry-cache writes leave
|
|
15
|
+
* untagged image layers behind on every push; both provisioners apply the same
|
|
16
|
+
* lifecycle policy idempotently, so a differing value would flip-flop between
|
|
17
|
+
* `fjall build` and `fjall deploy` runs (last writer wins).
|
|
18
|
+
*/
|
|
19
|
+
export declare const CACHE_REPO_UNTAGGED_RETENTION_DAYS = 14;
|
|
20
|
+
/**
|
|
21
|
+
* The exact lifecycle-policy document both provisioners PUT on the cache
|
|
22
|
+
* repo. Shared so the stored policy text is byte-identical regardless of
|
|
23
|
+
* which path wrote last — a structurally-equal-but-differently-worded
|
|
24
|
+
* document would rewrite the policy on every alternating build/deploy run.
|
|
25
|
+
*/
|
|
26
|
+
export declare function untaggedLifecyclePolicyText(daysUntilExpiry: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(e){return`${e}-cache`}const n=14;function i(e){return JSON.stringify({rules:[{rulePriority:1,description:`Expire untagged images after ${e} days`,selection:{tagStatus:"untagged",countType:"sinceImagePushed",countUnit:"days",countNumber:e},action:{type:"expire"}}]})}export{n as CACHE_REPO_UNTAGGED_RETENTION_DAYS,t as buildCacheRepositoryName,i as untaggedLifecyclePolicyText};
|
|
@@ -8,7 +8,7 @@ export declare const DEFAULT_DOCKER_BIN = "docker";
|
|
|
8
8
|
export declare const SIGTERM_GRACE_MS = 5000;
|
|
9
9
|
export declare const STDERR_TAIL_LINES = 50;
|
|
10
10
|
export declare const STDERR_TAIL_LINE_MAX_CHARS = 2000;
|
|
11
|
-
export declare const DEFAULT_BUILD_TIMEOUT_MS =
|
|
11
|
+
export declare const DEFAULT_BUILD_TIMEOUT_MS = 1800000;
|
|
12
12
|
export declare const DEFAULT_PUSH_TIMEOUT_MS = 300000;
|
|
13
13
|
export declare const DEFAULT_PULL_TIMEOUT_MS = 300000;
|
|
14
14
|
export declare const DEFAULT_INSPECT_TIMEOUT_MS = 30000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const _="DockerCli",o="DockerCli.buildx",E="0.13.0",t="23.0.0",T=64,L="fjall",e="docker",I=5e3,r=50,O=2e3,D=
|
|
1
|
+
const _="DockerCli",o="DockerCli.buildx",E="0.13.0",t="23.0.0",T=64,L="fjall",e="docker",I=5e3,r=50,O=2e3,D=18e5,c=3e5,s=3e5,R=3e4,U=1e4;export{E as BUILDX_VERSION_FLOOR,L as DEFAULT_BUILDER_NAME,D as DEFAULT_BUILD_TIMEOUT_MS,U as DEFAULT_DAEMON_PROBE_TIMEOUT_MS,e as DEFAULT_DOCKER_BIN,R as DEFAULT_INSPECT_TIMEOUT_MS,s as DEFAULT_PULL_TIMEOUT_MS,c as DEFAULT_PUSH_TIMEOUT_MS,o as DOCKER_CLI_BUILDX_LOG_CATEGORY,_ as DOCKER_CLI_LOG_CATEGORY,t as ENGINE_VERSION_FLOOR,T as PrerequisiteMissingExitCode,I as SIGTERM_GRACE_MS,r as STDERR_TAIL_LINES,O as STDERR_TAIL_LINE_MAX_CHARS};
|
package/dist/docker/index.d.ts
CHANGED
|
@@ -11,3 +11,4 @@ export { projectBuildxResult, type DockerBuildResultLike, type ProjectBuildxResu
|
|
|
11
11
|
export { abortChildProcess } from "./abortHelpers.js";
|
|
12
12
|
export { DockerCli, type DockerCliLogger, type DockerCliOptions, type BuildxProgressEvent, type PushProgressEvent, type PushResult, type PullProgressEvent, type PullResult, type ImagetoolsInspect, type EcrLoginArgs, type BuildxCapabilities, type DaemonInfo } from "./DockerCli.js";
|
|
13
13
|
export { createEcrAuthSession, type EcrAuthSession, type CreateEcrAuthSessionParams } from "./ecrCredentialStore.js";
|
|
14
|
+
export { buildCacheRepositoryName, untaggedLifecyclePolicyText, CACHE_REPO_UNTAGGED_RETENTION_DAYS } from "./cacheRepository.js";
|
package/dist/docker/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isSuccess as o,isFailure as E,success as _,failure as i}from"./result.js";import{DOCKER_CLI_LOG_CATEGORY as
|
|
1
|
+
import{isSuccess as o,isFailure as E,success as _,failure as i}from"./result.js";import{DOCKER_CLI_LOG_CATEGORY as t,DOCKER_CLI_BUILDX_LOG_CATEGORY as a,BUILDX_VERSION_FLOOR as s,ENGINE_VERSION_FLOOR as T,PrerequisiteMissingExitCode as u,DEFAULT_BUILDER_NAME as A,DEFAULT_DOCKER_BIN as L,SIGTERM_GRACE_MS as R,STDERR_TAIL_LINES as D,DEFAULT_BUILD_TIMEOUT_MS as U,DEFAULT_PUSH_TIMEOUT_MS as c,DEFAULT_PULL_TIMEOUT_MS as I,DEFAULT_INSPECT_TIMEOUT_MS as O,DEFAULT_DAEMON_PROBE_TIMEOUT_MS as S}from"./dockerCliConstants.js";import{BuildxBuildArgsSchema as x,BuildxBuildResultSchema as m,DockerCliErrorKindSchema as B,DockerCliErrorSchema as C,isDockerCliErrorKind as p}from"./dockerCliSchemas.js";import{buildxArgvBuilder as M}from"./buildxArgvBuilder.js";import{evaluateBakeGuard as P,evaluateResolvedBuildArgValues as F,acknowledgedBuildArgKeys as G,BAKE_GUARD_EXPOSURE_CLAUSE as n}from"./bakeGuard.js";import{PUBLIC_BUILD_ARG_PREFIXES as K,isPublicBuildVarName as h,inferPublicBuildArgKeys as k}from"./buildArgInference.js";import{parseRawjsonLine as v}from"./rawjsonParser.js";import{rawjsonToVertexEvent as V}from"./rawjsonToVertexEvent.js";import{parseMetadataFile as j}from"./metadataFileParser.js";import{projectBuildxResult as Y}from"./projectBuildxResult.js";import{abortChildProcess as q}from"./abortHelpers.js";import{DockerCli as J}from"./DockerCli.js";import{createEcrAuthSession as W}from"./ecrCredentialStore.js";import{buildCacheRepositoryName as $,untaggedLifecyclePolicyText as ee,CACHE_REPO_UNTAGGED_RETENTION_DAYS as re}from"./cacheRepository.js";export{n as BAKE_GUARD_EXPOSURE_CLAUSE,s as BUILDX_VERSION_FLOOR,x as BuildxBuildArgsSchema,m as BuildxBuildResultSchema,re as CACHE_REPO_UNTAGGED_RETENTION_DAYS,A as DEFAULT_BUILDER_NAME,U as DEFAULT_BUILD_TIMEOUT_MS,S as DEFAULT_DAEMON_PROBE_TIMEOUT_MS,L as DEFAULT_DOCKER_BIN,O as DEFAULT_INSPECT_TIMEOUT_MS,I as DEFAULT_PULL_TIMEOUT_MS,c as DEFAULT_PUSH_TIMEOUT_MS,a as DOCKER_CLI_BUILDX_LOG_CATEGORY,t as DOCKER_CLI_LOG_CATEGORY,J as DockerCli,B as DockerCliErrorKindSchema,C as DockerCliErrorSchema,T as ENGINE_VERSION_FLOOR,K as PUBLIC_BUILD_ARG_PREFIXES,u as PrerequisiteMissingExitCode,R as SIGTERM_GRACE_MS,D as STDERR_TAIL_LINES,q as abortChildProcess,G as acknowledgedBuildArgKeys,$ as buildCacheRepositoryName,M as buildxArgvBuilder,W as createEcrAuthSession,P as evaluateBakeGuard,F as evaluateResolvedBuildArgValues,i as failure,k as inferPublicBuildArgKeys,p as isDockerCliErrorKind,E as isFailure,h as isPublicBuildVarName,o as isSuccess,j as parseMetadataFile,v as parseRawjsonLine,Y as projectBuildxResult,V as rawjsonToVertexEvent,_ as success,ee as untaggedLifecyclePolicyText};
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,8 @@ export { buildAppConfigPath } from "./repo/appPath.js";
|
|
|
22
22
|
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
|
-
export { RESERVED_APP_NAMES, type ReservedAppName, RESERVED_APP_NAME_MESSAGE, isReservedAppName } from "./naming/reservedAppNames.js";
|
|
25
|
+
export { RESERVED_APP_NAMES, type ReservedAppName, RESERVED_APP_NAME_MESSAGE, isReservedAppName, RESERVED_APP_NAME_SUFFIX, RESERVED_APP_NAME_SUFFIX_MESSAGE, hasReservedAppNameSuffix } from "./naming/reservedAppNames.js";
|
|
26
26
|
export { deriveContentHashTag, CONTENT_HASH_TAG_PATTERN } from "./infra/deriveContentHashTag.js";
|
|
27
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";
|
|
28
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";
|
|
29
|
+
export { PHYSICAL_NAME_FALLBACK_PROPERTIES } from "./cfn/physicalNameProperties.js";
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DNS_APEX as o,getDomainExportNames as
|
|
1
|
+
import{DNS_APEX as o,getDomainExportNames as E}from"./infra/domainExports.js";import{BACKUP_VAULT_NAME as a}from"./infra/backupVault.js";import{APPROVAL_TOKEN_OUTPUT_PREFIX as S,TOKEN_STDERR_PREFIX as A}from"./deploy/approvalTokenOutput.js";import{imageTagParameterName as i}from"./infra/imageTags.js";import{toPascalCase as T,toKebab as N,toValidDatabaseName as m,toScreamingSnake as s,capitalise as O,getSafeZoneName as C,accountConstructKey as c,hasAsciiStableConstructKey as f}from"./naming/caseConversion.js";import{findAccountNameCollision as P}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 V,getErrorCode as h,getErrorStack as G,formatErrorString as L}from"./errorUtils.js";import{singleton as F}from"./async/singleton.js";import{DANGEROUS_ENV_VARS as X,filterDangerousEnvVars as b,maskSensitiveOutput as K,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 Ee,accountTier as te,getEnvironmentLabel as ae,ACCOUNT_ROLES as _e}from"./environments.js";import{RESOURCE_CATEGORIES as Ae,categoriseResource as ne,getExpectedDuration as ie,getFriendlyResourceType as Re}from"./resourceCategorisation.js";import{parseGitRemoteUrl as Ne}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 Pe,regions as ge,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 Ve,SSM_COMPONENT_ERROR as he,SSM_STANDARD_MAX_VALUE_BYTES as Ge,SecretNamespaceSchema as Le,buildNamespaceParts as ve,buildParameterPath as Fe,parseParameterPath as He,isManageablePath as Xe,parseDotEnv as be,escapeDotEnvValue as Ke}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 tr}from"./repo/inferContainerFromCandidates.js";import{RESERVED_APP_NAMES as _r,RESERVED_APP_NAME_MESSAGE as Sr,isReservedAppName as Ar,RESERVED_APP_NAME_SUFFIX as nr,RESERVED_APP_NAME_SUFFIX_MESSAGE as ir,hasReservedAppNameSuffix as Rr}from"./naming/reservedAppNames.js";import{deriveContentHashTag as Nr,CONTENT_HASH_TAG_PATTERN as mr}from"./infra/deriveContentHashTag.js";import{DEPLOY_MODES as Or,DeployModeSchema as Cr,IMAGE_TAG_PATTERN as cr,ImageTagSchema as fr,ServiceArtefactSchema as pr,ServiceArtefactsSchema as Pr,ARTEFACT_OUTPUT_FIELDS as gr,artefactOutputKey as Ir}from"./infra/deployArtefacts.js";import{MIGRATION_SNAPSHOT_NAME_PREFIX as ur,EXPECTED_SCHEMA_VERSION_ENV as xr,EXPECTED_SCHEMA_VERSION_TOOL_ENV as Dr,EXPECTED_CH_SCHEMA_VERSION_ENV as dr,SCHEMA_ADMIN_USER_ENV as lr,SCHEMA_ADMIN_PASSWORD_ENV as Ur,PRISMA_MIGRATION_DIR_RE as Vr,CLICKHOUSE_MIGRATION_SKIP_RE as hr}from"./migration/constants.js";import{PHYSICAL_NAME_FALLBACK_PROPERTIES as Lr}from"./cfn/physicalNameProperties.js";export{_e as ACCOUNT_ROLES,w as ACCOUNT_STAGES,Z as ACCOUNT_STAGES_WITH_ROOT,J as ACCOUNT_STAGE_LABELS,$ as ACCOUNT_TIERS,S as APPROVAL_TOKEN_OUTPUT_PREFIX,gr as ARTEFACT_OUTPUT_FIELDS,Oe as AWS_REGIONS_METADATA,ee as AccountTierSchema,a as BACKUP_VAULT_NAME,hr as CLICKHOUSE_MIGRATION_SKIP_RE,mr as CONTENT_HASH_TAG_PATTERN,We as ConnectionWireSchema,Be as ConnectionsListResponseSchema,X as DANGEROUS_ENV_VARS,Ce as DEFAULT_REGION,Or as DEPLOY_MODES,o as DNS_APEX,Cr as DeployModeSchema,dr as EXPECTED_CH_SCHEMA_VERSION_ENV,xr as EXPECTED_SCHEMA_VERSION_ENV,Dr as EXPECTED_SCHEMA_VERSION_TOOL_ENV,cr as IMAGE_TAG_PATTERN,fr as ImageTagSchema,xe as MACHINE_ONLY_SCOPES,fe as MAX_SECONDARY_REGIONS,ur as MIGRATION_SNAPSHOT_NAME_PREFIX,pe as OPT_IN_REGION_CODES,Lr as PHYSICAL_NAME_FALLBACK_PROPERTIES,Vr as PRISMA_MIGRATION_DIR_RE,u as REGION_SHORT_CODES,_r as RESERVED_APP_NAMES,Sr as RESERVED_APP_NAME_MESSAGE,nr as RESERVED_APP_NAME_SUFFIX,ir as RESERVED_APP_NAME_SUFFIX_MESSAGE,Ae as RESOURCE_CATEGORIES,Ur as SCHEMA_ADMIN_PASSWORD_ENV,lr as SCHEMA_ADMIN_USER_ENV,W as SCOPED_TOKEN_REGEX,ue as SCOPE_VALUES,Ue as SECRET_NAME_ERROR,le as SECRET_NAME_PATTERN,he as SSM_COMPONENT_ERROR,Ve as SSM_COMPONENT_PATTERN,Ge as SSM_STANDARD_MAX_VALUE_BYTES,q as STRUCTURAL_ENVIRONMENTS,Le as SecretNamespaceSchema,pr as ServiceArtefactSchema,Pr as ServiceArtefactsSchema,A as TOKEN_STDERR_PREFIX,De as USER_GRANTABLE_SCOPES,se as abbreviateRegion,c as accountConstructKey,te as accountTier,Ir as artefactOutputKey,Qe as buildAppConfigPath,ve as buildNamespaceParts,Fe as buildParameterPath,O as capitalise,ne as categoriseResource,I as defaultConnectedAccountName,ze as deriveAllTargets,Nr as deriveContentHashTag,ke as deriveRegionsFromOrgConfig,je as deriveTargets,Ze as environmentOrTier,oe as environmentToTier,Ke as escapeDotEnvValue,b as filterDangerousEnvVars,P as findAccountNameCollision,rr as findBoundaryPath,er as findInfrastructurePaths,qe as findTarget,x as findTrailingRegionShortCode,L as formatErrorString,we as generateTargetName,E as getDomainExportNames,ae as getEnvironmentLabel,h as getErrorCode,U as getErrorMessage,G as getErrorStack,ie as getExpectedDuration,Re as getFriendlyResourceType,ce as getRegionInfo,C as getSafeZoneName,f as hasAsciiStableConstructKey,V as hasErrorCode,Rr as hasReservedAppNameSuffix,i as imageTagParameterName,tr as inferContainerFromCandidates,Q as isAccountStage,re as isAccountTier,or as isInfrastructureFile,Xe as isManageablePath,Ar as isReservedAppName,j as mapSettledWithConcurrency,K as maskSensitiveOutput,l as normaliseError,Pe as optInRegionWarning,be as parseDotEnv,Ne as parseGitRemoteUrl,He as parseParameterPath,y as parseShellArgs,D as regionSuffixRejectionMessage,ge as regions,F as singleton,Y as sleep,Ee as stageFromWireEnvironment,M as suffixedAccountName,Ie as suggestRegionForTimezone,N as toKebab,T as toPascalCase,s as toScreamingSnake,m as toValidDatabaseName};
|
|
@@ -44,3 +44,30 @@ export declare const RESERVED_APP_NAME_MESSAGE = "This application name is reser
|
|
|
44
44
|
* inline, so the lowercasing discipline cannot drift across CLI/webapp/worker.
|
|
45
45
|
*/
|
|
46
46
|
export declare function isReservedAppName(name: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Reserved application-name suffix: `-cache`.
|
|
49
|
+
*
|
|
50
|
+
* Every app's ECR build-cache repository is derived as
|
|
51
|
+
* `` `${toKebab(appName)}-cache` `` (`buildCacheRepositoryName`,
|
|
52
|
+
* `util/src/docker/cacheRepository.ts`). An application whose own kebab form
|
|
53
|
+
* ends in `-cache` would collide with a sibling app's cache repo: the
|
|
54
|
+
* sibling's deploy session policy exempts that ARN from the foreign-ECR
|
|
55
|
+
* mutation Deny (deploy-core `deploySessionPolicy.ts`) and its cache ensure
|
|
56
|
+
* would overwrite the colliding app repo's lifecycle policy. Rejecting the
|
|
57
|
+
* suffix at create time keeps the `-cache` namespace exclusively
|
|
58
|
+
* derivational.
|
|
59
|
+
*/
|
|
60
|
+
export declare const RESERVED_APP_NAME_SUFFIX = "-cache";
|
|
61
|
+
/**
|
|
62
|
+
* Canonical user-facing rejection message for a `-cache`-suffixed name.
|
|
63
|
+
* Shared by every create surface so the wording cannot drift.
|
|
64
|
+
*/
|
|
65
|
+
export declare const RESERVED_APP_NAME_SUFFIX_MESSAGE = "Application names ending in '-cache' are reserved for Fjall build-cache repositories.";
|
|
66
|
+
/**
|
|
67
|
+
* Suffix check for the reserved `-cache` namespace. Runs on the kebab form,
|
|
68
|
+
* not the raw lowercase — `WebAppCache` contains no hyphen until kebab-cased,
|
|
69
|
+
* yet derives the colliding repo `web-app-cache`. Consumers MUST route
|
|
70
|
+
* through this helper rather than an inline `.endsWith()` so the kebab-first
|
|
71
|
+
* discipline cannot drift across CLI/webapp/worker.
|
|
72
|
+
*/
|
|
73
|
+
export declare function hasReservedAppNameSuffix(name: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
import{toKebab as r}from"./caseConversion.js";const o=["fjall","organisation","platform","account"],a="This application name is reserved for Fjall's organisation-tier infrastructure.";function i(e){return o.includes(e.toLowerCase())}const t="-cache",s="Application names ending in '-cache' are reserved for Fjall build-cache repositories.";function E(e){return r(e).endsWith(t)}export{o as RESERVED_APP_NAMES,a as RESERVED_APP_NAME_MESSAGE,t as RESERVED_APP_NAME_SUFFIX,s as RESERVED_APP_NAME_SUFFIX_MESSAGE,E as hasReservedAppNameSuffix,i as isReservedAppName};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/util",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.29.0",
|
|
4
4
|
"description": "Common utility methods",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"default": "./dist/index.js"
|
|
12
12
|
},
|
|
13
|
+
"./buildConcurrency": {
|
|
14
|
+
"types": "./dist/buildConcurrency.d.ts",
|
|
15
|
+
"default": "./dist/buildConcurrency.js"
|
|
16
|
+
},
|
|
13
17
|
"./config": {
|
|
14
18
|
"types": "./dist/config.d.ts",
|
|
15
19
|
"default": "./dist/config.js"
|
|
@@ -125,5 +129,5 @@
|
|
|
125
129
|
"engines": {
|
|
126
130
|
"node": ">=22.0.0"
|
|
127
131
|
},
|
|
128
|
-
"gitHead": "
|
|
132
|
+
"gitHead": "c40ea0e1435400f3f42faaad5bcbf50e4400c1d4"
|
|
129
133
|
}
|