@stacksjs/ts-cloud 0.3.1 → 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/bin/cli.js +418 -416
- package/dist/drivers/shared/package-manager.d.ts +1 -1
- package/dist/index.js +261 -101
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -39,17 +39,22 @@ import { cpSync, mkdtempSync, rmSync, writeFileSync as writeFileSync32 } from "n
|
|
|
39
39
|
import { tmpdir } from "node:os";
|
|
40
40
|
import { dirname as dirname22, isAbsolute as isAbsolute3, join as join62, resolve as resolve13 } from "node:path";
|
|
41
41
|
import { fileURLToPath } from "node:url";
|
|
42
|
-
import { readFileSync as readFileSync4 } from "node:fs";
|
|
43
|
-
import { dirname as dirname32, join as join72 } from "node:path";
|
|
44
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
45
42
|
import { execFileSync } from "node:child_process";
|
|
46
|
-
import {
|
|
43
|
+
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync4, rmSync as rmSync2 } from "node:fs";
|
|
47
44
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
48
|
-
import {
|
|
45
|
+
import { dirname as dirname32, join as join72 } from "node:path";
|
|
46
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
47
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
48
|
+
import { dirname as dirname42, join as join8 } from "node:path";
|
|
49
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
50
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
51
|
+
import { existsSync as existsSync52, mkdtempSync as mkdtempSync3, readdirSync as readdirSync52, readFileSync as readFileSync6, rmSync as rmSync3, statSync as statSync32, writeFileSync as writeFileSync52 } from "node:fs";
|
|
52
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
53
|
+
import { join as join9, relative as relative22 } from "node:path";
|
|
49
54
|
import { execSync as execSync2 } from "node:child_process";
|
|
50
55
|
import { createHash as createHash5 } from "node:crypto";
|
|
51
|
-
import { readdirSync as readdirSync62, readFileSync as
|
|
52
|
-
import { join as
|
|
56
|
+
import { readdirSync as readdirSync62, readFileSync as readFileSync7, statSync as statSync4 } from "node:fs";
|
|
57
|
+
import { join as join10, relative as relative32, resolve as resolve22 } from "node:path";
|
|
53
58
|
function __exportSetter3(name, newValue) {
|
|
54
59
|
this[name] = __returnValue3.bind(null, newValue);
|
|
55
60
|
}
|
|
@@ -25711,7 +25716,7 @@ async function packageServerlessApp(opts) {
|
|
|
25711
25716
|
opts.onStep?.("bundling application");
|
|
25712
25717
|
const result = await Bun.build({
|
|
25713
25718
|
entrypoints: [bootstrapPath],
|
|
25714
|
-
target: "node",
|
|
25719
|
+
target: app.kind === "bun" ? "bun" : "node",
|
|
25715
25720
|
format: "esm",
|
|
25716
25721
|
minify: false,
|
|
25717
25722
|
sourcemap: "none"
|
|
@@ -25742,6 +25747,54 @@ ${logs}`);
|
|
|
25742
25747
|
rmSync(stage, { recursive: true, force: true });
|
|
25743
25748
|
}
|
|
25744
25749
|
}
|
|
25750
|
+
function normalizeNodeVersion(v) {
|
|
25751
|
+
if (!v)
|
|
25752
|
+
return "22";
|
|
25753
|
+
const m = String(v).match(/(\d+)/);
|
|
25754
|
+
return m ? m[1] : "22";
|
|
25755
|
+
}
|
|
25756
|
+
function resolveServerlessRuntime(app) {
|
|
25757
|
+
const kind = app.kind ?? "node";
|
|
25758
|
+
if (kind === "php") {
|
|
25759
|
+
return {
|
|
25760
|
+
lambdaRuntime: "provided.al2023",
|
|
25761
|
+
kind: "php",
|
|
25762
|
+
version: app.phpVersion ?? "8.3",
|
|
25763
|
+
usesLayer: true,
|
|
25764
|
+
layerKind: "php",
|
|
25765
|
+
layerEnvVar: "TSCLOUD_PHP_LAYER_ARN"
|
|
25766
|
+
};
|
|
25767
|
+
}
|
|
25768
|
+
if (kind === "bun") {
|
|
25769
|
+
return {
|
|
25770
|
+
lambdaRuntime: "provided.al2023",
|
|
25771
|
+
kind: "bun",
|
|
25772
|
+
version: app.runtimeVersion ?? "latest",
|
|
25773
|
+
usesLayer: true,
|
|
25774
|
+
layerKind: "bun",
|
|
25775
|
+
layerEnvVar: "TSCLOUD_BUN_LAYER_ARN"
|
|
25776
|
+
};
|
|
25777
|
+
}
|
|
25778
|
+
const version2 = normalizeNodeVersion(app.runtimeVersion);
|
|
25779
|
+
const explicitProvided = app.runtime === "provided.al2023";
|
|
25780
|
+
const managed = !explicitProvided && MANAGED_NODE_VERSIONS.includes(version2);
|
|
25781
|
+
if (managed) {
|
|
25782
|
+
return {
|
|
25783
|
+
lambdaRuntime: app.runtime && app.runtime.startsWith("nodejs") ? app.runtime : `nodejs${version2}.x`,
|
|
25784
|
+
kind: "node",
|
|
25785
|
+
version: version2,
|
|
25786
|
+
usesLayer: false
|
|
25787
|
+
};
|
|
25788
|
+
}
|
|
25789
|
+
return {
|
|
25790
|
+
lambdaRuntime: "provided.al2023",
|
|
25791
|
+
kind: "node",
|
|
25792
|
+
version: version2,
|
|
25793
|
+
usesLayer: true,
|
|
25794
|
+
layerKind: "node",
|
|
25795
|
+
layerEnvVar: "TSCLOUD_NODE_LAYER_ARN"
|
|
25796
|
+
};
|
|
25797
|
+
}
|
|
25745
25798
|
function resolveQueueNames(app, slug, env) {
|
|
25746
25799
|
if (app.queues === false)
|
|
25747
25800
|
return [];
|
|
@@ -25755,7 +25808,7 @@ function resolveQueueNames(app, slug, env) {
|
|
|
25755
25808
|
function composeServerlessAppTemplate(opts) {
|
|
25756
25809
|
const { app, environment, handlers } = opts;
|
|
25757
25810
|
const slug = opts.config.project.slug;
|
|
25758
|
-
const runtime = app.
|
|
25811
|
+
const runtime = resolveServerlessRuntime(app).lambdaRuntime;
|
|
25759
25812
|
const architecture = app.architecture ?? "x86_64";
|
|
25760
25813
|
const region = opts.config.project.region;
|
|
25761
25814
|
const functionNames = {
|
|
@@ -26360,6 +26413,79 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
26360
26413
|
CMD [ "index.http" ]
|
|
26361
26414
|
`;
|
|
26362
26415
|
}
|
|
26416
|
+
function assetsDir() {
|
|
26417
|
+
return dirname32(fileURLToPath2(import.meta.url));
|
|
26418
|
+
}
|
|
26419
|
+
function sharedRuntimeLoop() {
|
|
26420
|
+
return readFileSync4(join72(assetsDir(), "runtime.mjs"), "utf-8");
|
|
26421
|
+
}
|
|
26422
|
+
function bootstrap(kind) {
|
|
26423
|
+
return readFileSync4(join72(assetsDir(), `${kind}-bootstrap`), "utf-8");
|
|
26424
|
+
}
|
|
26425
|
+
function buildNodeRuntimeLayerZip(options) {
|
|
26426
|
+
const architecture = options.architecture ?? "x86_64";
|
|
26427
|
+
const nodeArch = architecture === "arm64" ? "arm64" : "x64";
|
|
26428
|
+
const version2 = options.version.replace(/^v/, "");
|
|
26429
|
+
const step = options.onStep ?? (() => {});
|
|
26430
|
+
const stage = mkdtempSync2(join72(tmpdir2(), "tscloud-node-layer-"));
|
|
26431
|
+
try {
|
|
26432
|
+
const exact = version2.includes(".") ? version2 : resolveLatestNode(version2);
|
|
26433
|
+
const dir = `node-v${exact}-linux-${nodeArch}`;
|
|
26434
|
+
const url = `https://nodejs.org/dist/v${exact}/${dir}.tar.xz`;
|
|
26435
|
+
step(`downloading Node ${exact} (${architecture})`);
|
|
26436
|
+
const tar = join72(stage, "node.tar.xz");
|
|
26437
|
+
fetchToFile(url, tar);
|
|
26438
|
+
step("extracting node binary");
|
|
26439
|
+
execFileSync("tar", ["-xf", tar, "-C", stage, `${dir}/bin/node`], { stdio: "inherit" });
|
|
26440
|
+
const nodeBin = readFileSync4(join72(stage, dir, "bin", "node"));
|
|
26441
|
+
step("packaging layer");
|
|
26442
|
+
const entries = [
|
|
26443
|
+
{ name: "bootstrap", data: bootstrap("node"), mode: 493 },
|
|
26444
|
+
{ name: "runtime.mjs", data: sharedRuntimeLoop(), mode: 420 },
|
|
26445
|
+
{ name: "bin/node", data: nodeBin, mode: 493 }
|
|
26446
|
+
];
|
|
26447
|
+
return { zip: createZip(entries), architecture, version: exact, fileCount: entries.length };
|
|
26448
|
+
} finally {
|
|
26449
|
+
rmSync2(stage, { recursive: true, force: true });
|
|
26450
|
+
}
|
|
26451
|
+
}
|
|
26452
|
+
function buildBunRuntimeLayerZip(options) {
|
|
26453
|
+
const architecture = options.architecture ?? "x86_64";
|
|
26454
|
+
const bunArch = architecture === "arm64" ? "bun-linux-aarch64" : "bun-linux-x64";
|
|
26455
|
+
const version2 = options.version === "latest" ? "" : options.version.replace(/^v/, "");
|
|
26456
|
+
const step = options.onStep ?? (() => {});
|
|
26457
|
+
const stage = mkdtempSync2(join72(tmpdir2(), "tscloud-bun-layer-"));
|
|
26458
|
+
try {
|
|
26459
|
+
const tag = version2 ? `bun-v${version2}` : "latest";
|
|
26460
|
+
const url = `https://github.com/oven-sh/bun/releases/download/${tag}/${bunArch}.zip`;
|
|
26461
|
+
step(`downloading Bun ${version2 || "latest"} (${architecture})`);
|
|
26462
|
+
const zipPath = join72(stage, "bun.zip");
|
|
26463
|
+
fetchToFile(url, zipPath);
|
|
26464
|
+
step("extracting bun binary");
|
|
26465
|
+
execFileSync("unzip", ["-o", "-q", zipPath, "-d", stage], { stdio: "inherit" });
|
|
26466
|
+
const bunBin = readFileSync4(join72(stage, bunArch, "bun"));
|
|
26467
|
+
step("packaging layer");
|
|
26468
|
+
const entries = [
|
|
26469
|
+
{ name: "bootstrap", data: bootstrap("bun"), mode: 493 },
|
|
26470
|
+
{ name: "runtime.mjs", data: sharedRuntimeLoop(), mode: 420 },
|
|
26471
|
+
{ name: "bin/bun", data: bunBin, mode: 493 }
|
|
26472
|
+
];
|
|
26473
|
+
return { zip: createZip(entries), architecture, version: version2 || "latest", fileCount: entries.length };
|
|
26474
|
+
} finally {
|
|
26475
|
+
rmSync2(stage, { recursive: true, force: true });
|
|
26476
|
+
}
|
|
26477
|
+
}
|
|
26478
|
+
function fetchToFile(url, dest) {
|
|
26479
|
+
execFileSync("curl", ["-fsSL", "-o", dest, url], { stdio: ["ignore", "ignore", "inherit"] });
|
|
26480
|
+
}
|
|
26481
|
+
function resolveLatestNode(major) {
|
|
26482
|
+
const indexJson = execFileSync("curl", ["-fsSL", "https://nodejs.org/dist/index.json"], { encoding: "utf-8" });
|
|
26483
|
+
const releases = JSON.parse(indexJson);
|
|
26484
|
+
const match = releases.find((r) => r.version.startsWith(`v${major}.`));
|
|
26485
|
+
if (!match)
|
|
26486
|
+
throw new Error(`No Node release found for major version ${major}`);
|
|
26487
|
+
return match.version.replace(/^v/, "");
|
|
26488
|
+
}
|
|
26363
26489
|
function resolveApp(mod) {
|
|
26364
26490
|
const m = mod;
|
|
26365
26491
|
const def = m?.default ?? m;
|
|
@@ -26508,12 +26634,12 @@ php_admin_flag[log_errors] = on
|
|
|
26508
26634
|
clear_env = no
|
|
26509
26635
|
`;
|
|
26510
26636
|
}
|
|
26511
|
-
function
|
|
26512
|
-
return
|
|
26637
|
+
function assetsDir2() {
|
|
26638
|
+
return join8(dirname42(fileURLToPath3(import.meta.url)), "runtime-assets");
|
|
26513
26639
|
}
|
|
26514
26640
|
function phpRuntimeLayerAssets() {
|
|
26515
|
-
const dir =
|
|
26516
|
-
const read = (f) =>
|
|
26641
|
+
const dir = assetsDir2();
|
|
26642
|
+
const read = (f) => readFileSync5(join8(dir, f), "utf-8");
|
|
26517
26643
|
return [
|
|
26518
26644
|
{ path: "bootstrap", contents: read("bootstrap"), mode: 493 },
|
|
26519
26645
|
{ path: "tscloud/runtime.php", contents: read("runtime.php"), mode: 420 },
|
|
@@ -26543,7 +26669,7 @@ function laravelServerlessEnvDefaults(opts = {}) {
|
|
|
26543
26669
|
}
|
|
26544
26670
|
function* walk(dir) {
|
|
26545
26671
|
for (const entry of readdirSync52(dir)) {
|
|
26546
|
-
const full =
|
|
26672
|
+
const full = join9(dir, entry);
|
|
26547
26673
|
if (statSync32(full).isDirectory())
|
|
26548
26674
|
yield* walk(full);
|
|
26549
26675
|
else
|
|
@@ -26554,19 +26680,19 @@ function buildPhpRuntimeLayerZip(options = {}) {
|
|
|
26554
26680
|
const architecture = options.architecture ?? "x86_64";
|
|
26555
26681
|
const platform = options.platform ?? (architecture === "arm64" ? "linux/arm64" : "linux/amd64");
|
|
26556
26682
|
const step = options.onStep ?? (() => {});
|
|
26557
|
-
const stage =
|
|
26683
|
+
const stage = mkdtempSync3(join9(tmpdir3(), "tscloud-php-layer-"));
|
|
26558
26684
|
const imageTag = "tscloud-php-layer:build";
|
|
26559
26685
|
try {
|
|
26560
|
-
|
|
26686
|
+
writeFileSync52(join9(stage, "Dockerfile"), generatePhpLayerDockerfile(options));
|
|
26561
26687
|
step("Building PHP runtime image (docker)");
|
|
26562
|
-
|
|
26688
|
+
execFileSync2("docker", ["build", "--platform", platform, "-t", imageTag, stage], { stdio: "inherit" });
|
|
26563
26689
|
step("Extracting /opt from image");
|
|
26564
|
-
const cid =
|
|
26565
|
-
const optDir =
|
|
26690
|
+
const cid = execFileSync2("docker", ["create", "--platform", platform, imageTag], { encoding: "utf-8" }).trim();
|
|
26691
|
+
const optDir = join9(stage, "opt");
|
|
26566
26692
|
try {
|
|
26567
|
-
|
|
26693
|
+
execFileSync2("docker", ["cp", `${cid}:/opt/.`, optDir], { stdio: "inherit" });
|
|
26568
26694
|
} finally {
|
|
26569
|
-
|
|
26695
|
+
execFileSync2("docker", ["rm", cid], { stdio: "ignore" });
|
|
26570
26696
|
}
|
|
26571
26697
|
if (!existsSync52(optDir))
|
|
26572
26698
|
throw new Error("layer build produced no /opt directory");
|
|
@@ -26574,7 +26700,7 @@ function buildPhpRuntimeLayerZip(options = {}) {
|
|
|
26574
26700
|
for (const file of walk(optDir)) {
|
|
26575
26701
|
const rel = relative22(optDir, file).replace(/\\/g, "/");
|
|
26576
26702
|
const mode = statSync32(file).mode & 73 ? 493 : 420;
|
|
26577
|
-
entries.push({ name: rel, data:
|
|
26703
|
+
entries.push({ name: rel, data: readFileSync6(file), mode });
|
|
26578
26704
|
}
|
|
26579
26705
|
step("Injecting runtime assets");
|
|
26580
26706
|
const assetPaths = new Set(phpRuntimeLayerAssets().map((a) => a.path));
|
|
@@ -26586,7 +26712,7 @@ function buildPhpRuntimeLayerZip(options = {}) {
|
|
|
26586
26712
|
const zip2 = createZip(filtered);
|
|
26587
26713
|
return { zip: zip2, architecture, fileCount: filtered.length };
|
|
26588
26714
|
} finally {
|
|
26589
|
-
|
|
26715
|
+
rmSync3(stage, { recursive: true, force: true });
|
|
26590
26716
|
}
|
|
26591
26717
|
}
|
|
26592
26718
|
function isExcluded(rel, excludes) {
|
|
@@ -26594,7 +26720,7 @@ function isExcluded(rel, excludes) {
|
|
|
26594
26720
|
}
|
|
26595
26721
|
function* walk2(dir, root, excludes) {
|
|
26596
26722
|
for (const entry of readdirSync62(dir)) {
|
|
26597
|
-
const full =
|
|
26723
|
+
const full = join10(dir, entry);
|
|
26598
26724
|
const rel = relative32(root, full).replace(/\\/g, "/");
|
|
26599
26725
|
if (isExcluded(rel, excludes))
|
|
26600
26726
|
continue;
|
|
@@ -26621,7 +26747,7 @@ function collectPhpAppEntries(projectRoot, exclude = []) {
|
|
|
26621
26747
|
for (const file of walk2(root, root, excludes)) {
|
|
26622
26748
|
const rel = relative32(root, file).replace(/\\/g, "/");
|
|
26623
26749
|
const executable = (statSync4(file).mode & 73) !== 0;
|
|
26624
|
-
entries.push({ name: rel, data:
|
|
26750
|
+
entries.push({ name: rel, data: readFileSync7(file), mode: executable ? 493 : 420 });
|
|
26625
26751
|
}
|
|
26626
26752
|
return entries;
|
|
26627
26753
|
}
|
|
@@ -28068,7 +28194,7 @@ catch (error) {
|
|
|
28068
28194
|
|
|
28069
28195
|
return { statusCode: 200, body: 'OK' };
|
|
28070
28196
|
};
|
|
28071
|
-
`, inbound_default, exports_advanced2, IVRBuilder, exports_advanced3, MmsSupport, SmsChatbot, fifoQueueManager, dlqMonitoringManager, batchProcessingManager, queueManagementManager, CRC_TABLE, PHP_LAYER_EXTENSIONS, TEXT_CONTENT, LARAVEL_SERVERLESS_BUILD_STEPS, PHP_DEFAULT_EXCLUDES, staticSiteManager, storageAdvancedManager, healthCheckManager, networkSecurityManager, resourceManagementManager;
|
|
28197
|
+
`, inbound_default, exports_advanced2, IVRBuilder, exports_advanced3, MmsSupport, SmsChatbot, fifoQueueManager, dlqMonitoringManager, batchProcessingManager, queueManagementManager, CRC_TABLE, MANAGED_NODE_VERSIONS, PHP_LAYER_EXTENSIONS, TEXT_CONTENT, LARAVEL_SERVERLESS_BUILD_STEPS, PHP_DEFAULT_EXCLUDES, staticSiteManager, storageAdvancedManager, healthCheckManager, networkSecurityManager, resourceManagementManager;
|
|
28072
28198
|
var init_dist2 = __esm(async () => {
|
|
28073
28199
|
__defProp3 = Object.defineProperty;
|
|
28074
28200
|
__require3 = /* @__PURE__ */ createRequire2(import.meta.url);
|
|
@@ -41791,7 +41917,8 @@ Details:`;
|
|
|
41791
41917
|
type: "object",
|
|
41792
41918
|
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).",
|
|
41793
41919
|
properties: {
|
|
41794
|
-
runtime: { type: "string", description: "Lambda runtime (
|
|
41920
|
+
runtime: { type: "string", description: "Lambda runtime override (usually derived from kind + runtimeVersion)" },
|
|
41921
|
+
runtimeVersion: { type: "string", description: "Node major (18/20/22 managed, 24+ custom layer) or Bun release for node/bun apps" },
|
|
41795
41922
|
kind: { type: "string", enum: ["node", "bun", "php"], description: "Application kind (drives packaging + runtime)" },
|
|
41796
41923
|
entry: { type: "string", description: "Entry file exporting the request handler" },
|
|
41797
41924
|
memory: { type: "number", description: "HTTP function memory in MB" },
|
|
@@ -45604,6 +45731,7 @@ async function sendFallbackSms(to, message) {
|
|
|
45604
45731
|
}
|
|
45605
45732
|
return table2;
|
|
45606
45733
|
})();
|
|
45734
|
+
MANAGED_NODE_VERSIONS = ["18", "20", "22"];
|
|
45607
45735
|
PHP_LAYER_EXTENSIONS = [
|
|
45608
45736
|
"cli",
|
|
45609
45737
|
"fpm",
|
|
@@ -46829,9 +46957,9 @@ __export(exports_client, {
|
|
|
46829
46957
|
AWSClient: () => AWSClient
|
|
46830
46958
|
});
|
|
46831
46959
|
import * as crypto2 from "node:crypto";
|
|
46832
|
-
import { existsSync as existsSync14, readFileSync as
|
|
46960
|
+
import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
46833
46961
|
import { homedir as homedir6 } from "node:os";
|
|
46834
|
-
import { join as
|
|
46962
|
+
import { join as join11 } from "node:path";
|
|
46835
46963
|
function resolveS3Endpoint(options) {
|
|
46836
46964
|
const base = options.endpoint || `s3.${options.region}.amazonaws.com`;
|
|
46837
46965
|
if (!options.bucket) {
|
|
@@ -46889,12 +47017,12 @@ class AWSClient {
|
|
|
46889
47017
|
}
|
|
46890
47018
|
loadCredentialsFromFile() {
|
|
46891
47019
|
const profile = process.env.AWS_PROFILE || "default";
|
|
46892
|
-
const credentialsPath = process.env.AWS_SHARED_CREDENTIALS_FILE ||
|
|
47020
|
+
const credentialsPath = process.env.AWS_SHARED_CREDENTIALS_FILE || join11(homedir6(), ".aws", "credentials");
|
|
46893
47021
|
if (!existsSync14(credentialsPath)) {
|
|
46894
47022
|
return null;
|
|
46895
47023
|
}
|
|
46896
47024
|
try {
|
|
46897
|
-
const content =
|
|
47025
|
+
const content = readFileSync8(credentialsPath, "utf-8");
|
|
46898
47026
|
const credentials = this.parseCredentialsFile(content, profile);
|
|
46899
47027
|
if (credentials.accessKeyId && credentials.secretAccessKey) {
|
|
46900
47028
|
return credentials;
|
|
@@ -47388,7 +47516,7 @@ function detectCredentialSource() {
|
|
|
47388
47516
|
};
|
|
47389
47517
|
}
|
|
47390
47518
|
const profile = process.env.AWS_PROFILE || "default";
|
|
47391
|
-
const credentialsPath = process.env.AWS_SHARED_CREDENTIALS_FILE ||
|
|
47519
|
+
const credentialsPath = process.env.AWS_SHARED_CREDENTIALS_FILE || join11(homedir6(), ".aws", "credentials");
|
|
47392
47520
|
if (existsSync14(credentialsPath)) {
|
|
47393
47521
|
return {
|
|
47394
47522
|
source: "file",
|
|
@@ -47430,13 +47558,13 @@ function resolveCredentials2(profile) {
|
|
|
47430
47558
|
return loadProfileFromFile(process.env.AWS_PROFILE || "default") ?? { accessKeyId: "", secretAccessKey: "" };
|
|
47431
47559
|
}
|
|
47432
47560
|
function loadProfileFromFile(profile) {
|
|
47433
|
-
const { existsSync: existsSync15, readFileSync:
|
|
47561
|
+
const { existsSync: existsSync15, readFileSync: readFileSync9 } = __require("node:fs");
|
|
47434
47562
|
const { homedir: homedir5 } = __require("node:os");
|
|
47435
|
-
const { join:
|
|
47436
|
-
const credentialsPath = process.env.AWS_SHARED_CREDENTIALS_FILE ||
|
|
47563
|
+
const { join: join12 } = __require("node:path");
|
|
47564
|
+
const credentialsPath = process.env.AWS_SHARED_CREDENTIALS_FILE || join12(homedir5(), ".aws", "credentials");
|
|
47437
47565
|
if (!existsSync15(credentialsPath))
|
|
47438
47566
|
return null;
|
|
47439
|
-
const content =
|
|
47567
|
+
const content = readFileSync9(credentialsPath, "utf-8");
|
|
47440
47568
|
let currentProfile = null;
|
|
47441
47569
|
let accessKeyId;
|
|
47442
47570
|
let secretAccessKey;
|
|
@@ -47482,8 +47610,8 @@ function loadProfileFromFile(profile) {
|
|
|
47482
47610
|
// src/aws/s3.ts
|
|
47483
47611
|
import * as crypto3 from "node:crypto";
|
|
47484
47612
|
import { readdir as readdir4 } from "node:fs/promises";
|
|
47485
|
-
import { join as
|
|
47486
|
-
import { readFileSync as
|
|
47613
|
+
import { join as join13 } from "node:path";
|
|
47614
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
47487
47615
|
function toFetchBody(data) {
|
|
47488
47616
|
const { buffer, byteOffset, byteLength } = data;
|
|
47489
47617
|
if (buffer instanceof ArrayBuffer) {
|
|
@@ -47885,7 +48013,7 @@ class S3Client2 {
|
|
|
47885
48013
|
}
|
|
47886
48014
|
}
|
|
47887
48015
|
async copy(options) {
|
|
47888
|
-
const fileContent =
|
|
48016
|
+
const fileContent = readFileSync10(options.source);
|
|
47889
48017
|
await this.putObject({
|
|
47890
48018
|
bucket: options.bucket,
|
|
47891
48019
|
key: options.key,
|
|
@@ -47908,7 +48036,7 @@ class S3Client2 {
|
|
|
47908
48036
|
const relativePath = file.substring(options.source.length + 1);
|
|
47909
48037
|
const s3Key = options.prefix ? `${options.prefix}/${relativePath}` : relativePath;
|
|
47910
48038
|
if (!options.dryRun) {
|
|
47911
|
-
const fileContent =
|
|
48039
|
+
const fileContent = readFileSync10(file);
|
|
47912
48040
|
await this.putObject({
|
|
47913
48041
|
bucket: options.bucket,
|
|
47914
48042
|
key: s3Key,
|
|
@@ -47939,7 +48067,7 @@ class S3Client2 {
|
|
|
47939
48067
|
const files = [];
|
|
47940
48068
|
const entries = await readdir4(dir, { withFileTypes: true });
|
|
47941
48069
|
for (const entry of entries) {
|
|
47942
|
-
const fullPath =
|
|
48070
|
+
const fullPath = join13(dir, entry.name);
|
|
47943
48071
|
if (entry.isDirectory()) {
|
|
47944
48072
|
const subFiles = await this.listFilesRecursive(fullPath);
|
|
47945
48073
|
files.push(...subFiles);
|
|
@@ -56895,13 +57023,13 @@ async function uploadStaticFiles(options) {
|
|
|
56895
57023
|
const { sourceDir, bucket, region, cacheControl = "max-age=31536000, public", onProgress } = options;
|
|
56896
57024
|
const s32 = new S3Client2(region);
|
|
56897
57025
|
const { readdir: readdir5 } = await import("node:fs/promises");
|
|
56898
|
-
const { join:
|
|
57026
|
+
const { join: join12, relative: relative5 } = await import("node:path");
|
|
56899
57027
|
const { createHash: createHash7 } = await import("node:crypto");
|
|
56900
57028
|
async function listFiles(dir) {
|
|
56901
57029
|
const files2 = [];
|
|
56902
57030
|
const entries = await readdir5(dir, { withFileTypes: true });
|
|
56903
57031
|
for (const entry of entries) {
|
|
56904
|
-
const fullPath =
|
|
57032
|
+
const fullPath = join12(dir, entry.name);
|
|
56905
57033
|
if (entry.isDirectory()) {
|
|
56906
57034
|
files2.push(...await listFiles(fullPath));
|
|
56907
57035
|
} else {
|
|
@@ -57122,13 +57250,13 @@ var exports_serverless_image = {};
|
|
|
57122
57250
|
__export(exports_serverless_image, {
|
|
57123
57251
|
buildAndPushServerlessImage: () => buildAndPushServerlessImage
|
|
57124
57252
|
});
|
|
57125
|
-
import { execFileSync as
|
|
57126
|
-
import { mkdirSync as mkdirSync7, mkdtempSync as
|
|
57127
|
-
import { tmpdir as
|
|
57128
|
-
import { dirname as dirname7, join as
|
|
57253
|
+
import { execFileSync as execFileSync3, execSync as execSync3 } from "node:child_process";
|
|
57254
|
+
import { mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync4, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
|
|
57255
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
57256
|
+
import { dirname as dirname7, join as join15 } from "node:path";
|
|
57129
57257
|
function writeEntries(baseDir, entries) {
|
|
57130
57258
|
for (const e of entries) {
|
|
57131
|
-
const dest =
|
|
57259
|
+
const dest = join15(baseDir, e.name);
|
|
57132
57260
|
mkdirSync7(dirname7(dest), { recursive: true });
|
|
57133
57261
|
writeFileSync10(dest, e.data, e.mode ? { mode: e.mode } : undefined);
|
|
57134
57262
|
}
|
|
@@ -57139,9 +57267,9 @@ async function buildAndPushServerlessImage(opts) {
|
|
|
57139
57267
|
const platform = arch === "arm64" ? "linux/arm64" : "linux/amd64";
|
|
57140
57268
|
const isPhp = app.kind === "php";
|
|
57141
57269
|
const step2 = opts.onStep ?? (() => {});
|
|
57142
|
-
const stage =
|
|
57270
|
+
const stage = mkdtempSync4(join15(tmpdir4(), "tscloud-img-"));
|
|
57143
57271
|
try {
|
|
57144
|
-
const appDir =
|
|
57272
|
+
const appDir = join15(stage, "app");
|
|
57145
57273
|
mkdirSync7(appDir, { recursive: true });
|
|
57146
57274
|
let handlers;
|
|
57147
57275
|
let contentHash;
|
|
@@ -57150,19 +57278,19 @@ async function buildAndPushServerlessImage(opts) {
|
|
|
57150
57278
|
step2("staging application tree");
|
|
57151
57279
|
const entries = collectPhpAppEntries(projectRoot);
|
|
57152
57280
|
writeEntries(appDir, entries);
|
|
57153
|
-
writeEntries(
|
|
57281
|
+
writeEntries(join15(stage, "runtime"), phpRuntimeLayerAssets().map((a) => ({ name: a.path, data: a.contents, mode: a.mode })));
|
|
57154
57282
|
const handler8 = app.handlers?.http ?? "public/index.php";
|
|
57155
57283
|
handlers = { http: handler8, queue: app.handlers?.queue ?? handler8, cli: app.handlers?.cli ?? handler8 };
|
|
57156
57284
|
contentHash = sha256(entries.map((e) => `${e.name}:${e.data.length}`).join("|"));
|
|
57157
57285
|
} else {
|
|
57158
57286
|
step2("bundling application");
|
|
57159
57287
|
const artifact = await packageServerlessApp({ projectRoot, app, skipBuild: opts.skipBuild, onStep: step2 });
|
|
57160
|
-
writeFileSync10(
|
|
57288
|
+
writeFileSync10(join15(appDir, "index.mjs"), artifact.bundle);
|
|
57161
57289
|
handlers = artifact.handlers;
|
|
57162
57290
|
contentHash = artifact.sha256;
|
|
57163
57291
|
}
|
|
57164
57292
|
const tag = contentHash.slice(0, 16);
|
|
57165
|
-
writeFileSync10(
|
|
57293
|
+
writeFileSync10(join15(stage, "Dockerfile"), generateAppImageDockerfile({
|
|
57166
57294
|
kind: app.kind ?? "node",
|
|
57167
57295
|
phpVersion: app.phpVersion,
|
|
57168
57296
|
architecture: arch
|
|
@@ -57184,16 +57312,16 @@ async function buildAndPushServerlessImage(opts) {
|
|
|
57184
57312
|
throw new Error(`could not resolve ECR repository URI for ${repository}`);
|
|
57185
57313
|
const imageUri = `${repoUri}:${tag}`;
|
|
57186
57314
|
step2("docker build");
|
|
57187
|
-
|
|
57315
|
+
execFileSync3("docker", ["build", "--platform", platform, "-t", imageUri, stage], { stdio: "inherit" });
|
|
57188
57316
|
step2("ecr login");
|
|
57189
57317
|
const loginCmd = await ecr2.getDockerLoginCommand();
|
|
57190
57318
|
execSync3(loginCmd, { stdio: "inherit" });
|
|
57191
57319
|
step2("docker push");
|
|
57192
|
-
|
|
57320
|
+
execFileSync3("docker", ["push", imageUri], { stdio: "inherit" });
|
|
57193
57321
|
info(`Image: ${imageUri}`);
|
|
57194
57322
|
return { imageUri, tag, handlers };
|
|
57195
57323
|
} finally {
|
|
57196
|
-
|
|
57324
|
+
rmSync4(stage, { recursive: true, force: true });
|
|
57197
57325
|
}
|
|
57198
57326
|
}
|
|
57199
57327
|
var init_serverless_image = __esm(async () => {
|
|
@@ -78421,7 +78549,7 @@ class ApplicationAutoScalingClient {
|
|
|
78421
78549
|
init_s3();
|
|
78422
78550
|
import * as net from "node:net";
|
|
78423
78551
|
import * as tls from "node:tls";
|
|
78424
|
-
import { readFileSync as
|
|
78552
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
78425
78553
|
import * as crypto4 from "node:crypto";
|
|
78426
78554
|
|
|
78427
78555
|
class ImapServer {
|
|
@@ -78456,8 +78584,8 @@ class ImapServer {
|
|
|
78456
78584
|
});
|
|
78457
78585
|
if (this.config.tls?.key && this.config.tls?.cert) {
|
|
78458
78586
|
const tlsOptions = {
|
|
78459
|
-
key:
|
|
78460
|
-
cert:
|
|
78587
|
+
key: readFileSync11(this.config.tls.key),
|
|
78588
|
+
cert: readFileSync11(this.config.tls.cert)
|
|
78461
78589
|
};
|
|
78462
78590
|
this.tlsServer = tls.createServer(tlsOptions, (socket) => {
|
|
78463
78591
|
this.handleConnection(socket);
|
|
@@ -79261,8 +79389,8 @@ class ImapServer {
|
|
|
79261
79389
|
}
|
|
79262
79390
|
this.send(session, `${tag} OK Begin TLS negotiation`);
|
|
79263
79391
|
const tlsOptions = {
|
|
79264
|
-
key:
|
|
79265
|
-
cert:
|
|
79392
|
+
key: readFileSync11(this.config.tls.key),
|
|
79393
|
+
cert: readFileSync11(this.config.tls.cert),
|
|
79266
79394
|
isServer: true
|
|
79267
79395
|
};
|
|
79268
79396
|
const tlsSocket = new tls.TLSSocket(session.socket, tlsOptions);
|
|
@@ -79855,7 +79983,7 @@ init_ses();
|
|
|
79855
79983
|
init_s3();
|
|
79856
79984
|
import * as net2 from "node:net";
|
|
79857
79985
|
import * as tls2 from "node:tls";
|
|
79858
|
-
import { readFileSync as
|
|
79986
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
79859
79987
|
import * as crypto5 from "node:crypto";
|
|
79860
79988
|
|
|
79861
79989
|
class SmtpServer {
|
|
@@ -79886,8 +80014,8 @@ class SmtpServer {
|
|
|
79886
80014
|
});
|
|
79887
80015
|
if (this.config.tls?.key && this.config.tls?.cert) {
|
|
79888
80016
|
const tlsOptions = {
|
|
79889
|
-
key:
|
|
79890
|
-
cert:
|
|
80017
|
+
key: readFileSync12(this.config.tls.key),
|
|
80018
|
+
cert: readFileSync12(this.config.tls.cert)
|
|
79891
80019
|
};
|
|
79892
80020
|
this.tlsServer = tls2.createServer(tlsOptions, (socket) => {
|
|
79893
80021
|
this.handleConnection(socket, true);
|
|
@@ -80021,8 +80149,8 @@ class SmtpServer {
|
|
|
80021
80149
|
}
|
|
80022
80150
|
this.send(session, "220 Ready to start TLS");
|
|
80023
80151
|
const tlsOptions = {
|
|
80024
|
-
key:
|
|
80025
|
-
cert:
|
|
80152
|
+
key: readFileSync12(this.config.tls.key),
|
|
80153
|
+
cert: readFileSync12(this.config.tls.cert),
|
|
80026
80154
|
isServer: true
|
|
80027
80155
|
};
|
|
80028
80156
|
const tlsSocket = new tls2.TLSSocket(session.socket, tlsOptions);
|
|
@@ -82721,11 +82849,11 @@ init_static_site_external_dns();
|
|
|
82721
82849
|
init_static_site_external_dns();
|
|
82722
82850
|
import process19 from "node:process";
|
|
82723
82851
|
import { existsSync as existsSync16 } from "node:fs";
|
|
82724
|
-
import { join as
|
|
82852
|
+
import { join as join14 } from "node:path";
|
|
82725
82853
|
async function deploySite(config6) {
|
|
82726
82854
|
const start = Date.now();
|
|
82727
82855
|
const sourceDir = config6.sourceDir ?? "dist";
|
|
82728
|
-
if (!existsSync16(
|
|
82856
|
+
if (!existsSync16(join14(sourceDir, "index.html"))) {
|
|
82729
82857
|
return fail(start, `${sourceDir}/ has no index.html — build first.`);
|
|
82730
82858
|
}
|
|
82731
82859
|
if (!process19.env.AWS_ACCESS_KEY_ID || !process19.env.AWS_SECRET_ACCESS_KEY) {
|
|
@@ -82796,8 +82924,8 @@ function fail(start, message) {
|
|
|
82796
82924
|
// src/deploy/serverless-app.ts
|
|
82797
82925
|
init_cloudformation();
|
|
82798
82926
|
await init_dist2();
|
|
82799
|
-
import { existsSync as existsSync17, readdirSync as readdirSync8, readFileSync as
|
|
82800
|
-
import { join as
|
|
82927
|
+
import { existsSync as existsSync17, readdirSync as readdirSync8, readFileSync as readFileSync13, statSync as statSync5 } from "node:fs";
|
|
82928
|
+
import { join as join16, relative as relative6 } from "node:path";
|
|
82801
82929
|
init_s3();
|
|
82802
82930
|
init_cli();
|
|
82803
82931
|
function resolveContext(config6, environment) {
|
|
@@ -82925,7 +83053,7 @@ function contentType(file) {
|
|
|
82925
83053
|
}
|
|
82926
83054
|
function* walk3(dir) {
|
|
82927
83055
|
for (const entry of readdirSync8(dir)) {
|
|
82928
|
-
const full =
|
|
83056
|
+
const full = join16(dir, entry);
|
|
82929
83057
|
if (statSync5(full).isDirectory())
|
|
82930
83058
|
yield* walk3(full);
|
|
82931
83059
|
else
|
|
@@ -82939,7 +83067,7 @@ async function uploadAssets(s32, bucket, dir, prefix) {
|
|
|
82939
83067
|
await s32.putObject({
|
|
82940
83068
|
bucket,
|
|
82941
83069
|
key,
|
|
82942
|
-
body:
|
|
83070
|
+
body: readFileSync13(file),
|
|
82943
83071
|
contentType: contentType(file),
|
|
82944
83072
|
cacheControl: "public, max-age=31536000, immutable"
|
|
82945
83073
|
});
|
|
@@ -82966,11 +83094,15 @@ async function deployServerlessApp(config6, environment, opts = {}) {
|
|
|
82966
83094
|
const lambda2 = new LambdaClient(region);
|
|
82967
83095
|
const isPhp = app.kind === "php";
|
|
82968
83096
|
const imageMode = app.packaging === "image";
|
|
83097
|
+
const resolved = resolveServerlessRuntime(app);
|
|
82969
83098
|
let handlers;
|
|
82970
83099
|
let codeSource;
|
|
82971
83100
|
let artifactSha;
|
|
82972
83101
|
let runtimeLayers;
|
|
82973
83102
|
const parameters = [];
|
|
83103
|
+
if (imageMode && resolved.usesLayer && resolved.layerKind !== "php") {
|
|
83104
|
+
throw new Error(`packaging: 'image' currently supports PHP and managed Node runtimes. ` + `${resolved.kind}${resolved.kind === "node" ? ` ${resolved.version}` : ""} uses a custom runtime — ` + `use the default zip packaging (the runtime layer is built + attached automatically).`);
|
|
83105
|
+
}
|
|
82974
83106
|
if (imageMode) {
|
|
82975
83107
|
step("Building + pushing container image");
|
|
82976
83108
|
const { buildAndPushServerlessImage: buildAndPushServerlessImage2 } = await init_serverless_image().then(() => exports_serverless_image);
|
|
@@ -82993,10 +83125,12 @@ async function deployServerlessApp(config6, environment, opts = {}) {
|
|
|
82993
83125
|
info(`Artifact: ${artifact.sha256.slice(0, 12)} (${(artifact.zip.length / 1024).toFixed(0)} KB)`);
|
|
82994
83126
|
handlers = artifact.handlers;
|
|
82995
83127
|
artifactSha = artifact.sha256;
|
|
82996
|
-
if (
|
|
82997
|
-
|
|
83128
|
+
if (resolved.usesLayer) {
|
|
83129
|
+
const envArn = resolved.layerEnvVar ? process.env[resolved.layerEnvVar] : undefined;
|
|
83130
|
+
runtimeLayers = app.layers ?? (envArn ? [envArn] : undefined);
|
|
82998
83131
|
if (!runtimeLayers?.length) {
|
|
82999
|
-
|
|
83132
|
+
const buildCmd = resolved.layerKind === "php" ? "serverless:build-php-layer" : resolved.layerKind === "bun" ? "serverless:build-bun-layer" : "serverless:build-node-layer";
|
|
83133
|
+
throw new Error(`${resolved.kind} apps on provided.al2023 need a runtime layer. Set environments.<env>.app.layers or the ${resolved.layerEnvVar} env var (build one with \`cloud ${buildCmd}\`)${resolved.kind === "node" ? ", or use a managed Node version (18/20/22)" : ""}.`);
|
|
83000
83134
|
}
|
|
83001
83135
|
}
|
|
83002
83136
|
if (!await s32.bucketExists(artifactBucket)) {
|
|
@@ -83036,15 +83170,15 @@ async function deployServerlessApp(config6, environment, opts = {}) {
|
|
|
83036
83170
|
const outputs = await cfn.getStackOutputs(stackName).catch(() => ({}));
|
|
83037
83171
|
let assetUrl;
|
|
83038
83172
|
if (app.assets) {
|
|
83039
|
-
const
|
|
83040
|
-
if (existsSync17(
|
|
83173
|
+
const assetsDir3 = join16(projectRoot, app.assets);
|
|
83174
|
+
if (existsSync17(assetsDir3)) {
|
|
83041
83175
|
const cdn = outputs.AssetsCdnDomain;
|
|
83042
83176
|
assetUrl = cdn ? `https://${cdn}/${artifactSha}` : undefined;
|
|
83043
83177
|
step(`Syncing assets from ${app.assets}`);
|
|
83044
|
-
const n = await uploadAssets(s32, ctx.assetsBucket,
|
|
83178
|
+
const n = await uploadAssets(s32, ctx.assetsBucket, assetsDir3, artifactSha);
|
|
83045
83179
|
info(`Uploaded ${n} asset(s)${assetUrl ? ` → ${assetUrl}` : ""}`);
|
|
83046
83180
|
} else {
|
|
83047
|
-
warn(`Assets directory not found: ${
|
|
83181
|
+
warn(`Assets directory not found: ${assetsDir3}`);
|
|
83048
83182
|
}
|
|
83049
83183
|
}
|
|
83050
83184
|
step("Resolving secrets");
|
|
@@ -83185,10 +83319,26 @@ await init_dist2();
|
|
|
83185
83319
|
// src/drivers/aws/driver.ts
|
|
83186
83320
|
init_cloudformation();
|
|
83187
83321
|
await init_dist2();
|
|
83188
|
-
import { readFileSync as
|
|
83322
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
83189
83323
|
init_s3();
|
|
83190
83324
|
|
|
83191
83325
|
// src/drivers/shared/package-manager.ts
|
|
83326
|
+
var PANTRY_PACKAGES = {
|
|
83327
|
+
php: "php.net",
|
|
83328
|
+
nginx: "nginx.org",
|
|
83329
|
+
composer: "getcomposer.org",
|
|
83330
|
+
mysql: "mysql.com",
|
|
83331
|
+
mariadb: "mariadb.com/server",
|
|
83332
|
+
postgres: "postgresql.org",
|
|
83333
|
+
redis: "redis.io",
|
|
83334
|
+
memcached: "memcached.org",
|
|
83335
|
+
meilisearch: "meilisearch.com",
|
|
83336
|
+
git: "git-scm.com",
|
|
83337
|
+
certbot: "certbot.eff.org",
|
|
83338
|
+
bun: "bun.sh",
|
|
83339
|
+
node: "nodejs.org",
|
|
83340
|
+
deno: "deno.land"
|
|
83341
|
+
};
|
|
83192
83342
|
var PANTRY_INSTALL_DIR = "/usr/local/bin";
|
|
83193
83343
|
var PANTRY_PROJECT_DIR = "/opt/pantry";
|
|
83194
83344
|
function sh(value) {
|
|
@@ -83228,10 +83378,6 @@ function buildPantryServiceScript(services) {
|
|
|
83228
83378
|
function enabled(spec) {
|
|
83229
83379
|
return spec === true || typeof spec === "object" && spec != null;
|
|
83230
83380
|
}
|
|
83231
|
-
function sq(value) {
|
|
83232
|
-
const escaped = value.split("'").join("'\\''");
|
|
83233
|
-
return `'${escaped}'`;
|
|
83234
|
-
}
|
|
83235
83381
|
function planServices(services) {
|
|
83236
83382
|
const packages = [];
|
|
83237
83383
|
const names = [];
|
|
@@ -83239,7 +83385,7 @@ function planServices(services) {
|
|
|
83239
83385
|
packages.push("mysql.com");
|
|
83240
83386
|
names.push("mysql");
|
|
83241
83387
|
} else if (enabled(services.mariadb)) {
|
|
83242
|
-
packages.push(
|
|
83388
|
+
packages.push(PANTRY_PACKAGES.mariadb);
|
|
83243
83389
|
names.push("mariadb");
|
|
83244
83390
|
}
|
|
83245
83391
|
if (enabled(services.postgres)) {
|
|
@@ -83281,17 +83427,26 @@ function buildDatabaseSetupScript(database, services = {}) {
|
|
|
83281
83427
|
const useMariadb = enabled(services.mariadb) || database.engine === "mariadb";
|
|
83282
83428
|
const useMysql = enabled(services.mysql) || database.engine === "mysql";
|
|
83283
83429
|
if (usePostgres && !useMysql && !useMariadb) {
|
|
83284
|
-
const
|
|
83430
|
+
const pgIdent = (v) => `"${v.replace(/"/g, '""')}"`;
|
|
83431
|
+
const pgLit = (v) => `'${v.replace(/'/g, "''")}'`;
|
|
83285
83432
|
return [
|
|
83286
83433
|
pantryEnvActivation(),
|
|
83287
|
-
|
|
83288
|
-
|
|
83434
|
+
"for i in $(seq 1 30); do pg_isready -h 127.0.0.1 -p 5432 -q && break; sleep 2; done",
|
|
83435
|
+
"psql -h 127.0.0.1 -p 5432 -U postgres <<'TS_CLOUD_PG_EOF'",
|
|
83436
|
+
"DO $$ BEGIN",
|
|
83437
|
+
` IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = ${pgLit(user)}) THEN`,
|
|
83438
|
+
` CREATE ROLE ${pgIdent(user)} LOGIN PASSWORD ${pgLit(pass)};`,
|
|
83439
|
+
" END IF;",
|
|
83440
|
+
"END $$;",
|
|
83441
|
+
`SELECT 'CREATE DATABASE ${pgIdent(name)} OWNER ${pgIdent(user)}' ` + `WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = ${pgLit(name)})\\gexec`,
|
|
83442
|
+
"TS_CLOUD_PG_EOF"
|
|
83289
83443
|
];
|
|
83290
83444
|
}
|
|
83291
83445
|
const ident = (v) => v.replace(/`/g, "``");
|
|
83292
83446
|
const lit = (v) => v.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
83293
83447
|
return [
|
|
83294
83448
|
pantryEnvActivation(),
|
|
83449
|
+
"for i in $(seq 1 30); do mysqladmin -h 127.0.0.1 -P 3306 -u root ping 2>/dev/null | grep -q alive && break; sleep 2; done",
|
|
83295
83450
|
"mysql -h 127.0.0.1 -P 3306 -u root <<'TS_CLOUD_SQL_EOF'",
|
|
83296
83451
|
`CREATE DATABASE IF NOT EXISTS \`${ident(name)}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`,
|
|
83297
83452
|
`CREATE USER IF NOT EXISTS '${lit(user)}'@'%' IDENTIFIED BY '${lit(pass)}';`,
|
|
@@ -83438,9 +83593,9 @@ function buildNginxVhostScript(options) {
|
|
|
83438
83593
|
const out = [];
|
|
83439
83594
|
if (options.auth) {
|
|
83440
83595
|
const file = htpasswdPath(options.siteName);
|
|
83441
|
-
const
|
|
83442
|
-
const pw =
|
|
83443
|
-
const user =
|
|
83596
|
+
const sq = (v) => v.split("'").join("'\\''");
|
|
83597
|
+
const pw = sq(options.auth.password);
|
|
83598
|
+
const user = sq(options.auth.username);
|
|
83444
83599
|
out.push(`TS_CLOUD_HTPASS=$(openssl passwd -apr1 '${pw}')`, `printf '%s:%s\\n' '${user}' "$TS_CLOUD_HTPASS" > ${file}`, `chmod 640 ${file}`, `chown root:www-data ${file} 2>/dev/null || true`);
|
|
83445
83600
|
}
|
|
83446
83601
|
out.push(`cat > ${available} <<'TS_CLOUD_NGINX_EOF'`, vhost.replace(/\n$/, ""), "TS_CLOUD_NGINX_EOF", `ln -sf ${available} ${enabled2}`, "rm -f /etc/nginx/sites-enabled/default", `${NGINX_WRAPPER} -t`, "systemctl reload ts-cloud-nginx 2>/dev/null || systemctl restart ts-cloud-nginx 2>/dev/null || true");
|
|
@@ -84204,7 +84359,7 @@ class AwsDriver {
|
|
|
84204
84359
|
await s32.putObject({
|
|
84205
84360
|
bucket,
|
|
84206
84361
|
key: options.remoteKey,
|
|
84207
|
-
body:
|
|
84362
|
+
body: readFileSync14(options.localPath),
|
|
84208
84363
|
contentType: "application/gzip"
|
|
84209
84364
|
});
|
|
84210
84365
|
return { artifactRef: `s3://${bucket}/${options.remoteKey}` };
|
|
@@ -84311,9 +84466,9 @@ class AwsDriver {
|
|
|
84311
84466
|
|
|
84312
84467
|
// src/drivers/hetzner/driver.ts
|
|
84313
84468
|
await init_dist2();
|
|
84314
|
-
import { existsSync as existsSync18, readFileSync as
|
|
84469
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
|
|
84315
84470
|
import { homedir as homedir7 } from "node:os";
|
|
84316
|
-
import { join as
|
|
84471
|
+
import { join as join18 } from "node:path";
|
|
84317
84472
|
import { execSync as execSync5 } from "node:child_process";
|
|
84318
84473
|
|
|
84319
84474
|
// src/drivers/hetzner/client.ts
|
|
@@ -84743,10 +84898,10 @@ function matchesTsCloudLabels(labels, slug, environment, role = "app") {
|
|
|
84743
84898
|
|
|
84744
84899
|
// src/drivers/hetzner/state.ts
|
|
84745
84900
|
import { mkdir as mkdir4, readFile, writeFile as writeFile4 } from "node:fs/promises";
|
|
84746
|
-
import { join as
|
|
84901
|
+
import { join as join17 } from "node:path";
|
|
84747
84902
|
var STATE_DIR = ".ts-cloud/state";
|
|
84748
84903
|
function driverStatePath(stackName) {
|
|
84749
|
-
return
|
|
84904
|
+
return join17(process.cwd(), STATE_DIR, `${stackName}.json`);
|
|
84750
84905
|
}
|
|
84751
84906
|
async function readDriverState(stackName) {
|
|
84752
84907
|
try {
|
|
@@ -84758,7 +84913,7 @@ async function readDriverState(stackName) {
|
|
|
84758
84913
|
}
|
|
84759
84914
|
async function writeDriverState(stackName, state) {
|
|
84760
84915
|
const path = driverStatePath(stackName);
|
|
84761
|
-
await mkdir4(
|
|
84916
|
+
await mkdir4(join17(process.cwd(), STATE_DIR), { recursive: true });
|
|
84762
84917
|
await writeFile4(path, `${JSON.stringify(state, null, 2)}
|
|
84763
84918
|
`, "utf8");
|
|
84764
84919
|
}
|
|
@@ -84766,7 +84921,7 @@ async function writeDriverState(stackName, state) {
|
|
|
84766
84921
|
// src/drivers/hetzner/driver.ts
|
|
84767
84922
|
var SSH_MAX_BUFFER = 1024 * 1024 * 256;
|
|
84768
84923
|
function expandHome(path) {
|
|
84769
|
-
return path.startsWith("~/") ?
|
|
84924
|
+
return path.startsWith("~/") ? join18(homedir7(), path.slice(2)) : path;
|
|
84770
84925
|
}
|
|
84771
84926
|
|
|
84772
84927
|
class HetznerDriver {
|
|
@@ -84838,7 +84993,7 @@ class HetznerDriver {
|
|
|
84838
84993
|
}) : undefined;
|
|
84839
84994
|
const provision = buildComputeProvisionScripts(config6);
|
|
84840
84995
|
const baked = compute.bakedImage === true;
|
|
84841
|
-
const
|
|
84996
|
+
const bootstrap2 = buildUbuntuBootstrapScript({
|
|
84842
84997
|
runtime: provision.runtime,
|
|
84843
84998
|
runtimeVersion: provision.runtimeVersion,
|
|
84844
84999
|
systemPackages: compute.systemPackages,
|
|
@@ -84848,7 +85003,7 @@ class HetznerDriver {
|
|
|
84848
85003
|
rpxProvision,
|
|
84849
85004
|
baked
|
|
84850
85005
|
});
|
|
84851
|
-
const userData = wrapCloudInitUserData(
|
|
85006
|
+
const userData = wrapCloudInitUserData(bootstrap2);
|
|
84852
85007
|
const serverType = resolveHetznerServerType(compute.size);
|
|
84853
85008
|
const image = compute.image || config6.hetzner?.image || "ubuntu-24.04";
|
|
84854
85009
|
const firewallName = `${slug}-${environment}-app-fw`;
|
|
@@ -85197,7 +85352,7 @@ class HetznerDriver {
|
|
|
85197
85352
|
if (!existsSync18(this.sshPublicKeyPath)) {
|
|
85198
85353
|
throw new Error(`SSH public key not found at ${this.sshPublicKeyPath}. ts-cloud deploys to Hetzner over SSH and needs a public key to authorize on the server. ` + `Generate one (\`ssh-keygen -t ed25519\`) or set hetzner.sshPrivateKeyPath / HCLOUD_SSH_PUBLIC_KEY.`);
|
|
85199
85354
|
}
|
|
85200
|
-
const publicKey =
|
|
85355
|
+
const publicKey = readFileSync15(this.sshPublicKeyPath, "utf8").trim();
|
|
85201
85356
|
const normalized = normalizeSshPublicKey(publicKey);
|
|
85202
85357
|
const existing = await this.client.listSshKeys();
|
|
85203
85358
|
const match = existing.find((key) => normalizeSshPublicKey(key.public_key) === normalized);
|
|
@@ -86077,6 +86232,7 @@ export {
|
|
|
86077
86232
|
stackDependencyManager,
|
|
86078
86233
|
signRequestAsync,
|
|
86079
86234
|
signRequest,
|
|
86235
|
+
sharedRuntimeLoop,
|
|
86080
86236
|
sha256,
|
|
86081
86237
|
setupDns01Challenge,
|
|
86082
86238
|
setMaintenance,
|
|
@@ -86103,6 +86259,7 @@ export {
|
|
|
86103
86259
|
resolveSiteKind,
|
|
86104
86260
|
resolveSiteDeployTarget,
|
|
86105
86261
|
resolveSiteBucketName,
|
|
86262
|
+
resolveServerlessRuntime,
|
|
86106
86263
|
resolveServerlessAssetBucketName,
|
|
86107
86264
|
resolveServerlessArtifactBucketName,
|
|
86108
86265
|
resolveServerlessAppStackName,
|
|
@@ -86333,8 +86490,10 @@ export {
|
|
|
86333
86490
|
buildSiteDeployScript,
|
|
86334
86491
|
buildPhpRuntimeLayerZip,
|
|
86335
86492
|
buildOptimizationManager,
|
|
86493
|
+
buildNodeRuntimeLayerZip,
|
|
86336
86494
|
buildFunctionEnv,
|
|
86337
86495
|
buildCloudFormationTemplate,
|
|
86496
|
+
buildBunRuntimeLayerZip,
|
|
86338
86497
|
buildAndPushServerlessImage,
|
|
86339
86498
|
bounceComplaintHandler,
|
|
86340
86499
|
blueGreenManager,
|
|
@@ -86439,6 +86598,7 @@ export {
|
|
|
86439
86598
|
MigrationManager,
|
|
86440
86599
|
MetricsManager,
|
|
86441
86600
|
Messaging,
|
|
86601
|
+
MANAGED_NODE_VERSIONS,
|
|
86442
86602
|
LogsManager,
|
|
86443
86603
|
LambdaVersionsManager,
|
|
86444
86604
|
LambdaVPCManager,
|