From 65fe5febb3ada0949b8c3548d83847ef1eb2808f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 19 Sep 2026 17:21:19 +0200 Subject: [PATCH 1/5] fix(tooling): classify four net.Socket providers and unmask the ledger gate `scripts/native_result_ledger.py` is red on pristine `main`, blocking the path-filtered `Native Result Ledger / check` workflow on every PR that touches `native_table/**` or the ledger itself. Two independent defects, one hiding the other. 1. Stale row count (bookkeeping). #10658's `net.Socket` surface cluster landed in merge train 221 and grew `native_table/net_events.rs` from 53 to 58 typed rows. `EXPECTED_ROWS` stayed at 371, so the gate failed with `expected 371 classified rows, found 376`. 2. Four unclassified providers (the real defect). Those five new rows carry four runtime symbols that were never added to `native_result_ledger.tsv`, so the table declared a result class the provider inventory had no opinion about. An unclassified `result_kind` misrepresents to the GC what a native call returns. The count check runs FIRST and raises, so the classification-coverage check never executed: the stale constant was acting as a mask. Bumping the constant alone would have turned the gate green and shipped (2). Each of the four providers was read, not name-matched. All four return their `handle: i64` argument unchanged -- a `next_id_or_throw()` registry id and key into `statics::sockets()`, not a heap address -- which is exactly `NativeRetKind::HandleId` ("an integer registry id or provider sentinel"): js_ext_net_socket_on perry-ext-net/src/handle_exports.rs:65 js_net_socket_prepend_listener perry-ext-net/src/lifecycle.rs:1040 js_net_socket_prepend_once_listener perry-ext-net/src/lifecycle.rs:1060 js_net_socket_unpipe perry-ext-net/src/pipe.rs:325 `js_ext_net_socket_on` backs two rows (`on` and `addListener` share the symbol), hence five rows from four symbols. The sibling `js_net_socket_pipe` returns `f64`/`NR_F64`, which the scanner does not classify, so it needs no row. Constants: EXPECTED_ROWS 371 -> 376, EXPECTED_PROVIDERS 322 -> 326. These describe `main` as it stands at 023dc0b653; in-flight binding-removal PRs that also move `EXPECTED_ROWS` re-derive their own number at rebase time. --- scripts/native_result_ledger.py | 13 +++++++++++-- scripts/native_result_ledger.tsv | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/native_result_ledger.py b/scripts/native_result_ledger.py index 5b3e166c1a..7ca06de8c5 100644 --- a/scripts/native_result_ledger.py +++ b/scripts/native_result_ledger.py @@ -23,8 +23,17 @@ # prose comments in fastify.rs, while one real row uses the positional `cr(...)` # helper, leaving 371 executable declarations. The scanner parses declarations, # not comments, and includes that helper row. -EXPECTED_ROWS = 371 -EXPECTED_PROVIDERS = 322 +# +# +5 rows / +4 providers since then (#10738): #10658's `net.Socket` surface +# cluster landed in merge train 221 and grew `native_table/net_events.rs` from +# 53 to 58 typed rows, carrying four new runtime symbols — +# `js_ext_net_socket_on` (two rows: `on` and `addListener` share the symbol), +# `js_net_socket_prepend_listener`, `js_net_socket_prepend_once_listener` and +# `js_net_socket_unpipe`. Each returns its `handle: i64` argument unchanged, a +# `next_id_or_throw()` registry id rather than a heap address, so all four are +# NR_HANDLE_ID. +EXPECTED_ROWS = 376 +EXPECTED_PROVIDERS = 326 KINDS = { "NR_GCPTR", "NR_NULLABLE_GCPTR", diff --git a/scripts/native_result_ledger.tsv b/scripts/native_result_ledger.tsv index 45bcc5c586..170454102d 100644 --- a/scripts/native_result_ledger.tsv +++ b/scripts/native_result_ledger.tsv @@ -74,6 +74,7 @@ js_events_on NR_GCPTR crates/perry-ext-events/src/module_on.rs *mut ArrayHeader js_events_once NR_GCPTR crates/perry-ext-events/src/lib.rs *mut Promise js_ext_net_create_server NR_HANDLE_ID crates/perry-ext-net/src/lib.rs i64 js_ext_net_socket_connect NR_HANDLE_ID crates/perry-ext-net/src/lib.rs i64 +js_ext_net_socket_on NR_HANDLE_ID crates/perry-ext-net/src/handle_exports.rs i64 js_ext_net_socket_once NR_HANDLE_ID crates/perry-ext-net/src/handle_exports.rs i64 js_ext_tls_connect NR_HANDLE_ID crates/perry-ext-net/src/tls.rs i64 js_fastify_app_server NR_HANDLE_ID crates/perry-ext-fastify/src/app.rs Handle @@ -161,6 +162,8 @@ js_net_socket_address_new NR_HANDLE_ID crates/perry-ext-net/src/classes.rs i64 js_net_socket_alloc NR_HANDLE_ID crates/perry-ext-net/src/lib.rs i64 js_net_socket_listeners NR_GCPTR crates/perry-ext-net/src/lifecycle.rs i64 js_net_socket_noop_self NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 +js_net_socket_prepend_listener NR_HANDLE_ID crates/perry-ext-net/src/lifecycle.rs i64 +js_net_socket_prepend_once_listener NR_HANDLE_ID crates/perry-ext-net/src/lifecycle.rs i64 js_net_socket_raw_listeners NR_GCPTR crates/perry-ext-net/src/lifecycle.rs i64 js_net_socket_ref NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_net_socket_remove_all_listeners NR_HANDLE_ID crates/perry-ext-net/src/lifecycle.rs i64 @@ -169,6 +172,7 @@ js_net_socket_reset_and_destroy NR_HANDLE_ID crates/perry-ext-net/src/lifecycle. js_net_socket_set_encoding NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_net_socket_set_timeout NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_net_socket_set_type_of_service NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 +js_net_socket_unpipe NR_HANDLE_ID crates/perry-ext-net/src/pipe.rs i64 js_net_socket_unref NR_HANDLE_ID crates/perry-ext-net/src/option_setters.rs i64 js_node_forge_certificate_from_pem NR_JS_VALUE crates/perry-ext-node-forge/src/lib.rs JsValue js_node_forge_create_certificate NR_JS_VALUE crates/perry-ext-node-forge/src/lib.rs JsValue From 13828a970a068304dd9fd9366b82377e1ea85e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 19 Sep 2026 17:22:23 +0200 Subject: [PATCH 2/5] docs: changelog fragment for #10740 --- ...tive-result-ledger-net-socket-providers.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 changelog.d/10740-native-result-ledger-net-socket-providers.md diff --git a/changelog.d/10740-native-result-ledger-net-socket-providers.md b/changelog.d/10740-native-result-ledger-net-socket-providers.md new file mode 100644 index 0000000000..e37592c059 --- /dev/null +++ b/changelog.d/10740-native-result-ledger-net-socket-providers.md @@ -0,0 +1,36 @@ +Fix `scripts/native_result_ledger.py`, which was red on `main` and blocking +the path-filtered `Native Result Ledger` workflow on every PR touching +`crates/perry-codegen/src/lower_call/native_table/**` or the ledger files. + +Two defects, one masking the other. `EXPECTED_ROWS` was stale at 371 while +#10658's `net.Socket` surface cluster (merge train 221) grew +`native_table/net_events.rs` from 53 to 58 typed rows. Behind that stale +count sat the real problem: those five rows carry four runtime symbols that +had no entry in `scripts/native_result_ledger.tsv`, so the codegen table +declared a result class the provider inventory had no opinion about — and an +unclassified `result_kind` misrepresents to the GC what a native call +returns. Because `check()` raises on its first failure, the row-count check +never let the classification-coverage check run, so bumping the constant +alone would have turned the gate green and shipped the real defect. + +Each provider was read rather than name-matched. All four return their +`handle: i64` argument unchanged — a `next_id_or_throw()` registry id and key +into `statics::sockets()`, not a heap address — so all four are +`NR_HANDLE_ID` (`NativeRetKind::HandleId`, "an integer registry id or +provider sentinel"): + +- `js_ext_net_socket_on` — `crates/perry-ext-net/src/handle_exports.rs` +- `js_net_socket_prepend_listener` — `crates/perry-ext-net/src/lifecycle.rs` +- `js_net_socket_prepend_once_listener` — `crates/perry-ext-net/src/lifecycle.rs` +- `js_net_socket_unpipe` — `crates/perry-ext-net/src/pipe.rs` + +Four symbols across five rows: `js_ext_net_socket_on` backs both the `on` and +the `addListener` rows. The sibling `js_net_socket_pipe` returns `f64` under +`ret: NR_F64`, which the scanner does not classify, so it needs no row. + +`EXPECTED_ROWS` 371 → 376 and `EXPECTED_PROVIDERS` 322 → 326, with the +existing explanatory comment extended to attribute the delta to #10658 and +train 221. The gate was re-proved to bite: deleting a new row reddens it on +the provider count, deleting it with the count adjusted reddens it naming the +symbol, and misclassifying `js_net_socket_unpipe` as `NR_GCPTR` reddens it on +the table/provider disagreement. From 12797db82704b16ca4e8ef06335ab2c96f71ba87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 19 Sep 2026 07:04:16 +0000 Subject: [PATCH 3/5] refactor(stdlib): remove uuid native binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the native uuid binding so `import { v4, parse, stringify, NIL } from "uuid"` (no perry.compilePackages entry) resolves to the real npm package compiled from source, per the owner's decision to stop shipping hand-written Rust reimplementations of npm packages. The native binding is missing `parse`/`stringify` entirely (a `parse`/`stringify` roundtrip throws: `bytes` comes back `undefined`), and `NIL` reads as `undefined` (js_uuid_nil exists in the deleted source but was never wired into either NativeModSig dispatch table or the API manifest, so property access on the uuid module namespace fell through to undefined). v1/v3/v4/v5/validate/version were correct in both. Per #10678 (duplicate extern "C" exports across perry-ext-*/perry-stdlib pairs), this binding existed twice: crates/perry-ext-uuid/ (the governance-tracked binding crate) and crates/perry-stdlib/src/uuid.rs (a second, independent implementation behind the now-removed bundled-uuid feature). Both are deleted, along with the 7-entry NativeModSig dispatch block in native_table/utils_crypto.rs, the well_known_bindings.toml entry, the "uuid" NATIVE_MODULES entry and its 7 manifest rows, and the 6 Android stub exports. crypto/random.rs entanglement: crypto.randomUUID()/randomUUID({v7:true}) and nodemailer's message-id generation both call the `uuid` Cargo crate (uuid::Uuid::new_v4()/now_v7()) directly and unconditionally — neither site has a cfg(feature) gate. The `uuid` crate dependency in perry-stdlib/Cargo.toml was therefore never actually optional in practice even though it was declared `optional = true` behind the bundled-uuid npm-binding feature; removing that feature without also dropping `optional = true` would have broken the build the moment bundled-uuid stopped being enabled. Made `uuid` a required (non-optional) dependency and retargeted the `ids` feature umbrella to `["bundled-nanoid"]`. crypto.randomUUID()/randomUUID({v7:true}) and node:crypto's randomBytes are unaffected — verified below. Retargeted the one dts-shape regression test that used uuid.v4() as its zero-arg-module-function fixture (perry-api-manifest's dts_uuid_v4_has_no_args) to perry/gc.minor(), which is unrelated to any binding-removal churn. Built on perrymaster (--profile perry-dev). A real `npm install uuid` project (no perry.compilePackages entry) exercising v1/v4/v5/v3, validate/version, a parse/stringify roundtrip, and NIL, diffed against `node --experimental-strip-types` (Node 26.5.1): byte-for-byte identical, including the deterministic v5/v3 (name+namespace) values. Confirmed against a pristine origin/main (8df83f8c1) baseline build that the same program crashes there: `NIL: undefined`, `parse instanceof Uint8Array: false`, then `TypeError: Cannot read properties of undefined (reading 'length')` on the roundtrip — reproducing the reported bug exactly. crypto.randomUUID() and node:crypto's randomBytes/randomUUID were re-checked against the fix and still work (both call the `uuid` crate directly, unaffected by the binding removal). - cargo build --profile perry-dev -p perry -p perry-runtime-static -p perry-stdlib-static: clean; confirmed .a mtimes moved. - cargo check --workspace --all-targets (host-compatible exclusion set via workspace_architecture.py --print-excluded-scope) under -D warnings: clean. - cargo test -p perry-api-manifest: 39+4 passing (after retargeting the uuid-fixture test). - cargo test -p perry-codegen --test manifest_consistency: 5/5 passing. - cargo test -p perry --bin perry -- well_known: 27/27 passing. - cargo test -p perry-hir: full suite passing (test_lower_native_module_ registration uses "uuid" only as synthetic example data for a generic register/lookup mechanism — unaffected by the registry removal). - python3 scripts/binding_governance.py --check: OK (39 extension crates). - node scripts/binding_pins.mjs --check: OK (37 pinned, lock-step holds). - python3 scripts/workspace_architecture.py --check: OK. - python3 scripts/native_result_ledger.py: OK, 371 rows/322 providers unchanged (none of uuid's dispatch rows used a ledger-tracked NR_* kind). - python3 scripts/string_payload_access_inventory.py --write-baseline: perry-stdlib inline-offset 40 -> 38 (uuid.rs's own 2 sites). - Regenerated docs/api/perry.d.ts + docs/src/api/reference.md (perry --print-api-manifest) and docs/src/native-libraries/ governance.md (binding_governance.py --table) from the fixed manifest. - cargo fmt --all -- --check: clean. - scripts/run_lint_gates.sh (SKIP_COMPILE_GATES=1): 76 of 77 passed; the one failure (Public benchmark evidence freshness) is the pre-existing, known-red-on-every-PR gate per this campaign's contract. - Compile tier of run_lint_gates.sh (known-red on Linux per this campaign's contract). - Full gap suite (host stalls under auto-optimize per contract). - test-files/test_parity_uuid.ts is already excluded from the parity gate (test-parity/known_failures.json, "ci-env": Node's own oracle run fails ERR_MODULE_NOT_FOUND because uuid was never added to the repo's root package.json/package-lock.json — the same pre-existing gap documented for nanoid, #8271). Its `@covers` comment now points at a deleted file (crates/perry-stdlib/src/uuid.rs); leaving it untouched, matching how the sibling nanoid PR (#10693) left its own equivalent parity fixture alone. - No version bump / CLAUDE.md edit — per this campaign's convention, the maintainer bumps at merge time. - crates/perry-ui-android/src/stdlib_stubs.rs was edited to remove the matching 6 js_uuid_* stub exports (following the established pattern from the sibling removals) but not build-verified — this host has no Android NDK and the package is excluded from the host-compatible check scope. --- Cargo.lock | 8 - Cargo.toml | 2 - crates/perry-api-manifest/src/emit.rs | 16 +- crates/perry-api-manifest/src/entries.rs | 1 - .../perry-api-manifest/src/entries/part_1.rs | 65 ------ .../lower_call/native_table/utils_crypto.rs | 74 ------- crates/perry-ext-uuid/Cargo.toml | 19 -- crates/perry-ext-uuid/src/lib.rs | 206 ------------------ crates/perry-stdlib/Cargo.toml | 9 +- crates/perry-stdlib/src/lib.rs | 4 - crates/perry-stdlib/src/uuid.rs | 127 ----------- crates/perry-ui-android/src/stdlib_stubs.rs | 24 -- .../perry/src/commands/compile/well_known.rs | 2 +- crates/perry/src/commands/stdlib_features.rs | 1 - crates/perry/well_known_bindings.toml | 15 -- docs/api/perry.d.ts | 19 +- docs/src/api/reference.md | 15 +- docs/src/native-libraries/governance.md | 1 - scripts/string_payload_access_baseline.txt | 2 +- scripts/unrooted_local_shape_baseline.json | 3 +- workspace-architecture.json | 9 +- 21 files changed, 23 insertions(+), 599 deletions(-) delete mode 100644 crates/perry-ext-uuid/Cargo.toml delete mode 100644 crates/perry-ext-uuid/src/lib.rs delete mode 100644 crates/perry-stdlib/src/uuid.rs diff --git a/Cargo.lock b/Cargo.lock index 8d6a3d63a2..cbc7b386db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6215,14 +6215,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "perry-ext-uuid" -version = "0.5.1603" -dependencies = [ - "perry-ffi", - "uuid", -] - [[package]] name = "perry-ext-ws" version = "0.5.1603" diff --git a/Cargo.toml b/Cargo.toml index db69ec9ec0..f87bd22316 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ members = [ "crates/perry-native-registration", "crates/perry-ext-dotenv", "crates/perry-ext-nanoid", - "crates/perry-ext-uuid", "crates/perry-ext-bcrypt", "crates/perry-ext-argon2", "crates/perry-perex", @@ -476,7 +475,6 @@ perry-ffi = { path = "crates/perry-ffi", version = "0.5.1011" } perry-native-registration = { path = "crates/perry-native-registration", version = "0.5.1534" } perry-ext-dotenv = { path = "crates/perry-ext-dotenv" } perry-ext-nanoid = { path = "crates/perry-ext-nanoid" } -perry-ext-uuid = { path = "crates/perry-ext-uuid" } perry-ext-bcrypt = { path = "crates/perry-ext-bcrypt" } perry-ext-argon2 = { path = "crates/perry-ext-argon2" } perry-perex = { path = "crates/perry-perex" } diff --git a/crates/perry-api-manifest/src/emit.rs b/crates/perry-api-manifest/src/emit.rs index 1c42e002de..5a3945493b 100644 --- a/crates/perry-api-manifest/src/emit.rs +++ b/crates/perry-api-manifest/src/emit.rs @@ -880,18 +880,22 @@ mod tests { } } - /// uuid.v4() is no-args and returns a string — verify the renderer - /// emits an empty arg list instead of `(...args: any[])`. + /// perry/gc.minor() is no-args and returns a number — verify the + /// renderer emits an empty arg list instead of `(...args: any[])`. + /// (Formerly used uuid.v4() as the fixture; retargeted when the uuid + /// native binding was removed — see #10678/#466.) #[test] - fn dts_uuid_v4_has_no_args() { + fn dts_zero_arg_module_fn_has_no_args() { let dts = emit_dts("test"); - let block_start = dts.find("declare module \"uuid\"").expect("uuid block"); + let block_start = dts + .find("declare module \"perry/gc\"") + .expect("perry/gc block"); let after = &dts[block_start..]; let block_end = after.find("\n}\n").expect("block end"); let block = &after[..block_end]; assert!( - block.contains("export function v4(): string"), - "uuid.v4 should be (): string\nblock: {}", + block.contains("export function minor(): number"), + "perry/gc.minor should be (): number\nblock: {}", block ); } diff --git a/crates/perry-api-manifest/src/entries.rs b/crates/perry-api-manifest/src/entries.rs index d0d365f8d3..09604c36e7 100644 --- a/crates/perry-api-manifest/src/entries.rs +++ b/crates/perry-api-manifest/src/entries.rs @@ -32,7 +32,6 @@ pub const NATIVE_MODULES: &[&str] = &[ "mysql2", // MySQL/MariaDB client "mysql2/promise", // mysql2's promise-API subpath "pg", // PostgreSQL client - "uuid", // RFC-4122 UUID generation "qs", // nested query-string parser/stringifier (Stripe dependency) "bcrypt", // bcrypt password hashing (replaces the N-API addon) "argon2", // Argon2 password hashing (replaces the N-API addon) diff --git a/crates/perry-api-manifest/src/entries/part_1.rs b/crates/perry-api-manifest/src/entries/part_1.rs index bc68f1b035..2b801b3cf7 100644 --- a/crates/perry-api-manifest/src/entries/part_1.rs +++ b/crates/perry-api-manifest/src/entries/part_1.rs @@ -1101,71 +1101,6 @@ pub(crate) const API_MANIFEST_PART_1: &[ApiEntry] = &[ method("decimal.js", "isZero", true, None), method("decimal.js", "isPositive", true, None), method("decimal.js", "isNegative", true, None), - method_sig("uuid", "v4", false, None, &[], TypeSpec::String), - method_sig("uuid", "v1", false, None, &[], TypeSpec::String), - method_sig("uuid", "v7", false, None, &[], TypeSpec::String), - method_sig( - "uuid", - "v5", - false, - None, - &[ - ParamSpec::Named { - name: "name", - ty: TypeSpec::String, - optional: false, - }, - ParamSpec::Named { - name: "namespace", - ty: TypeSpec::String, - optional: false, - }, - ], - TypeSpec::String, - ), - method_sig( - "uuid", - "v3", - false, - None, - &[ - ParamSpec::Named { - name: "name", - ty: TypeSpec::String, - optional: false, - }, - ParamSpec::Named { - name: "namespace", - ty: TypeSpec::String, - optional: false, - }, - ], - TypeSpec::String, - ), - method_sig( - "uuid", - "validate", - false, - None, - &[ParamSpec::Named { - name: "id", - ty: TypeSpec::String, - optional: false, - }], - TypeSpec::Bool, - ), - method_sig( - "uuid", - "version", - false, - None, - &[ParamSpec::Named { - name: "id", - ty: TypeSpec::String, - optional: false, - }], - TypeSpec::Number, - ), method_sig( "nodemailer", "createTransport", diff --git a/crates/perry-codegen/src/lower_call/native_table/utils_crypto.rs b/crates/perry-codegen/src/lower_call/native_table/utils_crypto.rs index 9d73a01b09..96529d8cd8 100644 --- a/crates/perry-codegen/src/lower_call/native_table/utils_crypto.rs +++ b/crates/perry-codegen/src/lower_call/native_table/utils_crypto.rs @@ -1,80 +1,6 @@ use super::*; pub(super) const UTILS_CRYPTO_ROWS: &[NativeModSig] = &[ - // ========== uuid ========== - // All generators return `*mut StringHeader`, so they must box as - // NR_STR (STRING_TAG) — NR_PTR boxed them as a generic native handle - // and `v4()` read back as `[object Object]` (#5197). - NativeModSig { - module: "uuid", - has_receiver: false, - method: "v4", - class_filter: None, - runtime: "js_uuid_v4", - args: &[], - ret: NR_STR, - }, - NativeModSig { - module: "uuid", - has_receiver: false, - method: "v1", - class_filter: None, - runtime: "js_uuid_v1", - args: &[], - ret: NR_STR, - }, - NativeModSig { - module: "uuid", - has_receiver: false, - method: "v7", - class_filter: None, - runtime: "js_uuid_v7", - args: &[], - ret: NR_STR, - }, - // v5 (SHA-1) / v3 (MD5) name-based: `vN(name, namespace)`. The shim - // supports the string-UUID namespace form; the array-namespace form - // is only reachable via `perry.compilePackages`. - NativeModSig { - module: "uuid", - has_receiver: false, - method: "v5", - class_filter: None, - runtime: "js_uuid_v5", - args: &[NA_STR, NA_STR], - ret: NR_STR, - }, - NativeModSig { - module: "uuid", - has_receiver: false, - method: "v3", - class_filter: None, - runtime: "js_uuid_v3", - args: &[NA_STR, NA_STR], - ret: NR_STR, - }, - NativeModSig { - module: "uuid", - has_receiver: false, - method: "validate", - class_filter: None, - runtime: "js_uuid_validate", - // Runtime sig is `*const StringHeader` → coerce the arg to a - // string pointer (NA_F64 passed raw NaN-box bits, so validate - // always read 0 — #5197). NR_BOOL boxes the 1.0/0.0 result as a - // real JS boolean so it prints `true`/`false`, not `1`/`0`. - args: &[NA_STR], - ret: NR_BOOL, - }, - NativeModSig { - module: "uuid", - has_receiver: false, - method: "version", - class_filter: None, - runtime: "js_uuid_version", - args: &[NA_STR], - ret: NR_F64, - }, // ========== nodemailer ========== NativeModSig { module: "nodemailer", diff --git a/crates/perry-ext-uuid/Cargo.toml b/crates/perry-ext-uuid/Cargo.toml deleted file mode 100644 index ee33a83746..0000000000 --- a/crates/perry-ext-uuid/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "perry-ext-uuid" -version.workspace = true -edition.workspace = true -license.workspace = true -description = "Native bindings for the npm `uuid` package — uses only `perry-ffi`. Third port under #466 Phase 5 (after dotenv + nanoid)." - -[lints] -workspace = true - -[lib] -crate-type = ["staticlib", "rlib"] - -[dependencies] -perry-ffi.workspace = true -uuid = { version = "1.23", features = ["v1", "v3", "v4", "v5", "v7"] } - -[dev-dependencies] -perry-ffi = { workspace = true, features = ["runtime-link"] } diff --git a/crates/perry-ext-uuid/src/lib.rs b/crates/perry-ext-uuid/src/lib.rs deleted file mode 100644 index cded359210..0000000000 --- a/crates/perry-ext-uuid/src/lib.rs +++ /dev/null @@ -1,206 +0,0 @@ -//! Native bindings for the npm `uuid` package. -//! -//! Functionally identical to `crates/perry-stdlib/src/uuid.rs`. Only -//! depends on [`perry_ffi`] — third wrapper port under #466 Phase 5. - -use perry_ffi::{alloc_string, read_string, JsString, StringHeader}; -use uuid::Uuid; - -/// `uuid.v4()` — random UUID. -#[no_mangle] -pub extern "C" fn js_uuid_v4() -> *mut StringHeader { - let uuid = Uuid::new_v4(); - alloc_string(&uuid.to_string()).as_raw() -} - -/// `uuid.v1()` — timestamp + node-id UUID. Node id is random -/// (Perry doesn't introspect the host MAC). -#[no_mangle] -pub extern "C" fn js_uuid_v1() -> *mut StringHeader { - let ts = uuid::Timestamp::now(uuid::NoContext); - let uuid = Uuid::new_v1(ts, &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab]); - alloc_string(&uuid.to_string()).as_raw() -} - -/// `uuid.v7()` — Unix-timestamp UUID. -#[no_mangle] -pub extern "C" fn js_uuid_v7() -> *mut StringHeader { - let uuid = Uuid::now_v7(); - alloc_string(&uuid.to_string()).as_raw() -} - -/// Parse a NaN-boxed namespace argument into a `Uuid`. The shim only -/// supports the string-UUID namespace form (`v5(name, '6ba7…')`), which -/// covers the `uuid.v5.DNS`/`uuid.v5.URL` constants and the overwhelming -/// majority of real usage. A non-string / unparseable namespace falls -/// back to the nil UUID rather than crashing — the array-namespace form -/// is only reachable via `perry.compilePackages` (real source). -unsafe fn parse_namespace(ns_ptr: *const StringHeader) -> Uuid { - let handle = JsString::from_raw(ns_ptr as *mut StringHeader); - read_string(handle) - .and_then(|s| Uuid::parse_str(s).ok()) - .unwrap_or_else(Uuid::nil) -} - -/// `uuid.v5(name, namespace)` — SHA-1 name-based UUID. -/// -/// # Safety -/// -/// `name_ptr` / `ns_ptr` must be null or Perry-runtime `StringHeader` -/// pointers. -#[no_mangle] -pub unsafe extern "C" fn js_uuid_v5( - name_ptr: *const StringHeader, - ns_ptr: *const StringHeader, -) -> *mut StringHeader { - let name = read_string(JsString::from_raw(name_ptr as *mut StringHeader)).unwrap_or(""); - let namespace = parse_namespace(ns_ptr); - let uuid = Uuid::new_v5(&namespace, name.as_bytes()); - alloc_string(&uuid.to_string()).as_raw() -} - -/// `uuid.v3(name, namespace)` — MD5 name-based UUID. -/// -/// # Safety -/// -/// `name_ptr` / `ns_ptr` must be null or Perry-runtime `StringHeader` -/// pointers. -#[no_mangle] -pub unsafe extern "C" fn js_uuid_v3( - name_ptr: *const StringHeader, - ns_ptr: *const StringHeader, -) -> *mut StringHeader { - let name = read_string(JsString::from_raw(name_ptr as *mut StringHeader)).unwrap_or(""); - let namespace = parse_namespace(ns_ptr); - let uuid = Uuid::new_v3(&namespace, name.as_bytes()); - alloc_string(&uuid.to_string()).as_raw() -} - -/// `uuid.validate(str) -> boolean` — encoded as `1.0` / `0.0` -/// because the Perry FFI ABI carries booleans as f64. -/// -/// # Safety -/// -/// `str_ptr` must be null or a Perry-runtime `StringHeader` pointer. -#[no_mangle] -pub unsafe extern "C" fn js_uuid_validate(str_ptr: *const StringHeader) -> f64 { - let handle = JsString::from_raw(str_ptr as *mut StringHeader); - let Some(s) = read_string(handle) else { - return 0.0; - }; - if Uuid::parse_str(s).is_ok() { - 1.0 - } else { - 0.0 - } -} - -/// `uuid.version(str) -> number` — version digit, or `NaN` if the -/// input isn't a valid UUID. -/// -/// # Safety -/// -/// `str_ptr` must be null or a Perry-runtime `StringHeader` pointer. -#[no_mangle] -pub unsafe extern "C" fn js_uuid_version(str_ptr: *const StringHeader) -> f64 { - let handle = JsString::from_raw(str_ptr as *mut StringHeader); - let Some(s) = read_string(handle) else { - return f64::NAN; - }; - match Uuid::parse_str(s) { - Ok(uuid) => uuid.get_version_num() as f64, - Err(_) => f64::NAN, - } -} - -/// `uuid.NIL` — all-zeros sentinel UUID, as a string. -#[no_mangle] -pub extern "C" fn js_uuid_nil() -> *mut StringHeader { - alloc_string(&Uuid::nil().to_string()).as_raw() -} - -#[cfg(test)] -mod tests { - use super::*; - - fn read_handle(handle: *mut StringHeader) -> String { - read_string(unsafe { JsString::from_raw(handle) }) - .expect("non-null") - .to_string() - } - - #[test] - fn v4_is_36_chars_with_dashes() { - let s = read_handle(js_uuid_v4()); - assert_eq!(s.len(), 36); - assert_eq!(s.chars().filter(|c| *c == '-').count(), 4); - } - - #[test] - fn v1_v7_round_trip_through_validate_and_version() { - // Spelled out per-version because `extern "C" fn` doesn't - // coerce to plain `fn` without a wrapper closure, and the - // payoff of compressing two assertions isn't worth one. - for (s, want_ver) in [ - (read_handle(js_uuid_v1()), 1.0), - (read_handle(js_uuid_v7()), 7.0), - ] { - let s_handle = alloc_string(&s); - let valid = unsafe { js_uuid_validate(s_handle.as_raw() as *const _) }; - assert_eq!(valid, 1.0, "{} should validate", s); - let ver = unsafe { js_uuid_version(s_handle.as_raw() as *const _) }; - assert_eq!(ver, want_ver, "{} version", s); - } - } - - #[test] - fn validate_rejects_garbage() { - let s = alloc_string("not a uuid"); - let valid = unsafe { js_uuid_validate(s.as_raw() as *const _) }; - assert_eq!(valid, 0.0); - } - - #[test] - fn version_returns_nan_for_garbage() { - let s = alloc_string("not a uuid"); - let ver = unsafe { js_uuid_version(s.as_raw() as *const _) }; - assert!(ver.is_nan()); - } - - #[test] - fn nil_is_all_zeros_with_dashes() { - let s = read_handle(js_uuid_nil()); - assert_eq!(s, "00000000-0000-0000-0000-000000000000"); - } - - #[test] - fn v5_matches_the_reference_vector() { - // `v5('perry', '6ba7b810-9dad-11d1-80b4-00c04fd430c8')` — the - // exact value Node's `uuid` produces (issue #5197). - let name = alloc_string("perry"); - let ns = alloc_string("6ba7b810-9dad-11d1-80b4-00c04fd430c8"); - let id = - read_handle(unsafe { js_uuid_v5(name.as_raw() as *const _, ns.as_raw() as *const _) }); - assert_eq!(id, "6cb3836f-339d-52d8-acc6-8751229b61cf"); - let id_handle = alloc_string(&id); - assert_eq!( - unsafe { js_uuid_version(id_handle.as_raw() as *const _) }, - 5.0 - ); - } - - #[test] - fn v3_matches_the_reference_vector() { - // `v3('perry', '6ba7b810-9dad-11d1-80b4-00c04fd430c8')`. - let name = alloc_string("perry"); - let ns = alloc_string("6ba7b810-9dad-11d1-80b4-00c04fd430c8"); - let id = - read_handle(unsafe { js_uuid_v3(name.as_raw() as *const _, ns.as_raw() as *const _) }); - assert_eq!(id, "3533df6e-72b1-3859-a772-7410b3d2f9c2"); - let id_handle = alloc_string(&id); - assert_eq!( - unsafe { js_uuid_version(id_handle.as_raw() as *const _) }, - 3.0 - ); - } -} diff --git a/crates/perry-stdlib/Cargo.toml b/crates/perry-stdlib/Cargo.toml index 0bf7059911..d56b9fd646 100644 --- a/crates/perry-stdlib/Cargo.toml +++ b/crates/perry-stdlib/Cargo.toml @@ -297,8 +297,7 @@ bundled-ratelimit = ["dep:governor", "async-runtime"] # Phase 4 step 2) toggles. Each sub-feature pulls in its own # optional dep + gates its own module so a wrapper port can strip # exactly one binding from perry-stdlib without affecting the other. -ids = ["bundled-uuid", "bundled-nanoid"] -bundled-uuid = ["dep:uuid"] +ids = ["bundled-nanoid"] bundled-nanoid = ["dep:nanoid"] # Async runtime (tokio) - internal feature @@ -440,7 +439,11 @@ governor = { version = "0.10", optional = true } # Validation # IDs -uuid = { version = "1.23", features = ["v4", "v1", "v3", "v5", "v7"], optional = true } +# Required unconditionally by crypto/random.rs (crypto.randomUUID / +# randomUUID({ v7: true })), which has no feature gate of its own — +# never optional, regardless of the bundled-uuid npm-binding feature +# (removed; see #10678/#466). +uuid = { version = "1.23", features = ["v4", "v1", "v3", "v5", "v7"] } nanoid = { version = "0.5", optional = true } # LRU Cache — optional from v0.5.539 so the well-known flip can diff --git a/crates/perry-stdlib/src/lib.rs b/crates/perry-stdlib/src/lib.rs index 17b47f6bbd..41c5353d1e 100644 --- a/crates/perry-stdlib/src/lib.rs +++ b/crates/perry-stdlib/src/lib.rs @@ -413,10 +413,6 @@ pub use ratelimit::*; // each binding independently. The umbrella stays as // `ids = ["bundled-uuid", "bundled-nanoid"]` so existing // `--features ids` callers keep working byte-identically. -#[cfg(feature = "bundled-uuid")] -pub mod uuid; -#[cfg(feature = "bundled-uuid")] -pub use uuid::*; #[cfg(feature = "bundled-nanoid")] pub mod nanoid; diff --git a/crates/perry-stdlib/src/uuid.rs b/crates/perry-stdlib/src/uuid.rs deleted file mode 100644 index 1fa8b90020..0000000000 --- a/crates/perry-stdlib/src/uuid.rs +++ /dev/null @@ -1,127 +0,0 @@ -//! UUID generation module -//! -//! Native implementation of the 'uuid' npm package using the Rust uuid crate. -//! Supports v1, v4, and v7 UUID generation. - -use perry_runtime::{js_string_from_bytes, StringHeader}; -use uuid::Uuid; - -/// Generate a v4 (random) UUID and return it as a string -/// uuid.v4() -> string -#[no_mangle] -pub extern "C" fn js_uuid_v4() -> *mut StringHeader { - let uuid = Uuid::new_v4(); - let uuid_str = uuid.to_string(); - js_string_from_bytes(uuid_str.as_ptr(), uuid_str.len() as u32) -} - -/// Generate a v1 (timestamp + MAC address) UUID and return it as a string -/// uuid.v1() -> string -/// Note: Uses a random node ID since we don't have access to real MAC -#[no_mangle] -pub extern "C" fn js_uuid_v1() -> *mut StringHeader { - // v1 requires a timestamp and node ID - // We use now_v1 which generates based on current time with random node - let ts = uuid::Timestamp::now(uuid::NoContext); - let uuid = Uuid::new_v1(ts, &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab]); - let uuid_str = uuid.to_string(); - js_string_from_bytes(uuid_str.as_ptr(), uuid_str.len() as u32) -} - -/// Generate a v7 (Unix timestamp-based) UUID and return it as a string -/// uuid.v7() -> string -#[no_mangle] -pub extern "C" fn js_uuid_v7() -> *mut StringHeader { - let uuid = Uuid::now_v7(); - let uuid_str = uuid.to_string(); - js_string_from_bytes(uuid_str.as_ptr(), uuid_str.len() as u32) -} - -/// Parse a namespace argument (string-UUID form) into a `Uuid`, falling -/// back to the nil UUID when the argument isn't a parseable UUID string. -/// The array-namespace form is only reachable via `perry.compilePackages`. -unsafe fn parse_namespace(ns_ptr: *const StringHeader) -> Uuid { - let namespace = crate::common::string_from_header(ns_ptr).unwrap_or_default(); - Uuid::parse_str(&namespace).unwrap_or_else(|_| Uuid::nil()) -} - -/// Generate a v5 (SHA-1 name-based) UUID and return it as a string -/// uuid.v5(name, namespace) -> string -#[no_mangle] -pub unsafe extern "C" fn js_uuid_v5( - name_ptr: *const StringHeader, - ns_ptr: *const StringHeader, -) -> *mut StringHeader { - let namespace = parse_namespace(ns_ptr); - let name = crate::common::string_from_header(name_ptr).unwrap_or_default(); - let uuid = Uuid::new_v5(&namespace, name.as_bytes()); - let uuid_str = uuid.to_string(); - js_string_from_bytes(uuid_str.as_ptr(), uuid_str.len() as u32) -} - -/// Generate a v3 (MD5 name-based) UUID and return it as a string -/// uuid.v3(name, namespace) -> string -#[no_mangle] -pub unsafe extern "C" fn js_uuid_v3( - name_ptr: *const StringHeader, - ns_ptr: *const StringHeader, -) -> *mut StringHeader { - let namespace = parse_namespace(ns_ptr); - let name = crate::common::string_from_header(name_ptr).unwrap_or_default(); - let uuid = Uuid::new_v3(&namespace, name.as_bytes()); - let uuid_str = uuid.to_string(); - js_string_from_bytes(uuid_str.as_ptr(), uuid_str.len() as u32) -} - -/// Validate if a string is a valid UUID -/// uuid.validate(str) -> boolean -#[no_mangle] -pub unsafe extern "C" fn js_uuid_validate(str_ptr: *const StringHeader) -> f64 { - if str_ptr.is_null() { - return 0.0; // false - } - - let len = (*str_ptr).byte_len as usize; - let data_ptr = (str_ptr as *const u8).add(std::mem::size_of::()); - let bytes = std::slice::from_raw_parts(data_ptr, len); - - match std::str::from_utf8(bytes) { - Ok(s) => { - if Uuid::parse_str(s).is_ok() { - 1.0 // true - } else { - 0.0 // false - } - } - Err(_) => 0.0, // false - } -} - -/// Get the version of a UUID string -/// uuid.version(str) -> number -#[no_mangle] -pub unsafe extern "C" fn js_uuid_version(str_ptr: *const StringHeader) -> f64 { - if str_ptr.is_null() { - return f64::NAN; - } - - let len = (*str_ptr).byte_len as usize; - let data_ptr = (str_ptr as *const u8).add(std::mem::size_of::()); - let bytes = std::slice::from_raw_parts(data_ptr, len); - - match std::str::from_utf8(bytes) { - Ok(s) => match Uuid::parse_str(s) { - Ok(uuid) => uuid.get_version_num() as f64, - Err(_) => f64::NAN, - }, - Err(_) => f64::NAN, - } -} - -/// Generate a NIL UUID (all zeros) -/// uuid.NIL -> string (constant) -#[no_mangle] -pub extern "C" fn js_uuid_nil() -> *mut StringHeader { - let uuid_str = Uuid::nil().to_string(); - js_string_from_bytes(uuid_str.as_ptr(), uuid_str.len() as u32) -} diff --git a/crates/perry-ui-android/src/stdlib_stubs.rs b/crates/perry-ui-android/src/stdlib_stubs.rs index a086f0c45c..99951335a2 100644 --- a/crates/perry-ui-android/src/stdlib_stubs.rs +++ b/crates/perry-ui-android/src/stdlib_stubs.rs @@ -1446,30 +1446,6 @@ pub extern "C" fn js_sqlite_transaction_commit() -> i64 { pub extern "C" fn js_sqlite_transaction_rollback() -> i64 { 0 } -#[no_mangle] -pub extern "C" fn js_uuid_nil() -> i64 { - 0 -} -#[no_mangle] -pub extern "C" fn js_uuid_v1() -> i64 { - 0 -} -#[no_mangle] -pub extern "C" fn js_uuid_v4() -> i64 { - 0 -} -#[no_mangle] -pub extern "C" fn js_uuid_v7() -> i64 { - 0 -} -#[no_mangle] -pub extern "C" fn js_uuid_validate() -> i64 { - 0 -} -#[no_mangle] -pub extern "C" fn js_uuid_version() -> i64 { - 0 -} // readline (#347) — TUI use case isn't relevant on Android, so stubs // return inert values (handle 0, no-op for everything). The `_active` // stub returns 0 so the host event loop doesn't keep ticking. diff --git a/crates/perry/src/commands/compile/well_known.rs b/crates/perry/src/commands/compile/well_known.rs index 573723d2e9..f23031ba8a 100644 --- a/crates/perry/src/commands/compile/well_known.rs +++ b/crates/perry/src/commands/compile/well_known.rs @@ -485,7 +485,7 @@ mod tests { #[test] fn shipped_unproven_bindings_are_partial() { - for name in ["dotenv", "nanoid", "uuid"] { + for name in ["dotenv", "nanoid"] { let b = lookup_well_known(name).unwrap_or_else(|| panic!("{name} registered")); assert_eq!( b.compat, diff --git a/crates/perry/src/commands/stdlib_features.rs b/crates/perry/src/commands/stdlib_features.rs index b0117047f2..e508bceb8b 100644 --- a/crates/perry/src/commands/stdlib_features.rs +++ b/crates/perry/src/commands/stdlib_features.rs @@ -166,7 +166,6 @@ pub fn module_to_features(module: &str) -> &'static [&'static str] { // perry-stdlib/Cargo.toml as `bundled-uuid + bundled-nanoid` // for backwards compat, but feature-set computation goes // straight to the per-binding feature. - "uuid" => &["bundled-uuid"], "nanoid" => &["bundled-nanoid"], // ── Container ───────────────────────────────────────────────── diff --git a/crates/perry/well_known_bindings.toml b/crates/perry/well_known_bindings.toml index c0c6b2f983..db16d7c6b9 100644 --- a/crates/perry/well_known_bindings.toml +++ b/crates/perry/well_known_bindings.toml @@ -76,21 +76,6 @@ repo = "https://github.com/ai/nanoid" ref = "4dacb107b54ffd0e1abfe91b7ef452e0fd5a8e12" ported-at = "6.0.0" date = "2026-07-30" -[bindings.uuid] -crate = "perry-ext-uuid" -lib = "perry_ext_uuid" -tracking = "#466" -# Partial: several upstream exports and input forms are absent (including -# parse/stringify and newer conversion/constants APIs). -compat = "partial" - -[bindings.uuid.upstream] -version = "14.0.1" -sha256 = "e062c57ed120ea135478f305da04802bf69eab23fbc0ca2bae6989b6855390c4" -repo = "https://github.com/uuidjs/uuid" -ref = "70177807e9229dfacde2038dc1e722f1828f358a" -ported-at = "14.0.1" -date = "2026-07-30" [bindings.qs] crate = "perry-ext-qs" lib = "perry_ext_qs" diff --git a/docs/api/perry.d.ts b/docs/api/perry.d.ts index 1dfe4903dd..c798cd7bb3 100644 --- a/docs/api/perry.d.ts +++ b/docs/api/perry.d.ts @@ -1,6 +1,6 @@ // Auto-generated from Perry's API manifest (#465). Do not edit by hand. // Source: perry-api-manifest::API_MANIFEST -// Coverage: 2085 entries across 134 modules +// Coverage: 2078 entries across 133 modules type PerryI8 = number & { readonly __perryI8?: never }; type PerryI16 = number & { readonly __perryI16?: never }; @@ -4362,23 +4362,6 @@ declare module "util/types" { export function isWeakSet(...args: any[]): any; } -declare module "uuid" { - /** stdlib */ - export function v1(): string; - /** stdlib */ - export function v3(name: string, namespace: string): string; - /** stdlib */ - export function v4(): string; - /** stdlib */ - export function v5(name: string, namespace: string): string; - /** stdlib */ - export function v7(): string; - /** stdlib */ - export function validate(id: string): boolean; - /** stdlib */ - export function version(id: string): number; -} - declare module "v8" { /** stdlib */ export class DefaultDeserializer { [key: string]: any; } diff --git a/docs/src/api/reference.md b/docs/src/api/reference.md index 128b24f1e8..d1d9f3bbd5 100644 --- a/docs/src/api/reference.md +++ b/docs/src/api/reference.md @@ -2,7 +2,7 @@ This page is auto-generated from Perry's compile-time API manifest (`perry-api-manifest::API_MANIFEST`). It is the source of truth for what `perry compile` accepts; references to symbols not listed here produce `R005 UnimplementedApi` (issue #463). Stubs (#464) are flagged ⚠ — they link cleanly but no-op at runtime on the chosen target. -Total: 3027 entries across 136 modules. +Total: 3020 entries across 135 modules. ## Modules @@ -135,7 +135,6 @@ Total: 3027 entries across 136 modules. - [`url`](#url) - [`util`](#util) - [`util/types`](#utiltypes) -- [`uuid`](#uuid) - [`v8`](#v8) - [`vm`](#vm) - [`wasi`](#wasi) @@ -3916,18 +3915,6 @@ Total: 3027 entries across 136 modules. - `isWeakMap` — module - `isWeakSet` — module -## `uuid` - -### Methods - -- `v1` — module -- `v3` — module -- `v4` — module -- `v5` — module -- `v7` — module -- `validate` — module -- `version` — module - ## `v8` ### Classes diff --git a/docs/src/native-libraries/governance.md b/docs/src/native-libraries/governance.md index 4886a87a77..297f380946 100644 --- a/docs/src/native-libraries/governance.md +++ b/docs/src/native-libraries/governance.md @@ -119,7 +119,6 @@ from `well_known_bindings.toml`. Regenerate this table with | `perry-ext-streams` | `streams` | Runtime API | Keep near core; consolidate when practical | Bundled; retained | | `perry-ext-typescript` | `typescript` | Source package | Compile the upstream package source | Bundled; migration pending | | `perry-ext-undici` | `undici` | Source package | Compile the upstream package source | Bundled; migration pending | -| `perry-ext-uuid` | `uuid` | Source package | Compile the upstream package source | Bundled; migration pending | | `perry-ext-ws` | `ws` | Runtime API | Keep near core; consolidate when practical | Bundled; retained | | `perry-ext-zlib` | `zlib` | Runtime API | Keep near core; consolidate when practical | Bundled; retained | diff --git a/scripts/string_payload_access_baseline.txt b/scripts/string_payload_access_baseline.txt index bc1ba4ef70..c1069bc178 100644 --- a/scripts/string_payload_access_baseline.txt +++ b/scripts/string_payload_access_baseline.txt @@ -13,7 +13,7 @@ inline-offset | perry-ext-pg | 2 inline-offset | perry-ext-zlib | 3 inline-offset | perry-ffi | 3 inline-offset | perry-runtime | 350 -inline-offset | perry-stdlib | 39 +inline-offset | perry-stdlib | 37 inline-offset | perry-updater | 5 reader-helper | perry-ext-ethers | 1 reader-helper | perry-runtime | 13 diff --git a/scripts/unrooted_local_shape_baseline.json b/scripts/unrooted_local_shape_baseline.json index 5ecbec01f0..7aae581ae2 100644 --- a/scripts/unrooted_local_shape_baseline.json +++ b/scripts/unrooted_local_shape_baseline.json @@ -29,7 +29,6 @@ "crates/perry-ext-pg/src/lib.rs": 7, "crates/perry-ext-ratelimit/src/lib.rs": 4, "crates/perry-ext-streams/src/lib.rs": 4, - "crates/perry-ext-uuid/src/lib.rs": 2, "crates/perry-ext-ws/src/server.rs": 3, "crates/perry-ext-zlib/src/stream.rs": 3, "crates/perry-stdlib/src/cheerio.rs": 6, @@ -86,5 +85,5 @@ "crates/perry-stdlib/src/zlib.rs": 3 }, "schema_version": 3, - "total": 580 + "total": 578 } diff --git a/workspace-architecture.json b/workspace-architecture.json index 3f5c8d42fd..ebca2c85f8 100644 --- a/workspace-architecture.json +++ b/workspace-architecture.json @@ -25,7 +25,7 @@ ] }, "baseline": { - "workspace_members": 80, + "workspace_members": 79, "default_dependency_closure": [ "perry", "perry-api-manifest", @@ -68,7 +68,7 @@ "perry-updater" ], "decision_counts": { - "externalize": 31, + "externalize": 30, "keep": 44, "merge": 1, "remove": 1, @@ -315,11 +315,6 @@ "decision": "externalize", "migration": "compile-source" }, - "perry-ext-uuid": { - "category": "binding", - "decision": "externalize", - "migration": "compile-source" - }, "perry-ext-ws": { "category": "binding", "decision": "keep", From 3374dbbd039432be3e34b11156f6f2e4341ed694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 19 Sep 2026 07:05:48 +0000 Subject: [PATCH 4/5] changelog: add fragment for #10701 (uuid native binding removal) --- .../10701-uuid-native-binding-removal.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 changelog.d/10701-uuid-native-binding-removal.md diff --git a/changelog.d/10701-uuid-native-binding-removal.md b/changelog.d/10701-uuid-native-binding-removal.md new file mode 100644 index 0000000000..9dc178f98f --- /dev/null +++ b/changelog.d/10701-uuid-native-binding-removal.md @@ -0,0 +1,20 @@ +Removed the native `uuid` binding: it is missing `parse`/`stringify` +entirely (a roundtrip throws — `parse` returns `undefined`), and `NIL` +reads as `undefined` (`js_uuid_nil` existed in the deleted source but was +never wired into either the `NativeModSig` dispatch table or the API +manifest). `import { v4, parse, stringify, NIL } from "uuid"` (no +`perry.compilePackages` entry) now compiles the real npm package from +source, matching Node byte-for-byte. + +Deleted both duplicate hand-written implementations +(`crates/perry-ext-uuid` and `crates/perry-stdlib/src/uuid.rs`, which +independently exported the same `js_uuid_*` symbols — #10678). + +`crypto.randomUUID()`/`randomUUID({ v7: true })` and nodemailer's +message-id generation both call the `uuid` Cargo crate directly and +unconditionally, with no feature gate — the dependency in +`perry-stdlib/Cargo.toml` was declared `optional = true` behind the +now-removed `bundled-uuid` npm-binding feature but was never actually +optional in practice. Made it a required dependency so those two call +sites keep compiling once `bundled-uuid` is gone; verified +`crypto.randomUUID()` still works. From 1376bbf0434ce9e1f26ebe74ece509ca3349b58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Sat, 19 Sep 2026 18:07:20 +0200 Subject: [PATCH 5/5] chore: release merge train 225 as v0.5.1604 --- CLAUDE.md | 2 +- Cargo.lock | 154 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 3 files changed, 79 insertions(+), 79 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1e4ecd3eaf..39dbd67118 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation. -**Current Version:** 0.5.1603 +**Current Version:** 0.5.1604 ## TypeScript Parity Status diff --git a/Cargo.lock b/Cargo.lock index cbc7b386db..ebd1fecdee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5623,7 +5623,7 @@ checksum = "1473d470930ed48574515a25df34900f3af89c6fa422d903e019121312a9f13e" [[package]] name = "perry" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "base64 0.22.1", @@ -5687,7 +5687,7 @@ dependencies = [ [[package]] name = "perry-api-manifest" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-dispatch", "serde", @@ -5695,7 +5695,7 @@ dependencies = [ [[package]] name = "perry-audio-miniaudio" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "cc", "libc", @@ -5704,7 +5704,7 @@ dependencies = [ [[package]] name = "perry-codegen" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "aho-corasick", "anyhow", @@ -5721,7 +5721,7 @@ dependencies = [ [[package]] name = "perry-codegen-arkts" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-hir", @@ -5729,7 +5729,7 @@ dependencies = [ [[package]] name = "perry-codegen-glance" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-hir", @@ -5737,7 +5737,7 @@ dependencies = [ [[package]] name = "perry-codegen-js" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-dispatch", @@ -5746,7 +5746,7 @@ dependencies = [ [[package]] name = "perry-codegen-swiftui" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-hir", @@ -5754,7 +5754,7 @@ dependencies = [ [[package]] name = "perry-codegen-wasm" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "base64 0.22.1", @@ -5766,7 +5766,7 @@ dependencies = [ [[package]] name = "perry-codegen-wear-tiles" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-hir", @@ -5774,7 +5774,7 @@ dependencies = [ [[package]] name = "perry-container-compose" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "async-trait", "clap", @@ -5798,14 +5798,14 @@ dependencies = [ [[package]] name = "perry-container-e2e" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", ] [[package]] name = "perry-diagnostics" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "serde", "serde_json", @@ -5813,7 +5813,7 @@ dependencies = [ [[package]] name = "perry-dispatch" -version = "0.5.1603" +version = "0.5.1604" [[package]] name = "perry-doc-fixture-my-bindings" @@ -5824,7 +5824,7 @@ dependencies = [ [[package]] name = "perry-doc-tests" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "clap", @@ -5839,7 +5839,7 @@ dependencies = [ [[package]] name = "perry-ext-ads" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "block2", "objc2", @@ -5849,7 +5849,7 @@ dependencies = [ [[package]] name = "perry-ext-argon2" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "argon2", "perry-ffi", @@ -5858,7 +5858,7 @@ dependencies = [ [[package]] name = "perry-ext-axios" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "reqwest", @@ -5867,7 +5867,7 @@ dependencies = [ [[package]] name = "perry-ext-bcrypt" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "bcrypt", "perry-ffi", @@ -5875,7 +5875,7 @@ dependencies = [ [[package]] name = "perry-ext-better-sqlite3" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "rusqlite", @@ -5883,7 +5883,7 @@ dependencies = [ [[package]] name = "perry-ext-cheerio" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "scraper", @@ -5891,7 +5891,7 @@ dependencies = [ [[package]] name = "perry-ext-commander" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "perry-runtime", @@ -5899,7 +5899,7 @@ dependencies = [ [[package]] name = "perry-ext-cron" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "chrono", "cron", @@ -5909,7 +5909,7 @@ dependencies = [ [[package]] name = "perry-ext-dayjs" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "chrono", "perry-ffi", @@ -5917,7 +5917,7 @@ dependencies = [ [[package]] name = "perry-ext-decimal" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "rust_decimal", @@ -5925,7 +5925,7 @@ dependencies = [ [[package]] name = "perry-ext-dotenv" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "serde_json", @@ -5933,7 +5933,7 @@ dependencies = [ [[package]] name = "perry-ext-ethers" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "rand 0.10.2", @@ -5941,7 +5941,7 @@ dependencies = [ [[package]] name = "perry-ext-events" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "perry-runtime", @@ -5949,14 +5949,14 @@ dependencies = [ [[package]] name = "perry-ext-exponential-backoff" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-fastify" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "bytes", "http-body-util", @@ -5973,7 +5973,7 @@ dependencies = [ [[package]] name = "perry-ext-fetch" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "bytes", "lazy_static", @@ -5986,7 +5986,7 @@ dependencies = [ [[package]] name = "perry-ext-http" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "bytes", @@ -6018,7 +6018,7 @@ dependencies = [ [[package]] name = "perry-ext-ioredis" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "lazy_static", "perry-ffi", @@ -6028,7 +6028,7 @@ dependencies = [ [[package]] name = "perry-ext-lru-cache" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "lru", "perry-ffi", @@ -6037,7 +6037,7 @@ dependencies = [ [[package]] name = "perry-ext-moment" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "chrono", "perry-ffi", @@ -6045,7 +6045,7 @@ dependencies = [ [[package]] name = "perry-ext-mongodb" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "bson", "futures-util", @@ -6057,7 +6057,7 @@ dependencies = [ [[package]] name = "perry-ext-mysql2" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "chrono", "perry-ffi", @@ -6069,7 +6069,7 @@ dependencies = [ [[package]] name = "perry-ext-nanoid" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "nanoid", "perry-ffi", @@ -6078,7 +6078,7 @@ dependencies = [ [[package]] name = "perry-ext-net" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "bytes", "perry-ffi", @@ -6093,7 +6093,7 @@ dependencies = [ [[package]] name = "perry-ext-node-forge" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "const-oid 0.10.2", "der 0.8.2", @@ -6112,7 +6112,7 @@ dependencies = [ [[package]] name = "perry-ext-nodemailer" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "lettre", "perry-ffi", @@ -6122,7 +6122,7 @@ dependencies = [ [[package]] name = "perry-ext-parcel-watcher" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "notify", "perry-ffi", @@ -6134,7 +6134,7 @@ dependencies = [ [[package]] name = "perry-ext-pdf" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "printpdf", @@ -6142,7 +6142,7 @@ dependencies = [ [[package]] name = "perry-ext-pg" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "sqlx", @@ -6151,7 +6151,7 @@ dependencies = [ [[package]] name = "perry-ext-qs" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "perry-runtime", @@ -6160,7 +6160,7 @@ dependencies = [ [[package]] name = "perry-ext-ratelimit" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "governor", "perry-ffi", @@ -6168,7 +6168,7 @@ dependencies = [ [[package]] name = "perry-ext-sharp" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "fast_image_resize", "image", @@ -6179,7 +6179,7 @@ dependencies = [ [[package]] name = "perry-ext-streams" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "lazy_static", "perry-ffi", @@ -6188,7 +6188,7 @@ dependencies = [ [[package]] name = "perry-ext-typescript" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-ffi", @@ -6208,7 +6208,7 @@ dependencies = [ [[package]] name = "perry-ext-undici" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-ffi", "perry-runtime", @@ -6217,7 +6217,7 @@ dependencies = [ [[package]] name = "perry-ext-ws" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "futures-util", "lazy_static", @@ -6230,7 +6230,7 @@ dependencies = [ [[package]] name = "perry-ext-zlib" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "brotli", "flate2", @@ -6240,7 +6240,7 @@ dependencies = [ [[package]] name = "perry-ffi" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "dashmap 6.2.1", "once_cell", @@ -6250,7 +6250,7 @@ dependencies = [ [[package]] name = "perry-hir" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-api-manifest", @@ -6270,11 +6270,11 @@ dependencies = [ [[package]] name = "perry-native-registration" -version = "0.5.1603" +version = "0.5.1604" [[package]] name = "perry-parser" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "perry-diagnostics", @@ -6287,7 +6287,7 @@ dependencies = [ [[package]] name = "perry-perex" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perex", "regex", @@ -6295,7 +6295,7 @@ dependencies = [ [[package]] name = "perry-runtime" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "ahash", "base64 0.22.1", @@ -6353,14 +6353,14 @@ dependencies = [ [[package]] name = "perry-runtime-static" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-runtime", ] [[package]] name = "perry-stdlib" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "aes 0.8.4", "aes 0.9.1", @@ -6447,21 +6447,21 @@ dependencies = [ [[package]] name = "perry-stdlib-static" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-stdlib", ] [[package]] name = "perry-transform" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "perry-hir", ] [[package]] name = "perry-ui" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "dirs", "perry-ffi", @@ -6471,7 +6471,7 @@ dependencies = [ [[package]] name = "perry-ui-android" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "jni", @@ -6486,7 +6486,7 @@ dependencies = [ [[package]] name = "perry-ui-geisterhand" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "rand 0.10.2", "serde", @@ -6496,7 +6496,7 @@ dependencies = [ [[package]] name = "perry-ui-gtk4" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "cairo-rs 0.22.9", @@ -6519,7 +6519,7 @@ dependencies = [ [[package]] name = "perry-ui-ios" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "block2", @@ -6536,7 +6536,7 @@ dependencies = [ [[package]] name = "perry-ui-macos" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "block2", @@ -6553,7 +6553,7 @@ dependencies = [ [[package]] name = "perry-ui-model" -version = "0.5.1603" +version = "0.5.1604" [[package]] name = "perry-ui-test" @@ -6564,11 +6564,11 @@ dependencies = [ [[package]] name = "perry-ui-testkit" -version = "0.5.1603" +version = "0.5.1604" [[package]] name = "perry-ui-tvos" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "block2", @@ -6585,7 +6585,7 @@ dependencies = [ [[package]] name = "perry-ui-visionos" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "block2", @@ -6602,7 +6602,7 @@ dependencies = [ [[package]] name = "perry-ui-watchos" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "block2", "libc", @@ -6616,7 +6616,7 @@ dependencies = [ [[package]] name = "perry-ui-windows" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "libc", @@ -6635,7 +6635,7 @@ dependencies = [ [[package]] name = "perry-ui-windows-winui" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "base64 0.22.1", "libc", @@ -6648,7 +6648,7 @@ dependencies = [ [[package]] name = "perry-updater" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "anyhow", "base64 0.22.1", @@ -6663,7 +6663,7 @@ dependencies = [ [[package]] name = "perry-wasm-host" -version = "0.5.1603" +version = "0.5.1604" dependencies = [ "wasmi", ] diff --git a/Cargo.toml b/Cargo.toml index f87bd22316..b8cf098885 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -334,7 +334,7 @@ codegen-units = 1 codegen-units = 1 [workspace.package] -version = "0.5.1603" +version = "0.5.1604" edition = "2021" license = "MIT" repository = "https://github.com/PerryTS/perry"