diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa33bcf152c..1740a8e5e7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,11 +109,24 @@ jobs: with: global-json-file: global.json + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - uses: pnpm/action-setup@v4 + with: + run_install: true + - name: Create /stdb dir run: | sudo mkdir /stdb sudo chmod 777 /stdb + - name: Build typescript module sdk + working-directory: crates/bindings-typescript + run: pnpm build + - name: Run cargo test #Note: Unreal tests will be run separately run: cargo test --all -- --skip unreal diff --git a/.gitignore b/.gitignore index 3d6c2da169a..f06da623de2 100644 --- a/.gitignore +++ b/.gitignore @@ -166,6 +166,7 @@ linux-target/ ### VisualStudioCode ### .vscode/* +.vscode !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json diff --git a/Cargo.lock b/Cargo.lock index fa6cb645241..a29c980d5d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,6 +177,12 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" +[[package]] +name = "append-only-vec" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7992085ec035cfe96992dd31bfd495a2ebd31969bb95f624471cb6c0b349e571" + [[package]] name = "approx" version = "0.3.2" @@ -195,6 +201,12 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arcstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" + [[package]] name = "array-init" version = "2.1.0" @@ -213,6 +225,17 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "async-scoped" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4042078ea593edffc452eef14e99fdb2b120caa4ad9618bcdeabc4a023b98740" +dependencies = [ + "futures", + "pin-project", + "tokio", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -417,6 +440,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base-encode" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17bd29f7c70f32e9387f4d4acfa5ea7b7749ef784fb78cf382df97069337b8c" + [[package]] name = "base64" version = "0.21.7" @@ -429,6 +458,16 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + [[package]] name = "benchmarks-module" version = "0.1.0" @@ -459,13 +498,33 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bindgen" version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.12.1", @@ -488,7 +547,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cexpr", "clang-sys", "itertools 0.12.1", @@ -540,9 +599,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ "serde", ] @@ -627,9 +686,12 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +dependencies = [ + "allocator-api2", +] [[package]] name = "byte-unit" @@ -778,6 +840,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.2.21" @@ -801,7 +872,18 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom", + "nom 7.1.3", +] + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", ] [[package]] @@ -837,7 +919,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.1.1", ] [[package]] @@ -1016,7 +1098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -1029,6 +1111,39 @@ dependencies = [ "memchr", ] +[[package]] +name = "commondir" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab552acb7c0a751c75c3dd4f9b95d31ed85c985ce5c70232a2952ffbe7ecfda5" +dependencies = [ + "thiserror 1.0.69", +] + +[[package]] +name = "compact_str" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + +[[package]] +name = "concurrent_lru" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feb5cb312f774e8a24540e27206db4e890f7d488563671d24a16389cf4c2e4e" +dependencies = [ + "once_cell", +] + [[package]] name = "connect_disconnect_client" version = "1.5.0" @@ -1118,6 +1233,12 @@ dependencies = [ "libm", ] +[[package]] +name = "cow-utils" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79" + [[package]] name = "cpp_demangle" version = "0.4.4" @@ -1413,6 +1534,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "css-module-lexer" +version = "0.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b51940c54c6ca015d3add383571ec5610114466eb67aa0a27096e1dcf3c9e29" +dependencies = [ + "smallvec", +] + [[package]] name = "cursive" version = "0.20.0" @@ -1601,6 +1731,27 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "unicode-xid", +] + [[package]] name = "dialoguer" version = "0.11.0" @@ -1677,7 +1828,16 @@ version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ - "dirs-sys", + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys 0.5.0", ] [[package]] @@ -1688,10 +1848,22 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.4.6", "windows-sys 0.48.0", ] +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.2", + "windows-sys 0.60.2", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1699,7 +1871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] @@ -1714,6 +1886,12 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "dragonbox_ecma" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d742b56656e8b14d63e7ea9806597b1849ae25412584c8adf78c0f67bd985e66" + [[package]] name = "duct" version = "0.13.7" @@ -1953,6 +2131,26 @@ dependencies = [ "regex", ] +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set 0.8.0", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "fast-glob" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d26eec0ae9682c457cb0f85de67ad417b716ae852736a5d94c2ad6e92a997c9" +dependencies = [ + "arrayvec", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1982,6 +2180,14 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "file-id" +version = "0.2.3" +source = "git+https://github.com/sapphi-red/notify?rev=refs%2Fheads%2Fpatches#cf2f71ff72bab5a94084001f6a776af81afebaac" +dependencies = [ + "windows-sys 0.60.2", +] + [[package]] name = "filetime" version = "0.2.25" @@ -2000,6 +2206,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.1" @@ -2071,6 +2283,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "fslock" version = "0.2.1" @@ -2201,7 +2422,7 @@ dependencies = [ "libc", "log", "rustversion", - "windows", + "windows 0.58.0", ] [[package]] @@ -2356,12 +2577,22 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ + "allocator-api2", "equivalent", "foldhash", "rayon", "serde", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "allocator-api2", +] + [[package]] name = "hashlink" version = "0.8.4" @@ -2653,7 +2884,7 @@ name = "iai-callgrind" version = "0.8.0" source = "git+https://github.com/clockworklabs/iai-callgrind.git?branch=main#3e78f68534bbe389e0fb00f729a6a7b877627a06" dependencies = [ - "bincode", + "bincode 1.3.3", "iai-callgrind-macros", "iai-callgrind-runner", ] @@ -2675,7 +2906,7 @@ version = "0.8.0" source = "git+https://github.com/clockworklabs/iai-callgrind.git?branch=main#3e78f68534bbe389e0fb00f729a6a7b877627a06" dependencies = [ "anyhow", - "bincode", + "bincode 1.3.3", "cargo_metadata", "clap 3.2.23", "colored", @@ -3002,6 +3233,15 @@ dependencies = [ "web-time", ] +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + [[package]] name = "inferno" version = "0.11.21" @@ -3044,6 +3284,26 @@ dependencies = [ "str_stack", ] +[[package]] +name = "inotify" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" +dependencies = [ + "bitflags 2.9.4", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "inout" version = "0.1.4" @@ -3082,7 +3342,7 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "libc", ] @@ -3137,6 +3397,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -3217,6 +3486,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-escape-simd" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1f7d5786a4cb0f4e0f862b562a0e085b5bfa23a4f0dc05e7b823ed4e4d791f" +dependencies = [ + "anyhow", +] + +[[package]] +name = "json-strip-comments" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4135b29c84322dbc3327272084360785665452213a576a991b3ac2f63148e82" +dependencies = [ + "memchr", +] + [[package]] name = "junction" version = "1.2.0" @@ -3244,6 +3531,26 @@ dependencies = [ "spacetimedb 1.5.0", ] +[[package]] +name = "kqueue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "lazy-regex" version = "3.4.1" @@ -3298,7 +3605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.0", + "windows-targets 0.48.5", ] [[package]] @@ -3323,7 +3630,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "libc", "redox_syscall 0.5.12", ] @@ -3491,9 +3798,9 @@ checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memfd" @@ -3562,6 +3869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -3661,7 +3969,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -3683,6 +3991,55 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + +[[package]] +name = "notify" +version = "8.2.0" +source = "git+https://github.com/sapphi-red/notify?rev=refs%2Fheads%2Fpatches#cf2f71ff72bab5a94084001f6a776af81afebaac" +dependencies = [ + "bitflags 2.9.4", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio 1.0.3", + "notify-types", + "walkdir", + "windows-sys 0.60.2", +] + +[[package]] +name = "notify-debouncer-full" +version = "0.6.0" +source = "git+https://github.com/sapphi-red/notify?rev=refs%2Fheads%2Fpatches#cf2f71ff72bab5a94084001f6a776af81afebaac" +dependencies = [ + "file-id", + "log", + "notify", + "notify-types", + "walkdir", +] + +[[package]] +name = "notify-types" +version = "2.0.0" +source = "git+https://github.com/sapphi-red/notify?rev=refs%2Fheads%2Fpatches#cf2f71ff72bab5a94084001f6a776af81afebaac" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3828,7 +4185,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "objc2", ] @@ -3862,7 +4219,7 @@ version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "foreign-types", "libc", @@ -3932,6 +4289,12 @@ version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + [[package]] name = "overload" version = "0.1.1" @@ -3953,6 +4316,509 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" + +[[package]] +name = "oxc" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0147cb62f855e00fc310021ca211413311681f5e6cea489f4e157c11c802f1a9" +dependencies = [ + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_cfg", + "oxc_codegen", + "oxc_diagnostics", + "oxc_isolated_declarations", + "oxc_mangler", + "oxc_minifier", + "oxc_parser", + "oxc_regular_expression", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "oxc_transformer", + "oxc_transformer_plugins", +] + +[[package]] +name = "oxc-browserslist" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7612127f5fa1ef0f3e98905ddfc10a7fa1df98944b75d774bb3cb4b530663616" +dependencies = [ + "bincode 2.0.1", + "flate2", + "nom 8.0.0", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "thiserror 2.0.12", + "time", +] + +[[package]] +name = "oxc-miette" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c42cefdcbebec6b0b72229ac0e02261a6770cb7ba39ccc5475a856164066db1" +dependencies = [ + "cfg-if", + "owo-colors 4.2.3", + "oxc-miette-derive", + "textwrap", + "thiserror 2.0.12", + "unicode-segmentation", + "unicode-width 0.2.0", +] + +[[package]] +name = "oxc-miette-derive" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05bbaa5b6b98826bb62b164406f703bee72c5287af9986f9c863fa8ea992b476" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "oxc_allocator" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c2294f53fe0d6a715ad1877300fe5432033db1e5804800f82ee84840bd09894" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.16.0", + "oxc_data_structures", + "oxc_estree", + "rustc-hash 2.1.1", + "serde", +] + +[[package]] +name = "oxc_ast" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678ce41e4a2fc2b5eb2b870a2b2dec2e0cdd9861d1bc22d19f6ce2dd2942f236" +dependencies = [ + "bitflags 2.9.4", + "oxc_allocator", + "oxc_ast_macros", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_estree", + "oxc_regular_expression", + "oxc_span", + "oxc_syntax", +] + +[[package]] +name = "oxc_ast_macros" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85d18fd697fdceb2b61329e3fff5b3b61520b9a2f898714ed84345bfa0957b9e" +dependencies = [ + "phf 0.13.1", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "oxc_ast_visit" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f93e36c0d169bf3c23dc4f545255a0c3b2acae23fcb963d5a59629f4444769" +dependencies = [ + "oxc_allocator", + "oxc_ast", + "oxc_span", + "oxc_syntax", +] + +[[package]] +name = "oxc_cfg" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b20eb52edbd6510dbc147a3c253332ebe6be3b730f9938c3253e0aca877a17ec" +dependencies = [ + "bitflags 2.9.4", + "itertools 0.14.0", + "oxc_index", + "oxc_syntax", + "petgraph 0.8.3", + "rustc-hash 2.1.1", +] + +[[package]] +name = "oxc_codegen" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d0faa35a719816d3488d6c920ba44f6d89e2e255fa8045e1f69992c30106e15" +dependencies = [ + "bitflags 2.9.4", + "cow-utils", + "dragonbox_ecma", + "itoa", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_index", + "oxc_semantic", + "oxc_sourcemap", + "oxc_span", + "oxc_syntax", + "rustc-hash 2.1.1", +] + +[[package]] +name = "oxc_compat" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e8b4b593d0c06c6c0c0f6f52e8497b2cf2411c99f6975f774602a6c509a8f9" +dependencies = [ + "cow-utils", + "oxc-browserslist", + "oxc_syntax", + "rustc-hash 2.1.1", + "serde", +] + +[[package]] +name = "oxc_data_structures" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca52a37a6fc68321a86a169064993d7bb5ea83efe64ff0fa6f8d4718261718d" +dependencies = [ + "ropey", +] + +[[package]] +name = "oxc_diagnostics" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a671bb9d9e9ef62a89e8b8f2308f511246d42ff56403831b7f0e32432861563" +dependencies = [ + "cow-utils", + "oxc-miette", + "percent-encoding", +] + +[[package]] +name = "oxc_ecmascript" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "569d276186f994866a9793fac530361995c204ee62bbcf351168352434119373" +dependencies = [ + "cow-utils", + "num-bigint", + "num-traits", + "oxc_allocator", + "oxc_ast", + "oxc_span", + "oxc_syntax", +] + +[[package]] +name = "oxc_estree" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916aaf325a3156c3d12d15c88d7d0fa1049090dad5e227659b74494ccf5258db" +dependencies = [ + "dragonbox_ecma", + "itoa", + "oxc_data_structures", +] + +[[package]] +name = "oxc_index" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3e6120999627ec9703025eab7c9f410ebb7e95557632a8902ca48210416c2b" +dependencies = [ + "nonmax", + "rayon", + "serde", +] + +[[package]] +name = "oxc_isolated_declarations" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d13f2968f5f7c3e611468e22d053e73223b0de8e21518eeb043672d5c420eb1" +dependencies = [ + "bitflags 2.9.4", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_span", + "oxc_syntax", + "rustc-hash 2.1.1", +] + +[[package]] +name = "oxc_mangler" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385a2920126be514159cff462eb94255f1cef187bf5780ffa3f2100f75f0f27c" +dependencies = [ + "itertools 0.14.0", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_index", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "rustc-hash 2.1.1", +] + +[[package]] +name = "oxc_minifier" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b24aabd566d8f9104cedab2911c479a91408c99eaf5b107eb3289fa8a2c57b" +dependencies = [ + "cow-utils", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_codegen", + "oxc_compat", + "oxc_data_structures", + "oxc_ecmascript", + "oxc_mangler", + "oxc_parser", + "oxc_regular_expression", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "oxc_traverse", + "rustc-hash 2.1.1", +] + +[[package]] +name = "oxc_parser" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db89e1c024fe806c90c8bae0a40b4efac5ac76c07d148b1fa93cbc0efaa50dd" +dependencies = [ + "bitflags 2.9.4", + "cow-utils", + "memchr", + "num-bigint", + "num-traits", + "oxc_allocator", + "oxc_ast", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_regular_expression", + "oxc_span", + "oxc_syntax", + "rustc-hash 2.1.1", + "seq-macro", +] + +[[package]] +name = "oxc_regular_expression" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de2762ca6e1d717ed35a0e65086ea4495b0b69534fe7d3c4a846f4b53a2f231" +dependencies = [ + "bitflags 2.9.4", + "oxc_allocator", + "oxc_ast_macros", + "oxc_diagnostics", + "oxc_span", + "phf 0.13.1", + "rustc-hash 2.1.1", + "unicode-id-start", +] + +[[package]] +name = "oxc_resolver" +version = "11.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bc696688fc6cbab56971f02badc233541f964f4705240c986abc02535a3728e" +dependencies = [ + "cfg-if", + "indexmap 2.9.0", + "json-strip-comments", + "libc", + "once_cell", + "papaya", + "pnp", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "simdutf8", + "thiserror 2.0.12", + "tracing", + "url", + "windows 0.62.1", +] + +[[package]] +name = "oxc_semantic" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3c0f020670078ece7fde05e83a3797078cc84f500e1bb078e0c48861232e3f" +dependencies = [ + "itertools 0.14.0", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_cfg", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_index", + "oxc_span", + "oxc_syntax", + "phf 0.13.1", + "rustc-hash 2.1.1", + "self_cell", +] + +[[package]] +name = "oxc_sourcemap" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ff280f25901ac054ad8552395ecd6a455e4b9352a94debbc34c433760586ef" +dependencies = [ + "base64-simd", + "json-escape-simd", + "rustc-hash 2.1.1", + "serde", + "serde_json", +] + +[[package]] +name = "oxc_span" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0567f9473b114f91493baab8f9c6f8bfb9e7f7767a861544c147a4eeba9e00" +dependencies = [ + "compact_str", + "oxc-miette", + "oxc_allocator", + "oxc_ast_macros", + "oxc_estree", + "serde", +] + +[[package]] +name = "oxc_syntax" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "163ca5aee9139e5b04c5848795e632dbdcb472be1b3658be4b32ff957993610d" +dependencies = [ + "bitflags 2.9.4", + "cow-utils", + "dragonbox_ecma", + "nonmax", + "oxc_allocator", + "oxc_ast_macros", + "oxc_data_structures", + "oxc_estree", + "oxc_index", + "oxc_span", + "phf 0.13.1", + "serde", + "unicode-id-start", +] + +[[package]] +name = "oxc_transformer" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ed81ad384621c3afc95000867dfffcb2caa438fb753c8bce83b5564347132" +dependencies = [ + "base64 0.22.1", + "compact_str", + "indexmap 2.9.0", + "itoa", + "memchr", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_compat", + "oxc_data_structures", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_parser", + "oxc_regular_expression", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "oxc_traverse", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "sha1", +] + +[[package]] +name = "oxc_transformer_plugins" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cf1c7ab2242611442004815f8134f7b9987aa7066b21197601676b7a7a29d7" +dependencies = [ + "cow-utils", + "itoa", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_diagnostics", + "oxc_ecmascript", + "oxc_parser", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "oxc_transformer", + "oxc_traverse", + "rustc-hash 2.1.1", +] + +[[package]] +name = "oxc_traverse" +version = "0.94.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8561f5e51bb4bfc37394ceb6390bfa59e90d82d6d0fb805a585042f9d3bb410e" +dependencies = [ + "itoa", + "oxc_allocator", + "oxc_ast", + "oxc_ast_visit", + "oxc_data_structures", + "oxc_ecmascript", + "oxc_semantic", + "oxc_span", + "oxc_syntax", + "rustc-hash 2.1.1", +] + +[[package]] +name = "papaya" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92dd0b07c53a0a0c764db2ace8c541dc47320dad97c2200c2a637ab9dd2328f" +dependencies = [ + "equivalent", + "seize", +] + [[package]] name = "papergrid" version = "0.10.0" @@ -4024,6 +4890,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -4046,9 +4918,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perf-test-module" @@ -4064,10 +4936,22 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ - "fixedbitset", + "fixedbitset 0.4.2", "indexmap 2.9.0", ] +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset 0.5.7", + "hashbrown 0.15.3", + "indexmap 2.9.0", + "serde", +] + [[package]] name = "pg_interval" version = "0.4.2" @@ -4110,7 +4994,41 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_shared", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared 0.13.1", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared 0.13.1", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared 0.13.1", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] @@ -4122,6 +5040,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -4201,6 +5128,25 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "pnp" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a10a726fb86dab6571b148c0f52cf619a4aabf0ac4fcf578bd4cd2178fb0e6d0" +dependencies = [ + "byteorder", + "concurrent_lru", + "dirs 6.0.0", + "fancy-regex 0.16.2", + "miniz_oxide", + "pathdiff", + "radix_trie", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "thiserror 2.0.12", +] + [[package]] name = "portable-atomic" version = "1.11.0" @@ -4388,7 +5334,7 @@ checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.9.0", + "bitflags 2.9.4", "lazy_static", "num-traits", "rand 0.8.5", @@ -4733,7 +5679,7 @@ version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", ] [[package]] @@ -4747,6 +5693,17 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 2.0.12", +] + [[package]] name = "regalloc2" version = "0.10.2" @@ -4810,6 +5767,16 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "regress" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145bb27393fe455dd64d6cbc8d059adfa392590a45eadf079c01b11857e7b010" +dependencies = [ + "hashbrown 0.15.3", + "memchr", +] + [[package]] name = "remove_dir_all" version = "0.5.3" @@ -4935,70 +5902,411 @@ version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted 0.9.0", - "windows-sys 0.52.0", + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta 0.1.4", + "rend 0.4.2", + "rkyv_derive 0.7.45", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" +dependencies = [ + "bytes", + "hashbrown 0.15.3", + "indexmap 2.9.0", + "munge", + "ptr_meta 0.3.0", + "rancor", + "rend 0.5.2", + "rkyv_derive 0.8.10", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "rolldown" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "anyhow", + "append-only-vec", + "arcstr", + "bitflags 2.9.4", + "commondir", + "css-module-lexer", + "derive_more 2.0.1", + "dunce", + "futures", + "indexmap 2.9.0", + "itertools 0.14.0", + "itoa", + "memchr", + "notify", + "oxc", + "oxc_allocator", + "oxc_ecmascript", + "oxc_index", + "oxc_traverse", + "petgraph 0.8.3", + "rayon", + "rolldown_common", + "rolldown_debug", + "rolldown_ecmascript", + "rolldown_ecmascript_utils", + "rolldown_error", + "rolldown_fs", + "rolldown_plugin", + "rolldown_plugin_chunk_import_map", + "rolldown_plugin_data_uri", + "rolldown_plugin_hmr", + "rolldown_plugin_oxc_runtime", + "rolldown_resolver", + "rolldown_sourcemap", + "rolldown_std_utils", + "rolldown_tracing", + "rolldown_utils", + "rolldown_watcher", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "string_wizard", + "sugar_path", + "tokio", + "tracing", + "url", + "xxhash-rust", +] + +[[package]] +name = "rolldown-ariadne" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77dff57c9de498bb1eb5b1ce682c2e3a0ae956b266fa0933c3e151b87b078967" +dependencies = [ + "unicode-width 0.2.0", + "yansi", +] + +[[package]] +name = "rolldown_common" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "anyhow", + "arcstr", + "bitflags 2.9.4", + "dashmap 6.1.0", + "derive_more 2.0.1", + "fast-glob", + "itertools 0.14.0", + "num-bigint", + "oxc", + "oxc_ecmascript", + "oxc_index", + "oxc_resolver", + "rolldown_ecmascript", + "rolldown_error", + "rolldown_sourcemap", + "rolldown_std_utils", + "rolldown_utils", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "simdutf8", + "string_wizard", + "sugar_path", + "tokio", +] + +[[package]] +name = "rolldown_debug" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "blake3", + "dashmap 6.1.0", + "rolldown_debug_action", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "rolldown_debug_action" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "serde", + "ts-rs", +] + +[[package]] +name = "rolldown_ecmascript" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "arcstr", + "oxc", + "oxc_sourcemap", + "rolldown_error", + "self_cell", +] + +[[package]] +name = "rolldown_ecmascript_utils" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "oxc", + "rolldown_common", + "smallvec", +] + +[[package]] +name = "rolldown_error" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "anyhow", + "arcstr", + "bitflags 2.9.4", + "derive_more 2.0.1", + "heck 0.5.0", + "oxc", + "oxc_resolver", + "rolldown-ariadne", + "rolldown_utils", + "ropey", + "rustc-hash 2.1.1", + "sugar_path", +] + +[[package]] +name = "rolldown_fs" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "oxc_resolver", + "vfs", +] + +[[package]] +name = "rolldown_plugin" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "anyhow", + "arcstr", + "async-trait", + "bitflags 2.9.4", + "dashmap 6.1.0", + "derive_more 2.0.1", + "oxc_index", + "rolldown_common", + "rolldown_debug", + "rolldown_ecmascript", + "rolldown_error", + "rolldown_resolver", + "rolldown_sourcemap", + "rolldown_utils", + "rustc-hash 2.1.1", + "serde", + "serde_json", + "string_wizard", + "sugar_path", + "tokio", + "tracing", + "typedmap", +] + +[[package]] +name = "rolldown_plugin_chunk_import_map" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "arcstr", + "rolldown_common", + "rolldown_plugin", + "rolldown_utils", + "rustc-hash 2.1.1", + "serde_json", + "xxhash-rust", +] + +[[package]] +name = "rolldown_plugin_data_uri" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "arcstr", + "base64-simd", + "rolldown_common", + "rolldown_plugin", + "rolldown_utils", + "simdutf8", + "urlencoding", +] + +[[package]] +name = "rolldown_plugin_hmr" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "arcstr", + "oxc", + "rolldown_common", + "rolldown_plugin", +] + +[[package]] +name = "rolldown_plugin_oxc_runtime" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "arcstr", + "phf 0.13.1", + "rolldown_plugin", + "rolldown_utils", +] + +[[package]] +name = "rolldown_resolver" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "anyhow", + "arcstr", + "dashmap 6.1.0", + "itertools 0.14.0", + "oxc_resolver", + "rolldown_common", + "rolldown_fs", + "rolldown_utils", + "sugar_path", +] + +[[package]] +name = "rolldown_sourcemap" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "memchr", + "oxc", + "oxc_sourcemap", + "rolldown_utils", + "rustc-hash 2.1.1", ] [[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +name = "rolldown_std_utils" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta 0.1.4", - "rend 0.4.2", - "rkyv_derive 0.7.45", - "seahash", - "tinyvec", - "uuid", + "regex", ] [[package]] -name = "rkyv" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" +name = "rolldown_tracing" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" dependencies = [ - "bytes", - "hashbrown 0.15.3", - "indexmap 2.9.0", - "munge", - "ptr_meta 0.3.0", - "rancor", - "rend 0.5.2", - "rkyv_derive 0.8.10", - "tinyvec", - "uuid", + "tracing", + "tracing-chrome", + "tracing-subscriber", ] [[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +name = "rolldown_utils" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "anyhow", + "arcstr", + "async-scoped", + "base-encode", + "base64-simd", + "cow-utils", + "dashmap 6.1.0", + "fast-glob", + "form_urlencoded", + "futures", + "indexmap 2.9.0", + "infer", + "itoa", + "memchr", + "mime", + "nom 8.0.0", + "oxc", + "oxc_index", + "phf 0.13.1", + "rayon", + "regex", + "regress", + "rolldown_std_utils", + "rustc-hash 2.1.1", + "serde_json", + "simdutf8", + "sugar_path", + "tokio", + "uuid", + "xxhash-rust", ] [[package]] -name = "rkyv_derive" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" +name = "rolldown_watcher" +version = "0.1.0" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", + "notify", + "notify-debouncer-full", + "rolldown_error", ] [[package]] @@ -5008,18 +6316,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.9.0", + "bitflags 2.9.4", "serde", "serde_derive", ] +[[package]] +name = "ropey" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5" +dependencies = [ + "smallvec", + "str_indices", +] + [[package]] name = "rusqlite" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "fallible-iterator 0.2.0", "fallible-streaming-iterator", "hashlink", @@ -5077,7 +6395,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.4.15", @@ -5090,7 +6408,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.9.4", @@ -5175,7 +6493,7 @@ version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "994eca4bca05c87e86e15d90fc7a91d1be64b4482b38cb2d27474568fe7c9db9" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "cfg-if", "clipboard-win", "fd-lock", @@ -5289,7 +6607,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5306,6 +6624,16 @@ dependencies = [ "libc", ] +[[package]] +name = "seize" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "self-replace" version = "1.5.0" @@ -5317,6 +6645,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "self_cell" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" + [[package]] name = "semver" version = "1.0.26" @@ -5326,6 +6660,12 @@ dependencies = [ "serde", ] +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + [[package]] name = "serde" version = "1.0.219" @@ -5614,6 +6954,12 @@ dependencies = [ "serde", ] +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "socket2" version = "0.5.9" @@ -5649,7 +6995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cd00b22d3170c92858f448db222a135c6302e336f1729c17e77f634c7e9e849" dependencies = [ "bytemuck", - "derive_more", + "derive_more 0.99.20", "getrandom 0.2.16", "log", "rand 0.8.5", @@ -5665,7 +7011,7 @@ name = "spacetimedb" version = "1.5.0" dependencies = [ "bytemuck", - "derive_more", + "derive_more 0.99.20", "getrandom 0.2.16", "insta", "log", @@ -5792,7 +7138,7 @@ dependencies = [ "clap-markdown", "colored", "convert_case 0.6.0", - "dirs", + "dirs 5.0.1", "duct", "email_address", "flate2", @@ -5806,6 +7152,8 @@ dependencies = [ "percent-encoding", "regex", "reqwest 0.12.15", + "rolldown", + "rolldown_utils", "rustyline", "serde", "serde_json", @@ -5853,7 +7201,7 @@ dependencies = [ "bytes", "bytestring", "chrono", - "derive_more", + "derive_more 0.99.20", "email_address", "futures", "headers", @@ -5901,7 +7249,7 @@ dependencies = [ "bytes", "bytestring", "chrono", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "hex", "itertools 0.12.1", @@ -5939,7 +7287,7 @@ name = "spacetimedb-commitlog" version = "1.5.0" dependencies = [ "async-stream", - "bitflags 2.9.0", + "bitflags 2.9.4", "bytes", "crc32c", "env_logger 0.10.2", @@ -5987,8 +7335,8 @@ dependencies = [ "criterion", "crossbeam-channel", "crossbeam-queue", - "derive_more", - "dirs", + "derive_more 0.99.20", + "dirs 5.0.1", "enum-as-inner", "enum-map", "env_logger 0.10.2", @@ -6108,7 +7456,7 @@ version = "1.5.0" dependencies = [ "anyhow", "bytes", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "enum-map", "itertools 0.12.1", @@ -6173,7 +7521,7 @@ version = "1.5.0" dependencies = [ "anyhow", "bigdecimal", - "derive_more", + "derive_more 0.99.20", "ethnum", "pretty_assertions", "spacetimedb 1.5.0", @@ -6234,10 +7582,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9b8d04af6da14e3b7cc79b4b88c1c309c994eeba6a97f298fd0cdc7f897209" dependencies = [ "anyhow", - "bitflags 2.9.0", + "bitflags 2.9.4", "blake3", "chrono", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "hex", "itertools 0.12.1", @@ -6252,11 +7600,11 @@ name = "spacetimedb-lib" version = "1.5.0" dependencies = [ "anyhow", - "bitflags 2.9.0", + "bitflags 2.9.4", "blake3", "bytes", "chrono", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "enum-map", "hex", @@ -6301,7 +7649,7 @@ version = "1.5.0" dependencies = [ "anyhow", "chrono", - "dirs", + "dirs 5.0.1", "fs2", "itoa", "junction", @@ -6334,7 +7682,7 @@ name = "spacetimedb-physical-plan" version = "1.5.0" dependencies = [ "anyhow", - "derive_more", + "derive_more 0.99.20", "either", "pretty_assertions", "spacetimedb-expr", @@ -6351,7 +7699,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0181dc495c66138755705e573f0e0a9a7024660f207ebd1e35d0a1f839813e84" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "either", "itertools 0.12.1", "nohash-hasher", @@ -6361,7 +7709,7 @@ dependencies = [ name = "spacetimedb-primitives" version = "1.5.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "either", "itertools 0.12.1", "nohash-hasher", @@ -6394,12 +7742,12 @@ checksum = "2e9700ea5d62401c05633ce86d369dbc4a73ec978ac7e347ab8563626ad01fbc" dependencies = [ "anyhow", "arrayvec", - "bitflags 2.9.0", + "bitflags 2.9.4", "bytemuck", "bytes", "chrono", "decorum", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "ethnum", "hex", @@ -6419,14 +7767,14 @@ dependencies = [ "ahash 0.8.12", "anyhow", "arrayvec", - "bitflags 2.9.0", + "bitflags 2.9.4", "blake3", "bytemuck", "bytes", "bytestring", "chrono", "decorum", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "ethnum", "hex", @@ -6451,7 +7799,7 @@ name = "spacetimedb-schema" version = "1.5.0" dependencies = [ "anyhow", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "enum-map", "hashbrown 0.15.3", @@ -6459,7 +7807,7 @@ dependencies = [ "insta", "itertools 0.12.1", "lazy_static", - "petgraph", + "petgraph 0.6.5", "proptest", "serde_json", "serial_test", @@ -6543,7 +7891,7 @@ dependencies = [ name = "spacetimedb-sql-parser" version = "1.5.0" dependencies = [ - "derive_more", + "derive_more 0.99.20", "spacetimedb-lib 1.5.0", "sqlparser", "thiserror 1.0.69", @@ -6557,7 +7905,7 @@ dependencies = [ "async-trait", "axum", "clap 4.5.37", - "dirs", + "dirs 5.0.1", "futures", "hostname", "http 1.3.1", @@ -6613,7 +7961,7 @@ dependencies = [ "criterion", "crossbeam-queue", "decorum", - "derive_more", + "derive_more 0.99.20", "enum-as-inner", "itertools 0.12.1", "proptest", @@ -6687,7 +8035,7 @@ version = "1.5.0" dependencies = [ "anyhow", "arrayvec", - "derive_more", + "derive_more 0.99.20", "itertools 0.12.1", "log", "smallvec", @@ -6731,7 +8079,7 @@ dependencies = [ "itertools 0.11.0", "libtest-mimic", "md-5", - "owo-colors", + "owo-colors 3.5.0", "regex", "similar", "subst", @@ -6781,7 +8129,7 @@ dependencies = [ "chrono", "clap 4.5.37", "console", - "derive_more", + "derive_more 0.99.20", "fs-err", "futures", "glob", @@ -6809,12 +8157,24 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "str-buf" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" +[[package]] +name = "str_indices" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6" + [[package]] name = "str_stack" version = "0.1.0" @@ -6830,6 +8190,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "string_wizard" +version = "0.0.26" +source = "git+https://github.com/rolldown/rolldown.git?tag=v1.0.0-beta.42#596339764e63f3403e425c2cd8b23a1bc7170f77" +dependencies = [ + "memchr", + "oxc_index", + "oxc_sourcemap", + "rustc-hash 2.1.1", + "serde", +] + [[package]] name = "stringprep" version = "0.1.5" @@ -6900,6 +8272,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "sugar_path" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8230d5b8a65a6d4d4a7e5ee8dbdd9312ba447a8b8329689a390a0945d69b57ce" + [[package]] name = "syn" version = "1.0.109" @@ -6966,9 +8344,9 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" dependencies = [ - "bincode", + "bincode 1.3.3", "bitflags 1.3.2", - "fancy-regex", + "fancy-regex 0.11.0", "flate2", "fnv", "once_cell", @@ -6999,7 +8377,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -7162,6 +8540,11 @@ name = "textwrap" version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width 0.2.0", +] [[package]] name = "thin-vec" @@ -7415,7 +8798,7 @@ dependencies = [ "log", "parking_lot 0.12.3", "percent-encoding", - "phf", + "phf 0.11.3", "pin-project-lite", "postgres-protocol", "postgres-types", @@ -7548,7 +8931,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "bytes", "http 1.3.1", "http-body 1.0.1", @@ -7605,6 +8988,17 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "tracing-chrome" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0a738ed5d6450a9fb96e86a23ad808de2b727fd1394585da5cdd6788ffe724" +dependencies = [ + "serde_json", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "tracing-core" version = "0.1.33" @@ -7648,6 +9042,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.19" @@ -7658,12 +9062,15 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log 0.2.0", + "tracing-serde", ] [[package]] @@ -7718,6 +9125,28 @@ dependencies = [ "toml 0.8.22", ] +[[package]] +name = "ts-rs" +version = "11.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef1b7a6d914a34127ed8e1fa927eb7088903787bcded4fa3eef8f85ee1568be" +dependencies = [ + "thiserror 2.0.12", + "ts-rs-macros", +] + +[[package]] +name = "ts-rs-macros" +version = "11.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ed7b4c18cc150a6a0a1e9ea1ecfa688791220781af6e119f9599a8502a0a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "termcolor", +] + [[package]] name = "tungstenite" version = "0.27.0" @@ -7743,6 +9172,15 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "typedmap" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63278e72ed4f207eb3216c944cbafb35bdb656d2eab97ef73c0c165a1cd3e319" +dependencies = [ + "dashmap 6.1.0", +] + [[package]] name = "typenum" version = "1.18.0" @@ -7779,12 +9217,24 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +[[package]] +name = "unicode-id-start" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007" + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-normalization" version = "0.1.24" @@ -7836,6 +9286,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "upgrade-version" version = "0.1.0" @@ -7898,11 +9354,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom 0.3.2", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -7912,7 +9370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8827809a2884fb68530d678a8ef15b1ed1344bbf844879194d68c140c6f844f9" dependencies = [ "bindgen 0.72.1", - "bitflags 2.9.0", + "bitflags 2.9.4", "fslock", "gzip-header", "home", @@ -7946,6 +9404,27 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vfs" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e723b9e1c02a3cf9f9d0de6a4ddb8cdc1df859078902fe0ae0589d615711ae6" +dependencies = [ + "filetime", +] + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "vte" version = "0.14.1" @@ -8130,7 +9609,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65a5a0689975b9fd93c02f5400cfd9669858b99607e54e7b892c6080cba598bb" dependencies = [ "ahash 0.8.12", - "bitflags 2.9.0", + "bitflags 2.9.4", "hashbrown 0.14.5", "indexmap 2.9.0", "semver", @@ -8157,7 +9636,7 @@ dependencies = [ "addr2line 0.22.0", "anyhow", "async-trait", - "bitflags 2.9.0", + "bitflags 2.9.4", "bumpalo", "cc", "cfg-if", @@ -8458,7 +9937,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] @@ -8477,6 +9956,27 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e6c4a1f363c8210c6f77ba24f645c61c6fb941eccf013da691f7e09515b8ac" +dependencies = [ + "windows-collections", + "windows-core 0.62.1", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123e712f464a8a60ce1a13f4c446d2d43ab06464cb5842ff68f5c71b6fb7852e" +dependencies = [ + "windows-core 0.62.1", +] + [[package]] name = "windows-core" version = "0.58.0" @@ -8496,13 +9996,37 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", - "windows-link", + "windows-implement 0.60.1", + "windows-interface 0.59.2", + "windows-link 0.1.1", "windows-result 0.3.2", "windows-strings 0.4.0", ] +[[package]] +name = "windows-core" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +dependencies = [ + "windows-implement 0.60.1", + "windows-interface 0.59.2", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", +] + +[[package]] +name = "windows-future" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a" +dependencies = [ + "windows-core 0.62.1", + "windows-link 0.2.0", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -8516,9 +10040,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2", "quote", @@ -8538,9 +10062,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2", "quote", @@ -8553,6 +10077,22 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-numerics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" +dependencies = [ + "windows-core 0.62.1", + "windows-link 0.2.0", +] + [[package]] name = "windows-registry" version = "0.4.0" @@ -8561,7 +10101,7 @@ checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ "windows-result 0.3.2", "windows-strings 0.3.1", - "windows-targets 0.53.0", + "windows-targets 0.53.4", ] [[package]] @@ -8579,7 +10119,16 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ - "windows-link", + "windows-link 0.1.1", +] + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", ] [[package]] @@ -8598,7 +10147,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-link", + "windows-link 0.1.1", ] [[package]] @@ -8607,7 +10156,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" dependencies = [ - "windows-link", + "windows-link 0.1.1", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", ] [[package]] @@ -8646,6 +10204,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -8694,10 +10261,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.0" +version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" dependencies = [ + "windows-link 0.2.0", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -8708,6 +10276,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -8919,7 +10496,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", ] [[package]] @@ -8989,6 +10566,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "xz2" version = "0.1.7" diff --git a/Cargo.toml b/Cargo.toml index 52ea189d320..1a5328570b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -233,6 +233,8 @@ rayon = "1.8" rayon-core = "1.11.0" regex = "1" reqwest = { version = "0.12", features = ["stream", "json"] } +rolldown = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-beta.42" } +rolldown_utils = { git = "https://github.com/rolldown/rolldown.git", tag = "v1.0.0-beta.42" } ron = "0.8" rusqlite = { version = "0.29.0", features = ["bundled", "column_decltype"] } rust_decimal = { version = "1.29.1", features = ["db-tokio-postgres"] } @@ -292,7 +294,7 @@ unicode-ident = "1.0.12" unicode-normalization = "0.1.23" url = "2.3.1" urlencoding = "2.1.2" -uuid = { version = "1.2.1", features = ["v4"] } +uuid = { version = "1.18.1", features = ["v4"] } v8 = "140.2" walkdir = "2.2.5" wasmbin = "0.6" diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts index ba73d0a7012..c5f335a93ad 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_connected_reducer.ts @@ -29,6 +29,8 @@ import { } from 'spacetimedb'; export type IdentityConnected = {}; +let _cached_IdentityConnected_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -38,9 +40,13 @@ export const IdentityConnected = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ + if (_cached_IdentityConnected_type_value) + return _cached_IdentityConnected_type_value; + _cached_IdentityConnected_type_value = __AlgebraicTypeValue.Product({ elements: [], }); + _cached_IdentityConnected_type_value.value.elements.push(); + return _cached_IdentityConnected_type_value; }, serialize(writer: __BinaryWriter, value: IdentityConnected): void { diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts index 6d042131f92..1d2c3901076 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/identity_disconnected_reducer.ts @@ -29,6 +29,8 @@ import { } from 'spacetimedb'; export type IdentityDisconnected = {}; +let _cached_IdentityDisconnected_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -38,9 +40,13 @@ export const IdentityDisconnected = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ + if (_cached_IdentityDisconnected_type_value) + return _cached_IdentityDisconnected_type_value; + _cached_IdentityDisconnected_type_value = __AlgebraicTypeValue.Product({ elements: [], }); + _cached_IdentityDisconnected_type_value.value.elements.push(); + return _cached_IdentityDisconnected_type_value; }, serialize(writer: __BinaryWriter, value: IdentityDisconnected): void { diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts index 148aaea5f98..4657fe2fed0 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using spacetimedb cli version 1.5.0 (commit 3f65da1a72997e396bacaf5b2f58a7a9f0e1feeb). +// This was generated using spacetimedb cli version 1.5.0 (commit 5bfc84351742a6a8dc717b6c0011946f2d1b632d). /* eslint-disable */ /* tslint:disable */ diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts index 05d4bedf56a..e4080eced64 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/message_type.ts @@ -33,6 +33,8 @@ export type Message = { sent: __Timestamp; text: string; }; +let _cached_Message_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -42,19 +44,20 @@ export const Message = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'sender', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { - name: 'sent', - algebraicType: __AlgebraicTypeValue.createTimestampType(), - }, - { name: 'text', algebraicType: __AlgebraicTypeValue.String }, - ], - }); + if (_cached_Message_type_value) return _cached_Message_type_value; + _cached_Message_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Message_type_value.value.elements.push( + { + name: 'sender', + algebraicType: __AlgebraicTypeValue.createIdentityType(), + }, + { + name: 'sent', + algebraicType: __AlgebraicTypeValue.createTimestampType(), + }, + { name: 'text', algebraicType: __AlgebraicTypeValue.String } + ); + return _cached_Message_type_value; }, serialize(writer: __BinaryWriter, value: Message): void { diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts index 8753b3ec593..e30d08b732e 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/send_message_reducer.ts @@ -31,6 +31,8 @@ import { export type SendMessage = { text: string; }; +let _cached_SendMessage_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -40,9 +42,15 @@ export const SendMessage = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [{ name: 'text', algebraicType: __AlgebraicTypeValue.String }], + if (_cached_SendMessage_type_value) return _cached_SendMessage_type_value; + _cached_SendMessage_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_SendMessage_type_value.value.elements.push({ + name: 'text', + algebraicType: __AlgebraicTypeValue.String, }); + return _cached_SendMessage_type_value; }, serialize(writer: __BinaryWriter, value: SendMessage): void { diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts index d8a6022e248..e571226e6be 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/set_name_reducer.ts @@ -31,6 +31,8 @@ import { export type SetName = { name: string; }; +let _cached_SetName_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -40,9 +42,13 @@ export const SetName = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [{ name: 'name', algebraicType: __AlgebraicTypeValue.String }], + if (_cached_SetName_type_value) return _cached_SetName_type_value; + _cached_SetName_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_SetName_type_value.value.elements.push({ + name: 'name', + algebraicType: __AlgebraicTypeValue.String, }); + return _cached_SetName_type_value; }, serialize(writer: __BinaryWriter, value: SetName): void { diff --git a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts index 2a65361f193..974cc8d48e6 100644 --- a/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts +++ b/crates/bindings-typescript/examples/quickstart-chat/src/module_bindings/user_type.ts @@ -33,6 +33,8 @@ export type User = { name: string | undefined; online: boolean; }; +let _cached_User_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -42,21 +44,22 @@ export const User = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'identity', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { name: 'online', algebraicType: __AlgebraicTypeValue.Bool }, - ], - }); + if (_cached_User_type_value) return _cached_User_type_value; + _cached_User_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_User_type_value.value.elements.push( + { + name: 'identity', + algebraicType: __AlgebraicTypeValue.createIdentityType(), + }, + { + name: 'name', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { name: 'online', algebraicType: __AlgebraicTypeValue.Bool } + ); + return _cached_User_type_value; }, serialize(writer: __BinaryWriter, value: User): void { diff --git a/crates/bindings-typescript/package.json b/crates/bindings-typescript/package.json index 3bfde043df5..49f051916f5 100644 --- a/crates/bindings-typescript/package.json +++ b/crates/bindings-typescript/package.json @@ -19,7 +19,10 @@ "license": "ISC", "author": "Clockwork Labs", "type": "module", - "sideEffects": false, + "sideEffects": [ + "./src/server/polyfills.ts", + "./src/server/register_hooks.ts" + ], "scripts": { "build:js": "tsup", "build:types": "tsc -p tsconfig.build.json", @@ -151,6 +154,7 @@ ], "dependencies": { "base64-js": "^1.5.1", + "fast-text-encoding": "^1.0.0", "prettier": "^3.3.3" }, "peerDependencies": { @@ -168,6 +172,7 @@ "devDependencies": { "@eslint/js": "^9.17.0", "@size-limit/file": "^11.2.0", + "@types/fast-text-encoding": "^1.0.3", "@types/react": "^19.1.13", "@typescript-eslint/eslint-plugin": "^8.18.2", "@typescript-eslint/parser": "^8.18.2", diff --git a/crates/bindings-typescript/src/index.ts b/crates/bindings-typescript/src/index.ts index ff0a3862ea1..5204fe0b972 100644 --- a/crates/bindings-typescript/src/index.ts +++ b/crates/bindings-typescript/src/index.ts @@ -8,5 +8,5 @@ export * from './lib/time_duration'; export * from './lib/timestamp'; export * from './lib/utils'; export * from './lib/identity'; +export * from './lib/option'; export * from './sdk'; -export { default as t } from './server/type_builders'; diff --git a/crates/bindings-typescript/src/lib/algebraic_type.ts b/crates/bindings-typescript/src/lib/algebraic_type.ts index 733f7624617..10182743560 100644 --- a/crates/bindings-typescript/src/lib/algebraic_type.ts +++ b/crates/bindings-typescript/src/lib/algebraic_type.ts @@ -4,6 +4,7 @@ import { ConnectionId } from './connection_id'; import type BinaryReader from './binary_reader'; import BinaryWriter from './binary_writer'; import { Identity } from './identity'; +import { Option } from './option'; import { AlgebraicType as AlgebraicTypeType, AlgebraicType as AlgebraicTypeValue, @@ -54,6 +55,10 @@ export type AlgebraicType = AlgebraicTypeType; * Algebraic Type utilities. */ export const AlgebraicType: { + Sum(value: T): { tag: 'Sum'; value: T }; + Product(value: T): { tag: 'Product'; value: T }; + Array(value: T): { tag: 'Array'; value: T }; + createOptionType(innerType: AlgebraicTypeType): AlgebraicTypeType; createIdentityType(): AlgebraicTypeType; createConnectionIdType(): AlgebraicTypeType; @@ -72,16 +77,20 @@ export const AlgebraicType: { intoMapKey(ty: AlgebraicTypeType, value: any): ComparablePrimitive; } & typeof AlgebraicTypeValue = { ...AlgebraicTypeValue, + Sum: (value: T): { tag: 'Sum'; value: T } => ({ + tag: 'Sum', + value, + }), + Product: (value: T): { tag: 'Product'; value: T } => ({ + tag: 'Product', + value, + }), + Array: (value: T): { tag: 'Array'; value: T } => ({ + tag: 'Array', + value, + }), createOptionType: function (innerType: AlgebraicTypeType): AlgebraicTypeType { - return AlgebraicTypeValue.Sum({ - variants: [ - { name: 'some', algebraicType: innerType }, - { - name: 'none', - algebraicType: AlgebraicTypeValue.Product({ elements: [] }), - }, - ], - }); + return Option.getAlgebraicType(innerType); }, createIdentityType: function (): AlgebraicTypeType { return Identity.getAlgebraicType(); @@ -366,6 +375,8 @@ export const ProductType: { }, }; +export type SumType = SumTypeType; + /** * Unlike most languages, sums in SATS are *[structural]* and not nominal. * When checking whether two nominal types are the same, diff --git a/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts b/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts index fa30cb0f3c8..fcbc92cd34c 100644 --- a/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/algebraic_type_type.ts @@ -48,6 +48,8 @@ export type AlgebraicType = | AlgebraicTypeVariants.F32 | AlgebraicTypeVariants.F64; +let _cached_AlgebraicType_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const AlgebraicType = { // Helper functions for constructing each variant of the tagged union. @@ -56,10 +58,16 @@ export const AlgebraicType = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - Ref: (value: number): AlgebraicType => ({ tag: 'Ref', value }), - Sum: (value: SumType): AlgebraicType => ({ tag: 'Sum', value }), - Product: (value: ProductType): AlgebraicType => ({ tag: 'Product', value }), - Array: (value: AlgebraicType): AlgebraicType => ({ tag: 'Array', value }), + Ref: (value: number): AlgebraicTypeVariants.Ref => ({ tag: 'Ref', value }), + Sum: (value: SumType): AlgebraicTypeVariants.Sum => ({ tag: 'Sum', value }), + Product: (value: ProductType): AlgebraicTypeVariants.Product => ({ + tag: 'Product', + value, + }), + Array: (value: AlgebraicType): AlgebraicTypeVariants.Array => ({ + tag: 'Array', + value, + }), String: { tag: 'String' } as const, Bool: { tag: 'Bool' } as const, I8: { tag: 'I8' } as const, @@ -78,84 +86,88 @@ export const AlgebraicType = { F64: { tag: 'F64' } as const, getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { name: 'Ref', algebraicType: __AlgebraicTypeValue.U32 }, - { name: 'Sum', algebraicType: SumType.getTypeScriptAlgebraicType() }, - { - name: 'Product', - algebraicType: ProductType.getTypeScriptAlgebraicType(), - }, - { - name: 'Array', - algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), - }, - { - name: 'String', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'Bool', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'I8', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'U8', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'I16', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'U16', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'I32', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'U32', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'I64', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'U64', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'I128', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'U128', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'I256', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'U256', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'F32', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'F64', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - ], + if (_cached_AlgebraicType_type_value) + return _cached_AlgebraicType_type_value; + _cached_AlgebraicType_type_value = __AlgebraicTypeValue.Sum({ + variants: [], }); + _cached_AlgebraicType_type_value.value.variants.push( + { name: 'Ref', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'Sum', algebraicType: SumType.getTypeScriptAlgebraicType() }, + { + name: 'Product', + algebraicType: ProductType.getTypeScriptAlgebraicType(), + }, + { + name: 'Array', + algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), + }, + { + name: 'String', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'Bool', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'I8', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'U8', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'I16', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'U16', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'I32', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'U32', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'I64', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'U64', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'I128', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'U128', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'I256', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'U256', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'F32', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'F64', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + } + ); + return _cached_AlgebraicType_type_value; }, serialize(writer: __BinaryWriter, value: AlgebraicType): void { diff --git a/crates/bindings-typescript/src/lib/autogen/index_type_type.ts b/crates/bindings-typescript/src/lib/autogen/index_type_type.ts index b40d393be79..691424a1d7b 100644 --- a/crates/bindings-typescript/src/lib/autogen/index_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/index_type_type.ts @@ -21,6 +21,8 @@ import * as IndexTypeVariants from './index_type_variants'; // The tagged union or sum type for the algebraic type `IndexType`. export type IndexType = IndexTypeVariants.BTree | IndexTypeVariants.Hash; +let _cached_IndexType_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const IndexType = { // Helper functions for constructing each variant of the tagged union. @@ -33,18 +35,19 @@ export const IndexType = { Hash: { tag: 'Hash' } as const, getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'BTree', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'Hash', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - ], - }); + if (_cached_IndexType_type_value) return _cached_IndexType_type_value; + _cached_IndexType_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_IndexType_type_value.value.variants.push( + { + name: 'BTree', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'Hash', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + } + ); + return _cached_IndexType_type_value; }, serialize(writer: __BinaryWriter, value: IndexType): void { diff --git a/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts b/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts index 2be8c908e49..1ac1f627392 100644 --- a/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/lifecycle_type.ts @@ -24,6 +24,8 @@ export type Lifecycle = | LifecycleVariants.OnConnect | LifecycleVariants.OnDisconnect; +let _cached_Lifecycle_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const Lifecycle = { // Helper functions for constructing each variant of the tagged union. @@ -37,22 +39,23 @@ export const Lifecycle = { OnDisconnect: { tag: 'OnDisconnect' } as const, getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'Init', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'OnConnect', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'OnDisconnect', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - ], - }); + if (_cached_Lifecycle_type_value) return _cached_Lifecycle_type_value; + _cached_Lifecycle_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_Lifecycle_type_value.value.variants.push( + { + name: 'Init', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'OnConnect', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'OnDisconnect', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + } + ); + return _cached_Lifecycle_type_value; }, serialize(writer: __BinaryWriter, value: Lifecycle): void { diff --git a/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts b/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts index dcd0fa396d4..427e9f437f0 100644 --- a/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/misc_module_export_type.ts @@ -25,6 +25,8 @@ import * as MiscModuleExportVariants from './misc_module_export_variants'; // The tagged union or sum type for the algebraic type `MiscModuleExport`. export type MiscModuleExport = MiscModuleExportVariants.TypeAlias; +let _cached_MiscModuleExport_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const MiscModuleExport = { // Helper functions for constructing each variant of the tagged union. @@ -33,20 +35,22 @@ export const MiscModuleExport = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - TypeAlias: (value: TypeAlias): MiscModuleExport => ({ + TypeAlias: (value: TypeAlias): MiscModuleExportVariants.TypeAlias => ({ tag: 'TypeAlias', value, }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'TypeAlias', - algebraicType: TypeAlias.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_MiscModuleExport_type_value) + return _cached_MiscModuleExport_type_value; + _cached_MiscModuleExport_type_value = __AlgebraicTypeValue.Sum({ + variants: [], + }); + _cached_MiscModuleExport_type_value.value.variants.push({ + name: 'TypeAlias', + algebraicType: TypeAlias.getTypeScriptAlgebraicType(), }); + return _cached_MiscModuleExport_type_value; }, serialize(writer: __BinaryWriter, value: MiscModuleExport): void { diff --git a/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts b/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts index 2cbbcb10c79..18e793c3857 100644 --- a/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/product_type_element_type.ts @@ -24,6 +24,8 @@ export type ProductTypeElement = { name: string | undefined; algebraicType: AlgebraicType; }; +let _cached_ProductTypeElement_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -33,20 +35,24 @@ export const ProductTypeElement = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { - name: 'algebraicType', - algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_ProductTypeElement_type_value) + return _cached_ProductTypeElement_type_value; + _cached_ProductTypeElement_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_ProductTypeElement_type_value.value.elements.push( + { + name: 'name', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { + name: 'algebraicType', + algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), + } + ); + return _cached_ProductTypeElement_type_value; }, serialize(writer: __BinaryWriter, value: ProductTypeElement): void { diff --git a/crates/bindings-typescript/src/lib/autogen/product_type_type.ts b/crates/bindings-typescript/src/lib/autogen/product_type_type.ts index f0cacc4b4ee..aa72f5a57af 100644 --- a/crates/bindings-typescript/src/lib/autogen/product_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/product_type_type.ts @@ -23,6 +23,8 @@ declare type __keep_ProductTypeElement = ProductTypeElement; export type ProductType = { elements: ProductTypeElement[]; }; +let _cached_ProductType_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -32,16 +34,17 @@ export const ProductType = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'elements', - algebraicType: __AlgebraicTypeValue.Array( - ProductTypeElement.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_ProductType_type_value) return _cached_ProductType_type_value; + _cached_ProductType_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_ProductType_type_value.value.elements.push({ + name: 'elements', + algebraicType: __AlgebraicTypeValue.Array( + ProductTypeElement.getTypeScriptAlgebraicType() + ), }); + return _cached_ProductType_type_value; }, serialize(writer: __BinaryWriter, value: ProductType): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts index 6ba1638bf55..c7ceea12688 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_column_def_v_8_type.ts @@ -24,6 +24,8 @@ export type RawColumnDefV8 = { colName: string; colType: AlgebraicType; }; +let _cached_RawColumnDefV8_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -33,15 +35,19 @@ export const RawColumnDefV8 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'colName', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'colType', - algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_RawColumnDefV8_type_value) + return _cached_RawColumnDefV8_type_value; + _cached_RawColumnDefV8_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawColumnDefV8_type_value.value.elements.push( + { name: 'colName', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'colType', + algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), + } + ); + return _cached_RawColumnDefV8_type_value; }, serialize(writer: __BinaryWriter, value: RawColumnDefV8): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts index f62f5ba2516..f3b486cf3c6 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_column_default_value_v_9_type.ts @@ -22,6 +22,9 @@ export type RawColumnDefaultValueV9 = { colId: number; value: Uint8Array; }; +let _cached_RawColumnDefaultValueV9_type_value: __AlgebraicTypeType | null = + null; + /** * An object for generated helper functions. */ @@ -31,16 +34,20 @@ export const RawColumnDefaultValueV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'table', algebraicType: __AlgebraicTypeValue.String }, - { name: 'colId', algebraicType: __AlgebraicTypeValue.U16 }, - { - name: 'value', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - ], + if (_cached_RawColumnDefaultValueV9_type_value) + return _cached_RawColumnDefaultValueV9_type_value; + _cached_RawColumnDefaultValueV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawColumnDefaultValueV9_type_value.value.elements.push( + { name: 'table', algebraicType: __AlgebraicTypeValue.String }, + { name: 'colId', algebraicType: __AlgebraicTypeValue.U16 }, + { + name: 'value', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + } + ); + return _cached_RawColumnDefaultValueV9_type_value; }, serialize(writer: __BinaryWriter, value: RawColumnDefaultValueV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts index 2f65f4cc2ff..453163184fa 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_constraint_data_v_9_type.ts @@ -25,6 +25,8 @@ import * as RawConstraintDataV9Variants from './raw_constraint_data_v_9_variants // The tagged union or sum type for the algebraic type `RawConstraintDataV9`. export type RawConstraintDataV9 = RawConstraintDataV9Variants.Unique; +let _cached_RawConstraintDataV9_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const RawConstraintDataV9 = { // Helper functions for constructing each variant of the tagged union. @@ -33,20 +35,21 @@ export const RawConstraintDataV9 = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - Unique: (value: RawUniqueConstraintDataV9): RawConstraintDataV9 => ({ - tag: 'Unique', - value, - }), + Unique: ( + value: RawUniqueConstraintDataV9 + ): RawConstraintDataV9Variants.Unique => ({ tag: 'Unique', value }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'Unique', - algebraicType: RawUniqueConstraintDataV9.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_RawConstraintDataV9_type_value) + return _cached_RawConstraintDataV9_type_value; + _cached_RawConstraintDataV9_type_value = __AlgebraicTypeValue.Sum({ + variants: [], + }); + _cached_RawConstraintDataV9_type_value.value.variants.push({ + name: 'Unique', + algebraicType: RawUniqueConstraintDataV9.getTypeScriptAlgebraicType(), }); + return _cached_RawConstraintDataV9_type_value; }, serialize(writer: __BinaryWriter, value: RawConstraintDataV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts index 2c0875dcb8e..53a1d66fafa 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_8_type.ts @@ -22,6 +22,8 @@ export type RawConstraintDefV8 = { constraints: number; columns: number[]; }; +let _cached_RawConstraintDefV8_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -31,16 +33,20 @@ export const RawConstraintDefV8 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'constraintName', algebraicType: __AlgebraicTypeValue.String }, - { name: 'constraints', algebraicType: __AlgebraicTypeValue.U8 }, - { - name: 'columns', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), - }, - ], + if (_cached_RawConstraintDefV8_type_value) + return _cached_RawConstraintDefV8_type_value; + _cached_RawConstraintDefV8_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawConstraintDefV8_type_value.value.elements.push( + { name: 'constraintName', algebraicType: __AlgebraicTypeValue.String }, + { name: 'constraints', algebraicType: __AlgebraicTypeValue.U8 }, + { + name: 'columns', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), + } + ); + return _cached_RawConstraintDefV8_type_value; }, serialize(writer: __BinaryWriter, value: RawConstraintDefV8): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts index 227f73848f0..eb21bf196eb 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_constraint_def_v_9_type.ts @@ -24,6 +24,8 @@ export type RawConstraintDefV9 = { name: string | undefined; data: RawConstraintDataV9; }; +let _cached_RawConstraintDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -33,20 +35,24 @@ export const RawConstraintDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { - name: 'data', - algebraicType: RawConstraintDataV9.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_RawConstraintDefV9_type_value) + return _cached_RawConstraintDefV9_type_value; + _cached_RawConstraintDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawConstraintDefV9_type_value.value.elements.push( + { + name: 'name', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { + name: 'data', + algebraicType: RawConstraintDataV9.getTypeScriptAlgebraicType(), + } + ); + return _cached_RawConstraintDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawConstraintDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts index c1034347e85..c9d9b9111cc 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_index_algorithm_type.ts @@ -24,6 +24,8 @@ export type RawIndexAlgorithm = | RawIndexAlgorithmVariants.Hash | RawIndexAlgorithmVariants.Direct; +let _cached_RawIndexAlgorithm_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const RawIndexAlgorithm = { // Helper functions for constructing each variant of the tagged union. @@ -32,24 +34,37 @@ export const RawIndexAlgorithm = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - BTree: (value: number[]): RawIndexAlgorithm => ({ tag: 'BTree', value }), - Hash: (value: number[]): RawIndexAlgorithm => ({ tag: 'Hash', value }), - Direct: (value: number): RawIndexAlgorithm => ({ tag: 'Direct', value }), + BTree: (value: number[]): RawIndexAlgorithmVariants.BTree => ({ + tag: 'BTree', + value, + }), + Hash: (value: number[]): RawIndexAlgorithmVariants.Hash => ({ + tag: 'Hash', + value, + }), + Direct: (value: number): RawIndexAlgorithmVariants.Direct => ({ + tag: 'Direct', + value, + }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'BTree', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), - }, - { - name: 'Hash', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), - }, - { name: 'Direct', algebraicType: __AlgebraicTypeValue.U16 }, - ], + if (_cached_RawIndexAlgorithm_type_value) + return _cached_RawIndexAlgorithm_type_value; + _cached_RawIndexAlgorithm_type_value = __AlgebraicTypeValue.Sum({ + variants: [], }); + _cached_RawIndexAlgorithm_type_value.value.variants.push( + { + name: 'BTree', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), + }, + { + name: 'Hash', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), + }, + { name: 'Direct', algebraicType: __AlgebraicTypeValue.U16 } + ); + return _cached_RawIndexAlgorithm_type_value; }, serialize(writer: __BinaryWriter, value: RawIndexAlgorithm): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts index c65d0ea4efd..4760d1cd435 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_8_type.ts @@ -26,6 +26,8 @@ export type RawIndexDefV8 = { indexType: IndexType; columns: number[]; }; +let _cached_RawIndexDefV8_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -35,20 +37,24 @@ export const RawIndexDefV8 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'indexName', algebraicType: __AlgebraicTypeValue.String }, - { name: 'isUnique', algebraicType: __AlgebraicTypeValue.Bool }, - { - name: 'indexType', - algebraicType: IndexType.getTypeScriptAlgebraicType(), - }, - { - name: 'columns', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), - }, - ], + if (_cached_RawIndexDefV8_type_value) + return _cached_RawIndexDefV8_type_value; + _cached_RawIndexDefV8_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawIndexDefV8_type_value.value.elements.push( + { name: 'indexName', algebraicType: __AlgebraicTypeValue.String }, + { name: 'isUnique', algebraicType: __AlgebraicTypeValue.Bool }, + { + name: 'indexType', + algebraicType: IndexType.getTypeScriptAlgebraicType(), + }, + { + name: 'columns', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), + } + ); + return _cached_RawIndexDefV8_type_value; }, serialize(writer: __BinaryWriter, value: RawIndexDefV8): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts index 22f49713e40..d3df3940259 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_index_def_v_9_type.ts @@ -25,6 +25,8 @@ export type RawIndexDefV9 = { accessorName: string | undefined; algorithm: RawIndexAlgorithm; }; +let _cached_RawIndexDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -34,26 +36,30 @@ export const RawIndexDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { - name: 'accessorName', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { - name: 'algorithm', - algebraicType: RawIndexAlgorithm.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_RawIndexDefV9_type_value) + return _cached_RawIndexDefV9_type_value; + _cached_RawIndexDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawIndexDefV9_type_value.value.elements.push( + { + name: 'name', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { + name: 'accessorName', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { + name: 'algorithm', + algebraicType: RawIndexAlgorithm.getTypeScriptAlgebraicType(), + } + ); + return _cached_RawIndexDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawIndexDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts index b4f27e219bd..f8a0566672b 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_misc_module_export_v_9_type.ts @@ -26,6 +26,8 @@ import * as RawMiscModuleExportV9Variants from './raw_misc_module_export_v_9_var export type RawMiscModuleExportV9 = RawMiscModuleExportV9Variants.ColumnDefaultValue; +let _cached_RawMiscModuleExportV9_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const RawMiscModuleExportV9 = { // Helper functions for constructing each variant of the tagged union. @@ -36,17 +38,22 @@ export const RawMiscModuleExportV9 = { // ``` ColumnDefaultValue: ( value: RawColumnDefaultValueV9 - ): RawMiscModuleExportV9 => ({ tag: 'ColumnDefaultValue', value }), + ): RawMiscModuleExportV9Variants.ColumnDefaultValue => ({ + tag: 'ColumnDefaultValue', + value, + }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'ColumnDefaultValue', - algebraicType: RawColumnDefaultValueV9.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_RawMiscModuleExportV9_type_value) + return _cached_RawMiscModuleExportV9_type_value; + _cached_RawMiscModuleExportV9_type_value = __AlgebraicTypeValue.Sum({ + variants: [], + }); + _cached_RawMiscModuleExportV9_type_value.value.variants.push({ + name: 'ColumnDefaultValue', + algebraicType: RawColumnDefaultValueV9.getTypeScriptAlgebraicType(), }); + return _cached_RawMiscModuleExportV9_type_value; }, serialize(writer: __BinaryWriter, value: RawMiscModuleExportV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts index fb70996fc7f..6df7f5869b6 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_module_def_type.ts @@ -30,6 +30,8 @@ export type RawModuleDef = | RawModuleDefVariants.V8BackCompat | RawModuleDefVariants.V9; +let _cached_RawModuleDef_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const RawModuleDef = { // Helper functions for constructing each variant of the tagged union. @@ -38,25 +40,28 @@ export const RawModuleDef = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - V8BackCompat: (value: RawModuleDefV8): RawModuleDef => ({ + V8BackCompat: (value: RawModuleDefV8): RawModuleDefVariants.V8BackCompat => ({ tag: 'V8BackCompat', value, }), - V9: (value: RawModuleDefV9): RawModuleDef => ({ tag: 'V9', value }), + V9: (value: RawModuleDefV9): RawModuleDefVariants.V9 => ({ + tag: 'V9', + value, + }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'V8BackCompat', - algebraicType: RawModuleDefV8.getTypeScriptAlgebraicType(), - }, - { - name: 'V9', - algebraicType: RawModuleDefV9.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_RawModuleDef_type_value) return _cached_RawModuleDef_type_value; + _cached_RawModuleDef_type_value = __AlgebraicTypeValue.Sum({ + variants: [], }); + _cached_RawModuleDef_type_value.value.variants.push( + { + name: 'V8BackCompat', + algebraicType: RawModuleDefV8.getTypeScriptAlgebraicType(), + }, + { name: 'V9', algebraicType: RawModuleDefV9.getTypeScriptAlgebraicType() } + ); + return _cached_RawModuleDef_type_value; }, serialize(writer: __BinaryWriter, value: RawModuleDef): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts index 4c311eb52e8..1ea5fdf6afa 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_8_type.ts @@ -35,6 +35,8 @@ export type RawModuleDefV8 = { reducers: ReducerDef[]; miscExports: MiscModuleExport[]; }; +let _cached_RawModuleDefV8_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -44,32 +46,36 @@ export const RawModuleDefV8 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'typespace', - algebraicType: Typespace.getTypeScriptAlgebraicType(), - }, - { - name: 'tables', - algebraicType: __AlgebraicTypeValue.Array( - TableDesc.getTypeScriptAlgebraicType() - ), - }, - { - name: 'reducers', - algebraicType: __AlgebraicTypeValue.Array( - ReducerDef.getTypeScriptAlgebraicType() - ), - }, - { - name: 'miscExports', - algebraicType: __AlgebraicTypeValue.Array( - MiscModuleExport.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_RawModuleDefV8_type_value) + return _cached_RawModuleDefV8_type_value; + _cached_RawModuleDefV8_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawModuleDefV8_type_value.value.elements.push( + { + name: 'typespace', + algebraicType: Typespace.getTypeScriptAlgebraicType(), + }, + { + name: 'tables', + algebraicType: __AlgebraicTypeValue.Array( + TableDesc.getTypeScriptAlgebraicType() + ), + }, + { + name: 'reducers', + algebraicType: __AlgebraicTypeValue.Array( + ReducerDef.getTypeScriptAlgebraicType() + ), + }, + { + name: 'miscExports', + algebraicType: __AlgebraicTypeValue.Array( + MiscModuleExport.getTypeScriptAlgebraicType() + ), + } + ); + return _cached_RawModuleDefV8_type_value; }, serialize(writer: __BinaryWriter, value: RawModuleDefV8): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts index edf06c0dc9d..f73d0060b67 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_module_def_v_9_type.ts @@ -43,6 +43,8 @@ export type RawModuleDefV9 = { miscExports: RawMiscModuleExportV9[]; rowLevelSecurity: RawRowLevelSecurityDefV9[]; }; +let _cached_RawModuleDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -52,44 +54,48 @@ export const RawModuleDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'typespace', - algebraicType: Typespace.getTypeScriptAlgebraicType(), - }, - { - name: 'tables', - algebraicType: __AlgebraicTypeValue.Array( - RawTableDefV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'reducers', - algebraicType: __AlgebraicTypeValue.Array( - RawReducerDefV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'types', - algebraicType: __AlgebraicTypeValue.Array( - RawTypeDefV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'miscExports', - algebraicType: __AlgebraicTypeValue.Array( - RawMiscModuleExportV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'rowLevelSecurity', - algebraicType: __AlgebraicTypeValue.Array( - RawRowLevelSecurityDefV9.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_RawModuleDefV9_type_value) + return _cached_RawModuleDefV9_type_value; + _cached_RawModuleDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawModuleDefV9_type_value.value.elements.push( + { + name: 'typespace', + algebraicType: Typespace.getTypeScriptAlgebraicType(), + }, + { + name: 'tables', + algebraicType: __AlgebraicTypeValue.Array( + RawTableDefV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'reducers', + algebraicType: __AlgebraicTypeValue.Array( + RawReducerDefV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'types', + algebraicType: __AlgebraicTypeValue.Array( + RawTypeDefV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'miscExports', + algebraicType: __AlgebraicTypeValue.Array( + RawMiscModuleExportV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'rowLevelSecurity', + algebraicType: __AlgebraicTypeValue.Array( + RawRowLevelSecurityDefV9.getTypeScriptAlgebraicType() + ), + } + ); + return _cached_RawModuleDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawModuleDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts index bca9f550b52..85872e7391d 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_reducer_def_v_9_type.ts @@ -28,6 +28,8 @@ export type RawReducerDefV9 = { params: ProductType; lifecycle: Lifecycle | undefined; }; +let _cached_RawReducerDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -37,21 +39,25 @@ export const RawReducerDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'params', - algebraicType: ProductType.getTypeScriptAlgebraicType(), - }, - { - name: 'lifecycle', - algebraicType: __AlgebraicTypeValue.createOptionType( - Lifecycle.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_RawReducerDefV9_type_value) + return _cached_RawReducerDefV9_type_value; + _cached_RawReducerDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawReducerDefV9_type_value.value.elements.push( + { name: 'name', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'params', + algebraicType: ProductType.getTypeScriptAlgebraicType(), + }, + { + name: 'lifecycle', + algebraicType: __AlgebraicTypeValue.createOptionType( + Lifecycle.getTypeScriptAlgebraicType() + ), + } + ); + return _cached_RawReducerDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawReducerDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts index 5f9c22f5c34..b611871d29b 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_row_level_security_def_v_9_type.ts @@ -20,6 +20,9 @@ import { export type RawRowLevelSecurityDefV9 = { sql: string; }; +let _cached_RawRowLevelSecurityDefV9_type_value: __AlgebraicTypeType | null = + null; + /** * An object for generated helper functions. */ @@ -29,9 +32,16 @@ export const RawRowLevelSecurityDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [{ name: 'sql', algebraicType: __AlgebraicTypeValue.String }], + if (_cached_RawRowLevelSecurityDefV9_type_value) + return _cached_RawRowLevelSecurityDefV9_type_value; + _cached_RawRowLevelSecurityDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_RawRowLevelSecurityDefV9_type_value.value.elements.push({ + name: 'sql', + algebraicType: __AlgebraicTypeValue.String, }); + return _cached_RawRowLevelSecurityDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawRowLevelSecurityDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts index 9715ba23cb2..1ea84503d48 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_schedule_def_v_9_type.ts @@ -22,6 +22,8 @@ export type RawScheduleDefV9 = { reducerName: string; scheduledAtColumn: number; }; +let _cached_RawScheduleDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -31,18 +33,22 @@ export const RawScheduleDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { name: 'reducerName', algebraicType: __AlgebraicTypeValue.String }, - { name: 'scheduledAtColumn', algebraicType: __AlgebraicTypeValue.U16 }, - ], + if (_cached_RawScheduleDefV9_type_value) + return _cached_RawScheduleDefV9_type_value; + _cached_RawScheduleDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawScheduleDefV9_type_value.value.elements.push( + { + name: 'name', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { name: 'reducerName', algebraicType: __AlgebraicTypeValue.String }, + { name: 'scheduledAtColumn', algebraicType: __AlgebraicTypeValue.U16 } + ); + return _cached_RawScheduleDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawScheduleDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts index 1ea08449bba..70cf0cd455b 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_scoped_type_name_v_9_type.ts @@ -21,6 +21,8 @@ export type RawScopedTypeNameV9 = { scope: string[]; name: string; }; +let _cached_RawScopedTypeNameV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -30,17 +32,19 @@ export const RawScopedTypeNameV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'scope', - algebraicType: __AlgebraicTypeValue.Array( - __AlgebraicTypeValue.String - ), - }, - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - ], + if (_cached_RawScopedTypeNameV9_type_value) + return _cached_RawScopedTypeNameV9_type_value; + _cached_RawScopedTypeNameV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawScopedTypeNameV9_type_value.value.elements.push( + { + name: 'scope', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.String), + }, + { name: 'name', algebraicType: __AlgebraicTypeValue.String } + ); + return _cached_RawScopedTypeNameV9_type_value; }, serialize(writer: __BinaryWriter, value: RawScopedTypeNameV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts index 47867a8e404..75c1799359f 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_8_type.ts @@ -26,6 +26,8 @@ export type RawSequenceDefV8 = { maxValue: bigint | undefined; allocated: bigint; }; +let _cached_RawSequenceDefV8_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -35,32 +37,36 @@ export const RawSequenceDefV8 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'sequenceName', algebraicType: __AlgebraicTypeValue.String }, - { name: 'colPos', algebraicType: __AlgebraicTypeValue.U16 }, - { name: 'increment', algebraicType: __AlgebraicTypeValue.I128 }, - { - name: 'start', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.I128 - ), - }, - { - name: 'minValue', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.I128 - ), - }, - { - name: 'maxValue', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.I128 - ), - }, - { name: 'allocated', algebraicType: __AlgebraicTypeValue.I128 }, - ], + if (_cached_RawSequenceDefV8_type_value) + return _cached_RawSequenceDefV8_type_value; + _cached_RawSequenceDefV8_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawSequenceDefV8_type_value.value.elements.push( + { name: 'sequenceName', algebraicType: __AlgebraicTypeValue.String }, + { name: 'colPos', algebraicType: __AlgebraicTypeValue.U16 }, + { name: 'increment', algebraicType: __AlgebraicTypeValue.I128 }, + { + name: 'start', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.I128 + ), + }, + { + name: 'minValue', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.I128 + ), + }, + { + name: 'maxValue', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.I128 + ), + }, + { name: 'allocated', algebraicType: __AlgebraicTypeValue.I128 } + ); + return _cached_RawSequenceDefV8_type_value; }, serialize(writer: __BinaryWriter, value: RawSequenceDefV8): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts index 5b903476ad8..4043c78a806 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_sequence_def_v_9_type.ts @@ -25,6 +25,8 @@ export type RawSequenceDefV9 = { maxValue: bigint | undefined; increment: bigint; }; +let _cached_RawSequenceDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -34,36 +36,40 @@ export const RawSequenceDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { name: 'column', algebraicType: __AlgebraicTypeValue.U16 }, - { - name: 'start', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.I128 - ), - }, - { - name: 'minValue', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.I128 - ), - }, - { - name: 'maxValue', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.I128 - ), - }, - { name: 'increment', algebraicType: __AlgebraicTypeValue.I128 }, - ], + if (_cached_RawSequenceDefV9_type_value) + return _cached_RawSequenceDefV9_type_value; + _cached_RawSequenceDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawSequenceDefV9_type_value.value.elements.push( + { + name: 'name', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { name: 'column', algebraicType: __AlgebraicTypeValue.U16 }, + { + name: 'start', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.I128 + ), + }, + { + name: 'minValue', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.I128 + ), + }, + { + name: 'maxValue', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.I128 + ), + }, + { name: 'increment', algebraicType: __AlgebraicTypeValue.I128 } + ); + return _cached_RawSequenceDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawSequenceDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts index 6e58a758a09..56775011d3e 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_8_type.ts @@ -39,6 +39,8 @@ export type RawTableDefV8 = { tableAccess: string; scheduled: string | undefined; }; +let _cached_RawTableDefV8_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -48,43 +50,47 @@ export const RawTableDefV8 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'columns', - algebraicType: __AlgebraicTypeValue.Array( - RawColumnDefV8.getTypeScriptAlgebraicType() - ), - }, - { - name: 'indexes', - algebraicType: __AlgebraicTypeValue.Array( - RawIndexDefV8.getTypeScriptAlgebraicType() - ), - }, - { - name: 'constraints', - algebraicType: __AlgebraicTypeValue.Array( - RawConstraintDefV8.getTypeScriptAlgebraicType() - ), - }, - { - name: 'sequences', - algebraicType: __AlgebraicTypeValue.Array( - RawSequenceDefV8.getTypeScriptAlgebraicType() - ), - }, - { name: 'tableType', algebraicType: __AlgebraicTypeValue.String }, - { name: 'tableAccess', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'scheduled', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - ], + if (_cached_RawTableDefV8_type_value) + return _cached_RawTableDefV8_type_value; + _cached_RawTableDefV8_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawTableDefV8_type_value.value.elements.push( + { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'columns', + algebraicType: __AlgebraicTypeValue.Array( + RawColumnDefV8.getTypeScriptAlgebraicType() + ), + }, + { + name: 'indexes', + algebraicType: __AlgebraicTypeValue.Array( + RawIndexDefV8.getTypeScriptAlgebraicType() + ), + }, + { + name: 'constraints', + algebraicType: __AlgebraicTypeValue.Array( + RawConstraintDefV8.getTypeScriptAlgebraicType() + ), + }, + { + name: 'sequences', + algebraicType: __AlgebraicTypeValue.Array( + RawSequenceDefV8.getTypeScriptAlgebraicType() + ), + }, + { name: 'tableType', algebraicType: __AlgebraicTypeValue.String }, + { name: 'tableAccess', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'scheduled', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + } + ); + return _cached_RawTableDefV8_type_value; }, serialize(writer: __BinaryWriter, value: RawTableDefV8): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts index 2f0328db1da..88d6045c24a 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_table_def_v_9_type.ts @@ -46,6 +46,8 @@ export type RawTableDefV9 = { tableType: TableType; tableAccess: TableAccess; }; +let _cached_RawTableDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -55,48 +57,52 @@ export const RawTableDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'productTypeRef', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'primaryKey', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), - }, - { - name: 'indexes', - algebraicType: __AlgebraicTypeValue.Array( - RawIndexDefV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'constraints', - algebraicType: __AlgebraicTypeValue.Array( - RawConstraintDefV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'sequences', - algebraicType: __AlgebraicTypeValue.Array( - RawSequenceDefV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'schedule', - algebraicType: __AlgebraicTypeValue.createOptionType( - RawScheduleDefV9.getTypeScriptAlgebraicType() - ), - }, - { - name: 'tableType', - algebraicType: TableType.getTypeScriptAlgebraicType(), - }, - { - name: 'tableAccess', - algebraicType: TableAccess.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_RawTableDefV9_type_value) + return _cached_RawTableDefV9_type_value; + _cached_RawTableDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawTableDefV9_type_value.value.elements.push( + { name: 'name', algebraicType: __AlgebraicTypeValue.String }, + { name: 'productTypeRef', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'primaryKey', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), + }, + { + name: 'indexes', + algebraicType: __AlgebraicTypeValue.Array( + RawIndexDefV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'constraints', + algebraicType: __AlgebraicTypeValue.Array( + RawConstraintDefV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'sequences', + algebraicType: __AlgebraicTypeValue.Array( + RawSequenceDefV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'schedule', + algebraicType: __AlgebraicTypeValue.createOptionType( + RawScheduleDefV9.getTypeScriptAlgebraicType() + ), + }, + { + name: 'tableType', + algebraicType: TableType.getTypeScriptAlgebraicType(), + }, + { + name: 'tableAccess', + algebraicType: TableAccess.getTypeScriptAlgebraicType(), + } + ); + return _cached_RawTableDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawTableDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts index 772c6fd4587..5a589342fe4 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_type_def_v_9_type.ts @@ -25,6 +25,8 @@ export type RawTypeDefV9 = { ty: number; customOrdering: boolean; }; +let _cached_RawTypeDefV9_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -34,16 +36,19 @@ export const RawTypeDefV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'name', - algebraicType: RawScopedTypeNameV9.getTypeScriptAlgebraicType(), - }, - { name: 'ty', algebraicType: __AlgebraicTypeValue.U32 }, - { name: 'customOrdering', algebraicType: __AlgebraicTypeValue.Bool }, - ], + if (_cached_RawTypeDefV9_type_value) return _cached_RawTypeDefV9_type_value; + _cached_RawTypeDefV9_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_RawTypeDefV9_type_value.value.elements.push( + { + name: 'name', + algebraicType: RawScopedTypeNameV9.getTypeScriptAlgebraicType(), + }, + { name: 'ty', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'customOrdering', algebraicType: __AlgebraicTypeValue.Bool } + ); + return _cached_RawTypeDefV9_type_value; }, serialize(writer: __BinaryWriter, value: RawTypeDefV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts b/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts index a3e4b69b22f..5d0ff3e4cef 100644 --- a/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/raw_unique_constraint_data_v_9_type.ts @@ -20,6 +20,9 @@ import { export type RawUniqueConstraintDataV9 = { columns: number[]; }; +let _cached_RawUniqueConstraintDataV9_type_value: __AlgebraicTypeType | null = + null; + /** * An object for generated helper functions. */ @@ -29,14 +32,16 @@ export const RawUniqueConstraintDataV9 = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'columns', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), - }, - ], + if (_cached_RawUniqueConstraintDataV9_type_value) + return _cached_RawUniqueConstraintDataV9_type_value; + _cached_RawUniqueConstraintDataV9_type_value = __AlgebraicTypeValue.Product( + { elements: [] } + ); + _cached_RawUniqueConstraintDataV9_type_value.value.elements.push({ + name: 'columns', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U16), }); + return _cached_RawUniqueConstraintDataV9_type_value; }, serialize(writer: __BinaryWriter, value: RawUniqueConstraintDataV9): void { diff --git a/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts b/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts index 85b1539d6a8..55f9af77507 100644 --- a/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/reducer_def_type.ts @@ -24,6 +24,8 @@ export type ReducerDef = { name: string; args: ProductTypeElement[]; }; +let _cached_ReducerDef_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -33,17 +35,20 @@ export const ReducerDef = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'args', - algebraicType: __AlgebraicTypeValue.Array( - ProductTypeElement.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_ReducerDef_type_value) return _cached_ReducerDef_type_value; + _cached_ReducerDef_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_ReducerDef_type_value.value.elements.push( + { name: 'name', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'args', + algebraicType: __AlgebraicTypeValue.Array( + ProductTypeElement.getTypeScriptAlgebraicType() + ), + } + ); + return _cached_ReducerDef_type_value; }, serialize(writer: __BinaryWriter, value: ReducerDef): void { diff --git a/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts b/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts index 620a12c3ecb..c8e1bd6313c 100644 --- a/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/sum_type_type.ts @@ -23,6 +23,8 @@ declare type __keep_SumTypeVariant = SumTypeVariant; export type SumType = { variants: SumTypeVariant[]; }; +let _cached_SumType_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -32,16 +34,15 @@ export const SumType = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'variants', - algebraicType: __AlgebraicTypeValue.Array( - SumTypeVariant.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_SumType_type_value) return _cached_SumType_type_value; + _cached_SumType_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_SumType_type_value.value.elements.push({ + name: 'variants', + algebraicType: __AlgebraicTypeValue.Array( + SumTypeVariant.getTypeScriptAlgebraicType() + ), }); + return _cached_SumType_type_value; }, serialize(writer: __BinaryWriter, value: SumType): void { diff --git a/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts b/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts index cca70c726ec..9f784c25997 100644 --- a/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/sum_type_variant_type.ts @@ -24,6 +24,8 @@ export type SumTypeVariant = { name: string | undefined; algebraicType: AlgebraicType; }; +let _cached_SumTypeVariant_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -33,20 +35,24 @@ export const SumTypeVariant = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'name', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { - name: 'algebraicType', - algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_SumTypeVariant_type_value) + return _cached_SumTypeVariant_type_value; + _cached_SumTypeVariant_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_SumTypeVariant_type_value.value.elements.push( + { + name: 'name', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { + name: 'algebraicType', + algebraicType: AlgebraicType.getTypeScriptAlgebraicType(), + } + ); + return _cached_SumTypeVariant_type_value; }, serialize(writer: __BinaryWriter, value: SumTypeVariant): void { diff --git a/crates/bindings-typescript/src/lib/autogen/table_access_type.ts b/crates/bindings-typescript/src/lib/autogen/table_access_type.ts index 46f2e1c806a..884835677b3 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_access_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_access_type.ts @@ -23,6 +23,8 @@ export type TableAccess = | TableAccessVariants.Public | TableAccessVariants.Private; +let _cached_TableAccess_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const TableAccess = { // Helper functions for constructing each variant of the tagged union. @@ -35,18 +37,19 @@ export const TableAccess = { Private: { tag: 'Private' } as const, getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'Public', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'Private', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - ], - }); + if (_cached_TableAccess_type_value) return _cached_TableAccess_type_value; + _cached_TableAccess_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_TableAccess_type_value.value.variants.push( + { + name: 'Public', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'Private', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + } + ); + return _cached_TableAccess_type_value; }, serialize(writer: __BinaryWriter, value: TableAccess): void { diff --git a/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts b/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts index 1f13c15f753..78d3f6f7bb3 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_desc_type.ts @@ -24,6 +24,8 @@ export type TableDesc = { schema: RawTableDefV8; data: number; }; +let _cached_TableDesc_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -33,15 +35,18 @@ export const TableDesc = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'schema', - algebraicType: RawTableDefV8.getTypeScriptAlgebraicType(), - }, - { name: 'data', algebraicType: __AlgebraicTypeValue.U32 }, - ], + if (_cached_TableDesc_type_value) return _cached_TableDesc_type_value; + _cached_TableDesc_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_TableDesc_type_value.value.elements.push( + { + name: 'schema', + algebraicType: RawTableDefV8.getTypeScriptAlgebraicType(), + }, + { name: 'data', algebraicType: __AlgebraicTypeValue.U32 } + ); + return _cached_TableDesc_type_value; }, serialize(writer: __BinaryWriter, value: TableDesc): void { diff --git a/crates/bindings-typescript/src/lib/autogen/table_type_type.ts b/crates/bindings-typescript/src/lib/autogen/table_type_type.ts index b75201e743e..d2237db481b 100644 --- a/crates/bindings-typescript/src/lib/autogen/table_type_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/table_type_type.ts @@ -21,6 +21,8 @@ import * as TableTypeVariants from './table_type_variants'; // The tagged union or sum type for the algebraic type `TableType`. export type TableType = TableTypeVariants.System | TableTypeVariants.User; +let _cached_TableType_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const TableType = { // Helper functions for constructing each variant of the tagged union. @@ -33,18 +35,19 @@ export const TableType = { User: { tag: 'User' } as const, getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'System', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - { - name: 'User', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - ], - }); + if (_cached_TableType_type_value) return _cached_TableType_type_value; + _cached_TableType_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_TableType_type_value.value.variants.push( + { + name: 'System', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + }, + { + name: 'User', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + } + ); + return _cached_TableType_type_value; }, serialize(writer: __BinaryWriter, value: TableType): void { diff --git a/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts b/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts index 6a9fb0b3292..6bb6000a51b 100644 --- a/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/type_alias_type.ts @@ -21,6 +21,8 @@ export type TypeAlias = { name: string; ty: number; }; +let _cached_TypeAlias_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -30,12 +32,15 @@ export const TypeAlias = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'ty', algebraicType: __AlgebraicTypeValue.U32 }, - ], + if (_cached_TypeAlias_type_value) return _cached_TypeAlias_type_value; + _cached_TypeAlias_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_TypeAlias_type_value.value.elements.push( + { name: 'name', algebraicType: __AlgebraicTypeValue.String }, + { name: 'ty', algebraicType: __AlgebraicTypeValue.U32 } + ); + return _cached_TypeAlias_type_value; }, serialize(writer: __BinaryWriter, value: TypeAlias): void { diff --git a/crates/bindings-typescript/src/lib/autogen/typespace_type.ts b/crates/bindings-typescript/src/lib/autogen/typespace_type.ts index 0dc609b8ea5..7eb7d338238 100644 --- a/crates/bindings-typescript/src/lib/autogen/typespace_type.ts +++ b/crates/bindings-typescript/src/lib/autogen/typespace_type.ts @@ -23,6 +23,8 @@ declare type __keep_AlgebraicType = AlgebraicType; export type Typespace = { types: AlgebraicType[]; }; +let _cached_Typespace_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -32,16 +34,17 @@ export const Typespace = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'types', - algebraicType: __AlgebraicTypeValue.Array( - AlgebraicType.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_Typespace_type_value) return _cached_Typespace_type_value; + _cached_Typespace_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_Typespace_type_value.value.elements.push({ + name: 'types', + algebraicType: __AlgebraicTypeValue.Array( + AlgebraicType.getTypeScriptAlgebraicType() + ), }); + return _cached_Typespace_type_value; }, serialize(writer: __BinaryWriter, value: Typespace): void { diff --git a/crates/bindings-typescript/src/lib/binary_reader.ts b/crates/bindings-typescript/src/lib/binary_reader.ts index f40f4101bca..5a7cba95393 100644 --- a/crates/bindings-typescript/src/lib/binary_reader.ts +++ b/crates/bindings-typescript/src/lib/binary_reader.ts @@ -1,118 +1,142 @@ export default class BinaryReader { - #buffer: DataView; + /** + * The DataView used to read values from the binary data. + * + * Note: The DataView's `byteOffset` is relative to the beginning of the + * underlying ArrayBuffer, not the start of the provided Uint8Array input. + * This `BinaryReader`'s `#offset` field is used to track the current read position + * relative to the start of the provided Uint8Array input. + */ + #view: DataView; + + /** + * Represents the offset (in bytes) relative to the start of the DataView + * and provided Uint8Array input. + * + * Note: This is *not* the absolute byte offset within the underlying ArrayBuffer. + */ #offset: number = 0; constructor(input: Uint8Array) { - this.#buffer = new DataView(input.buffer); - this.#offset = input.byteOffset; + this.#view = new DataView(input.buffer, input.byteOffset, input.byteLength); + this.#offset = 0; } get offset(): number { return this.#offset; } + get remaining(): number { + return this.#view.byteLength - this.#offset; + } + + /** Ensure we have at least `n` bytes left to read */ + #ensure(n: number): void { + if (this.#offset + n > this.#view.byteLength) { + throw new RangeError( + `Tried to read ${n} byte(s) at relative offset ${this.#offset}, but only ${this.remaining} byte(s) remain` + ); + } + } + readUInt8Array(): Uint8Array { const length = this.readU32(); - const value: Uint8Array = new Uint8Array( - this.#buffer.buffer, - this.#offset, - length - ); - this.#offset += length; - return value; + this.#ensure(length); + return this.readBytes(length); } readBool(): boolean { - const value = this.#buffer.getUint8(this.#offset); + const value = this.#view.getUint8(this.#offset); this.#offset += 1; return value !== 0; } readByte(): number { - const value = this.#buffer.getUint8(this.#offset); + const value = this.#view.getUint8(this.#offset); this.#offset += 1; return value; } readBytes(length: number): Uint8Array { - const value: DataView = new DataView( - this.#buffer.buffer, - this.#offset, + // Create a Uint8Array view over the DataView's buffer at the current offset + // The #view.buffer is the whole ArrayBuffer, so we need to account for the + // #view's starting position in that buffer (#view.byteOffset) and the current #offset + const array = new Uint8Array( + this.#view.buffer, + this.#view.byteOffset + this.#offset, length ); this.#offset += length; - return new Uint8Array(value.buffer); + return array; } readI8(): number { - const value = this.#buffer.getInt8(this.#offset); + const value = this.#view.getInt8(this.#offset); this.#offset += 1; return value; } readU8(): number { - const value = this.#buffer.getUint8(this.#offset); - this.#offset += 1; - return value; + return this.readByte(); } readI16(): number { - const value = this.#buffer.getInt16(this.#offset, true); + const value = this.#view.getInt16(this.#offset, true); this.#offset += 2; return value; } readU16(): number { - const value = this.#buffer.getUint16(this.#offset, true); + const value = this.#view.getUint16(this.#offset, true); this.#offset += 2; return value; } readI32(): number { - const value = this.#buffer.getInt32(this.#offset, true); + const value = this.#view.getInt32(this.#offset, true); this.#offset += 4; return value; } readU32(): number { - const value = this.#buffer.getUint32(this.#offset, true); + const value = this.#view.getUint32(this.#offset, true); this.#offset += 4; return value; } readI64(): bigint { - const value = this.#buffer.getBigInt64(this.#offset, true); + const value = this.#view.getBigInt64(this.#offset, true); this.#offset += 8; return value; } readU64(): bigint { - const value = this.#buffer.getBigUint64(this.#offset, true); + const value = this.#view.getBigUint64(this.#offset, true); this.#offset += 8; return value; } readU128(): bigint { - const lowerPart = this.#buffer.getBigUint64(this.#offset, true); - const upperPart = this.#buffer.getBigUint64(this.#offset + 8, true); + const lowerPart = this.#view.getBigUint64(this.#offset, true); + const upperPart = this.#view.getBigUint64(this.#offset + 8, true); this.#offset += 16; return (upperPart << BigInt(64)) + lowerPart; } readI128(): bigint { - const lowerPart = this.#buffer.getBigUint64(this.#offset, true); - const upperPart = this.#buffer.getBigInt64(this.#offset + 8, true); + const lowerPart = this.#view.getBigUint64(this.#offset, true); + const upperPart = this.#view.getBigInt64(this.#offset + 8, true); this.#offset += 16; return (upperPart << BigInt(64)) + lowerPart; } readU256(): bigint { - const p0 = this.#buffer.getBigUint64(this.#offset, true); - const p1 = this.#buffer.getBigUint64(this.#offset + 8, true); - const p2 = this.#buffer.getBigUint64(this.#offset + 16, true); - const p3 = this.#buffer.getBigUint64(this.#offset + 24, true); + const p0 = this.#view.getBigUint64(this.#offset, true); + const p1 = this.#view.getBigUint64(this.#offset + 8, true); + const p2 = this.#view.getBigUint64(this.#offset + 16, true); + const p3 = this.#view.getBigUint64(this.#offset + 24, true); this.#offset += 32; return ( @@ -124,10 +148,10 @@ export default class BinaryReader { } readI256(): bigint { - const p0 = this.#buffer.getBigUint64(this.#offset, true); - const p1 = this.#buffer.getBigUint64(this.#offset + 8, true); - const p2 = this.#buffer.getBigUint64(this.#offset + 16, true); - const p3 = this.#buffer.getBigInt64(this.#offset + 24, true); + const p0 = this.#view.getBigUint64(this.#offset, true); + const p1 = this.#view.getBigUint64(this.#offset + 8, true); + const p2 = this.#view.getBigUint64(this.#offset + 16, true); + const p3 = this.#view.getBigInt64(this.#offset + 24, true); this.#offset += 32; return ( @@ -139,27 +163,19 @@ export default class BinaryReader { } readF32(): number { - const value = this.#buffer.getFloat32(this.#offset, true); + const value = this.#view.getFloat32(this.#offset, true); this.#offset += 4; return value; } readF64(): number { - const value = this.#buffer.getFloat64(this.#offset, true); + const value = this.#view.getFloat64(this.#offset, true); this.#offset += 8; return value; } readString(): string { - const length = this.readU32(); - const uint8Array = new Uint8Array( - this.#buffer.buffer, - this.#offset, - length - ); - const decoder = new TextDecoder('utf-8'); - const value = decoder.decode(uint8Array); - this.#offset += length; - return value; + const uint8Array = this.readUInt8Array(); + return new TextDecoder('utf-8').decode(uint8Array); } } diff --git a/crates/bindings-typescript/src/lib/binary_writer.ts b/crates/bindings-typescript/src/lib/binary_writer.ts index 8a55a3ffd44..e9b8609893a 100644 --- a/crates/bindings-typescript/src/lib/binary_writer.ts +++ b/crates/bindings-typescript/src/lib/binary_writer.ts @@ -29,6 +29,10 @@ export default class BinaryWriter { return this.#buffer.slice(0, this.#offset); } + get offset(): number { + return this.#offset; + } + writeUInt8Array(value: Uint8Array): void { const length = value.length; diff --git a/crates/bindings-typescript/src/lib/connection_id.ts b/crates/bindings-typescript/src/lib/connection_id.ts index e8a981602c4..64da6361395 100644 --- a/crates/bindings-typescript/src/lib/connection_id.ts +++ b/crates/bindings-typescript/src/lib/connection_id.ts @@ -1,6 +1,13 @@ import { AlgebraicType } from './algebraic_type'; import { hexStringToU128, u128ToHexString, u128ToUint8Array } from './utils'; +export type ConnectionIdAlgebraicType = { + tag: 'Product'; + value: { + elements: [{ name: '__connection_id__'; algebraicType: { tag: 'U128' } }]; + }; +}; + /** * A unique identifier for a client connected to a database. */ @@ -18,7 +25,7 @@ export class ConnectionId { * Get the algebraic type representation of the {@link ConnectionId} type. * @returns The algebraic type representation of the type. */ - static getAlgebraicType(): AlgebraicType { + static getAlgebraicType(): ConnectionIdAlgebraicType { return AlgebraicType.Product({ elements: [ { name: '__connection_id__', algebraicType: AlgebraicType.U128 }, diff --git a/crates/bindings-typescript/src/lib/identity.ts b/crates/bindings-typescript/src/lib/identity.ts index e2e128ce74f..3b2b0e60ed8 100644 --- a/crates/bindings-typescript/src/lib/identity.ts +++ b/crates/bindings-typescript/src/lib/identity.ts @@ -1,6 +1,13 @@ import { AlgebraicType } from './algebraic_type'; import { hexStringToU256, u256ToHexString, u256ToUint8Array } from './utils'; +export type IdentityAlgebraicType = { + tag: 'Product'; + value: { + elements: [{ name: '__identity__'; algebraicType: { tag: 'U256' } }]; + }; +}; + /** * A unique identifier for a user connected to a database. */ @@ -22,7 +29,7 @@ export class Identity { * Get the algebraic type representation of the {@link Identity} type. * @returns The algebraic type representation of the type. */ - static getAlgebraicType(): AlgebraicType { + static getAlgebraicType(): IdentityAlgebraicType { return AlgebraicType.Product({ elements: [{ name: '__identity__', algebraicType: AlgebraicType.U256 }], }); @@ -62,4 +69,8 @@ export class Identity { static zero(): Identity { return new Identity(0n); } + + toString(): string { + return this.toHexString(); + } } diff --git a/crates/bindings-typescript/src/lib/option.ts b/crates/bindings-typescript/src/lib/option.ts new file mode 100644 index 00000000000..c6f719a89fe --- /dev/null +++ b/crates/bindings-typescript/src/lib/option.ts @@ -0,0 +1,30 @@ +import { AlgebraicType } from './algebraic_type'; + +export type OptionAlgebraicType = { + tag: 'Sum'; + value: { + variants: [ + { name: 'some'; algebraicType: AlgebraicType }, + { + name: 'none'; + algebraicType: { tag: 'Product'; value: { elements: [] } }; + }, + ]; + }; +}; + +export const Option: { + getAlgebraicType(innerType: AlgebraicType): OptionAlgebraicType; +} = { + getAlgebraicType(innerType: AlgebraicType): OptionAlgebraicType { + return AlgebraicType.Sum({ + variants: [ + { name: 'some', algebraicType: innerType }, + { + name: 'none', + algebraicType: AlgebraicType.Product({ elements: [] }), + }, + ], + }); + }, +}; diff --git a/crates/bindings-typescript/src/lib/schedule_at.ts b/crates/bindings-typescript/src/lib/schedule_at.ts index cbb9fae7b23..4fb185e7ea2 100644 --- a/crates/bindings-typescript/src/lib/schedule_at.ts +++ b/crates/bindings-typescript/src/lib/schedule_at.ts @@ -1,22 +1,42 @@ import { AlgebraicType } from './algebraic_type'; -import { TimeDuration } from './time_duration'; -import { Timestamp } from './timestamp'; +import { TimeDuration, type TimeDurationAlgebraicType } from './time_duration'; +import { Timestamp, type TimestampAlgebraicType } from './timestamp'; + +export type ScheduleAtAlgebraicType = { + tag: 'Sum'; + value: { + variants: [ + { name: 'Interval'; algebraicType: TimeDurationAlgebraicType }, + { name: 'Time'; algebraicType: TimestampAlgebraicType }, + ]; + }; +}; + +type ScheduleAtType = Interval | Time; export const ScheduleAt: { + interval: (micros: bigint) => ScheduleAtType; + time: (microsSinceUnixEpoch: bigint) => ScheduleAtType; /** * Get the algebraic type representation of the {@link ScheduleAt} type. * @returns The algebraic type representation of the type. */ - getAlgebraicType(): AlgebraicType; + getAlgebraicType(): ScheduleAtAlgebraicType; } = { - getAlgebraicType(): AlgebraicType { + interval(value: bigint): ScheduleAtType { + return Interval(value); + }, + time(value: bigint): ScheduleAtType { + return Time(value); + }, + getAlgebraicType(): ScheduleAtAlgebraicType { return AlgebraicType.Sum({ variants: [ { name: 'Interval', - algebraicType: AlgebraicType.createTimeDurationType(), + algebraicType: TimeDuration.getAlgebraicType(), }, - { name: 'Time', algebraicType: AlgebraicType.createTimestampType() }, + { name: 'Time', algebraicType: Timestamp.getAlgebraicType() }, ], }); }, @@ -26,18 +46,18 @@ export type Interval = { tag: 'Interval'; value: TimeDuration; }; -export const Interval = (value: bigint): Interval => ({ +export const Interval = (micros: bigint): Interval => ({ tag: 'Interval', - value: new TimeDuration(value), + value: new TimeDuration(micros), }); export type Time = { tag: 'Time'; value: Timestamp; }; -export const Time = (value: bigint): Time => ({ +export const Time = (microsSinceUnixEpoch: bigint): Time => ({ tag: 'Time', - value: new Timestamp(value), + value: new Timestamp(microsSinceUnixEpoch), }); -export type ScheduleAt = Interval | Time; export default ScheduleAt; +export type ScheduleAt = ScheduleAtType; diff --git a/crates/bindings-typescript/src/lib/time_duration.ts b/crates/bindings-typescript/src/lib/time_duration.ts index 478dc329264..c8ccc5d64af 100644 --- a/crates/bindings-typescript/src/lib/time_duration.ts +++ b/crates/bindings-typescript/src/lib/time_duration.ts @@ -1,5 +1,14 @@ import { AlgebraicType } from './algebraic_type'; +export type TimeDurationAlgebraicType = { + tag: 'Product'; + value: { + elements: [ + { name: '__time_duration_micros__'; algebraicType: { tag: 'I64' } }, + ]; + }; +}; + /** * A difference between two points in time, represented as a number of microseconds. */ @@ -12,7 +21,7 @@ export class TimeDuration { * Get the algebraic type representation of the {@link TimeDuration} type. * @returns The algebraic type representation of the type. */ - static getAlgebraicType(): AlgebraicType { + static getAlgebraicType(): TimeDurationAlgebraicType { return AlgebraicType.Product({ elements: [ { @@ -38,4 +47,14 @@ export class TimeDuration { static fromMillis(millis: number): TimeDuration { return new TimeDuration(BigInt(millis) * TimeDuration.MICROS_PER_MILLIS); } + + /** This outputs the same string format that we use in the host and in Rust modules */ + toString(): string { + const micros = this.micros; + const sign = micros < 0 ? '-' : '+'; + const pos = micros < 0 ? -micros : micros; + const secs = pos / 1_000_000n; + const micros_remaining = pos % 1_000_000n; + return `${sign}${secs}.${String(micros_remaining).padStart(6, '0')}`; + } } diff --git a/crates/bindings-typescript/src/lib/timestamp.ts b/crates/bindings-typescript/src/lib/timestamp.ts index 4f3081824c3..e97fca90de8 100644 --- a/crates/bindings-typescript/src/lib/timestamp.ts +++ b/crates/bindings-typescript/src/lib/timestamp.ts @@ -1,4 +1,17 @@ import { AlgebraicType } from './algebraic_type'; +import { TimeDuration } from './time_duration'; + +export type TimestampAlgebraicType = { + tag: 'Product'; + value: { + elements: [ + { + name: '__timestamp_micros_since_unix_epoch__'; + algebraicType: { tag: 'I64' }; + }, + ]; + }; +}; /** * A point in time, represented as a number of microseconds since the Unix epoch. @@ -20,7 +33,7 @@ export class Timestamp { * Get the algebraic type representation of the {@link Timestamp} type. * @returns The algebraic type representation of the type. */ - static getAlgebraicType(): AlgebraicType { + static getAlgebraicType(): TimestampAlgebraicType { return AlgebraicType.Product({ elements: [ { @@ -71,4 +84,11 @@ export class Timestamp { } return new Date(Number(millis)); } + + since(other: Timestamp): TimeDuration { + return new TimeDuration( + this.__timestamp_micros_since_unix_epoch__ - + other.__timestamp_micros_since_unix_epoch__ + ); + } } diff --git a/crates/bindings-typescript/src/sdk/client_api/bsatn_row_list_type.ts b/crates/bindings-typescript/src/sdk/client_api/bsatn_row_list_type.ts index 41ebeab6ddc..2e769689c07 100644 --- a/crates/bindings-typescript/src/sdk/client_api/bsatn_row_list_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/bsatn_row_list_type.ts @@ -35,6 +35,8 @@ export type BsatnRowList = { sizeHint: RowSizeHint; rowsData: Uint8Array; }; +let _cached_BsatnRowList_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -44,18 +46,21 @@ export const BsatnRowList = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'sizeHint', - algebraicType: RowSizeHint.getTypeScriptAlgebraicType(), - }, - { - name: 'rowsData', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - ], + if (_cached_BsatnRowList_type_value) return _cached_BsatnRowList_type_value; + _cached_BsatnRowList_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_BsatnRowList_type_value.value.elements.push( + { + name: 'sizeHint', + algebraicType: RowSizeHint.getTypeScriptAlgebraicType(), + }, + { + name: 'rowsData', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + } + ); + return _cached_BsatnRowList_type_value; }, serialize(writer: __BinaryWriter, value: BsatnRowList): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/call_reducer_type.ts b/crates/bindings-typescript/src/sdk/client_api/call_reducer_type.ts index 08e72a21425..8b41532f796 100644 --- a/crates/bindings-typescript/src/sdk/client_api/call_reducer_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/call_reducer_type.ts @@ -34,6 +34,8 @@ export type CallReducer = { requestId: number; flags: number; }; +let _cached_CallReducer_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -43,17 +45,20 @@ export const CallReducer = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'reducer', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'args', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { name: 'flags', algebraicType: __AlgebraicTypeValue.U8 }, - ], + if (_cached_CallReducer_type_value) return _cached_CallReducer_type_value; + _cached_CallReducer_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_CallReducer_type_value.value.elements.push( + { name: 'reducer', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'args', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + }, + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'flags', algebraicType: __AlgebraicTypeValue.U8 } + ); + return _cached_CallReducer_type_value; }, serialize(writer: __BinaryWriter, value: CallReducer): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts b/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts index bdc05a1183e..4883bbf7a85 100644 --- a/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/client_message_type.ts @@ -61,6 +61,8 @@ export type ClientMessage = | ClientMessageVariants.Unsubscribe | ClientMessageVariants.UnsubscribeMulti; +let _cached_ClientMessage_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const ClientMessage = { // Helper functions for constructing each variant of the tagged union. @@ -69,65 +71,75 @@ export const ClientMessage = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - CallReducer: (value: CallReducer): ClientMessage => ({ + CallReducer: (value: CallReducer): ClientMessageVariants.CallReducer => ({ tag: 'CallReducer', value, }), - Subscribe: (value: Subscribe): ClientMessage => ({ tag: 'Subscribe', value }), - OneOffQuery: (value: OneOffQuery): ClientMessage => ({ - tag: 'OneOffQuery', + Subscribe: (value: Subscribe): ClientMessageVariants.Subscribe => ({ + tag: 'Subscribe', value, }), - SubscribeSingle: (value: SubscribeSingle): ClientMessage => ({ - tag: 'SubscribeSingle', + OneOffQuery: (value: OneOffQuery): ClientMessageVariants.OneOffQuery => ({ + tag: 'OneOffQuery', value, }), - SubscribeMulti: (value: SubscribeMulti): ClientMessage => ({ - tag: 'SubscribeMulti', + SubscribeSingle: ( + value: SubscribeSingle + ): ClientMessageVariants.SubscribeSingle => ({ + tag: 'SubscribeSingle', value, }), - Unsubscribe: (value: Unsubscribe): ClientMessage => ({ + SubscribeMulti: ( + value: SubscribeMulti + ): ClientMessageVariants.SubscribeMulti => ({ tag: 'SubscribeMulti', value }), + Unsubscribe: (value: Unsubscribe): ClientMessageVariants.Unsubscribe => ({ tag: 'Unsubscribe', value, }), - UnsubscribeMulti: (value: UnsubscribeMulti): ClientMessage => ({ + UnsubscribeMulti: ( + value: UnsubscribeMulti + ): ClientMessageVariants.UnsubscribeMulti => ({ tag: 'UnsubscribeMulti', value, }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'CallReducer', - algebraicType: CallReducer.getTypeScriptAlgebraicType(), - }, - { - name: 'Subscribe', - algebraicType: Subscribe.getTypeScriptAlgebraicType(), - }, - { - name: 'OneOffQuery', - algebraicType: OneOffQuery.getTypeScriptAlgebraicType(), - }, - { - name: 'SubscribeSingle', - algebraicType: SubscribeSingle.getTypeScriptAlgebraicType(), - }, - { - name: 'SubscribeMulti', - algebraicType: SubscribeMulti.getTypeScriptAlgebraicType(), - }, - { - name: 'Unsubscribe', - algebraicType: Unsubscribe.getTypeScriptAlgebraicType(), - }, - { - name: 'UnsubscribeMulti', - algebraicType: UnsubscribeMulti.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_ClientMessage_type_value) + return _cached_ClientMessage_type_value; + _cached_ClientMessage_type_value = __AlgebraicTypeValue.Sum({ + variants: [], }); + _cached_ClientMessage_type_value.value.variants.push( + { + name: 'CallReducer', + algebraicType: CallReducer.getTypeScriptAlgebraicType(), + }, + { + name: 'Subscribe', + algebraicType: Subscribe.getTypeScriptAlgebraicType(), + }, + { + name: 'OneOffQuery', + algebraicType: OneOffQuery.getTypeScriptAlgebraicType(), + }, + { + name: 'SubscribeSingle', + algebraicType: SubscribeSingle.getTypeScriptAlgebraicType(), + }, + { + name: 'SubscribeMulti', + algebraicType: SubscribeMulti.getTypeScriptAlgebraicType(), + }, + { + name: 'Unsubscribe', + algebraicType: Unsubscribe.getTypeScriptAlgebraicType(), + }, + { + name: 'UnsubscribeMulti', + algebraicType: UnsubscribeMulti.getTypeScriptAlgebraicType(), + } + ); + return _cached_ClientMessage_type_value; }, serialize(writer: __BinaryWriter, value: ClientMessage): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts b/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts index 006d5af19e9..65ec3b3f8eb 100644 --- a/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/compressable_query_update_type.ts @@ -39,6 +39,9 @@ export type CompressableQueryUpdate = | CompressableQueryUpdateVariants.Brotli | CompressableQueryUpdateVariants.Gzip; +let _cached_CompressableQueryUpdate_type_value: __AlgebraicTypeType | null = + null; + // A value with helper functions to construct the type. export const CompressableQueryUpdate = { // Helper functions for constructing each variant of the tagged union. @@ -47,36 +50,42 @@ export const CompressableQueryUpdate = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - Uncompressed: (value: QueryUpdate): CompressableQueryUpdate => ({ + Uncompressed: ( + value: QueryUpdate + ): CompressableQueryUpdateVariants.Uncompressed => ({ tag: 'Uncompressed', value, }), - Brotli: (value: Uint8Array): CompressableQueryUpdate => ({ + Brotli: (value: Uint8Array): CompressableQueryUpdateVariants.Brotli => ({ tag: 'Brotli', value, }), - Gzip: (value: Uint8Array): CompressableQueryUpdate => ({ + Gzip: (value: Uint8Array): CompressableQueryUpdateVariants.Gzip => ({ tag: 'Gzip', value, }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'Uncompressed', - algebraicType: QueryUpdate.getTypeScriptAlgebraicType(), - }, - { - name: 'Brotli', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - { - name: 'Gzip', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - ], + if (_cached_CompressableQueryUpdate_type_value) + return _cached_CompressableQueryUpdate_type_value; + _cached_CompressableQueryUpdate_type_value = __AlgebraicTypeValue.Sum({ + variants: [], }); + _cached_CompressableQueryUpdate_type_value.value.variants.push( + { + name: 'Uncompressed', + algebraicType: QueryUpdate.getTypeScriptAlgebraicType(), + }, + { + name: 'Brotli', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + }, + { + name: 'Gzip', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + } + ); + return _cached_CompressableQueryUpdate_type_value; }, serialize(writer: __BinaryWriter, value: CompressableQueryUpdate): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/database_update_type.ts b/crates/bindings-typescript/src/sdk/client_api/database_update_type.ts index df26b86e78d..45745374d29 100644 --- a/crates/bindings-typescript/src/sdk/client_api/database_update_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/database_update_type.ts @@ -34,6 +34,8 @@ declare type __keep_TableUpdate = TableUpdate; export type DatabaseUpdate = { tables: TableUpdate[]; }; +let _cached_DatabaseUpdate_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -43,16 +45,18 @@ export const DatabaseUpdate = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'tables', - algebraicType: __AlgebraicTypeValue.Array( - TableUpdate.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_DatabaseUpdate_type_value) + return _cached_DatabaseUpdate_type_value; + _cached_DatabaseUpdate_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_DatabaseUpdate_type_value.value.elements.push({ + name: 'tables', + algebraicType: __AlgebraicTypeValue.Array( + TableUpdate.getTypeScriptAlgebraicType() + ), }); + return _cached_DatabaseUpdate_type_value; }, serialize(writer: __BinaryWriter, value: DatabaseUpdate): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/energy_quanta_type.ts b/crates/bindings-typescript/src/sdk/client_api/energy_quanta_type.ts index cde22e44782..73ab3911e5c 100644 --- a/crates/bindings-typescript/src/sdk/client_api/energy_quanta_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/energy_quanta_type.ts @@ -31,6 +31,8 @@ import { export type EnergyQuanta = { quanta: bigint; }; +let _cached_EnergyQuanta_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -40,9 +42,15 @@ export const EnergyQuanta = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [{ name: 'quanta', algebraicType: __AlgebraicTypeValue.U128 }], + if (_cached_EnergyQuanta_type_value) return _cached_EnergyQuanta_type_value; + _cached_EnergyQuanta_type_value = __AlgebraicTypeValue.Product({ + elements: [], + }); + _cached_EnergyQuanta_type_value.value.elements.push({ + name: 'quanta', + algebraicType: __AlgebraicTypeValue.U128, }); + return _cached_EnergyQuanta_type_value; }, serialize(writer: __BinaryWriter, value: EnergyQuanta): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/identity_token_type.ts b/crates/bindings-typescript/src/sdk/client_api/identity_token_type.ts index fc9c31df25a..e92172030cd 100644 --- a/crates/bindings-typescript/src/sdk/client_api/identity_token_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/identity_token_type.ts @@ -33,6 +33,8 @@ export type IdentityToken = { token: string; connectionId: __ConnectionId; }; +let _cached_IdentityToken_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -42,19 +44,23 @@ export const IdentityToken = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'identity', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { name: 'token', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'connectionId', - algebraicType: __AlgebraicTypeValue.createConnectionIdType(), - }, - ], + if (_cached_IdentityToken_type_value) + return _cached_IdentityToken_type_value; + _cached_IdentityToken_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_IdentityToken_type_value.value.elements.push( + { + name: 'identity', + algebraicType: __AlgebraicTypeValue.createIdentityType(), + }, + { name: 'token', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'connectionId', + algebraicType: __AlgebraicTypeValue.createConnectionIdType(), + } + ); + return _cached_IdentityToken_type_value; }, serialize(writer: __BinaryWriter, value: IdentityToken): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/index.ts b/crates/bindings-typescript/src/sdk/client_api/index.ts index 7cc49d0f56d..5e3cc809133 100644 --- a/crates/bindings-typescript/src/sdk/client_api/index.ts +++ b/crates/bindings-typescript/src/sdk/client_api/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using ../../index cli version 1.5.0 (commit 3f65da1a72997e396bacaf5b2f58a7a9f0e1feeb). +// This was generated using ../../index cli version 1.5.0 (commit 5bfc84351742a6a8dc717b6c0011946f2d1b632d). /* eslint-disable */ /* tslint:disable */ diff --git a/crates/bindings-typescript/src/sdk/client_api/initial_subscription_type.ts b/crates/bindings-typescript/src/sdk/client_api/initial_subscription_type.ts index d9a26e185c5..26533c4e263 100644 --- a/crates/bindings-typescript/src/sdk/client_api/initial_subscription_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/initial_subscription_type.ts @@ -36,6 +36,8 @@ export type InitialSubscription = { requestId: number; totalHostExecutionDuration: __TimeDuration; }; +let _cached_InitialSubscription_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,19 +47,23 @@ export const InitialSubscription = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'databaseUpdate', - algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), - }, - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'totalHostExecutionDuration', - algebraicType: __AlgebraicTypeValue.createTimeDurationType(), - }, - ], + if (_cached_InitialSubscription_type_value) + return _cached_InitialSubscription_type_value; + _cached_InitialSubscription_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_InitialSubscription_type_value.value.elements.push( + { + name: 'databaseUpdate', + algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), + }, + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'totalHostExecutionDuration', + algebraicType: __AlgebraicTypeValue.createTimeDurationType(), + } + ); + return _cached_InitialSubscription_type_value; }, serialize(writer: __BinaryWriter, value: InitialSubscription): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/one_off_query_response_type.ts b/crates/bindings-typescript/src/sdk/client_api/one_off_query_response_type.ts index 0967c644f81..3e0dd287591 100644 --- a/crates/bindings-typescript/src/sdk/client_api/one_off_query_response_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/one_off_query_response_type.ts @@ -37,6 +37,8 @@ export type OneOffQueryResponse = { tables: OneOffTable[]; totalHostExecutionDuration: __TimeDuration; }; +let _cached_OneOffQueryResponse_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -46,30 +48,34 @@ export const OneOffQueryResponse = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'messageId', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - { - name: 'error', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.String - ), - }, - { - name: 'tables', - algebraicType: __AlgebraicTypeValue.Array( - OneOffTable.getTypeScriptAlgebraicType() - ), - }, - { - name: 'totalHostExecutionDuration', - algebraicType: __AlgebraicTypeValue.createTimeDurationType(), - }, - ], + if (_cached_OneOffQueryResponse_type_value) + return _cached_OneOffQueryResponse_type_value; + _cached_OneOffQueryResponse_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_OneOffQueryResponse_type_value.value.elements.push( + { + name: 'messageId', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + }, + { + name: 'error', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.String + ), + }, + { + name: 'tables', + algebraicType: __AlgebraicTypeValue.Array( + OneOffTable.getTypeScriptAlgebraicType() + ), + }, + { + name: 'totalHostExecutionDuration', + algebraicType: __AlgebraicTypeValue.createTimeDurationType(), + } + ); + return _cached_OneOffQueryResponse_type_value; }, serialize(writer: __BinaryWriter, value: OneOffQueryResponse): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/one_off_query_type.ts b/crates/bindings-typescript/src/sdk/client_api/one_off_query_type.ts index 5864f69c484..14ef4c02b90 100644 --- a/crates/bindings-typescript/src/sdk/client_api/one_off_query_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/one_off_query_type.ts @@ -32,6 +32,8 @@ export type OneOffQuery = { messageId: Uint8Array; queryString: string; }; +let _cached_OneOffQuery_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -41,15 +43,18 @@ export const OneOffQuery = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'messageId', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - { name: 'queryString', algebraicType: __AlgebraicTypeValue.String }, - ], + if (_cached_OneOffQuery_type_value) return _cached_OneOffQuery_type_value; + _cached_OneOffQuery_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_OneOffQuery_type_value.value.elements.push( + { + name: 'messageId', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + }, + { name: 'queryString', algebraicType: __AlgebraicTypeValue.String } + ); + return _cached_OneOffQuery_type_value; }, serialize(writer: __BinaryWriter, value: OneOffQuery): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/one_off_table_type.ts b/crates/bindings-typescript/src/sdk/client_api/one_off_table_type.ts index 945b073f2bd..9767f476433 100644 --- a/crates/bindings-typescript/src/sdk/client_api/one_off_table_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/one_off_table_type.ts @@ -35,6 +35,8 @@ export type OneOffTable = { tableName: string; rows: BsatnRowList; }; +let _cached_OneOffTable_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -44,15 +46,15 @@ export const OneOffTable = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'rows', - algebraicType: BsatnRowList.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_OneOffTable_type_value) return _cached_OneOffTable_type_value; + _cached_OneOffTable_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_OneOffTable_type_value.value.elements.push( + { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, + { name: 'rows', algebraicType: BsatnRowList.getTypeScriptAlgebraicType() } + ); + return _cached_OneOffTable_type_value; }, serialize(writer: __BinaryWriter, value: OneOffTable): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/query_id_type.ts b/crates/bindings-typescript/src/sdk/client_api/query_id_type.ts index 4426c0f4eb7..a2ffef60aad 100644 --- a/crates/bindings-typescript/src/sdk/client_api/query_id_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/query_id_type.ts @@ -31,6 +31,8 @@ import { export type QueryId = { id: number; }; +let _cached_QueryId_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -40,9 +42,13 @@ export const QueryId = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [{ name: 'id', algebraicType: __AlgebraicTypeValue.U32 }], + if (_cached_QueryId_type_value) return _cached_QueryId_type_value; + _cached_QueryId_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_QueryId_type_value.value.elements.push({ + name: 'id', + algebraicType: __AlgebraicTypeValue.U32, }); + return _cached_QueryId_type_value; }, serialize(writer: __BinaryWriter, value: QueryId): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/query_update_type.ts b/crates/bindings-typescript/src/sdk/client_api/query_update_type.ts index d27c2b0eeee..3523e9f5196 100644 --- a/crates/bindings-typescript/src/sdk/client_api/query_update_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/query_update_type.ts @@ -35,6 +35,8 @@ export type QueryUpdate = { deletes: BsatnRowList; inserts: BsatnRowList; }; +let _cached_QueryUpdate_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -44,18 +46,21 @@ export const QueryUpdate = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'deletes', - algebraicType: BsatnRowList.getTypeScriptAlgebraicType(), - }, - { - name: 'inserts', - algebraicType: BsatnRowList.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_QueryUpdate_type_value) return _cached_QueryUpdate_type_value; + _cached_QueryUpdate_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_QueryUpdate_type_value.value.elements.push( + { + name: 'deletes', + algebraicType: BsatnRowList.getTypeScriptAlgebraicType(), + }, + { + name: 'inserts', + algebraicType: BsatnRowList.getTypeScriptAlgebraicType(), + } + ); + return _cached_QueryUpdate_type_value; }, serialize(writer: __BinaryWriter, value: QueryUpdate): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/reducer_call_info_type.ts b/crates/bindings-typescript/src/sdk/client_api/reducer_call_info_type.ts index 462feb59735..ce37a59a355 100644 --- a/crates/bindings-typescript/src/sdk/client_api/reducer_call_info_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/reducer_call_info_type.ts @@ -34,6 +34,8 @@ export type ReducerCallInfo = { args: Uint8Array; requestId: number; }; +let _cached_ReducerCallInfo_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -43,17 +45,21 @@ export const ReducerCallInfo = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'reducerName', algebraicType: __AlgebraicTypeValue.String }, - { name: 'reducerId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'args', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), - }, - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - ], + if (_cached_ReducerCallInfo_type_value) + return _cached_ReducerCallInfo_type_value; + _cached_ReducerCallInfo_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_ReducerCallInfo_type_value.value.elements.push( + { name: 'reducerName', algebraicType: __AlgebraicTypeValue.String }, + { name: 'reducerId', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'args', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U8), + }, + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 } + ); + return _cached_ReducerCallInfo_type_value; }, serialize(writer: __BinaryWriter, value: ReducerCallInfo): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts b/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts index bc6a4aa7a03..345dbeefd25 100644 --- a/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/row_size_hint_type.ts @@ -34,6 +34,8 @@ export type RowSizeHint = | RowSizeHintVariants.FixedSize | RowSizeHintVariants.RowOffsets; +let _cached_RowSizeHint_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const RowSizeHint = { // Helper functions for constructing each variant of the tagged union. @@ -42,19 +44,26 @@ export const RowSizeHint = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - FixedSize: (value: number): RowSizeHint => ({ tag: 'FixedSize', value }), - RowOffsets: (value: bigint[]): RowSizeHint => ({ tag: 'RowOffsets', value }), + FixedSize: (value: number): RowSizeHintVariants.FixedSize => ({ + tag: 'FixedSize', + value, + }), + RowOffsets: (value: bigint[]): RowSizeHintVariants.RowOffsets => ({ + tag: 'RowOffsets', + value, + }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { name: 'FixedSize', algebraicType: __AlgebraicTypeValue.U16 }, - { - name: 'RowOffsets', - algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U64), - }, - ], - }); + if (_cached_RowSizeHint_type_value) return _cached_RowSizeHint_type_value; + _cached_RowSizeHint_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_RowSizeHint_type_value.value.variants.push( + { name: 'FixedSize', algebraicType: __AlgebraicTypeValue.U16 }, + { + name: 'RowOffsets', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.U64), + } + ); + return _cached_RowSizeHint_type_value; }, serialize(writer: __BinaryWriter, value: RowSizeHint): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts b/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts index 15ef1399a40..868a382da42 100644 --- a/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/server_message_type.ts @@ -73,6 +73,8 @@ export type ServerMessage = | ServerMessageVariants.SubscribeMultiApplied | ServerMessageVariants.UnsubscribeMultiApplied; +let _cached_ServerMessage_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const ServerMessage = { // Helper functions for constructing each variant of the tagged union. @@ -81,92 +83,113 @@ export const ServerMessage = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - InitialSubscription: (value: InitialSubscription): ServerMessage => ({ + InitialSubscription: ( + value: InitialSubscription + ): ServerMessageVariants.InitialSubscription => ({ tag: 'InitialSubscription', value, }), - TransactionUpdate: (value: TransactionUpdate): ServerMessage => ({ + TransactionUpdate: ( + value: TransactionUpdate + ): ServerMessageVariants.TransactionUpdate => ({ tag: 'TransactionUpdate', value, }), - TransactionUpdateLight: (value: TransactionUpdateLight): ServerMessage => ({ + TransactionUpdateLight: ( + value: TransactionUpdateLight + ): ServerMessageVariants.TransactionUpdateLight => ({ tag: 'TransactionUpdateLight', value, }), - IdentityToken: (value: IdentityToken): ServerMessage => ({ - tag: 'IdentityToken', - value, - }), - OneOffQueryResponse: (value: OneOffQueryResponse): ServerMessage => ({ + IdentityToken: ( + value: IdentityToken + ): ServerMessageVariants.IdentityToken => ({ tag: 'IdentityToken', value }), + OneOffQueryResponse: ( + value: OneOffQueryResponse + ): ServerMessageVariants.OneOffQueryResponse => ({ tag: 'OneOffQueryResponse', value, }), - SubscribeApplied: (value: SubscribeApplied): ServerMessage => ({ + SubscribeApplied: ( + value: SubscribeApplied + ): ServerMessageVariants.SubscribeApplied => ({ tag: 'SubscribeApplied', value, }), - UnsubscribeApplied: (value: UnsubscribeApplied): ServerMessage => ({ + UnsubscribeApplied: ( + value: UnsubscribeApplied + ): ServerMessageVariants.UnsubscribeApplied => ({ tag: 'UnsubscribeApplied', value, }), - SubscriptionError: (value: SubscriptionError): ServerMessage => ({ + SubscriptionError: ( + value: SubscriptionError + ): ServerMessageVariants.SubscriptionError => ({ tag: 'SubscriptionError', value, }), - SubscribeMultiApplied: (value: SubscribeMultiApplied): ServerMessage => ({ + SubscribeMultiApplied: ( + value: SubscribeMultiApplied + ): ServerMessageVariants.SubscribeMultiApplied => ({ tag: 'SubscribeMultiApplied', value, }), - UnsubscribeMultiApplied: (value: UnsubscribeMultiApplied): ServerMessage => ({ + UnsubscribeMultiApplied: ( + value: UnsubscribeMultiApplied + ): ServerMessageVariants.UnsubscribeMultiApplied => ({ tag: 'UnsubscribeMultiApplied', value, }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'InitialSubscription', - algebraicType: InitialSubscription.getTypeScriptAlgebraicType(), - }, - { - name: 'TransactionUpdate', - algebraicType: TransactionUpdate.getTypeScriptAlgebraicType(), - }, - { - name: 'TransactionUpdateLight', - algebraicType: TransactionUpdateLight.getTypeScriptAlgebraicType(), - }, - { - name: 'IdentityToken', - algebraicType: IdentityToken.getTypeScriptAlgebraicType(), - }, - { - name: 'OneOffQueryResponse', - algebraicType: OneOffQueryResponse.getTypeScriptAlgebraicType(), - }, - { - name: 'SubscribeApplied', - algebraicType: SubscribeApplied.getTypeScriptAlgebraicType(), - }, - { - name: 'UnsubscribeApplied', - algebraicType: UnsubscribeApplied.getTypeScriptAlgebraicType(), - }, - { - name: 'SubscriptionError', - algebraicType: SubscriptionError.getTypeScriptAlgebraicType(), - }, - { - name: 'SubscribeMultiApplied', - algebraicType: SubscribeMultiApplied.getTypeScriptAlgebraicType(), - }, - { - name: 'UnsubscribeMultiApplied', - algebraicType: UnsubscribeMultiApplied.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_ServerMessage_type_value) + return _cached_ServerMessage_type_value; + _cached_ServerMessage_type_value = __AlgebraicTypeValue.Sum({ + variants: [], }); + _cached_ServerMessage_type_value.value.variants.push( + { + name: 'InitialSubscription', + algebraicType: InitialSubscription.getTypeScriptAlgebraicType(), + }, + { + name: 'TransactionUpdate', + algebraicType: TransactionUpdate.getTypeScriptAlgebraicType(), + }, + { + name: 'TransactionUpdateLight', + algebraicType: TransactionUpdateLight.getTypeScriptAlgebraicType(), + }, + { + name: 'IdentityToken', + algebraicType: IdentityToken.getTypeScriptAlgebraicType(), + }, + { + name: 'OneOffQueryResponse', + algebraicType: OneOffQueryResponse.getTypeScriptAlgebraicType(), + }, + { + name: 'SubscribeApplied', + algebraicType: SubscribeApplied.getTypeScriptAlgebraicType(), + }, + { + name: 'UnsubscribeApplied', + algebraicType: UnsubscribeApplied.getTypeScriptAlgebraicType(), + }, + { + name: 'SubscriptionError', + algebraicType: SubscriptionError.getTypeScriptAlgebraicType(), + }, + { + name: 'SubscribeMultiApplied', + algebraicType: SubscribeMultiApplied.getTypeScriptAlgebraicType(), + }, + { + name: 'UnsubscribeMultiApplied', + algebraicType: UnsubscribeMultiApplied.getTypeScriptAlgebraicType(), + } + ); + return _cached_ServerMessage_type_value; }, serialize(writer: __BinaryWriter, value: ServerMessage): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/subscribe_applied_type.ts b/crates/bindings-typescript/src/sdk/client_api/subscribe_applied_type.ts index 210e842b98d..637b77472ea 100644 --- a/crates/bindings-typescript/src/sdk/client_api/subscribe_applied_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/subscribe_applied_type.ts @@ -40,6 +40,8 @@ export type SubscribeApplied = { queryId: QueryId; rows: SubscribeRows; }; +let _cached_SubscribeApplied_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -49,23 +51,24 @@ export const SubscribeApplied = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'totalHostExecutionDurationMicros', - algebraicType: __AlgebraicTypeValue.U64, - }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - { - name: 'rows', - algebraicType: SubscribeRows.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_SubscribeApplied_type_value) + return _cached_SubscribeApplied_type_value; + _cached_SubscribeApplied_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_SubscribeApplied_type_value.value.elements.push( + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'totalHostExecutionDurationMicros', + algebraicType: __AlgebraicTypeValue.U64, + }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() }, + { + name: 'rows', + algebraicType: SubscribeRows.getTypeScriptAlgebraicType(), + } + ); + return _cached_SubscribeApplied_type_value; }, serialize(writer: __BinaryWriter, value: SubscribeApplied): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_applied_type.ts b/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_applied_type.ts index 954c7e99175..c068eada2a5 100644 --- a/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_applied_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_applied_type.ts @@ -40,6 +40,8 @@ export type SubscribeMultiApplied = { queryId: QueryId; update: DatabaseUpdate; }; +let _cached_SubscribeMultiApplied_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -49,23 +51,24 @@ export const SubscribeMultiApplied = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'totalHostExecutionDurationMicros', - algebraicType: __AlgebraicTypeValue.U64, - }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - { - name: 'update', - algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_SubscribeMultiApplied_type_value) + return _cached_SubscribeMultiApplied_type_value; + _cached_SubscribeMultiApplied_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_SubscribeMultiApplied_type_value.value.elements.push( + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'totalHostExecutionDurationMicros', + algebraicType: __AlgebraicTypeValue.U64, + }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() }, + { + name: 'update', + algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), + } + ); + return _cached_SubscribeMultiApplied_type_value; }, serialize(writer: __BinaryWriter, value: SubscribeMultiApplied): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_type.ts b/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_type.ts index 54061fc1d66..34aad33a9a6 100644 --- a/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/subscribe_multi_type.ts @@ -36,6 +36,8 @@ export type SubscribeMulti = { requestId: number; queryId: QueryId; }; +let _cached_SubscribeMulti_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,21 +47,20 @@ export const SubscribeMulti = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'queryStrings', - algebraicType: __AlgebraicTypeValue.Array( - __AlgebraicTypeValue.String - ), - }, - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_SubscribeMulti_type_value) + return _cached_SubscribeMulti_type_value; + _cached_SubscribeMulti_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_SubscribeMulti_type_value.value.elements.push( + { + name: 'queryStrings', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.String), + }, + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() } + ); + return _cached_SubscribeMulti_type_value; }, serialize(writer: __BinaryWriter, value: SubscribeMulti): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/subscribe_rows_type.ts b/crates/bindings-typescript/src/sdk/client_api/subscribe_rows_type.ts index 929e30986de..ceb20dff46a 100644 --- a/crates/bindings-typescript/src/sdk/client_api/subscribe_rows_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/subscribe_rows_type.ts @@ -36,6 +36,8 @@ export type SubscribeRows = { tableName: string; tableRows: TableUpdate; }; +let _cached_SubscribeRows_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,16 +47,20 @@ export const SubscribeRows = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'tableId', algebraicType: __AlgebraicTypeValue.U32 }, - { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'tableRows', - algebraicType: TableUpdate.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_SubscribeRows_type_value) + return _cached_SubscribeRows_type_value; + _cached_SubscribeRows_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_SubscribeRows_type_value.value.elements.push( + { name: 'tableId', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'tableRows', + algebraicType: TableUpdate.getTypeScriptAlgebraicType(), + } + ); + return _cached_SubscribeRows_type_value; }, serialize(writer: __BinaryWriter, value: SubscribeRows): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/subscribe_single_type.ts b/crates/bindings-typescript/src/sdk/client_api/subscribe_single_type.ts index 500acd4c4aa..cb72b19fe54 100644 --- a/crates/bindings-typescript/src/sdk/client_api/subscribe_single_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/subscribe_single_type.ts @@ -36,6 +36,8 @@ export type SubscribeSingle = { requestId: number; queryId: QueryId; }; +let _cached_SubscribeSingle_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,16 +47,17 @@ export const SubscribeSingle = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'query', algebraicType: __AlgebraicTypeValue.String }, - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_SubscribeSingle_type_value) + return _cached_SubscribeSingle_type_value; + _cached_SubscribeSingle_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_SubscribeSingle_type_value.value.elements.push( + { name: 'query', algebraicType: __AlgebraicTypeValue.String }, + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() } + ); + return _cached_SubscribeSingle_type_value; }, serialize(writer: __BinaryWriter, value: SubscribeSingle): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/subscribe_type.ts b/crates/bindings-typescript/src/sdk/client_api/subscribe_type.ts index c5071aaeea9..da3b45b269d 100644 --- a/crates/bindings-typescript/src/sdk/client_api/subscribe_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/subscribe_type.ts @@ -32,6 +32,8 @@ export type Subscribe = { queryStrings: string[]; requestId: number; }; +let _cached_Subscribe_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -41,17 +43,18 @@ export const Subscribe = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'queryStrings', - algebraicType: __AlgebraicTypeValue.Array( - __AlgebraicTypeValue.String - ), - }, - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - ], + if (_cached_Subscribe_type_value) return _cached_Subscribe_type_value; + _cached_Subscribe_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_Subscribe_type_value.value.elements.push( + { + name: 'queryStrings', + algebraicType: __AlgebraicTypeValue.Array(__AlgebraicTypeValue.String), + }, + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 } + ); + return _cached_Subscribe_type_value; }, serialize(writer: __BinaryWriter, value: Subscribe): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/subscription_error_type.ts b/crates/bindings-typescript/src/sdk/client_api/subscription_error_type.ts index 1ed77cf31d8..2c1d3325dfd 100644 --- a/crates/bindings-typescript/src/sdk/client_api/subscription_error_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/subscription_error_type.ts @@ -35,6 +35,8 @@ export type SubscriptionError = { tableId: number | undefined; error: string; }; +let _cached_SubscriptionError_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -44,33 +46,37 @@ export const SubscriptionError = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'totalHostExecutionDurationMicros', - algebraicType: __AlgebraicTypeValue.U64, - }, - { - name: 'requestId', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.U32 - ), - }, - { - name: 'queryId', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.U32 - ), - }, - { - name: 'tableId', - algebraicType: __AlgebraicTypeValue.createOptionType( - __AlgebraicTypeValue.U32 - ), - }, - { name: 'error', algebraicType: __AlgebraicTypeValue.String }, - ], + if (_cached_SubscriptionError_type_value) + return _cached_SubscriptionError_type_value; + _cached_SubscriptionError_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_SubscriptionError_type_value.value.elements.push( + { + name: 'totalHostExecutionDurationMicros', + algebraicType: __AlgebraicTypeValue.U64, + }, + { + name: 'requestId', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.U32 + ), + }, + { + name: 'queryId', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.U32 + ), + }, + { + name: 'tableId', + algebraicType: __AlgebraicTypeValue.createOptionType( + __AlgebraicTypeValue.U32 + ), + }, + { name: 'error', algebraicType: __AlgebraicTypeValue.String } + ); + return _cached_SubscriptionError_type_value; }, serialize(writer: __BinaryWriter, value: SubscriptionError): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/table_update_type.ts b/crates/bindings-typescript/src/sdk/client_api/table_update_type.ts index da42438b4a0..1c195641522 100644 --- a/crates/bindings-typescript/src/sdk/client_api/table_update_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/table_update_type.ts @@ -37,6 +37,8 @@ export type TableUpdate = { numRows: bigint; updates: CompressableQueryUpdate[]; }; +let _cached_TableUpdate_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -46,19 +48,22 @@ export const TableUpdate = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'tableId', algebraicType: __AlgebraicTypeValue.U32 }, - { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, - { name: 'numRows', algebraicType: __AlgebraicTypeValue.U64 }, - { - name: 'updates', - algebraicType: __AlgebraicTypeValue.Array( - CompressableQueryUpdate.getTypeScriptAlgebraicType() - ), - }, - ], + if (_cached_TableUpdate_type_value) return _cached_TableUpdate_type_value; + _cached_TableUpdate_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_TableUpdate_type_value.value.elements.push( + { name: 'tableId', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'tableName', algebraicType: __AlgebraicTypeValue.String }, + { name: 'numRows', algebraicType: __AlgebraicTypeValue.U64 }, + { + name: 'updates', + algebraicType: __AlgebraicTypeValue.Array( + CompressableQueryUpdate.getTypeScriptAlgebraicType() + ), + } + ); + return _cached_TableUpdate_type_value; }, serialize(writer: __BinaryWriter, value: TableUpdate): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/transaction_update_light_type.ts b/crates/bindings-typescript/src/sdk/client_api/transaction_update_light_type.ts index c369c5a8888..24765e2b063 100644 --- a/crates/bindings-typescript/src/sdk/client_api/transaction_update_light_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/transaction_update_light_type.ts @@ -35,6 +35,9 @@ export type TransactionUpdateLight = { requestId: number; update: DatabaseUpdate; }; +let _cached_TransactionUpdateLight_type_value: __AlgebraicTypeType | null = + null; + /** * An object for generated helper functions. */ @@ -44,15 +47,19 @@ export const TransactionUpdateLight = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'update', - algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_TransactionUpdateLight_type_value) + return _cached_TransactionUpdateLight_type_value; + _cached_TransactionUpdateLight_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_TransactionUpdateLight_type_value.value.elements.push( + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'update', + algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), + } + ); + return _cached_TransactionUpdateLight_type_value; }, serialize(writer: __BinaryWriter, value: TransactionUpdateLight): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/transaction_update_type.ts b/crates/bindings-typescript/src/sdk/client_api/transaction_update_type.ts index a3d085093c5..8e8c08c5206 100644 --- a/crates/bindings-typescript/src/sdk/client_api/transaction_update_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/transaction_update_type.ts @@ -46,6 +46,8 @@ export type TransactionUpdate = { energyQuantaUsed: EnergyQuanta; totalHostExecutionDuration: __TimeDuration; }; +let _cached_TransactionUpdate_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -55,38 +57,42 @@ export const TransactionUpdate = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'status', - algebraicType: UpdateStatus.getTypeScriptAlgebraicType(), - }, - { - name: 'timestamp', - algebraicType: __AlgebraicTypeValue.createTimestampType(), - }, - { - name: 'callerIdentity', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { - name: 'callerConnectionId', - algebraicType: __AlgebraicTypeValue.createConnectionIdType(), - }, - { - name: 'reducerCall', - algebraicType: ReducerCallInfo.getTypeScriptAlgebraicType(), - }, - { - name: 'energyQuantaUsed', - algebraicType: EnergyQuanta.getTypeScriptAlgebraicType(), - }, - { - name: 'totalHostExecutionDuration', - algebraicType: __AlgebraicTypeValue.createTimeDurationType(), - }, - ], + if (_cached_TransactionUpdate_type_value) + return _cached_TransactionUpdate_type_value; + _cached_TransactionUpdate_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_TransactionUpdate_type_value.value.elements.push( + { + name: 'status', + algebraicType: UpdateStatus.getTypeScriptAlgebraicType(), + }, + { + name: 'timestamp', + algebraicType: __AlgebraicTypeValue.createTimestampType(), + }, + { + name: 'callerIdentity', + algebraicType: __AlgebraicTypeValue.createIdentityType(), + }, + { + name: 'callerConnectionId', + algebraicType: __AlgebraicTypeValue.createConnectionIdType(), + }, + { + name: 'reducerCall', + algebraicType: ReducerCallInfo.getTypeScriptAlgebraicType(), + }, + { + name: 'energyQuantaUsed', + algebraicType: EnergyQuanta.getTypeScriptAlgebraicType(), + }, + { + name: 'totalHostExecutionDuration', + algebraicType: __AlgebraicTypeValue.createTimeDurationType(), + } + ); + return _cached_TransactionUpdate_type_value; }, serialize(writer: __BinaryWriter, value: TransactionUpdate): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_applied_type.ts b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_applied_type.ts index ac9cb54f071..e40f9d5ecf6 100644 --- a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_applied_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_applied_type.ts @@ -40,6 +40,8 @@ export type UnsubscribeApplied = { queryId: QueryId; rows: SubscribeRows; }; +let _cached_UnsubscribeApplied_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -49,23 +51,24 @@ export const UnsubscribeApplied = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'totalHostExecutionDurationMicros', - algebraicType: __AlgebraicTypeValue.U64, - }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - { - name: 'rows', - algebraicType: SubscribeRows.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_UnsubscribeApplied_type_value) + return _cached_UnsubscribeApplied_type_value; + _cached_UnsubscribeApplied_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_UnsubscribeApplied_type_value.value.elements.push( + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'totalHostExecutionDurationMicros', + algebraicType: __AlgebraicTypeValue.U64, + }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() }, + { + name: 'rows', + algebraicType: SubscribeRows.getTypeScriptAlgebraicType(), + } + ); + return _cached_UnsubscribeApplied_type_value; }, serialize(writer: __BinaryWriter, value: UnsubscribeApplied): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_applied_type.ts b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_applied_type.ts index 3c6be11266b..d3cc7eba1f1 100644 --- a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_applied_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_applied_type.ts @@ -40,6 +40,9 @@ export type UnsubscribeMultiApplied = { queryId: QueryId; update: DatabaseUpdate; }; +let _cached_UnsubscribeMultiApplied_type_value: __AlgebraicTypeType | null = + null; + /** * An object for generated helper functions. */ @@ -49,23 +52,24 @@ export const UnsubscribeMultiApplied = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'totalHostExecutionDurationMicros', - algebraicType: __AlgebraicTypeValue.U64, - }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - { - name: 'update', - algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_UnsubscribeMultiApplied_type_value) + return _cached_UnsubscribeMultiApplied_type_value; + _cached_UnsubscribeMultiApplied_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_UnsubscribeMultiApplied_type_value.value.elements.push( + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { + name: 'totalHostExecutionDurationMicros', + algebraicType: __AlgebraicTypeValue.U64, + }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() }, + { + name: 'update', + algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), + } + ); + return _cached_UnsubscribeMultiApplied_type_value; }, serialize(writer: __BinaryWriter, value: UnsubscribeMultiApplied): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_type.ts b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_type.ts index c8331bfea34..64279e511ff 100644 --- a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_multi_type.ts @@ -35,6 +35,8 @@ export type UnsubscribeMulti = { requestId: number; queryId: QueryId; }; +let _cached_UnsubscribeMulti_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -44,15 +46,16 @@ export const UnsubscribeMulti = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_UnsubscribeMulti_type_value) + return _cached_UnsubscribeMulti_type_value; + _cached_UnsubscribeMulti_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_UnsubscribeMulti_type_value.value.elements.push( + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() } + ); + return _cached_UnsubscribeMulti_type_value; }, serialize(writer: __BinaryWriter, value: UnsubscribeMulti): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_type.ts b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_type.ts index 7eb80eedc5c..d8d55cfd897 100644 --- a/crates/bindings-typescript/src/sdk/client_api/unsubscribe_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/unsubscribe_type.ts @@ -35,6 +35,8 @@ export type Unsubscribe = { requestId: number; queryId: QueryId; }; +let _cached_Unsubscribe_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -44,15 +46,15 @@ export const Unsubscribe = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, - { - name: 'queryId', - algebraicType: QueryId.getTypeScriptAlgebraicType(), - }, - ], + if (_cached_Unsubscribe_type_value) return _cached_Unsubscribe_type_value; + _cached_Unsubscribe_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_Unsubscribe_type_value.value.elements.push( + { name: 'requestId', algebraicType: __AlgebraicTypeValue.U32 }, + { name: 'queryId', algebraicType: QueryId.getTypeScriptAlgebraicType() } + ); + return _cached_Unsubscribe_type_value; }, serialize(writer: __BinaryWriter, value: Unsubscribe): void { diff --git a/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts b/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts index a2e9961b8dd..ca9022ea5db 100644 --- a/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts +++ b/crates/bindings-typescript/src/sdk/client_api/update_status_type.ts @@ -39,6 +39,8 @@ export type UpdateStatus = | UpdateStatusVariants.Failed | UpdateStatusVariants.OutOfEnergy; +let _cached_UpdateStatus_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const UpdateStatus = { // Helper functions for constructing each variant of the tagged union. @@ -47,27 +49,33 @@ export const UpdateStatus = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - Committed: (value: DatabaseUpdate): UpdateStatus => ({ + Committed: (value: DatabaseUpdate): UpdateStatusVariants.Committed => ({ tag: 'Committed', value, }), - Failed: (value: string): UpdateStatus => ({ tag: 'Failed', value }), + Failed: (value: string): UpdateStatusVariants.Failed => ({ + tag: 'Failed', + value, + }), OutOfEnergy: { tag: 'OutOfEnergy' } as const, getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { - name: 'Committed', - algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), - }, - { name: 'Failed', algebraicType: __AlgebraicTypeValue.String }, - { - name: 'OutOfEnergy', - algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), - }, - ], + if (_cached_UpdateStatus_type_value) return _cached_UpdateStatus_type_value; + _cached_UpdateStatus_type_value = __AlgebraicTypeValue.Sum({ + variants: [], }); + _cached_UpdateStatus_type_value.value.variants.push( + { + name: 'Committed', + algebraicType: DatabaseUpdate.getTypeScriptAlgebraicType(), + }, + { name: 'Failed', algebraicType: __AlgebraicTypeValue.String }, + { + name: 'OutOfEnergy', + algebraicType: __AlgebraicTypeValue.Product({ elements: [] }), + } + ); + return _cached_UpdateStatus_type_value; }, serialize(writer: __BinaryWriter, value: UpdateStatus): void { diff --git a/crates/bindings-typescript/src/sdk/db_connection_impl.ts b/crates/bindings-typescript/src/sdk/db_connection_impl.ts index f483848c83c..b8a2639c705 100644 --- a/crates/bindings-typescript/src/sdk/db_connection_impl.ts +++ b/crates/bindings-typescript/src/sdk/db_connection_impl.ts @@ -302,8 +302,7 @@ export class DbConnectionImpl< const rowType = this.#remoteModule.tables[tableName]!.rowType; const primaryKeyInfo = this.#remoteModule.tables[tableName]!.primaryKeyInfo; - while (reader.offset < buffer.length + buffer.byteOffset) { - const initialOffset = reader.offset; + while (reader.remaining > 0) { const row = AlgebraicType.deserializeValue(reader, rowType); let rowId: ComparablePrimitive | undefined = undefined; if (primaryKeyInfo !== undefined) { @@ -313,10 +312,7 @@ export class DbConnectionImpl< ); } else { // Get a view of the bytes for this row. - const rowBytes = buffer.subarray( - initialOffset - buffer.byteOffset, - reader.offset - buffer.byteOffset - ); + const rowBytes = buffer.subarray(0, reader.offset); // Convert it to a base64 string, so we can use it as a map key. const asBase64 = fromByteArray(rowBytes); rowId = asBase64; diff --git a/crates/bindings-typescript/src/server/constraints.ts b/crates/bindings-typescript/src/server/constraints.ts new file mode 100644 index 00000000000..4301137281f --- /dev/null +++ b/crates/bindings-typescript/src/server/constraints.ts @@ -0,0 +1,39 @@ +import type { UntypedTableDef } from './table'; +import type { ColumnMetadata } from './type_builders'; + +/** + * A helper type to determine if all columns in an index are unique. + */ +export type AllUnique< + TableDef extends UntypedTableDef, + Columns extends Array, +> = { + [i in keyof Columns]: ColumnIsUnique< + TableDef['columns'][Columns[i]]['columnMetadata'] + >; +} extends true[] + ? true + : false; + +/** + * A helper type to determine if a column is unique based on its metadata. + * A column is considered unique if it has either `isUnique` or `isPrimaryKey` set to true in its metadata. + * @template M - The column metadata to check. + * @returns `true` if the column is unique, otherwise `false`. + * @example + * ```typescript + * type Meta1 = { isUnique: true }; + * type Meta2 = { isPrimaryKey: true }; + * type Meta3 = { isUnique: false }; + * type Meta4 = {}; + * type Result1 = ColumnIsUnique; // true + * type Result2 = ColumnIsUnique; // true + * type Result3 = ColumnIsUnique; // false + * type Result4 = ColumnIsUnique; // false + * ``` + */ +export type ColumnIsUnique> = M extends + | { isUnique: true } + | { isPrimaryKey: true } + ? true + : false; diff --git a/crates/bindings-typescript/src/server/errors.ts b/crates/bindings-typescript/src/server/errors.ts new file mode 100644 index 00000000000..845acfd1659 --- /dev/null +++ b/crates/bindings-typescript/src/server/errors.ts @@ -0,0 +1,245 @@ +/** + * Base class for all Spacetime host errors (i.e. errors that may be thrown + * by database functions). + * + * Instances of SpacetimeError can be created with just an error code, + * which will return the appropriate subclass instance. + */ +export class SpacetimeHostError extends Error { + public readonly code: number; + public readonly message: string; + constructor(code: number) { + super(); + const proto = Object.getPrototypeOf(this); + let cls; + if (errorProtoypes.has(proto)) { + cls = proto.constructor; + if (code !== cls.CODE) + throw new TypeError(`invalid error code for ${cls.name}`); + } else if (proto === SpacetimeHostError.prototype) { + cls = errnoToClass.get(code); + if (!cls) throw new RangeError(`unknown error code ${code}`); + } else { + throw new TypeError('cannot subclass SpacetimeError'); + } + Object.setPrototypeOf(this, cls.prototype); + this.code = cls.CODE; + this.message = cls.MESSAGE; + } + get name(): string { + return errnoToClass.get(this.code)?.name ?? 'SpacetimeHostError'; + } +} + +/** + * An error thrown by a reducer that indicates a problem to the sender. + * + * When this error is thrown by a reducer, the sender will be notified + * that the reducer failed gracefully with the given message. + */ +export class SenderError extends Error { + constructor(message: string) { + super(message); + } + get name() { + return 'SenderError'; + } +} + +/** + * A generic error class for unknown error codes. + */ +export class HostCallFailure extends SpacetimeHostError { + static CODE = 1; + static MESSAGE = 'ABI called by host returned an error'; + constructor() { + super(HostCallFailure.CODE); + } +} + +/** + * Error indicating that an ABI call was made outside of a transaction. + */ +export class NotInTransaction extends SpacetimeHostError { + static CODE = 2; + static MESSAGE = 'ABI call can only be made while in a transaction'; + constructor() { + super(NotInTransaction.CODE); + } +} + +/** + * Error indicating that BSATN decoding failed. + * This typically means that the data could not be decoded to the expected type. + */ +export class BsatnDecodeError extends SpacetimeHostError { + static CODE = 3; + static MESSAGE = "Couldn't decode the BSATN to the expected type"; + constructor() { + super(BsatnDecodeError.CODE); + } +} + +/** + * Error indicating that a specified table does not exist. + */ +export class NoSuchTable extends SpacetimeHostError { + static CODE = 4; + static MESSAGE = 'No such table'; + constructor() { + super(NoSuchTable.CODE); + } +} + +/** + * Error indicating that a specified index does not exist. + */ +export class NoSuchIndex extends SpacetimeHostError { + static CODE = 5; + static MESSAGE = 'No such index'; + constructor() { + super(NoSuchIndex.CODE); + } +} + +/** + * Error indicating that a specified row iterator is not valid. + */ +export class NoSuchIter extends SpacetimeHostError { + static CODE = 6; + static MESSAGE = 'The provided row iterator is not valid'; + constructor() { + super(NoSuchIter.CODE); + } +} + +/** + * Error indicating that a specified console timer does not exist. + */ +export class NoSuchConsoleTimer extends SpacetimeHostError { + static CODE = 7; + static MESSAGE = 'The provided console timer does not exist'; + constructor() { + super(NoSuchConsoleTimer.CODE); + } +} + +/** + * Error indicating that a specified bytes source or sink is not valid. + */ +export class NoSuchBytes extends SpacetimeHostError { + static CODE = 8; + static MESSAGE = 'The provided bytes source or sink is not valid'; + constructor() { + super(NoSuchBytes.CODE); + } +} + +/** + * Error indicating that a provided sink has no more space left. + */ +export class NoSpace extends SpacetimeHostError { + static CODE = 9; + static MESSAGE = 'The provided sink has no more space left'; + constructor() { + super(NoSpace.CODE); + } +} + +/** + * Error indicating that there is no more space in the database. + */ +export class BufferTooSmall extends SpacetimeHostError { + static CODE = 11; + static MESSAGE = 'The provided buffer is not large enough to store the data'; + constructor() { + super(BufferTooSmall.CODE); + } +} + +/** + * Error indicating that a value with a given unique identifier already exists. + */ +export class UniqueAlreadyExists extends SpacetimeHostError { + static CODE = 12; + static MESSAGE = 'Value with given unique identifier already exists'; + constructor() { + super(UniqueAlreadyExists.CODE); + } +} + +/** + * Error indicating that the specified delay in scheduling a row was too long. + */ +export class ScheduleAtDelayTooLong extends SpacetimeHostError { + static CODE = 13; + static MESSAGE = 'Specified delay in scheduling row was too long'; + constructor() { + super(ScheduleAtDelayTooLong.CODE); + } +} + +/** + * Error indicating that an index was not unique when it was expected to be. + */ +export class IndexNotUnique extends SpacetimeHostError { + static CODE = 14; + static MESSAGE = 'The index was not unique'; + constructor() { + super(IndexNotUnique.CODE); + } +} + +/** + * Error indicating that an index was not unique when it was expected to be. + */ +export class NoSuchRow extends SpacetimeHostError { + static CODE = 15; + static MESSAGE = 'The row was not found, e.g., in an update call'; + constructor() { + super(NoSuchRow.CODE); + } +} + +/** + * Error indicating that an auto-increment sequence has overflowed. + */ +export class AutoIncOverflow extends SpacetimeHostError { + static CODE = 16; + static MESSAGE = 'The auto-increment sequence overflowed'; + constructor() { + super(AutoIncOverflow.CODE); + } +} + +/** + * List of all SpacetimeError subclasses. + */ +const errorSubclasses = [ + HostCallFailure, + NotInTransaction, + BsatnDecodeError, + NoSuchTable, + NoSuchIndex, + NoSuchIter, + NoSuchConsoleTimer, + NoSuchBytes, + NoSpace, + BufferTooSmall, + UniqueAlreadyExists, + ScheduleAtDelayTooLong, + IndexNotUnique, + NoSuchRow, +]; + +/** + * Set of prototypes of all SpacetimeError subclasses for quick lookup. + */ +const errorProtoypes = new Set(errorSubclasses.map(cls => cls.prototype)); + +/** + * Map from error codes to their corresponding SpacetimeError subclass. + */ +const errnoToClass = new Map( + errorSubclasses.map(cls => [cls.CODE as number, cls]) +); diff --git a/crates/bindings-typescript/src/server/index.ts b/crates/bindings-typescript/src/server/index.ts index 2c4f2d7bedd..b99732ce995 100644 --- a/crates/bindings-typescript/src/server/index.ts +++ b/crates/bindings-typescript/src/server/index.ts @@ -1,2 +1,8 @@ export * from './type_builders'; -export * from './type_util'; +export { schema } from './schema'; +export { table } from './table'; +export * as errors from './errors'; +export { SenderError } from './errors'; + +import './polyfills'; // Ensure polyfills are loaded +import './register_hooks'; // Ensure module hooks are registered diff --git a/crates/bindings-typescript/src/server/indexes.ts b/crates/bindings-typescript/src/server/indexes.ts new file mode 100644 index 00000000000..7af552012f6 --- /dev/null +++ b/crates/bindings-typescript/src/server/indexes.ts @@ -0,0 +1,153 @@ +import type { RowType, UntypedTableDef } from './table'; +import type { ColumnMetadata, IndexTypes } from './type_builders'; +import type { CollapseTuple, Prettify } from './type_util'; +import { Range } from './range'; +import type { ColumnIsUnique } from './constraints'; + +/** + * Index helper type used *inside* {@link table} to enforce that only + * existing column names are referenced. + */ +export type IndexOpts = { + name?: string; +} & ( + | { algorithm: 'btree'; columns: readonly AllowedCol[] } + | { algorithm: 'direct'; column: AllowedCol } +); + +/** + * An untyped representation of an index definition. + */ +type UntypedIndex = { + name: string; + unique: boolean; + algorithm: 'btree' | 'direct'; + columns: AllowedCol[]; +}; + +/** + * A helper type to extract the column names from an index definition. + */ +export type IndexColumns> = I extends { + columns: string[]; +} + ? I['columns'] + : I extends { column: string } + ? [I['column']] + : never; + +/** + * A type representing the indexes defined on a table. + */ +export type Indexes< + TableDef extends UntypedTableDef, + I extends Record>, +> = { + [k in keyof I]: Index; +}; + +/** + * A type representing a database index, which can be either unique or ranged. + */ +export type Index< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = I['unique'] extends true + ? UniqueIndex + : RangedIndex; + +/** + * A type representing a unique index on a database table. + * Unique indexes enforce that the indexed columns contain unique values. + */ +export type UniqueIndex< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = { + find(col_val: IndexVal): RowType | null; + delete(col_val: IndexVal): boolean; + update(col_val: RowType): RowType; +}; + +/** + * A type representing a ranged index on a database table. + * Ranged indexes allow for range queries on the indexed columns. + */ +export type RangedIndex< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = { + filter( + range: IndexScanRangeBounds + ): IterableIterator>; + delete(range: IndexScanRangeBounds): number; +}; + +/** + * A helper type to extract the value type of an index based on the table definition and index definition. + * This type constructs a tuple of the types of the columns that make up the index. + */ +export type IndexVal< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = CollapseTuple<_IndexVal>; + +/** + * A helper type to extract the types of the columns that make up an index. + */ +type _IndexVal = { + [i in keyof Columns]: TableDef['columns'][Columns[i]]['typeBuilder']['type']; +}; + +/** + * A helper type to define the bounds for scanning an index. + * This type allows for specifying exact values or ranges for each column in the index. + * It supports omitting trailing columns if the index is multi-column. + */ +export type IndexScanRangeBounds< + TableDef extends UntypedTableDef, + I extends UntypedIndex, +> = _IndexScanRangeBounds<_IndexVal>; + +/** + * A helper type to define the bounds for scanning an index. + * This type allows for specifying exact values or ranges for each column in the index. + * It supports omitting trailing columns if the index is multi-column. + * This version only allows omitting the array if the index is single-column to avoid ambiguity. + */ +type _IndexScanRangeBounds = Columns extends [infer Term] + ? Term | Range + : _IndexScanRangeBoundsCase; + +/** + * A helper type to define the bounds for scanning an index. + * This type allows for specifying exact values or ranges for each column in the index. + * It supports omitting trailing columns if the index is multi-column. + */ +type _IndexScanRangeBoundsCase = Columns extends [ + ...infer Prefix, + infer Term, +] + ? [...Prefix, Term | Range] | _IndexScanRangeBounds + : never; + +/** + * A helper type representing a column index definition. + */ +export type ColumnIndex< + Name extends string, + M extends ColumnMetadata, +> = Prettify< + { + name: Name; + unique: ColumnIsUnique; + columns: [Name]; + algorithm: 'btree' | 'direct'; + } & (M extends { + indexType: infer I extends NonNullable; + } + ? { algorithm: I } + : ColumnIsUnique extends true + ? { algorithm: 'btree' } + : never) +>; diff --git a/crates/bindings-typescript/src/server/polyfills.ts b/crates/bindings-typescript/src/server/polyfills.ts new file mode 100644 index 00000000000..c6ba5bae56e --- /dev/null +++ b/crates/bindings-typescript/src/server/polyfills.ts @@ -0,0 +1 @@ +import 'fast-text-encoding'; diff --git a/crates/bindings-typescript/src/server/range.ts b/crates/bindings-typescript/src/server/range.ts new file mode 100644 index 00000000000..38c3277ea41 --- /dev/null +++ b/crates/bindings-typescript/src/server/range.ts @@ -0,0 +1,53 @@ +/** + * A class representing a range with optional lower and upper bounds. + * This class is used to specify ranges for index scans in SpacetimeDB. + * + * The range can be defined with inclusive or exclusive bounds, or can be unbounded on either side. + * @template T - The type of the values in the range. + * @example + * ```typescript + * // Create a range from 10 (inclusive) to 20 (exclusive) + * const range = new Range( + * { tag: 'included', value: 10 }, + * { tag: 'excluded', value: 20 } + * ); + * // Create an unbounded range + * const unboundedRange = new Range(); + * ``` + */ +export class Range { + #from: Bound; + #to: Bound; + public constructor(from?: Bound | null, to?: Bound | null) { + this.#from = from ?? { tag: 'unbounded' }; + this.#to = to ?? { tag: 'unbounded' }; + } + + public get from(): Bound { + return this.#from; + } + public get to(): Bound { + return this.#to; + } +} + +/** + * A type representing a bound in a range, which can be inclusive, exclusive, or unbounded. + * - `included`: The bound is inclusive, meaning the value is part of the range. + * - `excluded`: The bound is exclusive, meaning the value is not part of the range. + * - `unbounded`: The bound is unbounded, meaning there is no limit in that direction. + * @template T - The type of the value for the bound. + * @example + * ```typescript + * // Inclusive bound + * const inclusiveBound: Bound = { tag: 'included', value: 10 }; + * // Exclusive bound + * const exclusiveBound: Bound = { tag: 'excluded', value: 20 }; + * // Unbounded bound + * const unbounded: Bound = { tag: 'unbounded' }; + * ``` + */ +export type Bound = + | { tag: 'included'; value: T } + | { tag: 'excluded'; value: T } + | { tag: 'unbounded' }; diff --git a/crates/bindings-typescript/src/server/reducers.ts b/crates/bindings-typescript/src/server/reducers.ts new file mode 100644 index 00000000000..55470756b71 --- /dev/null +++ b/crates/bindings-typescript/src/server/reducers.ts @@ -0,0 +1,221 @@ +import type { ProductType } from '../lib/algebraic_type'; +import Lifecycle from '../lib/autogen/lifecycle_type'; +import type RawReducerDefV9 from '../lib/autogen/raw_reducer_def_v_9_type'; +import type { ConnectionId } from '../lib/connection_id'; +import type { Identity } from '../lib/identity'; +import type { Timestamp } from '../lib/timestamp'; +import { MODULE_DEF, type UntypedSchemaDef } from './schema'; +import type { Table } from './table'; +import type { + InferTypeOfRow, + RowBuilder, + RowObj, + TypeBuilder, +} from './type_builders'; + +/** + * Helper to extract the parameter types from an object type + */ +export type ParamsObj = Record>; + +/** + * Helper to convert a ParamsObj or RowObj into an object type + */ +type ParamsAsObject = + InferTypeOfRow; + +/** + * Defines a SpacetimeDB reducer function. + * Reducers are the primary way to modify the state of your SpacetimeDB application. + * They are atomic, meaning that either all operations within a reducer succeed, + * or none of them do. + * @template S - The inferred schema type of the SpacetimeDB module. + * @template Params - The type of the parameters object expected by the reducer. + * @param ctx - The reducer context, providing access to `sender`, `timestamp`, `connection_id`, and `db`. + * @param payload - An object containing the arguments passed to the reducer, typed according to `params`. + * @example + * ```typescript + * // Define a reducer named 'create_user' that takes 'username' (string) and 'email' (string) + * reducer( + * 'create_user', + * { + * username: t.string(), + * email: t.string(), + * }, + * (ctx, { username, email }) => { + * // Access the 'user' table from the database view in the context + * ctx.db.user.insert({ username, email, created_at: ctx.timestamp }); + * console.log(`User ${username} created by ${ctx.sender.identityId}`); + * } + * ); + * ``` + */ +export type Reducer< + S extends UntypedSchemaDef, + Params extends ParamsObj | RowObj, +> = ( + ctx: ReducerCtx, + payload: ParamsAsObject +) => void | { tag: 'ok' } | { tag: 'err'; value: string }; + +/** + * A type representing the database view, mapping table names to their corresponding Table handles. + */ +export type DbView = { + readonly [Tbl in SchemaDef['tables'][number] as Tbl['name']]: Table; +}; + +/** + * Reducer context parametrized by the inferred Schema + */ +export type ReducerCtx = Readonly<{ + sender: Identity; + identity: Identity; + timestamp: Timestamp; + connectionId: ConnectionId | null; + db: DbView; +}>; + +/** + * internal: pushReducer() helper used by reducer() and lifecycle wrappers + * + * @param name - The name of the reducer. + * @param params - The parameters for the reducer. + * @param fn - The reducer function. + * @param lifecycle - Optional lifecycle hooks for the reducer. + */ +export function pushReducer( + name: string, + params: RowObj | RowBuilder, + fn: Reducer, + lifecycle?: RawReducerDefV9['lifecycle'] +): void { + if (existingReducers.has(name)) + throw new TypeError(`There is already a reducer with the name '${name}'`); + existingReducers.add(name); + + const paramType: ProductType = { + elements: Object.entries(params).map(([n, c]) => ({ + name: n, + algebraicType: ('typeBuilder' in c ? c.typeBuilder : c).algebraicType, + })), + }; + + MODULE_DEF.reducers.push({ + name, + params: paramType, + lifecycle, // <- lifecycle flag lands here + }); + + REDUCERS.push(fn); +} + +const existingReducers = new Set(); +export const REDUCERS: Reducer[] = []; + +/** + * Defines a SpacetimeDB reducer function. + * + * Reducers are the primary way to modify the state of your SpacetimeDB application. + * They are atomic, meaning that either all operations within a reducer succeed, + * or none of them do. + * + * @template S - The inferred schema type of the SpacetimeDB module. + * @template Params - The type of the parameters object expected by the reducer. + * + * @param {string} name - The name of the reducer. This name will be used to call the reducer from clients. + * @param {Params} params - An object defining the parameters that the reducer accepts. + * Each key-value pair represents a parameter name and its corresponding + * {@link TypeBuilder} or {@link ColumnBuilder}. + * @param {(ctx: ReducerCtx, payload: ParamsAsObject) => void} fn - The reducer function itself. + * - `ctx`: The reducer context, providing access to `sender`, `timestamp`, `connection_id`, and `db`. + * - `payload`: An object containing the arguments passed to the reducer, typed according to `params`. + * + * @example + * ```typescript + * // Define a reducer named 'create_user' that takes 'username' (string) and 'email' (string) + * reducer( + * 'create_user', + * { + * username: t.string(), + * email: t.string(), + * }, + * (ctx, { username, email }) => { + * // Access the 'user' table from the database view in the context + * ctx.db.user.insert({ username, email, created_at: ctx.timestamp }); + * console.log(`User ${username} created by ${ctx.sender.identityId}`); + * } + * ); + * ``` + */ +export function reducer< + S extends UntypedSchemaDef, + Params extends ParamsObj | RowObj, +>( + name: string, + params: Params, + fn: (ctx: ReducerCtx, payload: ParamsAsObject) => void +): void { + pushReducer(name, params, fn); +} + +/** + * Registers an initialization reducer that runs when the SpacetimeDB module is published + * for the first time. + * This function is useful to set up any initial state of your database that is guaranteed + * to run only once, and before any other reducers or client connections. + * @template S - The inferred schema type of the SpacetimeDB module. + * @template Params - The type of the parameters object expected by the initialization reducer. + * + * @param params - The parameters object defining the expected input for the initialization reducer. + * @param fn - The initialization reducer function. + * - `ctx`: The reducer context, providing access to `sender`, `timestamp`, `connection_id`, and `db`. + */ +export function init( + params: Params, + fn: Reducer +): void { + pushReducer('init', params, fn, Lifecycle.Init); +} + +/** + * Registers a reducer to be called when a client connects to the SpacetimeDB module. + * This function allows you to define custom logic that should execute + * whenever a new client establishes a connection. + * @template S - The inferred schema type of the SpacetimeDB module. + * @template Params - The type of the parameters object expected by the connection reducer. + * @param params - The parameters object defining the expected input for the connection reducer. + * @param fn - The connection reducer function itself. + */ +export function clientConnected< + S extends UntypedSchemaDef, + Params extends ParamsObj, +>(params: Params, fn: Reducer): void { + pushReducer('on_connect', params, fn, Lifecycle.OnConnect); +} + +/** + * Registers a reducer to be called when a client disconnects from the SpacetimeDB module. + * This function allows you to define custom logic that should execute + * whenever a client disconnects. + * + * @template S - The inferred schema type of the SpacetimeDB module. + * @template Params - The type of the parameters object expected by the disconnection reducer. + * @param params - The parameters object defining the expected input for the disconnection reducer. + * @param fn - The disconnection reducer function itself. + * @example + * ```typescript + * spacetime.clientDisconnected( + * { reason: t.string() }, + * (ctx, { reason }) => { + * console.log(`Client ${ctx.connection_id} disconnected: ${reason}`); + * } + * ); + * ``` + */ +export function clientDisconnected< + S extends UntypedSchemaDef, + Params extends ParamsObj, +>(params: Params, fn: Reducer): void { + pushReducer('on_disconnect', params, fn, Lifecycle.OnDisconnect); +} diff --git a/crates/bindings-typescript/src/server/register_hooks.ts b/crates/bindings-typescript/src/server/register_hooks.ts new file mode 100644 index 00000000000..4ebee6df628 --- /dev/null +++ b/crates/bindings-typescript/src/server/register_hooks.ts @@ -0,0 +1,4 @@ +import { register_hooks } from 'spacetime:sys@1.0'; +import { hooks } from './runtime'; + +register_hooks(hooks); diff --git a/crates/bindings-typescript/src/server/runtime.ts b/crates/bindings-typescript/src/server/runtime.ts new file mode 100644 index 00000000000..07bdb626bb9 --- /dev/null +++ b/crates/bindings-typescript/src/server/runtime.ts @@ -0,0 +1,522 @@ +import { AlgebraicType } from '../lib/algebraic_type'; +import RawModuleDef from '../lib/autogen/raw_module_def_type'; +import type RawModuleDefV9 from '../lib/autogen/raw_module_def_v_9_type'; +import type RawTableDefV9 from '../lib/autogen/raw_table_def_v_9_type'; +import type Typespace from '../lib/autogen/typespace_type'; +import { ConnectionId } from '../lib/connection_id'; +import { Identity } from '../lib/identity'; +import { Timestamp } from '../lib/timestamp'; +import { BinaryReader, BinaryWriter } from '../sdk'; +import { SenderError, SpacetimeHostError } from './errors'; +import { Range, type Bound } from './range'; +import { + type Index, + type IndexVal, + type UniqueIndex, + type RangedIndex, +} from './indexes'; +import { type RowType, type Table, type TableMethods } from './table'; +import { type DbView, type ReducerCtx, REDUCERS } from './reducers'; +import { MODULE_DEF } from './schema'; + +import * as _syscalls from 'spacetime:sys@1.0'; +import type { u16, u32, ModuleHooks } from 'spacetime:sys@1.0'; + +const { freeze } = Object; + +const sys: typeof _syscalls = freeze( + Object.fromEntries( + Object.entries(_syscalls).map(([name, syscall]) => [ + name, + wrapSyscall(syscall), + ]) + ) as typeof _syscalls +); + +export const hooks: ModuleHooks = { + __describe_module__() { + const writer = new BinaryWriter(128); + RawModuleDef.serialize(writer, RawModuleDef.V9(MODULE_DEF)); + return writer.getBuffer(); + }, + __call_reducer__(reducerId, sender, connId, timestamp, argsBuf) { + const argsType = AlgebraicType.Product( + MODULE_DEF.reducers[reducerId].params + ); + const args = AlgebraicType.deserializeValue( + new BinaryReader(argsBuf), + argsType + ); + const ctx: ReducerCtx = freeze({ + sender: new Identity(sender), + get identity() { + return new Identity(sys.identity().__identity__); + }, + timestamp: new Timestamp(timestamp), + connectionId: ConnectionId.nullIfZero(new ConnectionId(connId)), + db: getDbView(), + }); + try { + return REDUCERS[reducerId](ctx, args) ?? { tag: 'ok' }; + } catch (e) { + if (e instanceof SenderError) { + return { tag: 'err', value: e.message }; + } + throw e; + } + }, +}; + +let DB_VIEW: DbView | null = null; +function getDbView() { + DB_VIEW ??= makeDbView(MODULE_DEF); + return DB_VIEW; +} + +function makeDbView(module_def: RawModuleDefV9): DbView { + return freeze( + Object.fromEntries( + module_def.tables.map(table => [ + table.name, + makeTableView(module_def.typespace, table), + ]) + ) + ); +} + +function makeTableView(typespace: Typespace, table: RawTableDefV9): Table { + const table_id = sys.table_id_from_name(table.name); + const rowType = typespace.types[table.productTypeRef]; + if (rowType.tag !== 'Product') throw 'impossible'; + + const baseSize = bsatnBaseSize(typespace, rowType); + + const sequences = table.sequences.map(seq => { + const col = rowType.value.elements[seq.column]; + const colType = col.algebraicType; + return { + colName: col.name!, + read: (reader: BinaryReader) => + AlgebraicType.deserializeValue(reader, colType), + }; + }); + const hasAutoIncrement = sequences.length > 0; + + const iter = () => + new TableIterator(sys.datastore_table_scan_bsatn(table_id), rowType); + + const integrate_generated_columns = hasAutoIncrement + ? (row: RowType, ret_buf: Uint8Array) => { + const reader = new BinaryReader(ret_buf); + for (const { colName, read } of sequences) { + row[colName] = read(reader); + } + } + : null; + + const tableMethods: TableMethods = { + count: () => sys.datastore_table_row_count(table_id), + iter, + [Symbol.iterator]: () => iter(), + insert: row => { + const writer = new BinaryWriter(baseSize); + AlgebraicType.serializeValue(writer, rowType, row); + const ret_buf = sys.datastore_insert_bsatn(table_id, writer.getBuffer()); + const ret = { ...row }; + integrate_generated_columns?.(ret, ret_buf); + + return { ok: true, val: ret }; + }, + delete: (row: RowType): boolean => { + const writer = new BinaryWriter(4 + baseSize); + writer.writeU32(1); + AlgebraicType.serializeValue(writer, rowType, row); + const count = sys.datastore_delete_all_by_eq_bsatn( + table_id, + writer.getBuffer() + ); + return count > 0; + }, + }; + + const tableView = Object.assign( + Object.create(null), + tableMethods + ) as Table; + + for (const indexDef of table.indexes) { + const index_id = sys.index_id_from_name(indexDef.name!); + + let column_ids: number[]; + switch (indexDef.algorithm.tag) { + case 'BTree': + column_ids = indexDef.algorithm.value; + break; + case 'Hash': + throw new Error('impossible'); + case 'Direct': + column_ids = [indexDef.algorithm.value]; + break; + } + const numColumns = column_ids.length; + + const columnSet = new Set(column_ids); + const isUnique = table.constraints + .filter(x => x.data.tag === 'Unique') + .map(x => columnSet.isSubsetOf(new Set(x.data.value.columns))); + + const indexType = AlgebraicType.Product({ + elements: column_ids.map(id => rowType.value.elements[id]), + }); + + const baseSize = bsatnBaseSize(typespace, indexType); + + const serializePrefix = ( + writer: BinaryWriter, + prefix: any[], + prefix_elems: number + ) => { + if (prefix.length > numColumns - 1) + throw new TypeError('too many elements in prefix'); + for (let i = 0; i < prefix_elems; i++) { + const elemType = indexType.value.elements[i].algebraicType; + AlgebraicType.serializeValue(writer, elemType, prefix[i]); + } + return writer; + }; + + type IndexScanArgs = [ + prefix: Uint8Array, + prefix_elems: u16, + rstart: Uint8Array, + rend: Uint8Array, + ]; + + let index: Index; + if (isUnique) { + const serializeBound = (col_val: any[]): IndexScanArgs => { + if (col_val.length !== numColumns) + throw new TypeError('wrong number of elements'); + + const writer = new BinaryWriter(baseSize + 1); + const prefix_elems = numColumns - 1; + serializePrefix(writer, col_val, prefix_elems); + const rstartOffset = writer.offset; + writer.writeU8(0); + AlgebraicType.serializeValue( + writer, + indexType.value.elements[numColumns - 1].algebraicType, + col_val[numColumns - 1] + ); + const buffer = writer.getBuffer(); + const prefix = buffer.slice(0, rstartOffset); + const rstart = buffer.slice(rstartOffset); + return [prefix, prefix_elems, rstart, rstart]; + }; + index = { + find: (col_val: IndexVal): RowType | null => { + if (numColumns === 1) col_val = [col_val]; + const args = serializeBound(col_val); + const iter = new TableIterator( + sys.datastore_index_scan_range_bsatn(index_id, ...args), + rowType + ); + const { value, done } = iter.next(); + if (done) return null; + if (!iter.next().done) + throw new Error( + '`datastore_index_scan_range_bsatn` on unique field cannot return >1 rows' + ); + return value; + }, + delete: (col_val: IndexVal): boolean => { + if (numColumns === 1) col_val = [col_val]; + const args = serializeBound(col_val); + const num = sys.datastore_delete_by_index_scan_range_bsatn( + index_id, + ...args + ); + return num > 0; + }, + update: (row: RowType): RowType => { + const writer = new BinaryWriter(baseSize); + AlgebraicType.serializeValue(writer, rowType, row); + const ret_buf = sys.datastore_update_bsatn( + table_id, + index_id, + writer.getBuffer() + ); + integrate_generated_columns?.(row, ret_buf); + return row; + }, + } as UniqueIndex; + } else { + const serializeRange = (range: any[]): IndexScanArgs => { + if (range.length > numColumns) throw new TypeError('too many elements'); + + const writer = new BinaryWriter(baseSize + 1); + const prefix_elems = range.length - 1; + serializePrefix(writer, range, prefix_elems); + const rstartOffset = writer.offset; + const term = range[range.length - 1]; + const termType = + indexType.value.elements[range.length - 1].algebraicType; + let rstart: Uint8Array, rend: Uint8Array; + if (term instanceof Range) { + const writeBound = (bound: Bound) => { + const tags = { included: 0, excluded: 1, unbounded: 2 }; + writer.writeU8(tags[bound.tag]); + if (bound.tag !== 'unbounded') + AlgebraicType.serializeValue(writer, termType, bound.value); + }; + writeBound(term.from); + const rendOffset = writer.offset; + writeBound(term.to); + rstart = writer.getBuffer().slice(rstartOffset, rendOffset); + rend = writer.getBuffer().slice(rendOffset); + } else { + writer.writeU8(0); + AlgebraicType.serializeValue(writer, termType, term); + rstart = rend = writer.getBuffer().slice(rstartOffset); + } + const buffer = writer.getBuffer(); + const prefix = buffer.slice(0, rstartOffset); + return [prefix, prefix_elems, rstart, rend]; + }; + index = { + filter: (range: any): IterableIterator> => { + if (numColumns === 1) range = [range]; + const args = serializeRange(range); + return new TableIterator( + sys.datastore_index_scan_range_bsatn(index_id, ...args), + rowType + ); + }, + delete: (range: any): u32 => { + if (numColumns === 1) range = [range]; + const args = serializeRange(range); + return sys.datastore_delete_by_index_scan_range_bsatn( + index_id, + ...args + ); + }, + } as RangedIndex; + } + + if (Object.hasOwn(tableView, indexDef.name!)) { + freeze(Object.assign(tableView[indexDef.name!], index)); + } else { + tableView[indexDef.name!] = freeze(index) as any; + } + } + + return freeze(tableView); +} + +function bsatnBaseSize(typespace: Typespace, ty: AlgebraicType): number { + const assumedArrayLength = 4; + while (ty.tag === 'Ref') ty = typespace.types[ty.value]; + if (ty.tag === 'Product') { + let sum = 0; + for (const { algebraicType: elem } of ty.value.elements) { + sum += bsatnBaseSize(typespace, elem); + } + return sum; + } else if (ty.tag === 'Sum') { + let min = Infinity; + for (const { algebraicType: vari } of ty.value.variants) { + const vSize = bsatnBaseSize(typespace, vari); + if (vSize < min) min = vSize; + } + if (min === Infinity) min = 0; + return 4 + min; + } else if (ty.tag == 'Array') { + return 4 + assumedArrayLength * bsatnBaseSize(typespace, ty.value); + } + return { + String: 4 + assumedArrayLength, + Sum: 1, + Bool: 1, + I8: 1, + U8: 1, + I16: 2, + U16: 2, + I32: 4, + U32: 4, + F32: 4, + I64: 8, + U64: 8, + F64: 8, + I128: 16, + U128: 16, + I256: 32, + U256: 32, + }[ty.tag]; +} + +function hasOwn( + o: object, + k: K +): o is K extends PropertyKey ? { [k in K]: unknown } : never { + return Object.hasOwn(o, k); +} + +class TableIterator implements IterableIterator { + #id: u32 | -1; + #reader: BinaryReader; + #ty: AlgebraicType; + constructor(id: u32, ty: AlgebraicType) { + this.#id = id; + this.#reader = new BinaryReader(new Uint8Array()); + this.#ty = ty; + } + [Symbol.iterator](): typeof this { + return this; + } + next(): IteratorResult { + while (true) { + if (this.#reader.remaining > 0) { + const value = AlgebraicType.deserializeValue(this.#reader, this.#ty); + return { value }; + } + if (this.#id === -1) { + return { value: undefined, done: true }; + } + this.#advance_iter(); + } + } + + #advance_iter() { + let buf_max_len = 0x10000; + while (true) { + try { + const { 0: done, 1: buf } = sys.row_iter_bsatn_advance( + this.#id, + buf_max_len + ); + if (done) this.#id = -1; + this.#reader = new BinaryReader(buf); + return; + } catch (e) { + if (e && typeof e === 'object' && hasOwn(e, '__buffer_too_small__')) { + buf_max_len = e.__buffer_too_small__ as number; + continue; + } + throw e; + } + } + } + + [Symbol.dispose]() { + if (this.#id >= 0) { + this.#id = -1; + sys.row_iter_bsatn_close(this.#id); + } + } +} + +function wrapSyscall any>( + func: F +): (...args: Parameters) => ReturnType { + const name = func.name; + return { + [name](...args: Parameters) { + try { + return func(...args); + } catch (e) { + if ( + e !== null && + typeof e === 'object' && + hasOwn(e, '__code_error__') && + typeof e.__code_error__ == 'number' + ) { + throw new SpacetimeHostError(e.__code_error__); + } + throw e; + } + }, + }[name]; +} + +function fmtLog(...data: any[]) { + return data.join(' '); +} + +const console_level_error = 0; +const console_level_warn = 1; +const console_level_info = 2; +const console_level_debug = 3; +const console_level_trace = 4; +const _console_level_panic = 101; + +const timerMap = new Map(); + +const console: Console = { + // @ts-expect-error we want a blank prototype, but typescript complains + __proto__: {}, + [Symbol.toStringTag]: 'console', + assert: (condition = false, ...data: any[]) => { + if (!condition) { + sys.console_log(console_level_error, fmtLog(...data)); + } + }, + clear: () => {}, + debug: (...data: any[]) => { + sys.console_log(console_level_debug, fmtLog(...data)); + }, + error: (...data: any[]) => { + sys.console_log(console_level_error, fmtLog(...data)); + }, + info: (...data: any[]) => { + sys.console_log(console_level_info, fmtLog(...data)); + }, + log: (...data: any[]) => { + sys.console_log(console_level_info, fmtLog(...data)); + }, + table: (tabularData: any, _properties: any) => { + sys.console_log(console_level_info, fmtLog(tabularData)); + }, + trace: (...data: any[]) => { + sys.console_log(console_level_trace, fmtLog(...data)); + }, + warn: (...data: any[]) => { + sys.console_log(console_level_warn, fmtLog(...data)); + }, + dir: (_item: any, _options: any) => {}, + dirxml: (..._data: any[]) => {}, + // Counting + count: (_label = 'default') => {}, + countReset: (_label = 'default') => {}, + // Grouping + group: (..._data: any[]) => {}, + groupCollapsed: (..._data: any[]) => {}, + groupEnd: () => {}, + // Timing + time: (label = 'default') => { + if (timerMap.has(label)) { + sys.console_log(console_level_warn, `Timer '${label}' already exists.`); + return; + } + timerMap.set(label, sys.console_timer_start(label)); + }, + timeLog: (label = 'default', ...data: any[]) => { + sys.console_log(console_level_info, fmtLog(label, ...data)); + }, + timeEnd: (label = 'default') => { + const spanId = timerMap.get(label); + if (spanId === undefined) { + sys.console_log(console_level_warn, `Timer '${label}' does not exist.`); + return; + } + sys.console_timer_end(spanId); + timerMap.delete(label); + }, + // Additional console methods to satisfy the Console interface + timeStamp: () => {}, + profile: () => {}, + profileEnd: () => {}, +}; + +(console as any).Console = console; + +globalThis.console = console; diff --git a/crates/bindings-typescript/src/server/schema.ts b/crates/bindings-typescript/src/server/schema.ts new file mode 100644 index 00000000000..4360d3778d0 --- /dev/null +++ b/crates/bindings-typescript/src/server/schema.ts @@ -0,0 +1,355 @@ +import type RawTableDefV9 from '../lib/autogen/raw_table_def_v_9_type'; +import type Typespace from '../lib/autogen/typespace_type'; +import { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + type ColumnBuilder, + type RowObj, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + type TypeBuilder, +} from './type_builders'; +import type { TableSchema, UntypedTableDef } from './table'; +import { + clientConnected, + clientDisconnected, + init, + reducer, + type ParamsObj, + type Reducer, +} from './reducers'; +import type RawModuleDefV9 from '../lib/autogen/raw_module_def_v_9_type'; +import { + AlgebraicType, + type AlgebraicTypeVariants, +} from '../lib/algebraic_type'; +import type RawScopedTypeNameV9 from '../lib/autogen/raw_scoped_type_name_v_9_type'; + +/** + * The global module definition that gets populated by calls to `reducer()` and lifecycle hooks. + */ +export const MODULE_DEF: RawModuleDefV9 = { + typespace: { types: [] }, + tables: [], + reducers: [], + types: [], + miscExports: [], + rowLevelSecurity: [], +}; + +const COMPOUND_TYPES = new Map< + AlgebraicTypeVariants.Product | AlgebraicTypeVariants.Sum, + AlgebraicTypeVariants.Ref +>(); + +export function addType( + name: string | undefined, + ty: T +): T | AlgebraicTypeVariants.Ref { + if ( + (ty.tag === 'Product' && ty.value.elements.length > 0) || + (ty.tag === 'Sum' && ty.value.variants.length > 0) + ) { + let r = COMPOUND_TYPES.get(ty); + if (r == null) { + r = AlgebraicType.Ref(MODULE_DEF.typespace.types.length); + MODULE_DEF.typespace.types.push(ty); + COMPOUND_TYPES.set(ty, r); + if (name != null) + MODULE_DEF.types.push({ + name: splitName(name), + ty: r.value, + customOrdering: true, + }); + } + return r; + } else { + return ty; + } +} + +export function splitName(name: string): RawScopedTypeNameV9 { + const scope = name.split('.'); + return { name: scope.pop()!, scope }; +} + +/** + * An untyped representation of the database schema. + */ +export type UntypedSchemaDef = { + tables: readonly UntypedTableDef[]; +}; + +/** + * Helper type to convert an array of TableSchema into a schema definition + */ +type TablesToSchema[]> = { + tables: { + /** @type {UntypedTableDef} */ + readonly [i in keyof T]: { + name: T[i]['tableName']; + columns: T[i]['rowType']['row']; + indexes: T[i]['idxs']; + }; + }; +}; + +/** + * The Schema class represents the database schema for a SpacetimeDB application. + * It encapsulates the table definitions and typespace, and provides methods to define + * reducers and lifecycle hooks. + * + * Schema has a generic parameter S which represents the inferred schema type. This type + * is automatically inferred when creating a schema using the `schema()` function and is + * used to type the database view in reducer contexts. + * + * The methods on this class are used to register reducers and lifecycle hooks + * with the SpacetimeDB runtime. Theey forward to free functions that handle the actual + * registration logic, but having them as methods on the Schema class helps with type inference. + * + * @template S - The inferred schema type of the SpacetimeDB module. + * + * @example + * ```typescript + * const spacetime = schema( + * table({ name: 'user' }, userType), + * table({ name: 'post' }, postType) + * ); + * spacetime.reducer( + * 'create_user', + * { username: t.string(), email: t.string() }, + * (ctx, { username, email }) => { + * ctx.db.user.insert({ username, email, created_at: ctx.timestamp }); + * console.log(`User ${username} created by ${ctx.sender.identityId}`); + * } + * ); + * ``` + */ +// TODO(cloutiertyler): It might be nice to have a way to access the types +// for the tables from the schema object, e.g. `spacetimedb.user.type` would +// be the type of the user table. +class Schema { + readonly tablesDef: { tables: RawTableDefV9[] }; + readonly typespace: Typespace; + readonly schemaType!: S; + + constructor(tables: RawTableDefV9[], typespace: Typespace) { + this.tablesDef = { tables }; + this.typespace = typespace; + } + + /** + * Defines a SpacetimeDB reducer function. + * + * Reducers are the primary way to modify the state of your SpacetimeDB application. + * They are atomic, meaning that either all operations within a reducer succeed, + * or none of them do. + * + * @template S - The inferred schema type of the SpacetimeDB module. + * @template Params - The type of the parameters object expected by the reducer. + * + * @param {string} name - The name of the reducer. This name will be used to call the reducer from clients. + * @param {Params} params - An object defining the parameters that the reducer accepts. + * Each key-value pair represents a parameter name and its corresponding + * {@link TypeBuilder} or {@link ColumnBuilder}. + * @param {(ctx: ReducerCtx, payload: ParamsAsObject) => void} fn - The reducer function itself. + * - `ctx`: The reducer context, providing access to `sender`, `timestamp`, `connection_id`, and `db`. + * - `payload`: An object containing the arguments passed to the reducer, typed according to `params`. + * + * @example + * ```typescript + * // Define a reducer named 'create_user' that takes 'username' (string) and 'email' (string) + * spacetime.reducer( + * 'create_user', + * { + * username: t.string(), + * email: t.string(), + * }, + * (ctx, { username, email }) => { + * // Access the 'user' table from the database view in the context + * ctx.db.user.insert({ username, email, created_at: ctx.timestamp }); + * console.log(`User ${username} created by ${ctx.sender.identityId}`); + * } + * ); + * ``` + */ + reducer( + name: string, + params: Params, + fn: Reducer + ): void; + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + reducer(name: string, fn: Reducer): void; + reducer( + name: string, + paramsOrFn: Params | Reducer, + fn?: Reducer + ): void { + if (typeof paramsOrFn === 'function') { + // This is the case where params are omitted. + // The second argument is the reducer function. + // We pass an empty object for the params. + reducer(name, {}, paramsOrFn); + } else { + // This is the case where params are provided. + // The second argument is the params object, and the third is the function. + // The `fn` parameter is guaranteed to be defined here. + reducer(name, paramsOrFn, fn!); + } + } + + /** + * Registers an initialization reducer that runs when the SpacetimeDB module is published + * for the first time. + * + * This function is useful to set up any initial state of your database that is guaranteed + * to run only once, and before any other reducers or client connections. + * + * @template S - The inferred schema type of the SpacetimeDB module. + * @param {Reducer} fn - The initialization reducer function. + * - `ctx`: The reducer context, providing access to `sender`, `timestamp`, `connection_id`, and `db`. + * @example + * ```typescript + * spacetime.init((ctx) => { + * ctx.db.user.insert({ username: 'admin', email: 'admin@example.com' }); + * }); + * ``` + */ + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + init(fn: Reducer): void { + init({}, fn); + } + + /** + * Registers a reducer to be called when a client connects to the SpacetimeDB module. + * This function allows you to define custom logic that should execute + * whenever a new client establishes a connection. + * @template S - The inferred schema type of the SpacetimeDB module. + * + * @param fn - The reducer function to execute on client connection. + * + * @example + * ```typescript + * spacetime.clientConnected( + * (ctx) => { + * console.log(`Client ${ctx.connectionId} connected`); + * } + * ); + */ + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + clientConnected(fn: Reducer): void { + clientConnected({}, fn); + } + + /** + * Registers a reducer to be called when a client disconnects from the SpacetimeDB module. + * This function allows you to define custom logic that should execute + * whenever a client disconnects. + * @template S - The inferred schema type of the SpacetimeDB module. + * + * @param fn - The reducer function to execute on client disconnection. + * + * @example + * ```typescript + * spacetime.clientDisconnected( + * (ctx) => { + * console.log(`Client ${ctx.connectionId} disconnected`); + * } + * ); + * ``` + */ + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + clientDisconnected(fn: Reducer): void { + clientDisconnected({}, fn); + } + + clientVisibilityFilter = { + sql(filter: string): void { + MODULE_DEF.rowLevelSecurity.push({ sql: filter }); + }, + }; +} + +/** + * Extracts the inferred schema type from a Schema instance + */ +export type InferSchema> = + SchemaDef extends Schema ? S : never; + +/** + * Creates a schema from table definitions + * @param handles - Array of table handles created by table() function + * @returns ColumnBuilder representing the complete database schema + * @example + * ```ts + * const s = schema( + * table({ name: 'user' }, userType), + * table({ name: 'post' }, postType) + * ); + * ``` + */ +export function schema[]>( + ...handles: H +): Schema>; + +/** + * Creates a schema from table definitions + * @param handles - Array of table handles created by table() function + * @returns ColumnBuilder representing the complete database schema + * @example + * ```ts + * const s = schema( + * table({ name: 'user' }, userType), + * table({ name: 'post' }, postType) + * ); + * ``` + */ +export function schema[]>( + ...handles: H +): Schema>; + +/** + * Creates a schema from table definitions (array overload) + * @param handles - Array of table handles created by table() function + * @returns ColumnBuilder representing the complete database schema + */ +export function schema[]>( + handles: H +): Schema>; + +/** + * Creates a schema from table definitions + * @param args - Either an array of table handles or a variadic list of table handles + * @returns ColumnBuilder representing the complete database schema + * @example + * ```ts + * const s = schema( + * table({ name: 'user' }, userType), + * table({ name: 'post' }, postType) + * ); + * ``` + */ +export function schema( + ...args: + | [readonly TableSchema[]] + | readonly TableSchema[] +): Schema { + const handles: readonly TableSchema[] = + args.length === 1 && Array.isArray(args[0]) ? args[0] : args; + + const tableDefs = handles.map(h => h.tableDef); + + // Side-effect: + // Modify the `MODULE_DEF` which will be read by + // __describe_module__ + MODULE_DEF.tables.push(...tableDefs); + // MODULE_DEF.typespace = typespace; + // throw new Error( + // MODULE_DEF.tables + // .map(t => { + // const p = MODULE_DEF.typespace.types[t.productTypeRef]; + // return `${t.name}: ${t.productTypeRef} ${p && (p as AlgebraicTypeVariants.Product).value.elements.map(x => x.name)}`; + // }) + // .join('\n') + // ); + + return new Schema(tableDefs, MODULE_DEF.typespace); +} diff --git a/crates/bindings-typescript/src/server/sys.d.ts b/crates/bindings-typescript/src/server/sys.d.ts new file mode 100644 index 00000000000..1ee5ed8d103 --- /dev/null +++ b/crates/bindings-typescript/src/server/sys.d.ts @@ -0,0 +1,67 @@ +declare module 'spacetime:sys@1.0' { + export type u8 = number; + export type u16 = number; + export type u32 = number; + export type u64 = bigint; + export type u128 = bigint; + export type u256 = bigint; + + export type ModuleHooks = { + __describe_module__(): Uint8Array; + + __call_reducer__( + reducerId: u32, + sender: u256, + connId: u128, + timestamp: bigint, + argsBuf: Uint8Array + ): { tag: 'ok' } | { tag: 'err'; value: string }; + }; + + export function register_hooks(hooks: ModuleHooks); + + export function table_id_from_name(name: string): u32; + export function index_id_from_name(name: string): u32; + export function datastore_table_row_count(table_id: u32): u64; + export function datastore_table_scan_bsatn(table_id: u32): u32; + export function datastore_index_scan_range_bsatn( + index_id: u32, + prefix: Uint8Array, + prefix_elems: u16, + rstart: Uint8Array, + rend: Uint8Array + ): u32; + export function row_iter_bsatn_advance( + iter: u32, + buffer_max_len: u32 + ): [boolean, Uint8Array]; + export function row_iter_bsatn_close(iter: u32): void; + export function datastore_insert_bsatn( + table_id: u32, + row: Uint8Array + ): Uint8Array; + export function datastore_update_bsatn( + table_id: u32, + index_id: u32, + row: Uint8Array + ): Uint8Array; + export function datastore_delete_by_index_scan_range_bsatn( + index_id: u32, + prefix: Uint8Array, + prefix_elems: u16, + rstart: Uint8Array, + rend: Uint8Array + ): u32; + export function datastore_delete_all_by_eq_bsatn( + table_id: u32, + relation: Uint8Array + ): u32; + export function volatile_nonatomic_schedule_immediate( + reducer_name: string, + args: Uint8Array + ): void; + export function console_log(level: u8, message: string): void; + export function console_timer_start(name: string): u32; + export function console_timer_end(span_id: u32): void; + export function identity(): { __identity__: u256 }; +} diff --git a/crates/bindings-typescript/src/server/table.ts b/crates/bindings-typescript/src/server/table.ts new file mode 100644 index 00000000000..7e10c18085e --- /dev/null +++ b/crates/bindings-typescript/src/server/table.ts @@ -0,0 +1,333 @@ +import { AlgebraicType } from '../lib/algebraic_type'; +import type RawConstraintDefV9 from '../lib/autogen/raw_constraint_def_v_9_type'; +import RawIndexAlgorithm from '../lib/autogen/raw_index_algorithm_type'; +import type RawIndexDefV9 from '../lib/autogen/raw_index_def_v_9_type'; +import type RawSequenceDefV9 from '../lib/autogen/raw_sequence_def_v_9_type'; +import type RawTableDefV9 from '../lib/autogen/raw_table_def_v_9_type'; +import type { AllUnique } from './constraints'; +import type { ColumnIndex, IndexColumns, Indexes, IndexOpts } from './indexes'; +import { MODULE_DEF, splitName } from './schema'; +import { + RowBuilder, + type ColumnBuilder, + type ColumnMetadata, + type InferTypeOfRow, + type RowObj, + type TypeBuilder, +} from './type_builders'; +import type { Prettify } from './type_util'; + +export type AlgebraicTypeRef = number; +type ColId = number; +type ColList = ColId[]; + +/** + * A helper type to extract the row type from a TableDef + */ +export type RowType = InferTypeOfRow< + TableDef['columns'] +>; + +/** + * Coerces a column which may be a TypeBuilder or ColumnBuilder into a ColumnBuilder + */ +export type CoerceColumn< + Col extends TypeBuilder | ColumnBuilder, +> = + Col extends TypeBuilder ? ColumnBuilder : Col; + +/** + * Coerces a RowObj where TypeBuilders are replaced with ColumnBuilders + */ +export type CoerceRow = { + [k in keyof Row & string]: CoerceColumn; +}; + +/** + * Helper type to coerce an array of IndexOpts + */ +type CoerceArray[]> = X; + +/** + * An untyped representation of a table's schema. + */ +export type UntypedTableDef = { + name: string; + columns: Record>>; + indexes: IndexOpts[]; +}; + +/** + * A type representing the indexes defined on a table. + */ +export type TableIndexes = { + [k in keyof TableDef['columns'] & string]: ColumnIndex< + k, + TableDef['columns'][k]['columnMetadata'] + >; +} & { + [I in TableDef['indexes'][number] as I['name'] & {}]: { + name: I['name']; + unique: AllUnique>; + algorithm: Lowercase; + columns: IndexColumns; + }; +}; + +/** + * Options for configuring a database table. + * - `name`: The name of the table. + * - `public`: Whether the table is publicly accessible. Defaults to `false`. + * - `indexes`: An array of index configurations for the table. + * - `scheduled`: The name of the reducer to be executed based on the scheduled rows in this table. + */ +export type TableOpts = { + name: string; + public?: boolean; + indexes?: IndexOpts[]; // declarative multi‑column indexes + scheduled?: string; +}; + +/** + * Extracts the indices from TableOpts, defaulting to an empty array if none are provided. + */ +type OptsIndices> = Opts extends { + indexes: infer Ixs extends NonNullable; +} + ? Ixs + : CoerceArray<[]>; + +/** + * Table + * + * - Row: row shape + * - UCV: unique-constraint violation error type (never if none) + * - AIO: auto-increment overflow error type (never if none) + */ +export type Table = Prettify< + TableMethods & Indexes> +>; + +/** + * A type representing the methods available on a table. + */ +export type TableMethods = { + /** Returns the number of rows in the TX state. */ + count(): bigint; + + /** Iterate over all rows in the TX state. Rust Iterator → TS IterableIterator. */ + iter(): IterableIterator>; + [Symbol.iterator](): IterableIterator>; + + /** + * Insert and return the inserted row (auto-increment fields filled). + * + * May throw on error: + * * If there are any unique or primary key columns in this table, may throw {@link UniqueAlreadyExists}. + * * If there are any auto-incrementing columns in this table, may throw {@link AutoIncOverflow}. + * */ + insert(row: RowType): RowType; + + /** Delete a row equal to `row`. Returns true if something was deleted. */ + delete(row: RowType): boolean; +}; + +/** + * Represents a handle to a database table, including its name, row type, and row spacetime type. + */ +export type TableSchema< + TableName extends string, + Row extends Record>, + Idx extends readonly IndexOpts[], +> = { + readonly rowType: RowBuilder; + + /** + * The name of the table. + */ + readonly tableName: TableName; + + /** + * The {@link AlgebraicType} representing the structure of a row in the table. + */ + readonly rowSpacetimeType: AlgebraicType; + + /** + * The {@link RawTableDefV9} of the configured table + */ + readonly tableDef: RawTableDefV9; + + /** + * The indexes defined on the table. + */ + readonly idxs: Idx; +}; + +/** + * Defines a database table with schema and options + * @param opts - Table configuration including name, indexes, and access control + * @param row - Product type defining the table's row structure + * @returns Table handle for use in schema() function + * @example + * ```ts + * const playerTable = table( + * { name: 'player', public: true }, + * t.object({ + * id: t.u32().primary_key(), + * name: t.string().index('btree') + * }) + * ); + * ``` + */ +export function table>( + opts: Opts, + row: Row | RowBuilder +): TableSchema, OptsIndices> { + const { + name, + public: isPublic = false, + indexes: userIndexes = [], + scheduled, + } = opts; + + // 1. column catalogue + helpers + const colIds = new Map(); + const colNameList: string[] = []; + + if (!(row instanceof RowBuilder)) { + row = new RowBuilder(row); + } + + row.resolveType().value.elements.forEach((elem, i) => { + colIds.set(elem.name, i); + colNameList.push(elem.name); + }); + + // gather primary keys, per‑column indexes, uniques, sequences + const pk: ColList = []; + const indexes: RawIndexDefV9[] = []; + const constraints: RawConstraintDefV9[] = []; + const sequences: RawSequenceDefV9[] = []; + + let scheduleAtCol: ColId | undefined; + + for (const [name, builder] of Object.entries(row.row)) { + const meta: ColumnMetadata = builder.columnMetadata; + + if (meta.isPrimaryKey) { + pk.push(colIds.get(name)!); + } + + const isUnique = meta.isUnique || meta.isPrimaryKey; + + // implicit 1‑column indexes + if (meta.indexType || isUnique) { + const algo = meta.indexType ?? 'btree'; + const id = colIds.get(name)!; + let algorithm: RawIndexAlgorithm; + switch (algo) { + case 'btree': + algorithm = RawIndexAlgorithm.BTree([id]); + break; + case 'direct': + algorithm = RawIndexAlgorithm.Direct(id); + break; + } + indexes.push({ + name: undefined, + accessorName: name, + algorithm, + }); + } + + if (isUnique) { + constraints.push({ + name: undefined, + data: { tag: 'Unique', value: { columns: [colIds.get(name)!] } }, + }); + } + + if (meta.isAutoIncrement) { + sequences.push({ + name: undefined, + start: undefined, + minValue: undefined, + maxValue: undefined, + column: colIds.get(name)!, + increment: 1n, + }); + } + + if (meta.isScheduleAt) { + scheduleAtCol = colIds.get(name)!; + } + } + + // convert explicit multi‑column indexes coming from options.indexes + for (const indexOpts of userIndexes ?? []) { + let algorithm: RawIndexAlgorithm; + switch (indexOpts.algorithm) { + case 'btree': + algorithm = { + tag: 'BTree', + value: indexOpts.columns.map(c => colIds.get(c)!), + }; + break; + case 'direct': + algorithm = { tag: 'Direct', value: colIds.get(indexOpts.column)! }; + break; + } + indexes.push({ name: undefined, accessorName: indexOpts.name, algorithm }); + } + + for (const index of indexes) { + const cols = + index.algorithm.tag === 'Direct' + ? [index.algorithm.value] + : index.algorithm.value; + const colS = cols.map(i => colNameList[i]).join('_'); + index.name = `${name}_${colS}_idx_${index.algorithm.tag.toLowerCase()}`; + } + + // Temporarily set the type ref to 0. We will set this later + // in the schema function. + + const tableDef: RawTableDefV9 = { + name, + productTypeRef: row.algebraicType.value as number, + primaryKey: pk, + indexes, + constraints, + sequences, + schedule: + scheduled && scheduleAtCol !== undefined + ? { + name: undefined, + reducerName: scheduled, + scheduledAtColumn: scheduleAtCol, + } + : undefined, + tableType: { tag: 'User' }, + tableAccess: { tag: isPublic ? 'Public' : 'Private' }, + }; + + MODULE_DEF.types.push({ + customOrdering: true, + name: splitName(name), + ty: row.algebraicType.value as number, + }); + + const productType = AlgebraicType.Product({ + elements: row.resolveType().value.elements.map(elem => { + return { name: elem.name, algebraicType: elem.algebraicType }; + }), + }); + + return { + rowType: row as RowBuilder>, + tableName: name, + rowSpacetimeType: productType, + tableDef, + idxs: indexes as OptsIndices, + }; +} diff --git a/crates/bindings-typescript/src/server/type_builders.test-d.ts b/crates/bindings-typescript/src/server/type_builders.test-d.ts index 3f622d7efb2..d0595f25829 100644 --- a/crates/bindings-typescript/src/server/type_builders.test-d.ts +++ b/crates/bindings-typescript/src/server/type_builders.test-d.ts @@ -1,4 +1,5 @@ -import { t, type AlgebraicTypeVariants } from '..'; +import { t } from '../server'; +import { type AlgebraicTypeVariants } from '..'; import type { I32ColumnBuilder, I64ColumnBuilder, @@ -28,6 +29,20 @@ const _row: Row = { idx: 100n, }; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const rowOptionOptional = { + foo: t.string().optional().optional(), +}; +type RowOptionOptional = InferTypeOfRow; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const _rowOptionOptionalNone: RowOptionOptional = { + foo: undefined, +}; +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const _rowOptionOptionalSome: RowOptionOptional = { + foo: 'hello', +}; + // Test that a row must not allow non-TypeBuilder or ColumnBuilder values // eslint-disable-next-line @typescript-eslint/no-unused-vars const row2 = { @@ -38,16 +53,17 @@ const row2 = { bar: t.i32().primaryKey(), idx: t.i64().index('btree').unique(), }; +// @ts-expect-error this should error type Row2 = InferTypeOfRow; // eslint-disable-next-line @typescript-eslint/no-unused-vars type _ = MustBeNever; // Test type inference on a type with a nested object // eslint-disable-next-line @typescript-eslint/no-unused-vars -const point = t.object({ +const point = t.object('Point', { x: t.i32(), y: t.f64(), - z: t.object({ + z: t.object('Foo', { foo: t.string(), }), }); @@ -63,7 +79,7 @@ const _point: Point = { // Test type inference on an enum // eslint-disable-next-line @typescript-eslint/no-unused-vars -const e = t.enum({ +const e = t.enum('E', { A: t.string(), B: t.number(), }); diff --git a/crates/bindings-typescript/src/server/type_builders.ts b/crates/bindings-typescript/src/server/type_builders.ts index c06ea3e64c3..244206a22dc 100644 --- a/crates/bindings-typescript/src/server/type_builders.ts +++ b/crates/bindings-typescript/src/server/type_builders.ts @@ -3,37 +3,82 @@ import { ConnectionId, Identity, ScheduleAt, - SumTypeVariant, TimeDuration, Timestamp, + Option, type AlgebraicTypeVariants, + type ConnectionIdAlgebraicType, + type IdentityAlgebraicType, + type TimeDurationAlgebraicType, + type TimestampAlgebraicType, } from '..'; -import type { Set } from './type_util'; +import type { OptionAlgebraicType } from '../lib/option'; +import { addType, MODULE_DEF } from './schema'; +import type { CoerceRow } from './table'; +import { set, type Set } from './type_util'; /** * Helper type to extract the TypeScript type from a TypeBuilder */ -export type InferTypeOfTypeBuilder = +export type InferTypeOfTypeBuilder> = T extends TypeBuilder ? U : never; +/** + * Helper type to extract the Spacetime type from a TypeBuilder + */ +export type InferSpacetimeTypeOfTypeBuilder> = + T extends TypeBuilder ? U : never; + /** * Helper type to extract the TypeScript type from a TypeBuilder */ -export type Infer = InferTypeOfTypeBuilder; +export type Infer> = InferTypeOfTypeBuilder; /** * Helper type to extract the type of a row from an object. */ -export type InferTypeOfRow = - T extends Record | TypeBuilder> - ? { - [K in keyof T]: T[K] extends ColumnBuilder - ? V - : T[K] extends TypeBuilder - ? V - : never; - } - : never; +export type InferTypeOfRow = { + [K in keyof T & string]: InferTypeOfTypeBuilder>; +}; + +/** + * Helper type to extract the Spacetime type from a row object. + */ +type CollapseColumn< + T extends TypeBuilder | ColumnBuilder, +> = T extends ColumnBuilder ? T['typeBuilder'] : T; + +/** + * A type representing an object which is used to define the type of + * a row in a table. + */ +export type RowObj = Record< + string, + TypeBuilder | ColumnBuilder +>; + +/** + * Type which converts the elements of RowObj to a ProductType elements array + */ +type ElementsArrayFromRowObj = Array< + { + [N in keyof Obj & string]: { + name: N; + algebraicType: InferSpacetimeTypeOfTypeBuilder>; + }; + }[keyof Obj & string] +>; + +/** + * A type which converts the elements of RowObj to a TypeScript object type. + * It works by `Infer`ing the types of the column builders which are the values of + * the keys in the object passed in. + * + * e.g. { a: I32TypeBuilder, b: StringBuilder } -> { a: number, b: string } + */ +type RowType = { + [K in keyof Row]: InferTypeOfTypeBuilder>; +}; /** * Type which represents a valid argument to the ProductColumnBuilder @@ -43,10 +88,14 @@ type ElementsObj = Record>; /** * Type which converts the elements of ElementsObj to a ProductType elements array */ -type ElementsArrayFromElementsObj = { - name: keyof Obj & string; - algebraicType: Obj[keyof Obj & string]['spacetimeType']; -}[]; +type ElementsArrayFromElementsObj = Array< + { + [N in keyof Obj & string]: { + name: N; + algebraicType: InferSpacetimeTypeOfTypeBuilder; + }; + }[keyof Obj & string] +>; /** * A type which converts the elements of ElementsObj to a TypeScript object type. @@ -55,11 +104,14 @@ type ElementsArrayFromElementsObj = { * * e.g. { a: I32TypeBuilder, b: StringBuilder } -> { a: number, b: string } */ -type TypeScriptTypeFromElementsObj = { +type ObjectType = { [K in keyof Elements]: InferTypeOfTypeBuilder; }; type VariantsObj = Record>; +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +type UnitBuilder = ProductBuilder<{}>; +type SimpleVariantsObj = Record; /** * A type which converts the elements of ElementsObj to a TypeScript object type. @@ -68,7 +120,7 @@ type VariantsObj = Record>; * * e.g. { A: I32TypeBuilder, B: StringBuilder } -> { tag: "A", value: number } | { tag: "B", value: string } */ -type TypeScriptTypeFromVariantsObj = { +type EnumType = { [K in keyof Variants]: { tag: K; value: InferTypeOfTypeBuilder }; }[keyof Variants]; @@ -77,26 +129,22 @@ type TypeScriptTypeFromVariantsObj = { */ type VariantsArrayFromVariantsObj = { name: keyof Obj & string; - algebraicType: Obj[keyof Obj & string]['spacetimeType']; + algebraicType: InferSpacetimeTypeOfTypeBuilder; }[]; /** * A generic type builder that captures both the TypeScript type * and the corresponding `AlgebraicType`. */ -export class TypeBuilder { +export class TypeBuilder + implements Optional +{ /** * The TypeScript phantom type. This is not stored at runtime, * but is visible to the compiler */ readonly type!: Type; - /** - * TypeScript phantom type representing the type of the particular - * AlgebraicType stored in {@link algebraicType}. - */ - readonly spacetimeType!: SpacetimeType; - /** * The SpacetimeDB algebraic type (run‑time value). In addition to storing * the runtime representation of the `AlgebraicType`, it also captures @@ -106,11 +154,21 @@ export class TypeBuilder { * * e.g. `string` corresponds to `AlgebraicType.String` */ - readonly algebraicType: AlgebraicType; + readonly algebraicType: SpacetimeType | AlgebraicTypeVariants.Ref; - constructor(algebraicType: AlgebraicType) { + constructor(algebraicType: SpacetimeType | AlgebraicTypeVariants.Ref) { this.algebraicType = algebraicType; } + + resolveType(): SpacetimeType { + let ty: AlgebraicType = this.algebraicType; + while (ty.tag === 'Ref') ty = MODULE_DEF.typespace.types[ty.value]; + return ty as SpacetimeType; + } + + optional(): OptionBuilder { + return new OptionBuilder(this); + } } /** @@ -133,7 +191,7 @@ export class TypeBuilder { interface PrimaryKeyable< Type, SpacetimeType extends AlgebraicType, - M extends ColumnMetadata = DefaultMetadata, + M extends ColumnMetadata = DefaultMetadata, > { /** * Specify this column as primary key @@ -165,7 +223,7 @@ interface PrimaryKeyable< interface Uniqueable< Type, SpacetimeType extends AlgebraicType, - M extends ColumnMetadata = DefaultMetadata, + M extends ColumnMetadata = DefaultMetadata, > { /** * Specify this column as unique @@ -192,14 +250,15 @@ interface Uniqueable< interface Indexable< Type, SpacetimeType extends AlgebraicType, - M extends ColumnMetadata = DefaultMetadata, + M extends ColumnMetadata = DefaultMetadata, > { /** * Specify the index type for this column * @param algorithm The index algorithm to use */ - index( - algorithm?: N + index(): ColumnBuilder>; + index>( + algorithm: N ): ColumnBuilder>; } @@ -223,7 +282,7 @@ interface Indexable< interface AutoIncrementable< Type, SpacetimeType extends AlgebraicType, - M extends ColumnMetadata = DefaultMetadata, + M extends ColumnMetadata = DefaultMetadata, > { /** * Specify this column as auto-incrementing @@ -235,47 +294,104 @@ interface AutoIncrementable< >; } +/** + * Interface for types that can be converted into an optional type. + * All {@link TypeBuilder}s implement this interface, however since the `optional()` method + * returns an {@link OptionBuilder}, {@link OptionBuilder} controls what metadata is allowed + * to be configured for the column. This allows us to restrict whether things like indexes + * or unique constraints can be applied to optional columns. + * + * For this reason {@link ColumnBuilder} does not implement this interface. + */ +interface Optional { + /** + * Specify this column as optional + */ + optional(this: TypeBuilder): OptionBuilder; +} + +/** + * Interface for types that can be converted into a column builder with default value metadata. + * Implementing this interface allows a type to have a default value specified in a table column + * in a type-safe manner. The `default()` method returns a new `ColumnBuilder` instance + * with the metadata updated to include the specified default value. + * + * @typeParam Type - The TypeScript type of the column's value. + * @typeParam SpacetimeType - The corresponding SpacetimeDB algebraic type. + * @typeParam M - The metadata type for the column, defaulting to `DefaultMetadata`. + * + * @remarks + * - This interface is typically implemented by type builders for primitive and complex types. + * - The returned `ColumnBuilder` will have its metadata extended with `{ default: value }`. + * - The default value must be of the same type as the column's TypeScript type. + * - This method can be called multiple times; the last call takes precedence. + */ +interface Defaultable< + Type, + SpacetimeType extends AlgebraicType, + M extends ColumnMetadata = DefaultMetadata, +> { + /** + * Specify a default value for this column + * @param value The default value for the column + * @example + * ```typescript + * const col = t.i32().default(42); + * ``` + * @remarks + * - This method can be called multiple times; the last call takes precedence. + * - The default value must be of the same type as the column's TypeScript type. + */ + default( + value: Type + ): ColumnBuilder>; +} + export class U8Builder extends TypeBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U8); } - index( - algorithm?: N - ): U8ColumnBuilder> { - return new U8ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): U8ColumnBuilder>; + index>( + algorithm: N + ): U8ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U8ColumnBuilder> { + return new U8ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): U8ColumnBuilder> { - return new U8ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new U8ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): U8ColumnBuilder> { - return new U8ColumnBuilder>( + return new U8ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): U8ColumnBuilder> { - return new U8ColumnBuilder>( + return new U8ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: number + ): U8ColumnBuilder> { + return new U8ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -286,41 +402,45 @@ export class U16Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U16); } - index( - algorithm?: N - ): U16ColumnBuilder> { - return new U16ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): U16ColumnBuilder>; + index>( + algorithm: N + ): U16ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U16ColumnBuilder> { + return new U16ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): U16ColumnBuilder> { - return new U16ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new U16ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): U16ColumnBuilder> { - return new U16ColumnBuilder>( + return new U16ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): U16ColumnBuilder> { - return new U16ColumnBuilder>( + return new U16ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: number + ): U16ColumnBuilder> { + return new U16ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -331,41 +451,45 @@ export class U32Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U32); } - index( - algorithm?: N - ): U32ColumnBuilder> { - return new U32ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): U32ColumnBuilder>; + index>( + algorithm: N + ): U32ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U32ColumnBuilder> { + return new U32ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): U32ColumnBuilder> { - return new U32ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new U32ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): U32ColumnBuilder> { - return new U32ColumnBuilder>( + return new U32ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): U32ColumnBuilder> { - return new U32ColumnBuilder>( + return new U32ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: number + ): U32ColumnBuilder> { + return new U32ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -376,41 +500,45 @@ export class U64Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U64); } - index( - algorithm?: N - ): U64ColumnBuilder> { - return new U64ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): U64ColumnBuilder>; + index>( + algorithm: N + ): U64ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U64ColumnBuilder> { + return new U64ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): U64ColumnBuilder> { - return new U64ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new U64ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): U64ColumnBuilder> { - return new U64ColumnBuilder>( + return new U64ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): U64ColumnBuilder> { - return new U64ColumnBuilder>( + return new U64ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: bigint + ): U64ColumnBuilder> { + return new U64ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -421,41 +549,48 @@ export class U128Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U128); } - index( - algorithm?: N - ): U128ColumnBuilder> { - return new U128ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): U128ColumnBuilder>; + index>( + algorithm: N + ): U128ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U128ColumnBuilder> { + return new U128ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): U128ColumnBuilder> { - return new U128ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new U128ColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); } primaryKey(): U128ColumnBuilder> { - return new U128ColumnBuilder>( + return new U128ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): U128ColumnBuilder> { - return new U128ColumnBuilder>( + return new U128ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: bigint + ): U128ColumnBuilder> { + return new U128ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -466,41 +601,48 @@ export class U256Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.U256); } - index( - algorithm?: N - ): U256ColumnBuilder> { - return new U256ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): U256ColumnBuilder>; + index>( + algorithm: N + ): U256ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U256ColumnBuilder> { + return new U256ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): U256ColumnBuilder> { - return new U256ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new U256ColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); } primaryKey(): U256ColumnBuilder> { - return new U256ColumnBuilder>( + return new U256ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): U256ColumnBuilder> { - return new U256ColumnBuilder>( + return new U256ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: bigint + ): U256ColumnBuilder> { + return new U256ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -511,41 +653,45 @@ export class I8Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I8); } - index( - algorithm?: N - ): I8ColumnBuilder> { - return new I8ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): I8ColumnBuilder>; + index>( + algorithm: N + ): I8ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I8ColumnBuilder> { + return new I8ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): I8ColumnBuilder> { - return new I8ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new I8ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): I8ColumnBuilder> { - return new I8ColumnBuilder>( + return new I8ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): I8ColumnBuilder> { - return new I8ColumnBuilder>( + return new I8ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: number + ): I8ColumnBuilder> { + return new I8ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -556,41 +702,45 @@ export class I16Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I16); } - index( - algorithm?: N - ): I16ColumnBuilder> { - return new I16ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): I16ColumnBuilder>; + index>( + algorithm: N + ): I16ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I16ColumnBuilder> { + return new I16ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): I16ColumnBuilder> { - return new I16ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new I16ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): I16ColumnBuilder> { - return new I16ColumnBuilder>( + return new I16ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): I16ColumnBuilder> { - return new I16ColumnBuilder>( + return new I16ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: number + ): I16ColumnBuilder> { + return new I16ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -598,44 +748,49 @@ export class I16Builder export class I32Builder extends TypeBuilder implements + TypeBuilder, Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I32); } - index( - algorithm?: N - ): I32ColumnBuilder> { - return new I32ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): I32ColumnBuilder>; + index>( + algorithm: N + ): I32ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I32ColumnBuilder> { + return new I32ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): I32ColumnBuilder> { - return new I32ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new I32ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): I32ColumnBuilder> { - return new I32ColumnBuilder>( + return new I32ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): I32ColumnBuilder> { - return new I32ColumnBuilder>( + return new I32ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: number + ): I32ColumnBuilder> { + return new I32ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -646,41 +801,45 @@ export class I64Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I64); } - index( - algorithm?: N - ): I64ColumnBuilder> { - return new I64ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): I64ColumnBuilder>; + index>( + algorithm: N + ): I64ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I64ColumnBuilder> { + return new I64ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): I64ColumnBuilder> { - return new I64ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new I64ColumnBuilder(this, set(defaultMetadata, { isUnique: true })); } primaryKey(): I64ColumnBuilder> { - return new I64ColumnBuilder>( + return new I64ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): I64ColumnBuilder> { - return new I64ColumnBuilder>( + return new I64ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: bigint + ): I64ColumnBuilder> { + return new I64ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -691,41 +850,48 @@ export class I128Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I128); } - index( - algorithm?: N - ): I128ColumnBuilder> { - return new I128ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): I128ColumnBuilder>; + index>( + algorithm: N + ): I128ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I128ColumnBuilder> { + return new I128ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): I128ColumnBuilder> { - return new I128ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new I128ColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); } primaryKey(): I128ColumnBuilder> { - return new I128ColumnBuilder>( + return new I128ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): I128ColumnBuilder> { - return new I128ColumnBuilder>( + return new I128ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: bigint + ): I128ColumnBuilder> { + return new I128ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -736,55 +902,84 @@ export class I256Builder Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { constructor() { super(AlgebraicType.I256); } - index( - algorithm?: N - ): I256ColumnBuilder> { - return new I256ColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): I256ColumnBuilder>; + index>( + algorithm: N + ): I256ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I256ColumnBuilder> { + return new I256ColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): I256ColumnBuilder> { - return new I256ColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new I256ColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); } primaryKey(): I256ColumnBuilder> { - return new I256ColumnBuilder>( + return new I256ColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) ); } autoInc(): I256ColumnBuilder> { - return new I256ColumnBuilder>( + return new I256ColumnBuilder( this, - { - ...defaultMetadata, - isAutoIncrement: true, - } + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: bigint + ): I256ColumnBuilder> { + return new I256ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } -export class F32Builder extends TypeBuilder { +export class F32Builder + extends TypeBuilder + implements Defaultable +{ constructor() { super(AlgebraicType.F32); } + default( + value: number + ): F32ColumnBuilder> { + return new F32ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) + ); + } } -export class F64Builder extends TypeBuilder { +export class F64Builder + extends TypeBuilder + implements Defaultable +{ constructor() { super(AlgebraicType.F64); } + default( + value: number + ): F64ColumnBuilder> { + return new F64ColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) + ); + } } export class BoolBuilder @@ -792,32 +987,42 @@ export class BoolBuilder implements Indexable, Uniqueable, - PrimaryKeyable + PrimaryKeyable, + Defaultable { constructor() { super(AlgebraicType.Bool); } - index( - algorithm?: N - ): BoolColumnBuilder> { - return new BoolColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): BoolColumnBuilder>; + index>( + algorithm: N + ): BoolColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): BoolColumnBuilder> { + return new BoolColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): BoolColumnBuilder> { - return new BoolColumnBuilder>(this, { - ...defaultMetadata, - isUnique: true, - }); + return new BoolColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); } primaryKey(): BoolColumnBuilder> { - return new BoolColumnBuilder>( + return new BoolColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) + ); + } + default( + value: boolean + ): BoolColumnBuilder> { + return new BoolColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -827,47 +1032,55 @@ export class StringBuilder implements Indexable, Uniqueable, - PrimaryKeyable + PrimaryKeyable, + Defaultable { constructor() { super(AlgebraicType.String); } - index( - algorithm?: N - ): StringColumnBuilder> { - return new StringColumnBuilder>(this, { - ...defaultMetadata, - indexType: algorithm, - }); + index(): StringColumnBuilder>; + index>( + algorithm: N + ): StringColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): StringColumnBuilder> { + return new StringColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); } unique(): StringColumnBuilder> { - return new StringColumnBuilder>( + return new StringColumnBuilder( this, - { - ...defaultMetadata, - isUnique: true, - } + set(defaultMetadata, { isUnique: true }) ); } primaryKey(): StringColumnBuilder< Set > { - return new StringColumnBuilder>( + return new StringColumnBuilder( this, - { - ...defaultMetadata, - isPrimaryKey: true, - } + set(defaultMetadata, { isPrimaryKey: true }) + ); + } + default( + value: string + ): StringColumnBuilder> { + return new StringColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } -export class ArrayBuilder< - Element extends TypeBuilder, -> extends TypeBuilder< - Array, - { tag: 'Array'; value: Element['spacetimeType'] } -> { +export class ArrayBuilder> + extends TypeBuilder< + Array>, + { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder } + > + implements Defaultable>, any> +{ /** * The phantom element type of the array for TypeScript */ @@ -876,21 +1089,66 @@ export class ArrayBuilder< constructor(element: Element) { super(AlgebraicType.Array(element.algebraicType)); } + default( + value: Array> + ): ArrayColumnBuilder> { + return new ArrayColumnBuilder( + this.element, + set(defaultMetadata, { defaultValue: value }) + ); + } } -export class ProductBuilder extends TypeBuilder< - TypeScriptTypeFromElementsObj, - { - tag: 'Product'; - value: { elements: ElementsArrayFromElementsObj }; - } -> { +export class OptionBuilder> + extends TypeBuilder< + InferTypeOfTypeBuilder | undefined, + OptionAlgebraicType + > + implements + Defaultable | undefined, OptionAlgebraicType> +{ /** - * The phantom element types of the product for TypeScript + * The phantom value type of the option for TypeScript */ - readonly elements!: Elements; + readonly value!: Value; + + constructor(value: Value) { + let innerType: AlgebraicType; + if (value instanceof ColumnBuilder) { + innerType = value.typeBuilder.algebraicType; + } else { + innerType = value.algebraicType; + } + super(Option.getAlgebraicType(innerType)); + } + default( + value: InferTypeOfTypeBuilder | undefined + ): OptionColumnBuilder< + InferTypeOfTypeBuilder, + Set< + DefaultMetadata, + 'defaultValue', + InferTypeOfTypeBuilder | undefined + > + > { + return new OptionColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) + ); + } +} - constructor(elements: Elements) { +export class ProductBuilder + extends TypeBuilder< + ObjectType, + { + tag: 'Product'; + value: { elements: ElementsArrayFromElementsObj }; + } + > + implements Defaultable, any> +{ + constructor(elements: Elements, name?: string) { function elementsArrayFromElementsObj(obj: Obj) { return Object.entries(obj).map(([name, { algebraicType }]) => ({ name, @@ -898,35 +1156,356 @@ export class ProductBuilder extends TypeBuilder< })); } super( - AlgebraicType.Product({ - elements: elementsArrayFromElementsObj(elements), - }) + addType( + name, + AlgebraicType.Product({ + elements: elementsArrayFromElementsObj(elements), + }) + ) + ); + } + default( + value: ObjectType + ): ProductColumnBuilder> { + return new ProductColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } -export class SumBuilder extends TypeBuilder< - TypeScriptTypeFromVariantsObj, - { tag: 'Sum'; value: { variants: VariantsArrayFromVariantsObj } } +export class RowBuilder extends TypeBuilder< + RowType, + { + tag: 'Product'; + value: { elements: ElementsArrayFromRowObj }; + } > { - /** - * The phantom variant types of the sum for TypeScript - */ - readonly variants!: Variants; + row: CoerceRow; + constructor(row: Row) { + const mappedRow = Object.fromEntries( + Object.entries(row).map(([name, builder]) => [ + name, + builder instanceof ColumnBuilder + ? builder + : new ColumnBuilder(builder, {}), + ]) + ) as CoerceRow; + + const elements = Object.entries(mappedRow).map(([name, builder]) => ({ + name, + algebraicType: builder.typeBuilder.algebraicType, + })) as ElementsArrayFromRowObj; + + super(addType(undefined, AlgebraicType.Product({ elements }))); + + this.row = mappedRow; + } +} - constructor(variants: Variants) { +export class SumBuilder extends TypeBuilder< + EnumType, + { tag: 'Sum'; value: { variants: VariantsArrayFromVariantsObj } } +> { + constructor(variants: Variants, name?: string) { function variantsArrayFromVariantsObj( variants: Variants - ): SumTypeVariant[] { + ) { return Object.entries(variants).map(([name, { algebraicType }]) => ({ name, algebraicType, })); } super( - AlgebraicType.Sum({ - variants: variantsArrayFromVariantsObj(variants), - }) + addType( + name, + AlgebraicType.Sum({ + variants: variantsArrayFromVariantsObj(variants), + }) + ) + ); + } + default( + value: EnumType + ): SumColumnBuilder> { + return new SumColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) + ); + } +} + +export class SimpleSumBuilder + extends SumBuilder + implements + Indexable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + >, + PrimaryKeyable< + EnumType, + { + tag: 'Sum'; + value: { variants: VariantsArrayFromVariantsObj }; + } + > +{ + index(): SimpleSumColumnBuilder< + Variants, + Set + >; + index>( + algorithm: N + ): SimpleSumColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): SimpleSumColumnBuilder< + Variants, + Set + > { + return new SimpleSumColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); + } + primaryKey(): SimpleSumColumnBuilder< + Variants, + Set + > { + return new SimpleSumColumnBuilder( + this, + set(defaultMetadata, { isPrimaryKey: true }) + ); + } +} + +export class IdentityBuilder + extends TypeBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + constructor() { + super(Identity.getAlgebraicType()); + } + index(): IdentityColumnBuilder>; + index>( + algorithm: N + ): IdentityColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): IdentityColumnBuilder> { + return new IdentityColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); + } + unique(): IdentityColumnBuilder> { + return new IdentityColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); + } + primaryKey(): IdentityColumnBuilder< + Set + > { + return new IdentityColumnBuilder( + this, + set(defaultMetadata, { isPrimaryKey: true }) + ); + } + autoInc(): IdentityColumnBuilder< + Set + > { + return new IdentityColumnBuilder( + this, + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: Identity + ): IdentityColumnBuilder> { + return new IdentityColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) + ); + } +} + +export class ConnectionIdBuilder + extends TypeBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + constructor() { + super(ConnectionId.getAlgebraicType()); + } + index(): ConnectionIdColumnBuilder< + Set + >; + index>( + algorithm: N + ): ConnectionIdColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): ConnectionIdColumnBuilder> { + return new ConnectionIdColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); + } + unique(): ConnectionIdColumnBuilder> { + return new ConnectionIdColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); + } + primaryKey(): ConnectionIdColumnBuilder< + Set + > { + return new ConnectionIdColumnBuilder( + this, + set(defaultMetadata, { isPrimaryKey: true }) + ); + } + autoInc(): ConnectionIdColumnBuilder< + Set + > { + return new ConnectionIdColumnBuilder( + this, + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: ConnectionId + ): ConnectionIdColumnBuilder< + Set + > { + return new ConnectionIdColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) + ); + } +} + +export class TimestampBuilder + extends TypeBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + constructor() { + super(Timestamp.getAlgebraicType()); + } + index(): TimestampColumnBuilder>; + index>( + algorithm: N + ): TimestampColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): TimestampColumnBuilder> { + return new TimestampColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); + } + unique(): TimestampColumnBuilder> { + return new TimestampColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); + } + primaryKey(): TimestampColumnBuilder< + Set + > { + return new TimestampColumnBuilder( + this, + set(defaultMetadata, { isPrimaryKey: true }) + ); + } + autoInc(): TimestampColumnBuilder< + Set + > { + return new TimestampColumnBuilder( + this, + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: Timestamp + ): TimestampColumnBuilder> { + return new TimestampColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) + ); + } +} + +export class TimeDurationBuilder + extends TypeBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + constructor() { + super(TimeDuration.getAlgebraicType()); + } + index(): TimeDurationColumnBuilder< + Set + >; + index>( + algorithm: N + ): TimeDurationColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): TimeDurationColumnBuilder> { + return new TimeDurationColumnBuilder( + this, + set(defaultMetadata, { indexType: algorithm }) + ); + } + unique(): TimeDurationColumnBuilder> { + return new TimeDurationColumnBuilder( + this, + set(defaultMetadata, { isUnique: true }) + ); + } + primaryKey(): TimeDurationColumnBuilder< + Set + > { + return new TimeDurationColumnBuilder( + this, + set(defaultMetadata, { isPrimaryKey: true }) + ); + } + autoInc(): TimeDurationColumnBuilder< + Set + > { + return new TimeDurationColumnBuilder( + this, + set(defaultMetadata, { isAutoIncrement: true }) + ); + } + default( + value: TimeDuration + ): TimeDurationColumnBuilder< + Set + > { + return new TimeDurationColumnBuilder( + this, + set(defaultMetadata, { defaultValue: value }) ); } } @@ -935,17 +1514,18 @@ export class SumBuilder extends TypeBuilder< * The type of index types that can be applied to a column. * `undefined` is the default */ -type IndexTypes = 'btree' | 'hash' | undefined; +export type IndexTypes = 'btree' | 'direct' | undefined; /** * Metadata describing column constraints and index type */ -export type ColumnMetadata = { +export type ColumnMetadata = { isPrimaryKey?: true; isUnique?: true; isAutoIncrement?: true; isScheduleAt?: true; indexType?: IndexTypes; + defaultValue?: Type; }; /** @@ -956,7 +1536,7 @@ type DefaultMetadata = object; /** * Default metadata state value for a newly created column */ -const defaultMetadata: DefaultMetadata = {}; +const defaultMetadata: ColumnMetadata = {}; /** * A column builder allows you to incrementally specify constraints @@ -968,625 +1548,1028 @@ const defaultMetadata: DefaultMetadata = {}; export class ColumnBuilder< Type, SpacetimeType extends AlgebraicType, - M extends ColumnMetadata = DefaultMetadata, + M extends ColumnMetadata = DefaultMetadata, > { - /** - * The TypeScript phantom type. This is not stored at runtime, - * but is visible to the compiler - */ - readonly columnMetadataType!: M; - typeBuilder: TypeBuilder; - columnMetadata: ColumnMetadata; + columnMetadata: M; - constructor( - typeBuilder: TypeBuilder, - metadata?: ColumnMetadata - ) { + constructor(typeBuilder: TypeBuilder, metadata: M) { this.typeBuilder = typeBuilder; - this.columnMetadata = metadata ?? defaultMetadata; + this.columnMetadata = metadata; } } -export class U8ColumnBuilder +export class U8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): U8ColumnBuilder> { - return new U8ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): U8ColumnBuilder>; + index>( + algorithm: N + ): U8ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U8ColumnBuilder> { + return new U8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): U8ColumnBuilder> { - return new U8ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new U8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): U8ColumnBuilder> { - return new U8ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isPrimaryKey: true, - }); + return new U8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isPrimaryKey: true }) + ); } autoInc(): U8ColumnBuilder> { - return new U8ColumnBuilder>( + return new U8ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: number): U8ColumnBuilder> { + return new U8ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class U16ColumnBuilder +export class U16ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): U16ColumnBuilder> { - return new U16ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): U16ColumnBuilder>; + index>( + algorithm: N + ): U16ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U16ColumnBuilder> { + return new U16ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): U16ColumnBuilder> { - return new U16ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new U16ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): U16ColumnBuilder> { - return new U16ColumnBuilder>( + return new U16ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): U16ColumnBuilder> { - return new U16ColumnBuilder>( + return new U16ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: number): U16ColumnBuilder> { + return new U16ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class U32ColumnBuilder +export class U32ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): U32ColumnBuilder> { - return new U32ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): U32ColumnBuilder>; + index>( + algorithm: N + ): U32ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U32ColumnBuilder> { + return new U32ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): U32ColumnBuilder> { - return new U32ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new U32ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): U32ColumnBuilder> { - return new U32ColumnBuilder>( + return new U32ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): U32ColumnBuilder> { - return new U32ColumnBuilder>( + return new U32ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: number): U32ColumnBuilder> { + return new U32ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class U64ColumnBuilder +export class U64ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): U64ColumnBuilder> { - return new U64ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): U64ColumnBuilder>; + index>( + algorithm: N + ): U64ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U64ColumnBuilder> { + return new U64ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): U64ColumnBuilder> { - return new U64ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new U64ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): U64ColumnBuilder> { - return new U64ColumnBuilder>( + return new U64ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): U64ColumnBuilder> { - return new U64ColumnBuilder>( + return new U64ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: bigint): U64ColumnBuilder> { + return new U64ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class U128ColumnBuilder +export class U128ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): U128ColumnBuilder> { - return new U128ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): U128ColumnBuilder>; + index>( + algorithm: N + ): U128ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U128ColumnBuilder> { + return new U128ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): U128ColumnBuilder> { - return new U128ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new U128ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): U128ColumnBuilder> { - return new U128ColumnBuilder>( + return new U128ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): U128ColumnBuilder> { - return new U128ColumnBuilder>( + return new U128ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: bigint): U128ColumnBuilder> { + return new U128ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class U256ColumnBuilder +export class U256ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): U256ColumnBuilder> { - return new U256ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): U256ColumnBuilder>; + index>( + algorithm: N + ): U256ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): U256ColumnBuilder> { + return new U256ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): U256ColumnBuilder> { - return new U256ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new U256ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): U256ColumnBuilder> { - return new U256ColumnBuilder>( + return new U256ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): U256ColumnBuilder> { - return new U256ColumnBuilder>( + return new U256ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: bigint): U256ColumnBuilder> { + return new U256ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class I8ColumnBuilder +export class I8ColumnBuilder = DefaultMetadata> extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): I8ColumnBuilder> { - return new I8ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): I8ColumnBuilder>; + index>( + algorithm: N + ): I8ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I8ColumnBuilder> { + return new I8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): I8ColumnBuilder> { - return new I8ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new I8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): I8ColumnBuilder> { - return new I8ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isPrimaryKey: true, - }); + return new I8ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isPrimaryKey: true }) + ); } autoInc(): I8ColumnBuilder> { - return new I8ColumnBuilder>( + return new I8ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: number): I8ColumnBuilder> { + return new I8ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class I16ColumnBuilder +export class I16ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): I16ColumnBuilder> { - return new I16ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): I16ColumnBuilder>; + index>( + algorithm: N + ): I16ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I16ColumnBuilder> { + return new I16ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): I16ColumnBuilder> { - return new I16ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new I16ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): I16ColumnBuilder> { - return new I16ColumnBuilder>( + return new I16ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): I16ColumnBuilder> { - return new I16ColumnBuilder>( + return new I16ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: number): I16ColumnBuilder> { + return new I16ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class I32ColumnBuilder +export class I32ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): I32ColumnBuilder> { - return new I32ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): I32ColumnBuilder>; + index>( + algorithm: N + ): I32ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I32ColumnBuilder> { + return new I32ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): I32ColumnBuilder> { - return new I32ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new I32ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): I32ColumnBuilder> { - return new I32ColumnBuilder>( + return new I32ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): I32ColumnBuilder> { - return new I32ColumnBuilder>( + return new I32ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: number): I32ColumnBuilder> { + return new I32ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class I64ColumnBuilder +export class I64ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): I64ColumnBuilder> { - return new I64ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): I64ColumnBuilder>; + index>( + algorithm: N + ): I64ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I64ColumnBuilder> { + return new I64ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): I64ColumnBuilder> { - return new I64ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new I64ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): I64ColumnBuilder> { - return new I64ColumnBuilder>( + return new I64ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): I64ColumnBuilder> { - return new I64ColumnBuilder>( + return new I64ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: bigint): I64ColumnBuilder> { + return new I64ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class I128ColumnBuilder +export class I128ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index< - M extends ColumnMetadata = DefaultMetadata, - N extends IndexTypes = 'btree', - >(algorithm?: N): I128ColumnBuilder> { - return new I128ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): I128ColumnBuilder>; + index>( + algorithm: N + ): I128ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I128ColumnBuilder> { + return new I128ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): I128ColumnBuilder> { - return new I128ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new I128ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): I128ColumnBuilder> { - return new I128ColumnBuilder>( + return new I128ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): I128ColumnBuilder> { - return new I128ColumnBuilder>( + return new I128ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: bigint): I128ColumnBuilder> { + return new I128ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class I256ColumnBuilder +export class I256ColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, PrimaryKeyable, - AutoIncrementable + AutoIncrementable, + Defaultable { - index( - algorithm?: N - ): I256ColumnBuilder> { - return new I256ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): I256ColumnBuilder>; + index>( + algorithm: N + ): I256ColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): I256ColumnBuilder> { + return new I256ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): I256ColumnBuilder> { - return new I256ColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new I256ColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): I256ColumnBuilder> { - return new I256ColumnBuilder>( + return new I256ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } autoInc(): I256ColumnBuilder> { - return new I256ColumnBuilder>( + return new I256ColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isAutoIncrement: true, - } + set(this.columnMetadata, { isAutoIncrement: true }) ); } + default(value: bigint): I256ColumnBuilder> { + return new I256ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } export class F32ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> extends ColumnBuilder {} + M extends ColumnMetadata = DefaultMetadata, + > + extends ColumnBuilder + implements Defaultable +{ + default(value: number): F32ColumnBuilder> { + return new F32ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} + export class F64ColumnBuilder< - M extends ColumnMetadata = DefaultMetadata, -> extends ColumnBuilder {} -export class BoolColumnBuilder + M extends ColumnMetadata = DefaultMetadata, + > + extends ColumnBuilder + implements Defaultable +{ + default(value: number): F64ColumnBuilder> { + return new F64ColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} + +export class BoolColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, - PrimaryKeyable + PrimaryKeyable, + Defaultable { - index< - M extends ColumnMetadata = DefaultMetadata, - N extends IndexTypes = 'btree', - >(algorithm?: N): BoolColumnBuilder> { - return new BoolColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): BoolColumnBuilder>; + index>( + algorithm: N + ): BoolColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): BoolColumnBuilder> { + return new BoolColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): BoolColumnBuilder> { - return new BoolColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new BoolColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): BoolColumnBuilder> { - return new BoolColumnBuilder>( + return new BoolColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } + default(value: boolean): BoolColumnBuilder> { + return new BoolColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } -export class StringColumnBuilder +export class StringColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > extends ColumnBuilder implements Indexable, Uniqueable, - PrimaryKeyable + PrimaryKeyable, + Defaultable { - index< - M extends ColumnMetadata = DefaultMetadata, - N extends IndexTypes = 'btree', - >(algorithm?: N): StringColumnBuilder> { - return new StringColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - indexType: algorithm, - }); + index(): StringColumnBuilder>; + index>( + algorithm: N + ): StringColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): StringColumnBuilder> { + return new StringColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); } unique(): StringColumnBuilder> { - return new StringColumnBuilder>(this.typeBuilder, { - ...this.columnMetadata, - isUnique: true, - }); + return new StringColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); } primaryKey(): StringColumnBuilder> { - return new StringColumnBuilder>( + return new StringColumnBuilder( this.typeBuilder, - { - ...this.columnMetadata, - isPrimaryKey: true, - } + set(this.columnMetadata, { isPrimaryKey: true }) ); } + default(value: string): StringColumnBuilder> { + return new StringColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } } export class ArrayColumnBuilder< - Element extends TypeBuilder, - M extends ColumnMetadata = DefaultMetadata, -> extends ColumnBuilder< - Array, - { tag: 'Array'; value: Element['spacetimeType'] }, - M -> {} + Element extends TypeBuilder, + M extends ColumnMetadata< + Array> + > = DefaultMetadata, + > + extends ColumnBuilder< + Array>, + { tag: 'Array'; value: InferSpacetimeTypeOfTypeBuilder }, + M + > + implements + Defaultable< + Array>, + AlgebraicTypeVariants.Array + > +{ + default( + value: Array> + ): ArrayColumnBuilder< + Element, + Set>> + > { + return new ArrayColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} + +export class OptionColumnBuilder< + Value extends TypeBuilder, + M extends ColumnMetadata< + InferTypeOfTypeBuilder | undefined + > = DefaultMetadata, + > + extends ColumnBuilder< + InferTypeOfTypeBuilder | undefined, + OptionAlgebraicType, + M + > + implements + Defaultable | undefined, OptionAlgebraicType> +{ + default( + value: InferTypeOfTypeBuilder | undefined + ): OptionColumnBuilder< + InferTypeOfTypeBuilder, + Set | undefined> + > { + return new OptionColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} export class ProductColumnBuilder< - Elements extends Array<{ name: string; algebraicType: AlgebraicType }>, - M extends ColumnMetadata = DefaultMetadata, -> extends ColumnBuilder< - { [K in Elements[number]['name']]: any }, - { tag: 'Product'; value: { elements: Elements } }, - M -> {} + Elements extends ElementsObj, + M extends ColumnMetadata> = DefaultMetadata, + > + extends ColumnBuilder< + ObjectType, + { + tag: 'Product'; + value: { elements: ElementsArrayFromElementsObj }; + }, + M + > + implements Defaultable, AlgebraicTypeVariants.Product> +{ + default( + value: ObjectType + ): ProductColumnBuilder> { + return new ProductColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { defaultValue: value }) + ); + } +} export class SumColumnBuilder< - Variants extends Array<{ name: string; algebraicType: AlgebraicType }>, - M extends ColumnMetadata = DefaultMetadata, -> extends ColumnBuilder< - { - [K in Variants[number]['name']]: { tag: K; value: any }; - }[Variants[number]['name']], - { tag: 'Sum'; value: { variants: Variants } }, - M -> {} + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, + > + extends ColumnBuilder< + EnumType, + { tag: 'Sum'; value: { variants: VariantsArrayFromVariantsObj } }, + M + > + implements Defaultable, AlgebraicTypeVariants.Sum> +{ + default( + value: EnumType + ): SumColumnBuilder> { + return new SumColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { defaultValue: value }) + ); + } +} + +export class SimpleSumColumnBuilder< + Variants extends VariantsObj, + M extends ColumnMetadata> = DefaultMetadata, + > + extends SumColumnBuilder + implements + Indexable, AlgebraicTypeVariants.Sum>, + PrimaryKeyable, AlgebraicTypeVariants.Sum> +{ + index(): SimpleSumColumnBuilder< + Variants, + Set + >; + index>( + algorithm: N + ): SimpleSumColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): SimpleSumColumnBuilder< + Variants, + Set + > { + return new SimpleSumColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); + } + primaryKey(): SimpleSumColumnBuilder< + Variants, + Set + > { + return new SimpleSumColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isPrimaryKey: true }) + ); + } +} + +export class IdentityColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > + extends ColumnBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + index(): IdentityColumnBuilder>; + index>( + algorithm: N + ): IdentityColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): IdentityColumnBuilder> { + return new IdentityColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); + } + unique(): IdentityColumnBuilder> { + return new IdentityColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); + } + primaryKey(): IdentityColumnBuilder> { + return new IdentityColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isPrimaryKey: true }) + ); + } + default( + value: Identity + ): IdentityColumnBuilder> { + return new IdentityColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} + +export class ConnectionIdColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > + extends ColumnBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + index(): ConnectionIdColumnBuilder>; + index>( + algorithm: N + ): ConnectionIdColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): ConnectionIdColumnBuilder> { + return new ConnectionIdColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); + } + unique(): ConnectionIdColumnBuilder> { + return new ConnectionIdColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); + } + primaryKey(): ConnectionIdColumnBuilder> { + return new ConnectionIdColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isPrimaryKey: true }) + ); + } + default( + value: ConnectionId + ): ConnectionIdColumnBuilder> { + return new ConnectionIdColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} + +export class TimestampColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > + extends ColumnBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + index(): TimestampColumnBuilder>; + index>( + algorithm: N + ): TimestampColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): TimestampColumnBuilder> { + return new TimestampColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); + } + unique(): TimestampColumnBuilder> { + return new TimestampColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); + } + primaryKey(): TimestampColumnBuilder> { + return new TimestampColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isPrimaryKey: true }) + ); + } + default( + value: Timestamp + ): TimestampColumnBuilder> { + return new TimestampColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} + +export class TimeDurationColumnBuilder< + M extends ColumnMetadata = DefaultMetadata, + > + extends ColumnBuilder + implements + Indexable, + Uniqueable, + PrimaryKeyable, + Defaultable +{ + index(): TimeDurationColumnBuilder>; + index>( + algorithm: N + ): TimeDurationColumnBuilder>; + index( + algorithm: IndexTypes = 'btree' + ): TimeDurationColumnBuilder> { + return new TimeDurationColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { indexType: algorithm }) + ); + } + unique(): TimeDurationColumnBuilder> { + return new TimeDurationColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isUnique: true }) + ); + } + primaryKey(): TimeDurationColumnBuilder> { + return new TimeDurationColumnBuilder( + this.typeBuilder, + set(this.columnMetadata, { isPrimaryKey: true }) + ); + } + default( + value: TimeDuration + ): TimeDurationColumnBuilder> { + return new TimeDurationColumnBuilder(this.typeBuilder, { + ...this.columnMetadata, + defaultValue: value, + }); + } +} /** * A collection of factory functions for creating various SpacetimeDB algebraic types @@ -1605,7 +2588,7 @@ export class SumColumnBuilder< * * @see {@link TypeBuilder} */ -const t = { +export const t = { /** * Creates a new `Bool` {@link AlgebraicType} to be used in table definitions * Represented as `boolean` in TypeScript. @@ -1730,12 +2713,46 @@ const t = { * are essentially the same as objects in JavaScript/TypeScript. * Properties of the object must also be {@link TypeBuilder}s. * Represented as an object with specific properties in TypeScript. + * + * @param name (optional) A display name for the product type. If omitted, an anonymous product type is created. * @param obj The object defining the properties of the type, whose property * values must be {@link TypeBuilder}s. - * @returns A new {@link ProductBuilder} instance + * @returns A new {@link ProductBuilder} instance. */ - object(obj: Obj): ProductBuilder { - return new ProductBuilder(obj); + object: ((nameOrObj: any, maybeObj?: any) => { + if (typeof nameOrObj === 'string') { + if (!maybeObj) { + throw new TypeError( + 'When providing a name, you must also provide the object.' + ); + } + return new ProductBuilder(maybeObj, nameOrObj); + } + return new ProductBuilder(nameOrObj, undefined); + }) as { + (name: string, obj: Obj): ProductBuilder; + // TODO: Currently names are not optional + // (obj: Obj): ProductBuilder; + }, + + /** + * Creates a new `Row` {@link AlgebraicType} to be used in table definitions. Row types in SpacetimeDB + * are similar to `Product` types, but are specifically used to define the schema of a table row. + * Properties of the object must also be {@link TypeBuilder} or {@link ColumnBuilder}s. + * + * You can represent a `Row` as either a {@link RowObj} or an {@link RowBuilder} type when + * defining a table schema. + * + * The {@link RowBuilder} type is useful when you want to create a type which can be used anywhere + * a {@link TypeBuilder} is accepted, such as in nested objects or arrays, or as the argument + * to a scheduled function. + * + * @param obj The object defining the properties of the row, whose property + * values must be {@link TypeBuilder}s or {@link ColumnBuilder}s. + * @returns A new {@link RowBuilder} instance + */ + row(obj: Obj): RowBuilder { + return new RowBuilder(obj); }, /** @@ -1747,7 +2764,7 @@ const t = { array>( e: Element ): ArrayBuilder { - return new ArrayBuilder(e); + return new ArrayBuilder(e); }, /** @@ -1755,12 +2772,50 @@ const t = { * are similar to enums or unions in languages like Rust or TypeScript respectively. * Each variant of the enum must be a {@link TypeBuilder}. * Represented as a union of string literals in TypeScript. + * + * @param name (optional) A display name for the sum type. If omitted, an anonymous sum type is created. * @param obj The object defining the variants of the enum, whose variant - * types must be `TypeBuilder`s. - * @returns A new {@link SumBuilder} instance + * types must be {@link TypeBuilder}s. + * @returns A new {@link SumBuilder} instance. + */ + enum: ((nameOrObj: any, maybeObj?: any) => { + let obj: VariantsObj = nameOrObj; + let name: string | undefined = undefined; + if (typeof nameOrObj === 'string') { + if (!maybeObj) { + throw new TypeError( + 'When providing a name, you must also provide the variants object.' + ); + } + obj = maybeObj; + name = nameOrObj; + } + if ( + Object.values(obj).every(x => { + const ty: AlgebraicType = x.resolveType(); + return ty.tag === 'Product' && ty.value.elements.length === 0; + }) + ) { + return new SimpleSumBuilder(obj as SimpleVariantsObj, name); + } + return new SumBuilder(obj, name); + }) as { + ( + name: string, + obj: Obj + ): SimpleSumBuilder; + (name: string, obj: Obj): SumBuilder; + // TODO: Currently names are not optional + // (obj: Obj): SumBuilder; + }, + + /** + * This is a special helper function for conveniently creating {@link Product} type columns with no fields. + * + * @returns A new {@link ProductBuilder} instance with no fields. */ - enum(obj: Obj): SumBuilder { - return new SumBuilder(obj); + unit(): UnitBuilder { + return new ProductBuilder({}); }, /** @@ -1770,37 +2825,33 @@ const t = { scheduleAt: (): ColumnBuilder< ScheduleAt, ReturnType, - Omit & { isScheduleAt: true } + Omit, 'isScheduleAt'> & { isScheduleAt: true } > => { - return new ColumnBuilder< - ScheduleAt, - ReturnType, - Omit & { isScheduleAt: true } - >( - new TypeBuilder< - ScheduleAt, - ReturnType - >(ScheduleAt.getAlgebraicType()), - { - ...defaultMetadata, - isScheduleAt: true, - } + return new ColumnBuilder( + new TypeBuilder(ScheduleAt.getAlgebraicType()), + set(defaultMetadata, { isScheduleAt: true }) ); }, + /** + * This is a convenience method for creating a column with the {@link Option} type. + * You can create a column of the same type by constructing an enum with a `some` and `none` variant. + * @param value The type of the value contained in the `some` variant of the `Option`. + * @returns A new {@link OptionBuilder} instance with the {@link Option} type. + */ + option>( + value: Value + ): OptionBuilder { + return new OptionBuilder(value); + }, + /** * This is a convenience method for creating a column with the {@link Identity} type. * You can create a column of the same type by constructing an `object` with a single `__identity__` element. * @returns A new {@link TypeBuilder} instance with the {@link Identity} type. */ - identity: (): TypeBuilder< - Identity, - AlgebraicTypeVariants.Product & { value: typeof Identity } - > => { - return new TypeBuilder< - Identity, - AlgebraicTypeVariants.Product & { value: typeof Identity } - >(Identity.getAlgebraicType()); + identity: (): IdentityBuilder => { + return new IdentityBuilder(); }, /** @@ -1808,14 +2859,8 @@ const t = { * You can create a column of the same type by constructing an `object` with a single `__connection_id__` element. * @returns A new {@link TypeBuilder} instance with the {@link ConnectionId} type. */ - connectionId: (): TypeBuilder< - string, - AlgebraicTypeVariants.Product & { value: typeof ConnectionId } - > => { - return new TypeBuilder< - string, - AlgebraicTypeVariants.Product & { value: typeof ConnectionId } - >(ConnectionId.getAlgebraicType()); + connectionId: (): ConnectionIdBuilder => { + return new ConnectionIdBuilder(); }, /** @@ -1823,14 +2868,8 @@ const t = { * You can create a column of the same type by constructing an `object` with a single `__timestamp_micros_since_unix_epoch__` element. * @returns A new {@link TypeBuilder} instance with the {@link Timestamp} type. */ - timestamp: (): TypeBuilder< - Timestamp, - AlgebraicTypeVariants.Product & { value: typeof Timestamp } - > => { - return new TypeBuilder< - Timestamp, - AlgebraicTypeVariants.Product & { value: typeof Timestamp } - >(Timestamp.getAlgebraicType()); + timestamp: (): TimestampBuilder => { + return new TimestampBuilder(); }, /** @@ -1838,14 +2877,8 @@ const t = { * You can create a column of the same type by constructing an `object` with a single `__time_duration_micros__` element. * @returns A new {@link TypeBuilder} instance with the {@link TimeDuration} type. */ - timeDuration: (): TypeBuilder< - TimeDuration, - AlgebraicTypeVariants.Product & { value: typeof TimeDuration } - > => { - return new TypeBuilder< - TimeDuration, - AlgebraicTypeVariants.Product & { value: typeof TimeDuration } - >(TimeDuration.getAlgebraicType()); + timeDuration: (): TimeDurationBuilder => { + return new TimeDurationBuilder(); }, } as const; export default t; diff --git a/crates/bindings-typescript/src/server/type_util.ts b/crates/bindings-typescript/src/server/type_util.ts index b2c7192b69b..4febb2c11c8 100644 --- a/crates/bindings-typescript/src/server/type_util.ts +++ b/crates/bindings-typescript/src/server/type_util.ts @@ -10,15 +10,25 @@ export type Set = Prettify< Omit & { [K in F]: V } >; -type Equals = - (() => T extends A ? 1 : 2) extends () => T extends B ? 1 : 2 - ? true - : false; +/** + * Sets a field in an object + * @param x The original object + * @param t The object containing the field to set + * @returns A new object with the field set + */ +export function set( + x: T, + t: { [k in F]: V } +): Set { + return { ...x, ...t }; +} -export type DifferenceFromDefault = Prettify<{ - [K in keyof T as K extends keyof D - ? Equals extends true - ? never - : K - : K]: T[K]; -}>; +/** + * Helper to extract the value types from an object type + */ +export type Values = T[keyof T]; + +/** + * A helper type to collapse a tuple into a single type if it has only one element. + */ +export type CollapseTuple = A extends [infer T] ? T : A; diff --git a/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts b/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts index c678b1a9bab..494f9eb5d1e 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/create_player_reducer.ts @@ -36,6 +36,8 @@ export type CreatePlayer = { name: string; location: Point; }; +let _cached_CreatePlayer_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,12 +47,15 @@ export const CreatePlayer = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() }, - ], + if (_cached_CreatePlayer_type_value) return _cached_CreatePlayer_type_value; + _cached_CreatePlayer_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_CreatePlayer_type_value.value.elements.push( + { name: 'name', algebraicType: __AlgebraicTypeValue.String }, + { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() } + ); + return _cached_CreatePlayer_type_value; }, serialize(writer: __BinaryWriter, value: CreatePlayer): void { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/index.ts b/crates/bindings-typescript/test-app/src/module_bindings/index.ts index 2b33de7da7a..104b8f6c14c 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/index.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/index.ts @@ -1,7 +1,7 @@ // THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. -// This was generated using ../../../src/index cli version 1.5.0 (commit 3f65da1a72997e396bacaf5b2f58a7a9f0e1feeb). +// This was generated using ../../../src/index cli version 1.5.0 (commit 5bfc84351742a6a8dc717b6c0011946f2d1b632d). /* eslint-disable */ /* tslint:disable */ diff --git a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts index 2f6b5c0dc1d..4bafe1fb1e4 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/player_type.ts @@ -36,6 +36,8 @@ export type Player = { name: string; location: Point; }; +let _cached_Player_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,13 +47,14 @@ export const Player = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'ownerId', algebraicType: __AlgebraicTypeValue.String }, - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() }, - ], - }); + if (_cached_Player_type_value) return _cached_Player_type_value; + _cached_Player_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Player_type_value.value.elements.push( + { name: 'ownerId', algebraicType: __AlgebraicTypeValue.String }, + { name: 'name', algebraicType: __AlgebraicTypeValue.String }, + { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() } + ); + return _cached_Player_type_value; }, serialize(writer: __BinaryWriter, value: Player): void { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts index 2ce084a5366..9bd08a301a1 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/point_type.ts @@ -32,6 +32,8 @@ export type Point = { x: number; y: number; }; +let _cached_Point_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -41,12 +43,13 @@ export const Point = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'x', algebraicType: __AlgebraicTypeValue.U16 }, - { name: 'y', algebraicType: __AlgebraicTypeValue.U16 }, - ], - }); + if (_cached_Point_type_value) return _cached_Point_type_value; + _cached_Point_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Point_type_value.value.elements.push( + { name: 'x', algebraicType: __AlgebraicTypeValue.U16 }, + { name: 'y', algebraicType: __AlgebraicTypeValue.U16 } + ); + return _cached_Point_type_value; }, serialize(writer: __BinaryWriter, value: Point): void { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts index e75e6ef5ba3..8f2545fa8be 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/unindexed_player_type.ts @@ -36,6 +36,8 @@ export type UnindexedPlayer = { name: string; location: Point; }; +let _cached_UnindexedPlayer_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,13 +47,17 @@ export const UnindexedPlayer = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: 'ownerId', algebraicType: __AlgebraicTypeValue.String }, - { name: 'name', algebraicType: __AlgebraicTypeValue.String }, - { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() }, - ], + if (_cached_UnindexedPlayer_type_value) + return _cached_UnindexedPlayer_type_value; + _cached_UnindexedPlayer_type_value = __AlgebraicTypeValue.Product({ + elements: [], }); + _cached_UnindexedPlayer_type_value.value.elements.push( + { name: 'ownerId', algebraicType: __AlgebraicTypeValue.String }, + { name: 'name', algebraicType: __AlgebraicTypeValue.String }, + { name: 'location', algebraicType: Point.getTypeScriptAlgebraicType() } + ); + return _cached_UnindexedPlayer_type_value; }, serialize(writer: __BinaryWriter, value: UnindexedPlayer): void { diff --git a/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts b/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts index c9375cc27a9..6fa4066b314 100644 --- a/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts +++ b/crates/bindings-typescript/test-app/src/module_bindings/user_type.ts @@ -32,6 +32,8 @@ export type User = { identity: __Identity; username: string; }; +let _cached_User_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -41,15 +43,16 @@ export const User = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { - name: 'identity', - algebraicType: __AlgebraicTypeValue.createIdentityType(), - }, - { name: 'username', algebraicType: __AlgebraicTypeValue.String }, - ], - }); + if (_cached_User_type_value) return _cached_User_type_value; + _cached_User_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_User_type_value.value.elements.push( + { + name: 'identity', + algebraicType: __AlgebraicTypeValue.createIdentityType(), + }, + { name: 'username', algebraicType: __AlgebraicTypeValue.String } + ); + return _cached_User_type_value; }, serialize(writer: __BinaryWriter, value: User): void { diff --git a/crates/bindings-typescript/test-app/tsconfig.app.json b/crates/bindings-typescript/test-app/tsconfig.app.json index 26662381ec1..563997710d1 100644 --- a/crates/bindings-typescript/test-app/tsconfig.app.json +++ b/crates/bindings-typescript/test-app/tsconfig.app.json @@ -4,7 +4,7 @@ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "target": "ES2020", "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ESNext", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, diff --git a/crates/bindings-typescript/tests/binary_read_write.test.ts b/crates/bindings-typescript/tests/binary_read_write.test.ts index 413714edc05..ecf316b56b7 100644 --- a/crates/bindings-typescript/tests/binary_read_write.test.ts +++ b/crates/bindings-typescript/tests/binary_read_write.test.ts @@ -1,5 +1,21 @@ import { describe, expect, test } from 'vitest'; -import { BinaryReader, BinaryWriter } from '../src/index'; +import { + AlgebraicType, + BinaryReader, + BinaryWriter, + ConnectionId, + TimeDuration, + Timestamp, +} from '../src/index'; +import * as ws from '../src/sdk/client_api'; +import { + anIdentity, + bobIdentity, + encodeCreatePlayerArgs, + encodeUser, + sallyIdentity, +} from './utils'; +import { ServerMessage } from '../src/sdk/client_api'; /* // Generated by the following Rust code: @@ -107,4 +123,61 @@ describe('BinaryReader/Writer', () => { expect(writer.getBuffer()).toEqual(arr); } }); + + test('correctly serializes and then deserializes a complicated web socket message', () => { + const user1 = { identity: bobIdentity, username: 'bob' }; + const user2 = { + identity: sallyIdentity, + username: 'sally', + }; + const binary = [...encodeUser(user1)].concat([...encodeUser(user2)]); + const transactionUpdate = ws.ServerMessage.TransactionUpdate({ + status: ws.UpdateStatus.Committed({ + tables: [ + { + tableId: 35, + tableName: 'user', + numRows: BigInt(1), + updates: [ + ws.CompressableQueryUpdate.Uncompressed({ + deletes: { + sizeHint: ws.RowSizeHint.FixedSize(0), // not used + rowsData: new Uint8Array([]), + }, + // FIXME: this test is evil: an initial subscription can never contain deletes or updates. + inserts: { + sizeHint: ws.RowSizeHint.FixedSize(0), // not used + rowsData: new Uint8Array(binary), + }, + }), + ], + }, + ], + }), + timestamp: new Timestamp(1681391805281203n), + callerIdentity: anIdentity, + callerConnectionId: ConnectionId.random(), + reducerCall: { + reducerName: 'create_player', + reducerId: 0, + args: encodeCreatePlayerArgs('A Player', { x: 2, y: 3 }), + requestId: 0, + }, + energyQuantaUsed: { quanta: BigInt(33841000) }, + totalHostExecutionDuration: new TimeDuration(BigInt(1234567890)), + }); + const writer = new BinaryWriter(1024); + AlgebraicType.serializeValue( + writer, + ServerMessage.getTypeScriptAlgebraicType(), + transactionUpdate + ); + const rawBytes = writer.getBuffer(); + + const deserializedTransactionUpdate = AlgebraicType.deserializeValue( + new BinaryReader(rawBytes), + ServerMessage.getTypeScriptAlgebraicType() + ); + expect(deserializedTransactionUpdate).toEqual(transactionUpdate); + }); }); diff --git a/crates/bindings-typescript/tests/db_connection.test.ts b/crates/bindings-typescript/tests/db_connection.test.ts index d680ec781f5..02dff03d690 100644 --- a/crates/bindings-typescript/tests/db_connection.test.ts +++ b/crates/bindings-typescript/tests/db_connection.test.ts @@ -9,22 +9,18 @@ import { beforeEach, describe, expect, test } from 'vitest'; import { ConnectionId } from '../src'; import { Timestamp } from '../src'; import { TimeDuration } from '../src'; -import { AlgebraicType } from '../src'; -import { BinaryWriter } from '../src'; import * as ws from '../src/sdk/client_api'; import type { ReducerEvent } from '../src/sdk/db_connection_impl'; import { Identity } from '../src'; import WebsocketTestAdapter from '../src/sdk/websocket_test_adapter'; - -const anIdentity = Identity.fromString( - '0000000000000000000000000000000000000000000000000000000000000069' -); -const bobIdentity = Identity.fromString( - '0000000000000000000000000000000000000000000000000000000000000b0b' -); -const sallyIdentity = Identity.fromString( - '000000000000000000000000000000000000000000000000000000000006a111' -); +import { + anIdentity, + bobIdentity, + encodeCreatePlayerArgs, + encodePlayer, + encodeUser, + sallyIdentity, +} from './utils'; class Deferred { #isResolved: boolean = false; @@ -69,25 +65,6 @@ class Deferred { beforeEach(() => {}); -function encodePlayer(value: Player): Uint8Array { - const writer = new BinaryWriter(1024); - Player.serialize(writer, value); - return writer.getBuffer(); -} - -function encodeUser(value: User): Uint8Array { - const writer = new BinaryWriter(1024); - User.serialize(writer, value); - return writer.getBuffer(); -} - -function encodeCreatePlayerArgs(name: string, location: Point): Uint8Array { - const writer = new BinaryWriter(1024); - AlgebraicType.serializeValue(writer, AlgebraicType.String, name); - Point.serialize(writer, location); - return writer.getBuffer(); -} - describe('DbConnection', () => { test('call onConnectError callback after websocket connection failed to be established', async () => { const onConnectErrorPromise = new Deferred(); diff --git a/crates/bindings-typescript/tests/index.test.ts b/crates/bindings-typescript/tests/index.test.ts index e244b60e4b2..570728769fb 100644 --- a/crates/bindings-typescript/tests/index.test.ts +++ b/crates/bindings-typescript/tests/index.test.ts @@ -3,18 +3,19 @@ import { AlgebraicType, ConnectionId, Identity, - t, type IdentityTokenMessage, } from '../src/index'; +import type { ColumnBuilder } from '../src/server'; +import { t } from '../src/server/type_builders'; describe('TypeBuilder', () => { it('builds the correct algebraic type for a point', () => { - const point = t.object({ + const point = t.object('', { x: t.f64(), y: t.f64(), z: t.f64(), }); - expect(point.algebraicType).toEqual({ + expect(point.resolveType()).toEqual({ tag: 'Product', value: { elements: [ @@ -27,11 +28,11 @@ describe('TypeBuilder', () => { }); it('builds the correct algebraic type for a sum type', () => { - const sumType = t.enum({ + const sumType = t.enum('', { a: t.string(), b: t.number(), }); - expect(sumType.algebraicType).toEqual({ + expect(sumType.resolveType()).toEqual({ tag: 'Sum', value: { variants: [ @@ -43,7 +44,11 @@ describe('TypeBuilder', () => { }); it('builds a ColumnBuilder with an index, unique constraint, and primary key', () => { - const col = t.i32().index('btree').unique().primaryKey(); + const col = t.i32().index('btree').unique().primaryKey() as ColumnBuilder< + any, + any, + any + >; expect(col.typeBuilder.algebraicType).toEqual({ tag: 'I32', }); @@ -55,10 +60,10 @@ describe('TypeBuilder', () => { }); it('builds ColumnBuilders with the correct metadata', () => { - const indexCol = t.i32().index('btree'); - const uniqueCol = t.i32().unique(); - const primaryKeyCol = t.i32().primaryKey(); - const autoIncCol = t.i32().autoInc(); + const indexCol = t.i32().index('btree') as ColumnBuilder; + const uniqueCol = t.i32().unique() as ColumnBuilder; + const primaryKeyCol = t.i32().primaryKey() as ColumnBuilder; + const autoIncCol = t.i32().autoInc() as ColumnBuilder; expect(indexCol.typeBuilder.algebraicType).toEqual({ tag: 'I32', diff --git a/crates/bindings-typescript/tests/utils.ts b/crates/bindings-typescript/tests/utils.ts new file mode 100644 index 00000000000..19461b384cf --- /dev/null +++ b/crates/bindings-typescript/tests/utils.ts @@ -0,0 +1,34 @@ +import { AlgebraicType, BinaryWriter, Identity } from '../src'; +import { Player, Point, User } from '../test-app/src/module_bindings'; + +export const anIdentity = Identity.fromString( + '0000000000000000000000000000000000000000000000000000000000000069' +); +export const bobIdentity = Identity.fromString( + '0000000000000000000000000000000000000000000000000000000000000b0b' +); +export const sallyIdentity = Identity.fromString( + '000000000000000000000000000000000000000000000000000000000006a111' +); + +export function encodePlayer(value: Player): Uint8Array { + const writer = new BinaryWriter(1024); + Player.serialize(writer, value); + return writer.getBuffer(); +} + +export function encodeUser(value: User): Uint8Array { + const writer = new BinaryWriter(1024); + User.serialize(writer, value); + return writer.getBuffer(); +} + +export function encodeCreatePlayerArgs( + name: string, + location: Point +): Uint8Array { + const writer = new BinaryWriter(1024); + AlgebraicType.serializeValue(writer, AlgebraicType.String, name); + Point.serialize(writer, location); + return writer.getBuffer(); +} diff --git a/crates/bindings-typescript/tsup.config.ts b/crates/bindings-typescript/tsup.config.ts index 68dde97bba0..d9bee996e52 100644 --- a/crates/bindings-typescript/tsup.config.ts +++ b/crates/bindings-typescript/tsup.config.ts @@ -118,8 +118,20 @@ export default defineConfig([ sourcemap: true, clean: true, platform: 'neutral', // flip to 'node' if you actually rely on Node builtins - treeshake: 'smallest', - external: ['undici'], + banner: { + js: + 'typeof globalThis!=="undefined"&&(' + + '(globalThis.global=globalThis.global||globalThis),' + + '(globalThis.window=globalThis.window||globalThis));', + }, + treeshake: { + moduleSideEffects: [ + 'src/server/polyfills.ts', + 'src/server/register_hooks.ts', + ], + }, + external: ['undici', /^spacetime:sys.*$/], + noExternal: ['base64-js', 'fast-text-encoding'], outExtension, esbuildOptions: commonEsbuildTweaks(), }, diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 1ec691324ad..365f049b25c 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -74,6 +74,8 @@ walkdir.workspace = true wasmbin.workspace = true webbrowser.workspace = true clap-markdown.workspace = true +rolldown.workspace = true +rolldown_utils.workspace = true [target.'cfg(not(target_env = "msvc"))'.dependencies] tikv-jemallocator = { workspace = true } diff --git a/crates/cli/src/subcommands/build.rs b/crates/cli/src/subcommands/build.rs index 66f768e3443..e0c31b20ed1 100644 --- a/crates/cli/src/subcommands/build.rs +++ b/crates/cli/src/subcommands/build.rs @@ -31,7 +31,7 @@ pub fn cli() -> clap::Command { ) } -pub async fn exec(_config: Config, args: &ArgMatches) -> Result { +pub async fn exec(_config: Config, args: &ArgMatches) -> Result<(PathBuf, &'static str), anyhow::Error> { let project_path = args.get_one::("project_path").unwrap(); let lint_dir = args.get_one::("lint_dir").unwrap(); let lint_dir = if lint_dir.is_empty() { @@ -56,17 +56,17 @@ pub async fn exec(_config: Config, args: &ArgMatches) -> Result Result { +) -> Result<(PathBuf, &'static str), anyhow::Error> { // Note: "build" must be the start of the string, because `build::cli()` is the entire build subcommand. // If we don't include this, the args will be misinterpreted (e.g. as commands). let arg_string = format!("build {} --project-path {}", arg_string, project_path.display()); diff --git a/crates/cli/src/subcommands/generate.rs b/crates/cli/src/subcommands/generate.rs index d109a8fab88..f8da4eb731d 100644 --- a/crates/cli/src/subcommands/generate.rs +++ b/crates/cli/src/subcommands/generate.rs @@ -36,6 +36,16 @@ pub fn cli() -> clap::Command { .conflicts_with("build_options") .help("The system path (absolute or relative) to the compiled wasm binary we should inspect"), ) + .arg( + Arg::new("js_file") + .value_parser(clap::value_parser!(PathBuf)) + .long("js-path") + .short('j') + .group("source") + .conflicts_with("project_path") + .conflicts_with("build_options") + .help("The system path (absolute or relative) to the bundled javascript file we should inspect"), + ) .arg( Arg::new("project_path") .value_parser(clap::value_parser!(PathBuf)) @@ -120,6 +130,7 @@ pub async fn exec_ex( ) -> anyhow::Result<()> { let project_path = args.get_one::("project_path").unwrap(); let wasm_file = args.get_one::("wasm_file").cloned(); + let js_file = args.get_one::("js_file").cloned(); let json_module = args.get_many::("json_module"); let lang = *args.get_one::("lang").unwrap(); let namespace = args.get_one::("namespace").unwrap(); @@ -144,16 +155,20 @@ pub async fn exec_ex( }; module.try_into()? } else { - let wasm_path = if let Some(path) = wasm_file { + let path = if let Some(path) = wasm_file { + println!("Skipping build. Instead we are inspecting {}", path.display()); + path.clone() + } else if let Some(path) = js_file { println!("Skipping build. Instead we are inspecting {}", path.display()); path.clone() } else { - build::exec_with_argstring(config.clone(), project_path, build_options).await? + let (path, _) = build::exec_with_argstring(config.clone(), project_path, build_options).await?; + path }; let spinner = indicatif::ProgressBar::new_spinner(); spinner.enable_steady_tick(std::time::Duration::from_millis(60)); - spinner.set_message("Extracting schema from wasm..."); - extract_descriptions(&wasm_path).context("could not extract schema")? + spinner.set_message(format!("Extracting schema from {}...", path.display())); + extract_descriptions(&path).context("could not extract schema")? }; fs::create_dir_all(out_dir)?; diff --git a/crates/cli/src/subcommands/init.rs b/crates/cli/src/subcommands/init.rs index 8a087b81b9a..8810fbf57fb 100644 --- a/crates/cli/src/subcommands/init.rs +++ b/crates/cli/src/subcommands/init.rs @@ -141,6 +141,7 @@ pub async fn exec(_config: Config, args: &ArgMatches) -> Result<(), anyhow::Erro match project_lang { ModuleLanguage::Rust => exec_init_rust(args).await, ModuleLanguage::Csharp => exec_init_csharp(args).await, + ModuleLanguage::Javascript => exec_init_typescript(args).await, } } @@ -204,6 +205,35 @@ pub async fn exec_init_csharp(args: &ArgMatches) -> anyhow::Result<()> { Ok(()) } +pub async fn exec_init_typescript(args: &ArgMatches) -> anyhow::Result<()> { + let project_path = args.get_one::("project-path").unwrap(); + + let export_files = vec![ + (include_str!("project/typescript/package._json"), "package.json"), + (include_str!("project/typescript/tsconfig._json"), "tsconfig.json"), + (include_str!("project/typescript/index._ts"), "src/index.ts"), + (include_str!("project/typescript/_gitignore"), ".gitignore"), + ]; + + // Check all dependencies + check_for_git(); + + for (contents, file) in export_files { + let path = project_path.join(file); + + create_directory(path.parent().unwrap())?; + + std::fs::write(path, contents)?; + } + + println!( + "{}", + format!("Project successfully created at path: {}", project_path.display()).green() + ); + + Ok(()) +} + fn create_directory(path: &Path) -> Result<(), anyhow::Error> { std::fs::create_dir_all(path).context("Failed to create directory") } diff --git a/crates/cli/src/subcommands/project/typescript/_gitignore b/crates/cli/src/subcommands/project/typescript/_gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/crates/cli/src/subcommands/project/typescript/index._ts b/crates/cli/src/subcommands/project/typescript/index._ts new file mode 100644 index 00000000000..0142eefd44f --- /dev/null +++ b/crates/cli/src/subcommands/project/typescript/index._ts @@ -0,0 +1,33 @@ +import { schema, table, t } from 'spacetimedb/server'; + +export const spacetimedb = schema( + table( + { name: 'person' }, + { + name: t.string(), + } + ) +); + +spacetimedb.reducer('init', (_ctx) => { + // Called when the module is initially published +}); + +spacetimedb.reducer('client_connected', (_ctx) => { + // Called every time a new client connects +}); + +spacetimedb.reducer('client_disconnected', (_ctx) => { + // Called every time a client disconnects +}); + +spacetimedb.reducer('add', { name: t.string() }, (ctx, { name }) => { + ctx.db.person.insert({ name }); +}); + +spacetimedb.reducer('say_hello', (ctx) => { + for (const person of ctx.db.person.iter()) { + console.info(`Hello, ${person.name}!`); + } + console.info('Hello, World!'); +}); \ No newline at end of file diff --git a/crates/cli/src/subcommands/project/typescript/package._json b/crates/cli/src/subcommands/project/typescript/package._json new file mode 100644 index 00000000000..5d58eb5b7e9 --- /dev/null +++ b/crates/cli/src/subcommands/project/typescript/package._json @@ -0,0 +1,15 @@ +{ + "name": "spacetime-module", + "version": "1.0.0", + "description": "", + "scripts": { + "build": "spacetime build", + "publish": "spacetime publish" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "spacetimedb": "1.5.*" + } +} \ No newline at end of file diff --git a/crates/cli/src/subcommands/project/typescript/tsconfig._json b/crates/cli/src/subcommands/project/typescript/tsconfig._json new file mode 100644 index 00000000000..77c6124cb16 --- /dev/null +++ b/crates/cli/src/subcommands/project/typescript/tsconfig._json @@ -0,0 +1,24 @@ + +/* + * This tsconfig is used for TypeScript projects created with `spacetimedb init + * --lang typescript`. You can modify it as needed for your project, although + * some options are required by SpacetimeDB. + */ +{ + "compilerOptions": { + "strict": true, + "skipLibCheck": true, + "moduleResolution": "bundler", + "jsx": "react-jsx", + + /* The following options are required by SpacetimeDB + * and should not be modified + */ + "target": "ESNext", + "lib": ["ES2021", "dom"], + "module": "ESNext", + "isolatedModules": true, + "noEmit": true + }, + "include": ["./**/*"] +} \ No newline at end of file diff --git a/crates/cli/src/subcommands/publish.rs b/crates/cli/src/subcommands/publish.rs index d1ad3208359..aa0c1c5dcd0 100644 --- a/crates/cli/src/subcommands/publish.rs +++ b/crates/cli/src/subcommands/publish.rs @@ -129,8 +129,7 @@ pub async fn exec(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E println!("(JS) Skipping build. Instead we are publishing {}", path.display()); (path.clone(), "Js") } else { - let path = build::exec_with_argstring(config.clone(), path_to_project, build_options).await?; - (path, "Wasm") + build::exec_with_argstring(config.clone(), path_to_project, build_options).await? }; let program_bytes = fs::read(path_to_program)?; diff --git a/crates/cli/src/tasks/javascript.rs b/crates/cli/src/tasks/javascript.rs new file mode 100644 index 00000000000..71b136e8b54 --- /dev/null +++ b/crates/cli/src/tasks/javascript.rs @@ -0,0 +1,175 @@ +use regex::Regex; +use rolldown::{Bundler, BundlerOptions, Either, SourceMapType}; +use rolldown_utils::indexmap::FxIndexMap; +use rolldown_utils::js_regex::HybridRegex; +use rolldown_utils::pattern_filter::StringOrRegex; +use std::fs; +use std::path::{Path, PathBuf}; +use std::sync::OnceLock; +use tokio::runtime::{Builder, Handle, Runtime}; + +static RUNTIME: OnceLock = OnceLock::new(); + +fn runtime() -> &'static Runtime { + RUNTIME.get_or_init(|| { + Builder::new_multi_thread() + .enable_all() + .build() + .expect("build tokio runtime") + }) +} + +/// Synchronously run an async future from a non-async function. +/// +/// - If we're already inside a Tokio runtime, we switch to the blocking pool +/// and `block_on` the future (prevents scheduler starvation). +/// - Otherwise, we use a shared, long-lived runtime. +pub fn run_blocking(fut: F) -> T +where + F: std::future::Future + Send + 'static, + T: Send + 'static, +{ + match Handle::try_current() { + Ok(handle) => tokio::task::block_in_place(|| handle.block_on(fut)), + Err(_) => runtime().block_on(fut), + } +} + +pub(crate) fn build_javascript(project_path: &Path, build_debug: bool) -> anyhow::Result { + let cwd = fs::canonicalize(project_path)?; + let mut bundler = Bundler::new(BundlerOptions { + input: Some(vec!["./src/index.ts".to_string().into()]), + cwd: Some(cwd), + sourcemap: Some(SourceMapType::Inline), + external: Some(rolldown::IsExternal::StringOrRegex(vec![ + // Mark the bindings as external so we don't get a warning. + StringOrRegex::Regex(HybridRegex::Optimize(Regex::new("spacetime:sys.*").unwrap())), + ])), + platform: Some(rolldown::Platform::Browser), // Browser is the correct choice here because it doesn't inject Node.js polyfills. + shim_missing_exports: Some(false), + name: None, + entry_filenames: None, + chunk_filenames: None, // The pattern to use for naming shared chunks created when code-splitting + css_entry_filenames: None, + css_chunk_filenames: None, // We're not doing CSS + asset_filenames: None, // assets/[name]-[hash][extname] + sanitize_filename: Some(rolldown::SanitizeFilename::Boolean(true)), // Replace characters that are invalid in filenames with underscores + dir: None, // The output directory to write to. We only want a single output file, so we won't set this. + file: Some("./dist/bundle.js".into()), // The output file to write to. We want a single output file. + format: Some(rolldown::OutputFormat::Esm), // We want to use ES Modules in SpacetimeDB + exports: Some(rolldown::OutputExports::None), // Let Rolldown decide based on what the module exports (we could probably also use Named here) + globals: None, // We don't have any external dependencies except for `spacetimedb` which is a dependency and declares all its globals + generated_code: Some(rolldown::GeneratedCodeOptions::es2015()), + es_module: Some(rolldown::EsModuleFlag::IfDefaultProp), // See https://rollupjs.org/configuration-options/#output-esmodule + drop_labels: None, + hash_characters: None, // File name hash characters, we don't care + banner: None, // String to prepend to the bundle + footer: None, // String to append to the bundle + intro: None, // Similar to the above, but inside the wrappers + outro: None, // Similar to the above, but inside the wrappers + sourcemap_base_url: None, // Absolute URLs for the source map + sourcemap_ignore_list: None, // See https://rollupjs.org/configuration-options/#output-sourcemapignorelist + sourcemap_path_transform: None, // Function to transform source map paths + sourcemap_debug_ids: Some(true), // Seems like a good idea. See: https://rollupjs.org/configuration-options/#output-sourcemapdebugids + module_types: None, // Lets you associate file extensions with module types, e.g. `.data` -> `json`. We don't need this. + // Wrapper around https://docs.rs/oxc_resolver/latest/oxc_resolver/struct.ResolveOptions.html, see also https://rolldown.rs/guide/features#module-resolution + resolve: Some(rolldown::ResolveOptions { + // Prefer environment-neutral exports + condition_names: Some(vec!["production".into(), "import".into(), "default".into()]), + main_fields: Some(vec!["exports".into(), "module".into(), "main".into()]), + extensions: Some(vec![ + ".ts".into(), + ".tsx".into(), + ".mjs".into(), + ".js".into(), + ".cjs".into(), + ".json".into(), + ]), + symlinks: Some(true), + ..Default::default() + }), + treeshake: rolldown::TreeshakeOptions::Option(rolldown::InnerOptions { + module_side_effects: rolldown::ModuleSideEffects::Boolean(true), // TODO: SpacetimeDB currently relies on `import './runtime'` to set up the environment, so we can't tree-shake that away. + annotations: Some(true), // Respect the `/* @__PURE__ */` annotations that tools like Terser use to identify pure functions for tree-shaking. + manual_pure_functions: None, // Don't manually specify any pure functions. + unknown_global_side_effects: Some(true), // Default, basically if there is an unknown global, assume it has side effects. + commonjs: Some(true), // Enable some optimizations for CommonJS modules, even though we don't use any. This is the default. + property_read_side_effects: Some(rolldown::PropertyReadSideEffects::Always), // Assume that property reads can have side effects. This is safest for users who might use getters with side effects. + property_write_side_effects: Some(rolldown::PropertyWriteSideEffects::Always), // Assume that property writes can have side effects. This is safest for users who might use setters with side effects. + }), + experimental: None, // None for now, although be aware that Rollup has an experimental `perf` option. + minify: Some(rolldown::RawMinifyOptions::Bool(false)), // Disable minification until we have proper support for source maps. + define: Some(FxIndexMap::from_iter([ + // TODO(cloutiertyler): I actually think we should probably just always do production mode event in debug builds + ( + "process.env.NODE_ENV".to_string(), + if build_debug { "development" } else { "production" }.into(), + ), + ])), + extend: Some(false), // Not relevant for us, this is for extending global variables in UMD/IIFE bundles and we have ESM only. + profiler_names: None, // Unclear what this is, choosing the default. + keep_names: None, // Unclear what this is, choosing the default. + inject: None, // Unclear on why we'd need this, choosing the default. + external_live_bindings: Some(true), // Don't assume that external bindings are going to change over time. Generates more optimized code. + inline_dynamic_imports: Some(false), // Don't muck with dynamic imports, we want to keep them as-is. + advanced_chunks: None, // Not relevant to us, this is for advanced code-splitting strategies. + checks: Some(rolldown::ChecksOptions { + circular_dependency: Some(true), // Check circular dependencies + eval: Some(false), // We don't care about eval + missing_global_name: Some(true), // Warn if a global variable is missing a name in the output bundle + missing_name_option_for_iife_export: None, // Don't care, we don't use IIFE + mixed_export: Some(false), // Don't care about mixed exports + unresolved_entry: Some(true), // If the entry point is unresolved, that's a problem + unresolved_import: Some(true), // If an import is unresolved, that's a problem + filename_conflict: Some(true), + common_js_variable_in_esm: Some(true), + import_is_undefined: Some(true), + empty_import_meta: Some(true), + configuration_field_conflict: Some(true), + prefer_builtin_feature: Some(true), + }), + transform: Some(rolldown::BundlerTransformOptions { + jsx: None, // Don't transform JSX + target: Some(Either::Left("esnext".to_owned())), // Default, no transformation + assumptions: None, // No compiler assumptions, we don't need to minmax output size + decorator: None, // Disable experimental decorators + typescript: Some(rolldown::TypeScriptOptions { + jsx_pragma: None, // I am unclear on what this is + jsx_pragma_frag: None, // I am unclear on what this is + only_remove_type_imports: Some(true), // I am assuming we just want to strip these + allow_namespaces: Some(false), // No namespaces, only allow JS + types + allow_declare_fields: Some(true), // Allow `declare` fields in classes and strip these + remove_class_fields_without_initializer: Some(false), // Leave them there to not mess with behavior + declaration: None, // We don't need to generate any declaration files, these are not libraries, although you could imagine this in the future + rewrite_import_extensions: Some(Either::Left(true)), // Rewrite .ts/.tsx extensions to .js/.jsx, not really relevant for us since we only have a single entry point + }), + plugins: None, + }), + watch: None, // We don't need watch mode + legal_comments: Some(rolldown::LegalComments::None), // We don't need any legal comments + polyfill_require: Some(false), // We don't need to polyfill require, only ESM here + defer_sync_scan_data: None, // Unclear what this is + make_absolute_externals_relative: None, // See https://rollupjs.org/configuration-options/#makeabsoluteexternalsrelative + debug: None, // This is undocumented + invalidate_js_side_cache: None, + log_level: Some(rolldown::LogLevel::Debug), // Default logging + on_log: None, // Don't need it + preserve_modules: Some(false), // We want a single output file + virtual_dirname: None, // Requires preserve_modules to be true + preserve_modules_root: None, // Only relevant if preserve_modules is true + preserve_entry_signatures: None, // Default is fine, see https://rollupjs.org/configuration-options/#preserveentrysignatures + optimization: None, // Defaults are fine + top_level_var: Some(false), // This is the safer choice since we'll keep vars scoped to modules + minify_internal_exports: Some(true), // Sure + context: None, // We don't want a top level `this` in modules + tsconfig: Some(project_path.join("tsconfig.json").to_string_lossy().into_owned()), + })?; + + let bundle_output = run_blocking(async move { bundler.write().await })?; + + bundle_output.warnings.into_iter().for_each(|w| { + eprintln!("Rolldown warning: {w}"); + }); + + Ok(project_path.join("dist").join("bundle.js")) +} diff --git a/crates/cli/src/tasks/mod.rs b/crates/cli/src/tasks/mod.rs index 79201db0689..a88f10a9b0b 100644 --- a/crates/cli/src/tasks/mod.rs +++ b/crates/cli/src/tasks/mod.rs @@ -3,17 +3,31 @@ use std::path::{Path, PathBuf}; use crate::util::{self, ModuleLanguage}; use self::csharp::build_csharp; -use crate::tasks::rust::build_rust; +use self::javascript::build_javascript; +use self::rust::build_rust; use duct::cmd; -pub fn build(project_path: &Path, lint_dir: Option<&Path>, build_debug: bool) -> anyhow::Result { +// TODO: Replace the returned `&'static str` with a copy of `HostType` from core. +pub fn build( + project_path: &Path, + lint_dir: Option<&Path>, + build_debug: bool, +) -> anyhow::Result<(PathBuf, &'static str)> { let lang = util::detect_module_language(project_path)?; - let mut wasm_path = match lang { + let output_path = match lang { ModuleLanguage::Rust => build_rust(project_path, lint_dir, build_debug), ModuleLanguage::Csharp => build_csharp(project_path, build_debug), + ModuleLanguage::Javascript => build_javascript(project_path, build_debug), }?; - if !build_debug { + + if lang == ModuleLanguage::Javascript { + Ok((output_path, "Js")) + } else if !build_debug { + Ok((output_path, "Wasm")) + } else { + // for release builds, optimize wasm modules with wasm-opt + let mut wasm_path = output_path; eprintln!("Optimising module with wasm-opt..."); let wasm_path_opt = wasm_path.with_extension("opt.wasm"); match cmd!("wasm-opt", "-all", "-g", "-O2", &wasm_path, "-o", &wasm_path_opt).run() { @@ -33,9 +47,10 @@ pub fn build(project_path: &Path, lint_dir: Option<&Path>, build_debug: bool) -> eprintln!("Continuing with unoptimised module."); } } + Ok((wasm_path, "Wasm")) } - Ok(wasm_path) } pub mod csharp; +pub mod javascript; pub mod rust; diff --git a/crates/cli/src/util.rs b/crates/cli/src/util.rs index 7161d4c9fec..011f2693427 100644 --- a/crates/cli/src/util.rs +++ b/crates/cli/src/util.rs @@ -195,15 +195,26 @@ pub const VALID_PROTOCOLS: [&str; 2] = ["http", "https"]; pub enum ModuleLanguage { Csharp, Rust, + Javascript, } impl clap::ValueEnum for ModuleLanguage { fn value_variants<'a>() -> &'a [Self] { - &[Self::Csharp, Self::Rust] + &[Self::Csharp, Self::Rust, Self::Javascript] } fn to_possible_value(&self) -> Option { match self { Self::Csharp => Some(clap::builder::PossibleValue::new("csharp").aliases(["c#", "cs", "C#", "CSharp"])), Self::Rust => Some(clap::builder::PossibleValue::new("rust").aliases(["rs", "Rust"])), + Self::Javascript => Some(clap::builder::PossibleValue::new("typescript").aliases([ + "JavaScript", + "javascript", + "js", + "TypeScript", + "ts", + "ECMAScript", + "ecmascript", + "es", + ])), } } } @@ -219,6 +230,8 @@ pub fn detect_module_language(path_to_project: &Path) -> anyhow::Result( Extension(auth): Extension, body: Bytes, ) -> axum::response::Result> { - // Feature gate V8 modules. - // The host must've been compiled with the `unstable` feature. - // TODO(v8): ungate this when V8 is ready to ship. - #[cfg(not(feature = "unstable"))] - if host_type == HostType::Js { - return Err(( - StatusCode::BAD_REQUEST, - "JS host type requires a host with unstable features", - ) - .into()); - } - // You should not be able to publish to a database that you do not own // so, unless you are the owner, this will fail. @@ -712,18 +700,6 @@ pub async fn pre_publish( Extension(auth): Extension, body: Bytes, ) -> axum::response::Result> { - // Feature gate V8 modules. - // The host must've been compiled with the `unstable` feature. - // TODO(v8): ungate this when V8 is ready to ship. - #[cfg(not(feature = "unstable"))] - if host_type == HostType::Js { - return Err(( - StatusCode::BAD_REQUEST, - "JS host type requires a host with unstable features", - ) - .into()); - } - // User should not be able to print migration plans for a database that they do not own let database_identity = resolve_and_authenticate(&ctx, &name_or_identity, &auth).await?; let style = match style { diff --git a/crates/codegen/src/typescript.rs b/crates/codegen/src/typescript.rs index 85483e5001f..e8c793be5b8 100644 --- a/crates/codegen/src/typescript.rs +++ b/crates/codegen/src/typescript.rs @@ -728,6 +728,7 @@ fn print_lint_suppression(output: &mut Indenter) { fn write_get_algebraic_type_for_product( module: &ModuleDef, out: &mut Indenter, + type_cache_name: &str, elements: &[(Identifier, AlgebraicTypeUse)], ) { writeln!( @@ -740,9 +741,18 @@ fn write_get_algebraic_type_for_product( writeln!(out, "getTypeScriptAlgebraicType(): __AlgebraicTypeType {{"); { out.indent(1); - write!(out, "return "); - convert_product_type(module, out, elements, ""); - writeln!(out, ";"); + writeln!(out, "if ({type_cache_name}) return {type_cache_name};"); + // initialization is split in two because of recursive types + writeln!( + out, + "{type_cache_name} = __AlgebraicTypeValue.Product({{ elements: [] }});" + ); + writeln!(out, "{type_cache_name}.value.elements.push("); + out.indent(1); + convert_product_type_elements(module, out, elements, ""); + out.dedent(1); + writeln!(out, ");"); + writeln!(out, "return {type_cache_name};"); out.dedent(1); } writeln!(out, "}},"); @@ -763,6 +773,10 @@ fn define_body_for_product( writeln!(out, "}};"); } + let type_cache_name = &*format!("_cached_{name}_type_value"); + writeln!(out, "let {type_cache_name}: __AlgebraicTypeType | null = null;"); + out.newline(); + writeln!( out, "/** @@ -771,7 +785,7 @@ fn define_body_for_product( ); writeln!(out, "export const {name} = {{"); out.indent(1); - write_get_algebraic_type_for_product(module, out, elements); + write_get_algebraic_type_for_product(module, out, type_cache_name, elements); writeln!(out); writeln!(out, "serialize(writer: __BinaryWriter, value: {name}): void {{"); @@ -896,21 +910,31 @@ fn write_variant_constructors( let variant_name = ident.deref().to_case(Case::Pascal); write!(out, "{variant_name}: (value: "); write_type(module, out, ty, None, None).unwrap(); - writeln!(out, "): {name} => ({{ tag: \"{variant_name}\", value }}),"); + writeln!( + out, + "): {name}Variants.{variant_name} => ({{ tag: \"{variant_name}\", value }})," + ); } } fn write_get_algebraic_type_for_sum( module: &ModuleDef, out: &mut Indenter, + type_cache_name: &str, variants: &[(Identifier, AlgebraicTypeUse)], ) { writeln!(out, "getTypeScriptAlgebraicType(): __AlgebraicTypeType {{"); { indent_scope!(out); - write!(out, "return "); - convert_sum_type(module, &mut out, variants, ""); - writeln!(out, ";"); + writeln!(out, "if ({type_cache_name}) return {type_cache_name};"); + // initialization is split in two because of recursive types + writeln!(out, "{type_cache_name} = __AlgebraicTypeValue.Sum({{ variants: [] }});"); + writeln!(out, "{type_cache_name}.value.variants.push("); + out.indent(1); + convert_sum_type_variants(module, &mut out, variants, ""); + out.dedent(1); + writeln!(out, ");"); + writeln!(out, "return {type_cache_name};"); } writeln!(out, "}},"); } @@ -938,6 +962,10 @@ fn define_body_for_sum( out.newline(); + let type_cache_name = &*format!("_cached_{name}_type_value"); + writeln!(out, "let {type_cache_name}: __AlgebraicTypeType | null = null;"); + out.newline(); + // Write the runtime value with helper functions writeln!(out, "// A value with helper functions to construct the type."); writeln!(out, "export const {name} = {{"); @@ -957,7 +985,7 @@ fn define_body_for_sum( writeln!(out); // Write the function that generates the algebraic type. - write_get_algebraic_type_for_sum(module, out, variants); + write_get_algebraic_type_for_sum(module, out, type_cache_name, variants); writeln!(out); writeln!( @@ -1156,37 +1184,25 @@ fn convert_algebraic_type<'a>( } } -fn convert_sum_type<'a>( +fn convert_sum_type_variants<'a>( module: &'a ModuleDef, out: &mut Indenter, variants: &'a [(Identifier, AlgebraicTypeUse)], ref_prefix: &'a str, ) { - writeln!(out, "__AlgebraicTypeValue.Sum({{"); - out.indent(1); - writeln!(out, "variants: ["); - out.indent(1); for (ident, ty) in variants { write!(out, "{{ name: \"{ident}\", algebraicType: ",); convert_algebraic_type(module, out, ty, ref_prefix); writeln!(out, " }},"); } - out.dedent(1); - writeln!(out, "]"); - out.dedent(1); - write!(out, "}})") } -fn convert_product_type<'a>( +fn convert_product_type_elements<'a>( module: &'a ModuleDef, out: &mut Indenter, elements: &'a [(Identifier, AlgebraicTypeUse)], ref_prefix: &'a str, ) { - writeln!(out, "__AlgebraicTypeValue.Product({{"); - out.indent(1); - writeln!(out, "elements: ["); - out.indent(1); for (ident, ty) in elements { write!( out, @@ -1194,12 +1210,8 @@ fn convert_product_type<'a>( ident.deref().to_case(Case::Camel) ); convert_algebraic_type(module, out, ty, ref_prefix); - writeln!(out, "}},"); + writeln!(out, " }},"); } - out.dedent(1); - writeln!(out, "]"); - out.dedent(1); - write!(out, "}})") } /// Print imports for each of the `imports`. diff --git a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap index 1bb555a86e6..ee6178b0c03 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_typescript.snap @@ -36,6 +36,8 @@ import { export type AddPlayer = { name: string, }; +let _cached_AddPlayer_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -45,11 +47,12 @@ export const AddPlayer = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_AddPlayer_type_value) return _cached_AddPlayer_type_value; + _cached_AddPlayer_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_AddPlayer_type_value.value.elements.push( + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_AddPlayer_type_value; }, serialize(writer: __BinaryWriter, value: AddPlayer): void { @@ -99,6 +102,8 @@ import { export type AddPrivate = { name: string, }; +let _cached_AddPrivate_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -108,11 +113,12 @@ export const AddPrivate = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_AddPrivate_type_value) return _cached_AddPrivate_type_value; + _cached_AddPrivate_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_AddPrivate_type_value.value.elements.push( + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_AddPrivate_type_value; }, serialize(writer: __BinaryWriter, value: AddPrivate): void { @@ -163,6 +169,8 @@ export type Add = { name: string, age: number, }; +let _cached_Add_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -172,12 +180,13 @@ export const Add = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - { name: "age", algebraicType: __AlgebraicTypeValue.U8}, - ] - }); + if (_cached_Add_type_value) return _cached_Add_type_value; + _cached_Add_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Add_type_value.value.elements.push( + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + { name: "age", algebraicType: __AlgebraicTypeValue.U8 }, + ); + return _cached_Add_type_value; }, serialize(writer: __BinaryWriter, value: Add): void { @@ -225,6 +234,8 @@ import { } from "spacetimedb"; export type AssertCallerIdentityIsModuleIdentity = {}; +let _cached_AssertCallerIdentityIsModuleIdentity_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -234,10 +245,11 @@ export const AssertCallerIdentityIsModuleIdentity = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - ] - }); + if (_cached_AssertCallerIdentityIsModuleIdentity_type_value) return _cached_AssertCallerIdentityIsModuleIdentity_type_value; + _cached_AssertCallerIdentityIsModuleIdentity_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_AssertCallerIdentityIsModuleIdentity_type_value.value.elements.push( + ); + return _cached_AssertCallerIdentityIsModuleIdentity_type_value; }, serialize(writer: __BinaryWriter, value: AssertCallerIdentityIsModuleIdentity): void { @@ -287,6 +299,8 @@ import { export type Baz = { field: string, }; +let _cached_Baz_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -296,11 +310,12 @@ export const Baz = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "field", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_Baz_type_value) return _cached_Baz_type_value; + _cached_Baz_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Baz_type_value.value.elements.push( + { name: "field", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_Baz_type_value; }, serialize(writer: __BinaryWriter, value: Baz): void { @@ -349,6 +364,8 @@ import { } from "spacetimedb"; export type ClientConnected = {}; +let _cached_ClientConnected_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -358,10 +375,11 @@ export const ClientConnected = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - ] - }); + if (_cached_ClientConnected_type_value) return _cached_ClientConnected_type_value; + _cached_ClientConnected_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_ClientConnected_type_value.value.elements.push( + ); + return _cached_ClientConnected_type_value; }, serialize(writer: __BinaryWriter, value: ClientConnected): void { @@ -411,6 +429,8 @@ import { export type DeletePlayer = { id: bigint, }; +let _cached_DeletePlayer_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -420,11 +440,12 @@ export const DeletePlayer = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "id", algebraicType: __AlgebraicTypeValue.U64}, - ] - }); + if (_cached_DeletePlayer_type_value) return _cached_DeletePlayer_type_value; + _cached_DeletePlayer_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_DeletePlayer_type_value.value.elements.push( + { name: "id", algebraicType: __AlgebraicTypeValue.U64 }, + ); + return _cached_DeletePlayer_type_value; }, serialize(writer: __BinaryWriter, value: DeletePlayer): void { @@ -474,6 +495,8 @@ import { export type DeletePlayersByName = { name: string, }; +let _cached_DeletePlayersByName_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -483,11 +506,12 @@ export const DeletePlayersByName = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_DeletePlayersByName_type_value) return _cached_DeletePlayersByName_type_value; + _cached_DeletePlayersByName_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_DeletePlayersByName_type_value.value.elements.push( + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_DeletePlayersByName_type_value; }, serialize(writer: __BinaryWriter, value: DeletePlayersByName): void { @@ -544,6 +568,8 @@ export type Foobar = FoobarVariants.Baz | FoobarVariants.Bar | FoobarVariants.Har; +let _cached_Foobar_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const Foobar = { // Helper functions for constructing each variant of the tagged union. @@ -552,18 +578,19 @@ export const Foobar = { // assert!(foo.tag === "A"); // assert!(foo.value === 42); // ``` - Baz: (value: Baz): Foobar => ({ tag: "Baz", value }), + Baz: (value: Baz): FoobarVariants.Baz => ({ tag: "Baz", value }), Bar: { tag: "Bar" } as const, - Har: (value: number): Foobar => ({ tag: "Har", value }), + Har: (value: number): FoobarVariants.Har => ({ tag: "Har", value }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { name: "Baz", algebraicType: Baz.getTypeScriptAlgebraicType() }, - { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Har", algebraicType: __AlgebraicTypeValue.U32 }, - ] - }); + if (_cached_Foobar_type_value) return _cached_Foobar_type_value; + _cached_Foobar_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_Foobar_type_value.value.variants.push( + { name: "Baz", algebraicType: Baz.getTypeScriptAlgebraicType() }, + { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, + { name: "Har", algebraicType: __AlgebraicTypeValue.U32 }, + ); + return _cached_Foobar_type_value; }, serialize(writer: __BinaryWriter, value: Foobar): void { @@ -733,6 +760,8 @@ export type HasSpecialStuff = { identity: __Identity, connectionId: __ConnectionId, }; +let _cached_HasSpecialStuff_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -742,12 +771,13 @@ export const HasSpecialStuff = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "identity", algebraicType: __AlgebraicTypeValue.createIdentityType()}, - { name: "connectionId", algebraicType: __AlgebraicTypeValue.createConnectionIdType()}, - ] - }); + if (_cached_HasSpecialStuff_type_value) return _cached_HasSpecialStuff_type_value; + _cached_HasSpecialStuff_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_HasSpecialStuff_type_value.value.elements.push( + { name: "identity", algebraicType: __AlgebraicTypeValue.createIdentityType() }, + { name: "connectionId", algebraicType: __AlgebraicTypeValue.createConnectionIdType() }, + ); + return _cached_HasSpecialStuff_type_value; }, serialize(writer: __BinaryWriter, value: HasSpecialStuff): void { @@ -1454,6 +1484,8 @@ import { export type ListOverAge = { age: number, }; +let _cached_ListOverAge_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -1463,11 +1495,12 @@ export const ListOverAge = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "age", algebraicType: __AlgebraicTypeValue.U8}, - ] - }); + if (_cached_ListOverAge_type_value) return _cached_ListOverAge_type_value; + _cached_ListOverAge_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_ListOverAge_type_value.value.elements.push( + { name: "age", algebraicType: __AlgebraicTypeValue.U8 }, + ); + return _cached_ListOverAge_type_value; }, serialize(writer: __BinaryWriter, value: ListOverAge): void { @@ -1515,6 +1548,8 @@ import { } from "spacetimedb"; export type LogModuleIdentity = {}; +let _cached_LogModuleIdentity_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -1524,10 +1559,11 @@ export const LogModuleIdentity = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - ] - }); + if (_cached_LogModuleIdentity_type_value) return _cached_LogModuleIdentity_type_value; + _cached_LogModuleIdentity_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_LogModuleIdentity_type_value.value.elements.push( + ); + return _cached_LogModuleIdentity_type_value; }, serialize(writer: __BinaryWriter, value: LogModuleIdentity): void { @@ -1731,6 +1767,8 @@ import * as NamespaceTestCVariants from './namespace_test_c_variants' export type NamespaceTestC = NamespaceTestCVariants.Foo | NamespaceTestCVariants.Bar; +let _cached_NamespaceTestC_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const NamespaceTestC = { // Helper functions for constructing each variant of the tagged union. @@ -1743,12 +1781,13 @@ export const NamespaceTestC = { Bar: { tag: "Bar" } as const, getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { name: "Foo", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - ] - }); + if (_cached_NamespaceTestC_type_value) return _cached_NamespaceTestC_type_value; + _cached_NamespaceTestC_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_NamespaceTestC_type_value.value.variants.push( + { name: "Foo", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, + { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, + ); + return _cached_NamespaceTestC_type_value; }, serialize(writer: __BinaryWriter, value: NamespaceTestC): void { @@ -1837,6 +1876,8 @@ export type NamespaceTestF = NamespaceTestFVariants.Foo | NamespaceTestFVariants.Bar | NamespaceTestFVariants.Baz; +let _cached_NamespaceTestF_type_value: __AlgebraicTypeType | null = null; + // A value with helper functions to construct the type. export const NamespaceTestF = { // Helper functions for constructing each variant of the tagged union. @@ -1847,16 +1888,17 @@ export const NamespaceTestF = { // ``` Foo: { tag: "Foo" } as const, Bar: { tag: "Bar" } as const, - Baz: (value: string): NamespaceTestF => ({ tag: "Baz", value }), + Baz: (value: string): NamespaceTestFVariants.Baz => ({ tag: "Baz", value }), getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Sum({ - variants: [ - { name: "Foo", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, - { name: "Baz", algebraicType: __AlgebraicTypeValue.String }, - ] - }); + if (_cached_NamespaceTestF_type_value) return _cached_NamespaceTestF_type_value; + _cached_NamespaceTestF_type_value = __AlgebraicTypeValue.Sum({ variants: [] }); + _cached_NamespaceTestF_type_value.value.variants.push( + { name: "Foo", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, + { name: "Bar", algebraicType: __AlgebraicTypeValue.Product({ elements: [] }) }, + { name: "Baz", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_NamespaceTestF_type_value; }, serialize(writer: __BinaryWriter, value: NamespaceTestF): void { @@ -2053,6 +2095,8 @@ export type Person = { name: string, age: number, }; +let _cached_Person_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -2062,13 +2106,14 @@ export const Person = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "id", algebraicType: __AlgebraicTypeValue.U32}, - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - { name: "age", algebraicType: __AlgebraicTypeValue.U8}, - ] - }); + if (_cached_Person_type_value) return _cached_Person_type_value; + _cached_Person_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Person_type_value.value.elements.push( + { name: "id", algebraicType: __AlgebraicTypeValue.U32 }, + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + { name: "age", algebraicType: __AlgebraicTypeValue.U8 }, + ); + return _cached_Person_type_value; }, serialize(writer: __BinaryWriter, value: Person): void { @@ -2250,6 +2295,8 @@ export type PkMultiIdentity = { id: number, other: number, }; +let _cached_PkMultiIdentity_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -2259,12 +2306,13 @@ export const PkMultiIdentity = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "id", algebraicType: __AlgebraicTypeValue.U32}, - { name: "other", algebraicType: __AlgebraicTypeValue.U32}, - ] - }); + if (_cached_PkMultiIdentity_type_value) return _cached_PkMultiIdentity_type_value; + _cached_PkMultiIdentity_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_PkMultiIdentity_type_value.value.elements.push( + { name: "id", algebraicType: __AlgebraicTypeValue.U32 }, + { name: "other", algebraicType: __AlgebraicTypeValue.U32 }, + ); + return _cached_PkMultiIdentity_type_value; }, serialize(writer: __BinaryWriter, value: PkMultiIdentity): void { @@ -2469,6 +2517,8 @@ export type Player = { playerId: bigint, name: string, }; +let _cached_Player_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -2478,13 +2528,14 @@ export const Player = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "identity", algebraicType: __AlgebraicTypeValue.createIdentityType()}, - { name: "playerId", algebraicType: __AlgebraicTypeValue.U64}, - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_Player_type_value) return _cached_Player_type_value; + _cached_Player_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Player_type_value.value.elements.push( + { name: "identity", algebraicType: __AlgebraicTypeValue.createIdentityType() }, + { name: "playerId", algebraicType: __AlgebraicTypeValue.U64 }, + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_Player_type_value; }, serialize(writer: __BinaryWriter, value: Player): void { @@ -2536,6 +2587,8 @@ export type Point = { x: bigint, y: bigint, }; +let _cached_Point_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -2545,12 +2598,13 @@ export const Point = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "x", algebraicType: __AlgebraicTypeValue.I64}, - { name: "y", algebraicType: __AlgebraicTypeValue.I64}, - ] - }); + if (_cached_Point_type_value) return _cached_Point_type_value; + _cached_Point_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Point_type_value.value.elements.push( + { name: "x", algebraicType: __AlgebraicTypeValue.I64 }, + { name: "y", algebraicType: __AlgebraicTypeValue.I64 }, + ); + return _cached_Point_type_value; }, serialize(writer: __BinaryWriter, value: Point): void { @@ -2757,6 +2811,8 @@ import { export type PrivateTable = { name: string, }; +let _cached_PrivateTable_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -2766,11 +2822,12 @@ export const PrivateTable = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_PrivateTable_type_value) return _cached_PrivateTable_type_value; + _cached_PrivateTable_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_PrivateTable_type_value.value.elements.push( + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_PrivateTable_type_value; }, serialize(writer: __BinaryWriter, value: PrivateTable): void { @@ -2819,6 +2876,8 @@ import { } from "spacetimedb"; export type QueryPrivate = {}; +let _cached_QueryPrivate_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -2828,10 +2887,11 @@ export const QueryPrivate = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - ] - }); + if (_cached_QueryPrivate_type_value) return _cached_QueryPrivate_type_value; + _cached_QueryPrivate_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_QueryPrivate_type_value.value.elements.push( + ); + return _cached_QueryPrivate_type_value; }, serialize(writer: __BinaryWriter, value: QueryPrivate): void { @@ -2991,6 +3051,8 @@ export type RepeatingTestArg = { scheduledAt: { tag: "Interval", value: __TimeDuration } | { tag: "Time", value: __Timestamp }, prevTime: __Timestamp, }; +let _cached_RepeatingTestArg_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3000,13 +3062,14 @@ export const RepeatingTestArg = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "scheduledId", algebraicType: __AlgebraicTypeValue.U64}, - { name: "scheduledAt", algebraicType: __AlgebraicTypeValue.createScheduleAtType()}, - { name: "prevTime", algebraicType: __AlgebraicTypeValue.createTimestampType()}, - ] - }); + if (_cached_RepeatingTestArg_type_value) return _cached_RepeatingTestArg_type_value; + _cached_RepeatingTestArg_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_RepeatingTestArg_type_value.value.elements.push( + { name: "scheduledId", algebraicType: __AlgebraicTypeValue.U64 }, + { name: "scheduledAt", algebraicType: __AlgebraicTypeValue.createScheduleAtType() }, + { name: "prevTime", algebraicType: __AlgebraicTypeValue.createTimestampType() }, + ); + return _cached_RepeatingTestArg_type_value; }, serialize(writer: __BinaryWriter, value: RepeatingTestArg): void { @@ -3061,6 +3124,8 @@ declare type __keep_RepeatingTestArg = RepeatingTestArg; export type RepeatingTest = { arg: RepeatingTestArg, }; +let _cached_RepeatingTest_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3070,11 +3135,12 @@ export const RepeatingTest = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "arg", algebraicType: RepeatingTestArg.getTypeScriptAlgebraicType()}, - ] - }); + if (_cached_RepeatingTest_type_value) return _cached_RepeatingTest_type_value; + _cached_RepeatingTest_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_RepeatingTest_type_value.value.elements.push( + { name: "arg", algebraicType: RepeatingTestArg.getTypeScriptAlgebraicType() }, + ); + return _cached_RepeatingTest_type_value; }, serialize(writer: __BinaryWriter, value: RepeatingTest): void { @@ -3122,6 +3188,8 @@ import { } from "spacetimedb"; export type SayHello = {}; +let _cached_SayHello_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3131,10 +3199,11 @@ export const SayHello = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - ] - }); + if (_cached_SayHello_type_value) return _cached_SayHello_type_value; + _cached_SayHello_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_SayHello_type_value.value.elements.push( + ); + return _cached_SayHello_type_value; }, serialize(writer: __BinaryWriter, value: SayHello): void { @@ -3264,6 +3333,8 @@ export type TestA = { y: number, z: string, }; +let _cached_TestA_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3273,13 +3344,14 @@ export const TestA = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "x", algebraicType: __AlgebraicTypeValue.U32}, - { name: "y", algebraicType: __AlgebraicTypeValue.U32}, - { name: "z", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_TestA_type_value) return _cached_TestA_type_value; + _cached_TestA_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_TestA_type_value.value.elements.push( + { name: "x", algebraicType: __AlgebraicTypeValue.U32 }, + { name: "y", algebraicType: __AlgebraicTypeValue.U32 }, + { name: "z", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_TestA_type_value; }, serialize(writer: __BinaryWriter, value: TestA): void { @@ -3330,6 +3402,8 @@ import { export type TestB = { foo: string, }; +let _cached_TestB_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3339,11 +3413,12 @@ export const TestB = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "foo", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_TestB_type_value) return _cached_TestB_type_value; + _cached_TestB_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_TestB_type_value.value.elements.push( + { name: "foo", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_TestB_type_value; }, serialize(writer: __BinaryWriter, value: TestB): void { @@ -3392,6 +3467,8 @@ import { } from "spacetimedb"; export type TestBtreeIndexArgs = {}; +let _cached_TestBtreeIndexArgs_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3401,10 +3478,11 @@ export const TestBtreeIndexArgs = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - ] - }); + if (_cached_TestBtreeIndexArgs_type_value) return _cached_TestBtreeIndexArgs_type_value; + _cached_TestBtreeIndexArgs_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_TestBtreeIndexArgs_type_value.value.elements.push( + ); + return _cached_TestBtreeIndexArgs_type_value; }, serialize(writer: __BinaryWriter, value: TestBtreeIndexArgs): void { @@ -3540,6 +3618,8 @@ declare type __keep_NamespaceTestC = NamespaceTestC; export type TestD = { testC: NamespaceTestC | undefined, }; +let _cached_TestD_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3549,11 +3629,12 @@ export const TestD = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "testC", algebraicType: __AlgebraicTypeValue.createOptionType(NamespaceTestC.getTypeScriptAlgebraicType())}, - ] - }); + if (_cached_TestD_type_value) return _cached_TestD_type_value; + _cached_TestD_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_TestD_type_value.value.elements.push( + { name: "testC", algebraicType: __AlgebraicTypeValue.createOptionType(NamespaceTestC.getTypeScriptAlgebraicType()) }, + ); + return _cached_TestD_type_value; }, serialize(writer: __BinaryWriter, value: TestD): void { @@ -3713,6 +3794,8 @@ export type TestE = { id: bigint, name: string, }; +let _cached_TestE_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3722,12 +3805,13 @@ export const TestE = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "id", algebraicType: __AlgebraicTypeValue.U64}, - { name: "name", algebraicType: __AlgebraicTypeValue.String}, - ] - }); + if (_cached_TestE_type_value) return _cached_TestE_type_value; + _cached_TestE_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_TestE_type_value.value.elements.push( + { name: "id", algebraicType: __AlgebraicTypeValue.U64 }, + { name: "name", algebraicType: __AlgebraicTypeValue.String }, + ); + return _cached_TestE_type_value; }, serialize(writer: __BinaryWriter, value: TestE): void { @@ -3864,6 +3948,8 @@ declare type __keep_Foobar = Foobar; export type TestFoobar = { field: Foobar, }; +let _cached_TestFoobar_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3873,11 +3959,12 @@ export const TestFoobar = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "field", algebraicType: Foobar.getTypeScriptAlgebraicType()}, - ] - }); + if (_cached_TestFoobar_type_value) return _cached_TestFoobar_type_value; + _cached_TestFoobar_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_TestFoobar_type_value.value.elements.push( + { name: "field", algebraicType: Foobar.getTypeScriptAlgebraicType() }, + ); + return _cached_TestFoobar_type_value; }, serialize(writer: __BinaryWriter, value: TestFoobar): void { @@ -3944,6 +4031,8 @@ export type Test = { arg3: NamespaceTestC, arg4: NamespaceTestF, }; +let _cached_Test_type_value: __AlgebraicTypeType | null = null; + /** * An object for generated helper functions. */ @@ -3953,14 +4042,15 @@ export const Test = { * This function is derived from the AlgebraicType used to generate this type. */ getTypeScriptAlgebraicType(): __AlgebraicTypeType { - return __AlgebraicTypeValue.Product({ - elements: [ - { name: "arg", algebraicType: TestA.getTypeScriptAlgebraicType()}, - { name: "arg2", algebraicType: TestB.getTypeScriptAlgebraicType()}, - { name: "arg3", algebraicType: NamespaceTestC.getTypeScriptAlgebraicType()}, - { name: "arg4", algebraicType: NamespaceTestF.getTypeScriptAlgebraicType()}, - ] - }); + if (_cached_Test_type_value) return _cached_Test_type_value; + _cached_Test_type_value = __AlgebraicTypeValue.Product({ elements: [] }); + _cached_Test_type_value.value.elements.push( + { name: "arg", algebraicType: TestA.getTypeScriptAlgebraicType() }, + { name: "arg2", algebraicType: TestB.getTypeScriptAlgebraicType() }, + { name: "arg3", algebraicType: NamespaceTestC.getTypeScriptAlgebraicType() }, + { name: "arg4", algebraicType: NamespaceTestF.getTypeScriptAlgebraicType() }, + ); + return _cached_Test_type_value; }, serialize(writer: __BinaryWriter, value: Test): void { diff --git a/crates/core/src/host/v8/mod.rs b/crates/core/src/host/v8/mod.rs index 16bd261eef3..0555aaecc5f 100644 --- a/crates/core/src/host/v8/mod.rs +++ b/crates/core/src/host/v8/mod.rs @@ -1,4 +1,4 @@ -use self::de::{deserialize_js, property}; +use self::de::property; use self::error::{ catch_exception, exception_already_thrown, log_traceback, BufferTooSmall, CodeError, ExcResult, JsStackTrace, TerminationError, Throwable, @@ -17,7 +17,7 @@ use crate::host::wasm_common::module_host_actor::{ }; use crate::host::wasm_common::{RowIters, TimingSpanSet}; use crate::host::wasmtime::{epoch_ticker, ticks_in_duration, EPOCH_TICKS_PER_SECOND}; -use crate::host::{ArgsTuple, Scheduler}; +use crate::host::Scheduler; use crate::{module_host_context::ModuleCreationContext, replica_context::ReplicaContext}; use core::ffi::c_void; use core::sync::atomic::{AtomicBool, Ordering}; @@ -26,13 +26,13 @@ use core::{ptr, str}; use spacetimedb_client_api_messages::energy::ReducerBudget; use spacetimedb_datastore::locking_tx_datastore::MutTxId; use spacetimedb_datastore::traits::Program; -use spacetimedb_lib::{bsatn, ConnectionId, Identity, RawModuleDef, Timestamp}; +use spacetimedb_lib::{RawModuleDef, Timestamp}; use spacetimedb_schema::auto_migrate::MigrationPolicy; use std::sync::{Arc, LazyLock}; use std::time::Instant; use v8::script_compiler::{compile_module, Source}; use v8::{ - scope, Context, ContextScope, Function, Isolate, IsolateHandle, Local, MapFnTo, Object, OwnedIsolate, PinScope, + scope, Context, ContextScope, Function, Isolate, IsolateHandle, Local, MapFnTo, OwnedIsolate, PinScope, ResolveModuleCallback, ScriptOrigin, Value, }; @@ -343,9 +343,8 @@ impl JsInstance { with_scope(&mut isolate, |scope| { let res = catch_exception(scope, |scope| { // Prepare the JS module that has `__call_reducer__`. - let (module, _) = eval_user_module(scope, &self.program)?; - let object = module_object(scope, module)?; - Ok(object) + eval_user_module(scope, &self.program)?; + Ok(()) }) .map_err(anyhow::Error::from); @@ -358,9 +357,9 @@ impl JsInstance { // Call `__call_reducer__` with `tx` provided. // It should not be available before. let (tx, call_result) = match res { - Ok(object) => env.instance_env.tx.clone().set(tx, || { + Ok(()) => env.instance_env.tx.clone().set(tx, || { catch_exception(scope, |scope| { - let res = call_call_reducer_from_op(scope, object, op)?; + let res = call_call_reducer_from_op(scope, op)?; Ok(res) }) .map_err(anyhow::Error::from) @@ -576,16 +575,6 @@ fn duration_to_budget(_duration: Duration) -> ReducerBudget { ReducerBudget::ZERO } -/// Returns a module's object. -fn module_object<'scope>( - scope: &PinScope<'scope, '_>, - module: Local<'scope, v8::Module>, -) -> ExcResult> { - let ns = module.get_module_namespace(); - let object = cast!(scope, ns, Object, "object for module").map_err(|e| e.throw(scope))?; - Ok(object) -} - /// Calls free function `fun` with `args`. fn call_free_fun<'scope>( scope: &PinScope<'scope, '_>, @@ -596,53 +585,9 @@ fn call_free_fun<'scope>( fun.call(scope, receiver, args).ok_or_else(exception_already_thrown) } -/// Calls the `__call_reducer__` function on `object` using `op`. -fn call_call_reducer_from_op<'scope>( - scope: &mut PinScope<'scope, '_>, - object: Local<'scope, Object>, - op: ReducerOp<'_>, -) -> ExcResult { - call_call_reducer( - scope, - object, - op.id.into(), - op.caller_identity, - op.caller_connection_id, - op.timestamp.to_micros_since_unix_epoch(), - op.args, - ) -} - -/// Calls the `__call_reducer__` property on `object` as a function. -fn call_call_reducer<'scope>( - scope: &mut PinScope<'scope, '_>, - object: Local<'scope, Object>, - reducer_id: u32, - sender: &Identity, - conn_id: &ConnectionId, - timestamp: i64, - reducer_args: &ArgsTuple, -) -> ExcResult { - // Serialize the arguments. - let reducer_id = serialize_to_js(scope, &reducer_id)?; - let sender = serialize_to_js(scope, &sender.to_u256())?; - let conn_id: v8::Local<'_, v8::Value> = serialize_to_js(scope, &conn_id.to_u128())?; - let timestamp = serialize_to_js(scope, ×tamp)?; - let reducer_args = serialize_to_js(scope, reducer_args.get_bsatn())?; - let args = &[reducer_id, sender, conn_id, timestamp, reducer_args]; - - // Get the function on the global proxy object and convert to a function. - let call_reducer_key = str_from_ident!(__call_reducer__).string(scope); - let object = property(scope, object, call_reducer_key)?; - let fun = cast!(scope, object, Function, "function export for `__call_reducer__`").map_err(|e| e.throw(scope))?; - - // Call the function. - let ret = call_free_fun(scope, fun, args)?; - - // Deserialize the user result. - let user_res = deserialize_js(scope, ret)?; - - Ok(user_res) +/// Calls the `__call_reducer__` hook, if it's been registered. +fn call_call_reducer_from_op<'scope>(scope: &mut PinScope<'scope, '_>, op: ReducerOp<'_>) -> ExcResult { + syscall::call_call_reducer(scope, op) } /// Extracts the raw module def by running `__describe_module__` in `program`. @@ -655,17 +600,16 @@ fn extract_description(program: &str) -> Result { let handle = isolate.thread_safe_handle(); with_timeout_and_cb_every(handle, callback_every, callback, budget, || { with_scope(&mut isolate, |scope| { - let object = catch_exception(scope, |scope| { - let (module, _) = eval_user_module(scope, program)?; - let object = module_object(scope, module)?; - Ok(object) + catch_exception(scope, |scope| { + eval_user_module(scope, program)?; + Ok(()) }) .map_err(Into::into) .map_err(DescribeError::Setup)?; run_describer(log_traceback, || { catch_exception(scope, |scope| { - let def = call_describe_module(scope, object)?; + let def = call_describe_module(scope)?; Ok(def) }) .map_err(Into::into) @@ -674,65 +618,38 @@ fn extract_description(program: &str) -> Result { }) } -/// Calls the `__describe_module__` property, -/// on `object` as a function, -/// to extract a [`RawModuleDef`]. -fn call_describe_module<'scope>( - scope: &mut PinScope<'scope, '_>, - object: Local<'scope, Object>, -) -> ExcResult { - // Get the function on `object` and convert to a function. - let describe_module_key = str_from_ident!(__describe_module__).string(scope); - let object = property(scope, object, describe_module_key)?; - let fun = - cast!(scope, object, Function, "function export for `__describe_module__`").map_err(|e| e.throw(scope))?; - - // Call the function. - let raw_mod_js = call_free_fun(scope, fun, &[])?; - - // Deserialize the raw module. - let raw_mod = cast!( - scope, - raw_mod_js, - v8::Uint8Array, - "bytes return from __describe_module__" - ) - .map_err(|e| e.throw(scope))?; - - let bytes = raw_mod.get_contents(&mut []); - bsatn::from_slice::(bytes).map_err(|_e| error::TypeError("invalid bsatn module def").throw(scope)) +/// Calls the `__describe_module__` hook, if it's been registered. +fn call_describe_module<'scope>(scope: &mut PinScope<'scope, '_>) -> ExcResult { + syscall::call_describe_module(scope) } #[cfg(test)] mod test { use super::*; use crate::host::v8::to_value::test::with_scope; - use v8::{Local, Value}; + use crate::host::ArgsTuple; + use spacetimedb_lib::{ConnectionId, Identity}; + use spacetimedb_primitives::ReducerId; + use v8::{Local, Object}; - fn with_script( + fn with_module( code: &str, - logic: impl for<'scope> FnOnce(&mut PinScope<'scope, '_>, Local<'scope, Value>) -> R, + logic: impl for<'scope> FnOnce(&mut PinScope<'scope, '_>, Local<'scope, Object>) -> R, ) -> R { with_scope(|scope| { - let code = v8::String::new(scope, code).unwrap(); - let script_val = v8::Script::compile(scope, code, None).unwrap().run(scope).unwrap(); - logic(scope, script_val) + let (module, _) = eval_user_module(scope, code).unwrap(); + let ns = module.get_module_namespace().cast::(); + logic(scope, ns) }) } - /// Returns the global object. - fn global<'scope>(scope: &PinScope<'scope, '_>) -> Local<'scope, Object> { - scope.get_current_context().global(scope) - } - - fn with_script_catch( + fn with_module_catch( code: &str, logic: impl for<'scope> FnOnce(&mut PinScope<'scope, '_>, Local<'scope, Object>) -> ExcResult, ) -> anyhow::Result { - with_script(code, |scope, _| { + with_module(code, |scope, ns| { catch_exception(scope, |scope| { - let object = global(scope); - let ret = logic(scope, object)?; + let ret = logic(scope, ns)?; Ok(ret) }) .map_err(anyhow::Error::from) @@ -742,15 +659,17 @@ mod test { #[test] fn call_call_reducer_works() { let call = |code| { - with_script_catch(code, |scope, object| { - call_call_reducer( + with_module_catch(code, |scope, _| { + call_call_reducer_from_op( scope, - object, - 42, - &Identity::ONE, - &ConnectionId::ZERO, - 24, - &ArgsTuple::nullary(), + ReducerOp { + id: ReducerId(42), + name: "foobar", + caller_identity: &Identity::ONE, + caller_connection_id: &ConnectionId::ZERO, + timestamp: Timestamp::from_micros_since_unix_epoch(24), + args: &ArgsTuple::nullary(), + }, ) }) }; @@ -758,27 +677,29 @@ mod test { // Test the trap case. let ret = call( r#" - function __call_reducer__(reducer_id, sender, conn_id, timestamp, args) { + import { register_hooks } from "spacetime:sys@1.0"; + register_hooks({ __call_reducer__(reducer_id, sender, conn_id, timestamp, args) { throw new Error("foobar"); - } + } }) "#, ); let actual = format!("{}", ret.expect_err("should trap")).replace("\t", " "); let expected = r#" js error Uncaught Error: foobar - at __call_reducer__ (:3:23) + at __call_reducer__ (spacetimedb_module:4:23) "#; assert_eq!(actual.trim(), expected.trim()); // Test the error case. let ret = call( r#" - function __call_reducer__(reducer_id, sender, conn_id, timestamp, args) { + import { register_hooks } from "spacetime:sys@1.0"; + register_hooks({ __call_reducer__(reducer_id, sender, conn_id, timestamp, args) { return { "tag": "err", "value": "foobar", }; - } + } }) "#, ); assert_eq!(&*ret.expect("should not trap").expect_err("should error"), "foobar"); @@ -786,12 +707,13 @@ js error Uncaught Error: foobar // Test the error case. let ret = call( r#" - function __call_reducer__(reducer_id, sender, conn_id, timestamp, args) { + import { register_hooks } from "spacetime:sys@1.0"; + register_hooks({ __call_reducer__(reducer_id, sender, conn_id, timestamp, args) { return { "tag": "ok", "value": {}, }; - } + } }) "#, ); ret.expect("should not trap").expect("should not error"); @@ -800,11 +722,12 @@ js error Uncaught Error: foobar #[test] fn call_describe_module_works() { let code = r#" - function __describe_module__() { + import { register_hooks } from "spacetime:sys@1.0"; + register_hooks({ __describe_module__() { return new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - } + } }) "#; - let raw_mod = with_script_catch(code, call_describe_module).map_err(|e| e.to_string()); + let raw_mod = with_module_catch(code, |scope, _| call_describe_module(scope)).map_err(|e| e.to_string()); assert_eq!(raw_mod, Ok(RawModuleDef::V9(<_>::default()))); } } diff --git a/crates/core/src/host/v8/syscall.rs b/crates/core/src/host/v8/syscall.rs index f9fcb272275..fb6df035845 100644 --- a/crates/core/src/host/v8/syscall.rs +++ b/crates/core/src/host/v8/syscall.rs @@ -1,23 +1,27 @@ +use std::rc::Rc; + use super::de::{deserialize_js, scratch_buf}; -use super::error::{module_exception, ExcResult, ExceptionThrown}; +use super::error::{module_exception, ExcResult, ExceptionThrown, TypeError}; +use super::from_value::cast; use super::ser::serialize_to_js; use super::string::{str_from_ident, StringConst}; use super::{ - env_on_isolate, exception_already_thrown, BufferTooSmall, CodeError, JsInstanceEnv, JsStackTrace, TerminationError, - Throwable, + call_free_fun, env_on_isolate, exception_already_thrown, property, BufferTooSmall, CodeError, JsInstanceEnv, + JsStackTrace, TerminationError, Throwable, }; use crate::database_logger::{LogLevel, Record}; use crate::error::NodesError; use crate::host::instance_env::InstanceEnv; use crate::host::wasm_common::instrumentation::span; +use crate::host::wasm_common::module_host_actor::{ReducerOp, ReducerResult}; use crate::host::wasm_common::{err_to_errno_and_log, RowIterIdx, TimingSpan, TimingSpanIdx}; use crate::host::AbiCall; -use spacetimedb_lib::Identity; -use spacetimedb_primitives::{errno, ColId, IndexId, TableId}; +use spacetimedb_lib::{bsatn, Identity, RawModuleDef}; +use spacetimedb_primitives::{errno, ColId, IndexId, ReducerId, TableId}; use spacetimedb_sats::Serialize; use v8::{ callback_scope, ConstructorBehavior, Context, FixedArray, Function, FunctionCallbackArguments, Local, Module, - PinCallbackScope, PinScope, Value, + Object, PinCallbackScope, PinScope, Value, }; /// A dependency resolver for the user's module @@ -61,6 +65,7 @@ fn register_sys_module<'scope>(scope: &mut PinScope<'scope, '_>) -> Local<'scope } create_synthetic_module!( + (with_nothing, (), register_hooks), (with_sys_result, AbiCall::TableIdFromName, table_id_from_name), (with_sys_result, AbiCall::IndexIdFromName, index_id_from_name), ( @@ -179,6 +184,15 @@ fn with_sys_result<'scope, O: Serialize>( } } +fn with_nothing<'scope>( + (): (), + scope: &mut PinScope<'scope, '_>, + args: FunctionCallbackArguments<'scope>, + run: impl FnOnce(&mut PinScope<'scope, '_>, FunctionCallbackArguments<'scope>) -> FnRet<'scope>, +) -> FnRet<'scope> { + run(scope, args) +} + /// Turns a [`NodesError`] into a thrown exception. fn throw_nodes_error(abi_call: AbiCall, scope: &mut PinScope<'_, '_>, error: NodesError) -> ExceptionThrown { let res = match err_to_errno_and_log::(abi_call, error) { @@ -226,6 +240,131 @@ fn with_span<'scope, R>( result } +/// Module ABI that registers the functions called by the host. +/// +/// # Signature +/// +/// ```ignore +/// register_hooks(hooks: { +/// __describe_module__: () => u8[]; +/// __call_reducer__: ( +/// reducer_id: u32, +/// sender: u256, +/// conn_id: u128, +/// timestamp: i64, +/// args_buf: u8[] +/// ) => { tag: 'ok' } | { tag: 'err'; value: string }; +/// }): void +/// ``` +/// +/// # Types +/// +/// - `u8` is `number` in JS restricted to unsigned 8-bit integers. +/// - `u16` is `number` in JS restricted to unsigned 16-bit integers. +/// - `i64` is `bigint` in JS restricted to signed 64-bit integers. +/// - `u128` is `bigint` in JS restricted to unsigned 128-bit integers. +/// - `u256` is `bigint` in JS restricted to unsigned 256-bit integers. +/// +/// # Returns +/// +/// Returns nothing. +fn register_hooks<'scope>(scope: &mut PinScope<'scope, '_>, args: FunctionCallbackArguments<'_>) -> FnRet<'scope> { + let hooks = super::cast!(scope, args.get(0), Object, "hooks object").map_err(|e| e.throw(scope))?; + let ctx = scope.get_current_context(); + // `set_slot`` creates the annex - needs to be called first + // because `set_embedder_data` is currently buggy + ctx.set_slot(Rc::new(AbiVersion::V1)); + ctx.set_embedder_data(HOOKS_SLOT, hooks.into()); + Ok(v8::undefined(scope).into()) +} + +/// The `v8::Context::{get,set}_embedder_data` slot that holds the hooks object. +const HOOKS_SLOT: i32 = 20; + +#[derive(Copy, Clone)] +enum AbiVersion { + V1, +} + +fn get_hooks<'scope>(scope: &mut PinScope<'scope, '_>) -> ExcResult<(AbiVersion, Local<'scope, Object>)> { + let ctx = scope.get_current_context(); + let abi_version = *ctx + .get_slot::() + .ok_or_else(|| TypeError("module hooks were never registered").throw(scope))?; + + let hooks = ctx + .get_embedder_data(scope, HOOKS_SLOT) + .expect("if AbiVersion is set hooks must be set"); + Ok((abi_version, hooks.cast())) +} + +/// Calls the `__call_reducer__` hook, if it's been registered. +pub(super) fn call_call_reducer<'scope>( + scope: &mut PinScope<'scope, '_>, + op: ReducerOp<'_>, +) -> ExcResult { + let (abi_ver, hooks_obj) = get_hooks(scope)?; + let AbiVersion::V1 = abi_ver; + + let ReducerOp { + id: ReducerId(reducer_id), + name: _, + caller_identity: sender, + caller_connection_id: conn_id, + timestamp, + args: reducer_args, + } = op; + // Serialize the arguments. + let reducer_id = serialize_to_js(scope, &reducer_id)?; + let sender = serialize_to_js(scope, &sender.to_u256())?; + let conn_id: v8::Local<'_, v8::Value> = serialize_to_js(scope, &conn_id.to_u128())?; + let timestamp = serialize_to_js(scope, ×tamp)?; + let reducer_args = serialize_to_js(scope, reducer_args.get_bsatn())?; + let args = &[reducer_id, sender, conn_id, timestamp, reducer_args]; + + // Get the function on the global proxy object and convert to a function. + let call_reducer_key = str_from_ident!(__call_reducer__).string(scope); + let object = property(scope, hooks_obj, call_reducer_key)?; + let fun = cast!(scope, object, Function, "function export for `__call_reducer__`").map_err(|e| e.throw(scope))?; + + // Call the function. + let ret = call_free_fun(scope, fun, args)?; + + // Deserialize the user result. + let user_res = deserialize_js(scope, ret)?; + + Ok(user_res) +} + +/// Calls the `__describe_module__` hook, if it's been registered. +pub(super) fn call_describe_module<'scope>(scope: &mut PinScope<'scope, '_>) -> ExcResult { + let (abi_ver, hooks_obj) = get_hooks(scope)?; + let AbiVersion::V1 = abi_ver; + + // Get the function on `object` and convert to a function. + let describe_module_key = str_from_ident!(__describe_module__).string(scope); + let object = property(scope, hooks_obj, describe_module_key)?; + let fun = + cast!(scope, object, Function, "function export for `__describe_module__`").map_err(|e| e.throw(scope))?; + + // Call the function. + let raw_mod_js = call_free_fun(scope, fun, &[])?; + + // Deserialize the raw module. + let raw_mod = cast!( + scope, + raw_mod_js, + v8::Uint8Array, + "bytes return from __describe_module__" + ) + .map_err(|e| e.throw(scope))?; + + let bytes = raw_mod.get_contents(&mut []); + let module = + bsatn::from_slice::(bytes).map_err(|_e| TypeError("invalid bsatn module def").throw(scope))?; + Ok(module) +} + /// Module ABI that finds the `TableId` for a table name. /// /// # Signature diff --git a/crates/core/src/messages/control_db.rs b/crates/core/src/messages/control_db.rs index d3d209e728c..c60584af2e2 100644 --- a/crates/core/src/messages/control_db.rs +++ b/crates/core/src/messages/control_db.rs @@ -90,6 +90,7 @@ pub struct NodeStatus { serde::Deserialize, strum::AsRefStr, strum::Display, + strum::EnumString, )] #[repr(i32)] pub enum HostType { diff --git a/crates/schema/tests/ensure_same_schema.rs b/crates/schema/tests/ensure_same_schema.rs index 3625330181d..406d2b90749 100644 --- a/crates/schema/tests/ensure_same_schema.rs +++ b/crates/schema/tests/ensure_same_schema.rs @@ -1,65 +1,82 @@ // Wrap these tests in a `mod` whose name contains `csharp` // so that we can run tests with `--skip csharp` in environments without dotnet installed. -mod ensure_same_schema_rust_csharp { - use serial_test::serial; - use spacetimedb_schema::auto_migrate::{ponder_auto_migrate, AutoMigrateStep}; - use spacetimedb_schema::def::ModuleDef; - use spacetimedb_testing::modules::{CompilationMode, CompiledModule}; +use serial_test::serial; +use spacetimedb_schema::auto_migrate::{ponder_auto_migrate, AutoMigrateStep}; +use spacetimedb_schema::def::ModuleDef; +use spacetimedb_testing::modules::{CompilationMode, CompiledModule}; - fn get_normalized_schema(module_name: &str) -> ModuleDef { - let module = CompiledModule::compile(module_name, CompilationMode::Debug); - module.extract_schema_blocking() - } +fn get_normalized_schema(module_name: &str) -> ModuleDef { + let module = CompiledModule::compile(module_name, CompilationMode::Debug); + module.extract_schema_blocking() +} - fn assert_identical_modules(module_name_prefix: &str) { - let rs = get_normalized_schema(module_name_prefix); - let cs = get_normalized_schema(&format!("{module_name_prefix}-cs")); - let mut diff = ponder_auto_migrate(&cs, &rs) - .expect("could not compute a diff between Rust and C#") - .steps; +fn assert_identical_modules(module_name_prefix: &str, lang_name: &str, suffix: &str) { + let rs = get_normalized_schema(module_name_prefix); + let cs = get_normalized_schema(&format!("{module_name_prefix}-{suffix}")); + let mut diff = ponder_auto_migrate(&cs, &rs) + .unwrap_or_else(|e| panic!("could not compute a diff between Rust and {lang_name}: {e:?}")) + .steps; - // In any migration plan, all `RowLevelSecurityDef`s are ALWAYS removed and - // re-added to ensure the core engine reinintializes the policies. - // This is slightly silly (and arguably should be hidden inside `core`), - // but for now, we just ignore these steps and manually compare the `RowLevelSecurityDef`s. - diff.retain(|step| { - !matches!( - step, - AutoMigrateStep::AddRowLevelSecurity(_) | AutoMigrateStep::RemoveRowLevelSecurity(_) - ) - }); + // In any migration plan, all `RowLevelSecurityDef`s are ALWAYS removed and + // re-added to ensure the core engine reinintializes the policies. + // This is slightly silly (and arguably should be hidden inside `core`), + // but for now, we just ignore these steps and manually compare the `RowLevelSecurityDef`s. + diff.retain(|step| { + !matches!( + step, + AutoMigrateStep::AddRowLevelSecurity(_) | AutoMigrateStep::RemoveRowLevelSecurity(_) + ) + }); - assert!( - diff.is_empty(), - "Rust and C# modules are not identical. Here are the steps to migrate from C# to Rust: {diff:#?}" - ); + assert!( + diff.is_empty(), + "Rust and {lang_name} modules are not identical. Here are the steps to migrate from {lang_name} to Rust: {diff:#?}" + ); - let mut rls_rs = rs.row_level_security().collect::>(); - rls_rs.sort(); - let mut rls_cs = cs.row_level_security().collect::>(); - rls_cs.sort(); - assert_eq!( - rls_rs, rls_cs, - "Rust and C# modules are not identical: different row level security policies" - ) - } + let mut rls_rs = rs.row_level_security().collect::>(); + rls_rs.sort(); + let mut rls_cs = cs.row_level_security().collect::>(); + rls_cs.sort(); + assert_eq!( + rls_rs, rls_cs, + "Rust and {lang_name} modules are not identical: different row level security policies" + ) +} - macro_rules! declare_tests { +macro_rules! declare_tests { ($($name:ident => $path:literal,)*) => { - $( - #[test] - #[serial] - fn $name() { - assert_identical_modules($path); - } - )* + mod ensure_same_schema_rust_csharp { + use super::*; + $( + #[test] + #[serial] + fn $name() { + super::assert_identical_modules($path, "C#", "cs"); + } + )* + } + mod ensure_same_schema_rust_typescript { + use super::*; + $( + #[test] + #[serial] + fn $name() { + super::assert_identical_modules($path, "typescript", "ts"); + } + )* + } } } - declare_tests! { - module_test => "module-test", - sdk_test_connect_disconnect => "sdk-test-connect-disconnect", - sdk_test => "sdk-test", - benchmarks => "benchmarks", - } +declare_tests! { + module_test => "module-test", + sdk_test_connect_disconnect => "sdk-test-connect-disconnect", + sdk_test => "sdk-test", +} + +// FIXME: Move `benchmarks => "benchmarks,` back into the macro once `benchmarks-ts` exists +#[test] +#[serial] +fn ensure_same_schema_rust_csharp_benchmarks() { + assert_identical_modules("benchmarks", "C#", "cs"); } diff --git a/crates/standalone/src/subcommands/extract_schema.rs b/crates/standalone/src/subcommands/extract_schema.rs index 4e7b7a831d9..9b85e57059a 100644 --- a/crates/standalone/src/subcommands/extract_schema.rs +++ b/crates/standalone/src/subcommands/extract_schema.rs @@ -38,6 +38,7 @@ impl HostType { fn from_extension(ext: &str) -> Option { match ext { "wasm" => Some(Self::Wasm), + "js" => Some(Self::Js), _ => None, } } diff --git a/crates/testing/src/lib.rs b/crates/testing/src/lib.rs index 61e7adc29c5..f99a46f4769 100644 --- a/crates/testing/src/lib.rs +++ b/crates/testing/src/lib.rs @@ -1,4 +1,5 @@ use clap::Command as ClapCommand; +use spacetimedb::messages::control_db::HostType; use spacetimedb_cli::Config; use spacetimedb_paths::SpacetimePaths; use spacetimedb_schema::def::ModuleDef; @@ -69,7 +70,11 @@ fn extract_descriptions(wasm_file: &std::path::Path) -> anyhow::Result HostType::Wasm, + "js" => HostType::Js, + _ => unreachable!(), + }, )) }) } diff --git a/crates/testing/src/modules.rs b/crates/testing/src/modules.rs index 150171871e9..1a16c42f39d 100644 --- a/crates/testing/src/modules.rs +++ b/crates/testing/src/modules.rs @@ -94,6 +94,7 @@ impl ModuleHandle { pub struct CompiledModule { name: String, path: PathBuf, + pub(super) host_type: HostType, program_bytes: OnceLock>, } @@ -105,7 +106,7 @@ pub enum CompilationMode { impl CompiledModule { pub fn compile(name: &str, mode: CompilationMode) -> Self { - let path = spacetimedb_cli::build( + let (path, host_type) = spacetimedb_cli::build( &module_path(name), Some(PathBuf::from("src")).as_deref(), mode == CompilationMode::Debug, @@ -114,6 +115,7 @@ impl CompiledModule { Self { name: name.to_owned(), path, + host_type: host_type.parse().unwrap(), program_bytes: OnceLock::new(), } } @@ -127,7 +129,7 @@ impl CompiledModule { } pub async fn extract_schema(&self) -> ModuleDef { - spacetimedb::host::extract_schema(self.program_bytes().into(), HostType::Wasm) + spacetimedb::host::extract_schema(self.program_bytes().into(), self.host_type) .await .unwrap() } @@ -204,7 +206,7 @@ impl CompiledModule { database_identity: db_identity, program_bytes, num_replicas: None, - host_type: HostType::Wasm, + host_type: self.host_type, }, MigrationPolicy::Compatible, ) diff --git a/crates/testing/src/sdk.rs b/crates/testing/src/sdk.rs index 5eb18e9ea2d..6060e224b84 100644 --- a/crates/testing/src/sdk.rs +++ b/crates/testing/src/sdk.rs @@ -1,5 +1,6 @@ use duct::cmd; use rand::seq::IteratorRandom; +use spacetimedb::messages::control_db::HostType; use spacetimedb_data_structures::map::HashMap; use spacetimedb_paths::{RootDir, SpacetimePaths}; use std::fs::create_dir_all; @@ -119,19 +120,20 @@ impl Test { pub fn run(self) { let paths = ensure_standalone_process(); - let wasm_file = compile_module(&self.module_name); + let (file, host_type) = compile_module(&self.module_name); generate_bindings( paths, &self.generate_language, - &wasm_file, + &file, + host_type, &self.client_project, &self.generate_subdir, ); compile_client(&self.compile_command, &self.client_project); - let db_name = publish_module(paths, &wasm_file); + let db_name = publish_module(paths, &file, host_type); run_client(&self.run_command, &self.client_project, &db_name); } @@ -196,18 +198,18 @@ macro_rules! memoized { // which is bad both for performance reasons as well as can lead to errors // with toolchains like .NET which don't expect parallel invocations // of their build tools on the same project folder. -fn compile_module(module: &str) -> String { +fn compile_module(module: &str) -> (String, HostType) { let module = module.to_owned(); - memoized!(|module: String| -> String { + memoized!(|module: String| -> (String, HostType) { let module = CompiledModule::compile(module, CompilationMode::Debug); - module.path().to_str().unwrap().to_owned() + (module.path().to_str().unwrap().to_owned(), module.host_type) }) } // Note: this function does not memoize because we want each test to publish the same // module as a separate clean database instance for isolation purposes. -fn publish_module(paths: &SpacetimePaths, wasm_file: &str) -> String { +fn publish_module(paths: &SpacetimePaths, wasm_file: &str, host_type: HostType) -> String { let name = random_module_name(); invoke_cli( paths, @@ -216,7 +218,10 @@ fn publish_module(paths: &SpacetimePaths, wasm_file: &str) -> String { "--anonymous", "--server", "local", - "--bin-path", + match host_type { + HostType::Wasm => "--bin-path", + HostType::Js => "--js-path", + }, wasm_file, &name, ], @@ -275,6 +280,7 @@ fn generate_bindings( paths: &SpacetimePaths, language: &str, wasm_file: &str, + host_type: HostType, client_project: &str, generate_subdir: &str, ) { @@ -286,7 +292,16 @@ fn generate_bindings( // so our memoization has unit as the value. // This makes it run at most once for each key. memoized!(|(client_project, generate_subdir): (String, String)| -> () { - let mut args: Vec<&str> = vec!["generate", "--lang", language, "--bin-path", wasm_file]; + let mut args: Vec<&str> = vec![ + "generate", + "--lang", + language, + match host_type { + HostType::Wasm => "--bin-path", + HostType::Js => "--js-path", + }, + wasm_file, + ]; let generate_dir: String; diff --git a/crates/testing/tests/standalone_integration_test.rs b/crates/testing/tests/standalone_integration_test.rs index 856184014b1..e8e9f710693 100644 --- a/crates/testing/tests/standalone_integration_test.rs +++ b/crates/testing/tests/standalone_integration_test.rs @@ -99,6 +99,12 @@ fn test_calling_a_reducer_csharp() { test_calling_a_reducer_in_module("module-test-cs"); } +#[test] +#[serial] +fn test_calling_a_reducer_typescript() { + test_calling_a_reducer_in_module("module-test-ts"); +} + #[test] #[serial] fn test_calling_a_reducer_with_private_table() { diff --git a/docs/docs/cli-reference.md b/docs/docs/cli-reference.md index 11045a959f1..e28061f97b4 100644 --- a/docs/docs/cli-reference.md +++ b/docs/docs/cli-reference.md @@ -250,6 +250,7 @@ Run `spacetime help publish` for more detailed information. ###### Options: * `-b`, `--bin-path ` — The system path (absolute or relative) to the compiled wasm binary we should inspect +* `-j`, `--js-path ` — The system path (absolute or relative) to the bundled javascript file we should inspect * `-p`, `--project-path ` — The system path (absolute or relative) to the project you would like to inspect Default value: `.` @@ -333,7 +334,7 @@ Initializes a new spacetime project. WARNING: This command is UNSTABLE and subje * `-l`, `--lang ` — The spacetime module language. - Possible values: `csharp`, `rust` + Possible values: `csharp`, `rust`, `typescript` ## spacetime build diff --git a/modules/module-test-ts/package-lock.json b/modules/module-test-ts/package-lock.json new file mode 100644 index 00000000000..69a1f0ac828 --- /dev/null +++ b/modules/module-test-ts/package-lock.json @@ -0,0 +1,113 @@ +{ + "name": "sdk-test-module", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sdk-test-module", + "license": "ISC", + "dependencies": { + "fast-text-encoding": "^1.0.0" + }, + "devDependencies": { + "@types/fast-text-encoding": "^1.0.3", + "tsup": "^8.1.0" + } + }, + "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding": { + "version": "1.0.6", + "license": "Apache-2.0" + }, + "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup": { + "version": "8.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.25.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.50.0", + "@rollup/plugin-json": "6.1.0", + "@swc/core": "1.10.18", + "@types/debug": "4.1.12", + "@types/node": "22.13.4", + "@types/resolve": "1.20.6", + "bumpp": "^10.0.3", + "flat": "6.0.1", + "postcss": "8.5.2", + "postcss-simple-vars": "7.0.1", + "prettier": "3.5.1", + "resolve": "1.22.10", + "rollup-plugin-dts": "6.1.1", + "sass": "1.85.0", + "strip-json-comments": "5.0.1", + "svelte": "5.19.9", + "svelte-preprocess": "6.0.3", + "terser": "^5.39.0", + "ts-essentials": "10.0.4", + "tsup": "8.3.6", + "typescript": "5.7.3", + "vitest": "3.0.6", + "wait-for-expect": "3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@types/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-bbGJt6IyiuyAhPOX7htQDDzv2bDGJdWyd6X+e1BcdPzU3e5jyjOdB86LoTSoE80faY9v8Wt7/ix3Sp+coRJ03Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-text-encoding": { + "resolved": "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding", + "link": true + }, + "node_modules/tsup": { + "resolved": "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup", + "link": true + } + } +} diff --git a/modules/module-test-ts/package.json b/modules/module-test-ts/package.json new file mode 100644 index 00000000000..4e964319a75 --- /dev/null +++ b/modules/module-test-ts/package.json @@ -0,0 +1,13 @@ +{ + "name": "sdk-test-module", + "license": "ISC", + "type": "module", + "scripts": { + "build": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- build", + "generate-ts": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- generate --lang typescript --out-dir ts-codegen", + "publish": "cargo run -p spacetimedb-cli -- publish" + }, + "dependencies": { + "spacetimedb": "workspace:^" + } +} diff --git a/modules/module-test-ts/src/index.ts b/modules/module-test-ts/src/index.ts new file mode 100644 index 00000000000..ab035e4ebb2 --- /dev/null +++ b/modules/module-test-ts/src/index.ts @@ -0,0 +1,430 @@ +// ───────────────────────────────────────────────────────────────────────────── +// IMPORTS +// ───────────────────────────────────────────────────────────────────────────── +import { ScheduleAt } from 'spacetimedb'; +import { + schema, + table, + t, + type Infer, + type InferTypeOfRow, +} from 'spacetimedb/server'; + +// ───────────────────────────────────────────────────────────────────────────── +// TYPE ALIASES +// ───────────────────────────────────────────────────────────────────────────── +// Rust: pub type TestAlias = TestA +type TestAlias = TestA; + +// ───────────────────────────────────────────────────────────────────────────── +// SUPPORT TYPES (SpacetimeType equivalents) +// ───────────────────────────────────────────────────────────────────────────── + +// Rust: #[derive(SpacetimeType)] pub struct TestB { foo: String } +const testB = t.object('TestB', { + foo: t.string(), +}); +type TestB = Infer; + +// Rust: #[derive(SpacetimeType)] #[sats(name = "Namespace.TestC")] enum TestC { Foo, Bar } +const testC = t.enum('Namespace.TestC', { + Foo: t.unit(), + Bar: t.unit(), +}); +type TestC = Infer; + +// Rust: const DEFAULT_TEST_C: TestC = TestC::Foo; +const DEFAULT_TEST_C: TestC = { tag: 'Foo', value: {} } as const; + +// Rust: #[derive(SpacetimeType)] pub struct Baz { pub field: String } +const Baz = t.object('Baz', { + field: t.string(), +}); +type Baz = Infer; + +// Rust: #[derive(SpacetimeType)] pub enum Foobar { Baz(Baz), Bar, Har(u32) } +const foobar = t.enum('Foobar', { + Baz: Baz, + Bar: t.unit(), + Har: t.u32(), +}); +type Foobar = Infer; + +// Rust: #[derive(SpacetimeType)] #[sats(name = "Namespace.TestF")] enum TestF { Foo, Bar, Baz(String) } +const testF = t.enum('Namespace.TestF', { + Foo: t.unit(), + Bar: t.unit(), + Baz: t.string(), +}); +type TestF = Infer; + +// Rust: #[derive(Deserialize)] pub struct Foo<'a> { pub field: &'a str } +// In TS we simply model as a struct and provide a BSATN deserializer placeholder. +const Foo = t.object('Foo', { field: t.string() }); +type Foo = Infer; +function Foo_baz_bsatn(_bytes: Uint8Array): Foo { + // If your bindings expose a bsatn decode helper, use it here. + // return bsatn.fromSlice(bytes, Foo); + throw new Error('Implement BSATN decode for Foo if needed'); +} + +// ───────────────────────────────────────────────────────────────────────────── +// TABLE ROW DEFINITIONS (shape only) +// ───────────────────────────────────────────────────────────────────────────── + +// Rust: #[spacetimedb::table(name = person, public, index(name = age, btree(columns = [age])))] +const personRow = { + id: t.u32().primaryKey().autoInc(), + name: t.string(), + age: t.u8(), +}; + +// Rust: #[spacetimedb::table(name = test_a, index(name = foo, btree(columns = [x])))] +const testA = t.row({ + x: t.u32(), + y: t.u32(), + z: t.string(), +}); +type TestA = Infer; + +// Rust: #[table(name = test_d, public)] struct TestD { #[default(Some(DEFAULT_TEST_C))] test_c: Option, } +// NOTE: If your Option default requires wrapping, adjust to your bindings’ Option encoding. +const testDRow = { + test_c: t.option(testC).default(DEFAULT_TEST_C as unknown as any), +}; +type TestD = InferTypeOfRow; + +// Rust: #[spacetimedb::table(name = test_e)] #[derive(Debug)] +const testERow = { + id: t.u64().primaryKey().autoInc(), + name: t.string(), +}; + +// Rust: #[table(name = test_f, public)] pub struct TestFoobar { pub field: Foobar } +const testFRow = { + field: foobar, +}; + +// Rust: #[spacetimedb::table(name = private_table, private)] +const privateTableRow = { + name: t.string(), +}; + +// Rust: #[spacetimedb::table(name = points, private, index(name = multi_column_index, btree(columns = [x, y])))] +const pointsRow = { + x: t.i64(), + y: t.i64(), +}; + +// Rust: #[spacetimedb::table(name = pk_multi_identity)] +const pkMultiIdentityRow = { + id: t.u32().primaryKey(), + other: t.u32().unique().autoInc(), +}; + +// Rust: #[spacetimedb::table(name = repeating_test_arg, scheduled(repeating_test))] +const repeatingTestArg = t.row({ + scheduled_id: t.u64().primaryKey().autoInc(), + scheduled_at: t.scheduleAt(), + prev_time: t.timestamp(), +}); +type RepeatingTestArg = Infer; + +// Rust: #[spacetimedb::table(name = has_special_stuff)] +const hasSpecialStuffRow = { + identity: t.identity(), + connection_id: t.connectionId(), +}; + +// Rust: two tables with the same row type: player & logged_out_player +const playerLikeRow = { + identity: t.identity().primaryKey(), + player_id: t.u64().autoInc().unique(), + name: t.string().unique(), +}; + +// ───────────────────────────────────────────────────────────────────────────── +// SCHEMA (tables + indexes + visibility) +// ───────────────────────────────────────────────────────────────────────────── +const spacetimedb = schema( + // person (public) with btree index on age + table( + { + name: 'person', + public: true, + indexes: [{ name: 'age', algorithm: 'btree', columns: ['age'] }], + }, + personRow + ), + + // test_a with index foo on x + table( + { + name: 'test_a', + indexes: [{ name: 'foo', algorithm: 'btree', columns: ['x'] }], + }, + testA + ), + + // test_d (public) with default(Some(DEFAULT_TEST_C)) option field + table({ name: 'test_d', public: true }, testDRow), + + // test_e, default private, with primary key id auto_inc and btree index on name + table( + { + name: 'test_e', + public: false, + indexes: [{ name: 'name', algorithm: 'btree', columns: ['name'] }], + }, + testERow + ), + + // test_f (public) with Foobar field + table({ name: 'test_f', public: true }, testFRow), + + // private_table (explicit private) + table({ name: 'private_table', public: false }, privateTableRow), + + // points (private) with multi-column btree index (x, y) + table( + { + name: 'points', + public: false, + indexes: [ + { name: 'multi_column_index', algorithm: 'btree', columns: ['x', 'y'] }, + ], + }, + pointsRow + ), + + // pk_multi_identity with multiple constraints + table({ name: 'pk_multi_identity' }, pkMultiIdentityRow), + + // repeating_test_arg table with scheduled(repeating_test) + table( + { name: 'repeating_test_arg', scheduled: 'repeating_test' } as any, + repeatingTestArg + ), + + // has_special_stuff with Identity and ConnectionId + table({ name: 'has_special_stuff' }, hasSpecialStuffRow), + + // Two tables with the same row type: player and logged_out_player + table({ name: 'player', public: true }, playerLikeRow), + table({ name: 'logged_out_player', public: true }, playerLikeRow) +); + +// ───────────────────────────────────────────────────────────────────────────── +// REDUCERS (mirroring Rust order & behavior) +// ───────────────────────────────────────────────────────────────────────────── + +// init +spacetimedb.reducer('init', {}, ctx => { + ctx.db.repeating_test_arg.insert({ + prev_time: ctx.timestamp, + scheduled_id: 0n, // u64 autoInc placeholder (engine will assign) + scheduled_at: ScheduleAt.interval(1000000n), // 1000ms + }); +}); + +// repeating_test +spacetimedb.reducer( + 'repeating_test', + { arg: repeatingTestArg }, + (ctx, { arg }) => { + const delta = ctx.timestamp.since(arg.prev_time); // adjust if API differs + console.trace(`Timestamp: ${ctx.timestamp}, Delta time: ${delta}`); + } +); + +// add(name, age) +spacetimedb.reducer( + 'add', + { name: t.string(), age: t.u8() }, + (ctx, { name, age }) => { + ctx.db.person.insert({ id: 0, name, age }); + } +); + +// say_hello() +spacetimedb.reducer('say_hello', {}, ctx => { + for (const person of ctx.db.person.iter()) { + console.info(`Hello, ${person.name}!`); + } + console.info('Hello, World!'); +}); + +// list_over_age(age) +spacetimedb.reducer('list_over_age', { age: t.u8() }, (ctx, { age }) => { + // Prefer an index-based scan if exposed by bindings; otherwise iterate. + for (const person of ctx.db.person.iter()) { + if (person.age >= age) { + console.info(`${person.name} has age ${person.age} >= ${age}`); + } + } +}); + +// log_module_identity() +spacetimedb.reducer('log_module_identity', {}, ctx => { + console.info(`Module identity: ${ctx.identity}`); +}); + +// test(arg: TestAlias(TestA), arg2: TestB, arg3: TestC, arg4: TestF) +spacetimedb.reducer( + 'test', + { arg: testA, arg2: testB, arg3: testC, arg4: testF }, + (ctx, { arg, arg2, arg3, arg4 }) => { + console.info('BEGIN'); + console.info(`sender: ${ctx.sender}`); + console.info(`timestamp: ${ctx.timestamp}`); + console.info(`bar: ${arg2.foo}`); + + // TestC + if (arg3.tag === 'Foo') console.info('Foo'); + else if (arg3.tag === 'Bar') console.info('Bar'); + + // TestF + if (arg4.tag === 'Foo') console.info('Foo'); + else if (arg4.tag === 'Bar') console.info('Bar'); + else if (arg4.tag === 'Baz') console.info(arg4.value); + + // Insert test_a rows + for (let i = 0; i < 1000; i++) { + ctx.db.test_a.insert({ + x: (i >>> 0) + arg.x, + y: (i >>> 0) + arg.y, + z: 'Yo', + }); + } + + const rowCountBefore = ctx.db.test_a.count(); + console.info(`Row count before delete: ${rowCountBefore}`); + + // Delete rows by the indexed column `x` in [5,10) + let numDeleted = 0; + for (let x = 5; x < 10; x++) { + // Prefer index deletion if available; fallback to filter+delete + for (const row of ctx.db.test_a.iter()) { + if (row.x === x) { + if (ctx.db.test_a.delete(row)) numDeleted++; + } + } + } + + const rowCountAfter = ctx.db.test_a.count(); + if (Number(rowCountBefore) !== Number(rowCountAfter) + numDeleted) { + console.error( + `Started with ${rowCountBefore} rows, deleted ${numDeleted}, and wound up with ${rowCountAfter} rows... huh?` + ); + } + + // try_insert TestE { id: 0, name: "Tyler" } + try { + const inserted = ctx.db.test_e.tryInsert({ id: 0n, name: 'Tyler' }); + console.info(`Inserted: ${JSON.stringify(inserted)}`); + } catch (err) { + console.info(`Error: ${String(err)}`); + } + + console.info(`Row count after delete: ${rowCountAfter}`); + + const otherRowCount = ctx.db.test_a.count(); + console.info(`Row count filtered by condition: ${otherRowCount}`); + + console.info('MultiColumn'); + + for (let i = 0; i < 1000; i++) { + ctx.db.points.insert({ + x: BigInt(i) + BigInt(arg.x), + y: BigInt(i) + BigInt(arg.y), + }); + } + + let multiRowCount = 0; + for (const row of ctx.db.points.iter()) { + if (row.x >= 0n && row.y <= 200n) multiRowCount++; + } + console.info( + `Row count filtered by multi-column condition: ${multiRowCount}` + ); + + console.info('END'); + } +); + +// add_player(name) -> Result<(), String> +spacetimedb.reducer('add_player', { name: t.string() }, (ctx, { name }) => { + const rec = { id: 0n as bigint, name }; + const inserted = ctx.db.test_e.insert(rec); // id autoInc => always creates a new one + // No-op re-upsert by id index if your bindings support it. + if (ctx.db.test_e.id?.update) ctx.db.test_e.id.update(inserted); +}); + +// delete_player(id) -> Result<(), String> +spacetimedb.reducer('delete_player', { id: t.u64() }, (ctx, { id }) => { + const ok = ctx.db.test_e.id.delete(id); + if (!ok) throw new Error(`No TestE row with id ${id}`); +}); + +// delete_players_by_name(name) -> Result<(), String> +spacetimedb.reducer( + 'delete_players_by_name', + { name: t.string() }, + (ctx, { name }) => { + let deleted = 0; + for (const row of ctx.db.test_e.iter()) { + if (row.name === name) { + if (ctx.db.test_e.delete(row)) deleted++; + } + } + if (deleted === 0) + throw new Error(`No TestE row with name ${JSON.stringify(name)}`); + console.info( + `Deleted ${deleted} player(s) with name ${JSON.stringify(name)}` + ); + } +); + +// client_connected hook +spacetimedb.reducer('client_connected', {}, _ctx => { + // no-op +}); + +// add_private(name) +spacetimedb.reducer('add_private', { name: t.string() }, (ctx, { name }) => { + ctx.db.private_table.insert({ name }); +}); + +// query_private() +spacetimedb.reducer('query_private', {}, ctx => { + for (const row of ctx.db.private_table.iter()) { + console.info(`Private, ${row.name}!`); + } + console.info('Private, World!'); +}); + +// test_btree_index_args +// (In Rust this exists to type-check various index argument forms.) +spacetimedb.reducer('test_btree_index_args', {}, ctx => { + const s = 'String'; + // Demonstrate scanning via iteration; prefer index access if bindings expose it. + for (const row of ctx.db.test_e.iter()) { + if (row.name === s || row.name === 'str') { + // no-op; exercising types + } + } + for (const row of ctx.db.points.iter()) { + void row; // exercise multi-column index presence + } +}); + +// assert_caller_identity_is_module_identity +spacetimedb.reducer('assert_caller_identity_is_module_identity', {}, ctx => { + const caller = ctx.sender; + const owner = ctx.identity; + if (String(caller) !== String(owner)) { + throw new Error(`Caller ${caller} is not the owner ${owner}`); + } else { + console.info(`Called by the owner ${owner}`); + } +}); diff --git a/modules/module-test-ts/tsconfig.json b/modules/module-test-ts/tsconfig.json new file mode 100644 index 00000000000..9ee145701c7 --- /dev/null +++ b/modules/module-test-ts/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + + "strict": true, + "declaration": true, + "emitDeclarationOnly": false, + "noEmit": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowImportingTsExtensions": true, + "noImplicitAny": true, + "moduleResolution": "Bundler", + "isolatedDeclarations": false, + + // This library is ESM-only, do not import commonjs modules + "esModuleInterop": false, + "allowSyntheticDefaultImports": false, + "useDefineForClassFields": true, + + // Crucial when using esbuild/swc/babel instead of tsc emit: + "verbatimModuleSyntax": true, + "isolatedModules": true + }, + "include": ["src/index.ts", "tests/**/*"], + "exclude": ["node_modules", "**/__tests__/*", "dist/**/*"] +} diff --git a/modules/quickstart-chat-ts/package-lock.json b/modules/quickstart-chat-ts/package-lock.json new file mode 100644 index 00000000000..69a1f0ac828 --- /dev/null +++ b/modules/quickstart-chat-ts/package-lock.json @@ -0,0 +1,113 @@ +{ + "name": "sdk-test-module", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sdk-test-module", + "license": "ISC", + "dependencies": { + "fast-text-encoding": "^1.0.0" + }, + "devDependencies": { + "@types/fast-text-encoding": "^1.0.3", + "tsup": "^8.1.0" + } + }, + "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding": { + "version": "1.0.6", + "license": "Apache-2.0" + }, + "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup": { + "version": "8.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.25.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.50.0", + "@rollup/plugin-json": "6.1.0", + "@swc/core": "1.10.18", + "@types/debug": "4.1.12", + "@types/node": "22.13.4", + "@types/resolve": "1.20.6", + "bumpp": "^10.0.3", + "flat": "6.0.1", + "postcss": "8.5.2", + "postcss-simple-vars": "7.0.1", + "prettier": "3.5.1", + "resolve": "1.22.10", + "rollup-plugin-dts": "6.1.1", + "sass": "1.85.0", + "strip-json-comments": "5.0.1", + "svelte": "5.19.9", + "svelte-preprocess": "6.0.3", + "terser": "^5.39.0", + "ts-essentials": "10.0.4", + "tsup": "8.3.6", + "typescript": "5.7.3", + "vitest": "3.0.6", + "wait-for-expect": "3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@types/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-bbGJt6IyiuyAhPOX7htQDDzv2bDGJdWyd6X+e1BcdPzU3e5jyjOdB86LoTSoE80faY9v8Wt7/ix3Sp+coRJ03Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-text-encoding": { + "resolved": "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding", + "link": true + }, + "node_modules/tsup": { + "resolved": "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup", + "link": true + } + } +} diff --git a/modules/quickstart-chat-ts/package.json b/modules/quickstart-chat-ts/package.json new file mode 100644 index 00000000000..4e964319a75 --- /dev/null +++ b/modules/quickstart-chat-ts/package.json @@ -0,0 +1,13 @@ +{ + "name": "sdk-test-module", + "license": "ISC", + "type": "module", + "scripts": { + "build": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- build", + "generate-ts": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- generate --lang typescript --out-dir ts-codegen", + "publish": "cargo run -p spacetimedb-cli -- publish" + }, + "dependencies": { + "spacetimedb": "workspace:^" + } +} diff --git a/modules/quickstart-chat-ts/src/index.ts b/modules/quickstart-chat-ts/src/index.ts new file mode 100644 index 00000000000..f432aa73bf2 --- /dev/null +++ b/modules/quickstart-chat-ts/src/index.ts @@ -0,0 +1,82 @@ +// ───────────────────────────────────────────────────────────────────────────── +// IMPORTS +// ───────────────────────────────────────────────────────────────────────────── +import { schema, t, table, SenderError } from 'spacetimedb/server'; + +const User = table( + { name: 'user', public: true }, + { + identity: t.identity().primaryKey(), + name: t.string().optional(), + online: t.bool(), + } +); + +const Message = table( + { name: 'message', public: true }, + { sender: t.identity(), sent: t.timestamp(), text: t.string() } +); + +const spacetimedb = schema(User, Message); + +function validateName(name: string) { + if (!name) throw new SenderError('Names must not be empty'); +} + +spacetimedb.reducer('set_name', { name: t.string() }, (ctx, { name }) => { + validateName(name); + const user = ctx.db.user.identity.find(ctx.sender); + if (!user) throw new SenderError('Cannot set name for unknown user'); + console.info(`User ${ctx.sender} sets name to ${name}`); + ctx.db.user.identity.update({ ...user, name }); +}); + +function validateMessage(text: string) { + if (!text) throw new SenderError('Messages must not be empty'); +} + +spacetimedb.reducer('send_message', { text: t.string() }, (ctx, { text }) => { + // Things to consider: + // - Rate-limit messages per-user. + // - Reject messages from unnamed user. + validateMessage(text); + console.info(`User ${ctx.sender}: ${text}`); + ctx.db.message.insert({ + sender: ctx.sender, + text, + sent: ctx.timestamp, + }); +}); + +// Called when the module is initially published +spacetimedb.init(_ctx => {}); + +spacetimedb.clientConnected(ctx => { + const user = ctx.db.user.identity.find(ctx.sender); + if (user) { + // If this is a returning user, i.e. we already have a `User` with this `Identity`, + // set `online: true`, but leave `name` and `identity` unchanged. + ctx.db.user.identity.update({ ...user, online: true }); + } else { + // If this is a new user, create a `User` row for the `Identity`, + // which is online, but hasn't set a name. + ctx.db.user.insert({ + name: undefined, + identity: ctx.sender, + online: true, + }); + } +}); + +spacetimedb.clientDisconnected(ctx => { + const user = ctx.db.user.identity.find(ctx.sender); + if (user) { + ctx.db.user.identity.update({ ...user, online: false }); + } else { + // This branch should be unreachable, + // as it doesn't make sense for a client to disconnect without connecting first. + console.warn( + `Disconnect event for unknown user with identity ${ctx.sender}` + ); + } +}); diff --git a/modules/quickstart-chat-ts/tsconfig.json b/modules/quickstart-chat-ts/tsconfig.json new file mode 100644 index 00000000000..9ee145701c7 --- /dev/null +++ b/modules/quickstart-chat-ts/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + + "strict": true, + "declaration": true, + "emitDeclarationOnly": false, + "noEmit": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowImportingTsExtensions": true, + "noImplicitAny": true, + "moduleResolution": "Bundler", + "isolatedDeclarations": false, + + // This library is ESM-only, do not import commonjs modules + "esModuleInterop": false, + "allowSyntheticDefaultImports": false, + "useDefineForClassFields": true, + + // Crucial when using esbuild/swc/babel instead of tsc emit: + "verbatimModuleSyntax": true, + "isolatedModules": true + }, + "include": ["src/index.ts", "tests/**/*"], + "exclude": ["node_modules", "**/__tests__/*", "dist/**/*"] +} diff --git a/modules/sdk-test-connect-disconnect-ts/package-lock.json b/modules/sdk-test-connect-disconnect-ts/package-lock.json new file mode 100644 index 00000000000..69a1f0ac828 --- /dev/null +++ b/modules/sdk-test-connect-disconnect-ts/package-lock.json @@ -0,0 +1,113 @@ +{ + "name": "sdk-test-module", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sdk-test-module", + "license": "ISC", + "dependencies": { + "fast-text-encoding": "^1.0.0" + }, + "devDependencies": { + "@types/fast-text-encoding": "^1.0.3", + "tsup": "^8.1.0" + } + }, + "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding": { + "version": "1.0.6", + "license": "Apache-2.0" + }, + "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup": { + "version": "8.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.25.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.50.0", + "@rollup/plugin-json": "6.1.0", + "@swc/core": "1.10.18", + "@types/debug": "4.1.12", + "@types/node": "22.13.4", + "@types/resolve": "1.20.6", + "bumpp": "^10.0.3", + "flat": "6.0.1", + "postcss": "8.5.2", + "postcss-simple-vars": "7.0.1", + "prettier": "3.5.1", + "resolve": "1.22.10", + "rollup-plugin-dts": "6.1.1", + "sass": "1.85.0", + "strip-json-comments": "5.0.1", + "svelte": "5.19.9", + "svelte-preprocess": "6.0.3", + "terser": "^5.39.0", + "ts-essentials": "10.0.4", + "tsup": "8.3.6", + "typescript": "5.7.3", + "vitest": "3.0.6", + "wait-for-expect": "3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@types/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-bbGJt6IyiuyAhPOX7htQDDzv2bDGJdWyd6X+e1BcdPzU3e5jyjOdB86LoTSoE80faY9v8Wt7/ix3Sp+coRJ03Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-text-encoding": { + "resolved": "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding", + "link": true + }, + "node_modules/tsup": { + "resolved": "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup", + "link": true + } + } +} diff --git a/modules/sdk-test-connect-disconnect-ts/package.json b/modules/sdk-test-connect-disconnect-ts/package.json new file mode 100644 index 00000000000..4e964319a75 --- /dev/null +++ b/modules/sdk-test-connect-disconnect-ts/package.json @@ -0,0 +1,13 @@ +{ + "name": "sdk-test-module", + "license": "ISC", + "type": "module", + "scripts": { + "build": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- build", + "generate-ts": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- generate --lang typescript --out-dir ts-codegen", + "publish": "cargo run -p spacetimedb-cli -- publish" + }, + "dependencies": { + "spacetimedb": "workspace:^" + } +} diff --git a/modules/sdk-test-connect-disconnect-ts/src/index.ts b/modules/sdk-test-connect-disconnect-ts/src/index.ts new file mode 100644 index 00000000000..aa77578a84b --- /dev/null +++ b/modules/sdk-test-connect-disconnect-ts/src/index.ts @@ -0,0 +1,24 @@ +// ───────────────────────────────────────────────────────────────────────────── +// IMPORTS +// ───────────────────────────────────────────────────────────────────────────── +import { schema, t, table } from 'spacetimedb/server'; + +const Connected = table( + { name: 'connected', public: true }, + { identity: t.identity() } +); + +const Disconnected = table( + { name: 'disconnected', public: true }, + { identity: t.identity() } +); + +const spacetimedb = schema(Connected, Disconnected); + +spacetimedb.reducer('identity_connected', ctx => { + ctx.db.connected.insert({ identity: ctx.sender }); +}); + +spacetimedb.reducer('identity_disconnected', ctx => { + ctx.db.disconnected.insert({ identity: ctx.sender }); +}); diff --git a/modules/sdk-test-connect-disconnect-ts/tsconfig.json b/modules/sdk-test-connect-disconnect-ts/tsconfig.json new file mode 100644 index 00000000000..9ee145701c7 --- /dev/null +++ b/modules/sdk-test-connect-disconnect-ts/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + + "strict": true, + "declaration": true, + "emitDeclarationOnly": false, + "noEmit": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowImportingTsExtensions": true, + "noImplicitAny": true, + "moduleResolution": "Bundler", + "isolatedDeclarations": false, + + // This library is ESM-only, do not import commonjs modules + "esModuleInterop": false, + "allowSyntheticDefaultImports": false, + "useDefineForClassFields": true, + + // Crucial when using esbuild/swc/babel instead of tsc emit: + "verbatimModuleSyntax": true, + "isolatedModules": true + }, + "include": ["src/index.ts", "tests/**/*"], + "exclude": ["node_modules", "**/__tests__/*", "dist/**/*"] +} diff --git a/modules/sdk-test-ts/package-lock.json b/modules/sdk-test-ts/package-lock.json new file mode 100644 index 00000000000..69a1f0ac828 --- /dev/null +++ b/modules/sdk-test-ts/package-lock.json @@ -0,0 +1,113 @@ +{ + "name": "sdk-test-module", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sdk-test-module", + "license": "ISC", + "dependencies": { + "fast-text-encoding": "^1.0.0" + }, + "devDependencies": { + "@types/fast-text-encoding": "^1.0.3", + "tsup": "^8.1.0" + } + }, + "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding": { + "version": "1.0.6", + "license": "Apache-2.0" + }, + "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup": { + "version": "8.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.25.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.50.0", + "@rollup/plugin-json": "6.1.0", + "@swc/core": "1.10.18", + "@types/debug": "4.1.12", + "@types/node": "22.13.4", + "@types/resolve": "1.20.6", + "bumpp": "^10.0.3", + "flat": "6.0.1", + "postcss": "8.5.2", + "postcss-simple-vars": "7.0.1", + "prettier": "3.5.1", + "resolve": "1.22.10", + "rollup-plugin-dts": "6.1.1", + "sass": "1.85.0", + "strip-json-comments": "5.0.1", + "svelte": "5.19.9", + "svelte-preprocess": "6.0.3", + "terser": "^5.39.0", + "ts-essentials": "10.0.4", + "tsup": "8.3.6", + "typescript": "5.7.3", + "vitest": "3.0.6", + "wait-for-expect": "3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@types/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-bbGJt6IyiuyAhPOX7htQDDzv2bDGJdWyd6X+e1BcdPzU3e5jyjOdB86LoTSoE80faY9v8Wt7/ix3Sp+coRJ03Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-text-encoding": { + "resolved": "../../node_modules/.pnpm/fast-text-encoding@1.0.6/node_modules/fast-text-encoding", + "link": true + }, + "node_modules/tsup": { + "resolved": "../../node_modules/.pnpm/tsup@8.5.0_jiti@2.5.1_postcss@8.5.6_tsx@4.20.4_typescript@5.9.2/node_modules/tsup", + "link": true + } + } +} diff --git a/modules/sdk-test-ts/package.json b/modules/sdk-test-ts/package.json new file mode 100644 index 00000000000..4e964319a75 --- /dev/null +++ b/modules/sdk-test-ts/package.json @@ -0,0 +1,13 @@ +{ + "name": "sdk-test-module", + "license": "ISC", + "type": "module", + "scripts": { + "build": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- build", + "generate-ts": "cargo build -p spacetimedb-standalone && cargo run -p spacetimedb-cli -- generate --lang typescript --out-dir ts-codegen", + "publish": "cargo run -p spacetimedb-cli -- publish" + }, + "dependencies": { + "spacetimedb": "workspace:^" + } +} diff --git a/modules/sdk-test-ts/src/index.ts b/modules/sdk-test-ts/src/index.ts new file mode 100644 index 00000000000..0a7d2c3ec80 --- /dev/null +++ b/modules/sdk-test-ts/src/index.ts @@ -0,0 +1,1015 @@ +// ───────────────────────────────────────────────────────────────────────────── +// IMPORTS +// ───────────────────────────────────────────────────────────────────────────── +import { type RowObj, schema, t, table } from 'spacetimedb/server'; + +const SimpleEnum = t.enum('SimpleEnum', { + Zero: t.unit(), + One: t.unit(), + Two: t.unit(), +}); + +const EnumWithPayload = t.enum('EnumWithPayload', { + U8: t.u8(), + U16: t.u16(), + U32: t.u32(), + U64: t.u64(), + U128: t.u128(), + U256: t.u256(), + I8: t.i8(), + I16: t.i16(), + I32: t.i32(), + I64: t.i64(), + I128: t.i128(), + I256: t.i256(), + Bool: t.bool(), + F32: t.f32(), + F64: t.f64(), + Str: t.string(), + Identity: t.identity(), + ConnectionId: t.connectionId(), + Timestamp: t.timestamp(), + Bytes: t.array(t.u8()), + Ints: t.array(t.i32()), + Strings: t.array(t.string()), + SimpleEnums: t.array(SimpleEnum), + // SpacetimeDB doesn't yet support recursive types in modules + // Recursive(Vec), +}); + +const UnitStruct = t.object('UnitStruct', {}); + +const ByteStruct = t.object('ByteStruct', { + b: t.u8(), +}); + +const EveryPrimitiveStruct = t.object('EveryPrimitiveStruct', { + a: t.u8(), + b: t.u16(), + c: t.u32(), + d: t.u64(), + e: t.u128(), + f: t.u256(), + g: t.i8(), + h: t.i16(), + i: t.i32(), + j: t.i64(), + k: t.i128(), + l: t.i256(), + m: t.bool(), + n: t.f32(), + o: t.f64(), + p: t.string(), + q: t.identity(), + r: t.connectionId(), + s: t.timestamp(), + t: t.timeDuration(), +}); + +const EveryVecStruct = t.object('EveryVecStruct', { + a: t.array(t.u8()), + b: t.array(t.u16()), + c: t.array(t.u32()), + d: t.array(t.u64()), + e: t.array(t.u128()), + f: t.array(t.u256()), + g: t.array(t.i8()), + h: t.array(t.i16()), + i: t.array(t.i32()), + j: t.array(t.i64()), + k: t.array(t.i128()), + l: t.array(t.i256()), + m: t.array(t.bool()), + n: t.array(t.f32()), + o: t.array(t.f64()), + p: t.array(t.string()), + q: t.array(t.identity()), + r: t.array(t.connectionId()), + s: t.array(t.timestamp()), + t: t.array(t.timeDuration()), +}); + +type TableSchema = ReturnType>; + +type TableWithReducers = { + table: Table; + reducers(spacetimedb: ReturnType>): void; +}; + +/** Somewhat mimics the `define_tables!` macro in sdk-test/src/lib.rs */ +function tbl( + name: Name, + ops: { + insert?: string; + delete?: string; + insert_or_panic?: string; + update_by?: [string, keyof Row]; + delete_by?: [string, keyof Row]; + }, + row: Row +): TableWithReducers>> { + const t = table({ name, public: true }, row); + return { + table: t, + reducers(spacetimedb) { + if (ops.insert) { + spacetimedb.reducer(ops.insert, row, (ctx, args) => { + (ctx.db[name] as any).insert({ ...args }); + }); + } + if (ops.delete) { + spacetimedb.reducer(ops.delete, row, (ctx, args) => { + (ctx.db[name] as any).delete({ ...args }); + }); + } + if (ops.insert_or_panic) { + spacetimedb.reducer(ops.insert_or_panic, row, (ctx, args) => { + (ctx.db[name] as any).insert({ ...args }); + }); + } + if (ops.update_by) { + const [reducer, col] = ops.update_by; + spacetimedb.reducer(reducer, row, (ctx, args) => { + (ctx.db[name] as any)[col].update({ ...args }); + }); + } + if (ops.delete_by) { + const [reducer, col] = ops.delete_by; + spacetimedb.reducer(reducer, { [col]: row[col] }, (ctx, args) => { + (ctx.db[name] as any)[col].delete(args[col as any]); + }); + } + }, + }; +} + +// Tables holding a single value. +const singleValTables = [ + tbl('one_u8', { insert: 'insert_one_u8' }, { n: t.u8() }), + tbl('one_u16', { insert: 'insert_one_u16' }, { n: t.u16() }), + tbl('one_u32', { insert: 'insert_one_u32' }, { n: t.u32() }), + tbl('one_u64', { insert: 'insert_one_u64' }, { n: t.u64() }), + tbl('one_u128', { insert: 'insert_one_u128' }, { n: t.u128() }), + tbl('one_u256', { insert: 'insert_one_u256' }, { n: t.u256() }), + + tbl('one_i8', { insert: 'insert_one_i8' }, { n: t.i8() }), + tbl('one_i16', { insert: 'insert_one_i16' }, { n: t.i16() }), + tbl('one_i32', { insert: 'insert_one_i32' }, { n: t.i32() }), + tbl('one_i64', { insert: 'insert_one_i64' }, { n: t.i64() }), + tbl('one_i128', { insert: 'insert_one_i128' }, { n: t.i128() }), + tbl('one_i256', { insert: 'insert_one_i256' }, { n: t.i256() }), + + tbl('one_bool', { insert: 'insert_one_bool' }, { b: t.bool() }), + + tbl('one_f32', { insert: 'insert_one_f32' }, { f: t.f32() }), + tbl('one_f64', { insert: 'insert_one_f64' }, { f: t.f64() }), + + tbl('one_string', { insert: 'insert_one_string' }, { s: t.string() }), + + tbl('one_identity', { insert: 'insert_one_identity' }, { i: t.identity() }), + tbl( + 'one_connection_id', + { insert: 'insert_one_connection_id' }, + { a: t.connectionId() } + ), + + tbl( + 'one_timestamp', + { insert: 'insert_one_timestamp' }, + { t: t.timestamp() } + ), + + tbl( + 'one_simple_enum', + { insert: 'insert_one_simple_enum' }, + { e: SimpleEnum } + ), + tbl( + 'one_enum_with_payload', + { insert: 'insert_one_enum_with_payload' }, + { e: EnumWithPayload } + ), + + tbl( + 'one_unit_struct', + { insert: 'insert_one_unit_struct' }, + { s: UnitStruct } + ), + tbl( + 'one_byte_struct', + { insert: 'insert_one_byte_struct' }, + { s: ByteStruct } + ), + tbl( + 'one_every_primitive_struct', + { insert: 'insert_one_every_primitive_struct' }, + { s: EveryPrimitiveStruct } + ), + tbl( + 'one_every_vec_struct', + { insert: 'insert_one_every_vec_struct' }, + { s: EveryVecStruct } + ), +] as const; + +// Tables holding a Vec of various types. +const vecTables = [ + tbl('vec_u8', { insert: 'insert_vec_u8' }, { n: t.array(t.u8()) }), + tbl('vec_u16', { insert: 'insert_vec_u16' }, { n: t.array(t.u16()) }), + tbl('vec_u32', { insert: 'insert_vec_u32' }, { n: t.array(t.u32()) }), + tbl('vec_u64', { insert: 'insert_vec_u64' }, { n: t.array(t.u64()) }), + tbl('vec_u128', { insert: 'insert_vec_u128' }, { n: t.array(t.u128()) }), + tbl('vec_u256', { insert: 'insert_vec_u256' }, { n: t.array(t.u256()) }), + + tbl('vec_i8', { insert: 'insert_vec_i8' }, { n: t.array(t.i8()) }), + tbl('vec_i16', { insert: 'insert_vec_i16' }, { n: t.array(t.i16()) }), + tbl('vec_i32', { insert: 'insert_vec_i32' }, { n: t.array(t.i32()) }), + tbl('vec_i64', { insert: 'insert_vec_i64' }, { n: t.array(t.i64()) }), + tbl('vec_i128', { insert: 'insert_vec_i128' }, { n: t.array(t.i128()) }), + tbl('vec_i256', { insert: 'insert_vec_i256' }, { n: t.array(t.i256()) }), + + tbl('vec_bool', { insert: 'insert_vec_bool' }, { b: t.array(t.bool()) }), + + tbl('vec_f32', { insert: 'insert_vec_f32' }, { f: t.array(t.f32()) }), + tbl('vec_f64', { insert: 'insert_vec_f64' }, { f: t.array(t.f64()) }), + + tbl( + 'vec_string', + { insert: 'insert_vec_string' }, + { s: t.array(t.string()) } + ), + + tbl( + 'vec_identity', + { insert: 'insert_vec_identity' }, + { i: t.array(t.identity()) } + ), + tbl( + 'vec_connection_id', + { insert: 'insert_vec_connection_id' }, + { a: t.array(t.connectionId()) } + ), + + tbl( + 'vec_timestamp', + { insert: 'insert_vec_timestamp' }, + { t: t.array(t.timestamp()) } + ), + + tbl( + 'vec_simple_enum', + { insert: 'insert_vec_simple_enum' }, + { e: t.array(SimpleEnum) } + ), + tbl( + 'vec_enum_with_payload', + { insert: 'insert_vec_enum_with_payload' }, + { e: t.array(EnumWithPayload) } + ), + + tbl( + 'vec_unit_struct', + { insert: 'insert_vec_unit_struct' }, + { s: t.array(UnitStruct) } + ), + tbl( + 'vec_byte_struct', + { insert: 'insert_vec_byte_struct' }, + { s: t.array(ByteStruct) } + ), + tbl( + 'vec_every_primitive_struct', + { insert: 'insert_vec_every_primitive_struct' }, + { s: t.array(EveryPrimitiveStruct) } + ), + tbl( + 'vec_every_vec_struct', + { insert: 'insert_vec_every_vec_struct' }, + { s: t.array(EveryVecStruct) } + ), +] as const; + +// Tables holding an Option of various types. +const optionTables = [ + tbl('option_i32', { insert: 'insert_option_i32' }, { n: t.option(t.i32()) }), + tbl( + 'option_string', + { insert: 'insert_option_string' }, + { s: t.option(t.string()) } + ), + tbl( + 'option_identity', + { insert: 'insert_option_identity' }, + { i: t.option(t.identity()) } + ), + tbl( + 'option_simple_enum', + { insert: 'insert_option_simple_enum' }, + { e: t.option(SimpleEnum) } + ), + tbl( + 'option_every_primitive_struct', + { insert: 'insert_option_every_primitive_struct' }, + { s: t.option(EveryPrimitiveStruct) } + ), + tbl( + 'option_vec_option_i32', + { insert: 'insert_option_vec_option_i32' }, + { v: t.option(t.array(t.option(t.i32()))) } + ), +] as const; + +// Tables mapping a unique, but non-pk, key to a boring i32 payload. +// This allows us to test delete events, and the semantically correct absence of update events. +const uniqueTables = [ + tbl( + 'unique_u8', + { + insert_or_panic: 'insert_unique_u8', + update_by: ['update_unique_u8', 'n'], + delete_by: ['delete_unique_u8', 'n'], + }, + { n: t.u8().unique(), data: t.i32() } + ), + + tbl( + 'unique_u16', + { + insert_or_panic: 'insert_unique_u16', + update_by: ['update_unique_u16', 'n'], + delete_by: ['delete_unique_u16', 'n'], + }, + { n: t.u16().unique(), data: t.i32() } + ), + + tbl( + 'unique_u32', + { + insert_or_panic: 'insert_unique_u32', + update_by: ['update_unique_u32', 'n'], + delete_by: ['delete_unique_u32', 'n'], + }, + { n: t.u32().unique(), data: t.i32() } + ), + + tbl( + 'unique_u64', + { + insert_or_panic: 'insert_unique_u64', + update_by: ['update_unique_u64', 'n'], + delete_by: ['delete_unique_u64', 'n'], + }, + { n: t.u64().unique(), data: t.i32() } + ), + + tbl( + 'unique_u128', + { + insert_or_panic: 'insert_unique_u128', + update_by: ['update_unique_u128', 'n'], + delete_by: ['delete_unique_u128', 'n'], + }, + { n: t.u128().unique(), data: t.i32() } + ), + + tbl( + 'unique_u256', + { + insert_or_panic: 'insert_unique_u256', + update_by: ['update_unique_u256', 'n'], + delete_by: ['delete_unique_u256', 'n'], + }, + { n: t.u256().unique(), data: t.i32() } + ), + + tbl( + 'unique_i8', + { + insert_or_panic: 'insert_unique_i8', + update_by: ['update_unique_i8', 'n'], + delete_by: ['delete_unique_i8', 'n'], + }, + { n: t.i8().unique(), data: t.i32() } + ), + + tbl( + 'unique_i16', + { + insert_or_panic: 'insert_unique_i16', + update_by: ['update_unique_i16', 'n'], + delete_by: ['delete_unique_i16', 'n'], + }, + { n: t.i16().unique(), data: t.i32() } + ), + + tbl( + 'unique_i32', + { + insert_or_panic: 'insert_unique_i32', + update_by: ['update_unique_i32', 'n'], + delete_by: ['delete_unique_i32', 'n'], + }, + { n: t.i32().unique(), data: t.i32() } + ), + + tbl( + 'unique_i64', + { + insert_or_panic: 'insert_unique_i64', + update_by: ['update_unique_i64', 'n'], + delete_by: ['delete_unique_i64', 'n'], + }, + { n: t.i64().unique(), data: t.i32() } + ), + + tbl( + 'unique_i128', + { + insert_or_panic: 'insert_unique_i128', + update_by: ['update_unique_i128', 'n'], + delete_by: ['delete_unique_i128', 'n'], + }, + { n: t.i128().unique(), data: t.i32() } + ), + + tbl( + 'unique_i256', + { + insert_or_panic: 'insert_unique_i256', + update_by: ['update_unique_i256', 'n'], + delete_by: ['delete_unique_i256', 'n'], + }, + { n: t.i256().unique(), data: t.i32() } + ), + + tbl( + 'unique_bool', + { + insert_or_panic: 'insert_unique_bool', + update_by: ['update_unique_bool', 'b'], + delete_by: ['delete_unique_bool', 'b'], + }, + { b: t.bool().unique(), data: t.i32() } + ), + + tbl( + 'unique_string', + { + insert_or_panic: 'insert_unique_string', + update_by: ['update_unique_string', 's'], + delete_by: ['delete_unique_string', 's'], + }, + { s: t.string().unique(), data: t.i32() } + ), + + tbl( + 'unique_identity', + { + insert_or_panic: 'insert_unique_identity', + update_by: ['update_unique_identity', 'i'], + delete_by: ['delete_unique_identity', 'i'], + }, + { i: t.identity().unique(), data: t.i32() } + ), + + tbl( + 'unique_connection_id', + { + insert_or_panic: 'insert_unique_connection_id', + update_by: ['update_unique_connection_id', 'a'], + delete_by: ['delete_unique_connection_id', 'a'], + }, + { a: t.connectionId().unique(), data: t.i32() } + ), +] as const; + +// Tables mapping a primary key to a boring i32 payload. +// This allows us to test update and delete events. +const pkTables = [ + tbl( + 'pk_u8', + { + insert_or_panic: 'insert_pk_u8', + update_by: ['update_pk_u8', 'n'], + delete_by: ['delete_pk_u8', 'n'], + }, + { n: t.u8().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_u16', + { + insert_or_panic: 'insert_pk_u16', + update_by: ['update_pk_u16', 'n'], + delete_by: ['delete_pk_u16', 'n'], + }, + { n: t.u16().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_u32', + { + insert_or_panic: 'insert_pk_u32', + update_by: ['update_pk_u32', 'n'], + delete_by: ['delete_pk_u32', 'n'], + }, + { n: t.u32().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_u32_two', + { + insert_or_panic: 'insert_pk_u32_two', + update_by: ['update_pk_u32_two', 'n'], + delete_by: ['delete_pk_u32_two', 'n'], + }, + { n: t.u32().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_u64', + { + insert_or_panic: 'insert_pk_u64', + update_by: ['update_pk_u64', 'n'], + delete_by: ['delete_pk_u64', 'n'], + }, + { n: t.u64().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_u128', + { + insert_or_panic: 'insert_pk_u128', + update_by: ['update_pk_u128', 'n'], + delete_by: ['delete_pk_u128', 'n'], + }, + { n: t.u128().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_u256', + { + insert_or_panic: 'insert_pk_u256', + update_by: ['update_pk_u256', 'n'], + delete_by: ['delete_pk_u256', 'n'], + }, + { n: t.u256().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_i8', + { + insert_or_panic: 'insert_pk_i8', + update_by: ['update_pk_i8', 'n'], + delete_by: ['delete_pk_i8', 'n'], + }, + { n: t.i8().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_i16', + { + insert_or_panic: 'insert_pk_i16', + update_by: ['update_pk_i16', 'n'], + delete_by: ['delete_pk_i16', 'n'], + }, + { n: t.i16().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_i32', + { + insert_or_panic: 'insert_pk_i32', + update_by: ['update_pk_i32', 'n'], + delete_by: ['delete_pk_i32', 'n'], + }, + { n: t.i32().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_i64', + { + insert_or_panic: 'insert_pk_i64', + update_by: ['update_pk_i64', 'n'], + delete_by: ['delete_pk_i64', 'n'], + }, + { n: t.i64().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_i128', + { + insert_or_panic: 'insert_pk_i128', + update_by: ['update_pk_i128', 'n'], + delete_by: ['delete_pk_i128', 'n'], + }, + { n: t.i128().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_i256', + { + insert_or_panic: 'insert_pk_i256', + update_by: ['update_pk_i256', 'n'], + delete_by: ['delete_pk_i256', 'n'], + }, + { n: t.i256().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_bool', + { + insert_or_panic: 'insert_pk_bool', + update_by: ['update_pk_bool', 'b'], + delete_by: ['delete_pk_bool', 'b'], + }, + { b: t.bool().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_string', + { + insert_or_panic: 'insert_pk_string', + update_by: ['update_pk_string', 's'], + delete_by: ['delete_pk_string', 's'], + }, + { s: t.string().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_identity', + { + insert_or_panic: 'insert_pk_identity', + update_by: ['update_pk_identity', 'i'], + delete_by: ['delete_pk_identity', 'i'], + }, + { i: t.identity().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_connection_id', + { + insert_or_panic: 'insert_pk_connection_id', + update_by: ['update_pk_connection_id', 'a'], + delete_by: ['delete_pk_connection_id', 'a'], + }, + { a: t.connectionId().primaryKey(), data: t.i32() } + ), + + tbl( + 'pk_simple_enum', + { + insert_or_panic: 'insert_pk_simple_enum', + }, + { a: SimpleEnum.primaryKey(), data: t.i32() } + ), +] as const; + +// Some weird-looking tables. +const weirdTables = [ + // A table with many fields, of many different types. + tbl( + 'large_table', + { + insert: 'insert_large_table', + delete: 'delete_large_table', + }, + { + a: t.u8(), + b: t.u16(), + c: t.u32(), + d: t.u64(), + e: t.u128(), + f: t.u256(), + g: t.i8(), + h: t.i16(), + i: t.i32(), + j: t.i64(), + k: t.i128(), + l: t.i256(), + m: t.bool(), + n: t.f32(), + o: t.f64(), + p: t.string(), + q: SimpleEnum, + r: EnumWithPayload, + s: UnitStruct, + t: ByteStruct, + u: EveryPrimitiveStruct, + v: EveryVecStruct, + } + ), + + // A table which holds instances of other table structs. + // This tests that we can use tables as types. + tbl( + 'table_holds_table', + { + insert: 'insert_table_holds_table', + }, + { + a: singleValTables[0].table.rowType, // OneU8 + b: vecTables[0].table.rowType, // VecU8 + } + ), +]; + +const PkU32 = pkTables[2].table.rowType; + +const allTables = [ + ...singleValTables, + ...vecTables, + ...optionTables, + ...uniqueTables, + ...pkTables, + ...weirdTables, +] as const; + +type ExtractTables[]> = { + [i in keyof T]: T[i]['table']; +}; +const allTableDefs: ExtractTables = allTables.map( + x => x.table +) as any; + +const ScheduledTable = table( + { + name: 'scheduled_table', + scheduled: 'send_scheduled_message', + public: true, + }, + { + scheduled_id: t.u64().primaryKey().autoInc(), + scheduled_at: t.scheduleAt(), + text: t.string(), + } +); + +const IndexedTable = table( + { name: 'indexed_table' }, + { player_id: t.u32().index('btree') } +); + +const IndexedTable2 = table( + { + name: 'indexed_table_2', + indexes: [ + { + name: 'player_id_snazz_index', + algorithm: 'btree', + columns: ['player_id', 'player_snazz'], + }, + ], + }, + { + player_id: t.u32(), + player_snazz: t.f32(), + } +); + +const BTreeU32 = table( + { name: 'btree_u32', public: true }, + { + n: t.u32().index('btree'), + data: t.i32(), + } +); + +const Users = table( + { name: 'users', public: true }, + { + identity: t.identity().primaryKey(), + name: t.string(), + } +); + +const IndexedSimpleEnum = table( + { name: 'indexed_simple_enum', public: true }, + { n: SimpleEnum.index('btree') } +); + +const spacetimedb = schema( + ...allTableDefs, + ScheduledTable, + IndexedTable, + IndexedTable2, + BTreeU32, + Users, + IndexedSimpleEnum +); + +for (const { reducers } of allTables) { + reducers(spacetimedb as any); +} + +spacetimedb.clientVisibilityFilter.sql( + 'SELECT * FROM users WHERE identity = :sender' +); + +spacetimedb.reducer( + 'update_pk_simple_enum', + { a: SimpleEnum, data: t.i32() }, + (ctx, { a, data }) => { + const o = ctx.db.pk_simple_enum.a.find(a); + if (o == null) throw new Error('row not found'); + o.data = data; + ctx.db.pk_simple_enum.a.update(o); + } +); + +spacetimedb.reducer( + 'insert_into_btree_u32', + { rows: t.array(BTreeU32.rowType) }, + (ctx, { rows }) => { + for (const row of rows) { + ctx.db.btree_u32.insert(row); + } + } +); + +spacetimedb.reducer( + 'delete_from_btree_u32', + { rows: t.array(BTreeU32.rowType) }, + (ctx, { rows }) => { + for (const row of rows) { + ctx.db.btree_u32.delete(row); + } + } +); + +spacetimedb.reducer( + 'insert_into_pk_btree_u32', + { pk_u32: t.array(PkU32), bt_u32: t.array(BTreeU32.rowType) }, + (ctx, { pk_u32, bt_u32 }) => { + for (const row of pk_u32) { + ctx.db.pk_u32.insert(row); + } + for (const row of bt_u32) { + ctx.db.btree_u32.insert(row); + } + } +); + +/// The purpose of this reducer is for a test which +/// left-semijoins `UniqueU32` to `PkU32` +/// for the purposes of behavior testing row-deduplication. +spacetimedb.reducer( + 'insert_unique_u32_update_pk_u32', + { n: t.u32(), d_unique: t.i32(), d_pk: t.i32() }, + (ctx, { n, d_unique, d_pk }) => { + ctx.db.unique_u32.insert({ n, data: d_unique }); + ctx.db.pk_u32.n.update({ n, data: d_pk }); + } +); + +/// The purpose of this reducer is for a test with two separate semijoin queries +/// - `UniqueU32` to `PkU32` +/// - `UniqueU32` to `PkU32Two` +/// +/// for the purposes of behavior testing row-deduplication. +spacetimedb.reducer( + 'delete_pk_u32_insert_pk_u32_two', + { n: t.u32(), data: t.i32() }, + (ctx, { n, data }) => { + ctx.db.pk_u32_two.insert({ n, data }); + ctx.db.pk_u32.delete({ n, data }); + } +); + +spacetimedb.reducer('insert_caller_one_identity', ctx => { + ctx.db.one_identity.insert({ i: ctx.sender }); +}); + +spacetimedb.reducer('insert_caller_vec_identity', ctx => { + ctx.db.vec_identity.insert({ i: [ctx.sender] }); +}); + +spacetimedb.reducer( + 'insert_caller_unique_identity', + { data: t.i32() }, + (ctx, { data }) => { + ctx.db.unique_identity.insert({ i: ctx.sender, data }); + } +); + +spacetimedb.reducer( + 'insert_caller_pk_identity', + { data: t.i32() }, + (ctx, { data }) => { + ctx.db.pk_identity.insert({ i: ctx.sender, data }); + } +); + +spacetimedb.reducer('insert_caller_one_connection_id', ctx => { + if (!ctx.connectionId) throw new Error('No connection id in reducer context'); + ctx.db.one_connection_id.insert({ + a: ctx.connectionId, + }); +}); + +spacetimedb.reducer('insert_caller_vec_connection_id', ctx => { + if (!ctx.connectionId) throw new Error('No connection id in reducer context'); + ctx.db.vec_connection_id.insert({ + a: [ctx.connectionId], + }); +}); + +spacetimedb.reducer( + 'insert_caller_unique_connection_id', + { data: t.i32() }, + (ctx, { data }) => { + if (!ctx.connectionId) + throw new Error('No connection id in reducer context'); + ctx.db.unique_connection_id.insert({ + a: ctx.connectionId, + data, + }); + } +); + +spacetimedb.reducer( + 'insert_caller_pk_connection_id', + { data: t.i32() }, + (ctx, { data }) => { + if (!ctx.connectionId) + throw new Error('No connection id in reducer context'); + ctx.db.pk_connection_id.insert({ + a: ctx.connectionId, + data, + }); + } +); + +spacetimedb.reducer('insert_call_timestamp', ctx => { + ctx.db.one_timestamp.insert({ t: ctx.timestamp }); +}); + +spacetimedb.reducer( + 'insert_primitives_as_strings', + { s: EveryPrimitiveStruct }, + (ctx, { s }) => { + ctx.db.vec_string.insert({ + s: [ + s.a.toString(), + s.b.toString(), + s.c.toString(), + s.d.toString(), + s.e.toString(), + s.f.toString(), + s.g.toString(), + s.h.toString(), + s.i.toString(), + s.j.toString(), + s.k.toString(), + s.l.toString(), + s.m.toString(), + s.n.toString(), + s.o.toString(), + s.p.toString(), + s.q.toHexString(), + s.r.toHexString(), + s.s.toDate().toISOString(), + s.t.toString(), + ], + }); + } +); + +spacetimedb.reducer('no_op_succeeds', _ctx => {}); + +spacetimedb.clientVisibilityFilter.sql('SELECT * FROM one_u8'); + +spacetimedb.reducer( + 'send_scheduled_message', + { arg: ScheduledTable.rowType }, + (_ctx, { arg }) => { + const _ = [arg.text, arg.scheduled_at, arg.scheduled_id]; + } +); + +spacetimedb.reducer( + 'insert_user', + { name: t.string(), identity: t.identity() }, + (ctx, { name, identity }) => { + ctx.db.users.insert({ name, identity }); + } +); + +spacetimedb.reducer( + 'insert_into_indexed_simple_enum', + { n: SimpleEnum }, + (ctx, { n }) => { + ctx.db.indexed_simple_enum.insert({ n }); + } +); + +spacetimedb.reducer( + 'update_indexed_simple_enum', + { a: SimpleEnum, b: SimpleEnum }, + (ctx, { a, b }) => { + if (!ctx.db.indexed_simple_enum.n.filter(a).next().done) { + ctx.db.indexed_simple_enum.n.delete(a); + ctx.db.indexed_simple_enum.insert({ n: b }); + } + } +); diff --git a/modules/sdk-test-ts/tsconfig.json b/modules/sdk-test-ts/tsconfig.json new file mode 100644 index 00000000000..9ee145701c7 --- /dev/null +++ b/modules/sdk-test-ts/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + + "strict": true, + "declaration": true, + "emitDeclarationOnly": false, + "noEmit": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowImportingTsExtensions": true, + "noImplicitAny": true, + "moduleResolution": "Bundler", + "isolatedDeclarations": false, + + // This library is ESM-only, do not import commonjs modules + "esModuleInterop": false, + "allowSyntheticDefaultImports": false, + "useDefineForClassFields": true, + + // Crucial when using esbuild/swc/babel instead of tsc emit: + "verbatimModuleSyntax": true, + "isolatedModules": true + }, + "include": ["src/index.ts", "tests/**/*"], + "exclude": ["node_modules", "**/__tests__/*", "dist/**/*"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b0d29bf8822..fd635a4335f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: base64-js: specifier: ^1.5.1 version: 1.5.1 + fast-text-encoding: + specifier: ^1.0.0 + version: 1.0.6 prettier: specifier: ^3.3.3 version: 3.6.2 @@ -66,6 +69,9 @@ importers: '@size-limit/file': specifier: ^11.2.0 version: 11.2.0(size-limit@11.2.0) + '@types/fast-text-encoding': + specifier: ^1.0.3 + version: 1.0.3 '@types/react': specifier: ^19.1.13 version: 19.1.13 @@ -229,6 +235,30 @@ importers: specifier: ^5.0.0 version: 5.0.0 + modules/module-test-ts: + dependencies: + spacetimedb: + specifier: workspace:^ + version: link:../../crates/bindings-typescript + + modules/quickstart-chat-ts: + dependencies: + spacetimedb: + specifier: workspace:^ + version: link:../../crates/bindings-typescript + + modules/sdk-test-connect-disconnect-ts: + dependencies: + spacetimedb: + specifier: workspace:^ + version: link:../../crates/bindings-typescript + + modules/sdk-test-ts: + dependencies: + spacetimedb: + specifier: workspace:^ + version: link:../../crates/bindings-typescript + packages: '@adobe/css-tools@4.4.4': @@ -814,6 +844,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/fast-text-encoding@1.0.3': + resolution: {integrity: sha512-bbGJt6IyiuyAhPOX7htQDDzv2bDGJdWyd6X+e1BcdPzU3e5jyjOdB86LoTSoE80faY9v8Wt7/ix3Sp+coRJ03Q==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1293,6 +1326,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-text-encoding@1.0.6: + resolution: {integrity: sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==} + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -2824,6 +2860,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/fast-text-encoding@1.0.3': {} + '@types/json-schema@7.0.15': {} '@types/mdast@4.0.4': @@ -3461,6 +3499,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-text-encoding@1.0.6: {} + fastq@1.19.1: dependencies: reusify: 1.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index b4ea2a3e883..a728f55c145 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,4 +2,8 @@ packages: - 'crates/bindings-typescript' - 'crates/bindings-typescript/test-app' - 'crates/bindings-typescript/examples/quickstart-chat' - - 'docs' \ No newline at end of file + - 'modules/module-test-ts' + - 'modules/quickstart-chat-ts' + - 'modules/sdk-test-connect-disconnect-ts' + - 'modules/sdk-test-ts' + - 'docs' diff --git a/sdks/rust/tests/test.rs b/sdks/rust/tests/test.rs index 2ef45e9a048..a01ef513d34 100644 --- a/sdks/rust/tests/test.rs +++ b/sdks/rust/tests/test.rs @@ -267,3 +267,4 @@ macro_rules! declare_tests_with_suffix { declare_tests_with_suffix!(rust, ""); // TODO: migrate csharp to snake_case table names declare_tests_with_suffix!(csharp, "-cs"); +declare_tests_with_suffix!(typescript, "-ts"); diff --git a/tools/upgrade-version/src/main.rs b/tools/upgrade-version/src/main.rs index 1fa220db7dd..e0f54c9f940 100644 --- a/tools/upgrade-version/src/main.rs +++ b/tools/upgrade-version/src/main.rs @@ -1,5 +1,6 @@ #![allow(clippy::disallowed_macros)] +use anyhow::Context; use chrono::{Datelike, Local}; use clap::{Arg, ArgGroup, Command}; use duct::cmd; @@ -57,6 +58,35 @@ fn rewrite_json_version_inplace(path: impl AsRef, new_version: &str) -> an Ok(()) } +pub fn rewrite_package_json_dependency_version_inplace( + path: impl AsRef, + new_version: &str, +) -> anyhow::Result<()> { + let path = path.as_ref(); + let contents = fs::read_to_string(path).with_context(|| format!("Failed to read {}", path.display()))?; + + // This regex matches: + // "spacetimedb": "1.5.*" → capturing leading whitespace and quotes, then replacing only the version. + let re = Regex::new(r#"(?m)^(\s*"spacetimedb"\s*:\s*")([^"]*)(")"#).expect("Invalid regex"); + + let mut replaced = false; + let updated = re.replacen(&contents, 1, |caps: ®ex::Captures| { + replaced = true; + format!("{}{}{}", &caps[1], new_version, &caps[3]) + }); + + if !replaced { + anyhow::bail!( + "Could not find \"spacetimedb\" dependency to update in {}", + path.display() + ); + } + + fs::write(path, updated.as_ref()).with_context(|| format!("Failed to write updated file to {}", path.display()))?; + + Ok(()) +} + fn main() -> anyhow::Result<()> { let matches = Command::new("upgrade-version") .version("1.0") @@ -155,6 +185,11 @@ fn main() -> anyhow::Result<()> { if matches.get_flag("typescript") || matches.get_flag("all") { rewrite_json_version_inplace("crates/bindings-typescript/package.json", &full_version)?; + + rewrite_package_json_dependency_version_inplace( + "crates/cli/src/subcommands/project/typescript/package._json", + &wildcard_patch, + )?; } if matches.get_flag("csharp") || matches.get_flag("all") {