@ts-cloud/core 0.3.0 → 0.4.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/index.js CHANGED
@@ -25170,7 +25170,8 @@ var cloud_config_schema_default = {
25170
25170
  type: "object",
25171
25171
  description: "Serverless application manifest (Laravel-Vapor-equivalent). Defining this opts the environment into the serverless app deploy pipeline (http/queue/cli Lambda functions, assets, build/deploy hooks).",
25172
25172
  properties: {
25173
- runtime: { type: "string", description: "Lambda runtime (e.g. nodejs20.x, provided.al2023)" },
25173
+ runtime: { type: "string", description: "Lambda runtime override (usually derived from kind + runtimeVersion)" },
25174
+ runtimeVersion: { type: "string", description: "Node major (18/20/22 managed, 24+ custom layer) or Bun release for node/bun apps" },
25174
25175
  kind: { type: "string", enum: ["node", "bun", "php"], description: "Application kind (drives packaging + runtime)" },
25175
25176
  entry: { type: "string", description: "Entry file exporting the request handler" },
25176
25177
  memory: { type: "number", description: "HTTP function memory in MB" },
@@ -45281,7 +45282,7 @@ async function packageServerlessApp(opts) {
45281
45282
  opts.onStep?.("bundling application");
45282
45283
  const result = await Bun.build({
45283
45284
  entrypoints: [bootstrapPath],
45284
- target: "node",
45285
+ target: app.kind === "bun" ? "bun" : "node",
45285
45286
  format: "esm",
45286
45287
  minify: false,
45287
45288
  sourcemap: "none"
@@ -45312,6 +45313,57 @@ ${logs}`);
45312
45313
  rmSync(stage, { recursive: true, force: true });
45313
45314
  }
45314
45315
  }
45316
+ // src/serverless/runtime-resolve.ts
45317
+ var MANAGED_NODE_VERSIONS = ["18", "20", "22"];
45318
+ function normalizeNodeVersion(v) {
45319
+ if (!v)
45320
+ return "22";
45321
+ const m = String(v).match(/(\d+)/);
45322
+ return m ? m[1] : "22";
45323
+ }
45324
+ function resolveServerlessRuntime(app) {
45325
+ const kind = app.kind ?? "node";
45326
+ if (kind === "php") {
45327
+ return {
45328
+ lambdaRuntime: "provided.al2023",
45329
+ kind: "php",
45330
+ version: app.phpVersion ?? "8.3",
45331
+ usesLayer: true,
45332
+ layerKind: "php",
45333
+ layerEnvVar: "TSCLOUD_PHP_LAYER_ARN"
45334
+ };
45335
+ }
45336
+ if (kind === "bun") {
45337
+ return {
45338
+ lambdaRuntime: "provided.al2023",
45339
+ kind: "bun",
45340
+ version: app.runtimeVersion ?? "latest",
45341
+ usesLayer: true,
45342
+ layerKind: "bun",
45343
+ layerEnvVar: "TSCLOUD_BUN_LAYER_ARN"
45344
+ };
45345
+ }
45346
+ const version = normalizeNodeVersion(app.runtimeVersion);
45347
+ const explicitProvided = app.runtime === "provided.al2023";
45348
+ const managed = !explicitProvided && MANAGED_NODE_VERSIONS.includes(version);
45349
+ if (managed) {
45350
+ return {
45351
+ lambdaRuntime: app.runtime && app.runtime.startsWith("nodejs") ? app.runtime : `nodejs${version}.x`,
45352
+ kind: "node",
45353
+ version,
45354
+ usesLayer: false
45355
+ };
45356
+ }
45357
+ return {
45358
+ lambdaRuntime: "provided.al2023",
45359
+ kind: "node",
45360
+ version,
45361
+ usesLayer: true,
45362
+ layerKind: "node",
45363
+ layerEnvVar: "TSCLOUD_NODE_LAYER_ARN"
45364
+ };
45365
+ }
45366
+
45315
45367
  // src/serverless/composer.ts
45316
45368
  function resolveQueueNames(app, slug, env) {
45317
45369
  if (app.queues === false)
@@ -45326,7 +45378,7 @@ function resolveQueueNames(app, slug, env) {
45326
45378
  function composeServerlessAppTemplate(opts) {
45327
45379
  const { app, environment, handlers } = opts;
45328
45380
  const slug = opts.config.project.slug;
45329
- const runtime = app.runtime ?? "nodejs20.x";
45381
+ const runtime = resolveServerlessRuntime(app).lambdaRuntime;
45330
45382
  const architecture = app.architecture ?? "x86_64";
45331
45383
  const region = opts.config.project.region;
45332
45384
  const functionNames = {
@@ -45951,6 +46003,85 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
45951
46003
  CMD [ "index.http" ]
45952
46004
  `;
45953
46005
  }
46006
+ // src/serverless/runtimes/index.ts
46007
+ import { execFileSync } from "node:child_process";
46008
+ import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, rmSync as rmSync2 } from "node:fs";
46009
+ import { tmpdir as tmpdir2 } from "node:os";
46010
+ import { dirname as dirname3, join as join7 } from "node:path";
46011
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
46012
+ function assetsDir() {
46013
+ return dirname3(fileURLToPath2(import.meta.url));
46014
+ }
46015
+ function sharedRuntimeLoop() {
46016
+ return readFileSync4(join7(assetsDir(), "runtime.mjs"), "utf-8");
46017
+ }
46018
+ function bootstrap(kind) {
46019
+ return readFileSync4(join7(assetsDir(), `${kind}-bootstrap`), "utf-8");
46020
+ }
46021
+ function buildNodeRuntimeLayerZip(options) {
46022
+ const architecture = options.architecture ?? "x86_64";
46023
+ const nodeArch = architecture === "arm64" ? "arm64" : "x64";
46024
+ const version = options.version.replace(/^v/, "");
46025
+ const step = options.onStep ?? (() => {});
46026
+ const stage = mkdtempSync2(join7(tmpdir2(), "tscloud-node-layer-"));
46027
+ try {
46028
+ const exact = version.includes(".") ? version : resolveLatestNode(version);
46029
+ const dir = `node-v${exact}-linux-${nodeArch}`;
46030
+ const url = `https://nodejs.org/dist/v${exact}/${dir}.tar.xz`;
46031
+ step(`downloading Node ${exact} (${architecture})`);
46032
+ const tar = join7(stage, "node.tar.xz");
46033
+ fetchToFile(url, tar);
46034
+ step("extracting node binary");
46035
+ execFileSync("tar", ["-xf", tar, "-C", stage, `${dir}/bin/node`], { stdio: "inherit" });
46036
+ const nodeBin = readFileSync4(join7(stage, dir, "bin", "node"));
46037
+ step("packaging layer");
46038
+ const entries = [
46039
+ { name: "bootstrap", data: bootstrap("node"), mode: 493 },
46040
+ { name: "runtime.mjs", data: sharedRuntimeLoop(), mode: 420 },
46041
+ { name: "bin/node", data: nodeBin, mode: 493 }
46042
+ ];
46043
+ return { zip: createZip(entries), architecture, version: exact, fileCount: entries.length };
46044
+ } finally {
46045
+ rmSync2(stage, { recursive: true, force: true });
46046
+ }
46047
+ }
46048
+ function buildBunRuntimeLayerZip(options) {
46049
+ const architecture = options.architecture ?? "x86_64";
46050
+ const bunArch = architecture === "arm64" ? "bun-linux-aarch64" : "bun-linux-x64";
46051
+ const version = options.version === "latest" ? "" : options.version.replace(/^v/, "");
46052
+ const step = options.onStep ?? (() => {});
46053
+ const stage = mkdtempSync2(join7(tmpdir2(), "tscloud-bun-layer-"));
46054
+ try {
46055
+ const tag = version ? `bun-v${version}` : "latest";
46056
+ const url = `https://github.com/oven-sh/bun/releases/download/${tag}/${bunArch}.zip`;
46057
+ step(`downloading Bun ${version || "latest"} (${architecture})`);
46058
+ const zipPath = join7(stage, "bun.zip");
46059
+ fetchToFile(url, zipPath);
46060
+ step("extracting bun binary");
46061
+ execFileSync("unzip", ["-o", "-q", zipPath, "-d", stage], { stdio: "inherit" });
46062
+ const bunBin = readFileSync4(join7(stage, bunArch, "bun"));
46063
+ step("packaging layer");
46064
+ const entries = [
46065
+ { name: "bootstrap", data: bootstrap("bun"), mode: 493 },
46066
+ { name: "runtime.mjs", data: sharedRuntimeLoop(), mode: 420 },
46067
+ { name: "bin/bun", data: bunBin, mode: 493 }
46068
+ ];
46069
+ return { zip: createZip(entries), architecture, version: version || "latest", fileCount: entries.length };
46070
+ } finally {
46071
+ rmSync2(stage, { recursive: true, force: true });
46072
+ }
46073
+ }
46074
+ function fetchToFile(url, dest) {
46075
+ execFileSync("curl", ["-fsSL", "-o", dest, url], { stdio: ["ignore", "ignore", "inherit"] });
46076
+ }
46077
+ function resolveLatestNode(major) {
46078
+ const indexJson = execFileSync("curl", ["-fsSL", "https://nodejs.org/dist/index.json"], { encoding: "utf-8" });
46079
+ const releases = JSON.parse(indexJson);
46080
+ const match = releases.find((r) => r.version.startsWith(`v${major}.`));
46081
+ if (!match)
46082
+ throw new Error(`No Node release found for major version ${major}`);
46083
+ return match.version.replace(/^v/, "");
46084
+ }
45954
46085
  // src/serverless/runtime/adapter.ts
45955
46086
  function resolveApp(mod) {
45956
46087
  const m = mod;
@@ -46103,15 +46234,15 @@ clear_env = no
46103
46234
  `;
46104
46235
  }
46105
46236
  // src/serverless-php/runtime-assets.ts
46106
- import { readFileSync as readFileSync4 } from "node:fs";
46107
- import { dirname as dirname3, join as join7 } from "node:path";
46108
- import { fileURLToPath as fileURLToPath2 } from "node:url";
46109
- function assetsDir() {
46110
- return join7(dirname3(fileURLToPath2(import.meta.url)), "runtime-assets");
46237
+ import { readFileSync as readFileSync5 } from "node:fs";
46238
+ import { dirname as dirname4, join as join8 } from "node:path";
46239
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
46240
+ function assetsDir2() {
46241
+ return join8(dirname4(fileURLToPath3(import.meta.url)), "runtime-assets");
46111
46242
  }
46112
46243
  function phpRuntimeLayerAssets() {
46113
- const dir = assetsDir();
46114
- const read = (f) => readFileSync4(join7(dir, f), "utf-8");
46244
+ const dir = assetsDir2();
46245
+ const read = (f) => readFileSync5(join8(dir, f), "utf-8");
46115
46246
  return [
46116
46247
  { path: "bootstrap", contents: read("bootstrap"), mode: 493 },
46117
46248
  { path: "tscloud/runtime.php", contents: read("runtime.php"), mode: 420 },
@@ -46147,13 +46278,13 @@ var LARAVEL_SERVERLESS_BUILD_STEPS = [
46147
46278
  "php artisan view:cache"
46148
46279
  ];
46149
46280
  // src/serverless-php/layer-build.ts
46150
- import { execFileSync } from "node:child_process";
46151
- import { existsSync as existsSync5, mkdtempSync as mkdtempSync2, readdirSync as readdirSync5, readFileSync as readFileSync5, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync4 } from "node:fs";
46152
- import { tmpdir as tmpdir2 } from "node:os";
46153
- import { join as join8, relative as relative2 } from "node:path";
46281
+ import { execFileSync as execFileSync2 } from "node:child_process";
46282
+ import { existsSync as existsSync5, mkdtempSync as mkdtempSync3, readdirSync as readdirSync5, readFileSync as readFileSync6, rmSync as rmSync3, statSync as statSync3, writeFileSync as writeFileSync5 } from "node:fs";
46283
+ import { tmpdir as tmpdir3 } from "node:os";
46284
+ import { join as join9, relative as relative2 } from "node:path";
46154
46285
  function* walk(dir) {
46155
46286
  for (const entry of readdirSync5(dir)) {
46156
- const full = join8(dir, entry);
46287
+ const full = join9(dir, entry);
46157
46288
  if (statSync3(full).isDirectory())
46158
46289
  yield* walk(full);
46159
46290
  else
@@ -46164,19 +46295,19 @@ function buildPhpRuntimeLayerZip(options = {}) {
46164
46295
  const architecture = options.architecture ?? "x86_64";
46165
46296
  const platform = options.platform ?? (architecture === "arm64" ? "linux/arm64" : "linux/amd64");
46166
46297
  const step = options.onStep ?? (() => {});
46167
- const stage = mkdtempSync2(join8(tmpdir2(), "tscloud-php-layer-"));
46298
+ const stage = mkdtempSync3(join9(tmpdir3(), "tscloud-php-layer-"));
46168
46299
  const imageTag = "tscloud-php-layer:build";
46169
46300
  try {
46170
- writeFileSync4(join8(stage, "Dockerfile"), generatePhpLayerDockerfile(options));
46301
+ writeFileSync5(join9(stage, "Dockerfile"), generatePhpLayerDockerfile(options));
46171
46302
  step("Building PHP runtime image (docker)");
46172
- execFileSync("docker", ["build", "--platform", platform, "-t", imageTag, stage], { stdio: "inherit" });
46303
+ execFileSync2("docker", ["build", "--platform", platform, "-t", imageTag, stage], { stdio: "inherit" });
46173
46304
  step("Extracting /opt from image");
46174
- const cid = execFileSync("docker", ["create", "--platform", platform, imageTag], { encoding: "utf-8" }).trim();
46175
- const optDir = join8(stage, "opt");
46305
+ const cid = execFileSync2("docker", ["create", "--platform", platform, imageTag], { encoding: "utf-8" }).trim();
46306
+ const optDir = join9(stage, "opt");
46176
46307
  try {
46177
- execFileSync("docker", ["cp", `${cid}:/opt/.`, optDir], { stdio: "inherit" });
46308
+ execFileSync2("docker", ["cp", `${cid}:/opt/.`, optDir], { stdio: "inherit" });
46178
46309
  } finally {
46179
- execFileSync("docker", ["rm", cid], { stdio: "ignore" });
46310
+ execFileSync2("docker", ["rm", cid], { stdio: "ignore" });
46180
46311
  }
46181
46312
  if (!existsSync5(optDir))
46182
46313
  throw new Error("layer build produced no /opt directory");
@@ -46184,7 +46315,7 @@ function buildPhpRuntimeLayerZip(options = {}) {
46184
46315
  for (const file of walk(optDir)) {
46185
46316
  const rel = relative2(optDir, file).replace(/\\/g, "/");
46186
46317
  const mode = statSync3(file).mode & 73 ? 493 : 420;
46187
- entries.push({ name: rel, data: readFileSync5(file), mode });
46318
+ entries.push({ name: rel, data: readFileSync6(file), mode });
46188
46319
  }
46189
46320
  step("Injecting runtime assets");
46190
46321
  const assetPaths = new Set(phpRuntimeLayerAssets().map((a) => a.path));
@@ -46196,14 +46327,14 @@ function buildPhpRuntimeLayerZip(options = {}) {
46196
46327
  const zip2 = createZip(filtered);
46197
46328
  return { zip: zip2, architecture, fileCount: filtered.length };
46198
46329
  } finally {
46199
- rmSync2(stage, { recursive: true, force: true });
46330
+ rmSync3(stage, { recursive: true, force: true });
46200
46331
  }
46201
46332
  }
46202
46333
  // src/serverless-php/package-php.ts
46203
46334
  import { execSync as execSync2 } from "node:child_process";
46204
46335
  import { createHash as createHash5 } from "node:crypto";
46205
- import { readdirSync as readdirSync6, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
46206
- import { join as join9, relative as relative3, resolve as resolve2 } from "node:path";
46336
+ import { readdirSync as readdirSync6, readFileSync as readFileSync7, statSync as statSync4 } from "node:fs";
46337
+ import { join as join10, relative as relative3, resolve as resolve2 } from "node:path";
46207
46338
  var PHP_DEFAULT_EXCLUDES = [
46208
46339
  ".git",
46209
46340
  ".github",
@@ -46224,7 +46355,7 @@ function isExcluded(rel, excludes) {
46224
46355
  }
46225
46356
  function* walk2(dir, root, excludes) {
46226
46357
  for (const entry of readdirSync6(dir)) {
46227
- const full = join9(dir, entry);
46358
+ const full = join10(dir, entry);
46228
46359
  const rel = relative3(root, full).replace(/\\/g, "/");
46229
46360
  if (isExcluded(rel, excludes))
46230
46361
  continue;
@@ -46251,7 +46382,7 @@ function collectPhpAppEntries(projectRoot, exclude = []) {
46251
46382
  for (const file of walk2(root, root, excludes)) {
46252
46383
  const rel = relative3(root, file).replace(/\\/g, "/");
46253
46384
  const executable = (statSync4(file).mode & 73) !== 0;
46254
- entries.push({ name: rel, data: readFileSync6(file), mode: executable ? 493 : 420 });
46385
+ entries.push({ name: rel, data: readFileSync7(file), mode: executable ? 493 : 420 });
46255
46386
  }
46256
46387
  return entries;
46257
46388
  }
@@ -46743,6 +46874,7 @@ export {
46743
46874
  stackDependencyManager,
46744
46875
  signRequestAsync,
46745
46876
  signRequest,
46877
+ sharedRuntimeLoop,
46746
46878
  sha256,
46747
46879
  serviceMeshManager,
46748
46880
  sequence,
@@ -46763,6 +46895,7 @@ export {
46763
46895
  resolveSiteStackName,
46764
46896
  resolveSiteResourceName,
46765
46897
  resolveSiteBucketName,
46898
+ resolveServerlessRuntime,
46766
46899
  resolveServerlessAssetBucketName,
46767
46900
  resolveServerlessArtifactBucketName,
46768
46901
  resolveServerlessAppStackName,
@@ -46952,7 +47085,9 @@ export {
46952
47085
  canaryManager,
46953
47086
  buildPhpRuntimeLayerZip,
46954
47087
  buildOptimizationManager,
47088
+ buildNodeRuntimeLayerZip,
46955
47089
  buildCloudFormationTemplate,
47090
+ buildBunRuntimeLayerZip,
46956
47091
  bounceComplaintHandler,
46957
47092
  blueGreenManager,
46958
47093
  batchProcessingManager,
@@ -47033,6 +47168,7 @@ export {
47033
47168
  MigrationManager,
47034
47169
  MetricsManager,
47035
47170
  Messaging,
47171
+ MANAGED_NODE_VERSIONS,
47036
47172
  LogsManager,
47037
47173
  LambdaVersionsManager,
47038
47174
  LambdaVPCManager,
@@ -7,4 +7,6 @@ export * from './bootstrap';
7
7
  export * from './package';
8
8
  export * from './composer';
9
9
  export * from './app-image';
10
+ export * from './runtime-resolve';
11
+ export * from './runtimes';
10
12
  export * from './runtime/adapter';
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Resolves the Lambda runtime for a serverless app from its `kind` +
3
+ * `runtimeVersion`, deciding between an AWS **managed** Node runtime (zero
4
+ * config, no layer) and a **custom** `provided.al2023` runtime backed by a
5
+ * ts-cloud-built layer (binary + bootstrap + Runtime API loop).
6
+ *
7
+ * This unifies all three runtimes under one model: PHP, Bun, and newer Node
8
+ * versions all run on `provided.al2023` with a ts-cloud layer, while common Node
9
+ * versions stay on the managed runtime for simplicity.
10
+ */
11
+ import type { ServerlessAppConfig } from '../types';
12
+ /** Node major versions AWS provides a managed runtime for (`nodejs{N}.x`). */
13
+ export declare const MANAGED_NODE_VERSIONS: readonly ["18", "20", "22"];
14
+ export type RuntimeLayerKind = 'node' | 'bun' | 'php';
15
+ export interface ResolvedRuntime {
16
+ /** The Lambda `Runtime` value (e.g. `nodejs22.x` or `provided.al2023`). */
17
+ lambdaRuntime: string;
18
+ /** Application kind. */
19
+ kind: 'node' | 'bun' | 'php';
20
+ /** Resolved version string (node major / bun release / php version). */
21
+ version: string;
22
+ /** Whether a ts-cloud custom runtime layer is required. */
23
+ usesLayer: boolean;
24
+ /** Which layer to build/attach when {@link usesLayer}. */
25
+ layerKind?: RuntimeLayerKind;
26
+ /** Env var name the orchestrator reads for a fallback layer ARN. */
27
+ layerEnvVar?: string;
28
+ }
29
+ /**
30
+ * Resolve the runtime for an app. Honors an explicit `runtime` override; falls
31
+ * back to deriving from `kind`/`runtimeVersion`.
32
+ */
33
+ export declare function resolveServerlessRuntime(app: ServerlessAppConfig): ResolvedRuntime;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Unified custom-runtime (`provided.al2023`) layer builders for Node and Bun.
3
+ *
4
+ * Both ship the same shape as the PHP runtime layer — a binary + a `bootstrap`
5
+ * entrypoint + the shared {@link runtime.mjs} Runtime API loop — so newer Node
6
+ * versions (e.g. 24, beyond AWS's managed runtimes) and Bun run on Lambda the
7
+ * same way Laravel/PHP does. Unlike the PHP layer these need no Docker: the
8
+ * official binary is downloaded and zipped directly.
9
+ */
10
+ export type RuntimeArch = 'x86_64' | 'arm64';
11
+ /** The shared Runtime API loop source (bundled into every node/bun layer). */
12
+ export declare function sharedRuntimeLoop(): string;
13
+ export interface BuildRuntimeLayerOptions {
14
+ /** Runtime version (Node major like '24', or a Bun release like '1.3.13'). */
15
+ version: string;
16
+ /** Target architecture. @default 'x86_64' */
17
+ architecture?: RuntimeArch;
18
+ /** Progress callback. */
19
+ onStep?: (message: string) => void;
20
+ }
21
+ export interface RuntimeLayerArtifact {
22
+ zip: Buffer;
23
+ architecture: RuntimeArch;
24
+ version: string;
25
+ fileCount: number;
26
+ }
27
+ /**
28
+ * Build the Node custom-runtime layer (any Node version, incl. those without an
29
+ * AWS managed runtime such as 24). Downloads the official linux build and
30
+ * assembles `bootstrap` + `runtime.mjs` + `bin/node`.
31
+ */
32
+ export declare function buildNodeRuntimeLayerZip(options: BuildRuntimeLayerOptions): RuntimeLayerArtifact;
33
+ /**
34
+ * Build the Bun custom-runtime layer. Downloads the pinned Bun release and
35
+ * assembles `bootstrap` + `runtime.mjs` + `bin/bun`.
36
+ */
37
+ export declare function buildBunRuntimeLayerZip(options: BuildRuntimeLayerOptions): RuntimeLayerArtifact;
@@ -0,0 +1 @@
1
+ export {};
package/dist/types.d.ts CHANGED
@@ -1422,11 +1422,24 @@ export interface FunctionConfig {
1422
1422
  */
1423
1423
  export interface ServerlessAppConfig {
1424
1424
  /**
1425
- * Lambda runtime shared by all three functions.
1426
- * Use `provided.al2023` for PHP (custom runtime layer) or Bun custom runtimes.
1427
- * @default 'nodejs20.x'
1425
+ * Explicit Lambda runtime override. Usually you don't set this — it's derived
1426
+ * from {@link kind} + {@link runtimeVersion}:
1427
+ * - `node` on a managed version → `nodejs{18,20,22}.x`
1428
+ * - `node` on a non-managed version (e.g. 24), `bun`, or `php` →
1429
+ * `provided.al2023` with a ts-cloud-built custom runtime layer
1430
+ *
1431
+ * Set this to force a specific value (e.g. `provided.al2023` to run Node on a
1432
+ * custom layer even for a managed version).
1433
+ * @default derived from kind/runtimeVersion
1434
+ */
1435
+ runtime?: 'nodejs18.x' | 'nodejs20.x' | 'nodejs22.x' | 'provided.al2023' | (string & {});
1436
+ /**
1437
+ * Runtime version for `node`/`bun` apps (PHP uses {@link phpVersion}).
1438
+ * - node: '18' | '20' | '22' (managed) or '24'+ (custom provided.al2023 layer)
1439
+ * - bun: a Bun release, e.g. '1.3.13' (always a custom provided.al2023 layer)
1440
+ * @default node '22', bun the layer's pinned default
1428
1441
  */
1429
- runtime?: 'nodejs20.x' | 'nodejs22.x' | 'provided.al2023' | (string & {});
1442
+ runtimeVersion?: string;
1430
1443
  /**
1431
1444
  * Application kind. Drives packaging + runtime selection.
1432
1445
  * - `node` / `bun`: bundle a JS/TS handler artifact
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ts-cloud/core",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Core CloudFormation generation library for ts-cloud",
6
6
  "author": "Chris Breuer <chris@stacksjs.com>",
@@ -31,7 +31,7 @@
31
31
  "typecheck": "tsc --noEmit"
32
32
  },
33
33
  "dependencies": {
34
- "@ts-cloud/aws-types": "0.3.0"
34
+ "@ts-cloud/aws-types": "0.4.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "typescript": "^5.9.3"