@oliphaunt/wasix-ts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +655 -0
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.md +404 -0
- package/THIRD_PARTY_NOTICES.md +20 -0
- package/lib/archive.d.ts +21 -0
- package/lib/archive.js +336 -0
- package/lib/asset-source.d.ts +4 -0
- package/lib/asset-source.js +15 -0
- package/lib/byte-channel.d.ts +27 -0
- package/lib/byte-channel.js +170 -0
- package/lib/client-common.d.ts +6 -0
- package/lib/client-common.js +36 -0
- package/lib/client.d.ts +7 -0
- package/lib/client.js +24 -0
- package/lib/database-root.d.ts +19 -0
- package/lib/database-root.js +139 -0
- package/lib/database.d.ts +135 -0
- package/lib/database.js +1039 -0
- package/lib/descriptor-validation.d.ts +10 -0
- package/lib/descriptor-validation.js +75 -0
- package/lib/direct-client-common.d.ts +50 -0
- package/lib/direct-client-common.js +717 -0
- package/lib/direct-client.d.ts +4 -0
- package/lib/direct-client.js +13 -0
- package/lib/direct.node.d.ts +2 -0
- package/lib/direct.node.js +2 -0
- package/lib/errors.d.ts +25 -0
- package/lib/errors.js +34 -0
- package/lib/extension-descriptor.d.ts +14 -0
- package/lib/extension-descriptor.js +419 -0
- package/lib/extensions.d.ts +68 -0
- package/lib/extensions.js +769 -0
- package/lib/host/LICENSE +21 -0
- package/lib/host/index.d.mts +123 -0
- package/lib/host/index.mjs +11 -0
- package/lib/host/provenance.json +16 -0
- package/lib/host/wasmer_js_bg.wasm +0 -0
- package/lib/host/worker.mjs +11 -0
- package/lib/host-runtime.d.ts +5 -0
- package/lib/host-runtime.js +13 -0
- package/lib/icu-descriptor.d.ts +3 -0
- package/lib/icu-descriptor.js +92 -0
- package/lib/index.bun.d.ts +2 -0
- package/lib/index.bun.js +2 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.deno.d.ts +2 -0
- package/lib/index.deno.js +2 -0
- package/lib/index.js +2 -0
- package/lib/index.node.d.ts +2 -0
- package/lib/index.node.js +2 -0
- package/lib/internal-common.d.ts +12 -0
- package/lib/internal-common.js +274 -0
- package/lib/internal.d.ts +5 -0
- package/lib/internal.js +42 -0
- package/lib/internal.node.d.ts +5 -0
- package/lib/internal.node.js +8 -0
- package/lib/native-addon.d.ts +111 -0
- package/lib/native-addon.js +223 -0
- package/lib/native-server.d.ts +21 -0
- package/lib/native-server.js +109 -0
- package/lib/native-session.d.ts +60 -0
- package/lib/native-session.js +565 -0
- package/lib/node-actor.d.ts +7 -0
- package/lib/node-actor.js +10 -0
- package/lib/node-client-common.d.ts +9 -0
- package/lib/node-client-common.js +35 -0
- package/lib/node-client.d.ts +4 -0
- package/lib/node-client.js +13 -0
- package/lib/node-direct.d.ts +7 -0
- package/lib/node-direct.js +10 -0
- package/lib/node-worker-options.d.ts +5 -0
- package/lib/node-worker-options.js +65 -0
- package/lib/node-worker-port.d.ts +4 -0
- package/lib/node-worker-port.js +116 -0
- package/lib/node-worker.d.ts +1 -0
- package/lib/node-worker.js +38 -0
- package/lib/pgwire-connection.d.ts +60 -0
- package/lib/pgwire-connection.js +528 -0
- package/lib/pgwire.d.ts +3 -0
- package/lib/pgwire.js +105 -0
- package/lib/physical-archive.d.ts +29 -0
- package/lib/physical-archive.js +527 -0
- package/lib/protocol.d.ts +1 -0
- package/lib/protocol.js +1 -0
- package/lib/public.d.ts +4 -0
- package/lib/public.js +3 -0
- package/lib/query.d.ts +1 -0
- package/lib/query.js +1 -0
- package/lib/rpc.d.ts +203 -0
- package/lib/rpc.js +84 -0
- package/lib/runtime-descriptor.d.ts +3 -0
- package/lib/runtime-descriptor.js +79 -0
- package/lib/server.node.d.ts +1 -0
- package/lib/server.node.js +1 -0
- package/lib/startup-config.d.ts +2 -0
- package/lib/startup-config.js +19 -0
- package/lib/storage/bun.d.ts +6 -0
- package/lib/storage/bun.js +6 -0
- package/lib/storage/deno.d.ts +7 -0
- package/lib/storage/deno.js +7 -0
- package/lib/storage/incremental-storage.d.ts +25 -0
- package/lib/storage/incremental-storage.js +154 -0
- package/lib/storage/indexed-db-provider.d.ts +40 -0
- package/lib/storage/indexed-db-provider.js +259 -0
- package/lib/storage/indexed-db.d.ts +9 -0
- package/lib/storage/indexed-db.js +11 -0
- package/lib/storage/node.d.ts +10 -0
- package/lib/storage/node.js +13 -0
- package/lib/storage/opfs-pool.d.ts +31 -0
- package/lib/storage/opfs-pool.js +1271 -0
- package/lib/storage/opfs-provider.d.ts +4 -0
- package/lib/storage/opfs-provider.js +257 -0
- package/lib/storage/opfs.d.ts +8 -0
- package/lib/storage/opfs.js +10 -0
- package/lib/storage/restore-cleanup.d.ts +4 -0
- package/lib/storage/restore-cleanup.js +22 -0
- package/lib/storage/web-lock.d.ts +2 -0
- package/lib/storage/web-lock.js +64 -0
- package/lib/storage-provider.d.ts +47 -0
- package/lib/storage-provider.js +141 -0
- package/lib/storage-snapshot.d.ts +44 -0
- package/lib/storage-snapshot.js +274 -0
- package/lib/storage.d.ts +46 -0
- package/lib/storage.js +83 -0
- package/lib/tool-runtime.d.ts +43 -0
- package/lib/tool-runtime.js +93 -0
- package/lib/tool-worker-common.d.ts +48 -0
- package/lib/tool-worker-common.js +97 -0
- package/lib/tool-worker.d.ts +1 -0
- package/lib/tool-worker.js +10 -0
- package/lib/types.d.ts +230 -0
- package/lib/types.js +1 -0
- package/lib/wasix-runtime.d.ts +24 -0
- package/lib/wasix-runtime.js +186 -0
- package/lib/worker-client.d.ts +4 -0
- package/lib/worker-client.js +45 -0
- package/lib/worker-dispatch.d.ts +11 -0
- package/lib/worker-dispatch.js +174 -0
- package/lib/worker-entry.bun.d.ts +2 -0
- package/lib/worker-entry.bun.js +2 -0
- package/lib/worker-entry.d.ts +2 -0
- package/lib/worker-entry.deno.d.ts +2 -0
- package/lib/worker-entry.deno.js +2 -0
- package/lib/worker-entry.js +2 -0
- package/lib/worker-entry.node.d.ts +2 -0
- package/lib/worker-entry.node.js +2 -0
- package/lib/worker-node-client.d.ts +4 -0
- package/lib/worker-node-client.js +55 -0
- package/lib/worker-rpc.d.ts +36 -0
- package/lib/worker-rpc.js +422 -0
- package/lib/worker-transfer.d.ts +6 -0
- package/lib/worker-transfer.js +11 -0
- package/lib/worker.d.ts +1 -0
- package/lib/worker.js +21 -0
- package/lib/zstd.d.ts +4 -0
- package/lib/zstd.js +12 -0
- package/node_modules/@oliphaunt/js-core/README.md +7 -0
- package/node_modules/@oliphaunt/js-core/dist/commonjs/protocol.d.ts +1 -0
- package/node_modules/@oliphaunt/js-core/dist/commonjs/protocol.js +22 -0
- package/node_modules/@oliphaunt/js-core/dist/commonjs/query.d.ts +255 -0
- package/node_modules/@oliphaunt/js-core/dist/commonjs/query.js +2068 -0
- package/node_modules/@oliphaunt/js-core/dist/module/package.json +3 -0
- package/node_modules/@oliphaunt/js-core/dist/module/protocol.d.ts +1 -0
- package/node_modules/@oliphaunt/js-core/dist/module/protocol.js +19 -0
- package/node_modules/@oliphaunt/js-core/dist/module/query.d.ts +255 -0
- package/node_modules/@oliphaunt/js-core/dist/module/query.js +2039 -0
- package/node_modules/@oliphaunt/js-core/package.json +21 -0
- package/package.json +122 -0
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
# WASIX TypeScript binding architecture
|
|
2
|
+
|
|
3
|
+
## Boundary
|
|
4
|
+
|
|
5
|
+
`src/bindings/wasix-ts` is one public TypeScript API over two host adapters.
|
|
6
|
+
The package export conditions, not a runtime option, select the adapter:
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
browser/default node/bun/deno/electron
|
|
10
|
+
| |
|
|
11
|
+
v v
|
|
12
|
+
patched Wasmer JavaScript host napi-rs, Node-API 8 addon
|
|
13
|
+
| |
|
|
14
|
+
portable liboliphaunt-wasix Rust actor, direct, Worker, server
|
|
15
|
+
`---------------------+----------------'
|
|
16
|
+
v
|
|
17
|
+
shared TypeScript database API
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The browser adapter owns the portable runtime/seed descriptors and dynamic
|
|
21
|
+
extension carrier installation. The server adapter owns no Wasmer JavaScript
|
|
22
|
+
fallback: it loads one exact, prebuilt platform carrier whose Rust dependency
|
|
23
|
+
embeds the runtime, AOT objects, cluster seed, tools, and supported extension
|
|
24
|
+
catalog. Both execute the canonical WASIX guest and preserve its physical
|
|
25
|
+
database and backup formats.
|
|
26
|
+
|
|
27
|
+
This boundary deliberately does not depend on `src/sdks/js`,
|
|
28
|
+
`liboliphaunt-native`, `node-direct`, or the broker. The N-API product wraps the
|
|
29
|
+
WASIX Rust binding; it is not a route into the native PostgreSQL SDK.
|
|
30
|
+
|
|
31
|
+
Protocol and typed-query helpers are exact mirrors of `src/shared/js-core`.
|
|
32
|
+
That is a shared semantic source, not a dependency on the native TypeScript
|
|
33
|
+
product.
|
|
34
|
+
|
|
35
|
+
The patched Wasmer host under `host/` is a browser-only implementation
|
|
36
|
+
dependency of this binding, not another Oliphaunt runtime product. Browser
|
|
37
|
+
PostgreSQL binaries, PGDATA, and the canonical runtime manifest remain owned by
|
|
38
|
+
`liboliphaunt-wasix`; each extension product owns its separately versioned
|
|
39
|
+
portable carrier envelope. The N-API release embeds the corresponding frozen
|
|
40
|
+
artifacts instead of resolving those bytes during application startup.
|
|
41
|
+
|
|
42
|
+
The canonical guest also owns the backend-only single-backend spinlock and
|
|
43
|
+
scalar-atomic specializations carried by PostgreSQL patches 0035 and 0036.
|
|
44
|
+
They follow the guest into the Rust binding's AOT artifacts and the portable
|
|
45
|
+
module used by the browser. They are not a TypeScript host optimization.
|
|
46
|
+
Frontends, PGXS side modules, and concurrent PostgreSQL builds retain the normal
|
|
47
|
+
atomic implementation. Each adapter asserts the shared
|
|
48
|
+
`OLIPHAUNT_WASIX_SINGLE_BACKEND=1` concurrency invariant and denies guest
|
|
49
|
+
process and thread creation under it. Browser root and `/worker` use the same
|
|
50
|
+
Oliphaunt export driver. Native-host root, `/direct`, `/worker`, and `/server` use the
|
|
51
|
+
same Rust WASIX semantics with different explicit owners. Placement changes
|
|
52
|
+
ownership and hop count, not the PostgreSQL protocol contract.
|
|
53
|
+
|
|
54
|
+
## Browser lifecycle
|
|
55
|
+
|
|
56
|
+
`Oliphaunt.open()` from the root package uses the host driver in the importing
|
|
57
|
+
realm: setup is asynchronous, but PostgreSQL lifecycle and protocol exports run
|
|
58
|
+
in that realm and may monopolize its event loop while active. `Oliphaunt.open()` from
|
|
59
|
+
`@oliphaunt/wasix-ts/worker` creates one package-owned module Worker around the
|
|
60
|
+
same driver. There is no public placement option and neither entrypoint falls
|
|
61
|
+
back to the other. Both share one database state machine, mount
|
|
62
|
+
construction, PostgreSQL configuration, extension/role setup, and storage
|
|
63
|
+
contract. Immutable preparation and compiled modules are cached by verified
|
|
64
|
+
runtime identity, while writable `Directory` mounts and storage leases are
|
|
65
|
+
recreated for every open. Each handle remains one serialized PostgreSQL
|
|
66
|
+
session. Only the root entrypoint contends for its caller's event loop.
|
|
67
|
+
|
|
68
|
+
The pinned host currently instantiates dynamically loaded native side modules
|
|
69
|
+
synchronously. Chromium refuses Window-realm modules above 8 MiB, so the root
|
|
70
|
+
entrypoint fails early there for a selected carrier above that threshold. The
|
|
71
|
+
explicit `/worker` entrypoint and the root imported from a Dedicated Worker are
|
|
72
|
+
outside that Window restriction and apply descriptor-declared native
|
|
73
|
+
load order; a real Chrome canary loads PostGIS there and verifies recovery
|
|
74
|
+
across its large dependency module. The core guest uses the asynchronous path;
|
|
75
|
+
smaller qualified side modules remain supported in a direct Window.
|
|
76
|
+
|
|
77
|
+
1. The root entrypoint imports the package-relative host lazily in the caller
|
|
78
|
+
realm and creates no Worker. `/worker` creates one module Web Worker per open
|
|
79
|
+
and a temporary Worker for restore.
|
|
80
|
+
2. The binding resolves the default `@oliphaunt/liboliphaunt-wasix` descriptor
|
|
81
|
+
internally. The selected realm fetches or receives its canonical manifest, runtime,
|
|
82
|
+
and cluster-seed `.tar.zst` artifacts as one product/version identity. Each
|
|
83
|
+
uncached identity verifies descriptor sizes and hashes plus the manifest's
|
|
84
|
+
core/module and PostgreSQL/source identity; every open uses that exact
|
|
85
|
+
verified identity. Imported extension descriptors add their exact carrier
|
|
86
|
+
closure.
|
|
87
|
+
3. The selected realm safely expands the core artifacts and overlays only each
|
|
88
|
+
extension carrier's install-contract files into separate `/bin`, `/lib`, `/share`,
|
|
89
|
+
writable `/base`, `/home`, and `/tmp` Wasmer memory mounts. Before `/base` is
|
|
90
|
+
materialized, a storage provider lease supplies either the packaged cluster
|
|
91
|
+
seed or an exact-compatible persistent PGDATA. The source-pinned
|
|
92
|
+
host adds ephemeral `/dev/shm` and a real Wasmer `RandomFile` at
|
|
93
|
+
`/dev/urandom`. Its narrow `Directory` mutation journal records successful
|
|
94
|
+
writes and truncates through already-open descriptors as well as file,
|
|
95
|
+
directory, remove, and rename paths for either execution surface and every provider.
|
|
96
|
+
Both execution surfaces pass the verified precompiled main module and its original
|
|
97
|
+
bytes to `instantiateOliphauntDirect`. The root keeps the resulting Store in
|
|
98
|
+
the caller realm; `/worker` keeps it in its package Worker.
|
|
99
|
+
4. Both execution surfaces push protocol bytes through guest-owned reusable input
|
|
100
|
+
and output buffers. The host writes requests directly into canonical guest
|
|
101
|
+
memory and returns one owned JavaScript response copy, so PostgreSQL can
|
|
102
|
+
safely reuse or grow its memory after the call. Startup preserves an
|
|
103
|
+
`ErrorResponse` and its SQLSTATE even when startup terminates the guest.
|
|
104
|
+
5. The direct export driver completes the exported startup transition before
|
|
105
|
+
exposing the session. Selected carriers contribute verified artifacts and
|
|
106
|
+
required startup/preload configuration only; database-local extension SQL is
|
|
107
|
+
application/ORM-owned. A requested non-default user is selected from existing
|
|
108
|
+
roles with `SET ROLE`; standalone bootstrap remains the fixed `postgres`
|
|
109
|
+
identity.
|
|
110
|
+
6. The binding frames later responses through `ReadyForQuery` and exposes
|
|
111
|
+
serialized `query`, `execute`, buffered `execProtocolRaw`, callback
|
|
112
|
+
`execProtocolRawStream`, and callback-scoped `transaction` calls
|
|
113
|
+
through one database contract. The same contract supports explicit
|
|
114
|
+
`close()` and `await using` disposal.
|
|
115
|
+
Every successfully completed protocol operation reaches `ReadyForQuery`, then
|
|
116
|
+
asks a persistent provider to publish only journaled `/base` paths before the
|
|
117
|
+
Promise resolves. A callback transaction defers publication for `BEGIN`, its
|
|
118
|
+
body, and `COMMIT`/`ROLLBACK`, then publishes exactly once after the confirmed
|
|
119
|
+
final boundary. A new persistent synchronous-OPFS root uses a separate internal
|
|
120
|
+
full-publication boundary after initialization; it is not a public database
|
|
121
|
+
operation. PostgreSQL `CHECKPOINT` remains available through ordinary
|
|
122
|
+
`execute`. If a
|
|
123
|
+
PostgreSQL `ERROR` crosses the host boundary, the direct host
|
|
124
|
+
invokes `PostgresMainLongJmp`, sends and flushes readiness, and continues
|
|
125
|
+
through `PostgresMainLoopOnce`. Normal ErrorResponse returns receive the same
|
|
126
|
+
top-level cleanup as trapping errors.
|
|
127
|
+
7. `close` establishes a terminal admission cutoff and lets already accepted
|
|
128
|
+
database work drain. The direct owner
|
|
129
|
+
sends PostgreSQL Terminate through the same direct bridge, deactivates the
|
|
130
|
+
embedded lifecycle, and runs its atexit exports synchronously in the owning
|
|
131
|
+
realm. A successful close completes the
|
|
132
|
+
provider's final persistence boundary. Every outcome attempts provider close,
|
|
133
|
+
exclusive-lease release, and entrypoint-owned host-resource release. The
|
|
134
|
+
browser `/worker` waits for that close reply and then terminates its already
|
|
135
|
+
quiescent Worker; a Node-compatible `/worker` closes its native handle, posts
|
|
136
|
+
the reply, and exits itself. The public
|
|
137
|
+
handle memoizes that single outcome and becomes closed after teardown settles;
|
|
138
|
+
a rejected close never advertises the destroyed owner or guest as reusable.
|
|
139
|
+
If the isolated owner terminates independently, shared session state makes the
|
|
140
|
+
public handle closed immediately and prevents later work from crossing the
|
|
141
|
+
dead transport. An explicit close still memoizes and reports that terminal
|
|
142
|
+
failure while completing package-owned resource cleanup.
|
|
143
|
+
8. Each public database handle registers an opaque generation token for
|
|
144
|
+
best-effort forgotten-handle recovery. The finalizer holds no reference to
|
|
145
|
+
the public owner and only schedules work after returning. It atomically
|
|
146
|
+
claims the exact still-active generation, then schedules the same best-effort
|
|
147
|
+
close for that root, direct, or `/worker` generation. Explicit close
|
|
148
|
+
unregisters the generation before teardown, so queued stale finalizers are
|
|
149
|
+
harmless and cannot affect a later database.
|
|
150
|
+
|
|
151
|
+
Stock Wasmer's public browser API exposes streams and process completion, but
|
|
152
|
+
not arbitrary guest exports. The source-pinned host deliberately adds only the
|
|
153
|
+
narrow Oliphaunt export driver needed to match the Rust WASIX lifecycle; it is
|
|
154
|
+
not a general synchronous WASIX process API. Generic Wasmer process streams
|
|
155
|
+
remain upstream behavior and are not part of the TypeScript database surface.
|
|
156
|
+
|
|
157
|
+
## Node, Bun, Deno, and Electron lifecycle
|
|
158
|
+
|
|
159
|
+
Native-host conditions load one Node-API 8 addon. The root constructs
|
|
160
|
+
`NativeWasixActorDatabase`, which directly owns the Rust `AsyncOliphaunt`
|
|
161
|
+
database actor. Bounded admission is synchronous, PostgreSQL runs on its one
|
|
162
|
+
Rust owner thread, and completion settles the existing Promise on the importing
|
|
163
|
+
JavaScript thread. This is the responsive default and adds one native queue hop.
|
|
164
|
+
|
|
165
|
+
The conditional `/direct` export constructs `NativeWasixDatabase` around
|
|
166
|
+
synchronous `oliphaunt_wasix::Oliphaunt` on the importing JavaScript thread. It
|
|
167
|
+
has the fewest hops and can block that event loop. The conditional `/worker`
|
|
168
|
+
export creates one real package-owned Node-compatible Worker, which loads the
|
|
169
|
+
same `/direct` implementation inside that Worker. It adds the requested
|
|
170
|
+
JavaScript RPC hop and realm isolation without a child process or a second Rust
|
|
171
|
+
owner thread. Native direct handles remain creator-thread-affine.
|
|
172
|
+
|
|
173
|
+
Close establishes one admission cutoff. The actor drains accepted work and
|
|
174
|
+
settles its terminal completion. Direct close runs on its owning thread. A
|
|
175
|
+
package Worker closes its native database at quiescence, posts the close reply,
|
|
176
|
+
then closes its parent port and exits itself; the parent does not terminate a
|
|
177
|
+
Worker across an active Node-API frame. An unexpected Worker exit rejects
|
|
178
|
+
pending work and leaves the public handle terminal.
|
|
179
|
+
|
|
180
|
+
Query serialization, close semantics, the memory default, storage identity,
|
|
181
|
+
and public errors remain TypeScript-owned. Descriptor validation also remains
|
|
182
|
+
shared, but native release addons resolve validated extension SQL names against
|
|
183
|
+
their compile-time catalog instead of expanding portable extension archives at
|
|
184
|
+
open.
|
|
185
|
+
|
|
186
|
+
IndexedDB and OPFS remain browser-only and are rejected before a native-host
|
|
187
|
+
actor, direct, or Worker session starts. Directory persistence is exposed through matching
|
|
188
|
+
`storage/node`, `storage/bun`, and `storage/deno` entrypoints. They preserve the
|
|
189
|
+
shared managed-root descriptor and exclusive path ownership while Rust owns
|
|
190
|
+
the database bytes and durability. No host falls back to native
|
|
191
|
+
`@oliphaunt/ts`. Direct and explicit `/worker` entrypoints may themselves
|
|
192
|
+
be imported from an application-owned worker thread. Rust holds one OS advisory
|
|
193
|
+
lock for the managed-root lifetime, shared with direct Rust owners. There is no
|
|
194
|
+
JavaScript marker lock to recover. Callers should still close before externally
|
|
195
|
+
terminating their own realm.
|
|
196
|
+
|
|
197
|
+
## Protocol streams, tools, and local endpoints
|
|
198
|
+
|
|
199
|
+
The public callback stream reuses the guest's COPY-aware synchronous transport
|
|
200
|
+
and emits at most 64 KiB per callback. Browser root and native `/direct` invoke
|
|
201
|
+
the callback in their owning JavaScript realm. Browser and native-host
|
|
202
|
+
Workers block only their Worker with a shared-memory acknowledgement until the
|
|
203
|
+
importing-realm callback returns. The native actor uses a napi-rs thread-safe
|
|
204
|
+
function with queue size one and waits for each JavaScript acknowledgement.
|
|
205
|
+
Every path therefore preserves bounded backpressure and callback ordering.
|
|
206
|
+
|
|
207
|
+
Direct native requests borrow JavaScript input for the duration of their
|
|
208
|
+
synchronous call. Actor requests copy into owned Rust admission data before the
|
|
209
|
+
call returns. All native responses, backup archives, chunks, and tool output are
|
|
210
|
+
ordinary V8-owned typed arrays with predictable detach and lifetime behavior.
|
|
211
|
+
The Worker transport transfers eligible response `ArrayBuffer` values directly;
|
|
212
|
+
there is no external-buffer finalizer crossing an isolate or environment exit.
|
|
213
|
+
|
|
214
|
+
A callback returning a Promise or thenable is rejected: asynchronous
|
|
215
|
+
completion cannot acknowledge this synchronous backpressure contract, and the
|
|
216
|
+
PostgreSQL session is poisoned conservatively. The callback is also an
|
|
217
|
+
ownership boundary: it cannot queue work through the same database or
|
|
218
|
+
transaction while that database is waiting for the chunk acknowledgement. Such
|
|
219
|
+
reentry fails immediately instead of creating a hidden post-stream operation.
|
|
220
|
+
|
|
221
|
+
`@oliphaunt/wasix-tools` remains the optional public facade. In a browser it
|
|
222
|
+
resolves the separately published `@oliphaunt/liboliphaunt-wasix-tools` asset
|
|
223
|
+
carrier. `pg_dump` runs in the realm that already owns the database; `psql`
|
|
224
|
+
uses a separate persistent browser tool worker because COPY input is genuinely
|
|
225
|
+
full duplex. Its private pgwire connection has fixed, bounded shared-memory
|
|
226
|
+
rings.
|
|
227
|
+
|
|
228
|
+
Native release addons compile both frontends and the current extension catalog
|
|
229
|
+
into every platform binary. Node.js, Bun, Deno, and Electron route `pg_dump` and
|
|
230
|
+
`psql` through the existing Rust database owner on root, `/direct`, or `/worker` and do
|
|
231
|
+
not resolve portable tool bytes at invocation time. This intentionally trades
|
|
232
|
+
larger platform packages and a coordinated carrier release for fewer startup
|
|
233
|
+
reads, decompressions, compilation steps, and runtime compatibility edges.
|
|
234
|
+
|
|
235
|
+
The package export `@oliphaunt/wasix-ts/internal/tools` exists only so the
|
|
236
|
+
version-matched `@oliphaunt/wasix-tools` package can reach this bridge. It is not
|
|
237
|
+
an application API or part of the stable SDK surface, is undocumented for app
|
|
238
|
+
consumers, and may change only in lockstep with that companion package. Package
|
|
239
|
+
checks reject any other low-level query or protocol subpath exports.
|
|
240
|
+
|
|
241
|
+
The database session is exclusively serialized. It resets PostgreSQL with
|
|
242
|
+
`ROLLBACK`, `DISCARD ALL`, and the configured role before and after a tool, then
|
|
243
|
+
publishes storage once after the final safe cleanup boundary. An uncertain tool
|
|
244
|
+
transport outcome poisons the handle after making its stored state safe. The
|
|
245
|
+
tools remain outside the core public database surface on both adapters.
|
|
246
|
+
|
|
247
|
+
The host-only `/server` subpath uses conditions to export the same implementation
|
|
248
|
+
for Node, Bun, Deno, and Electron. It has no browser or default condition. The implementation
|
|
249
|
+
constructs the Rust `OliphauntServer` through the same addon rather than
|
|
250
|
+
adapting a JavaScript socket relay. It binds one loopback TCP or
|
|
251
|
+
PostgreSQL-named Unix listener and serves one active client. Another connection
|
|
252
|
+
may wait in the operating-system backlog, so consumers configure pools with a
|
|
253
|
+
maximum size of one. Each admitted connection receives a fresh embedded
|
|
254
|
+
backend. Server state, listener lifetime, and storage publication are
|
|
255
|
+
Rust-owned; the TypeScript facade retains the
|
|
256
|
+
existing Promise-shaped open/close and `closed` contract. The concurrent WASIX
|
|
257
|
+
postmaster remains a separate runtime product rather than a mode of this
|
|
258
|
+
single-backend SDK.
|
|
259
|
+
|
|
260
|
+
## Browser storage boundary
|
|
261
|
+
|
|
262
|
+
Storage is a binding-owned provider/lease contract rather than runtime asset
|
|
263
|
+
configuration:
|
|
264
|
+
|
|
265
|
+
```text
|
|
266
|
+
opaque storage descriptor
|
|
267
|
+
|
|
|
268
|
+
v
|
|
269
|
+
acquire provider lease ---- exact physical compatibility
|
|
270
|
+
|
|
|
271
|
+
+---- synchronous OPFS /base ---- exact-range file I/O
|
|
272
|
+
|
|
|
273
|
+
`---- portable /base ------ journaled publication
|
|
274
|
+
|
|
|
275
|
+
v
|
|
276
|
+
PostgreSQL boundary + release
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
The main package owns the fresh-memory descriptor and default. IndexedDB and
|
|
280
|
+
OPFS are selective `./storage/indexed-db` and `./storage/opfs` entrypoints whose
|
|
281
|
+
implementations load only when an opaque descriptor reaches the owning
|
|
282
|
+
realm. Raw serialized descriptors are not accepted from consumers. The
|
|
283
|
+
internal lease exposes `state`, one initial PGDATA mount,
|
|
284
|
+
an optional synchronous PGDATA materializer, `sync(directory, boundary)`, and
|
|
285
|
+
`close(directory, outcome)`; it does not own runtime or extension assets.
|
|
286
|
+
|
|
287
|
+
The source-pinned Wasmer `Directory` exposes a compact current-state mutation
|
|
288
|
+
journal. Write-capable files are wrapped so a PostgreSQL descriptor retained
|
|
289
|
+
across multiple operations records every later write, not only its initial
|
|
290
|
+
open. The shared portable delta layer drains the journal only at
|
|
291
|
+
PostgreSQL-safe host boundaries, collapses overlapping paths, reads changed
|
|
292
|
+
files and subtrees, and expresses removals explicitly. A provider without that
|
|
293
|
+
host capability falls back to a full scan, so correctness does not depend on
|
|
294
|
+
the optimization. Synchronous OPFS mounts bypass mutation tracking and serve the
|
|
295
|
+
guest synchronously in its owning worker. Process-lifetime `postmaster.pid` and
|
|
296
|
+
`postmaster.opts` never enter persistent storage.
|
|
297
|
+
|
|
298
|
+
Each logical IndexedDB name owns a separate physical IndexedDB database with
|
|
299
|
+
fixed metadata and one row per PGDATA path. Each boundary applies upserts and
|
|
300
|
+
removals in one atomic read-write transaction using the browser's default
|
|
301
|
+
commitState policy; an aborted write leaves the preceding generation intact,
|
|
302
|
+
and distinct logical databases do not share an object-store transaction. OPFS
|
|
303
|
+
stores a strict logical namespace and physical identity over flat backing files.
|
|
304
|
+
`/worker`, and the root inside a Dedicated Worker, preopen synchronous access
|
|
305
|
+
handles and perform exact-range guest I/O without a mailbox or nested worker. A
|
|
306
|
+
direct Window uses the portable path. Guest file flushes are immediate;
|
|
307
|
+
operation boundaries drain WAL; internal full-publication, close, and namespace publication
|
|
308
|
+
flush WAL before ordinary files and `global/pg_control`. The portable path uses
|
|
309
|
+
copy-on-write backing files and atomically replaces namespace state last. OPFS
|
|
310
|
+
has PostgreSQL recovery ordering but no cross-file transaction, so a failed
|
|
311
|
+
publication reports unknown state instead of claiming that nothing changed.
|
|
312
|
+
The synchronous path keeps a bounded private reserve of preopened backing files for
|
|
313
|
+
the synchronous hot path. Overflow is staged only until the mandatory host
|
|
314
|
+
boundary, which allocates, writes, and flushes every staged file before
|
|
315
|
+
publishing namespace state. A failure leaves the previous namespace
|
|
316
|
+
authoritative and poisons the live handle. The reserve is replenished
|
|
317
|
+
best-effort after successful boundaries, and hosts that cannot establish its
|
|
318
|
+
initial capacity use the portable path. Its size is an implementation detail,
|
|
319
|
+
not a public database-capacity limit.
|
|
320
|
+
|
|
321
|
+
Compatibility uses the PostgreSQL major and versioned WASIX physical format.
|
|
322
|
+
Runtime hashes and source fingerprints still reject mixed runtime, cluster-seed,
|
|
323
|
+
AOT, and extension build outputs, while package and carrier changes do not
|
|
324
|
+
rewrite the managed-root descriptor or reject an unchanged physical format.
|
|
325
|
+
Safe extension upgrade or removal remains an explicit migration concern rather
|
|
326
|
+
than a reason to reject every change in the available carrier set.
|
|
327
|
+
Cross-binding root handoff is not a supported or qualified workflow.
|
|
328
|
+
|
|
329
|
+
Persistent databases use an origin-scoped exclusive Web Lock. This preserves
|
|
330
|
+
the single-owner invariant rather than suggesting that one single-user
|
|
331
|
+
PostgreSQL backend represents independent connections. There is no leader
|
|
332
|
+
proxy or multi-tab transaction ownership yet.
|
|
333
|
+
|
|
334
|
+
Provider acquisition and PGDATA materialization happen before PostgreSQL
|
|
335
|
+
starts. Provider boundaries happen only after pgwire recovery returns
|
|
336
|
+
`ReadyForQuery`, so ordinary PostgreSQL errors retain their existing
|
|
337
|
+
`PostgresError` identity. A host persistence failure is instead a typed storage
|
|
338
|
+
error and poisons the live handle: guest state may be ahead of confirmed durable
|
|
339
|
+
storage, so retrying the application operation is not known to be safe.
|
|
340
|
+
|
|
341
|
+
## Selective extension descriptor contract
|
|
342
|
+
|
|
343
|
+
The consumer API accepts exact structural values rather than SQL strings:
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
type WasixExtensionDescriptor = {
|
|
347
|
+
schema: 'oliphaunt-wasix-extension-v1';
|
|
348
|
+
runtime: 'wasix';
|
|
349
|
+
product: string;
|
|
350
|
+
version: string;
|
|
351
|
+
compatibility: {
|
|
352
|
+
extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1';
|
|
353
|
+
postgresMajor: string;
|
|
354
|
+
wasixRuntimeProduct: 'liboliphaunt-wasix';
|
|
355
|
+
wasixRuntimeVersion: string;
|
|
356
|
+
};
|
|
357
|
+
sqlName: string;
|
|
358
|
+
carriers: readonly {
|
|
359
|
+
product: string;
|
|
360
|
+
version: string;
|
|
361
|
+
sqlName: string;
|
|
362
|
+
archive: string;
|
|
363
|
+
sha256: string;
|
|
364
|
+
size: number;
|
|
365
|
+
source: string | URL | ArrayBuffer | Uint8Array;
|
|
366
|
+
install: {
|
|
367
|
+
schema: 'oliphaunt-wasix-extension-install-v1';
|
|
368
|
+
dependencies: readonly string[];
|
|
369
|
+
coreExportsRequired: readonly string[];
|
|
370
|
+
// exact native-module, lifecycle, and installed-file projections
|
|
371
|
+
};
|
|
372
|
+
}[];
|
|
373
|
+
};
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
This is structural rather than nominal so a generated extension package can be
|
|
377
|
+
dependency-free; it does not import the host binding merely to acquire a brand.
|
|
378
|
+
The literal `runtime: 'wasix'` still makes native descriptors statically
|
|
379
|
+
incompatible with non-WASIX extension descriptors, and the client
|
|
380
|
+
runtime-validates the complete shape.
|
|
381
|
+
The binding keeps an internal validation/freezing helper for fixtures. It is not
|
|
382
|
+
part of the consumer entrypoint and generated packages do not depend on it.
|
|
383
|
+
|
|
384
|
+
Generated leaf packages can point at their package-owned payload without any
|
|
385
|
+
host conditional:
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
const carrier = {
|
|
389
|
+
source: new URL('./extensions/pgtap/extension.tar.zst', import.meta.url),
|
|
390
|
+
// product, version, SQL identity, archive key, hash, and size
|
|
391
|
+
} as const;
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
The development Vite harness derives virtual package descriptors from the current
|
|
395
|
+
canonical target outputs and uses development route strings while serving those
|
|
396
|
+
exact artifacts directly.
|
|
397
|
+
|
|
398
|
+
Each descriptor selects only its root `sqlName`. Its carrier array is a
|
|
399
|
+
dependency-complete byte closure, not an alternate dependency declaration. The
|
|
400
|
+
client validates each root's exact dependency closure, unions closures in
|
|
401
|
+
deterministic SQL-name order, deduplicates shared rows only when their complete
|
|
402
|
+
identity/install/compatibility metadata agrees, and rejects repeated rows,
|
|
403
|
+
duplicate roots, or conflicts. The selected realm resolves dependencies solely from
|
|
404
|
+
the imported install contracts, treating only the stripped core manifest's
|
|
405
|
+
`runtime-support` entries as runtime-provided. Before reading extension bytes,
|
|
406
|
+
it gates every carrier on the selected WASIX runtime version, PostgreSQL major,
|
|
407
|
+
extension-runtime contract, and required names in `runtime.link.exports`. It
|
|
408
|
+
then verifies each archive's declared size/hash and overlays exactly its
|
|
409
|
+
carrier-owned installed-file inventory. The core manifest is required to have
|
|
410
|
+
`extensions: []` so it cannot quietly reclaim optional extension ownership.
|
|
411
|
+
|
|
412
|
+
That byte-closure processing is the browser implementation. Node.js, Bun, Deno,
|
|
413
|
+
and Electron retain the same public descriptor and perform its structural/runtime
|
|
414
|
+
validation, but pass only the validated, dependency-ordered SQL names across
|
|
415
|
+
the N-API boundary. The Rust runtime resolves those names against the exact
|
|
416
|
+
extension features compiled into the release carrier. Unknown names fail; the
|
|
417
|
+
addon never treats arbitrary descriptor bytes as native code. A new or upgraded
|
|
418
|
+
extension can ship independently for browsers, but it becomes available to
|
|
419
|
+
native-host consumers only after the N-API product is rebuilt and released
|
|
420
|
+
with that feature.
|
|
421
|
+
|
|
422
|
+
## Host compatibility
|
|
423
|
+
|
|
424
|
+
The host is rebuilt from source rather than maintained as hand-edited generated
|
|
425
|
+
JavaScript/WASM. `host/source.toml` pins the Wasmer JS Git source and Cargo
|
|
426
|
+
crates; the adjacent patches are the reviewable compatibility delta. The build
|
|
427
|
+
lands first in `target/oliphaunt-wasix-ts/host`. Public package staging copies
|
|
428
|
+
the exact JS module, worker module, WebAssembly module, license, and provenance
|
|
429
|
+
into `lib/host`; the browser root imports the host in the caller realm, while
|
|
430
|
+
the browser `/worker` imports it in its package Worker. Node.js, Bun, Deno, and Electron
|
|
431
|
+
conditions do not import this module.
|
|
432
|
+
|
|
433
|
+
This is not a general backport of WASIX 0.702 to Wasmer 0.601. The authoritative
|
|
434
|
+
patch order is the `series` in `host/source.toml`; this document records the
|
|
435
|
+
resulting invariants instead of duplicating that filename inventory. Together,
|
|
436
|
+
the patches:
|
|
437
|
+
|
|
438
|
+
- honor configured args, environment, mounts, cwd, and stdio; preserve original
|
|
439
|
+
module bytes where the generic blocking worker needs them; and repair the
|
|
440
|
+
pinned npm/toolchain inputs without mutating their lock;
|
|
441
|
+
- provide only the 0.702 compatibility imports and runtime devices required by
|
|
442
|
+
the shipped guests, reject unavailable fork/context/thread/process behavior,
|
|
443
|
+
remove the retired Rust target, and recognize standard WebAssembly exception
|
|
444
|
+
reference types;
|
|
445
|
+
- make oversized main-module construction asynchronous through the builder and
|
|
446
|
+
linker while keeping the returned database driver synchronous and rejecting
|
|
447
|
+
unsupported oversized side modules before open;
|
|
448
|
+
- enforce the single-backend profile, use correct realtime and monotonic clocks,
|
|
449
|
+
amortize bounded pending-work checks, and avoid turning synchronous-file POSIX
|
|
450
|
+
close into an implicit fsync that bypasses PostgreSQL durability policy;
|
|
451
|
+
- expose the current-state mutation journal and the narrow caller-realm
|
|
452
|
+
synchronous filesystem bridge used by synchronous OPFS, without reviving the old
|
|
453
|
+
mailbox transport;
|
|
454
|
+
- provide the caller-realm PostgreSQL lifecycle and reusable-memory pgwire
|
|
455
|
+
driver, including COPY-aware callback streaming, top-level error recovery,
|
|
456
|
+
and a bounded 16 KiB failure-only stderr tail; and
|
|
457
|
+
- run only the packaged PostgreSQL frontend tools through a fresh caller-realm
|
|
458
|
+
WASIX process with captured stdio and synchronous pgwire callbacks. This path
|
|
459
|
+
uses neither the generic Wasmer scheduler worker nor a Web Streams pump.
|
|
460
|
+
|
|
461
|
+
The clock specialization is intentionally narrower than a general syscall
|
|
462
|
+
shortcut. Realtime uses the JavaScript epoch clock, while monotonic reads
|
|
463
|
+
calibrate the host's monotonic clock against the canonical Rust fallback epoch,
|
|
464
|
+
so fast and fallback reads cannot jump between domains. Process and thread CPU
|
|
465
|
+
clocks remain on the canonical fallback because wall time is not an equivalent
|
|
466
|
+
clock. Synthetic clock offsets remain honored by declining the direct import
|
|
467
|
+
for guests that import `clock_time_set`, and pending WASIX operations are
|
|
468
|
+
checked on a real-time bound. Invalid clock IDs, pointers, or host values use
|
|
469
|
+
the complete Rust syscall. Other WASIX programs retain the complete upstream
|
|
470
|
+
per-call path.
|
|
471
|
+
|
|
472
|
+
The exact pairing is qualified for the single-process direct Oliphaunt export
|
|
473
|
+
path in both execution surfaces, including repeated PostgreSQL `ERROR` recovery. The
|
|
474
|
+
direct driver treats every `PostgresMainLoopOnce` trap as the guest's exported
|
|
475
|
+
top-level recovery boundary and also cleans up non-trapping ErrorResponses.
|
|
476
|
+
Its JavaScript memory bridge is limited to the direct Oliphaunt driver: generic
|
|
477
|
+
WASIX streams keep their normal ownership and scheduling semantics. Copy failures
|
|
478
|
+
are caught before guest buffers are released, and protocol responses are copied
|
|
479
|
+
once into owned JavaScript storage rather than exposed as mutable guest views.
|
|
480
|
+
Browser qualification loads and calls PostGIS in a real worker and asserts that
|
|
481
|
+
its dependency side module exceeds Chromium's 8 MiB main-thread compilation
|
|
482
|
+
limit; the exemption is therefore attached to the worker realm, not to an
|
|
483
|
+
extension name or a benchmark payload size.
|
|
484
|
+
This remains an integration contract with the pinned Oliphaunt runtime rather
|
|
485
|
+
than a generic Wasmer guarantee.
|
|
486
|
+
Missing WASIX context switching is a broader compatibility gap, but is not part
|
|
487
|
+
of this PostgreSQL recovery path. Ordinary package resolution never selects
|
|
488
|
+
stock `@wasmer/sdk`; the published binding owns the source-pinned host. A larger
|
|
489
|
+
current-Wasmer JS port is outside this host's compatibility contract.
|
|
490
|
+
|
|
491
|
+
The version skew is upstream-owned rather than a loose Oliphaunt dependency.
|
|
492
|
+
The commit referenced by the latest npm `@wasmer/sdk` 0.10.0 release identifies
|
|
493
|
+
its checked-in source as 0.8.0 and embeds Wasmer 6.1 with the 0.601 Wasmer
|
|
494
|
+
support family. `wasmer-wasix` 0.702.1 embeds Wasmer 7.2.1 and
|
|
495
|
+
matching 0.702.1 virtual filesystem/network, package, configuration, backend,
|
|
496
|
+
and types contracts. A coordinated compile probe exposed incompatible
|
|
497
|
+
`FileSystem` mounting, `TaskWasm`, wasm-bindgen conversion, registry calls,
|
|
498
|
+
module hashing, and binary-package construction before the Oliphaunt runner and
|
|
499
|
+
recovery changes could be reapplied. Consequently 0.702.1 adoption is a full
|
|
500
|
+
source-host port plus browser qualification, not an isolated crate bump.
|
|
501
|
+
`host/source.toml` records the intentionally coherent 0.601 source family until
|
|
502
|
+
that port exists.
|
|
503
|
+
|
|
504
|
+
## PGlite reference, not product inheritance
|
|
505
|
+
|
|
506
|
+
PGlite independently validates the recovery shape used here. Its Emscripten
|
|
507
|
+
guest turns the active PostgreSQL top-level `longjmp` into a known exit status;
|
|
508
|
+
the TypeScript host then calls `PostgresMainLongJmp`, sends readiness, flushes,
|
|
509
|
+
and resumes `PostgresMainLoopOnce`. Its public database error is separately
|
|
510
|
+
decoded from pgwire. See PGlite's
|
|
511
|
+
[runtime loop](https://github.com/electric-sql/pglite/blob/67872123b637ba132cceb8dbb3f739a09685ee87/packages/pglite/src/pglite.ts#L932-L965)
|
|
512
|
+
and [guest shim](https://github.com/electric-sql/postgres-pglite/blob/7b4ee5086055dc5e54ae1e13e487888249438e68/pglite/src/pglitec/pglitec.c#L52-L84).
|
|
513
|
+
Oliphaunt deliberately uses an environment-gated Wasmer exception discriminator
|
|
514
|
+
instead of Emscripten's numeric sentinel, but preserves the same separation
|
|
515
|
+
between control-flow recovery and the pgwire `PostgresError` seen by callers.
|
|
516
|
+
Lifecycle SQL for a selectively imported extension runs in the owning realm.
|
|
517
|
+
Isolated-host errors are serialized by PostgreSQL field and rebuilt in the caller;
|
|
518
|
+
direct errors retain the same `PostgresError` identity in place. Generic
|
|
519
|
+
transport errors retain their name, message, and owner-side stack. Neither path
|
|
520
|
+
collapses SQLSTATE and diagnostics into a generic error.
|
|
521
|
+
|
|
522
|
+
PGlite is also a useful ordering reference: it stages extension archives and
|
|
523
|
+
precompiles Emscripten side modules before PostgreSQL starts. Those
|
|
524
|
+
`MAIN_MODULE`/`SIDE_MODULE` binaries are not WASIX carriers, however, and its
|
|
525
|
+
filesystem persistence is coupled to Emscripten FS.
|
|
526
|
+
|
|
527
|
+
The browser benchmark also exposed a preparation asymmetry: PGlite reused
|
|
528
|
+
precompiled modules while each WASIX open recompiled the verified guest bytes.
|
|
529
|
+
Caller-realm execution now bounds and keys immutable preparation and compiled-module
|
|
530
|
+
caches by exact runtime/carrier/GUC identity. Mutable directories and storage
|
|
531
|
+
leases never enter those caches. The checked-in insert benchmark compares WAL
|
|
532
|
+
volume alongside timing; separate root-cause diagnostics compare buffer
|
|
533
|
+
activity and relation sizes. Both keep host/runtime overhead visible without
|
|
534
|
+
changing PostgreSQL work or commitState settings.
|
|
535
|
+
|
|
536
|
+
This binding keeps the following deliberate divergences:
|
|
537
|
+
|
|
538
|
+
- extension lifecycle and install metadata comes from each selectively imported
|
|
539
|
+
`-wasix` package; the stripped runtime manifest cannot override it;
|
|
540
|
+
- runtime/PGDATA/manifest hashes, carrier hashes, required core exports, exact
|
|
541
|
+
installed-file inventories, dependencies, and collisions are checked before
|
|
542
|
+
startup;
|
|
543
|
+
- selecting an extension stages its verified artifacts and startup configuration;
|
|
544
|
+
applications explicitly run ordinary `CREATE EXTENSION`, `LOAD`, schema, or
|
|
545
|
+
migration SQL, matching the ownership expected by ORMs; and
|
|
546
|
+
- IndexedDB and OPFS now use source-pinned dirty-path synchronization at each
|
|
547
|
+
completed protocol operation, matching PGlite's useful commitState boundary
|
|
548
|
+
without importing Emscripten FS. Oliphaunt keeps explicit provider-specific
|
|
549
|
+
atomicity and exclusive ownership; multi-tab leadership remains unsupported.
|
|
550
|
+
|
|
551
|
+
The host validates every native `load-order` entry against the carrier's exact
|
|
552
|
+
installed-file inventory but does not execute it as SQL. Applications explicitly
|
|
553
|
+
issue any required `LOAD`/`CREATE EXTENSION` lifecycle, after which PostgreSQL and
|
|
554
|
+
Wasmer's dynamic linker remain responsible for each module's declared
|
|
555
|
+
`dylink-needed` closure. `shared-memory-required` contracts remain rejected
|
|
556
|
+
because the single-backend runtime has not qualified that capability.
|
|
557
|
+
|
|
558
|
+
## Asset ownership
|
|
559
|
+
|
|
560
|
+
The `@oliphaunt/wasix-ts` tarball does not contain PostgreSQL binaries. Browser
|
|
561
|
+
conditions import `@oliphaunt/liboliphaunt-wasix`, whose generated descriptor
|
|
562
|
+
points at package-owned runtime, PGDATA, and manifest assets. There is no public
|
|
563
|
+
raw runtime-source override. Development reads
|
|
564
|
+
`target/oliphaunt-wasix/assets`, produced by
|
|
565
|
+
`liboliphaunt-wasix:runtime-portable`, through the browser example's Vite
|
|
566
|
+
plugin, which models that generated carrier.
|
|
567
|
+
|
|
568
|
+
Node.js, Bun, Deno, and Electron also receive one target-filtered optional dependency.
|
|
569
|
+
The public carriers are
|
|
570
|
+
`@oliphaunt/wasix-napi-darwin-arm64`,
|
|
571
|
+
`@oliphaunt/wasix-napi-linux-arm64-gnu`,
|
|
572
|
+
`@oliphaunt/wasix-napi-linux-x64-gnu`, and
|
|
573
|
+
`@oliphaunt/wasix-napi-win32-x64-msvc`. Each has no install script and contains
|
|
574
|
+
one `oliphaunt_wasix_napi.node` binary with both standard and ICU profiles. The private
|
|
575
|
+
`@oliphaunt/wasix-napi` product coordinates the Rust build and carrier release;
|
|
576
|
+
applications never import it.
|
|
577
|
+
|
|
578
|
+
Linux carriers are GNU/glibc-only. The adapter identifies libc from the
|
|
579
|
+
runtime diagnostic report before resolving package-adjacent, optional, or
|
|
580
|
+
explicit addon paths; known musl and unknown libc identities fail closed.
|
|
581
|
+
|
|
582
|
+
Native release builds embed the runtime, seed, AOT objects, frontend tools, and
|
|
583
|
+
complete currently supported extension feature set. Optional extensions remain
|
|
584
|
+
exact, separately imported `-wasix` packages at the public TypeScript boundary,
|
|
585
|
+
but native hosts use their descriptor identity to select compiled-in artifacts
|
|
586
|
+
instead of copying the carrier bytes. Their availability is consequently a
|
|
587
|
+
release-time N-API contract.
|
|
588
|
+
|
|
589
|
+
The source workspace manifest deliberately does not resolve that generated
|
|
590
|
+
carrier from npm: the carrier exists only after same-candidate runtime assets
|
|
591
|
+
are frozen. SDK release staging injects the exact dependency recorded by
|
|
592
|
+
`oliphaunt.runtimeVersion`, validates it, and publishes only that staged
|
|
593
|
+
manifest. This keeps fresh frozen workspace installs independent of an
|
|
594
|
+
unpublished candidate while making the consumer tarball's browser runtime edge
|
|
595
|
+
exact. The same staging step rewrites every native optional dependency to the
|
|
596
|
+
exact N-API product version. The loader rejects a carrier whose package name,
|
|
597
|
+
version, target, WASIX runtime, addon ABI, Node-API level, or profile inventory do
|
|
598
|
+
not match the SDK metadata; the addon then self-reports its runtime and exact
|
|
599
|
+
supported profile inventory before open.
|
|
600
|
+
|
|
601
|
+
The release runtime carrier owns a stripped core manifest (`extensions: []`).
|
|
602
|
+
The development Vite plugin projects the same core-only bytes from the build
|
|
603
|
+
pipeline's qualification manifest and derives separate exact extension install
|
|
604
|
+
contracts from its extension rows. The binding rejects a nonempty core manifest,
|
|
605
|
+
so the runtime carrier cannot become the authority for independently versioned
|
|
606
|
+
extensions.
|
|
607
|
+
|
|
608
|
+
The first browser smoke selects the SQL-only `pgtap` carrier and explicitly runs
|
|
609
|
+
`CREATE EXTENSION`. That isolates manifest verification, dependency ordering, archive overlay, and lifecycle SQL
|
|
610
|
+
from dynamic linking. The separate `smoke-browser.mjs --pg-uuidv7` profile selects the
|
|
611
|
+
native carrier, calls `uuid_generate_v7()` before and after the two error
|
|
612
|
+
recovery cases, verifies both results are UUIDv7 values, and checks clean
|
|
613
|
+
process exit. That proves one exact `.so` against the pinned package-owned host; it
|
|
614
|
+
does not add or widen a canonical extension target claim. Generic native-module
|
|
615
|
+
support remains gated on a safer loader boundary and broader qualification.
|
|
616
|
+
|
|
617
|
+
The example's virtual Vite modules model the intended
|
|
618
|
+
`@oliphaunt/extension-pgtap-wasix` and
|
|
619
|
+
`@oliphaunt/extension-pg-uuidv7-wasix` package roots from current target
|
|
620
|
+
outputs. Its asset middleware and COOP/COEP headers are development-only.
|
|
621
|
+
Production hosting, cache policy, and asset integrity are application/carrier
|
|
622
|
+
concerns; the binding does not silently copy target-owned assets into its npm
|
|
623
|
+
bundle.
|
|
624
|
+
|
|
625
|
+
## Public package and qualification
|
|
626
|
+
|
|
627
|
+
`@oliphaunt/wasix-ts` is a separately versioned public SDK product. It has its own
|
|
628
|
+
release metadata and changelog, declares an exact browser dependency on the
|
|
629
|
+
published `@oliphaunt/liboliphaunt-wasix` runtime carrier, and declares the four
|
|
630
|
+
exact native packages as optional dependencies. It publishes the patched host
|
|
631
|
+
under `lib/host` for browser/default conditions. Conditional package exports
|
|
632
|
+
choose browser, Node.js, Bun, Deno, or Electron adapters. Browser root remains
|
|
633
|
+
caller-owned; the native-host root uses the Rust actor, `/direct` is caller-owned, and
|
|
634
|
+
the conditional `/worker` subpath is owned by its isolated Worker.
|
|
635
|
+
|
|
636
|
+
The browser smoke proves the exact runtime/host pairing can start PostgreSQL,
|
|
637
|
+
explicitly activate `pgtap`, retain SQLSTATE across repeated PostgreSQL error recovery,
|
|
638
|
+
continue with `42` on the same handle, persist through IndexedDB operation
|
|
639
|
+
boundaries, run an explicit `CHECKPOINT` through `execute`, and close with a
|
|
640
|
+
successful zero exit status. Each Node.js, Bun, Deno, and Electron host smoke installs the
|
|
641
|
+
packed SDK and matching packed platform carrier into a fresh external project,
|
|
642
|
+
verifies conditional-export and profile selection, starts the embedded
|
|
643
|
+
WASIX Rust runtime, activates a compiled extension, recovers from an error, and
|
|
644
|
+
closes cleanly. Each carrier also runs a real actor Simple Query roundtrip and
|
|
645
|
+
proves its V8-owned response buffer is transferable; Node additionally proves
|
|
646
|
+
direct and local-server lifecycles. The Deno proof uses local `node_modules`
|
|
647
|
+
with explicit read, environment, and FFI permissions and qualifies the declared
|
|
648
|
+
Deno CLI range, not managed Deno Deploy. Electron additionally qualifies the
|
|
649
|
+
ASAR-unpacked native-addon layout. The opt-in native browser profile
|
|
650
|
+
additionally loads and calls the canonical `pg_uuidv7.so`; it remains a narrow
|
|
651
|
+
canary rather than a generic dynamic-extension claim.
|
|
652
|
+
|
|
653
|
+
The intentional host, persistence, extension, and Wasmer compatibility limits
|
|
654
|
+
remain listed in [README.md](./README.md). They are explicit product boundaries,
|
|
655
|
+
not compatibility aliases or fallbacks to a native SDK.
|