@ts-cloud/core 0.9.4 → 0.11.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/types.d.ts CHANGED
@@ -1132,6 +1132,11 @@ export interface SiteConfig {
1132
1132
  * A release is a fresh directory, so anything the app WRITES and must keep
1133
1133
  * has to be listed here or the next deploy silently starts it from empty.
1134
1134
  *
1135
+ * A SQLite database is the one exception, added for you: when the site's
1136
+ * resolved env says `DB_CONNECTION=sqlite` and `DB_DATABASE` names a path
1137
+ * inside the release, the deploy shares that file without being asked. An
1138
+ * env that says SQLite but not WHERE is warned about rather than guessed at.
1139
+ *
1135
1140
  * An entry may instead be a {@link SharedPathSpec} naming an absolute
1136
1141
  * `target`, which is how SEVERAL sites of one project point at ONE file —
1137
1142
  * an app and its API sharing a single SQLite database, say. Each site
@@ -2830,6 +2835,23 @@ export interface ComputeConfig {
2830
2835
  * @default true for PHP boxes
2831
2836
  */
2832
2837
  autoUpdates?: boolean;
2838
+ /**
2839
+ * Self-updating binaries to keep current on the box.
2840
+ *
2841
+ * `autoUpdates` above covers the *operating system*. This covers the tools
2842
+ * you deploy: anything that ships as a GitHub release and can replace itself
2843
+ * (`<binary> upgrade`). ts-cloud renders the systemd service, timer and pause
2844
+ * switch for each one, so a project never hand-writes that into `userData`:
2845
+ *
2846
+ * ```ts
2847
+ * appUpdates: [{ service: 'mail', binary: '/opt/mail/mail-server' }]
2848
+ * ```
2849
+ *
2850
+ * ts-cloud only schedules the check. Skipping when already current, refusing
2851
+ * to downgrade, and rolling back a binary that will not start are the tool's
2852
+ * own responsibility — list a tool here only if its `upgrade` does those.
2853
+ */
2854
+ appUpdates?: ComputeAppUpdateTarget[];
2833
2855
  /**
2834
2856
  * Scheduled database backups (powered by `ts-backups`), synced to object
2835
2857
  * storage. Off unless configured.
@@ -2991,6 +3013,35 @@ export interface ComputeWafConfig {
2991
3013
  bypassPaths?: string[];
2992
3014
  }
2993
3015
  /** Scheduled database backup configuration. See {@link ComputeConfig.backups}. */
3016
+ /**
3017
+ * One self-updating binary that ts-cloud should keep current. See
3018
+ * `ComputeConfig.appUpdates`.
3019
+ */
3020
+ export interface ComputeAppUpdateTarget {
3021
+ /**
3022
+ * systemd service the tool runs as. Also names the generated units
3023
+ * (`<service>-upgrade.service` / `.timer`) and is passed to the tool so it
3024
+ * restarts the right unit after installing.
3025
+ */
3026
+ service: string;
3027
+ /** Absolute path of the installed binary to replace. */
3028
+ binary: string;
3029
+ /** Subcommand that performs the self-update. @default 'upgrade' */
3030
+ command?: string;
3031
+ /** Release channel to follow. @default 'stable' */
3032
+ channel?: 'stable' | 'canary';
3033
+ /** systemd `OnCalendar` expression for the check. @default 'daily' */
3034
+ schedule?: string;
3035
+ /**
3036
+ * Randomized spread applied to the scheduled time, so a fleet does not
3037
+ * stampede the release API at once. @default '4h'
3038
+ */
3039
+ randomizedDelay?: string;
3040
+ /** Extra flags appended to the update command (e.g. `--repo owner/name`). */
3041
+ args?: string[];
3042
+ /** Set false to render nothing for this target. @default true */
3043
+ enabled?: boolean;
3044
+ }
2994
3045
  export interface ComputeBackupConfig {
2995
3046
  /** Enable scheduled backups. @default false */
2996
3047
  enabled?: boolean;
@@ -3141,6 +3192,238 @@ export interface ComputeServicesConfig {
3141
3192
  meilisearch?: boolean | {
3142
3193
  version?: string;
3143
3194
  };
3195
+ /**
3196
+ * Provision the **mail server** on this box - `mail`, the Zig SMTP/IMAP
3197
+ * server (`github.com/mail-os/mail`), with its own webmail UI.
3198
+ *
3199
+ * `true` picks a mode from the environment rather than making you say it:
3200
+ * a production environment gets `'server'` (a real MTA that sends and
3201
+ * receives), anything else gets `'catcher'` (accepts everything, delivers
3202
+ * nowhere, shows it in the webmail UI). See {@link MailServiceConfig.mode}.
3203
+ *
3204
+ * ## Why this exists rather than a mailpit container
3205
+ *
3206
+ * Development mail traps and production mail servers are conventionally two
3207
+ * different programs, and that difference is where mail breaks. A message
3208
+ * that renders in mailpit has been through a parser nothing in production
3209
+ * will ever run; a `From` that mailpit accepts is one no MTA would. The bugs
3210
+ * that costs are the ones nobody can reproduce locally, which is the worst
3211
+ * kind.
3212
+ *
3213
+ * The two modes here are one binary with one parser, one authentication
3214
+ * path, one Maildir, and one UI. What development sees is what production
3215
+ * does, minus the delivery.
3216
+ */
3217
+ mail?: boolean | MailServiceConfig;
3218
+ }
3219
+ /**
3220
+ * What the on-box mail server is for. See {@link MailServiceConfig.mode}.
3221
+ *
3222
+ * - `'server'` - a real MTA. Receives on 25, submits on 587/465, serves IMAP,
3223
+ * signs with DKIM, and delivers outbound mail (directly or through a relay).
3224
+ * - `'catcher'` - accepts every message addressed to anywhere, delivers none
3225
+ * of them onward, and shows them in the webmail UI. The replacement for
3226
+ * mailpit/Mailhog, on the ports those tools use so nothing has to be
3227
+ * reconfigured to adopt it.
3228
+ */
3229
+ export type MailServiceMode = 'server' | 'catcher';
3230
+ /**
3231
+ * On-box mail server (`mail`). See {@link ComputeServicesConfig.mail}.
3232
+ *
3233
+ * Every field is optional; the defaults are a working server for the
3234
+ * environment's mode. What has no safe default - the hostname the server
3235
+ * announces, and therefore what its MX record must point at - is derived from
3236
+ * the project's own domain and can be overridden here.
3237
+ */
3238
+ export interface MailServiceConfig {
3239
+ /**
3240
+ * Real MTA or local trap. Defaults to `'server'` in a production
3241
+ * environment and `'catcher'` everywhere else.
3242
+ */
3243
+ mode?: MailServiceMode;
3244
+ /** Pin the mail server version. @default latest release */
3245
+ version?: string;
3246
+ /**
3247
+ * The FQDN this server announces in HELO/EHLO and signs mail as, e.g.
3248
+ * `mail.example.com`. It is also what an MX record has to resolve to, so it
3249
+ * must be a name you control and that resolves to this box.
3250
+ *
3251
+ * @default `mail.<the project's primary site domain>`, or `localhost` for a
3252
+ * catcher, which announces a name nobody has to resolve.
3253
+ */
3254
+ hostname?: string;
3255
+ /**
3256
+ * Additional domains delivered to mailboxes on this server, beyond
3257
+ * {@link hostname} and its parent (`mail.example.com` already covers
3258
+ * `example.com`). One server, several domains' mailboxes.
3259
+ */
3260
+ domains?: string[];
3261
+ /** Listening ports. Every one has a default; see {@link MailPortsConfig}. */
3262
+ ports?: MailPortsConfig;
3263
+ /**
3264
+ * TLS for SMTP/IMAP. Defaults to ACME (Let's Encrypt) for a `'server'` on a
3265
+ * real hostname, and off for a `'catcher'`, which is loopback-only.
3266
+ */
3267
+ tls?: MailTlsConfig;
3268
+ /**
3269
+ * DKIM signing. `true` generates a key per {@link domains} entry on first
3270
+ * provision and prints the DNS record to publish; the private key stays on
3271
+ * the box and is never rewritten once it exists.
3272
+ *
3273
+ * On by default for a `'server'`, off for a `'catcher'` - a trap signing
3274
+ * mail is signing mail nobody will ever verify.
3275
+ */
3276
+ dkim?: boolean | MailDkimConfig;
3277
+ /**
3278
+ * The webmail UI - the browser client the mail server serves itself, and
3279
+ * the thing you look at instead of mailpit's inbox.
3280
+ *
3281
+ * On by default. A catcher serves it on 8025 (mailpit's port, so a bookmark
3282
+ * or a `docker-compose` port mapping carries over); a server serves it on
3283
+ * 8080 behind the gateway.
3284
+ */
3285
+ webmail?: boolean | MailWebmailConfig;
3286
+ /**
3287
+ * Mailboxes to create on first provision. Idempotent: an account that
3288
+ * already exists has its password reset to what is declared here, so this
3289
+ * stays the source of truth rather than drifting after the first boot.
3290
+ *
3291
+ * Passwords belong in the environment, not in a committed config - write
3292
+ * `password: process.env.MAIL_ADMIN_PASSWORD!` rather than a literal.
3293
+ */
3294
+ accounts?: MailAccountConfig[];
3295
+ /**
3296
+ * How outbound mail leaves the box.
3297
+ *
3298
+ * - `'direct'` - talk to the recipient's MX on port 25. The right answer for
3299
+ * a box whose provider does not block outbound 25 and whose IP has
3300
+ * reverse DNS. Note that most providers block outbound 25 on new accounts
3301
+ * and unblock it on request; check before choosing this.
3302
+ * - `'ses'` - relay through AWS SES in {@link sesRegion}, which is what to
3303
+ * use while port 25 is blocked.
3304
+ * - `'none'` - accept and deliver locally, never send. What a catcher does.
3305
+ *
3306
+ * There is deliberately no generic smarthost option: the mail server has no
3307
+ * authenticated-relay path yet, so a `relay: { host, username, password }`
3308
+ * here would be a credential written to a box and then ignored, and mail
3309
+ * that appears to be configured and silently goes nowhere is worse than mail
3310
+ * that was never configured.
3311
+ *
3312
+ * @default `'direct'` for a server, `'none'` for a catcher.
3313
+ */
3314
+ delivery?: 'direct' | 'ses' | 'none';
3315
+ /** SES region for `delivery: 'ses'`. @default 'us-east-1' */
3316
+ sesRegion?: string;
3317
+ /** Where mailboxes, the database and DKIM keys live. @default '/var/lib/mail' */
3318
+ storagePath?: string;
3319
+ /** Largest message accepted, in bytes. @default 26214400 (25 MB) */
3320
+ maxMessageSize?: number;
3321
+ /** Inbound spam handling. Advisory by default; see {@link MailSpamConfig}. */
3322
+ spam?: MailSpamConfig;
3323
+ /** POST every received message to this URL. Off unless set. */
3324
+ webhookUrl?: string;
3325
+ /**
3326
+ * Open the mail ports to the internet.
3327
+ *
3328
+ * A `'server'` has to be reachable to receive mail, so this defaults to
3329
+ * true for it and the ports join the host firewall's allow list. A
3330
+ * `'catcher'` defaults to false and binds loopback only - a machine that
3331
+ * accepts every message for every recipient and shows them in a UI with no
3332
+ * password is an open relay and an open inbox, and it must never be
3333
+ * reachable from anywhere but the box itself.
3334
+ */
3335
+ expose?: boolean;
3336
+ }
3337
+ /**
3338
+ * Which ports the mail server listens on. The defaults are the standard ones
3339
+ * for a server, and mailpit's for a catcher, so adopting a catcher needs no
3340
+ * change to anything that was pointed at mailpit.
3341
+ */
3342
+ export interface MailPortsConfig {
3343
+ /** Inbound SMTP from other servers. @default 25 (server) / 1025 (catcher) */
3344
+ smtp?: number;
3345
+ /** Message submission (STARTTLS). @default 587; off for a catcher. */
3346
+ submission?: number;
3347
+ /** Implicit-TLS submission. @default 465; off for a catcher. */
3348
+ submissions?: number;
3349
+ /** IMAP. @default 143; off for a catcher. */
3350
+ imap?: number;
3351
+ /** IMAP over TLS. @default 993; off for a catcher. */
3352
+ imaps?: number;
3353
+ /** The webmail UI. @default 8080 (server) / 8025 (catcher) */
3354
+ webmail?: number;
3355
+ /** ManageSieve, when {@link MailServiceConfig} enables filtering. @default 4190 */
3356
+ managesieve?: number;
3357
+ }
3358
+ /** TLS for the mail server's SMTP/IMAP listeners. */
3359
+ export interface MailTlsConfig {
3360
+ /** Serve TLS at all. @default true for a server, false for a catcher. */
3361
+ enabled?: boolean;
3362
+ /**
3363
+ * Obtain and renew the certificate over ACME (Let's Encrypt) for
3364
+ * {@link MailServiceConfig.hostname}. @default true when TLS is enabled and
3365
+ * no explicit paths are given.
3366
+ */
3367
+ acme?: boolean;
3368
+ /** Contact address ACME registers. @default the first configured account. */
3369
+ acmeEmail?: string;
3370
+ /** Certificate path, when you supply the certificate yourself. */
3371
+ certPath?: string;
3372
+ /** Private key path, when you supply the certificate yourself. */
3373
+ keyPath?: string;
3374
+ /**
3375
+ * Refuse AUTH until the connection is encrypted. On by default for a
3376
+ * server: an SMTP AUTH over cleartext is a password on the wire.
3377
+ */
3378
+ requireForAuth?: boolean;
3379
+ }
3380
+ /** DKIM signing. See {@link MailServiceConfig.dkim}. */
3381
+ export interface MailDkimConfig {
3382
+ /** Selector published as `<selector>._domainkey.<domain>`. @default 'default' */
3383
+ selector?: string;
3384
+ /** Rotate the key on a schedule. Off by default. */
3385
+ rotate?: boolean;
3386
+ /** Days between rotations when {@link rotate} is on. @default 90 */
3387
+ rotateIntervalDays?: number;
3388
+ }
3389
+ /** The webmail UI. See {@link MailServiceConfig.webmail}. */
3390
+ export interface MailWebmailConfig {
3391
+ /** Serve it. @default true */
3392
+ enabled?: boolean;
3393
+ /** Port. @default 8080 (server) / 8025 (catcher) */
3394
+ port?: number;
3395
+ /**
3396
+ * Hostname to route to the UI through the box's gateway, e.g.
3397
+ * `mail.example.com`. Without one the UI is reachable on its port only,
3398
+ * which for a catcher is exactly right.
3399
+ */
3400
+ domain?: string;
3401
+ }
3402
+ /** A mailbox created on first provision. See {@link MailServiceConfig.accounts}. */
3403
+ export interface MailAccountConfig {
3404
+ /** Full address, e.g. `postmaster@example.com`. */
3405
+ address: string;
3406
+ /** The password. Read it from the environment; never commit one. */
3407
+ password: string;
3408
+ }
3409
+ /** Inbound spam handling. See {@link MailServiceConfig.spam}. */
3410
+ export interface MailSpamConfig {
3411
+ /** Score inbound mail and file it into Junk. @default true for a server. */
3412
+ enabled?: boolean;
3413
+ /**
3414
+ * Reject mail that fails DMARC outright rather than recording the verdict
3415
+ * in `Authentication-Results` and delivering it. Off by default: a policy
3416
+ * that bounces mail is one somebody has to be ready to hear about.
3417
+ */
3418
+ enforce?: boolean;
3419
+ /** Score at which mail is filed into Junk. @default 5 */
3420
+ junkScore?: number;
3421
+ /** Score at which mail is refused at SMTP time. @default 12 */
3422
+ rejectScore?: number;
3423
+ /** Consult DNS blocklists. @default true for a server. */
3424
+ dnsbl?: boolean;
3425
+ /** Greylist unknown senders. Off by default - it delays first contact. */
3426
+ greylist?: boolean;
3144
3427
  }
3145
3428
  /**
3146
3429
  * Reverse-proxy gateway provisioning for a compute box. The gateway is
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ts-cloud/core",
3
3
  "type": "module",
4
- "version": "0.9.4",
4
+ "version": "0.11.0",
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.9.4"
34
+ "@ts-cloud/aws-types": "0.11.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "typescript": "^7.0.2"