@ts-cloud/core 0.16.16 → 0.16.18

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.
@@ -23,8 +23,15 @@
23
23
  * }
24
24
  * ```
25
25
  *
26
+ * {@link validateOriginGroups} checks a whole distribution config the same way
27
+ * CloudFront does, so a distribution assembled by hand fails at template
28
+ * generation instead of half way through a CloudFormation deploy.
29
+ *
30
+ * Verified against a live distribution (S3 origins in two regions, failover on
31
+ * a missing object and on a primary that denies every read) for
32
+ * stacksjs/stacks#1159.
33
+ *
26
34
  * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/high_availability_origin_failover.html
27
- * @experimental Built against the AWS documentation; not yet exercised against a live distribution.
28
35
  */
29
36
  /** Every status code CloudFront accepts as a failover criterion. */
30
37
  export declare const CLOUDFRONT_FAILOVER_STATUS_CODES: readonly number[];
@@ -38,6 +45,27 @@ export declare const DEFAULT_FAILOVER_STATUS_CODES: readonly number[];
38
45
  export declare const ORIGIN_GROUP_ALLOWED_METHODS: readonly string[];
39
46
  /** Suffix appended to the primary origin id to name its origin group. */
40
47
  export declare const ORIGIN_GROUP_ID_SUFFIX = "-failover-group";
48
+ /**
49
+ * How CloudFront picks the origin it asks first.
50
+ *
51
+ * - `default`: always the primary (the first member), falling back to the
52
+ * secondary on a failover status code.
53
+ * - `media-quality-based`: CloudFront scores both origins and asks the better
54
+ * one first. Only valid when both members are AWS Elemental MediaPackage v2
55
+ * endpoints.
56
+ */
57
+ export type OriginGroupSelectionCriteria = 'default' | 'media-quality-based';
58
+ export declare const ORIGIN_GROUP_SELECTION_CRITERIA: readonly OriginGroupSelectionCriteria[];
59
+ /** `ConnectionAttempts` CloudFront accepts on an origin (its default is 3). */
60
+ export declare const ORIGIN_CONNECTION_ATTEMPTS: {
61
+ readonly min: 1;
62
+ readonly max: 3;
63
+ };
64
+ /** `ConnectionTimeout`, in seconds, CloudFront accepts on an origin (its default is 10). */
65
+ export declare const ORIGIN_CONNECTION_TIMEOUT: {
66
+ readonly min: 1;
67
+ readonly max: 10;
68
+ };
41
69
  export interface OriginGroupOptions {
42
70
  /** Id of the origin CloudFront asks first. */
43
71
  primaryOriginId: string;
@@ -47,6 +75,11 @@ export interface OriginGroupOptions {
47
75
  statusCodes?: readonly number[];
48
76
  /** Origin group id, which cache behaviors use as their `TargetOriginId`. @default `<primaryOriginId>-failover-group` */
49
77
  groupId?: string;
78
+ /**
79
+ * How CloudFront picks the origin it asks first. Omitted from the template
80
+ * unless set, which CloudFront treats as `default`.
81
+ */
82
+ selectionCriteria?: OriginGroupSelectionCriteria;
50
83
  }
51
84
  export interface CloudFrontOriginGroup {
52
85
  Id: string;
@@ -62,6 +95,14 @@ export interface CloudFrontOriginGroup {
62
95
  OriginId: string;
63
96
  }>;
64
97
  };
98
+ SelectionCriteria?: OriginGroupSelectionCriteria;
99
+ }
100
+ /** Connection tuning for one origin. Unset keys keep CloudFront's defaults (3 attempts, 10 seconds). */
101
+ export interface OriginConnectionOptions {
102
+ /** Times CloudFront tries to connect to the origin, 1-3. */
103
+ connectionAttempts?: number;
104
+ /** Seconds CloudFront waits to establish a connection, 1-10. */
105
+ connectionTimeout?: number;
65
106
  }
66
107
  export interface CloudFrontOriginGroups {
67
108
  Quantity: number;
@@ -76,6 +117,22 @@ export interface CloudFrontOriginGroups {
76
117
  export declare function resolveFailoverStatusCodes(statusCodes?: readonly number[]): number[];
77
118
  /** Build one origin group (primary first, secondary second). */
78
119
  export declare function buildOriginGroup(options: OriginGroupOptions): CloudFrontOriginGroup;
120
+ /**
121
+ * Validate an origin's connection tuning and return it in template form
122
+ * (`ConnectionAttempts` / `ConnectionTimeout`), holding only the keys that were
123
+ * set so an untuned origin's template is unchanged.
124
+ *
125
+ * Lowering these on the primary is how failover gets faster: by default
126
+ * CloudFront spends up to 30 seconds (3 attempts of 10 seconds) on an
127
+ * unreachable primary before it asks the secondary.
128
+ *
129
+ * @param where Names the origin in the error, e.g. `infrastructure.cdn.main`.
130
+ * @throws when a value is not a whole number in CloudFront's range.
131
+ */
132
+ export declare function resolveOriginConnection(options: OriginConnectionOptions | undefined, where?: string): {
133
+ ConnectionAttempts?: number;
134
+ ConnectionTimeout?: number;
135
+ };
79
136
  /** Build a distribution's `OriginGroups` block holding a single failover group. */
80
137
  export declare function buildOriginGroups(options: OriginGroupOptions): CloudFrontOriginGroups;
81
138
  /**
@@ -95,3 +152,26 @@ export declare function assertOriginGroupMethods(allowedMethods: readonly string
95
152
  * S3 *website* endpoints only speak HTTP and are custom origins.
96
153
  */
97
154
  export declare function isS3RestEndpoint(domainName: string): boolean;
155
+ /**
156
+ * Check every origin group in a distribution config against the rules
157
+ * CloudFront enforces, and throw a message that names the broken piece.
158
+ *
159
+ * Accepts the CloudFormation `DistributionConfig` (arrays) and the CloudFront
160
+ * API's (`{ Quantity, Items }`), and skips comparisons on values that are
161
+ * CloudFormation intrinsics. Checked:
162
+ *
163
+ * - each group has exactly two members, both existing origins, and distinct;
164
+ * - group ids are unique and do not shadow an origin id;
165
+ * - failover status codes are ones CloudFront accepts, and `Quantity` matches;
166
+ * - `SelectionCriteria` is `default` or `media-quality-based`, the latter only
167
+ * between MediaPackage v2 origins;
168
+ * - every cache behavior (default and path) that targets a group allows only
169
+ * GET, HEAD and OPTIONS;
170
+ * - every cache behavior targets an origin or group that exists;
171
+ * - every origin's `ConnectionAttempts` (1-3) and `ConnectionTimeout` (1-10).
172
+ *
173
+ * A distribution with no origin groups passes the group checks trivially.
174
+ *
175
+ * @param where Names the distribution in errors, e.g. `infrastructure.cdn.main`.
176
+ */
177
+ export declare function validateOriginGroups(distributionConfig: Record<string, any>, where?: string): void;
@@ -1,5 +1,6 @@
1
1
  import type { CloudFrontDistribution, CloudFrontOriginAccessControl, IAMRole, LambdaFunction } from '@ts-cloud/aws-types';
2
2
  import type { EnvironmentType } from '../types';
3
+ import type { OriginConnectionOptions, OriginGroupSelectionCriteria } from './cdn-failover';
3
4
  export interface DistributionOptions {
4
5
  slug: string;
5
6
  environment: EnvironmentType;
@@ -14,15 +15,14 @@ export interface DistributionOptions {
14
15
  /**
15
16
  * Secondary origin CloudFront fails over to when the primary errors.
16
17
  * Adds an origin group and points the default cache behavior at it.
17
- * @experimental See {@link CDN.addOriginFailover}.
18
+ * See {@link CDN.addOriginFailover}.
18
19
  */
19
20
  failoverOrigin?: FailoverOriginConfig;
20
21
  }
21
22
  /**
22
23
  * Secondary origin for CloudFront origin failover.
23
- * @experimental Built against the AWS documentation; not yet exercised against a live distribution.
24
24
  */
25
- export interface FailoverOriginConfig {
25
+ export interface FailoverOriginConfig extends OriginConnectionOptions {
26
26
  /** Domain of the secondary origin, e.g. a replica bucket in another region. */
27
27
  domainName: string;
28
28
  /** Origin kind. @default 's3' for an S3 REST endpoint, otherwise 'custom' */
@@ -35,8 +35,17 @@ export interface FailoverOriginConfig {
35
35
  * 416, 429, 500, 502, 503, 504. @default [500, 502, 503, 504]
36
36
  */
37
37
  statusCodes?: number[];
38
+ /** How CloudFront picks the origin it asks first. @default CloudFront's 'default' (primary first) */
39
+ selectionCriteria?: OriginGroupSelectionCriteria;
40
+ /**
41
+ * Connection tuning for the *primary* origin. Lower values make failover
42
+ * faster: CloudFront otherwise spends up to 30 seconds (3 attempts of 10
43
+ * seconds) on an unreachable primary. `connectionAttempts` and
44
+ * `connectionTimeout` on this object tune the secondary.
45
+ */
46
+ primary?: OriginConnectionOptions;
38
47
  }
39
- export interface OriginConfig {
48
+ export interface OriginConfig extends OriginConnectionOptions {
40
49
  type?: 's3' | 'alb' | 'custom';
41
50
  id?: string;
42
51
  originId?: string;
@@ -79,9 +88,8 @@ export declare class CDN {
79
88
  *
80
89
  * CloudFront only fails over GET, HEAD and OPTIONS, and rejects an origin
81
90
  * group behind a cache behavior that allows writes, so this throws if the
82
- * default cache behavior allows any other method.
83
- *
84
- * @experimental Built against the AWS documentation; not yet exercised against a live distribution.
91
+ * default cache behavior allows any other method. The finished config is
92
+ * checked with {@link validateOriginGroups}.
85
93
  */
86
94
  static addOriginFailover(distribution: CloudFrontDistribution, failover: FailoverOriginConfig): CloudFrontDistribution;
87
95
  /**
@@ -6,6 +6,7 @@ export * from './storage';
6
6
  export * from './registry';
7
7
  export * from './cdn';
8
8
  export * from './cdn-failover';
9
+ export * from './storage-failover';
9
10
  export * from './dns';
10
11
  export * from './security';
11
12
  export * from './compute';
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Cross-region failover for a website bucket (stacksjs/stacks#1159).
3
+ *
4
+ * The CloudFront half is an origin group (see `cdn-failover.ts`): the primary
5
+ * bucket first, a replica bucket in another region second. This module holds
6
+ * the pure pieces the bucket half needs:
7
+ *
8
+ * - {@link resolveStorageFailover} turns `infrastructure.storage.<name>.failover`
9
+ * into a concrete plan (replica name and region, status codes, connection
10
+ * tuning) and rejects configs CloudFront or S3 would refuse later.
11
+ * - {@link buildReplicationRole} and {@link buildReplicationConfiguration}
12
+ * emit the IAM role and `ReplicationConfiguration` that copy every write to
13
+ * the replica.
14
+ * - {@link STORAGE_FAILOVER_METADATA_KEY} names the template `Metadata` entry
15
+ * that tells a deployer which replicas to create before the stack and grant
16
+ * CloudFront access to after it. The replica cannot live in the stack: a
17
+ * CloudFormation stack only creates buckets in its own region.
18
+ */
19
+ import type { StorageFailoverConfig } from '../types';
20
+ /**
21
+ * Failover codes for a bucket origin when none are given. An S3 origin behind
22
+ * origin access control answers a missing object with 403 (the distribution
23
+ * may not list the bucket), so 403 and 404 cover an object the primary lost;
24
+ * the 5xx codes cover the bucket or its region failing.
25
+ */
26
+ export declare const DEFAULT_STORAGE_FAILOVER_STATUS_CODES: readonly number[];
27
+ /** Template `Metadata` key listing the failover replicas a stack depends on. */
28
+ export declare const STORAGE_FAILOVER_METADATA_KEY = "TsCloud::StorageFailover";
29
+ /** Sid of the replica bucket-policy statement that lets the distribution read it. */
30
+ export declare const FAILOVER_REPLICA_POLICY_SID = "AllowCloudFrontFailoverRead";
31
+ /** One replica, as recorded in the template metadata and consumed by the deployer. */
32
+ export interface StorageFailoverReplica {
33
+ /** `infrastructure.storage` key. */
34
+ name: string;
35
+ primaryBucket: string;
36
+ primaryRegion: string;
37
+ replicaBucket: string;
38
+ replicaRegion: string;
39
+ /** Whether S3 replication copies writes to the replica (and so whether it must be versioned). */
40
+ replicate: boolean;
41
+ /** Stack output holding the distribution ARN the replica policy is scoped to. */
42
+ distributionArnOutput: string;
43
+ }
44
+ export interface ResolvedStorageFailover {
45
+ replicaBucket: string;
46
+ replicaRegion: string;
47
+ replicate: boolean;
48
+ statusCodes: number[];
49
+ primaryConnection: {
50
+ ConnectionAttempts?: number;
51
+ ConnectionTimeout?: number;
52
+ };
53
+ }
54
+ /**
55
+ * Resolve and validate a bucket's failover config.
56
+ *
57
+ * @param where Names the bucket in errors, e.g. `infrastructure.storage.public`.
58
+ * @throws when the region is missing, malformed or the primary's own region,
59
+ * when the replica name is not a valid bucket name (or collides with the
60
+ * primary), or when a status code or connection setting is out of range.
61
+ */
62
+ export declare function resolveStorageFailover(options: {
63
+ failover: StorageFailoverConfig;
64
+ primaryBucket: string;
65
+ primaryRegion: string;
66
+ where?: string;
67
+ }): ResolvedStorageFailover;
68
+ /** S3 REST endpoint of a bucket, the domain a CloudFront S3 origin uses. */
69
+ export declare function s3RegionalDomain(bucket: string, region: string): string;
70
+ /**
71
+ * IAM role S3 assumes to replicate `primaryBucket` into `replicaBucket`. The
72
+ * permissions are the minimum the S3 docs list for live replication,
73
+ * including delete markers.
74
+ */
75
+ export declare function buildReplicationRole(options: {
76
+ primaryBucket: string;
77
+ replicaBucket: string;
78
+ roleName?: string;
79
+ }): any;
80
+ /**
81
+ * `ReplicationConfiguration` for the primary bucket: one rule copying every
82
+ * object, and its deletes, to the replica.
83
+ *
84
+ * @param roleArn The replication role's ARN, usually `{ 'Fn::GetAtt': [roleLogicalId, 'Arn'] }`.
85
+ */
86
+ export declare function buildReplicationConfiguration(options: {
87
+ replicaBucket: string;
88
+ roleArn: unknown;
89
+ }): any;
90
+ /**
91
+ * The replica bucket-policy statement that lets one distribution, through
92
+ * origin access control, read the replica.
93
+ */
94
+ export declare function buildFailoverReplicaPolicyStatement(options: {
95
+ replicaBucket: string;
96
+ distributionArn: string;
97
+ }): any;
98
+ /** Read the failover replicas a generated template depends on (empty when none). */
99
+ export declare function storageFailoverReplicasFromTemplate(template: unknown): StorageFailoverReplica[];
@@ -18,6 +18,10 @@ export declare class TemplateBuilder {
18
18
  * Add an output to the template
19
19
  */
20
20
  addOutput(name: string, output: NonNullable<CloudFormationTemplate['Outputs']>[string]): this;
21
+ /**
22
+ * Set a template-level `Metadata` entry
23
+ */
24
+ addMetadata(key: string, value: unknown): this;
21
25
  /**
22
26
  * Check if a resource already exists in the template
23
27
  */
package/dist/types.d.ts CHANGED
@@ -2194,6 +2194,18 @@ export interface StorageItemConfig {
2194
2194
  * Defaults to directory, which matches most blog/static-export outputs.
2195
2195
  */
2196
2196
  pathRewriteStyle?: 'directory' | 'flat';
2197
+ /**
2198
+ * CloudFront origin failover to a replica of this bucket in another region.
2199
+ * Only applies to a website bucket served through CloudFront. Off unless set.
2200
+ *
2201
+ * @example
2202
+ * ```ts
2203
+ * storage: {
2204
+ * public: { website: true, failover: { region: 'us-west-2' } },
2205
+ * }
2206
+ * ```
2207
+ */
2208
+ failover?: StorageFailoverConfig;
2197
2209
  /**
2198
2210
  * Whether this bucket serves a single-page application (SPA).
2199
2211
  * When true: 403/404 errors return index.html with status 200 (for client-side routing).
@@ -3145,6 +3157,107 @@ export interface ComputeConfig {
3145
3157
  * simple as adding an entry here and redeploying.
3146
3158
  */
3147
3159
  sshKeys?: SshKeyConfig[];
3160
+ /**
3161
+ * Bounded disk retention on box hosts (Hetzner and ssh providers, and AWS
3162
+ * EC2 boxes deployed over SSM).
3163
+ *
3164
+ * ts-cloud prunes what it leaves behind on a box: abandoned upload staging,
3165
+ * the release artifact cache, the Bun download cache, journald, unused
3166
+ * container images and the apt cache. Current and rollback releases are never
3167
+ * touched; `keepReleases` governs those. The cleanup runs after every deploy,
3168
+ * after a failed one, and on a systemd timer, so a box that stops deploying
3169
+ * still cleans. It reads root-filesystem usage first: below
3170
+ * `pressure.lowWaterPercent` it skips the expensive rules, and at or above
3171
+ * `pressure.highWaterPercent` it prunes on shorter windows and warns.
3172
+ *
3173
+ * Omit for the defaults. `false` turns the whole mechanism off, including a
3174
+ * timer an earlier deploy installed.
3175
+ */
3176
+ hostCleanup?: boolean | ComputeHostCleanupConfig;
3177
+ }
3178
+ /**
3179
+ * Retention windows for {@link ComputeConfig.hostCleanup}. Each field is an age
3180
+ * past which the matching files are deleted; omit one to keep its default.
3181
+ */
3182
+ export interface HostCleanupRetention {
3183
+ /**
3184
+ * Abandoned upload staging (`/var/ts-cloud/staging`, `/tmp/*-release.tar.gz`).
3185
+ * Doubles as the in-flight bound for a concurrent deploy, so it cannot go
3186
+ * below 15. @default 60
3187
+ */
3188
+ stagingMaxAgeMinutes?: number;
3189
+ /** Completed `*.tar.gz` in the release artifact cache, `-mtime` days. @default 2 */
3190
+ artifactMaxAgeDays?: number;
3191
+ /**
3192
+ * `.tmp` uploads to the artifact cache stranded by a dropped transfer. An
3193
+ * upload in flight is younger than this, so it cannot go below 15. @default 60
3194
+ */
3195
+ artifactUploadMaxAgeMinutes?: number;
3196
+ /** Bun's install (download) cache, `-mtime` days. @default 7 */
3197
+ bunCacheMaxAgeDays?: number;
3198
+ /** journald retention by age. @default 14 */
3199
+ journalMaxAgeDays?: number;
3200
+ /** journald retention by size. @default 512 */
3201
+ journalMaxSizeMb?: number;
3202
+ /** Unused docker/podman images, by age. @default 168 */
3203
+ containerImageMaxAgeHours?: number;
3204
+ }
3205
+ /** How host cleanup reacts to a filling disk. See {@link ComputeHostCleanupConfig.pressure}. */
3206
+ export interface HostCleanupPressureConfig {
3207
+ /**
3208
+ * Below this root-filesystem usage the cleanup runs only the cheap rules
3209
+ * (staging, artifacts, journald, registered paths) and skips the Bun cache
3210
+ * walk, image prunes and `apt-get clean`. `0` always runs everything.
3211
+ * @default 50
3212
+ */
3213
+ lowWaterPercent?: number;
3214
+ /**
3215
+ * At or above this usage the cleanup prunes with {@link escalated} windows,
3216
+ * prints a warning, and notifies the on-box notifier if it is still above
3217
+ * after cleaning. @default 85
3218
+ */
3219
+ highWaterPercent?: number;
3220
+ /**
3221
+ * Windows used at or above the high-water mark. Never looser than the normal
3222
+ * ones: each field is the smaller of the two.
3223
+ * @default { artifactMaxAgeDays: 0, bunCacheMaxAgeDays: 1, journalMaxAgeDays: 3, journalMaxSizeMb: 256, containerImageMaxAgeHours: 24 }
3224
+ */
3225
+ escalated?: HostCleanupRetention;
3226
+ }
3227
+ /**
3228
+ * A directory another component writes timestamped files into, pruned by the
3229
+ * same cleanup on the same schedule. Only direct children of `path` whose name
3230
+ * matches `pattern` are candidates, and only on the same filesystem.
3231
+ */
3232
+ export interface HostCleanupPathRule {
3233
+ /** Absolute directory, e.g. `/root/rpx-backups`. Not `/`, and not under `/var/www`. */
3234
+ path: string;
3235
+ /** `find -name` glob for the entries to prune, e.g. `cert-backup-*`. */
3236
+ pattern: string;
3237
+ /** Delete entries older than this many days (`-mtime`). */
3238
+ maxAgeDays: number;
3239
+ /** Prune matching files, or matching directories with their contents. @default 'file' */
3240
+ type?: 'file' | 'directory';
3241
+ }
3242
+ /** Host cleanup settings. See {@link ComputeConfig.hostCleanup}. */
3243
+ export interface ComputeHostCleanupConfig {
3244
+ /**
3245
+ * Install the `ts-cloud-host-cleanup.timer` systemd timer, so cleanup runs on
3246
+ * a schedule rather than only when something deploys. `false` removes a timer
3247
+ * an earlier deploy installed and keeps the deploy-time run. @default true
3248
+ */
3249
+ timer?: boolean;
3250
+ /** systemd `OnCalendar=` expression for the timer. @default 'daily' */
3251
+ schedule?: string;
3252
+ /** Retention windows; omit a field to keep its default. */
3253
+ retention?: HostCleanupRetention;
3254
+ /**
3255
+ * Disk-pressure thresholds. `false` runs every rule with the normal windows
3256
+ * regardless of usage, as ts-cloud did before the thresholds existed.
3257
+ */
3258
+ pressure?: boolean | HostCleanupPressureConfig;
3259
+ /** Extra directories to prune, e.g. a proxy's own backups. */
3260
+ paths?: HostCleanupPathRule[];
3148
3261
  }
3149
3262
  /** An operator SSH key authorized on the box. See {@link ComputeConfig.sshKeys}. */
3150
3263
  export interface SshKeyConfig {
@@ -4110,6 +4223,53 @@ export interface DatabaseItemConfig {
4110
4223
  }>;
4111
4224
  }>;
4112
4225
  }
4226
+ /** Object form of {@link CdnItemConfig.failoverOrigin}. */
4227
+ export interface CdnFailoverOriginConfig {
4228
+ /** Domain of the secondary origin. */
4229
+ domain: string;
4230
+ /** Path CloudFront prepends to requests sent to the secondary. */
4231
+ originPath?: string;
4232
+ /** Times CloudFront tries to connect to the secondary, 1-3. */
4233
+ connectionAttempts?: number;
4234
+ /** Seconds CloudFront waits to connect to the secondary, 1-10. */
4235
+ connectionTimeout?: number;
4236
+ }
4237
+ /**
4238
+ * CloudFront origin failover for a website bucket: a replica bucket in a
4239
+ * second region that CloudFront serves from when the primary bucket fails.
4240
+ *
4241
+ * ts-cloud creates the replica (versioned, private, encrypted) in
4242
+ * {@link region} before the stack deploys, replicates every write to it with
4243
+ * S3 replication, copies objects that predate replication across, and lets
4244
+ * the distribution read it through the same origin access control as the
4245
+ * primary. The replica lives outside the CloudFormation stack, because a stack
4246
+ * can only create buckets in its own region, so removing the stack leaves it
4247
+ * behind.
4248
+ */
4249
+ export interface StorageFailoverConfig {
4250
+ /** Region of the replica bucket. Must differ from the stack's region. */
4251
+ region: string;
4252
+ /** Replica bucket name. @default `<primary bucket>-<region>` */
4253
+ bucket?: string;
4254
+ /**
4255
+ * Primary status codes that send a request to the replica. CloudFront
4256
+ * accepts 400, 403, 404, 416, 429, 500, 502, 503 and 504.
4257
+ * @default [403, 404, 500, 502, 503, 504] - an S3 origin behind origin access
4258
+ * control answers a missing object with 403, so 403 and 404 cover an object
4259
+ * the primary lost, and the 5xx codes cover the bucket or region failing.
4260
+ */
4261
+ statusCodes?: number[];
4262
+ /** Times CloudFront tries to connect to the primary bucket, 1-3. @default CloudFront's 3 */
4263
+ connectionAttempts?: number;
4264
+ /** Seconds CloudFront waits to connect to the primary bucket, 1-10. @default CloudFront's 10 */
4265
+ connectionTimeout?: number;
4266
+ /**
4267
+ * Replicate the primary bucket to the replica with S3 replication (and turn
4268
+ * on the versioning that requires). Set false to keep the replica in sync
4269
+ * yourself. @default true
4270
+ */
4271
+ replicate?: boolean;
4272
+ }
4113
4273
  export interface CdnItemConfig {
4114
4274
  origin?: string;
4115
4275
  customDomain?: string | {
@@ -4129,6 +4289,15 @@ export interface CdnItemConfig {
4129
4289
  originShield?: boolean;
4130
4290
  /** AWS region used by Origin Shield. Defaults to the deployment region. */
4131
4291
  originShieldRegion?: string;
4292
+ /**
4293
+ * Times CloudFront tries to connect to {@link origin}, 1-3. CloudFront's
4294
+ * default is 3. Lower it, with {@link connectionTimeout}, to fail over
4295
+ * faster: an unreachable primary otherwise costs up to 30 seconds before
4296
+ * CloudFront asks {@link failoverOrigin}.
4297
+ */
4298
+ connectionAttempts?: number;
4299
+ /** Seconds CloudFront waits to connect to {@link origin}, 1-10. CloudFront's default is 10. */
4300
+ connectionTimeout?: number;
4132
4301
  /**
4133
4302
  * Secondary origin CloudFront fails over to when {@link origin} errors,
4134
4303
  * e.g. a replica bucket in another region. Adds a CloudFront origin group
@@ -4136,16 +4305,17 @@ export interface CdnItemConfig {
4136
4305
  * CloudFront only fails over GET, HEAD and OPTIONS requests. An S3 REST
4137
4306
  * endpoint becomes an S3 origin; any other host an HTTPS-only custom origin.
4138
4307
  *
4139
- * @experimental Generated from the AWS documentation; not yet verified
4140
- * against a live distribution.
4308
+ * A string is the secondary's domain. The object form also tunes the
4309
+ * secondary's connection settings and sets its origin path.
4141
4310
  */
4142
- failoverOrigin?: string;
4311
+ failoverOrigin?: string | CdnFailoverOriginConfig;
4143
4312
  /**
4144
4313
  * Status codes from {@link origin} that trigger failover to
4145
4314
  * {@link failoverOrigin}. CloudFront accepts 400, 403, 404, 416, 429, 500,
4146
- * 502, 503 and 504; anything else throws at template generation.
4315
+ * 502, 503 and 504; anything else throws at template generation. Add 403
4316
+ * and 404 to fail over on an object the primary does not have (an S3 origin
4317
+ * behind origin access control answers a missing object with 403).
4147
4318
  * @default [500, 502, 503, 504]
4148
- * @experimental
4149
4319
  */
4150
4320
  failoverStatusCodes?: number[];
4151
4321
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ts-cloud/core",
3
3
  "type": "module",
4
- "version": "0.16.16",
4
+ "version": "0.16.18",
5
5
  "description": "Core CloudFormation generation library for ts-cloud",
6
6
  "author": "Chris Breuer <chris@stacksjs.com>",
7
7
  "license": "MIT",
@@ -31,7 +31,7 @@
31
31
  "typecheck": "tsc --noEmit"
32
32
  },
33
33
  "dependencies": {
34
- "@ts-cloud/aws-types": "0.16.16"
34
+ "@ts-cloud/aws-types": "0.16.18"
35
35
  },
36
36
  "devDependencies": {
37
37
  "typescript": "^7.0.2"