@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.
Files changed (169) hide show
  1. package/ARCHITECTURE.md +655 -0
  2. package/CHANGELOG.md +33 -0
  3. package/LICENSE +21 -0
  4. package/README.md +404 -0
  5. package/THIRD_PARTY_NOTICES.md +20 -0
  6. package/lib/archive.d.ts +21 -0
  7. package/lib/archive.js +336 -0
  8. package/lib/asset-source.d.ts +4 -0
  9. package/lib/asset-source.js +15 -0
  10. package/lib/byte-channel.d.ts +27 -0
  11. package/lib/byte-channel.js +170 -0
  12. package/lib/client-common.d.ts +6 -0
  13. package/lib/client-common.js +36 -0
  14. package/lib/client.d.ts +7 -0
  15. package/lib/client.js +24 -0
  16. package/lib/database-root.d.ts +19 -0
  17. package/lib/database-root.js +139 -0
  18. package/lib/database.d.ts +135 -0
  19. package/lib/database.js +1039 -0
  20. package/lib/descriptor-validation.d.ts +10 -0
  21. package/lib/descriptor-validation.js +75 -0
  22. package/lib/direct-client-common.d.ts +50 -0
  23. package/lib/direct-client-common.js +717 -0
  24. package/lib/direct-client.d.ts +4 -0
  25. package/lib/direct-client.js +13 -0
  26. package/lib/direct.node.d.ts +2 -0
  27. package/lib/direct.node.js +2 -0
  28. package/lib/errors.d.ts +25 -0
  29. package/lib/errors.js +34 -0
  30. package/lib/extension-descriptor.d.ts +14 -0
  31. package/lib/extension-descriptor.js +419 -0
  32. package/lib/extensions.d.ts +68 -0
  33. package/lib/extensions.js +769 -0
  34. package/lib/host/LICENSE +21 -0
  35. package/lib/host/index.d.mts +123 -0
  36. package/lib/host/index.mjs +11 -0
  37. package/lib/host/provenance.json +16 -0
  38. package/lib/host/wasmer_js_bg.wasm +0 -0
  39. package/lib/host/worker.mjs +11 -0
  40. package/lib/host-runtime.d.ts +5 -0
  41. package/lib/host-runtime.js +13 -0
  42. package/lib/icu-descriptor.d.ts +3 -0
  43. package/lib/icu-descriptor.js +92 -0
  44. package/lib/index.bun.d.ts +2 -0
  45. package/lib/index.bun.js +2 -0
  46. package/lib/index.d.ts +2 -0
  47. package/lib/index.deno.d.ts +2 -0
  48. package/lib/index.deno.js +2 -0
  49. package/lib/index.js +2 -0
  50. package/lib/index.node.d.ts +2 -0
  51. package/lib/index.node.js +2 -0
  52. package/lib/internal-common.d.ts +12 -0
  53. package/lib/internal-common.js +274 -0
  54. package/lib/internal.d.ts +5 -0
  55. package/lib/internal.js +42 -0
  56. package/lib/internal.node.d.ts +5 -0
  57. package/lib/internal.node.js +8 -0
  58. package/lib/native-addon.d.ts +111 -0
  59. package/lib/native-addon.js +223 -0
  60. package/lib/native-server.d.ts +21 -0
  61. package/lib/native-server.js +109 -0
  62. package/lib/native-session.d.ts +60 -0
  63. package/lib/native-session.js +565 -0
  64. package/lib/node-actor.d.ts +7 -0
  65. package/lib/node-actor.js +10 -0
  66. package/lib/node-client-common.d.ts +9 -0
  67. package/lib/node-client-common.js +35 -0
  68. package/lib/node-client.d.ts +4 -0
  69. package/lib/node-client.js +13 -0
  70. package/lib/node-direct.d.ts +7 -0
  71. package/lib/node-direct.js +10 -0
  72. package/lib/node-worker-options.d.ts +5 -0
  73. package/lib/node-worker-options.js +65 -0
  74. package/lib/node-worker-port.d.ts +4 -0
  75. package/lib/node-worker-port.js +116 -0
  76. package/lib/node-worker.d.ts +1 -0
  77. package/lib/node-worker.js +38 -0
  78. package/lib/pgwire-connection.d.ts +60 -0
  79. package/lib/pgwire-connection.js +528 -0
  80. package/lib/pgwire.d.ts +3 -0
  81. package/lib/pgwire.js +105 -0
  82. package/lib/physical-archive.d.ts +29 -0
  83. package/lib/physical-archive.js +527 -0
  84. package/lib/protocol.d.ts +1 -0
  85. package/lib/protocol.js +1 -0
  86. package/lib/public.d.ts +4 -0
  87. package/lib/public.js +3 -0
  88. package/lib/query.d.ts +1 -0
  89. package/lib/query.js +1 -0
  90. package/lib/rpc.d.ts +203 -0
  91. package/lib/rpc.js +84 -0
  92. package/lib/runtime-descriptor.d.ts +3 -0
  93. package/lib/runtime-descriptor.js +79 -0
  94. package/lib/server.node.d.ts +1 -0
  95. package/lib/server.node.js +1 -0
  96. package/lib/startup-config.d.ts +2 -0
  97. package/lib/startup-config.js +19 -0
  98. package/lib/storage/bun.d.ts +6 -0
  99. package/lib/storage/bun.js +6 -0
  100. package/lib/storage/deno.d.ts +7 -0
  101. package/lib/storage/deno.js +7 -0
  102. package/lib/storage/incremental-storage.d.ts +25 -0
  103. package/lib/storage/incremental-storage.js +154 -0
  104. package/lib/storage/indexed-db-provider.d.ts +40 -0
  105. package/lib/storage/indexed-db-provider.js +259 -0
  106. package/lib/storage/indexed-db.d.ts +9 -0
  107. package/lib/storage/indexed-db.js +11 -0
  108. package/lib/storage/node.d.ts +10 -0
  109. package/lib/storage/node.js +13 -0
  110. package/lib/storage/opfs-pool.d.ts +31 -0
  111. package/lib/storage/opfs-pool.js +1271 -0
  112. package/lib/storage/opfs-provider.d.ts +4 -0
  113. package/lib/storage/opfs-provider.js +257 -0
  114. package/lib/storage/opfs.d.ts +8 -0
  115. package/lib/storage/opfs.js +10 -0
  116. package/lib/storage/restore-cleanup.d.ts +4 -0
  117. package/lib/storage/restore-cleanup.js +22 -0
  118. package/lib/storage/web-lock.d.ts +2 -0
  119. package/lib/storage/web-lock.js +64 -0
  120. package/lib/storage-provider.d.ts +47 -0
  121. package/lib/storage-provider.js +141 -0
  122. package/lib/storage-snapshot.d.ts +44 -0
  123. package/lib/storage-snapshot.js +274 -0
  124. package/lib/storage.d.ts +46 -0
  125. package/lib/storage.js +83 -0
  126. package/lib/tool-runtime.d.ts +43 -0
  127. package/lib/tool-runtime.js +93 -0
  128. package/lib/tool-worker-common.d.ts +48 -0
  129. package/lib/tool-worker-common.js +97 -0
  130. package/lib/tool-worker.d.ts +1 -0
  131. package/lib/tool-worker.js +10 -0
  132. package/lib/types.d.ts +230 -0
  133. package/lib/types.js +1 -0
  134. package/lib/wasix-runtime.d.ts +24 -0
  135. package/lib/wasix-runtime.js +186 -0
  136. package/lib/worker-client.d.ts +4 -0
  137. package/lib/worker-client.js +45 -0
  138. package/lib/worker-dispatch.d.ts +11 -0
  139. package/lib/worker-dispatch.js +174 -0
  140. package/lib/worker-entry.bun.d.ts +2 -0
  141. package/lib/worker-entry.bun.js +2 -0
  142. package/lib/worker-entry.d.ts +2 -0
  143. package/lib/worker-entry.deno.d.ts +2 -0
  144. package/lib/worker-entry.deno.js +2 -0
  145. package/lib/worker-entry.js +2 -0
  146. package/lib/worker-entry.node.d.ts +2 -0
  147. package/lib/worker-entry.node.js +2 -0
  148. package/lib/worker-node-client.d.ts +4 -0
  149. package/lib/worker-node-client.js +55 -0
  150. package/lib/worker-rpc.d.ts +36 -0
  151. package/lib/worker-rpc.js +422 -0
  152. package/lib/worker-transfer.d.ts +6 -0
  153. package/lib/worker-transfer.js +11 -0
  154. package/lib/worker.d.ts +1 -0
  155. package/lib/worker.js +21 -0
  156. package/lib/zstd.d.ts +4 -0
  157. package/lib/zstd.js +12 -0
  158. package/node_modules/@oliphaunt/js-core/README.md +7 -0
  159. package/node_modules/@oliphaunt/js-core/dist/commonjs/protocol.d.ts +1 -0
  160. package/node_modules/@oliphaunt/js-core/dist/commonjs/protocol.js +22 -0
  161. package/node_modules/@oliphaunt/js-core/dist/commonjs/query.d.ts +255 -0
  162. package/node_modules/@oliphaunt/js-core/dist/commonjs/query.js +2068 -0
  163. package/node_modules/@oliphaunt/js-core/dist/module/package.json +3 -0
  164. package/node_modules/@oliphaunt/js-core/dist/module/protocol.d.ts +1 -0
  165. package/node_modules/@oliphaunt/js-core/dist/module/protocol.js +19 -0
  166. package/node_modules/@oliphaunt/js-core/dist/module/query.d.ts +255 -0
  167. package/node_modules/@oliphaunt/js-core/dist/module/query.js +2039 -0
  168. package/node_modules/@oliphaunt/js-core/package.json +21 -0
  169. package/package.json +122 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ /// <reference lib="webworker" />
2
+ import * as host from './host/index.mjs';
3
+ import { createWasixToolWorkerDispatcher, toolWorkerResponseTransfers, } from './tool-worker-common.js';
4
+ const scope = globalThis;
5
+ const dispatch = createWasixToolWorkerDispatcher(host);
6
+ scope.addEventListener('message', (event) => {
7
+ void dispatch(event.data).then((response) => {
8
+ scope.postMessage(response, toolWorkerResponseTransfers(response));
9
+ });
10
+ });
package/lib/types.d.ts ADDED
@@ -0,0 +1,230 @@
1
+ import type { CommandResult, DescribeResult, ExecResult, InferQueryRow, ParameterOptions, QueryOptions, QueryParam, QueryResult, RawQueryResult } from './query.js';
2
+ import type { PersistentWasixStorage, WasixStorage } from './storage.js';
3
+ type QueryReadOptions = Omit<QueryOptions, 'encoders'>;
4
+ export type BinaryInput = ArrayBuffer | ArrayBufferView | Uint8Array | ReadonlyArray<number>;
5
+ /** A synchronous, serial raw-protocol consumer used as the backpressure acknowledgement. */
6
+ export type ProtocolChunkCallback = (chunk: Uint8Array) => undefined;
7
+ /** A host-neutral asset reference accepted by the portable WASIX carrier contract. */
8
+ export type WasixAssetSource = string | URL | ArrayBuffer | Uint8Array;
9
+ /** One exact archive carried by the portable WASIX runtime package. */
10
+ export type WasixRuntimeArchive = Readonly<{
11
+ /** Canonical path recorded by the generated runtime manifest. */
12
+ archive: string;
13
+ sha256: string;
14
+ size: number;
15
+ source: WasixAssetSource;
16
+ }>;
17
+ /** The canonical generated manifest carried alongside the runtime archives. */
18
+ export type WasixRuntimeManifest = Readonly<{
19
+ sha256: string;
20
+ size: number;
21
+ source: WasixAssetSource;
22
+ }>;
23
+ /**
24
+ * A package-authored runtime identity. The default value comes from
25
+ * `@oliphaunt/liboliphaunt-wasix`; callers normally never handle it directly.
26
+ */
27
+ export type WasixRuntimeDescriptor = Readonly<{
28
+ schema: 'oliphaunt-wasix-runtime-v2';
29
+ runtime: 'wasix';
30
+ product: 'liboliphaunt-wasix';
31
+ version: string;
32
+ runtimeArchive: WasixRuntimeArchive;
33
+ standardSeedArchive: WasixRuntimeArchive;
34
+ standardSeedManifest: WasixRuntimeManifest;
35
+ manifest: WasixRuntimeManifest;
36
+ }>;
37
+ /** Explicit optional ICU closure authored by `@oliphaunt/wasix-icu`. */
38
+ export type WasixIcuDescriptor = Readonly<{
39
+ schema: 'oliphaunt-wasix-icu-v1';
40
+ runtime: 'wasix';
41
+ product: 'oliphaunt-icu';
42
+ version: string;
43
+ compatibility: Readonly<{
44
+ runtimeProduct: 'liboliphaunt-wasix';
45
+ runtimeVersion: string;
46
+ postgresMajor: '18';
47
+ physicalFormat: 'wasix-pg18-v1';
48
+ compatibilityKey: 'wasix-pg18-datum32-v1';
49
+ dataVersion: '76.1';
50
+ dataForm: 'files-le';
51
+ dataTreeSha256: string;
52
+ }>;
53
+ dataArchive: WasixRuntimeArchive;
54
+ clusterSeedArchive: WasixRuntimeArchive;
55
+ clusterSeedManifest: WasixRuntimeManifest;
56
+ }>;
57
+ export type WasixExtensionCarrier = Readonly<{
58
+ /** Owning Oliphaunt release product, not the PostgreSQL SQL name. */
59
+ product: string;
60
+ /** Oliphaunt product version; upstream provenance stays release/evidence metadata. */
61
+ version: string;
62
+ sqlName: string;
63
+ /** Exact canonical manifest archive key, for example `extensions/pgtap.tar.zst`. */
64
+ archive: string;
65
+ sha256: string;
66
+ size: number;
67
+ /** Portable archive URL or bytes. The same descriptor can be hosted by Node or a browser. */
68
+ source: WasixAssetSource;
69
+ /** Exact install contract owned by this independently versioned carrier. */
70
+ install: WasixExtensionInstall;
71
+ }>;
72
+ export type WasixExtensionCompatibility = Readonly<{
73
+ extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1';
74
+ postgresMajor: string;
75
+ wasixRuntimeProduct: 'liboliphaunt-wasix';
76
+ wasixRuntimeVersion: string;
77
+ }>;
78
+ export type WasixExtensionInstall = Readonly<{
79
+ schema: 'oliphaunt-wasix-extension-install-v1';
80
+ name: string;
81
+ nativeModule: string | null;
82
+ nativeModules: readonly WasixExtensionNativeModule[];
83
+ dependencies: readonly string[];
84
+ coreExportsRequired: readonly string[];
85
+ loadOrder: readonly string[];
86
+ lifecycle: WasixExtensionLifecycle;
87
+ installedFiles: readonly string[];
88
+ unresolvedImports: readonly WasixExtensionImport[];
89
+ }>;
90
+ export type WasixExtensionImport = Readonly<{
91
+ module: string;
92
+ name: string;
93
+ kind: string;
94
+ }>;
95
+ export type WasixExtensionNativeModule = Readonly<{
96
+ name: string;
97
+ path: string;
98
+ sha256: string;
99
+ moduleSha256: string;
100
+ size: number;
101
+ }>;
102
+ export type WasixExtensionDescriptorInput = Readonly<{
103
+ schema: 'oliphaunt-wasix-extension-v1';
104
+ runtime: 'wasix';
105
+ /** Product and version of the root carrier selected by `sqlName`. */
106
+ product: string;
107
+ version: string;
108
+ /** Exact WASIX runtime identity against which this descriptor was qualified. */
109
+ compatibility: WasixExtensionCompatibility;
110
+ sqlName: string;
111
+ /** Root carrier plus any extension carrier dependencies required by this import. */
112
+ carriers: readonly WasixExtensionCarrier[];
113
+ }>;
114
+ /**
115
+ * A package-authored, runtime-validated WASIX extension import. Applications
116
+ * obtain these from extension packages instead of constructing SQL strings.
117
+ * The schema and runtime literals discriminate it structurally, so generated
118
+ * carrier packages do not need a dependency on this binding.
119
+ */
120
+ export type WasixExtensionDescriptor = WasixExtensionDescriptorInput;
121
+ /** Lifecycle fields owned by an independently versioned extension carrier. */
122
+ export type WasixExtensionLifecycle = {
123
+ createExtension: boolean;
124
+ createSchema: string | null;
125
+ loadSql: readonly string[];
126
+ postCreateSql: readonly string[];
127
+ startupConfig: readonly string[];
128
+ preloadRequired: boolean;
129
+ restartRequired: boolean;
130
+ sharedMemoryRequired: boolean;
131
+ };
132
+ /** Host-relevant subset of the generated liboliphaunt WASIX asset manifest. */
133
+ export type WasixAssetManifest = {
134
+ 'format-version': 2;
135
+ 'source-fingerprint': string;
136
+ runtime: {
137
+ archive: string;
138
+ sha256: string;
139
+ /** Present when the canonical producer records the outer archive size. */
140
+ size?: number;
141
+ 'module-sha256': string;
142
+ 'postgres-version': string;
143
+ link: {
144
+ exports: readonly {
145
+ name: string;
146
+ kind: string;
147
+ }[];
148
+ };
149
+ };
150
+ 'runtime-support': readonly {
151
+ name: string;
152
+ path: string;
153
+ sha256: string;
154
+ }[];
155
+ 'cluster-seeds': Readonly<Record<'standard' | 'icu', {
156
+ 'artifact-role': 'cluster-seed-standard' | 'cluster-seed-icu';
157
+ 'catalog-profile': 'standard' | 'icu';
158
+ archive: string;
159
+ manifest: string;
160
+ sha256: string;
161
+ size: number;
162
+ 'runtime-module-sha256': string;
163
+ 'source-fingerprint': string;
164
+ 'postgres-version': string;
165
+ 'physical-format': 'wasix-pg18-v1';
166
+ 'compatibility-key': 'wasix-pg18-datum32-v1';
167
+ 'icu-data-tree-sha256'?: string;
168
+ }>>;
169
+ /** The core runtime carrier is intentionally extension-free. */
170
+ extensions: readonly [];
171
+ };
172
+ export type OpenConfig = {
173
+ /** Existing PostgreSQL role selected after the fixed superuser bootstrap. */
174
+ username?: string;
175
+ database?: string;
176
+ /** PostgreSQL `-c name=value` settings applied before the database opens. */
177
+ startupGUCs?: Readonly<Record<string, string>>;
178
+ /** Optional ICU data plus the matching PostgreSQL ICU-catalog cluster seed. */
179
+ icu?: WasixIcuDescriptor;
180
+ /** Selectively imported WASIX carriers. SQL strings are intentionally not accepted. */
181
+ extensions?: readonly WasixExtensionDescriptor[];
182
+ /** Fresh memory by default, or an explicitly imported host storage adapter. */
183
+ storage?: WasixStorage;
184
+ };
185
+ export type OliphauntDatabase = {
186
+ /**
187
+ * True after the terminal close attempt settles, including when teardown
188
+ * rejects, or as soon as a package-owned isolated host terminates unexpectedly.
189
+ */
190
+ readonly closed: boolean;
191
+ execute(sql: string, parameters?: ReadonlyArray<QueryParam>, options?: ParameterOptions): Promise<CommandResult>;
192
+ query<Row = never, const Options extends QueryOptions = {}>(sql: string, parameters?: ReadonlyArray<QueryParam>, options?: Options & QueryOptions): Promise<QueryResult<InferQueryRow<Options, Row>>>;
193
+ queryRaw(sql: string, parameters?: ReadonlyArray<QueryParam>, options?: ParameterOptions): Promise<RawQueryResult>;
194
+ exec<Row = never, const Options extends QueryReadOptions = {}>(sql: string, options?: Options & QueryReadOptions): Promise<ExecResult<InferQueryRow<Options, Row>>>;
195
+ describe(sql: string, parameterTypeOids?: ReadonlyArray<number>): Promise<DescribeResult>;
196
+ execProtocolRaw(input: BinaryInput): Promise<Uint8Array>;
197
+ execProtocolRawStream(input: BinaryInput, onChunk: ProtocolChunkCallback): Promise<void>;
198
+ /** Create a session-preserving PostgreSQL online physical backup. */
199
+ backup(): Promise<Uint8Array>;
200
+ /**
201
+ * Own the session for one callback. Use callback return/throw or rollback()
202
+ * for lifecycle; manual BEGIN/START/COMMIT/END/ABORT/PREPARE TRANSACTION and
203
+ * AND CHAIN are unsupported. SAVEPOINT and ROLLBACK TO are allowed.
204
+ */
205
+ transaction<T>(body: (transaction: OliphauntTransaction) => Promise<T> | T): Promise<T>;
206
+ /**
207
+ * Stop admitting work and perform one terminal teardown attempt.
208
+ * Concurrent and later calls return the same promise. A rejection reports
209
+ * cleanup failure; it does not make the handle reusable. Calling from an
210
+ * active transaction callback rejects before teardown begins; close the
211
+ * database after that callback settles.
212
+ */
213
+ close(): Promise<void>;
214
+ [Symbol.asyncDispose](): Promise<void>;
215
+ };
216
+ /** A database session pinned to one callback-scoped PostgreSQL transaction. */
217
+ export type OliphauntTransaction = {
218
+ readonly closed: boolean;
219
+ execute(sql: string, parameters?: ReadonlyArray<QueryParam>, options?: ParameterOptions): Promise<CommandResult>;
220
+ query<Row = never, const Options extends QueryOptions = {}>(sql: string, parameters?: ReadonlyArray<QueryParam>, options?: Options & QueryOptions): Promise<QueryResult<InferQueryRow<Options, Row>>>;
221
+ queryRaw(sql: string, parameters?: ReadonlyArray<QueryParam>, options?: ParameterOptions): Promise<RawQueryResult>;
222
+ exec<Row = never, const Options extends QueryReadOptions = {}>(sql: string, options?: Options & QueryReadOptions): Promise<ExecResult<InferQueryRow<Options, Row>>>;
223
+ describe(sql: string, parameterTypeOids?: ReadonlyArray<number>): Promise<DescribeResult>;
224
+ rollback(): Promise<void>;
225
+ };
226
+ export type OliphauntClient = {
227
+ open(config?: OpenConfig): Promise<OliphauntDatabase>;
228
+ restore(storage: PersistentWasixStorage, bytes: BinaryInput): Promise<void>;
229
+ };
230
+ export {};
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { WasixDirectoryMount, WasixRuntimeLayout } from './archive.js';
2
+ import type { Directory } from './host/index.mjs';
3
+ import type { SerializedOpenOptions } from './rpc.js';
4
+ /** @internal Verified-module compilation cache shared by direct opens in one JS realm. */
5
+ export declare function compileWasixModule(module: Uint8Array, sha256: string): Promise<WebAssembly.Module>;
6
+ /** @internal Materialize the exact runtime mounts shared by both execution surfaces. */
7
+ export declare function materializeWasixMounts(DirectoryConstructor: typeof Directory, layout: WasixRuntimeLayout, pgdata: WasixDirectoryMount | undefined, createPgdataDirectory?: (DirectoryConstructor: typeof Directory) => Promise<Directory>): Promise<{
8
+ mounts: Record<string, Directory>;
9
+ baseDirectory: Directory;
10
+ }>;
11
+ /** @internal Materialize runtime support mounts for frontend tools. */
12
+ export declare function materializeWasixSupportMounts(DirectoryConstructor: typeof Directory, layout: Pick<WasixRuntimeLayout, 'mounts'>): Promise<Record<string, Directory>>;
13
+ /** @internal PostgreSQL argv shared by both execution surfaces. */
14
+ export declare function wasixPostgresArgs(options: SerializedOpenOptions): string[];
15
+ /** @internal PostgreSQL environment shared by both execution surfaces. */
16
+ export declare function wasixPostgresEnvironment(options: SerializedOpenOptions, icuEnabled?: boolean): Record<string, string>;
17
+ /** @internal Normalize lifecycle diagnostics without discarding structured primary errors. */
18
+ export declare function describeError(error: unknown): string;
19
+ /** @internal Preserve a structured primary while attaching cleanup diagnostics. */
20
+ export declare function composeLifecycleFailure(primary: Error, label: string, secondary: unknown): Error;
21
+ /** @internal Apply caller role after the direct bridge reaches ReadyForQuery. */
22
+ export declare function configureWasixDatabase(options: SerializedOpenOptions, exec: (input: Uint8Array) => Promise<Uint8Array>): Promise<void>;
23
+ /** @internal Restore the configured application role after DISCARD ALL. */
24
+ export declare function configureWasixRole(username: string, exec: (input: Uint8Array) => Promise<Uint8Array>): Promise<void>;
@@ -0,0 +1,186 @@
1
+ import { WasixStorageError } from './errors.js';
2
+ import { simpleQuery } from './protocol.js';
3
+ import { assertSuccessfulQueryResponse, PostgresError } from './query.js';
4
+ import { normalizeWasixStartupGUCs } from './startup-config.js';
5
+ let compiledModuleCache;
6
+ /** @internal Verified-module compilation cache shared by direct opens in one JS realm. */
7
+ export function compileWasixModule(module, sha256) {
8
+ if (compiledModuleCache?.sha256 !== sha256) {
9
+ const source = module.buffer instanceof ArrayBuffer
10
+ ? module
11
+ : Uint8Array.from(module);
12
+ const compiled = WebAssembly.compile(source);
13
+ compiledModuleCache = { sha256, module: compiled };
14
+ void compiled.catch(() => {
15
+ if (compiledModuleCache?.module === compiled) {
16
+ compiledModuleCache = undefined;
17
+ }
18
+ });
19
+ }
20
+ return compiledModuleCache.module;
21
+ }
22
+ /** @internal Materialize the exact runtime mounts shared by both execution surfaces. */
23
+ export async function materializeWasixMounts(DirectoryConstructor, layout, pgdata, createPgdataDirectory) {
24
+ const mounts = await materializeMountMap(DirectoryConstructor, layout);
25
+ let baseDirectory;
26
+ if (createPgdataDirectory !== undefined) {
27
+ baseDirectory = await createPgdataDirectory(DirectoryConstructor);
28
+ }
29
+ else {
30
+ if (pgdata === undefined) {
31
+ throw new Error('portable WASIX storage did not provide a PGDATA mount');
32
+ }
33
+ baseDirectory = await materializeDirectory(DirectoryConstructor, pgdata);
34
+ }
35
+ mounts['/base'] = baseDirectory;
36
+ return { mounts, baseDirectory };
37
+ }
38
+ /** @internal Materialize runtime support mounts for frontend tools. */
39
+ export function materializeWasixSupportMounts(DirectoryConstructor, layout) {
40
+ return materializeMountMap(DirectoryConstructor, layout);
41
+ }
42
+ async function materializeMountMap(DirectoryConstructor, layout) {
43
+ const mounts = {};
44
+ for (const [mountPath, contents] of Object.entries(layout.mounts)) {
45
+ mounts[mountPath] = await materializeDirectory(DirectoryConstructor, contents);
46
+ }
47
+ return mounts;
48
+ }
49
+ async function materializeDirectory(DirectoryConstructor, contents) {
50
+ const directory = new DirectoryConstructor(contents.files);
51
+ const existing = directoriesImpliedByFiles(Object.keys(contents.files));
52
+ const explicit = [...new Set(contents.directories)].sort(compareDirectoryDepth);
53
+ for (const path of explicit) {
54
+ if (existing.has(path)) {
55
+ continue;
56
+ }
57
+ await directory.createDir(path);
58
+ existing.add(path);
59
+ }
60
+ return directory;
61
+ }
62
+ function directoriesImpliedByFiles(paths) {
63
+ const directories = new Set();
64
+ for (const path of paths) {
65
+ const segments = path.split('/');
66
+ for (let index = 1; index < segments.length; index += 1) {
67
+ directories.add(segments.slice(0, index).join('/'));
68
+ }
69
+ }
70
+ return directories;
71
+ }
72
+ function compareDirectoryDepth(left, right) {
73
+ return left.split('/').length - right.split('/').length || left.localeCompare(right);
74
+ }
75
+ /** @internal PostgreSQL argv shared by both execution surfaces. */
76
+ export function wasixPostgresArgs(options) {
77
+ const args = ['--single'];
78
+ if (options.storage.kind === 'memory')
79
+ args.push('-F');
80
+ args.push('-O', '-j');
81
+ const startupGUCs = normalizeWasixStartupGUCs(options.startupGUCs);
82
+ for (const [configuredName, configuredValue] of Object.entries(startupGUCs)) {
83
+ const managed = Object.entries(SINGLE_BACKEND_GUCS).find(([name]) => name === configuredName.toLowerCase());
84
+ if (managed === undefined)
85
+ continue;
86
+ const [, requiredValue] = managed;
87
+ if (configuredValue !== requiredValue) {
88
+ throw new Error(`PostgreSQL startup GUC ${JSON.stringify(configuredName)} is managed by @oliphaunt/wasix-ts and must remain ${JSON.stringify(requiredValue)}`);
89
+ }
90
+ delete startupGUCs[configuredName];
91
+ }
92
+ for (const [name, value] of Object.entries({
93
+ search_path: 'public',
94
+ log_checkpoints: 'false',
95
+ wal_buffers: '4MB',
96
+ min_wal_size: '80MB',
97
+ shared_buffers: '128MB',
98
+ ...SINGLE_BACKEND_GUCS,
99
+ ...startupGUCs,
100
+ })) {
101
+ args.push('-c', `${name}=${value}`);
102
+ }
103
+ // Keep a database name that begins with `-` out of PostgreSQL's option
104
+ // parser. PostgreSQL's bundled getopt honors this standard delimiter.
105
+ args.push('-D', '/base', '--', options.database);
106
+ return args;
107
+ }
108
+ const SINGLE_BACKEND_GUCS = {
109
+ exit_on_error: 'false',
110
+ max_wal_senders: '0',
111
+ max_worker_processes: '0',
112
+ max_parallel_workers: '0',
113
+ max_parallel_workers_per_gather: '0',
114
+ max_parallel_maintenance_workers: '0',
115
+ io_method: 'sync',
116
+ };
117
+ /** @internal PostgreSQL environment shared by both execution surfaces. */
118
+ export function wasixPostgresEnvironment(options, icuEnabled = false) {
119
+ return {
120
+ PREFIX: '/',
121
+ PGDATA: '/base',
122
+ PGUSER: options.username,
123
+ PGDATABASE: options.database,
124
+ MODE: 'REACT',
125
+ REPL: 'N',
126
+ PGSYSCONFDIR: '/base',
127
+ PGCLIENTENCODING: 'UTF8',
128
+ HOME: '/home/postgres',
129
+ USER: options.username,
130
+ LOGNAME: options.username,
131
+ PATH: '/bin',
132
+ LC_CTYPE: 'C.UTF-8',
133
+ TZ: 'UTC',
134
+ PGTZ: 'UTC',
135
+ PG_COLOR: 'never',
136
+ PROJ_DATA: '/share/proj',
137
+ ...(icuEnabled ? { ICU_DATA: '/share/icu' } : {}),
138
+ // The canonical guest specializes backend atomics for a one-backend
139
+ // WebAssembly instance. Every host placement must enforce that invariant.
140
+ OLIPHAUNT_WASIX_SINGLE_BACKEND: '1',
141
+ };
142
+ }
143
+ /** @internal Normalize lifecycle diagnostics without discarding structured primary errors. */
144
+ export function describeError(error) {
145
+ if (!(error instanceof Error)) {
146
+ return String(error);
147
+ }
148
+ const detailed = error.detailedMessage;
149
+ return typeof detailed === 'string' && detailed.length > 0 && detailed !== error.message
150
+ ? `${error.message}: ${detailed}`
151
+ : error.message;
152
+ }
153
+ /** @internal Preserve a structured primary while attaching cleanup diagnostics. */
154
+ export function composeLifecycleFailure(primary, label, secondary) {
155
+ const message = `${primary.message}; ${label}: ${describeError(secondary)}`;
156
+ const cause = new AggregateError([primary, secondary], `${label} while handling ${primary.name || 'Error'}`);
157
+ if (primary instanceof PostgresError) {
158
+ const composed = new PostgresError(primary.fields.map((field) => ({ ...field })), [...primary.notices]);
159
+ Object.defineProperty(composed, 'cause', {
160
+ configurable: true,
161
+ value: cause,
162
+ });
163
+ return composed;
164
+ }
165
+ if (primary instanceof WasixStorageError) {
166
+ return new WasixStorageError(message, {
167
+ code: primary.code,
168
+ commitState: primary.commitState,
169
+ cause,
170
+ });
171
+ }
172
+ return new Error(message, { cause });
173
+ }
174
+ /** @internal Apply caller role after the direct bridge reaches ReadyForQuery. */
175
+ export async function configureWasixDatabase(options, exec) {
176
+ // Extension selection owns files and startup configuration only. Database-
177
+ // local CREATE EXTENSION/LOAD/schema/migration SQL remains application-owned.
178
+ await configureWasixRole(options.username, exec);
179
+ }
180
+ /** @internal Restore the configured application role after DISCARD ALL. */
181
+ export async function configureWasixRole(username, exec) {
182
+ if (username === 'postgres')
183
+ return;
184
+ const quoted = username.replaceAll('"', '""');
185
+ assertSuccessfulQueryResponse(await exec(simpleQuery(`SET ROLE "${quoted}"`)));
186
+ }
@@ -0,0 +1,4 @@
1
+ import type { OliphauntClient, OliphauntDatabase, OpenConfig } from './types.js';
2
+ /** Open PostgreSQL in a package-owned browser Worker. */
3
+ export declare function openWasix(config?: OpenConfig): Promise<OliphauntDatabase>;
4
+ export declare const Oliphaunt: OliphauntClient;
@@ -0,0 +1,45 @@
1
+ import { serializeOpenConfig } from './client-common.js';
2
+ import { openWasixWithWorker, restoreWasixWithWorker } from './worker-rpc.js';
3
+ /** Open PostgreSQL in a package-owned browser Worker. */
4
+ export async function openWasix(config = {}) {
5
+ const openOptions = serializeOpenConfig(config);
6
+ assertBrowserWorkerEnvironment();
7
+ return openWasixWithWorker(createBrowserWorker, openOptions);
8
+ }
9
+ async function restoreBrowserWasix(storage, bytes) {
10
+ assertBrowserWorkerEnvironment();
11
+ return restoreWasixWithWorker(createBrowserWorker, storage, bytes);
12
+ }
13
+ function assertBrowserWorkerEnvironment() {
14
+ if (globalThis.crossOriginIsolated !== true) {
15
+ throw new Error('@oliphaunt/wasix-ts/worker requires COOP: same-origin and COEP: require-corp response headers');
16
+ }
17
+ if (typeof Worker === 'undefined') {
18
+ throw new Error('@oliphaunt/wasix-ts/worker requires a browser with Web Workers');
19
+ }
20
+ }
21
+ export const Oliphaunt = {
22
+ open: openWasix,
23
+ restore: restoreBrowserWasix,
24
+ };
25
+ function createBrowserWorker() {
26
+ const worker = new Worker(new URL('./worker.js', import.meta.url), {
27
+ type: 'module',
28
+ name: 'oliphaunt-wasix',
29
+ });
30
+ return {
31
+ postMessage: (message, transfer) => worker.postMessage(message, [...transfer]),
32
+ terminate: () => worker.terminate(),
33
+ onMessage: (listener) => {
34
+ worker.addEventListener('message', (event) => listener(event.data));
35
+ },
36
+ onFatal: (listener) => {
37
+ worker.addEventListener('error', (event) => {
38
+ listener(new Error(event.message || 'Oliphaunt WASIX browser worker crashed'));
39
+ });
40
+ worker.addEventListener('messageerror', () => {
41
+ listener(new Error('Oliphaunt WASIX browser worker returned an unreadable message'));
42
+ });
43
+ },
44
+ };
45
+ }
@@ -0,0 +1,11 @@
1
+ import { type WasixDatabaseSession } from './database.js';
2
+ import { type SerializedOpenOptions, type WorkerRequest, type WorkerResponse } from './rpc.js';
3
+ export type WorkerResponder = (response: WorkerResponse, transfer?: readonly ArrayBuffer[]) => void;
4
+ export type WorkerSessionOpener = (options: SerializedOpenOptions) => Promise<WasixDatabaseSession>;
5
+ export type WorkerStorageRestorer = (storage: SerializedOpenOptions['storage'], bytes: Uint8Array) => Promise<void>;
6
+ export type WorkerDispatcherLifecycle = Readonly<{
7
+ /** Called only after close has settled and its response has been posted. */
8
+ onQuiescentClose?(): void;
9
+ }>;
10
+ /** @internal One request state machine shared by browser and server worker realms. */
11
+ export declare function createWorkerSessionDispatcher(openSession: WorkerSessionOpener, respond: WorkerResponder, restore?: WorkerStorageRestorer, lifecycle?: WorkerDispatcherLifecycle): (request: WorkerRequest) => Promise<void>;