From c35b38c4cbe664761505c8951cc7f611cecaabef Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Tue, 19 Nov 2024 23:10:28 -0800 Subject: [PATCH] chore: add deno uploads --- .gitattributes | 3 - Cargo.lock | 298 ++++++++++++++++-- examples/js-deno/deno.json | 3 + examples/js-deno/deno.lock | 17 + examples/js-deno/rivet.jsonc | 10 + examples/js-deno/rng_http.ts | 27 ++ examples/js-manual/rivet.jsonc | 7 +- packages/cli/Cargo.toml | 1 + packages/deno-embed/build.rs | 10 +- packages/js-utils/deno.lock | 213 +++++++++++++ packages/js-utils/src/tasks/build/build.ts | 204 +++++------- packages/js-utils/src/tasks/build/mod.ts | 34 ++ packages/js-utils/src/tasks/build/task.ts | 18 -- packages/js-utils/src/util/task/task.ts | 2 - .../toolchain/src/config/build/javascript.rs | 72 ++--- packages/toolchain/src/tasks/deploy/js.rs | 92 +++++- packages/toolchain/src/util/js_utils/mod.rs | 72 +++-- .../toolchain/src/util/js_utils/schemas.rs | 39 +++ scripts/postgres/mirror_release.ts | 70 ---- 19 files changed, 845 insertions(+), 347 deletions(-) create mode 100644 examples/js-deno/deno.json create mode 100644 examples/js-deno/deno.lock create mode 100644 examples/js-deno/rivet.jsonc create mode 100644 examples/js-deno/rng_http.ts create mode 100644 packages/js-utils/src/tasks/build/mod.ts delete mode 100644 packages/js-utils/src/tasks/build/task.ts create mode 100644 packages/toolchain/src/util/js_utils/schemas.rs delete mode 100755 scripts/postgres/mirror_release.ts diff --git a/.gitattributes b/.gitattributes index b7c90ca2..7230b706 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,3 @@ sdks/** linguist-generated=true **/Cargo.lock linguist-generated=true *.png binary -# This Rustacean is in denial there's more TypeScript than Rust in this repo -packages/backend/** linguist-vendored - diff --git a/Cargo.lock b/Cargo.lock index 20168eed..61eb66df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -592,6 +592,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -972,6 +983,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -980,12 +1109,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1164,6 +1304,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -1596,6 +1742,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "url", "uuid", "vergen-git2", ] @@ -1915,6 +2062,12 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" version = "0.11.1" @@ -1971,6 +2124,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2087,20 +2251,15 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.40.0" @@ -2205,27 +2364,12 @@ dependencies = [ "version_check", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-width" version = "0.1.14" @@ -2246,15 +2390,28 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -2681,6 +2838,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "xattr" version = "1.3.1" @@ -2692,6 +2861,73 @@ dependencies = [ "rustix", ] +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "zip" version = "0.5.13" diff --git a/examples/js-deno/deno.json b/examples/js-deno/deno.json new file mode 100644 index 00000000..5dcc847e --- /dev/null +++ b/examples/js-deno/deno.json @@ -0,0 +1,3 @@ +{ + "imports": { "@std/random": "jsr:@std/random@^0.1.0" } +} diff --git a/examples/js-deno/deno.lock b/examples/js-deno/deno.lock new file mode 100644 index 00000000..85a765dc --- /dev/null +++ b/examples/js-deno/deno.lock @@ -0,0 +1,17 @@ +{ + "version": "4", + "specifiers": { + "jsr:@std/random@*": "0.1.0", + "jsr:@std/random@0.1": "0.1.0" + }, + "jsr": { + "@std/random@0.1.0": { + "integrity": "70a006be0ffb77d036bab54aa8ae6bd0119ba77ace0f2f56f63273d4262a5667" + } + }, + "workspace": { + "dependencies": [ + "jsr:@std/random@0.1" + ] + } +} diff --git a/examples/js-deno/rivet.jsonc b/examples/js-deno/rivet.jsonc new file mode 100644 index 00000000..c08a6878 --- /dev/null +++ b/examples/js-deno/rivet.jsonc @@ -0,0 +1,10 @@ +{ + "version": "2.0", + "builds": [ + { + "tags": { "name": "rng-http" }, + "runtime": "javascript", + "script": "rng_http.ts" + } + ] +} diff --git a/examples/js-deno/rng_http.ts b/examples/js-deno/rng_http.ts new file mode 100644 index 00000000..d9163118 --- /dev/null +++ b/examples/js-deno/rng_http.ts @@ -0,0 +1,27 @@ +import { randomIntegerBetween, randomSeeded } from "@std/random"; + +console.log(Deno.env.toObject()); + +const portStr = Deno.env.get("PORT_ds_http") ?? Deno.env.get("HTTP_PORT"); +if (!portStr) throw "Missing port"; +const port = parseInt(portStr); +if (!isFinite(port)) throw "Invalid port"; + +const server = Deno.serve({ + handler, + port, + hostname: "0.0.0.0", +}); + +await server.finished; + +const prng = randomSeeded(1n); + +function handler(req: Request) { + console.log("Received request"); + + return new Response(randomIntegerBetween(1, 100, { prng }).toString(), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); +} diff --git a/examples/js-manual/rivet.jsonc b/examples/js-manual/rivet.jsonc index f0849d6a..b477c8d8 100644 --- a/examples/js-manual/rivet.jsonc +++ b/examples/js-manual/rivet.jsonc @@ -5,10 +5,7 @@ "tags": { "name": "echo-http" }, "runtime": "javascript", "bundler": "none", - "index_path": "echo_http.js" + "script": "echo_http.js" } - ], - "unstable": { - "multipart_enabled": false - } + ] } diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index c037fc85..cb24fc2e 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -19,6 +19,7 @@ serde_json = "1.0.120" anyhow = "1.0" uuid = { version = "1.11.0", features = ["v4"] } envy = "0.4.2" +url = { version = "2.5.3", features = ["serde"] } [build-dependencies] anyhow = "1.0" diff --git a/packages/deno-embed/build.rs b/packages/deno-embed/build.rs index f4d499e0..2f642f0d 100644 --- a/packages/deno-embed/build.rs +++ b/packages/deno-embed/build.rs @@ -5,7 +5,7 @@ use std::{env, fs, path::Path}; use zip::ZipArchive; const GITHUB_API_URL: &str = "https://api.github.com/repos/denoland/deno"; -const DENO_VERSION: &str = "1.46.3"; +const DENO_VERSION: &str = "2.0.6"; const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); fn main() -> Result<(), Box> { @@ -39,7 +39,9 @@ fn fetch_release_data() -> Result> { println!("Fetching release information from: {}", release_url); let client = Client::new(); - let mut request = client.get(&release_url).header(reqwest::header::USER_AGENT, USER_AGENT); + let mut request = client + .get(&release_url) + .header(reqwest::header::USER_AGENT, USER_AGENT); if let Ok(token) = env::var("GITHUB_TOKEN") { request = request.header(reqwest::header::AUTHORIZATION, format!("token {}", token)); @@ -96,7 +98,9 @@ fn download_binary_if_needed( println!("Downloading Deno binary from: {}", download_url); let client = Client::new(); - let mut request = client.get(download_url).header(reqwest::header::USER_AGENT, USER_AGENT); + let mut request = client + .get(download_url) + .header(reqwest::header::USER_AGENT, USER_AGENT); if let Ok(token) = env::var("GITHUB_TOKEN") { request = request.header(reqwest::header::AUTHORIZATION, format!("token {}", token)); diff --git a/packages/js-utils/deno.lock b/packages/js-utils/deno.lock index dcbe7e5a..75d6c7d4 100644 --- a/packages/js-utils/deno.lock +++ b/packages/js-utils/deno.lock @@ -2,23 +2,59 @@ "version": "3", "packages": { "specifiers": { + "jsr:@rivet-gg/esbuild-deno-loader@^0.10.3-fork.3": "jsr:@rivet-gg/esbuild-deno-loader@0.10.3-fork.3", "jsr:@std/assert@^0.213.1": "jsr:@std/assert@0.213.1", "jsr:@std/cli@^1.0.5": "jsr:@std/cli@1.0.6", + "jsr:@std/encoding@0.213": "jsr:@std/encoding@0.213.1", "jsr:@std/fmt@^1.0.1": "jsr:@std/fmt@1.0.2", + "jsr:@std/fs@0.213": "jsr:@std/fs@0.213.1", + "jsr:@std/json@^0.213.1": "jsr:@std/json@0.213.1", + "jsr:@std/jsonc@0.213": "jsr:@std/jsonc@0.213.1", "jsr:@std/path@0.213": "jsr:@std/path@0.213.1", + "jsr:@std/path@^0.213.1": "jsr:@std/path@0.213.1", + "npm:esbuild-plugins-node-modules-polyfill@1.6.4": "npm:esbuild-plugins-node-modules-polyfill@1.6.4_esbuild@0.20.2", + "npm:esbuild@^0.20.2": "npm:esbuild@0.20.2", "npm:zod-validation-error@^3.3.1": "npm:zod-validation-error@3.4.0_zod@3.23.8", "npm:zod@^3.23.8": "npm:zod@3.23.8" }, "jsr": { + "@rivet-gg/esbuild-deno-loader@0.10.3-fork.3": { + "integrity": "41712fa34aa18d6e5b644a5921dd4ca31f5924ce327288007bc7273b092932d3", + "dependencies": [ + "jsr:@std/encoding@0.213", + "jsr:@std/jsonc@0.213", + "jsr:@std/path@0.213" + ] + }, "@std/assert@0.213.1": { "integrity": "24c28178b30c8e0782c18e8e94ea72b16282207569cdd10ffb9d1d26f2edebfe" }, "@std/cli@1.0.6": { "integrity": "d22d8b38c66c666d7ad1f2a66c5b122da1704f985d3c47f01129f05abb6c5d3d" }, + "@std/encoding@0.213.1": { + "integrity": "fcbb6928713dde941a18ca5db88ca1544d0755ec8fb20fe61e2dc8144b390c62" + }, "@std/fmt@1.0.2": { "integrity": "87e9dfcdd3ca7c066e0c3c657c1f987c82888eb8103a3a3baa62684ffeb0f7a7" }, + "@std/fs@0.213.1": { + "integrity": "fbcaf099f8a85c27ab0712b666262cda8fe6d02e9937bf9313ecaea39a22c501", + "dependencies": [ + "jsr:@std/assert@^0.213.1", + "jsr:@std/path@^0.213.1" + ] + }, + "@std/json@0.213.1": { + "integrity": "f572b1de605d07c4a5602445dac54bfc51b1fb87a3710a17aed2608bfca54e68" + }, + "@std/jsonc@0.213.1": { + "integrity": "5578f21aa583b7eb7317eed077ffcde47b294f1056bdbb9aacec407758637bfe", + "dependencies": [ + "jsr:@std/assert@^0.213.1", + "jsr:@std/json@^0.213.1" + ] + }, "@std/path@0.213.1": { "integrity": "f187bf278a172752e02fcbacf6bd78a335ed320d080a7ed3a5a59c3e88abc673", "dependencies": [ @@ -27,6 +63,183 @@ } }, "npm": { + "@esbuild/aix-ppc64@0.20.2": { + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "dependencies": {} + }, + "@esbuild/android-arm64@0.20.2": { + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "dependencies": {} + }, + "@esbuild/android-arm@0.20.2": { + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "dependencies": {} + }, + "@esbuild/android-x64@0.20.2": { + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "dependencies": {} + }, + "@esbuild/darwin-arm64@0.20.2": { + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "dependencies": {} + }, + "@esbuild/darwin-x64@0.20.2": { + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "dependencies": {} + }, + "@esbuild/freebsd-arm64@0.20.2": { + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "dependencies": {} + }, + "@esbuild/freebsd-x64@0.20.2": { + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "dependencies": {} + }, + "@esbuild/linux-arm64@0.20.2": { + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "dependencies": {} + }, + "@esbuild/linux-arm@0.20.2": { + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "dependencies": {} + }, + "@esbuild/linux-ia32@0.20.2": { + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "dependencies": {} + }, + "@esbuild/linux-loong64@0.20.2": { + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "dependencies": {} + }, + "@esbuild/linux-mips64el@0.20.2": { + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "dependencies": {} + }, + "@esbuild/linux-ppc64@0.20.2": { + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "dependencies": {} + }, + "@esbuild/linux-riscv64@0.20.2": { + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "dependencies": {} + }, + "@esbuild/linux-s390x@0.20.2": { + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "dependencies": {} + }, + "@esbuild/linux-x64@0.20.2": { + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "dependencies": {} + }, + "@esbuild/netbsd-x64@0.20.2": { + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "dependencies": {} + }, + "@esbuild/openbsd-x64@0.20.2": { + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "dependencies": {} + }, + "@esbuild/sunos-x64@0.20.2": { + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "dependencies": {} + }, + "@esbuild/win32-arm64@0.20.2": { + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "dependencies": {} + }, + "@esbuild/win32-ia32@0.20.2": { + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "dependencies": {} + }, + "@esbuild/win32-x64@0.20.2": { + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "dependencies": {} + }, + "@jspm/core@2.1.0": { + "integrity": "sha512-3sRl+pkyFY/kLmHl0cgHiFp2xEqErA8N3ECjMs7serSUBmoJ70lBa0PG5t0IM6WJgdZNyyI0R8YFfi5wM8+mzg==", + "dependencies": {} + }, + "acorn@8.14.0": { + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dependencies": {} + }, + "confbox@0.1.8": { + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dependencies": {} + }, + "esbuild-plugins-node-modules-polyfill@1.6.4_esbuild@0.20.2": { + "integrity": "sha512-x3MCOvZrKDGAfqAYS/pZUUSwiN+XH7x84A+Prup0CZBJKuGfuGkTAC4g01D6JPs/GCM9wzZVfd8bmiy+cP/iXA==", + "dependencies": { + "@jspm/core": "@jspm/core@2.1.0", + "esbuild": "esbuild@0.20.2", + "local-pkg": "local-pkg@0.5.1", + "resolve.exports": "resolve.exports@2.0.2" + } + }, + "esbuild@0.20.2": { + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dependencies": { + "@esbuild/aix-ppc64": "@esbuild/aix-ppc64@0.20.2", + "@esbuild/android-arm": "@esbuild/android-arm@0.20.2", + "@esbuild/android-arm64": "@esbuild/android-arm64@0.20.2", + "@esbuild/android-x64": "@esbuild/android-x64@0.20.2", + "@esbuild/darwin-arm64": "@esbuild/darwin-arm64@0.20.2", + "@esbuild/darwin-x64": "@esbuild/darwin-x64@0.20.2", + "@esbuild/freebsd-arm64": "@esbuild/freebsd-arm64@0.20.2", + "@esbuild/freebsd-x64": "@esbuild/freebsd-x64@0.20.2", + "@esbuild/linux-arm": "@esbuild/linux-arm@0.20.2", + "@esbuild/linux-arm64": "@esbuild/linux-arm64@0.20.2", + "@esbuild/linux-ia32": "@esbuild/linux-ia32@0.20.2", + "@esbuild/linux-loong64": "@esbuild/linux-loong64@0.20.2", + "@esbuild/linux-mips64el": "@esbuild/linux-mips64el@0.20.2", + "@esbuild/linux-ppc64": "@esbuild/linux-ppc64@0.20.2", + "@esbuild/linux-riscv64": "@esbuild/linux-riscv64@0.20.2", + "@esbuild/linux-s390x": "@esbuild/linux-s390x@0.20.2", + "@esbuild/linux-x64": "@esbuild/linux-x64@0.20.2", + "@esbuild/netbsd-x64": "@esbuild/netbsd-x64@0.20.2", + "@esbuild/openbsd-x64": "@esbuild/openbsd-x64@0.20.2", + "@esbuild/sunos-x64": "@esbuild/sunos-x64@0.20.2", + "@esbuild/win32-arm64": "@esbuild/win32-arm64@0.20.2", + "@esbuild/win32-ia32": "@esbuild/win32-ia32@0.20.2", + "@esbuild/win32-x64": "@esbuild/win32-x64@0.20.2" + } + }, + "local-pkg@0.5.1": { + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", + "dependencies": { + "mlly": "mlly@1.7.3", + "pkg-types": "pkg-types@1.2.1" + } + }, + "mlly@1.7.3": { + "integrity": "sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==", + "dependencies": { + "acorn": "acorn@8.14.0", + "pathe": "pathe@1.1.2", + "pkg-types": "pkg-types@1.2.1", + "ufo": "ufo@1.5.4" + } + }, + "pathe@1.1.2": { + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dependencies": {} + }, + "pkg-types@1.2.1": { + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "dependencies": { + "confbox": "confbox@0.1.8", + "mlly": "mlly@1.7.3", + "pathe": "pathe@1.1.2" + } + }, + "resolve.exports@2.0.2": { + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dependencies": {} + }, + "ufo@1.5.4": { + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dependencies": {} + }, "zod-validation-error@3.4.0_zod@3.23.8": { "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", "dependencies": { diff --git a/packages/js-utils/src/tasks/build/build.ts b/packages/js-utils/src/tasks/build/build.ts index bebb3584..48531f0b 100644 --- a/packages/js-utils/src/tasks/build/build.ts +++ b/packages/js-utils/src/tasks/build/build.ts @@ -1,137 +1,77 @@ -import { relative, resolve } from "@std/path"; -// import { -// ENTRYPOINT_PATH, -// OUTPUT_MANIFEST_PATH, -// projectDataPath, -// } from "../../project/project.ts"; -import { nodeModulesPolyfillPlugin } from "esbuild-plugins-node-modules-polyfill"; +import { resolve } from "@std/path"; import { denoPlugins } from "@rivet-gg/esbuild-deno-loader"; import { exists } from "@std/fs"; import * as esbuild from "esbuild"; -import { Input } from "./task.ts"; +import { Input, Output } from "./mod.ts"; -export async function build(input: Input) { - // const analyzeResult = Deno.env.get("_BACKEND_ESBUILD_META") == "1"; - // const noMinify = Deno.env.get("_BACKEND_ESBUILD_NO_MINIFY") == "1"; - // const result = await esbuild.build({ - // entryPoints: [projectDataPath(project, ENTRYPOINT_PATH)], - // outfile: bundledFile, - // format: "esm", - // sourcemap: true, - // plugins: [ - // // Bundle Deno dependencies - // ...denoPlugins(), - // - // // HACK: esbuild-deno-loader does not play nice with - // // Windows paths, so we manually resolve any paths that - // // start with a Windows path separator (\) and resolve - // // them to the full path. - // { - // name: "fix-windows-paths", - // setup(build: esbuild.PluginBuild) { - // build.onResolve({ filter: /^\\.*/ }, (args) => { - // const resolvedPath = resolve(args.resolveDir, args.path); - // if (!exists(resolvedPath, { isFile: true })) { - // return { - // errors: [{ text: `File could not be resolved: ${resolvedPath}` }], - // }; - // } - // - // return { - // path: resolve(args.resolveDir, args.path), - // }; - // }); - // }, - // } satisfies esbuild.Plugin, - // - // // Remove unused Node imports - // nodeModulesPolyfillPlugin({ - // globals: { - // Buffer: true, - // process: true, - // }, - // modules: { - // // Not used: - // // https://github.com/brianc/node-postgres/blob/50c06f9bc6ff2ca1e8d7b7268b9af54ce49d72c1/packages/pg/lib/crypto/utils.js#L3 - // crypto: "empty", - // dns: "empty", - // events: true, - // fs: "empty", - // net: "empty", - // path: "empty", - // string_decoder: true, - // tls: "empty", - // buffer: true, - // }, - // }), - // ], - // define: { - // // HACK: Disable `process.domain` in order to correctly handle this edge case: - // // https://github.com/brianc/node-postgres/blob/50c06f9bc6ff2ca1e8d7b7268b9af54ce49d72c1/packages/pg/lib/native/query.js#L126 - // "process.domain": "undefined", - // }, - // external: [ - // "node:process", - // "node:stream", - // "node:util", - // - // // Wasm must be loaded as a separate file manually, cannot be bundled - // "*.wasm", - // "*.wasm?module", - // ], - // bundle: true, - // minify: !noMinify, - // - // logLevel: analyzeResult ? "debug" : "error", - // metafile: analyzeResult, - // }); - // - // if (result.metafile) { - // console.log(await esbuild.analyzeMetafile(result.metafile)); - // } - // - // const bundleStr = await Deno.readTextFile(bundledFile); - // - // // TODO: Add ability for injecting WASM modules - // // // Find any `query-engine.wasm` - // // let wasmPath; - // // for (const module of project.modules.values()) { - // // const moduleWasmPath = resolve( - // // genPrismaOutputFolder(project, module), - // // "query_engine_bg.wasm", - // // ); - // // - // // if (await exists(moduleWasmPath)) { - // // wasmPath = moduleWasmPath; - // // break; - // // } - // // } - // // - // // // Check if wasm is actually required - // // if (wasmPath) { - // // // Make wasm import relative - // // bundleStr = bundleStr.replaceAll( - // // /file:[\w\\/\.\-]+query_engine_bg\.wasm/g, - // // "query-engine.wasm", - // // ); - // // } else if (/file:[\w\\/\.\-]+query_engine_bg\.wasm/.test(bundleStr)) { - // // throw new InternalError("Failed to find required query_engine_bg.wasm", { path: bundledFile }); - // // } - // - // await Deno.writeTextFile(bundledFile, bundleStr); - // - // // Write manifest of file paths for easier upload from Rivet CLI - // // - // // These modules are relative to the project root in case this was - // // generated from a Docker container. - // const manifest = { - // bundle: relative(project.path, bundledFile), - // wasm: undefined, - // // wasm: wasmPath ? relative(project.path, wasmPath) : undefined, - // }; - // - // await Deno.writeTextFile( - // projectDataPath(project, OUTPUT_MANIFEST_PATH), - // JSON.stringify(manifest), - // ); +export async function build(input: Input): Promise { + console.log("cwd", Deno.cwd()) + console.log("version", Deno.version) + let outfile = resolve(input.outDir, "index.js"); + const result = await esbuild.build({ + entryPoints: [input.entryPoint], + outfile, + format: "esm", + sourcemap: true, + plugins: [ + // Bundle Deno dependencies + ...denoPlugins({ + loader: "native", + configPath: input.deno.configPath, + importMapURL: input.deno.importMapUrl, + lockPath: input.deno.lockPath, + }), + + // HACK: esbuild-deno-loader does not play nice with + // Windows paths, so we manually resolve any paths that + // start with a Windows path separator (\) and resolve + // them to the full path. + // { + // name: "fix-windows-paths", + // setup(build: esbuild.PluginBuild) { + // build.onResolve({ filter: /^\\.*/ }, (args) => { + // const resolvedPath = resolve(args.resolveDir, args.path); + // if (!exists(resolvedPath, { isFile: true })) { + // return { + // errors: [{ text: `File could not be resolved: ${resolvedPath}` }], + // }; + // } + + // return { + // path: resolve(args.resolveDir, args.path), + // }; + // }); + // }, + // } satisfies esbuild.Plugin, + ], + define: { + // HACK: Disable `process.domain` in order to correctly handle this edge case: + // https://github.com/brianc/node-postgres/blob/50c06f9bc6ff2ca1e8d7b7268b9af54ce49d72c1/packages/pg/lib/native/query.js#L126 + "process.domain": "undefined", + }, + external: [ + // Provided by Deno + "node:*", + + // Wasm must be loaded as a separate file manually, cannot be bundled + "*.wasm", + "*.wasm?module", + ], + bundle: true, + minify: input.bundle.minify, + + // TODO: Remove any + logLevel: input.bundle.logLevel as any, + metafile: input.bundle.analyzeResult, + }); + + let analyzedMetafile = undefined; + if (result.metafile) { + analyzedMetafile = await esbuild.analyzeMetafile(result.metafile); + } + + return { + files: ["index.js"], + analyzedMetafile, + }; } diff --git a/packages/js-utils/src/tasks/build/mod.ts b/packages/js-utils/src/tasks/build/mod.ts new file mode 100644 index 00000000..1698cbf5 --- /dev/null +++ b/packages/js-utils/src/tasks/build/mod.ts @@ -0,0 +1,34 @@ +import { z } from "zod"; +import { globalOptsSchema } from "../../util/task/common.ts"; +import { runTask } from "../../util/task/task.ts"; +import { build } from "./build.ts"; + +export const inputSchema = z.object({ + entryPoint: z.string(), + outDir: z.string(), + deno: z.object({ + configPath: z.string().optional(), + importMapUrl: z.string().optional(), + lockPath: z.string().optional(), + }), + bundle: z.object({ + minify: z.boolean(), + analyzeResult: z.boolean(), + logLevel: z.string(), + }), +}).merge(globalOptsSchema); + +export type Input = z.infer; + +export interface Output { + files: string[]; + analyzedMetafile?: string; +} + +runTask({ + inputSchema, + async run(input) { + let output = await build(input); + console.log(JSON.stringify(output)); + }, +}); diff --git a/packages/js-utils/src/tasks/build/task.ts b/packages/js-utils/src/tasks/build/task.ts deleted file mode 100644 index 2c591823..00000000 --- a/packages/js-utils/src/tasks/build/task.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { z } from "zod"; -import { globalOptsSchema } from "../../util/task/common.ts"; -import { runTask } from "../../util/task/task.ts"; -import { build } from "./build.ts"; - -export const inputSchema = z.object({ - minify: z.boolean(), - analyzeResult: z.boolean(), -}).merge(globalOptsSchema); - -export type Input = z.infer; - -runTask({ - inputSchema, - async run(input) { - await build(input); - }, -}); diff --git a/packages/js-utils/src/util/task/task.ts b/packages/js-utils/src/util/task/task.ts index e8fa6560..fa23897a 100644 --- a/packages/js-utils/src/util/task/task.ts +++ b/packages/js-utils/src/util/task/task.ts @@ -41,8 +41,6 @@ export async function runTask(task: Task) { } catch (err) { printError(err); exitCode = 1; - } finally { - console.log("Exiting"); } Deno.exit(exitCode); diff --git a/packages/toolchain/src/config/build/javascript.rs b/packages/toolchain/src/config/build/javascript.rs index f91552ab..d1f61fa2 100644 --- a/packages/toolchain/src/config/build/javascript.rs +++ b/packages/toolchain/src/config/build/javascript.rs @@ -6,66 +6,60 @@ use super::Compression; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub struct Build { - #[serde(flatten)] - pub bundler: Bundler, - #[serde(skip_serializing_if = "Option::is_none")] - pub unstable: Option, + pub script: String, + pub bundler: Option, + #[serde(default)] + pub deno: Deno, + #[serde(default)] + pub unstable: Unstable, } impl Build { - pub fn unstable(&self) -> Unstable { - self.unstable.clone().unwrap_or_default() + pub fn bundler(&self) -> Bundler { + self.bundler.unwrap_or(Bundler::Deno) } } -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case", tag = "bundler", deny_unknown_fields)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] pub enum Bundler { - // Deno(DenoBuildMethod), - None(NoBuildMethod), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case", tag = "bundler", deny_unknown_fields)] -pub struct NoBuildMethod { - pub index_path: String, + Deno, + None, } -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case", tag = "bundler", deny_unknown_fields)] -pub struct DenoBuildMethod { - #[serde(skip_serializing_if = "Option::is_none")] - pub build_path: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub import_map: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub deno: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub bundle: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case", deny_unknown_fields)] pub struct Deno { - pub config: String, - pub no_lock: bool, - pub no_remote: bool, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case", deny_unknown_fields)] -pub struct Bundle { - pub minify: bool, + pub config_path: Option, + pub import_map_url: Option, + pub lock_path: Option, } #[derive(Default, Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "snake_case", deny_unknown_fields)] pub struct Unstable { + pub minify: Option, + pub analyze_result: Option, + pub esbuild_log_level: Option, // TODO(RVT-4127): Add compression support // pub compression: Option, } impl Unstable { + pub fn minify(&self) -> bool { + self.minify.unwrap_or(true) + } + + pub fn analyze_result(&self) -> bool { + self.analyze_result.unwrap_or(false) + } + + pub fn esbuild_log_level(&self) -> String { + self.esbuild_log_level + .clone() + .unwrap_or_else(|| "error".to_string()) + } + // TODO(RVT-4127): Add compression support pub fn compression(&self) -> Compression { Compression::None diff --git a/packages/toolchain/src/tasks/deploy/js.rs b/packages/toolchain/src/tasks/deploy/js.rs index 1438b023..64071658 100644 --- a/packages/toolchain/src/tasks/deploy/js.rs +++ b/packages/toolchain/src/tasks/deploy/js.rs @@ -9,7 +9,7 @@ use crate::{ config, paths, project::environment::TEMPEnvironment, toolchain_ctx::ToolchainCtx, - util::{net::upload, task, term}, + util::{js_utils, net::upload, task, term}, }; const BUILD_INDEX_NAME: &str = "index.js"; @@ -31,20 +31,90 @@ pub async fn build_and_upload( let project_root = paths::project_root()?; - // Determine build attributes - let build_config_unstable = opts.build_config.unstable(); - let compression = build_config_unstable.compression(); - + // Create dir to write build artifacts to let build_dir = tempfile::TempDir::new()?; - match opts.build_config.bundler { - config::build::javascript::Bundler::None(opts) => { - // Copy index file to build dir - fs::copy( - project_root.join(opts.index_path), - build_dir.path().join(BUILD_INDEX_NAME), + // Bundle JS + let compression = opts.build_config.unstable.compression(); + match opts.build_config.bundler() { + config::build::javascript::Bundler::Deno => { + // Validate that the script path has a .ts or .js extension + let script_path = project_root.join(&opts.build_config.script); + ensure!( + script_path.extension().and_then(|s| s.to_str()) == Some("ts") + || script_path.extension().and_then(|s| s.to_str()) == Some("js"), + "script file must have a .ts or .js extension for Deno bundler" + ); + + // Search for deno.json or deno.jsonc + let deno_config_path = ["deno.json", "deno.jsonc"] + .iter() + .find_map(|file_name| { + let path = project_root.join(file_name); + if path.exists() { + Some(path.display().to_string()) + } else { + None + } + }); + + // Search for a Deno lockfile + let deno_lockfile_path = ["deno.lock"] + .iter() + .find_map(|file_name| { + let path = project_root.join(file_name); + if path.exists() { + Some(path.display().to_string()) + } else { + None + } + }); + + // Build the bundle to the output dir. This will bundle all Deno dependencies into a + // single JS file. + // + // The Deno command is run in the project root, so `config_path`, `lock_path`, etc can + // all safely be passed as relative paths without joining with `project_root`. + let output = js_utils::run_command_and_parse_output::< + js_utils::schemas::build::Input, + js_utils::schemas::build::Output, + >( + "src/tasks/build/mod.ts", + &js_utils::schemas::build::Input { + entry_point: script_path, + out_dir: build_dir.path().to_path_buf(), + deno: js_utils::schemas::build::Deno { + config_path: deno_config_path.or_else(|| opts + .build_config + .deno + .config_path + .map(|x| project_root.join(x).display().to_string())), + import_map_url: opts.build_config.deno.import_map_url.clone(), + lock_path: deno_lockfile_path.or_else(|| opts.build_config.deno.lock_path.clone()), + }, + bundle: js_utils::schemas::build::Bundle { + minify: opts.build_config.unstable.minify(), + analyze_result: opts.build_config.unstable.analyze_result(), + log_level: opts.build_config.unstable.esbuild_log_level(), + }, + }, ) .await?; + if let Some(analyze_result) = output.analyzed_metafile { + task.log("[Bundle Analysis]"); + task.log(analyze_result); + } + } + config::build::javascript::Bundler::None => { + // Ensure the script path has a .js extension + let script_path = project_root.join(opts.build_config.script); + ensure!( + script_path.extension().and_then(|s| s.to_str()) == Some("js"), + "script file must have a .js extension when not using a bundler" + ); + + // Copy index file to build dir + fs::copy(script_path, build_dir.path().join(BUILD_INDEX_NAME)).await?; } }; diff --git a/packages/toolchain/src/util/js_utils/mod.rs b/packages/toolchain/src/util/js_utils/mod.rs index 56b619c2..2097e4dd 100644 --- a/packages/toolchain/src/util/js_utils/mod.rs +++ b/packages/toolchain/src/util/js_utils/mod.rs @@ -1,10 +1,13 @@ use anyhow::*; +use serde::de::DeserializeOwned; use serde::Serialize; -use std::{collections::HashMap, path::PathBuf, process::ExitCode}; +use std::{collections::HashMap, path::PathBuf}; use tokio::process::Command; use crate::{paths, util::task}; +pub mod schemas; + pub struct CommandOpts { pub task_path: &'static str, pub input: serde_json::Value, @@ -59,7 +62,7 @@ pub async fn build_backend_command_raw(opts: CommandOpts) -> Result format!("{base_url}/deno.jsonc"), "--lock".into(), format!("{base_url}/deno.lock"), - format!("{base_url}/cli/tasks/{}", opts.task_path), + format!("{base_url}/{}", opts.task_path), "--input".into(), input_json, ], @@ -71,6 +74,7 @@ pub async fn build_backend_command_raw(opts: CommandOpts) -> Result pub async fn build_backend_command(opts: CommandOpts) -> Result { let cmd_raw = build_backend_command_raw(opts).await?; let mut cmd = Command::new(cmd_raw.command); + cmd.kill_on_drop(true); cmd.args(cmd_raw.args) .envs(cmd_raw.envs) .current_dir(cmd_raw.current_dir); @@ -84,43 +88,45 @@ pub async fn run_backend_command_from_task(task: task::TaskCtx, opts: CommandOpt Ok(exit_code.code().unwrap_or(0)) } -pub async fn run_backend_command_passthrough( - task_path: &'static str, - input: &impl Serialize, -) -> ExitCode { - let input_json = match serde_json::to_value(input) { - Result::Ok(x) => x, - Err(err) => { - eprintln!("Serialize failed: {err:?}"); - return ExitCode::FAILURE; - } - }; +pub async fn run_command_and_parse_output( + js_task_path: &'static str, + input: &Input, +) -> Result { + let input_json = + serde_json::to_value(input).map_err(|err| anyhow!("Failed to serialize input: {err}"))?; - let mut cmd = match build_backend_command(CommandOpts { - task_path, + let mut cmd = build_backend_command(CommandOpts { + task_path: js_task_path, input: input_json, env: HashMap::new(), }) .await - { - Result::Ok(x) => x, - Err(err) => { - eprintln!("Error building command: {err:?}"); - return ExitCode::FAILURE; - } - }; - - let exit_code = match cmd.status().await { - Result::Ok(x) => x, - Err(err) => { - eprintln!("Error running command: {err:?}"); - return ExitCode::FAILURE; + .map_err(|err| anyhow!("Failed to build command: {err}"))?; + + let output = cmd + .output() + .await + .map_err(|err| anyhow!("Failed to run command: {err}"))?; + + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + + if output.status.success() { + if let Some(last_line) = stdout.lines().rev().find(|line| !line.trim().is_empty()) { + serde_json::from_str(last_line).map_err(|err| { + anyhow!("Failed to parse JSON from output: {err}\nOutput: {last_line}") + }) + } else { + Err(anyhow!("No non-blank lines in output\nStdout: {stdout}\nStderr: {stderr}")) } - }; - - if exit_code.success() { - ExitCode::SUCCESS } else { - ExitCode::FAILURE + let mut error_message = format!("Command failed with status: {}", output.status); + if !stdout.is_empty() { + error_message.push_str(&format!("\nstdout:\n{stdout}")); + } + if !stderr.is_empty() { + error_message.push_str(&format!("\nstderr:\n{stderr}")); + } + Err(anyhow!(error_message)) } } diff --git a/packages/toolchain/src/util/js_utils/schemas.rs b/packages/toolchain/src/util/js_utils/schemas.rs new file mode 100644 index 00000000..2c4bd141 --- /dev/null +++ b/packages/toolchain/src/util/js_utils/schemas.rs @@ -0,0 +1,39 @@ +pub mod build { + use serde::{Deserialize, Serialize}; + use std::path::PathBuf; + + #[derive(Serialize)] + #[serde(rename_all = "camelCase")] + pub struct Input { + pub entry_point: PathBuf, + pub out_dir: PathBuf, + pub deno: Deno, + pub bundle: Bundle, + } + + #[derive(Serialize)] + #[serde(rename_all = "camelCase")] + pub struct Deno { + #[serde(skip_serializing_if = "Option::is_none")] + pub config_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub import_map_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub lock_path: Option, + } + + #[derive(Serialize)] + #[serde(rename_all = "camelCase")] + pub struct Bundle { + pub minify: bool, + pub analyze_result: bool, + pub log_level: String, + } + + #[derive(Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct Output { + pub files: Vec, + pub analyzed_metafile: Option, + } +} diff --git a/scripts/postgres/mirror_release.ts b/scripts/postgres/mirror_release.ts deleted file mode 100755 index 0be802db..00000000 --- a/scripts/postgres/mirror_release.ts +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env -S deno run --allow-net --allow-env - -import { S3Bucket } from "https://deno.land/x/s3@0.5.0/mod.ts"; -import { assert } from "https://deno.land/std@0.224.0/testing/asserts.ts"; - -const GITHUB_REPO = "https://github.com/theseus-rs/postgresql-binaries"; -const BUCKET_NAME = "rivet-releases"; -const BUCKET_FOLDER = "postgres"; - -interface ReleaseData { - assets: { - name: string; - browser_download_url: string; - }[]; -} - -async function mirrorRelease(releaseName: string) { - const bucket = new S3Bucket({ - accessKeyID: Deno.env.get("AWS_ACCESS_KEY_ID")!, - secretKey: Deno.env.get("AWS_SECRET_ACCESS_KEY")!, - bucket: BUCKET_NAME, - region: "auto", - endpointURL: "https://2a94c6a0ced8d35ea63cddc86c2681e7.r2.cloudflarestorage.com/rivet-releases", - }); - - const releaseUrl = `https://api.github.com/repos/theseus-rs/postgresql-binaries/releases/tags/${releaseName}`; - console.log(`Fetching release information from ${releaseUrl}...`); - const response = await fetch(releaseUrl); - - if (!response.ok) { - console.error(`Failed to fetch release information. Status: ${response.status}`); - Deno.exit(1); - } - - const releaseData = await response.json() as ReleaseData; - const assets = releaseData.assets; - - assert(assets.length > 0, `No files found for release ${releaseName}. Please check the release name and try again. You can find a list of all releases at ${GITHUB_REPO}/releases.`); - - console.log(`Found ${assets.length} files to mirror.`); - - for (const asset of assets) { - const fileName = asset.name; - const downloadUrl = asset.browser_download_url; - const objectKey = `${BUCKET_FOLDER}/${releaseName}/${fileName}`; - - const existingObj = await bucket.headObject(objectKey); - if (existingObj) { - console.log(`Skipping ${fileName} (already exists)`); - } else { - console.log(`Downloading ${fileName}...`); - const fileResponse = await fetch(downloadUrl); - const fileData = await fileResponse.arrayBuffer(); - - console.log(`Uploading ${fileName} to ${BUCKET_NAME}/${objectKey}...`); - await bucket.putObject(objectKey, new Uint8Array(fileData)); - console.log(`Uploaded ${fileName}`); - } - } - - console.log(`Finished mirroring release ${releaseName}.`); -} - -const release = Deno.env.get("RELEASE_NAME"); -if (!release) { - console.error("Please provide a release name via the RELEASE_NAME environment variable"); - Deno.exit(1); -} - -await mirrorRelease(release);