@rivetkit/rivetkit-native 2.2.1-pr.4600.252b48e
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 +93 -0
- package/index.js +319 -0
- package/package.json +63 -0
- package/scripts/build.mjs +57 -0
- package/wrapper.d.ts +144 -0
- package/wrapper.js +422 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
export interface JsBindParam {
|
|
7
|
+
kind: string
|
|
8
|
+
intValue?: number
|
|
9
|
+
floatValue?: number
|
|
10
|
+
textValue?: string
|
|
11
|
+
blobValue?: Buffer
|
|
12
|
+
}
|
|
13
|
+
export interface ExecuteResult {
|
|
14
|
+
changes: number
|
|
15
|
+
}
|
|
16
|
+
export interface QueryResult {
|
|
17
|
+
columns: Array<string>
|
|
18
|
+
rows: Array<Array<any>>
|
|
19
|
+
}
|
|
20
|
+
/** Open a native SQLite database backed by the envoy's KV channel. */
|
|
21
|
+
export declare function openDatabaseFromEnvoy(jsHandle: JsEnvoyHandle, actorId: string): Promise<JsNativeDatabase>
|
|
22
|
+
/** Configuration for starting the native envoy client. */
|
|
23
|
+
export interface JsEnvoyConfig {
|
|
24
|
+
endpoint: string
|
|
25
|
+
token: string
|
|
26
|
+
namespace: string
|
|
27
|
+
poolName: string
|
|
28
|
+
version: number
|
|
29
|
+
metadata?: any
|
|
30
|
+
notGlobal: boolean
|
|
31
|
+
/**
|
|
32
|
+
* Log level for the Rust tracing subscriber (e.g. "trace", "debug", "info", "warn", "error").
|
|
33
|
+
* Falls back to RIVET_LOG_LEVEL, then LOG_LEVEL, then RUST_LOG env vars. Defaults to "warn".
|
|
34
|
+
*/
|
|
35
|
+
logLevel?: string
|
|
36
|
+
}
|
|
37
|
+
/** Options for KV list operations. */
|
|
38
|
+
export interface JsKvListOptions {
|
|
39
|
+
reverse?: boolean
|
|
40
|
+
limit?: number
|
|
41
|
+
}
|
|
42
|
+
/** A key-value entry returned from KV list operations. */
|
|
43
|
+
export interface JsKvEntry {
|
|
44
|
+
key: Buffer
|
|
45
|
+
value: Buffer
|
|
46
|
+
}
|
|
47
|
+
/** A single hibernating request entry. */
|
|
48
|
+
export interface HibernatingRequestEntry {
|
|
49
|
+
gatewayId: Buffer
|
|
50
|
+
requestId: Buffer
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Start the native envoy client synchronously.
|
|
54
|
+
*
|
|
55
|
+
* Returns a handle immediately. The caller must call `await handle.started()`
|
|
56
|
+
* to wait for the connection to be ready.
|
|
57
|
+
*/
|
|
58
|
+
export declare function startEnvoySyncJs(config: JsEnvoyConfig, eventCallback: (event: any) => void): JsEnvoyHandle
|
|
59
|
+
/** Start the native envoy client asynchronously. */
|
|
60
|
+
export declare function startEnvoyJs(config: JsEnvoyConfig, eventCallback: (event: any) => void): JsEnvoyHandle
|
|
61
|
+
/** Native SQLite database handle exposed to JavaScript. */
|
|
62
|
+
export declare class JsNativeDatabase {
|
|
63
|
+
run(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<ExecuteResult>
|
|
64
|
+
query(sql: string, params?: Array<JsBindParam> | undefined | null): Promise<QueryResult>
|
|
65
|
+
exec(sql: string): Promise<QueryResult>
|
|
66
|
+
close(): Promise<void>
|
|
67
|
+
}
|
|
68
|
+
/** Native envoy handle exposed to JavaScript via N-API. */
|
|
69
|
+
export declare class JsEnvoyHandle {
|
|
70
|
+
started(): Promise<void>
|
|
71
|
+
shutdown(immediate: boolean): void
|
|
72
|
+
get envoyKey(): string
|
|
73
|
+
sleepActor(actorId: string, generation?: number | undefined | null): void
|
|
74
|
+
stopActor(actorId: string, generation?: number | undefined | null, error?: string | undefined | null): void
|
|
75
|
+
destroyActor(actorId: string, generation?: number | undefined | null): void
|
|
76
|
+
setAlarm(actorId: string, alarmTs?: number | undefined | null, generation?: number | undefined | null): void
|
|
77
|
+
kvGet(actorId: string, keys: Array<Buffer>): Promise<Array<Buffer | undefined | null>>
|
|
78
|
+
kvPut(actorId: string, entries: Array<JsKvEntry>): Promise<void>
|
|
79
|
+
kvDelete(actorId: string, keys: Array<Buffer>): Promise<void>
|
|
80
|
+
kvDeleteRange(actorId: string, start: Buffer, end: Buffer): Promise<void>
|
|
81
|
+
kvListAll(actorId: string, options?: JsKvListOptions | undefined | null): Promise<Array<JsKvEntry>>
|
|
82
|
+
kvListRange(actorId: string, start: Buffer, end: Buffer, exclusive?: boolean | undefined | null, options?: JsKvListOptions | undefined | null): Promise<Array<JsKvEntry>>
|
|
83
|
+
kvListPrefix(actorId: string, prefix: Buffer, options?: JsKvListOptions | undefined | null): Promise<Array<JsKvEntry>>
|
|
84
|
+
kvDrop(actorId: string): Promise<void>
|
|
85
|
+
restoreHibernatingRequests(actorId: string, requests: Array<HibernatingRequestEntry>): void
|
|
86
|
+
sendHibernatableWebSocketMessageAck(gatewayId: Buffer, requestId: Buffer, clientMessageIndex: number): void
|
|
87
|
+
/** Send a message on an open WebSocket connection identified by messageIdHex. */
|
|
88
|
+
sendWsMessage(gatewayId: Buffer, requestId: Buffer, data: Buffer, binary: boolean): Promise<void>
|
|
89
|
+
/** Close an open WebSocket connection. */
|
|
90
|
+
closeWebsocket(gatewayId: Buffer, requestId: Buffer, code?: number | undefined | null, reason?: string | undefined | null): Promise<void>
|
|
91
|
+
startServerless(payload: Buffer): Promise<void>
|
|
92
|
+
respondCallback(responseId: string, data: any): Promise<void>
|
|
93
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'rivetkit-native.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./rivetkit-native.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('@rivetkit/rivetkit-native-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'rivetkit-native.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./rivetkit-native.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('@rivetkit/rivetkit-native-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'rivetkit-native.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./rivetkit-native.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('@rivetkit/rivetkit-native-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'rivetkit-native.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./rivetkit-native.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('@rivetkit/rivetkit-native-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'rivetkit-native.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./rivetkit-native.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('@rivetkit/rivetkit-native-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'rivetkit-native.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./rivetkit-native.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('@rivetkit/rivetkit-native-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'rivetkit-native.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./rivetkit-native.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('@rivetkit/rivetkit-native-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'rivetkit-native.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./rivetkit-native.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('@rivetkit/rivetkit-native-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'rivetkit-native.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./rivetkit-native.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('@rivetkit/rivetkit-native-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'rivetkit-native.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./rivetkit-native.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'rivetkit-native.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./rivetkit-native.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'rivetkit-native.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./rivetkit-native.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'rivetkit-native.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./rivetkit-native.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'rivetkit-native.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./rivetkit-native.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'rivetkit-native.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./rivetkit-native.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'rivetkit-native.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./rivetkit-native.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'rivetkit-native.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./rivetkit-native.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'rivetkit-native.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./rivetkit-native.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('@rivetkit/rivetkit-native-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { JsNativeDatabase, openDatabaseFromEnvoy, JsEnvoyHandle, startEnvoySyncJs, startEnvoyJs } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.JsNativeDatabase = JsNativeDatabase
|
|
316
|
+
module.exports.openDatabaseFromEnvoy = openDatabaseFromEnvoy
|
|
317
|
+
module.exports.JsEnvoyHandle = JsEnvoyHandle
|
|
318
|
+
module.exports.startEnvoySyncJs = startEnvoySyncJs
|
|
319
|
+
module.exports.startEnvoyJs = startEnvoyJs
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rivetkit/rivetkit-native",
|
|
3
|
+
"version": "2.2.1-pr.4600.252b48e",
|
|
4
|
+
"description": "Native N-API addon for RivetKit providing envoy client and SQLite access",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"default": "./index.js"
|
|
12
|
+
},
|
|
13
|
+
"./wrapper": {
|
|
14
|
+
"types": "./wrapper.d.ts",
|
|
15
|
+
"default": "./wrapper.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">= 20.0.0"
|
|
20
|
+
},
|
|
21
|
+
"napi": {
|
|
22
|
+
"name": "rivetkit-native",
|
|
23
|
+
"triples": {
|
|
24
|
+
"defaults": false,
|
|
25
|
+
"additional": [
|
|
26
|
+
"x86_64-unknown-linux-gnu",
|
|
27
|
+
"aarch64-unknown-linux-gnu",
|
|
28
|
+
"x86_64-unknown-linux-musl",
|
|
29
|
+
"aarch64-unknown-linux-musl",
|
|
30
|
+
"x86_64-apple-darwin",
|
|
31
|
+
"aarch64-apple-darwin",
|
|
32
|
+
"x86_64-pc-windows-msvc"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"index.js",
|
|
38
|
+
"index.d.ts",
|
|
39
|
+
"wrapper.js",
|
|
40
|
+
"wrapper.d.ts",
|
|
41
|
+
"package.json",
|
|
42
|
+
"scripts/build.mjs"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "node scripts/build.mjs",
|
|
46
|
+
"build:release": "node scripts/build.mjs --release",
|
|
47
|
+
"build:force": "node scripts/build.mjs --force",
|
|
48
|
+
"build:force:release": "node scripts/build.mjs --force --release"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@napi-rs/cli": "^2.18.4",
|
|
52
|
+
"@rivetkit/engine-envoy-protocol": "2.2.1-pr.4600.252b48e"
|
|
53
|
+
},
|
|
54
|
+
"optionalDependencies": {
|
|
55
|
+
"@rivetkit/rivetkit-native-darwin-arm64": "2.2.1-pr.4600.252b48e",
|
|
56
|
+
"@rivetkit/rivetkit-native-darwin-x64": "2.2.1-pr.4600.252b48e",
|
|
57
|
+
"@rivetkit/rivetkit-native-linux-arm64-gnu": "2.2.1-pr.4600.252b48e",
|
|
58
|
+
"@rivetkit/rivetkit-native-linux-arm64-musl": "2.2.1-pr.4600.252b48e",
|
|
59
|
+
"@rivetkit/rivetkit-native-linux-x64-gnu": "2.2.1-pr.4600.252b48e",
|
|
60
|
+
"@rivetkit/rivetkit-native-linux-x64-musl": "2.2.1-pr.4600.252b48e",
|
|
61
|
+
"@rivetkit/rivetkit-native-win32-x64-msvc": "2.2.1-pr.4600.252b48e"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Smart build wrapper for rivetkit-native.
|
|
4
|
+
*
|
|
5
|
+
* Skips the napi build if a prebuilt .node file already exists next to
|
|
6
|
+
* this package (either a root-level `rivetkit-native.*.node` or one inside
|
|
7
|
+
* a `npm/<platform>/` directory). This lets CI skip a redundant napi build
|
|
8
|
+
* when the cross-compiled artifacts have already been downloaded from the
|
|
9
|
+
* platform build jobs.
|
|
10
|
+
*
|
|
11
|
+
* Pass `--force` to always run the napi build.
|
|
12
|
+
*/
|
|
13
|
+
import { execSync } from "node:child_process";
|
|
14
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
15
|
+
import { dirname, join } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const packageDir = join(__dirname, "..");
|
|
20
|
+
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
const force = args.includes("--force");
|
|
23
|
+
const releaseArg = args.find((a) => a === "--release");
|
|
24
|
+
const extraFlags = releaseArg ? ["--release"] : [];
|
|
25
|
+
|
|
26
|
+
function hasPrebuiltArtifact() {
|
|
27
|
+
// Check for root-level .node files.
|
|
28
|
+
const rootFiles = readdirSync(packageDir);
|
|
29
|
+
if (rootFiles.some((f) => f.endsWith(".node"))) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
// Check for any npm/<platform>/*.node files.
|
|
33
|
+
const npmDir = join(packageDir, "npm");
|
|
34
|
+
if (existsSync(npmDir) && statSync(npmDir).isDirectory()) {
|
|
35
|
+
for (const entry of readdirSync(npmDir)) {
|
|
36
|
+
const platDir = join(npmDir, entry);
|
|
37
|
+
if (!statSync(platDir).isDirectory()) continue;
|
|
38
|
+
const files = readdirSync(platDir);
|
|
39
|
+
if (files.some((f) => f.endsWith(".node"))) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!force && hasPrebuiltArtifact()) {
|
|
48
|
+
console.log(
|
|
49
|
+
"[rivetkit-native/build] prebuilt .node artifact found — skipping napi build",
|
|
50
|
+
);
|
|
51
|
+
console.log("[rivetkit-native/build] use --force to rebuild from source");
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cmd = ["napi", "build", "--platform", ...extraFlags].join(" ");
|
|
56
|
+
console.log(`[rivetkit-native/build] running: ${cmd}`);
|
|
57
|
+
execSync(cmd, { stdio: "inherit", cwd: packageDir });
|
package/wrapper.d.ts
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { JsNativeDatabase, JsKvEntry, JsKvListOptions } from "./index";
|
|
2
|
+
|
|
3
|
+
export type { JsNativeDatabase, JsKvEntry, JsKvListOptions };
|
|
4
|
+
|
|
5
|
+
// Re-export protocol types from the envoy protocol package
|
|
6
|
+
export * as protocol from "@rivetkit/engine-envoy-protocol";
|
|
7
|
+
|
|
8
|
+
export interface HibernatingWebSocketMetadata {
|
|
9
|
+
gatewayId: ArrayBuffer;
|
|
10
|
+
requestId: ArrayBuffer;
|
|
11
|
+
envoyMessageIndex: number;
|
|
12
|
+
rivetMessageIndex: number;
|
|
13
|
+
path: string;
|
|
14
|
+
headers: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface KvListOptions {
|
|
18
|
+
reverse?: boolean;
|
|
19
|
+
limit?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Matches the TS EnvoyHandle interface from @rivetkit/engine-envoy-client */
|
|
23
|
+
export interface EnvoyHandle {
|
|
24
|
+
shutdown(immediate: boolean): void;
|
|
25
|
+
getProtocolMetadata(): any | undefined;
|
|
26
|
+
getEnvoyKey(): string;
|
|
27
|
+
started(): Promise<void>;
|
|
28
|
+
getActor(actorId: string, generation?: number): any | undefined;
|
|
29
|
+
sleepActor(actorId: string, generation?: number): void;
|
|
30
|
+
stopActor(actorId: string, generation?: number, error?: string): void;
|
|
31
|
+
destroyActor(actorId: string, generation?: number): void;
|
|
32
|
+
setAlarm(actorId: string, alarmTs: number | null, generation?: number): void;
|
|
33
|
+
kvGet(actorId: string, keys: Uint8Array[]): Promise<(Uint8Array | null)[]>;
|
|
34
|
+
kvListAll(actorId: string, options?: KvListOptions): Promise<[Uint8Array, Uint8Array][]>;
|
|
35
|
+
kvListRange(
|
|
36
|
+
actorId: string,
|
|
37
|
+
start: Uint8Array,
|
|
38
|
+
end: Uint8Array,
|
|
39
|
+
exclusive?: boolean,
|
|
40
|
+
options?: KvListOptions,
|
|
41
|
+
): Promise<[Uint8Array, Uint8Array][]>;
|
|
42
|
+
kvListPrefix(
|
|
43
|
+
actorId: string,
|
|
44
|
+
prefix: Uint8Array,
|
|
45
|
+
options?: KvListOptions,
|
|
46
|
+
): Promise<[Uint8Array, Uint8Array][]>;
|
|
47
|
+
kvPut(actorId: string, entries: [Uint8Array, Uint8Array][]): Promise<void>;
|
|
48
|
+
kvDelete(actorId: string, keys: Uint8Array[]): Promise<void>;
|
|
49
|
+
kvDeleteRange(actorId: string, start: Uint8Array, end: Uint8Array): Promise<void>;
|
|
50
|
+
kvDrop(actorId: string): Promise<void>;
|
|
51
|
+
restoreHibernatingRequests(
|
|
52
|
+
actorId: string,
|
|
53
|
+
metaEntries: HibernatingWebSocketMetadata[],
|
|
54
|
+
): void;
|
|
55
|
+
sendHibernatableWebSocketMessageAck(
|
|
56
|
+
gatewayId: ArrayBuffer,
|
|
57
|
+
requestId: ArrayBuffer,
|
|
58
|
+
clientMessageIndex: number,
|
|
59
|
+
): void;
|
|
60
|
+
startServerlessActor(payload: ArrayBuffer): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Matches the TS EnvoyConfig interface from @rivetkit/engine-envoy-client */
|
|
64
|
+
export interface EnvoyConfig {
|
|
65
|
+
logger?: any;
|
|
66
|
+
version: number;
|
|
67
|
+
endpoint: string;
|
|
68
|
+
token?: string;
|
|
69
|
+
namespace: string;
|
|
70
|
+
poolName: string;
|
|
71
|
+
prepopulateActorNames: Record<string, { metadata: Record<string, any> }>;
|
|
72
|
+
metadata?: Record<string, any>;
|
|
73
|
+
notGlobal?: boolean;
|
|
74
|
+
debugLatencyMs?: number;
|
|
75
|
+
serverlessStartPayload?: ArrayBuffer;
|
|
76
|
+
fetch: (
|
|
77
|
+
envoyHandle: EnvoyHandle,
|
|
78
|
+
actorId: string,
|
|
79
|
+
gatewayId: ArrayBuffer,
|
|
80
|
+
requestId: ArrayBuffer,
|
|
81
|
+
request: Request,
|
|
82
|
+
) => Promise<Response>;
|
|
83
|
+
websocket: (
|
|
84
|
+
envoyHandle: EnvoyHandle,
|
|
85
|
+
actorId: string,
|
|
86
|
+
ws: any,
|
|
87
|
+
gatewayId: ArrayBuffer,
|
|
88
|
+
requestId: ArrayBuffer,
|
|
89
|
+
request: Request,
|
|
90
|
+
path: string,
|
|
91
|
+
headers: Record<string, string>,
|
|
92
|
+
isHibernatable: boolean,
|
|
93
|
+
isRestoringHibernatable: boolean,
|
|
94
|
+
) => Promise<void>;
|
|
95
|
+
hibernatableWebSocket: {
|
|
96
|
+
canHibernate: (
|
|
97
|
+
actorId: string,
|
|
98
|
+
gatewayId: ArrayBuffer,
|
|
99
|
+
requestId: ArrayBuffer,
|
|
100
|
+
request: Request,
|
|
101
|
+
) => boolean;
|
|
102
|
+
};
|
|
103
|
+
onActorStart: (
|
|
104
|
+
envoyHandle: EnvoyHandle,
|
|
105
|
+
actorId: string,
|
|
106
|
+
generation: number,
|
|
107
|
+
config: import("@rivetkit/engine-envoy-protocol").ActorConfig,
|
|
108
|
+
preloadedKv: import("@rivetkit/engine-envoy-protocol").PreloadedKv | null,
|
|
109
|
+
) => Promise<void>;
|
|
110
|
+
onActorStop: (
|
|
111
|
+
envoyHandle: EnvoyHandle,
|
|
112
|
+
actorId: string,
|
|
113
|
+
generation: number,
|
|
114
|
+
reason: import("@rivetkit/engine-envoy-protocol").StopActorReason,
|
|
115
|
+
) => Promise<void>;
|
|
116
|
+
onShutdown: () => void;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Start the native envoy synchronously. Returns a handle immediately. */
|
|
120
|
+
export declare function startEnvoySync(config: EnvoyConfig): EnvoyHandle;
|
|
121
|
+
|
|
122
|
+
/** Start the native envoy and wait for it to be ready. */
|
|
123
|
+
export declare function startEnvoy(config: EnvoyConfig): Promise<EnvoyHandle>;
|
|
124
|
+
|
|
125
|
+
/** Open a native database backed by envoy KV for the specified actor. */
|
|
126
|
+
export declare function openDatabaseFromEnvoy(
|
|
127
|
+
handle: EnvoyHandle,
|
|
128
|
+
actorId: string,
|
|
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
|
+
|
|
144
|
+
export declare const utils: {};
|
package/wrapper.js
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin JS wrapper that adapts native callback envelopes to the
|
|
3
|
+
* EnvoyConfig callback shape used by the TypeScript envoy client.
|
|
4
|
+
*
|
|
5
|
+
* The native addon sends JSON envelopes with a "kind" field.
|
|
6
|
+
* This wrapper routes them to the appropriate EnvoyConfig callbacks.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const native = require("./index");
|
|
10
|
+
|
|
11
|
+
// Re-export protocol for consumers that need protocol types at runtime
|
|
12
|
+
let _protocol;
|
|
13
|
+
try {
|
|
14
|
+
_protocol = require("@rivetkit/engine-envoy-protocol");
|
|
15
|
+
} catch {
|
|
16
|
+
_protocol = {};
|
|
17
|
+
}
|
|
18
|
+
module.exports.protocol = _protocol;
|
|
19
|
+
module.exports.utils = {};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a wrapped EnvoyHandle that matches the TS EnvoyHandle interface.
|
|
23
|
+
*/
|
|
24
|
+
function wrapHandle(jsHandle) {
|
|
25
|
+
const handle = {
|
|
26
|
+
started: () => jsHandle.started(),
|
|
27
|
+
shutdown: (immediate) => jsHandle.shutdown(immediate ?? false),
|
|
28
|
+
getProtocolMetadata: () => undefined,
|
|
29
|
+
getEnvoyKey: () => jsHandle.envoyKey,
|
|
30
|
+
getActor: (_actorId, _generation) => undefined,
|
|
31
|
+
sleepActor: (actorId, generation) =>
|
|
32
|
+
jsHandle.sleepActor(actorId, generation ?? null),
|
|
33
|
+
stopActor: (actorId, generation, error) =>
|
|
34
|
+
jsHandle.stopActor(actorId, generation ?? null, error ?? null),
|
|
35
|
+
destroyActor: (actorId, generation) =>
|
|
36
|
+
jsHandle.destroyActor(actorId, generation ?? null),
|
|
37
|
+
setAlarm: (actorId, alarmTs, generation) =>
|
|
38
|
+
jsHandle.setAlarm(actorId, alarmTs ?? null, generation ?? null),
|
|
39
|
+
kvGet: async (actorId, keys) => {
|
|
40
|
+
const bufKeys = keys.map((k) => Buffer.from(k));
|
|
41
|
+
const result = await jsHandle.kvGet(actorId, bufKeys);
|
|
42
|
+
return result.map((v) => (v ? new Uint8Array(v) : null));
|
|
43
|
+
},
|
|
44
|
+
kvPut: async (actorId, entries) => {
|
|
45
|
+
const jsEntries = entries.map(([k, v]) => ({
|
|
46
|
+
key: Buffer.from(k),
|
|
47
|
+
value: Buffer.from(v),
|
|
48
|
+
}));
|
|
49
|
+
return jsHandle.kvPut(actorId, jsEntries);
|
|
50
|
+
},
|
|
51
|
+
kvDelete: async (actorId, keys) => {
|
|
52
|
+
const bufKeys = keys.map((k) => Buffer.from(k));
|
|
53
|
+
return jsHandle.kvDelete(actorId, bufKeys);
|
|
54
|
+
},
|
|
55
|
+
kvDeleteRange: async (actorId, start, end) => {
|
|
56
|
+
return jsHandle.kvDeleteRange(
|
|
57
|
+
actorId,
|
|
58
|
+
Buffer.from(start),
|
|
59
|
+
Buffer.from(end),
|
|
60
|
+
);
|
|
61
|
+
},
|
|
62
|
+
kvListAll: async (actorId, options) => {
|
|
63
|
+
const result = await jsHandle.kvListAll(actorId, options || null);
|
|
64
|
+
return result.map((e) => [new Uint8Array(e.key), new Uint8Array(e.value)]);
|
|
65
|
+
},
|
|
66
|
+
kvListRange: async (actorId, start, end, exclusive, options) => {
|
|
67
|
+
const result = await jsHandle.kvListRange(
|
|
68
|
+
actorId,
|
|
69
|
+
Buffer.from(start),
|
|
70
|
+
Buffer.from(end),
|
|
71
|
+
exclusive,
|
|
72
|
+
options || null,
|
|
73
|
+
);
|
|
74
|
+
return result.map((e) => [new Uint8Array(e.key), new Uint8Array(e.value)]);
|
|
75
|
+
},
|
|
76
|
+
kvListPrefix: async (actorId, prefix, options) => {
|
|
77
|
+
const result = await jsHandle.kvListPrefix(
|
|
78
|
+
actorId,
|
|
79
|
+
Buffer.from(prefix),
|
|
80
|
+
options || null,
|
|
81
|
+
);
|
|
82
|
+
return result.map((e) => [new Uint8Array(e.key), new Uint8Array(e.value)]);
|
|
83
|
+
},
|
|
84
|
+
kvDrop: (actorId) => jsHandle.kvDrop(actorId),
|
|
85
|
+
restoreHibernatingRequests: (actorId, metaEntries) => {
|
|
86
|
+
const requests = (metaEntries || []).map((e) => ({
|
|
87
|
+
gatewayId: Buffer.from(e.gatewayId),
|
|
88
|
+
requestId: Buffer.from(e.requestId),
|
|
89
|
+
}));
|
|
90
|
+
jsHandle.restoreHibernatingRequests(actorId, requests);
|
|
91
|
+
},
|
|
92
|
+
sendHibernatableWebSocketMessageAck: (
|
|
93
|
+
gatewayId,
|
|
94
|
+
requestId,
|
|
95
|
+
clientMessageIndex,
|
|
96
|
+
) =>
|
|
97
|
+
jsHandle.sendHibernatableWebSocketMessageAck(
|
|
98
|
+
Buffer.from(gatewayId),
|
|
99
|
+
Buffer.from(requestId),
|
|
100
|
+
clientMessageIndex,
|
|
101
|
+
),
|
|
102
|
+
startServerlessActor: (payload) => {
|
|
103
|
+
jsHandle.startServerless(Buffer.from(payload));
|
|
104
|
+
},
|
|
105
|
+
// Internal: expose raw handle for openDatabaseFromEnvoy
|
|
106
|
+
_raw: jsHandle,
|
|
107
|
+
};
|
|
108
|
+
return handle;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Start the native envoy synchronously with EnvoyConfig callbacks.
|
|
113
|
+
* Returns a wrapped handle matching the TS EnvoyHandle interface.
|
|
114
|
+
*/
|
|
115
|
+
function startEnvoySync(config) {
|
|
116
|
+
const wrappedHandle = { current: null };
|
|
117
|
+
|
|
118
|
+
const jsHandle = native.startEnvoySyncJs(
|
|
119
|
+
{
|
|
120
|
+
endpoint: config.endpoint,
|
|
121
|
+
token: config.token || "",
|
|
122
|
+
namespace: config.namespace,
|
|
123
|
+
poolName: config.poolName,
|
|
124
|
+
version: config.version,
|
|
125
|
+
metadata: config.metadata || null,
|
|
126
|
+
notGlobal: config.notGlobal ?? false,
|
|
127
|
+
},
|
|
128
|
+
(event) => {
|
|
129
|
+
handleEvent(event, config, wrappedHandle);
|
|
130
|
+
},
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const handle = wrapHandle(jsHandle);
|
|
134
|
+
wrappedHandle.current = handle;
|
|
135
|
+
return handle;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Start the native envoy and wait for it to be ready.
|
|
140
|
+
*/
|
|
141
|
+
async function startEnvoy(config) {
|
|
142
|
+
const handle = startEnvoySync(config);
|
|
143
|
+
await handle.started();
|
|
144
|
+
return handle;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Open a native database backed by envoy KV.
|
|
149
|
+
*/
|
|
150
|
+
async function openDatabaseFromEnvoy(handle, actorId) {
|
|
151
|
+
const rawHandle = handle._raw || handle;
|
|
152
|
+
return native.openDatabaseFromEnvoy(rawHandle, actorId);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Route callback envelopes from the native addon to EnvoyConfig callbacks.
|
|
157
|
+
*/
|
|
158
|
+
function handleEvent(event, config, wrappedHandle) {
|
|
159
|
+
const handle = wrappedHandle.current;
|
|
160
|
+
|
|
161
|
+
switch (event.kind) {
|
|
162
|
+
case "actor_start": {
|
|
163
|
+
const input = event.input ? Buffer.from(event.input, "base64") : undefined;
|
|
164
|
+
const actorConfig = {
|
|
165
|
+
name: event.name,
|
|
166
|
+
key: event.key || undefined,
|
|
167
|
+
createTs: event.createTs,
|
|
168
|
+
input,
|
|
169
|
+
};
|
|
170
|
+
Promise.resolve(
|
|
171
|
+
config.onActorStart(
|
|
172
|
+
handle,
|
|
173
|
+
event.actorId,
|
|
174
|
+
event.generation,
|
|
175
|
+
actorConfig,
|
|
176
|
+
null, // preloadedKv
|
|
177
|
+
),
|
|
178
|
+
).then(
|
|
179
|
+
() => {
|
|
180
|
+
if (handle._raw) {
|
|
181
|
+
handle._raw.respondCallback(event.responseId, {});
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
(err) => {
|
|
185
|
+
console.error("onActorStart error:", err);
|
|
186
|
+
if (handle._raw) {
|
|
187
|
+
handle._raw.respondCallback(event.responseId, {
|
|
188
|
+
error: String(err),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
case "actor_stop": {
|
|
196
|
+
Promise.resolve(
|
|
197
|
+
config.onActorStop(
|
|
198
|
+
handle,
|
|
199
|
+
event.actorId,
|
|
200
|
+
event.generation,
|
|
201
|
+
event.reason || "stopped",
|
|
202
|
+
),
|
|
203
|
+
).then(
|
|
204
|
+
() => {
|
|
205
|
+
if (handle._raw) {
|
|
206
|
+
handle._raw.respondCallback(event.responseId, {});
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
(err) => {
|
|
210
|
+
console.error("onActorStop error:", err);
|
|
211
|
+
if (handle._raw) {
|
|
212
|
+
handle._raw.respondCallback(event.responseId, {
|
|
213
|
+
error: String(err),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case "http_request": {
|
|
221
|
+
const body = event.body ? Buffer.from(event.body, "base64") : undefined;
|
|
222
|
+
const messageId = Buffer.from(event.messageId);
|
|
223
|
+
const gatewayId = messageId.subarray(0, 4);
|
|
224
|
+
const requestId = messageId.subarray(4, 8);
|
|
225
|
+
|
|
226
|
+
// Build a Request object matching the TS envoy-client interface
|
|
227
|
+
const headers = new Headers(event.headers || {});
|
|
228
|
+
const url = `http://actor${event.path}`;
|
|
229
|
+
const request = new Request(url, {
|
|
230
|
+
method: event.method,
|
|
231
|
+
headers,
|
|
232
|
+
body: body || undefined,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
Promise.resolve(
|
|
236
|
+
config.fetch(handle, event.actorId, gatewayId, requestId, request),
|
|
237
|
+
).then(
|
|
238
|
+
async (response) => {
|
|
239
|
+
if (handle._raw && response) {
|
|
240
|
+
const respHeaders = {};
|
|
241
|
+
if (response.headers) {
|
|
242
|
+
response.headers.forEach((value, key) => {
|
|
243
|
+
respHeaders[key] = value;
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
const respBody = response.body
|
|
247
|
+
? Buffer.from(await response.arrayBuffer()).toString("base64")
|
|
248
|
+
: undefined;
|
|
249
|
+
handle._raw.respondCallback(event.responseId, {
|
|
250
|
+
status: response.status || 200,
|
|
251
|
+
headers: respHeaders,
|
|
252
|
+
body: respBody,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
(err) => {
|
|
257
|
+
console.error("fetch callback error:", err);
|
|
258
|
+
if (handle._raw) {
|
|
259
|
+
handle._raw.respondCallback(event.responseId, {
|
|
260
|
+
status: 500,
|
|
261
|
+
headers: { "content-type": "text/plain" },
|
|
262
|
+
body: Buffer.from(String(err)).toString("base64"),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
case "websocket_open": {
|
|
270
|
+
if (config.websocket) {
|
|
271
|
+
const messageId = Buffer.from(event.messageId);
|
|
272
|
+
const gatewayId = messageId.subarray(0, 4);
|
|
273
|
+
const requestId = messageId.subarray(4, 8);
|
|
274
|
+
const wsIdHex = gatewayId.toString("hex") + requestId.toString("hex");
|
|
275
|
+
|
|
276
|
+
const headers = new Headers(event.headers || {});
|
|
277
|
+
headers.set("Upgrade", "websocket");
|
|
278
|
+
headers.set("Connection", "Upgrade");
|
|
279
|
+
const url = `http://actor${event.path}`;
|
|
280
|
+
const request = new Request(url, {
|
|
281
|
+
method: "GET",
|
|
282
|
+
headers,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Create a WebSocket-like object backed by EventTarget.
|
|
286
|
+
// The EngineActorDriver calls addEventListener on this.
|
|
287
|
+
// Events are dispatched when native websocket_message/close events arrive.
|
|
288
|
+
const target = new EventTarget();
|
|
289
|
+
const OPEN = 1;
|
|
290
|
+
const CLOSED = 3;
|
|
291
|
+
const ws = Object.create(target, {
|
|
292
|
+
readyState: { value: OPEN, writable: true },
|
|
293
|
+
OPEN: { value: OPEN },
|
|
294
|
+
CLOSED: { value: CLOSED },
|
|
295
|
+
send: {
|
|
296
|
+
value: (data) => {
|
|
297
|
+
if (handle._raw) {
|
|
298
|
+
const isBinary =
|
|
299
|
+
data instanceof ArrayBuffer || ArrayBuffer.isView(data);
|
|
300
|
+
const bytes = isBinary
|
|
301
|
+
? Buffer.from(data instanceof ArrayBuffer ? data : data.buffer, data instanceof ArrayBuffer ? 0 : data.byteOffset, data instanceof ArrayBuffer ? data.byteLength : data.byteLength)
|
|
302
|
+
: Buffer.from(String(data));
|
|
303
|
+
handle._raw.sendWsMessage(gatewayId, requestId, bytes, isBinary);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
close: {
|
|
308
|
+
value: (code, reason) => {
|
|
309
|
+
ws.readyState = CLOSED;
|
|
310
|
+
if (handle._raw) {
|
|
311
|
+
handle._raw.closeWebsocket(
|
|
312
|
+
gatewayId,
|
|
313
|
+
requestId,
|
|
314
|
+
code != null ? code : undefined,
|
|
315
|
+
reason != null ? String(reason) : undefined,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
addEventListener: { value: target.addEventListener.bind(target) },
|
|
321
|
+
removeEventListener: { value: target.removeEventListener.bind(target) },
|
|
322
|
+
dispatchEvent: { value: target.dispatchEvent.bind(target) },
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Store the ws object so websocket_message/close events can dispatch to it
|
|
326
|
+
if (!handle._wsMap) handle._wsMap = new Map();
|
|
327
|
+
handle._wsMap.set(wsIdHex, ws);
|
|
328
|
+
|
|
329
|
+
const canHibernate = config.hibernatableWebSocket
|
|
330
|
+
? config.hibernatableWebSocket.canHibernate(
|
|
331
|
+
event.actorId,
|
|
332
|
+
gatewayId,
|
|
333
|
+
requestId,
|
|
334
|
+
request,
|
|
335
|
+
)
|
|
336
|
+
: false;
|
|
337
|
+
|
|
338
|
+
console.log("[wrapper] websocket_open actorId:", event.actorId?.slice(0, 12), "path:", event.path);
|
|
339
|
+
Promise.resolve(
|
|
340
|
+
config.websocket(
|
|
341
|
+
handle,
|
|
342
|
+
event.actorId,
|
|
343
|
+
ws,
|
|
344
|
+
gatewayId,
|
|
345
|
+
requestId,
|
|
346
|
+
request,
|
|
347
|
+
event.path,
|
|
348
|
+
event.headers || {},
|
|
349
|
+
canHibernate,
|
|
350
|
+
false,
|
|
351
|
+
),
|
|
352
|
+
).then(() => {
|
|
353
|
+
console.log("[wrapper] websocket callback resolved, dispatching open event");
|
|
354
|
+
ws.dispatchEvent(new Event("open"));
|
|
355
|
+
console.log("[wrapper] open event dispatched");
|
|
356
|
+
}).catch((err) => {
|
|
357
|
+
console.error("[wrapper] websocket callback error:", err);
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
case "websocket_message": {
|
|
363
|
+
if (handle._wsMap && event.messageId) {
|
|
364
|
+
const messageId = Buffer.from(event.messageId);
|
|
365
|
+
const gatewayId = messageId.subarray(0, 4);
|
|
366
|
+
const requestId = messageId.subarray(4, 8);
|
|
367
|
+
const wsIdHex = gatewayId.toString("hex") + requestId.toString("hex");
|
|
368
|
+
|
|
369
|
+
const ws = handle._wsMap.get(wsIdHex);
|
|
370
|
+
|
|
371
|
+
if (ws) {
|
|
372
|
+
const data = event.data
|
|
373
|
+
? (event.binary
|
|
374
|
+
? Buffer.from(event.data, "base64")
|
|
375
|
+
: Buffer.from(event.data, "base64").toString())
|
|
376
|
+
: "";
|
|
377
|
+
const msgEvent = new MessageEvent("message", { data });
|
|
378
|
+
msgEvent.rivetGatewayId = messageId.subarray(0, 4);
|
|
379
|
+
msgEvent.rivetRequestId = messageId.subarray(4, 8);
|
|
380
|
+
msgEvent.rivetMessageIndex = messageId.readUint16LE(8);
|
|
381
|
+
ws.dispatchEvent(msgEvent);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
case "websocket_close": {
|
|
387
|
+
if (handle._wsMap && event.messageId) {
|
|
388
|
+
const messageId = Buffer.from(event.messageId);
|
|
389
|
+
const gatewayId = messageId.subarray(0, 4);
|
|
390
|
+
const requestId = messageId.subarray(4, 8);
|
|
391
|
+
const wsIdHex = gatewayId.toString("hex") + requestId.toString("hex");
|
|
392
|
+
|
|
393
|
+
const ws = handle._wsMap.get(wsIdHex);
|
|
394
|
+
if (ws) {
|
|
395
|
+
ws.readyState = 3;
|
|
396
|
+
ws.dispatchEvent(new CloseEvent("close", {
|
|
397
|
+
code: event.code || 1000,
|
|
398
|
+
reason: event.reason || "",
|
|
399
|
+
}));
|
|
400
|
+
handle._wsMap.delete(wsIdHex);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
case "hibernation_restore":
|
|
406
|
+
case "alarm":
|
|
407
|
+
case "wake":
|
|
408
|
+
break;
|
|
409
|
+
case "shutdown": {
|
|
410
|
+
if (config.onShutdown) {
|
|
411
|
+
config.onShutdown();
|
|
412
|
+
}
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
default:
|
|
416
|
+
console.warn("unknown native event kind:", event.kind);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
module.exports.startEnvoy = startEnvoy;
|
|
421
|
+
module.exports.startEnvoySync = startEnvoySync;
|
|
422
|
+
module.exports.openDatabaseFromEnvoy = openDatabaseFromEnvoy;
|