@ts-cloud/core 0.2.26 → 0.3.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.
@@ -171,7 +171,7 @@ export declare class CDN {
171
171
  */
172
172
  static readonly EdgeFunctionTemplates: {
173
173
  /**
174
- * Origin request handler for docs/VitePress routing
174
+ * Origin request handler for docs/BunPress routing
175
175
  */
176
176
  docsOriginRequest: string;
177
177
  /**
@@ -1073,6 +1073,7 @@ export declare class Compute {
1073
1073
  readonly java17: "java17";
1074
1074
  readonly go: "provided.al2023";
1075
1075
  readonly rust: "provided.al2023";
1076
+ readonly bun: "provided.al2023";
1076
1077
  };
1077
1078
  /**
1078
1079
  * Common function configurations
@@ -1145,7 +1146,7 @@ export declare class Compute {
1145
1146
  * - Multiple sites can share one EC2 instance
1146
1147
  */
1147
1148
  generateBunAppScript: (options: {
1148
- runtime?: "bun" | "node" | "deno";
1149
+ runtime?: "bun" | "node" | "deno" | "php";
1149
1150
  runtimeVersion?: string;
1150
1151
  systemPackages?: string[];
1151
1152
  database?: "sqlite" | "mysql" | "postgres";
@@ -1269,7 +1270,13 @@ export declare class Compute {
1269
1270
  subnetId: string;
1270
1271
  instanceType?: string;
1271
1272
  imageId?: string;
1272
- keyName: string;
1273
+ /**
1274
+ * EC2 KeyName for SSH access. Optional — when omitted, no SSH key is
1275
+ * associated with the instance and shell access goes via SSM Session
1276
+ * Manager. The provided KeyName must already exist in EC2 or the
1277
+ * launch fails with "key pair does not exist".
1278
+ */
1279
+ keyName?: string;
1273
1280
  domain?: string;
1274
1281
  userData?: string;
1275
1282
  allowedPorts?: number[];
@@ -0,0 +1,26 @@
1
+ import type { SiteConfig } from '../types';
2
+ /**
3
+ * The ts-cloud management dashboard (`@ts-cloud/ui`) as a deployable site —
4
+ * a static stx app served on the box by nginx, behind HTTP Basic auth whose
5
+ * password comes from an env value.
6
+ *
7
+ * Add it to your config's `sites` so `cloud deploy` builds + publishes it:
8
+ *
9
+ * ```ts
10
+ * sites: {
11
+ * dashboard: createDashboardSite({ domain: 'dashboard.acme.com', password: process.env.TS_CLOUD_UI_PASSWORD }),
12
+ * }
13
+ * ```
14
+ */
15
+ export declare function createDashboardSite(options: {
16
+ /** Domain the dashboard is served on (required for nginx vhost + SSL). */
17
+ domain: string;
18
+ /** Basic-auth password — typically `process.env.TS_CLOUD_UI_PASSWORD`. */
19
+ password?: string;
20
+ /** Basic-auth username. @default 'admin' */
21
+ username?: string;
22
+ /** Built UI output directory shipped to the box. @default 'ui/dist' */
23
+ root?: string;
24
+ /** Build command producing {@link root}. @default builds @ts-cloud/ui */
25
+ build?: string;
26
+ }): SiteConfig;
@@ -1,6 +1,7 @@
1
1
  export { createStaticSitePreset } from './static-site';
2
2
  export { createNodeJsServerPreset } from './nodejs-server';
3
3
  export { createNodeJsServerlessPreset } from './nodejs-serverless';
4
+ export { createServerlessNodePreset } from './serverless-node';
4
5
  export { createFullStackAppPreset } from './fullstack-app';
5
6
  export { createApiBackendPreset } from './api-backend';
6
7
  export { createWordPressPreset } from './wordpress';
@@ -10,4 +11,6 @@ export { createRealtimeAppPreset } from './realtime-app';
10
11
  export { createDataPipelinePreset } from './data-pipeline';
11
12
  export { createMLApiPreset } from './ml-api';
12
13
  export { createTraditionalWebAppPreset } from './traditional-web-app';
14
+ export { createLaravelPreset } from './laravel';
15
+ export { createServerlessLaravelPreset } from './serverless-laravel';
13
16
  export { extendPreset, composePresets, createPreset, mergeInfrastructure, withMonitoring, withSecurity, withDatabase, withCache, withCDN, withQueue, } from './extend';
@@ -0,0 +1,36 @@
1
+ import type { CloudConfig, InstanceSize, PhpVersion } from '../types';
2
+ /**
3
+ * Laravel Preset — a Forge-style single server.
4
+ *
5
+ * Provisions one box (Hetzner by default) running nginx + php-fpm + Composer,
6
+ * MySQL + Redis on the box, host firewall (UFW), automatic security updates,
7
+ * monitoring, and scheduled backups. The app is deployed from git into atomic
8
+ * zero-downtime releases, served over HTTPS via Let's Encrypt, with the queue
9
+ * worker and scheduler enabled.
10
+ */
11
+ export declare function createLaravelPreset(options: {
12
+ name: string;
13
+ slug: string;
14
+ /** App domain (also used for the Let's Encrypt cert). */
15
+ domain?: string;
16
+ /** Git repository to deploy. */
17
+ repository: {
18
+ url: string;
19
+ branch?: string;
20
+ provider?: 'github' | 'gitlab' | 'bitbucket' | 'custom';
21
+ };
22
+ /** PHP version. @default '8.3' */
23
+ phpVersion?: PhpVersion;
24
+ /** Server size. @default 'small' */
25
+ size?: InstanceSize;
26
+ /** App database name. @default slug */
27
+ database?: string;
28
+ /** Database password (set via env in real configs). */
29
+ databasePassword?: string;
30
+ /** Contact email for Let's Encrypt. */
31
+ sslEmail?: string;
32
+ /** Deploy strategy. @default 'push' */
33
+ deployStrategy?: 'push' | 'tag';
34
+ /** Provider. @default 'hetzner' */
35
+ provider?: 'hetzner' | 'aws';
36
+ }): Partial<CloudConfig>;
@@ -0,0 +1,38 @@
1
+ import type { CloudConfig } from '../types';
2
+ /**
3
+ * Serverless Laravel preset — a true Laravel-Vapor clone running on AWS Lambda.
4
+ *
5
+ * Produces an `environments.<env>.app` manifest (kind: 'php') that the serverless
6
+ * deploy pipeline turns into three Lambda functions on the ts-cloud PHP runtime
7
+ * layer: HTTP via php-fpm (API Gateway v2), an SQS queue worker (one job per
8
+ * invocation), and a CLI function (EventBridge scheduler + artisan commands),
9
+ * plus a DynamoDB cache table and CDN-backed `public/` assets.
10
+ *
11
+ * Build hooks default to the Laravel artisan caching steps (config/route/event/
12
+ * view cache) since the Lambda filesystem is read-only at runtime; the deploy
13
+ * hook runs migrations. Install the `tscloud/serverless` composer package in the
14
+ * app for the SQS queue bridge (a `laravel/vapor-core` replacement).
15
+ *
16
+ * @example
17
+ * export default createServerlessLaravelPreset({
18
+ * name: 'My App', slug: 'my-app', domain: 'my-app.com',
19
+ * layers: ['arn:aws:lambda:us-east-1:123:layer:tscloud-php-83:1'],
20
+ * })
21
+ */
22
+ export declare function createServerlessLaravelPreset(options: {
23
+ name: string;
24
+ slug: string;
25
+ domain?: string;
26
+ /** PHP runtime layer ARN(s). If omitted, set TSCLOUD_PHP_LAYER_ARN at deploy. */
27
+ layers?: string[];
28
+ phpVersion?: '8.1' | '8.2' | '8.3' | '8.4';
29
+ architecture?: 'x86_64' | 'arm64';
30
+ memory?: number;
31
+ /** Override build hooks (defaults to Laravel artisan caching). */
32
+ build?: string[];
33
+ /** Override deploy hooks (defaults to `migrate --force`). */
34
+ deploy?: string[];
35
+ cache?: 'dynamodb' | 'elasticache';
36
+ scheduler?: 'off' | 'on' | 'sub-minute';
37
+ region?: string;
38
+ }): Partial<CloudConfig>;
@@ -0,0 +1,36 @@
1
+ import type { CloudConfig } from '../types';
2
+ /**
3
+ * Serverless Node/Bun application preset (Laravel-Vapor-equivalent for JS/TS).
4
+ *
5
+ * Produces an `environments.<env>.app` manifest that the serverless deploy
6
+ * pipeline (`cloud deploy:serverless`) turns into three Lambda functions sharing
7
+ * one bundled artifact: HTTP (API Gateway v2), queue worker (SQS), and CLI
8
+ * (EventBridge scheduler + on-demand commands), plus a DynamoDB cache table and
9
+ * optional CDN-backed assets.
10
+ *
11
+ * @example
12
+ * export default createServerlessNodePreset({
13
+ * name: 'My API', slug: 'my-api',
14
+ * entry: 'src/server.ts', domain: 'api.example.com',
15
+ * build: ['bun install', 'bun run build'],
16
+ * deploy: ['migrate'],
17
+ * })
18
+ */
19
+ export declare function createServerlessNodePreset(options: {
20
+ name: string;
21
+ slug: string;
22
+ entry: string;
23
+ domain?: string;
24
+ runtime?: 'nodejs20.x' | 'nodejs22.x';
25
+ memory?: number;
26
+ /** Build commands run locally before packaging. */
27
+ build?: string[];
28
+ /** Deploy commands run remotely after activation (e.g. migrations). */
29
+ deploy?: string[];
30
+ /** Static asset directory served via CloudFront (e.g. `public` or `dist`). */
31
+ assets?: string;
32
+ /** Queue names; defaults to a single `default` queue. */
33
+ queues?: boolean | Array<string | Record<string, number>>;
34
+ scheduler?: 'off' | 'on' | 'sub-minute';
35
+ region?: string;
36
+ }): Partial<CloudConfig>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Generates the application container-image Dockerfile for serverless apps that
3
+ * exceed the 250 MB zip/layer limit (`packaging: 'image'`). Lambda runs the
4
+ * image directly (up to 10 GB).
5
+ *
6
+ * - Node/Bun: FROM the AWS Lambda Node base image; the bundled handler is copied
7
+ * to the task root and the function's `ImageConfig.Command` selects the export.
8
+ * - PHP: a self-contained multi-stage build — stage 1 compiles + relocates PHP
9
+ * (the same recipe as the runtime layer), stage 2 is the `provided.al2023`
10
+ * base with /opt (runtime) + /var/task (app) baked in; the bootstrap selects
11
+ * the mode from `TSCLOUD_LAMBDA_MODE`.
12
+ */
13
+ export interface AppImageDockerfileOptions {
14
+ kind: 'node' | 'bun' | 'php';
15
+ /** Node runtime tag (e.g. '20') — used for the Lambda Node base image. */
16
+ nodeMajor?: string;
17
+ /** PHP version for the runtime build stage (kind: 'php'). @default '8.3' */
18
+ phpVersion?: string;
19
+ /** CPU architecture (documented; the build uses --platform at build time). */
20
+ architecture?: 'x86_64' | 'arm64';
21
+ }
22
+ export declare function generateAppImageDockerfile(options: AppImageDockerfileOptions): string;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Generates the bootstrap entry module that is bundled as the Lambda artifact's
3
+ * top-level handler file. It imports the user's application entry plus the
4
+ * runtime adapter, then re-exports the three Lambda handlers (`http`, `queue`,
5
+ * `cli`) that API Gateway / SQS / EventBridge invoke.
6
+ */
7
+ export interface BootstrapOptions {
8
+ /** Import specifier for the user's app entry (absolute path or bare module). */
9
+ entryImport: string;
10
+ /** Import specifier for the runtime adapter. @default './adapter' */
11
+ adapterImport?: string;
12
+ }
13
+ export declare function generateBootstrap(opts: BootstrapOptions): string;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Composes the CloudFormation template for a Vapor-style serverless application:
3
+ * one code artifact wired into three Lambda functions (http/queue/cli) plus the
4
+ * surrounding infrastructure (API Gateway v2, SQS + DLQ, EventBridge scheduler,
5
+ * DynamoDB cache, assets S3 + CloudFront, IAM role, log groups).
6
+ *
7
+ * Activation model (v1): functions target `$LATEST`. The deploy orchestrator
8
+ * swaps code with `UpdateFunctionCode` (fast, atomic per function) and passes the
9
+ * current artifact via the `ArtifactBucket` / `ArtifactKey` stack parameters so
10
+ * stack updates never revert the deployed code. Alias-based blue/green is a v2
11
+ * refinement.
12
+ */
13
+ import type { CloudConfig, EnvironmentType, ServerlessAppConfig } from '../types';
14
+ import type { CloudFormationTemplate } from '../cloudformation/types';
15
+ export interface ComposeOptions {
16
+ config: Pick<CloudConfig, 'project'>;
17
+ environment: EnvironmentType;
18
+ app: ServerlessAppConfig;
19
+ /** Lambda handler strings per function (from packaging). */
20
+ handlers: {
21
+ http: string;
22
+ queue: string;
23
+ cli: string;
24
+ };
25
+ /** Custom-runtime layer ARNs (PHP). */
26
+ runtimeLayers?: string[];
27
+ }
28
+ export interface ComposedTemplate {
29
+ template: CloudFormationTemplate;
30
+ /** Deterministic Lambda function names the orchestrator drives directly. */
31
+ functionNames: {
32
+ http: string;
33
+ queue: string;
34
+ cli: string;
35
+ };
36
+ /** SQS queue names created (for the orchestrator + CLI commands). */
37
+ queueNames: string[];
38
+ /** Count of resources by CloudFormation type (for deploy summaries). */
39
+ resourceSummary: Record<string, number>;
40
+ }
41
+ /** Resolve the SQS queue names from the manifest. */
42
+ export declare function resolveQueueNames(app: ServerlessAppConfig, slug: string, env: EnvironmentType): string[];
43
+ export declare function composeServerlessAppTemplate(opts: ComposeOptions): ComposedTemplate;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Serverless application pipeline (Laravel-Vapor-equivalent) for Node/Bun apps.
3
+ * Packaging, the runtime adapter, and the CloudFormation composer.
4
+ */
5
+ export * from './zip';
6
+ export * from './bootstrap';
7
+ export * from './package';
8
+ export * from './composer';
9
+ export * from './app-image';
10
+ export * from './runtime/adapter';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Packages a Node/Bun serverless application into a single Lambda deployment
3
+ * artifact (a ZIP holding one bundled handler file). The same artifact backs all
4
+ * three functions (http/queue/cli); they differ only by handler export.
5
+ *
6
+ * Flow: run build hooks → write a generated bootstrap that wires the user's
7
+ * entry to the runtime adapter → bundle with `Bun.build` (target node) → ZIP →
8
+ * content-hash. The hash is the artifact identity used for skip-by-hash uploads,
9
+ * redeploys, and rollbacks.
10
+ */
11
+ import type { ServerlessAppConfig } from '../types';
12
+ export interface PackageOptions {
13
+ /** Project root the entry/build hooks resolve against. @default process.cwd() */
14
+ projectRoot?: string;
15
+ /** The serverless app manifest. */
16
+ app: ServerlessAppConfig;
17
+ /** Skip running `app.build` hooks (already run by the orchestrator). */
18
+ skipBuild?: boolean;
19
+ /** Progress callback. */
20
+ onStep?: (message: string) => void;
21
+ }
22
+ export interface PackagedArtifact {
23
+ /** The ZIP bytes ready to upload to S3 / Lambda. */
24
+ zip: Buffer;
25
+ /** The raw bundled JS (before zipping) — used for container-image builds. */
26
+ bundle: Buffer;
27
+ /** SHA-256 of the ZIP bytes (hex). Stable for identical inputs. */
28
+ sha256: string;
29
+ /** Handler file basename inside the artifact (no extension), e.g. `index`. */
30
+ handlerFile: string;
31
+ /** Lambda handler strings for each function. */
32
+ handlers: {
33
+ http: string;
34
+ queue: string;
35
+ cli: string;
36
+ };
37
+ /** Size of the bundled JS before zipping. */
38
+ bundleBytes: number;
39
+ }
40
+ /** Run build hooks locally, failing fast on the first non-zero exit. */
41
+ export declare function runBuildHooks(hooks: string[] | undefined, cwd: string, onStep?: (m: string) => void): void;
42
+ /** SHA-256 hex of arbitrary bytes. */
43
+ export declare function sha256(data: Buffer | Uint8Array | string): string;
44
+ /** S3 key for a deployment artifact, namespaced by project/env and content hash. */
45
+ export declare function artifactKey(slug: string, environment: string, hash: string): string;
46
+ export declare function packageServerlessApp(opts: PackageOptions): Promise<PackagedArtifact>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Serverless runtime adapter (Node/Bun).
3
+ *
4
+ * This module is **bundled into the Lambda deployment artifact** and runs inside
5
+ * the AWS Lambda Node.js runtime, so it must rely only on globals available
6
+ * there: `Request`, `Response`, `Headers`, `URL`, `Buffer`, `atob`/`btoa`.
7
+ * It contains no AWS SDK calls and no Node-only filesystem access.
8
+ *
9
+ * It translates the three event sources of a Vapor-style serverless app into
10
+ * plain, framework-agnostic callbacks:
11
+ * - HTTP : API Gateway v2 (payload format 2.0) ⇄ WHATWG `Request`/`Response`
12
+ * - Queue : SQS records → per-message job handler with partial-batch failures
13
+ * - CLI : `{ command, args }` → command handler (scheduler / migrations)
14
+ */
15
+ export interface ApiGatewayProxyEventV2 {
16
+ version: '2.0';
17
+ rawPath: string;
18
+ rawQueryString?: string;
19
+ cookies?: string[];
20
+ headers?: Record<string, string | undefined>;
21
+ body?: string;
22
+ isBase64Encoded?: boolean;
23
+ requestContext: {
24
+ domainName?: string;
25
+ http: {
26
+ method: string;
27
+ path: string;
28
+ protocol?: string;
29
+ sourceIp?: string;
30
+ userAgent?: string;
31
+ };
32
+ };
33
+ }
34
+ export interface ApiGatewayProxyResultV2 {
35
+ statusCode: number;
36
+ headers?: Record<string, string>;
37
+ cookies?: string[];
38
+ body?: string;
39
+ isBase64Encoded?: boolean;
40
+ }
41
+ export interface SqsRecord {
42
+ messageId: string;
43
+ receiptHandle?: string;
44
+ body: string;
45
+ attributes?: Record<string, string>;
46
+ messageAttributes?: Record<string, unknown>;
47
+ eventSourceARN?: string;
48
+ }
49
+ export interface SqsEvent {
50
+ Records: SqsRecord[];
51
+ }
52
+ export interface SqsBatchResponse {
53
+ batchItemFailures: Array<{
54
+ itemIdentifier: string;
55
+ }>;
56
+ }
57
+ export interface CliEvent {
58
+ command: string;
59
+ args?: string[];
60
+ }
61
+ export interface CliResult {
62
+ statusCode: number;
63
+ output: string;
64
+ }
65
+ export type FetchHandler = (request: Request) => Response | Promise<Response>;
66
+ export type JobHandler = (payload: unknown, record: SqsRecord) => unknown | Promise<unknown>;
67
+ export type CommandHandler = (event: CliEvent) => CliResult | Promise<CliResult>;
68
+ /** Lambda handler invoked by API Gateway v2. */
69
+ export type LambdaHttpHandler = (event: ApiGatewayProxyEventV2) => Promise<ApiGatewayProxyResultV2>;
70
+ /** Lambda handler invoked by an SQS event source mapping. */
71
+ export type LambdaQueueHandler = (event: SqsEvent) => Promise<SqsBatchResponse>;
72
+ /** Lambda handler invoked by EventBridge / on-demand for CLI commands. */
73
+ export type LambdaCliHandler = (event: CliEvent) => Promise<CliResult>;
74
+ export interface ServerlessApp {
75
+ fetch?: FetchHandler;
76
+ queue?: JobHandler;
77
+ cli?: CommandHandler;
78
+ }
79
+ /**
80
+ * Normalize whatever the user's entry module exports into a {@link ServerlessApp}.
81
+ * Accepts a bare fetch function, an object with `fetch`/`queue`/`cli`, or a
82
+ * Bun.serve-style `{ default: { fetch } }`.
83
+ */
84
+ export declare function resolveApp(mod: unknown): ServerlessApp;
85
+ export interface HttpAdapterOptions {
86
+ /**
87
+ * Read maintenance state from the environment. When `MAINTENANCE_MODE` is
88
+ * truthy, requests get a 503 unless they carry the bypass secret in the
89
+ * `x-maintenance-bypass` header or a `tscloud_bypass` cookie.
90
+ */
91
+ maintenance?: {
92
+ enabled: boolean;
93
+ bypassSecret?: string;
94
+ };
95
+ }
96
+ /** Translate an API Gateway v2 event into a WHATWG `Request`. */
97
+ export declare function eventToRequest(event: ApiGatewayProxyEventV2): Request;
98
+ /** Serialize a WHATWG `Response` into an API Gateway v2 result. */
99
+ export declare function responseToResult(response: Response): Promise<ApiGatewayProxyResultV2>;
100
+ /**
101
+ * Wrap a fetch-style handler into a Lambda HTTP handler for API Gateway v2.
102
+ * Honors maintenance mode (503 + bypass) before invoking the app.
103
+ */
104
+ export declare function createHttpHandler(handler: FetchHandler | undefined, opts?: HttpAdapterOptions): LambdaHttpHandler;
105
+ /**
106
+ * Wrap a job handler into a Lambda SQS handler. Each record is processed
107
+ * individually; failures are reported via `batchItemFailures` so only failed
108
+ * messages are retried (requires `ReportBatchItemFailures` on the mapping).
109
+ */
110
+ export declare function createQueueHandler(handler: JobHandler | undefined): LambdaQueueHandler;
111
+ /**
112
+ * Wrap a command handler into a Lambda CLI handler. Used by the EventBridge
113
+ * scheduler (`{ command: 'schedule:run' }`) and on-demand invocations
114
+ * (deploy hooks, migrations, `cloud command`).
115
+ */
116
+ export declare function createCliHandler(handler: CommandHandler | undefined): LambdaCliHandler;
117
+ /** Convenience: build all three Lambda handlers from a resolved app. */
118
+ export declare function createHandlers(app: ServerlessApp, opts?: HttpAdapterOptions): {
119
+ http: LambdaHttpHandler;
120
+ queue: LambdaQueueHandler;
121
+ cli: LambdaCliHandler;
122
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Minimal, dependency-free ZIP writer for Lambda deployment artifacts.
3
+ *
4
+ * Lambda deployment packages must be ZIP archives. This generalizes the
5
+ * single-file writer in `ts-cloud/src/aws/lambda.ts` to multiple files so the
6
+ * same code path serves a bundled Node/Bun handler (one file) and a full
7
+ * PHP/Laravel application tree (many files). Uses Node's `zlib` only — no
8
+ * third-party zip dependency, in keeping with the zero-dependency ethos.
9
+ */
10
+ export interface ZipEntry {
11
+ /** POSIX path inside the archive (forward slashes). */
12
+ name: string;
13
+ /** File contents. */
14
+ data: Buffer | Uint8Array | string;
15
+ /** Unix file mode (e.g. 0o755 for an executable `bootstrap`). @default 0o644 */
16
+ mode?: number;
17
+ /** Last-modified date; defaults to the Unix epoch for reproducible artifacts. */
18
+ date?: Date;
19
+ }
20
+ /**
21
+ * Build a ZIP archive from a set of entries. Files are deflate-compressed.
22
+ * External attributes encode the Unix mode so executables stay executable on
23
+ * extraction (required for a custom-runtime `bootstrap`).
24
+ */
25
+ export declare function createZip(entries: ZipEntry[]): Buffer;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Generates the Dockerfile that builds the ts-cloud PHP runtime layer for AWS
3
+ * Lambda (`provided.al2023`). Built against Amazon Linux 2023 so glibc and the
4
+ * shared libraries match the Lambda execution environment.
5
+ *
6
+ * AL2023's default repos can't select an arbitrary PHP minor version, so we use
7
+ * the Remi repository's SCL-style packages (`php83-php-*`, installed under
8
+ * `/opt/remi/php83/`), which lets the same recipe build PHP 8.1–8.4. The PHP
9
+ * binary, php-fpm, extensions, and their shared-library dependencies are then
10
+ * relocated under `/opt` so the archive works as a Lambda layer.
11
+ *
12
+ * Build it in CI (Docker required) — see {@link buildPhpRuntimeLayerZip}. The
13
+ * resulting /opt tree is published as a Lambda layer.
14
+ */
15
+ /**
16
+ * Laravel + serverless extension suffixes (appended to the `php{XY}-php-` Remi
17
+ * SCL prefix). `process` provides pcntl/posix; `pecl-redis6` the redis driver.
18
+ */
19
+ export declare const PHP_LAYER_EXTENSIONS: string[];
20
+ /** Full Remi SCL package names for a given PHP version (e.g. '8.3' → php83-php-*). */
21
+ export declare function phpLayerPackages(phpVersion: string): string[];
22
+ export interface PhpDockerfileOptions {
23
+ /** PHP version: 8.1 | 8.2 | 8.3 | 8.4. @default '8.3' */
24
+ phpVersion?: string;
25
+ }
26
+ /**
27
+ * The `FROM amazonlinux:2023 … /opt` build stage that compiles + relocates PHP.
28
+ * Shared by the standalone layer build and the multi-stage app-image build.
29
+ * Pass `asName` to emit `FROM amazonlinux:2023 AS <name>` for multi-stage use.
30
+ */
31
+ export declare function phpLayerBuildStage(phpVersion: string, asName?: string): string;
32
+ /**
33
+ * Standalone Dockerfile that builds the PHP runtime layer payload at /opt.
34
+ * Used by {@link buildPhpRuntimeLayerZip}.
35
+ */
36
+ export declare function generatePhpLayerDockerfile(options?: PhpDockerfileOptions): string;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * PHP/Laravel-on-Lambda runtime (true Laravel-Vapor clone).
3
+ * Custom runtime layer assets, FPM bridge config, Dockerfile + layer builder,
4
+ * and Laravel serverless environment defaults.
5
+ */
6
+ export * from './php-fpm-conf';
7
+ export * from './runtime-assets';
8
+ export * from './dockerfile';
9
+ export * from './layer-build';
10
+ export * from './package-php';
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Builds the ts-cloud PHP runtime layer ZIP.
3
+ *
4
+ * Runs the generated Dockerfile to produce a /opt tree (PHP + php-fpm +
5
+ * extensions for AL2023), extracts it, injects the runtime assets
6
+ * (bootstrap/runtime loops/fpm config), and packages everything as a Lambda
7
+ * layer ZIP. Publishing the ZIP as a layer version is done by the CLI using the
8
+ * ts-cloud Lambda client; this module only produces the artifact.
9
+ *
10
+ * Requires Docker. Intended to run in CI to publish a versioned, ts-cloud-owned
11
+ * layer that user deploys reference (no per-deploy compilation).
12
+ */
13
+ import { type PhpDockerfileOptions } from './dockerfile';
14
+ export interface BuildPhpLayerOptions extends PhpDockerfileOptions {
15
+ /** Target architecture. @default 'x86_64' */
16
+ architecture?: 'x86_64' | 'arm64';
17
+ /** Docker platform override (defaults from architecture). */
18
+ platform?: string;
19
+ /** Progress callback. */
20
+ onStep?: (message: string) => void;
21
+ }
22
+ export interface PhpLayerArtifact {
23
+ /** The Lambda layer ZIP bytes. */
24
+ zip: Buffer;
25
+ /** Compatible architecture. */
26
+ architecture: 'x86_64' | 'arm64';
27
+ /** Number of files in the layer. */
28
+ fileCount: number;
29
+ }
30
+ /**
31
+ * Build the PHP runtime layer ZIP via Docker. Throws if Docker is unavailable.
32
+ */
33
+ export declare function buildPhpRuntimeLayerZip(options?: BuildPhpLayerOptions): PhpLayerArtifact;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Packages a Laravel/PHP application into a Lambda deployment artifact.
3
+ *
4
+ * Unlike the Node/Bun path (which bundles a single JS file), a PHP app ships its
5
+ * whole source tree (vendor/ + app/ + public/ + bootstrap/ …). The PHP binary,
6
+ * php-fpm, and the runtime loop come from the PHP runtime layer, not the artifact.
7
+ * Build hooks (composer install + artisan caches) run before packaging because
8
+ * the Lambda filesystem is read-only at runtime.
9
+ */
10
+ import type { ServerlessAppConfig } from '../types';
11
+ import { type ZipEntry } from '../serverless/zip';
12
+ /** Paths excluded from the PHP deployment artifact by default. */
13
+ export declare const PHP_DEFAULT_EXCLUDES: string[];
14
+ export interface PackagePhpOptions {
15
+ projectRoot?: string;
16
+ app: ServerlessAppConfig;
17
+ skipBuild?: boolean;
18
+ /** Extra path prefixes (relative to root) to exclude. */
19
+ exclude?: string[];
20
+ onStep?: (message: string) => void;
21
+ }
22
+ export interface PackagedPhpArtifact {
23
+ zip: Buffer;
24
+ sha256: string;
25
+ handlers: {
26
+ http: string;
27
+ queue: string;
28
+ cli: string;
29
+ };
30
+ fileCount: number;
31
+ }
32
+ /**
33
+ * Run the PHP build hooks (composer install + artisan caches) for a project.
34
+ * Defaults to the Laravel serverless caching steps when none are configured.
35
+ */
36
+ export declare function runPhpBuildHooks(opts: PackagePhpOptions): void;
37
+ /**
38
+ * Collect the PHP application file tree (respecting excludes) as zip entries.
39
+ * Shared by {@link packagePhpApp} (zips) and the container-image staging (writes
40
+ * the entries to a build context).
41
+ */
42
+ export declare function collectPhpAppEntries(projectRoot: string, exclude?: string[]): ZipEntry[];
43
+ export declare function packagePhpApp(opts: PackagePhpOptions): PackagedPhpArtifact;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generates the php-fpm.conf used by the ts-cloud PHP Lambda runtime.
3
+ *
4
+ * A Lambda container serves exactly one request at a time, so FPM is configured
5
+ * with a single static worker listening on a unix socket in /tmp (the only
6
+ * writable location). Output goes to stderr → CloudWatch.
7
+ */
8
+ export interface PhpFpmConfigOptions {
9
+ /** Unix socket path FPM listens on. @default '/tmp/.tscloud-fpm.sock' */
10
+ socketPath?: string;
11
+ /** Workers per container. Lambda is single-request, so 1 is correct. @default 1 */
12
+ maxChildren?: number;
13
+ /** php-fpm error log path. @default '/tmp/storage/logs/php-fpm.log' */
14
+ errorLog?: string;
15
+ }
16
+ export declare function generatePhpFpmConfig(options?: PhpFpmConfigOptions): string;