hyperdb-wasm 0.0.26284-dev.wasm.gf1f9d795 → 0.0.26298-dev.wasm.gd63c7938

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/dist/api.d.ts CHANGED
@@ -7,12 +7,20 @@ export interface HyperDBClient {
7
7
  ready(): Promise<void>;
8
8
  connect(): Promise<WasmResult>;
9
9
  disconnect(connection: number): Promise<WasmResult>;
10
+ createDatabase(databaseName: string, persistent: boolean): Promise<WasmResult>;
11
+ openDatabase(databaseName: string): Promise<WasmResult>;
12
+ checkpointDatabase(databaseName: string): Promise<WasmResult>;
13
+ dropDatabase(databaseName: string): Promise<WasmResult>;
14
+ attachDatabase(connection: number, databaseName: string, alias: string): Promise<WasmResult>;
15
+ detachDatabase(connection: number, alias: string): Promise<WasmResult>;
10
16
  startQuery(connection: number, sql: string): Promise<WasmResult>;
11
- appendArrowIPC(connection: number, chunk: Uint8Array): Promise<WasmResult>;
12
- finishArrowIPC(connection: number, name: string, schema: string | null, create: boolean): Promise<WasmResult>;
17
+ insertArrowIPCFromPath(connection: number, path: string, name: string, schema: string | null, create: boolean, internal?: boolean): Promise<WasmResult>;
18
+ createTemporaryFile(bytes: Uint8Array): Promise<WasmResult>;
19
+ removeFile(path: string): Promise<WasmResult>;
13
20
  pollQuery(query: number): Promise<WasmResult>;
14
21
  cancelQuery(query: number): Promise<WasmResult>;
15
22
  releaseQuery(query: number): Promise<WasmResult>;
23
+ shutdown(): Promise<WasmResult>;
16
24
  terminate(): Promise<void>;
17
25
  }
18
26
  export interface ArrowInsertOptions {
@@ -20,17 +28,26 @@ export interface ArrowInsertOptions {
20
28
  readonly schema?: string;
21
29
  readonly create?: boolean;
22
30
  }
31
+ export interface DatabaseCreateOptions {
32
+ readonly storage?: 'memory' | 'persistent';
33
+ }
23
34
  export declare class HyperDB {
24
35
  private readonly client;
25
36
  private terminated;
26
37
  private termination;
38
+ private activeDatabaseOperations;
27
39
  private readonly connections;
28
40
  constructor(client: HyperDBClient);
29
41
  static create(options?: BrowserClientOptions): Promise<HyperDB>;
30
42
  ready(): Promise<void>;
31
43
  connect(): Promise<HyperDBConnection>;
44
+ createDatabase(databaseName: string, options?: DatabaseCreateOptions): Promise<void>;
45
+ openDatabase(databaseName: string): Promise<void>;
46
+ checkpointDatabase(databaseName: string): Promise<void>;
47
+ dropDatabase(databaseName: string): Promise<void>;
32
48
  terminate(): Promise<void>;
33
49
  private ensureRunning;
50
+ private runDatabaseOperation;
34
51
  }
35
52
  export declare class HyperDBConnection {
36
53
  private readonly client;
@@ -38,11 +55,11 @@ export declare class HyperDBConnection {
38
55
  private readonly onClose;
39
56
  private closed;
40
57
  private active;
41
- private arrowInsertOptions;
42
- private appendingArrow;
43
58
  private closing;
44
59
  constructor(client: HyperDBClient, connection: number, onClose?: () => void);
45
60
  close(): Promise<void>;
61
+ attachDatabase(databaseName: string, alias?: string): Promise<void>;
62
+ detachDatabase(alias: string): Promise<void>;
46
63
  sendIPC(sql: string): AsyncIterable<Uint8Array>;
47
64
  queryIPC(sql: string): Promise<Uint8Array>;
48
65
  send<T extends TypeMap = {
@@ -52,8 +69,8 @@ export declare class HyperDBConnection {
52
69
  [key: string]: DataType;
53
70
  }>(sql: string): Promise<Table<T>>;
54
71
  insertArrowTable(table: Table, options: ArrowInsertOptions): Promise<void>;
55
- insertArrowFromIPCStream(chunk: Uint8Array, options: ArrowInsertOptions): Promise<void>;
56
- finishArrowIPCStream(options?: ArrowInsertOptions): Promise<void>;
72
+ insertArrowIPCFromPath(path: string, options: ArrowInsertOptions): Promise<void>;
73
+ private insertArrowIPCFromPathInternal;
57
74
  private ensureAvailable;
58
75
  private release;
59
76
  closeForTermination(): Promise<void>;
package/dist/browser.js CHANGED
@@ -95,15 +95,39 @@ var init_client = __esm({
95
95
  disconnect(connection) {
96
96
  return this.request({ id: this.nextId++, type: "disconnect", connection });
97
97
  }
98
+ createDatabase(databaseName, persistent) {
99
+ return this.request({ id: this.nextId++, type: "createDatabase", databaseName, persistent });
100
+ }
101
+ openDatabase(databaseName) {
102
+ return this.request({ id: this.nextId++, type: "openDatabase", databaseName });
103
+ }
104
+ checkpointDatabase(databaseName) {
105
+ return this.request({ id: this.nextId++, type: "checkpointDatabase", databaseName });
106
+ }
107
+ dropDatabase(databaseName) {
108
+ return this.request({ id: this.nextId++, type: "dropDatabase", databaseName });
109
+ }
110
+ attachDatabase(connection, databaseName, alias) {
111
+ return this.request({ id: this.nextId++, type: "attachDatabase", connection, databaseName, alias });
112
+ }
113
+ detachDatabase(connection, alias) {
114
+ return this.request({ id: this.nextId++, type: "detachDatabase", connection, alias });
115
+ }
116
+ shutdown() {
117
+ return this.request({ id: this.nextId++, type: "shutdown" });
118
+ }
98
119
  startQuery(connection, sql) {
99
120
  return this.request({ id: this.nextId++, type: "startQuery", connection, sql });
100
121
  }
101
- appendArrowIPC(connection, chunk) {
102
- const payload = chunk.slice();
103
- return this.request({ id: this.nextId++, type: "appendArrowIPC", connection, chunk: payload }, [payload.buffer]);
122
+ insertArrowIPCFromPath(connection, path, name, schema, create, internal = false) {
123
+ return this.request({ id: this.nextId++, type: "insertArrowIPCFromPath", connection, path, name, schema, create, internal });
104
124
  }
105
- finishArrowIPC(connection, name, schema, create) {
106
- return this.request({ id: this.nextId++, type: "finishArrowIPC", connection, name, schema, create });
125
+ createTemporaryFile(bytes) {
126
+ const payload = bytes.slice();
127
+ return this.request({ id: this.nextId++, type: "createTemporaryFile", bytes: payload }, [payload.buffer]);
128
+ }
129
+ removeFile(path) {
130
+ return this.request({ id: this.nextId++, type: "removeFile", path });
107
131
  }
108
132
  pollQuery(query) {
109
133
  return this.request({ id: this.nextId++, type: "pollQuery", query });
@@ -12054,8 +12078,13 @@ function normalizeArrowInsertOptions(options) {
12054
12078
  if (!options.name) throw new Error("Arrow insert table name must not be empty");
12055
12079
  return { name: options.name, schema: options.schema ?? null, create: options.create ?? true };
12056
12080
  }
12057
- function equalArrowInsertOptions(left, right) {
12058
- return left.name === right.name && left.schema === right.schema && left.create === right.create;
12081
+ function validateDatabaseName(databaseName) {
12082
+ if (!databaseName) throw new Error("Database name must not be empty");
12083
+ if (databaseName.includes("\0")) throw new Error("Database name must not contain NUL");
12084
+ }
12085
+ function validateDatabaseAlias(alias) {
12086
+ if (!alias) throw new Error("Database alias must not be empty");
12087
+ if (alias.includes("\0")) throw new Error("Database alias must not contain NUL");
12059
12088
  }
12060
12089
  function materializeDictionaryColumns(table) {
12061
12090
  const dictionaryColumns = table.schema.fields.map((field, index) => DataType.isDictionary(field.type) ? index : -1).filter((index) => index !== -1);
@@ -12097,6 +12126,7 @@ var HyperDB = class _HyperDB {
12097
12126
  client;
12098
12127
  terminated = false;
12099
12128
  termination;
12129
+ activeDatabaseOperations = 0;
12100
12130
  connections = /* @__PURE__ */ new Set();
12101
12131
  static async create(options = {}) {
12102
12132
  const { createBrowserClient: createBrowserClient2 } = await Promise.resolve().then(() => (init_browser(), browser_exports));
@@ -12115,8 +12145,36 @@ var HyperDB = class _HyperDB {
12115
12145
  this.connections.add(result);
12116
12146
  return result;
12117
12147
  }
12148
+ async createDatabase(databaseName, options = {}) {
12149
+ validateDatabaseName(databaseName);
12150
+ if (options.storage !== void 0 && options.storage !== "memory" && options.storage !== "persistent") {
12151
+ throw new Error(`Unsupported database storage: ${String(options.storage)}`);
12152
+ }
12153
+ await this.runDatabaseOperation(async () => {
12154
+ expectOk(await this.client.createDatabase(databaseName, options.storage === "persistent"), "create database");
12155
+ });
12156
+ }
12157
+ async openDatabase(databaseName) {
12158
+ validateDatabaseName(databaseName);
12159
+ await this.runDatabaseOperation(async () => {
12160
+ expectOk(await this.client.openDatabase(databaseName), "open database");
12161
+ });
12162
+ }
12163
+ async checkpointDatabase(databaseName) {
12164
+ validateDatabaseName(databaseName);
12165
+ await this.runDatabaseOperation(async () => {
12166
+ expectOk(await this.client.checkpointDatabase(databaseName), "checkpoint database");
12167
+ });
12168
+ }
12169
+ async dropDatabase(databaseName) {
12170
+ validateDatabaseName(databaseName);
12171
+ await this.runDatabaseOperation(async () => {
12172
+ expectOk(await this.client.dropDatabase(databaseName), "drop database");
12173
+ });
12174
+ }
12118
12175
  async terminate() {
12119
12176
  if (this.terminated) return;
12177
+ if (this.activeDatabaseOperations !== 0) throw new Error("database has an active operation");
12120
12178
  if (!this.termination) {
12121
12179
  this.termination = (async () => {
12122
12180
  try {
@@ -12125,6 +12183,12 @@ var HyperDB = class _HyperDB {
12125
12183
  this.termination = void 0;
12126
12184
  throw error;
12127
12185
  }
12186
+ try {
12187
+ expectOk(await this.client.shutdown(), "shutdown");
12188
+ } catch (error) {
12189
+ this.termination = void 0;
12190
+ throw error;
12191
+ }
12128
12192
  this.terminated = true;
12129
12193
  await this.client.terminate();
12130
12194
  })();
@@ -12133,6 +12197,16 @@ var HyperDB = class _HyperDB {
12133
12197
  }
12134
12198
  ensureRunning() {
12135
12199
  if (this.terminated) throw new Error("database is terminated");
12200
+ if (this.termination) throw new Error("database is terminating");
12201
+ }
12202
+ async runDatabaseOperation(operation) {
12203
+ this.ensureRunning();
12204
+ ++this.activeDatabaseOperations;
12205
+ try {
12206
+ await operation();
12207
+ } finally {
12208
+ --this.activeDatabaseOperations;
12209
+ }
12136
12210
  }
12137
12211
  };
12138
12212
  var HyperDBConnection = class {
@@ -12146,13 +12220,10 @@ var HyperDBConnection = class {
12146
12220
  onClose;
12147
12221
  closed = false;
12148
12222
  active = false;
12149
- arrowInsertOptions;
12150
- appendingArrow = false;
12151
12223
  closing;
12152
12224
  async close() {
12153
12225
  if (this.closed) return;
12154
- if (this.active) throw new Error("connection has an active query");
12155
- if (this.arrowInsertOptions) throw new Error("connection has an unfinished Arrow IPC stream");
12226
+ if (this.active) throw new Error("connection has an active operation");
12156
12227
  if (!this.closing) {
12157
12228
  this.closing = (async () => {
12158
12229
  try {
@@ -12167,6 +12238,25 @@ var HyperDBConnection = class {
12167
12238
  }
12168
12239
  await this.closing;
12169
12240
  }
12241
+ async attachDatabase(databaseName, alias = databaseName) {
12242
+ validateDatabaseName(databaseName);
12243
+ validateDatabaseAlias(alias);
12244
+ this.ensureAvailable();
12245
+ try {
12246
+ expectOk(await this.client.attachDatabase(this.connection, databaseName, alias), "attach database");
12247
+ } finally {
12248
+ this.active = false;
12249
+ }
12250
+ }
12251
+ async detachDatabase(alias) {
12252
+ validateDatabaseAlias(alias);
12253
+ this.ensureAvailable();
12254
+ try {
12255
+ expectOk(await this.client.detachDatabase(this.connection, alias), "detach database");
12256
+ } finally {
12257
+ this.active = false;
12258
+ }
12259
+ }
12170
12260
  sendIPC(sql) {
12171
12261
  const connection = this;
12172
12262
  return {
@@ -12254,41 +12344,31 @@ var HyperDBConnection = class {
12254
12344
  return new Table(reader.schema, batches);
12255
12345
  }
12256
12346
  async insertArrowTable(table, options) {
12257
- await this.insertArrowFromIPCStream(tableToIPC(materializeDictionaryColumns(table), "stream"), options);
12258
- await this.finishArrowIPCStream();
12259
- }
12260
- async insertArrowFromIPCStream(chunk, options) {
12261
- if (this.closed) throw new Error("connection is closed");
12262
- if (this.closing) throw new Error("connection is closing");
12263
- if (this.active) throw new Error("connection has an active query");
12264
- if (this.appendingArrow) throw new Error("connection is appending Arrow IPC");
12265
- const normalized = normalizeArrowInsertOptions(options);
12266
- if (this.arrowInsertOptions && !equalArrowInsertOptions(this.arrowInsertOptions, normalized)) {
12267
- throw new Error("Arrow insert options must match the pending stream");
12268
- }
12269
- this.appendingArrow = true;
12347
+ this.ensureAvailable();
12348
+ let path;
12270
12349
  try {
12271
- expectOk(await this.client.appendArrowIPC(this.connection, chunk), "append Arrow IPC");
12272
- this.arrowInsertOptions = normalized;
12350
+ const result = await this.client.createTemporaryFile(tableToIPC(materializeDictionaryColumns(table), "stream"));
12351
+ expectOk(result, "create temporary Arrow IPC file");
12352
+ path = new TextDecoder().decode(result.payload);
12353
+ await this.insertArrowIPCFromPathInternal(path, options, true, false);
12273
12354
  } finally {
12274
- this.appendingArrow = false;
12355
+ try {
12356
+ if (path !== void 0) expectOk(await this.client.removeFile(path), "remove temporary Arrow IPC file");
12357
+ } finally {
12358
+ this.active = false;
12359
+ }
12275
12360
  }
12276
12361
  }
12277
- async finishArrowIPCStream(options) {
12278
- if (this.closed) throw new Error("connection is closed");
12279
- if (this.closing) throw new Error("connection is closing");
12280
- if (this.active) throw new Error("connection has an active query");
12281
- if (this.appendingArrow) throw new Error("connection is appending Arrow IPC");
12282
- const normalized = options ? normalizeArrowInsertOptions(options) : this.arrowInsertOptions;
12283
- if (!normalized) throw new Error("connection has no Arrow IPC input");
12284
- if (this.arrowInsertOptions && !equalArrowInsertOptions(this.arrowInsertOptions, normalized)) {
12285
- throw new Error("Arrow insert options must match the pending stream");
12286
- }
12287
- this.active = true;
12362
+ async insertArrowIPCFromPath(path, options) {
12363
+ await this.insertArrowIPCFromPathInternal(path, options, false);
12364
+ }
12365
+ async insertArrowIPCFromPathInternal(path, options, internal, acquire = true) {
12366
+ if (!path) throw new Error("Arrow IPC input path must not be empty");
12367
+ const normalized = normalizeArrowInsertOptions(options);
12368
+ if (acquire) this.ensureAvailable();
12288
12369
  let query;
12289
12370
  try {
12290
- query = readHandleFromResult(await this.client.finishArrowIPC(this.connection, normalized.name, normalized.schema, normalized.create), "finish Arrow IPC");
12291
- this.arrowInsertOptions = void 0;
12371
+ query = readHandleFromResult(await this.client.insertArrowIPCFromPath(this.connection, path, normalized.name, normalized.schema, normalized.create, internal), "insert Arrow IPC from path");
12292
12372
  for (; ; ) {
12293
12373
  let result = await this.client.pollQuery(query);
12294
12374
  while (result.state === "pending") {
@@ -12297,13 +12377,13 @@ var HyperDBConnection = class {
12297
12377
  }
12298
12378
  if (result.state === "done") return;
12299
12379
  if (result.state === "chunk") continue;
12300
- throw readErrorFromResult(result, "finish Arrow IPC");
12380
+ throw readErrorFromResult(result, "insert Arrow IPC from path");
12301
12381
  }
12302
12382
  } finally {
12303
12383
  try {
12304
12384
  if (query !== void 0) await this.release(query);
12305
12385
  } finally {
12306
- this.active = false;
12386
+ if (acquire) this.active = false;
12307
12387
  }
12308
12388
  }
12309
12389
  }
@@ -12311,7 +12391,7 @@ var HyperDBConnection = class {
12311
12391
  if (this.closed) throw new Error("connection is closed");
12312
12392
  if (this.closing) throw new Error("connection is closing");
12313
12393
  if (this.active) {
12314
- throw new Error("connection has an active query");
12394
+ throw new Error("connection has an active operation");
12315
12395
  }
12316
12396
  this.active = true;
12317
12397
  }
@@ -12326,8 +12406,7 @@ var HyperDBConnection = class {
12326
12406
  }
12327
12407
  }
12328
12408
  async closeForTermination() {
12329
- if (this.active) throw new Error("cannot terminate while a connection has an active query");
12330
- if (this.arrowInsertOptions) throw new Error("cannot terminate while a connection has an unfinished Arrow IPC stream");
12409
+ if (this.active) throw new Error("cannot terminate while a connection has an active operation");
12331
12410
  await this.close();
12332
12411
  }
12333
12412
  };
@@ -7,26 +7,43 @@
7
7
  if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 0) throw new Error(`${name} must be a nonnegative safe integer`);
8
8
  return number;
9
9
  }
10
+ function validateCString(value, name) {
11
+ if (!value) throw new Error(`${name} must not be empty`);
12
+ if (value.includes("\0")) throw new Error(`${name} must not contain NUL`);
13
+ }
10
14
  var HyperDBBindings = class {
11
15
  module;
12
16
  connect;
13
17
  disconnect;
18
+ createDatabase;
19
+ openDatabase;
20
+ checkpointDatabase;
21
+ dropDatabase;
22
+ shutdown;
23
+ attachDatabase;
24
+ detachDatabase;
14
25
  startQuery;
15
- appendArrowIPC;
16
- finishArrowIPC;
26
+ insertArrowIPCFromPath;
17
27
  pollQuery;
18
28
  cancelQuery;
19
29
  releaseQuery;
20
30
  resultState;
21
31
  resultPayloadLength;
22
32
  free;
33
+ nextTemporaryFile = 1;
23
34
  constructor(module) {
24
35
  this.module = module;
25
36
  this.connect = module.cwrap("hyperdb_wasm_connect", "pointer", []);
26
37
  this.disconnect = module.cwrap("hyperdb_wasm_disconnect", "pointer", ["number"]);
38
+ this.createDatabase = module.cwrap("hyperdb_wasm_create_database", "pointer", ["string", "number"]);
39
+ this.openDatabase = module.cwrap("hyperdb_wasm_open_database", "pointer", ["string"]);
40
+ this.checkpointDatabase = module.cwrap("hyperdb_wasm_checkpoint_database", "pointer", ["string"]);
41
+ this.dropDatabase = module.cwrap("hyperdb_wasm_drop_database", "pointer", ["string"]);
42
+ this.shutdown = module.cwrap("hyperdb_wasm_shutdown", "pointer", []);
43
+ this.attachDatabase = module.cwrap("hyperdb_wasm_attach_database", "pointer", ["number", "string", "string"]);
44
+ this.detachDatabase = module.cwrap("hyperdb_wasm_detach_database", "pointer", ["number", "string"]);
27
45
  this.startQuery = module.cwrap("hyperdb_wasm_query_start", "pointer", ["number", "string"]);
28
- this.appendArrowIPC = module.cwrap("hyperdb_wasm_arrow_insert_append", "pointer", ["number", "number", "number"]);
29
- this.finishArrowIPC = module.cwrap("hyperdb_wasm_arrow_insert_finish", "pointer", ["number", "string", "string", "number"]);
46
+ this.insertArrowIPCFromPath = module.cwrap("hyperdb_wasm_arrow_insert_from_path", "pointer", ["number", "string", "string", "string", "number"]);
30
47
  this.pollQuery = module.cwrap("hyperdb_wasm_query_poll", "pointer", ["number"]);
31
48
  this.cancelQuery = module.cwrap("hyperdb_wasm_query_cancel", "pointer", ["number"]);
32
49
  this.releaseQuery = module.cwrap("hyperdb_wasm_query_release", "pointer", ["number"]);
@@ -35,6 +52,16 @@
35
52
  this.free = module.cwrap("hyperdb_wasm_free", null, ["pointer"]);
36
53
  }
37
54
  handle(request) {
55
+ if (request.type === "createTemporaryFile") {
56
+ const path = `/tmp/hyperdb/arrow-${this.nextTemporaryFile++}.arrows`;
57
+ this.module.FS.mkdirTree("/tmp/hyperdb");
58
+ this.module.FS.writeFile(path, request.bytes);
59
+ return { response: { id: request.id, type: "response", result: { state: "ok", payload: new TextEncoder().encode(path) } }, transfer: [] };
60
+ }
61
+ if (request.type === "removeFile") {
62
+ this.module.FS.unlink(request.path);
63
+ return { response: { id: request.id, type: "response", result: { state: "ok", payload: new Uint8Array() } }, transfer: [] };
64
+ }
38
65
  const pointer = safeInteger(this.invoke(request), "result pointer");
39
66
  const result = this.decodeResult(pointer);
40
67
  const response = { id: request.id, type: "response", result };
@@ -46,21 +73,33 @@
46
73
  return this.connect();
47
74
  case "disconnect":
48
75
  return this.disconnect(request.connection);
76
+ case "createDatabase":
77
+ validateCString(request.databaseName, "database name");
78
+ return this.createDatabase(request.databaseName, Number(request.persistent));
79
+ case "openDatabase":
80
+ validateCString(request.databaseName, "database name");
81
+ return this.openDatabase(request.databaseName);
82
+ case "checkpointDatabase":
83
+ validateCString(request.databaseName, "database name");
84
+ return this.checkpointDatabase(request.databaseName);
85
+ case "dropDatabase":
86
+ validateCString(request.databaseName, "database name");
87
+ return this.dropDatabase(request.databaseName);
88
+ case "attachDatabase":
89
+ validateCString(request.databaseName, "database name");
90
+ validateCString(request.alias, "database alias");
91
+ return this.attachDatabase(request.connection, request.databaseName, request.alias);
92
+ case "detachDatabase":
93
+ validateCString(request.alias, "database alias");
94
+ return this.detachDatabase(request.connection, request.alias);
95
+ case "shutdown":
96
+ return this.shutdown();
49
97
  case "startQuery":
50
98
  return this.startQuery(request.connection, request.sql);
51
- case "appendArrowIPC": {
52
- const pointer = safeInteger(this.module._malloc(request.chunk.byteLength || 1), "allocation pointer");
53
- if (pointer === 0) throw new Error("wasm allocation failed");
54
- try {
55
- if (pointer + request.chunk.byteLength > this.module.HEAPU8.byteLength) throw new Error("allocation exceeds the wasm heap");
56
- this.module.HEAPU8.set(request.chunk, pointer);
57
- return this.appendArrowIPC(request.connection, pointer, request.chunk.byteLength);
58
- } finally {
59
- this.free(pointer);
60
- }
99
+ case "insertArrowIPCFromPath": {
100
+ const path = request.internal ? request.path : this.module.resolveHyperDBPath?.(request.path) ?? request.path;
101
+ return this.insertArrowIPCFromPath(request.connection, path, request.name, request.schema ?? "", Number(request.create));
61
102
  }
62
- case "finishArrowIPC":
63
- return this.finishArrowIPC(request.connection, request.name, request.schema ?? "", Number(request.create));
64
103
  case "pollQuery":
65
104
  return this.pollQuery(request.query);
66
105
  case "cancelQuery":
@@ -117,12 +156,26 @@
117
156
  return hasKeys(value, ["id", "type"]);
118
157
  case "disconnect":
119
158
  return hasKeys(value, ["id", "type", "connection"]) && Number.isSafeInteger(value.connection);
159
+ case "createDatabase":
160
+ return hasKeys(value, ["id", "type", "databaseName", "persistent"]) && typeof value.databaseName === "string" && typeof value.persistent === "boolean";
161
+ case "openDatabase":
162
+ case "checkpointDatabase":
163
+ case "dropDatabase":
164
+ return hasKeys(value, ["id", "type", "databaseName"]) && typeof value.databaseName === "string";
165
+ case "shutdown":
166
+ return hasKeys(value, ["id", "type"]);
167
+ case "attachDatabase":
168
+ return hasKeys(value, ["id", "type", "connection", "databaseName", "alias"]) && Number.isSafeInteger(value.connection) && typeof value.databaseName === "string" && typeof value.alias === "string";
169
+ case "detachDatabase":
170
+ return hasKeys(value, ["id", "type", "connection", "alias"]) && Number.isSafeInteger(value.connection) && typeof value.alias === "string";
120
171
  case "startQuery":
121
172
  return hasKeys(value, ["id", "type", "connection", "sql"]) && Number.isSafeInteger(value.connection) && typeof value.sql === "string";
122
- case "appendArrowIPC":
123
- return hasKeys(value, ["id", "type", "connection", "chunk"]) && Number.isSafeInteger(value.connection) && value.chunk instanceof Uint8Array;
124
- case "finishArrowIPC":
125
- return hasKeys(value, ["id", "type", "connection", "name", "schema", "create"]) && Number.isSafeInteger(value.connection) && typeof value.name === "string" && (typeof value.schema === "string" || value.schema === null) && typeof value.create === "boolean";
173
+ case "insertArrowIPCFromPath":
174
+ return hasKeys(value, ["id", "type", "connection", "path", "name", "schema", "create", "internal"]) && Number.isSafeInteger(value.connection) && typeof value.path === "string" && typeof value.name === "string" && (typeof value.schema === "string" || value.schema === null) && typeof value.create === "boolean" && typeof value.internal === "boolean";
175
+ case "createTemporaryFile":
176
+ return hasKeys(value, ["id", "type", "bytes"]) && value.bytes instanceof Uint8Array;
177
+ case "removeFile":
178
+ return hasKeys(value, ["id", "type", "path"]) && typeof value.path === "string";
126
179
  case "pollQuery":
127
180
  case "cancelQuery":
128
181
  case "releaseQuery":
@@ -192,7 +245,7 @@
192
245
  });
193
246
  };
194
247
  }
195
- function configureWorker(module, transport) {
248
+ function configureWorker(module, transport, configureFilesystem = () => void 0) {
196
249
  const queuedRequests = [];
197
250
  let bindings;
198
251
  const handle = (request) => {
@@ -214,10 +267,15 @@
214
267
  module.print = (text) => transport.postMessage({ type: "log", text });
215
268
  module.printErr = (text) => transport.postMessage({ type: "log", text });
216
269
  module.onRuntimeInitialized = () => {
217
- installHttpRuntime(module, transport);
218
- bindings = new HyperDBBindings(module);
219
- transport.postMessage({ type: "ready" });
220
- for (const request of queuedRequests.splice(0)) handle(request);
270
+ try {
271
+ configureFilesystem(module);
272
+ installHttpRuntime(module, transport);
273
+ bindings = new HyperDBBindings(module);
274
+ transport.postMessage({ type: "ready" });
275
+ for (const request of queuedRequests.splice(0)) handle(request);
276
+ } catch (error) {
277
+ transport.postMessage({ type: "fatal", error: `engine initialization failed: ${errorText(error)}` });
278
+ }
221
279
  };
222
280
  module.onAbort = (reason) => transport.postMessage({ type: "fatal", error: `engine aborted: ${String(reason)}` });
223
281
  }
@@ -241,7 +299,27 @@
241
299
  postMessage: (message, transfer = []) => self.postMessage(message, [...transfer]),
242
300
  onMessage: (listener) => self.addEventListener("message", (event) => listener(event.data))
243
301
  };
244
- configureWorker(module, transport);
302
+ configureWorker(module, transport, (runtime) => {
303
+ if (!runtime.OPFS) throw new Error("OPFS backend is unavailable");
304
+ runtime.FS.mkdirTree("/opfs");
305
+ runtime.FS.mount(runtime.OPFS, {}, "/opfs");
306
+ runtime.FS.mkdirTree("/hyperdb-persistent");
307
+ runtime.FS.mount(runtime.OPFS, {}, "/hyperdb-persistent");
308
+ runtime.FS.mkdirTree("/hyperdb-persistent/hyperdb");
309
+ runtime.resolveHyperDBPath = (path) => {
310
+ const parts = [];
311
+ for (const part of path.replace(/^\/+/, "").split("/")) {
312
+ if (!part || part === ".") continue;
313
+ if (part === "..") {
314
+ if (parts.length === 0) throw new Error(`Arrow IPC path is outside the OPFS root: ${path}`);
315
+ parts.pop();
316
+ } else {
317
+ parts.push(part);
318
+ }
319
+ }
320
+ return `/opfs/${parts.join("/")}`;
321
+ };
322
+ });
245
323
  self.importScripts(resolvedEngineUrl.href);
246
324
  }
247
325
  })();
package/dist/client.d.ts CHANGED
@@ -12,9 +12,17 @@ export declare class HyperDBEngineClient {
12
12
  ready(): Promise<void>;
13
13
  connect(): Promise<WasmResult>;
14
14
  disconnect(connection: number): Promise<WasmResult>;
15
+ createDatabase(databaseName: string, persistent: boolean): Promise<WasmResult>;
16
+ openDatabase(databaseName: string): Promise<WasmResult>;
17
+ checkpointDatabase(databaseName: string): Promise<WasmResult>;
18
+ dropDatabase(databaseName: string): Promise<WasmResult>;
19
+ attachDatabase(connection: number, databaseName: string, alias: string): Promise<WasmResult>;
20
+ detachDatabase(connection: number, alias: string): Promise<WasmResult>;
21
+ shutdown(): Promise<WasmResult>;
15
22
  startQuery(connection: number, sql: string): Promise<WasmResult>;
16
- appendArrowIPC(connection: number, chunk: Uint8Array): Promise<WasmResult>;
17
- finishArrowIPC(connection: number, name: string, schema: string | null, create: boolean): Promise<WasmResult>;
23
+ insertArrowIPCFromPath(connection: number, path: string, name: string, schema: string | null, create: boolean, internal?: boolean): Promise<WasmResult>;
24
+ createTemporaryFile(bytes: Uint8Array): Promise<WasmResult>;
25
+ removeFile(path: string): Promise<WasmResult>;
18
26
  pollQuery(query: number): Promise<WasmResult>;
19
27
  cancelQuery(query: number): Promise<WasmResult>;
20
28
  releaseQuery(query: number): Promise<WasmResult>;