@rivetkit/rivetkit-native 0.0.0-pr.4658.756b818 → 0.0.0-pr.4662.be7407a

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/index.d.ts CHANGED
@@ -18,7 +18,7 @@ export interface QueryResult {
18
18
  rows: Array<Array<any>>
19
19
  }
20
20
  /** Open a native SQLite database backed by the envoy's KV channel. */
21
- export declare function openDatabaseFromEnvoy(jsHandle: JsEnvoyHandle, actorId: string, preloadedEntries?: Array<JsKvEntry> | undefined | null): Promise<JsNativeDatabase>
21
+ export declare function openDatabaseFromEnvoy(jsHandle: JsEnvoyHandle, actorId: string): Promise<JsNativeDatabase>
22
22
  /** Configuration for starting the native envoy client. */
23
23
  export interface JsEnvoyConfig {
24
24
  endpoint: string
@@ -48,10 +48,6 @@ export interface JsKvEntry {
48
48
  export interface HibernatingRequestEntry {
49
49
  gatewayId: Buffer
50
50
  requestId: Buffer
51
- envoyMessageIndex: number
52
- rivetMessageIndex: number
53
- path: string
54
- headers?: Record<string, string>
55
51
  }
56
52
  /**
57
53
  * Start the native envoy client synchronously.
@@ -64,7 +60,6 @@ export declare function startEnvoySyncJs(config: JsEnvoyConfig, eventCallback: (
64
60
  export declare function startEnvoyJs(config: JsEnvoyConfig, eventCallback: (event: any) => void): JsEnvoyHandle
65
61
  /** Native SQLite database handle exposed to JavaScript. */
66
62
  export declare class JsNativeDatabase {
67
- takeLastKvError(): string | null
68
63
  run(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<ExecuteResult>
69
64
  query(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<QueryResult>
70
65
  exec(sql: string): Promise<QueryResult>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivetkit/rivetkit-native",
3
- "version": "0.0.0-pr.4658.756b818",
3
+ "version": "0.0.0-pr.4662.be7407a",
4
4
  "description": "Native N-API addon for RivetKit providing envoy client and SQLite access",
5
5
  "license": "Apache-2.0",
6
6
  "main": "index.js",
@@ -49,15 +49,15 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@napi-rs/cli": "^2.18.4",
52
- "@rivetkit/engine-envoy-protocol": "0.0.0-pr.4658.756b818"
52
+ "@rivetkit/engine-envoy-protocol": "0.0.0-pr.4662.be7407a"
53
53
  },
54
54
  "optionalDependencies": {
55
- "@rivetkit/rivetkit-native-darwin-arm64": "0.0.0-pr.4658.756b818",
56
- "@rivetkit/rivetkit-native-darwin-x64": "0.0.0-pr.4658.756b818",
57
- "@rivetkit/rivetkit-native-linux-arm64-gnu": "0.0.0-pr.4658.756b818",
58
- "@rivetkit/rivetkit-native-linux-arm64-musl": "0.0.0-pr.4658.756b818",
59
- "@rivetkit/rivetkit-native-linux-x64-gnu": "0.0.0-pr.4658.756b818",
60
- "@rivetkit/rivetkit-native-linux-x64-musl": "0.0.0-pr.4658.756b818",
61
- "@rivetkit/rivetkit-native-win32-x64-msvc": "0.0.0-pr.4658.756b818"
55
+ "@rivetkit/rivetkit-native-darwin-arm64": "0.0.0-pr.4662.be7407a",
56
+ "@rivetkit/rivetkit-native-darwin-x64": "0.0.0-pr.4662.be7407a",
57
+ "@rivetkit/rivetkit-native-linux-arm64-gnu": "0.0.0-pr.4662.be7407a",
58
+ "@rivetkit/rivetkit-native-linux-arm64-musl": "0.0.0-pr.4662.be7407a",
59
+ "@rivetkit/rivetkit-native-linux-x64-gnu": "0.0.0-pr.4662.be7407a",
60
+ "@rivetkit/rivetkit-native-linux-x64-musl": "0.0.0-pr.4662.be7407a",
61
+ "@rivetkit/rivetkit-native-win32-x64-msvc": "0.0.0-pr.4662.be7407a"
62
62
  }
63
63
  }
package/wrapper.d.ts CHANGED
@@ -126,6 +126,19 @@ export declare function startEnvoy(config: EnvoyConfig): Promise<EnvoyHandle>;
126
126
  export declare function openDatabaseFromEnvoy(
127
127
  handle: EnvoyHandle,
128
128
  actorId: string,
129
- preloadedEntries?: readonly [Uint8Array, Uint8Array][] | null,
130
129
  ): Promise<JsNativeDatabase>;
130
+
131
+ export interface NativeRawDatabase {
132
+ execute: <TRow extends Record<string, unknown> = Record<string, unknown>>(
133
+ query: string,
134
+ ...args: unknown[]
135
+ ) => Promise<TRow[]>;
136
+ close: () => Promise<void>;
137
+ }
138
+
139
+ export declare function openRawDatabaseFromEnvoy(
140
+ handle: EnvoyHandle,
141
+ actorId: string,
142
+ ): Promise<NativeRawDatabase>;
143
+
131
144
  export declare const utils: {};
package/wrapper.js CHANGED
@@ -98,10 +98,6 @@ function wrapHandle(jsHandle) {
98
98
  const requests = (metaEntries || []).map((e) => ({
99
99
  gatewayId: Buffer.from(e.gatewayId),
100
100
  requestId: Buffer.from(e.requestId),
101
- envoyMessageIndex: e.envoyMessageIndex ?? 0,
102
- rivetMessageIndex: e.rivetMessageIndex ?? 0,
103
- path: e.path ?? "",
104
- headers: e.headers ?? {},
105
101
  }));
106
102
  jsHandle.restoreHibernatingRequests(actorId, requests);
107
103
  },
@@ -138,7 +134,7 @@ function startEnvoySync(config) {
138
134
  poolName: config.poolName,
139
135
  version: config.version,
140
136
  metadata: config.metadata || null,
141
- notGlobal: config.notGlobal ?? false,
137
+ notGlobal: config.notGlobal,
142
138
  },
143
139
  (event) => {
144
140
  handleEvent(event, config, wrappedHandle);
@@ -162,39 +158,154 @@ async function startEnvoy(config) {
162
158
  /**
163
159
  * Open a native database backed by envoy KV.
164
160
  */
165
- async function openDatabaseFromEnvoy(handle, actorId, preloadedEntries) {
161
+ async function openDatabaseFromEnvoy(handle, actorId) {
166
162
  const rawHandle = handle._raw || handle;
167
- const nativePreloadedEntries = preloadedEntries
168
- ? preloadedEntries.map(([key, value]) => ({
169
- key: Buffer.from(key),
170
- value: Buffer.from(value),
171
- }))
172
- : null;
173
- return native.openDatabaseFromEnvoy(
174
- rawHandle,
175
- actorId,
176
- nativePreloadedEntries,
163
+ return native.openDatabaseFromEnvoy(rawHandle, actorId);
164
+ }
165
+
166
+ function isPlainObject(value) {
167
+ return (
168
+ !!value &&
169
+ typeof value === "object" &&
170
+ !Array.isArray(value) &&
171
+ Object.getPrototypeOf(value) === Object.prototype
177
172
  );
178
173
  }
179
174
 
180
- function decodePreloadedKv(preloadedKv) {
181
- if (!preloadedKv) {
182
- return null;
175
+ function toNativeBinding(value) {
176
+ if (value === null || value === undefined) {
177
+ return { kind: "null" };
178
+ }
179
+ if (typeof value === "bigint") {
180
+ return { kind: "int", intValue: Number(value) };
181
+ }
182
+ if (typeof value === "number") {
183
+ return Number.isInteger(value)
184
+ ? { kind: "int", intValue: value }
185
+ : { kind: "float", floatValue: value };
186
+ }
187
+ if (typeof value === "string") {
188
+ return { kind: "text", textValue: value };
189
+ }
190
+ if (value instanceof ArrayBuffer) {
191
+ return { kind: "blob", blobValue: Buffer.from(value) };
192
+ }
193
+ if (ArrayBuffer.isView(value)) {
194
+ return {
195
+ kind: "blob",
196
+ blobValue: Buffer.from(value.buffer, value.byteOffset, value.byteLength),
197
+ };
183
198
  }
184
199
 
185
- const decodeBytes = (value) => Uint8Array.from(Buffer.from(value, "base64"));
200
+ throw new Error(`unsupported sqlite binding type: ${typeof value}`);
201
+ }
202
+
203
+ function extractNamedSqliteParameters(sql) {
204
+ return [...sql.matchAll(/([:@$][A-Za-z_][A-Za-z0-9_]*)/g)].map(
205
+ (match) => match[1],
206
+ );
207
+ }
208
+
209
+ function getNamedSqliteBinding(bindings, name) {
210
+ if (name in bindings) {
211
+ return bindings[name];
212
+ }
213
+
214
+ const bareName = name.slice(1);
215
+ if (bareName in bindings) {
216
+ return bindings[bareName];
217
+ }
218
+
219
+ for (const prefix of [":", "@", "$"]) {
220
+ const candidate = `${prefix}${bareName}`;
221
+ if (candidate in bindings) {
222
+ return bindings[candidate];
223
+ }
224
+ }
225
+
226
+ return undefined;
227
+ }
228
+
229
+ function normalizeBindings(sql, args) {
230
+ if (!args || args.length === 0) {
231
+ return [];
232
+ }
233
+
234
+ if (
235
+ args.length === 1 &&
236
+ isPlainObject(args[0]) &&
237
+ !(args[0] instanceof Uint8Array)
238
+ ) {
239
+ const names = extractNamedSqliteParameters(sql);
240
+ if (names.length === 0) {
241
+ throw new Error(
242
+ "native sqlite object bindings require named placeholders in the SQL statement",
243
+ );
244
+ }
245
+ return names.map((name) => {
246
+ const value = getNamedSqliteBinding(args[0], name);
247
+ if (value === undefined) {
248
+ throw new Error(`missing bind parameter: ${name}`);
249
+ }
250
+ return toNativeBinding(value);
251
+ });
252
+ }
253
+
254
+ return args.map(toNativeBinding);
255
+ }
256
+
257
+ function mapRows(rows, columns) {
258
+ return rows.map((row) => {
259
+ const rowObject = {};
260
+ for (let i = 0; i < columns.length; i++) {
261
+ rowObject[columns[i]] = row[i];
262
+ }
263
+ return rowObject;
264
+ });
265
+ }
266
+
267
+ async function openRawDatabaseFromEnvoy(handle, actorId) {
268
+ const nativeDb = await openDatabaseFromEnvoy(handle, actorId);
269
+ let closed = false;
270
+
271
+ const ensureOpen = () => {
272
+ if (closed) {
273
+ throw new Error("database is closed");
274
+ }
275
+ };
186
276
 
187
277
  return {
188
- entries: (preloadedKv.entries || []).map((entry) => ({
189
- key: decodeBytes(entry.key),
190
- value: decodeBytes(entry.value),
191
- metadata: {
192
- version: decodeBytes(entry.metadata.version),
193
- updateTs: entry.metadata.updateTs,
194
- },
195
- })),
196
- requestedGetKeys: (preloadedKv.requestedGetKeys || []).map(decodeBytes),
197
- requestedPrefixes: (preloadedKv.requestedPrefixes || []).map(decodeBytes),
278
+ execute: async (query, ...args) => {
279
+ ensureOpen();
280
+
281
+ if (args.length > 0) {
282
+ const bindings = normalizeBindings(query, args);
283
+ const token = query.trimStart().slice(0, 16).toUpperCase();
284
+ const returnsRows =
285
+ token.startsWith("SELECT") ||
286
+ token.startsWith("PRAGMA") ||
287
+ token.startsWith("WITH") ||
288
+ /\bRETURNING\b/i.test(query);
289
+
290
+ if (returnsRows) {
291
+ const result = await nativeDb.query(query, bindings);
292
+ return mapRows(result.rows, result.columns);
293
+ }
294
+
295
+ await nativeDb.run(query, bindings);
296
+ return [];
297
+ }
298
+
299
+ const result = await nativeDb.exec(query);
300
+ return mapRows(result.rows, result.columns);
301
+ },
302
+ close: async () => {
303
+ if (closed) {
304
+ return;
305
+ }
306
+ closed = true;
307
+ await nativeDb.close();
308
+ },
198
309
  };
199
310
  }
200
311
 
@@ -219,7 +330,7 @@ function handleEvent(event, config, wrappedHandle) {
219
330
  event.actorId,
220
331
  event.generation,
221
332
  actorConfig,
222
- decodePreloadedKv(event.preloadedKv),
333
+ null, // preloadedKv
223
334
  ),
224
335
  ).then(
225
336
  async () => {
@@ -312,46 +423,6 @@ function handleEvent(event, config, wrappedHandle) {
312
423
  );
313
424
  break;
314
425
  }
315
- case "websocket_can_hibernate": {
316
- const gatewayId = Buffer.from(event.gatewayId);
317
- const requestId = Buffer.from(event.requestId);
318
- const headers = new Headers(event.headers || {});
319
- headers.set("Upgrade", "websocket");
320
- headers.set("Connection", "Upgrade");
321
- const request = new Request(`http://actor${event.path}`, {
322
- method: event.method,
323
- headers,
324
- });
325
-
326
- Promise.resolve(
327
- config.hibernatableWebSocket
328
- ? config.hibernatableWebSocket.canHibernate(
329
- event.actorId,
330
- gatewayId,
331
- requestId,
332
- request,
333
- )
334
- : false,
335
- ).then(
336
- async (canHibernate) => {
337
- if (handle._raw) {
338
- await handle._raw.respondCallback(event.responseId, {
339
- canHibernate: Boolean(canHibernate),
340
- });
341
- }
342
- },
343
- async (err) => {
344
- console.error("canHibernate error:", err);
345
- if (handle._raw) {
346
- await handle._raw.respondCallback(event.responseId, {
347
- canHibernate: false,
348
- error: String(err),
349
- });
350
- }
351
- },
352
- );
353
- break;
354
- }
355
426
  case "websocket_open": {
356
427
  if (config.websocket) {
357
428
  const messageId = Buffer.from(event.messageId);
@@ -503,3 +574,4 @@ function handleEvent(event, config, wrappedHandle) {
503
574
  module.exports.startEnvoy = startEnvoy;
504
575
  module.exports.startEnvoySync = startEnvoySync;
505
576
  module.exports.openDatabaseFromEnvoy = openDatabaseFromEnvoy;
577
+ module.exports.openRawDatabaseFromEnvoy = openRawDatabaseFromEnvoy;