@c9up/ream 0.2.3 → 0.2.5
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/Application.d.ts +85 -5
- package/dist/Application.d.ts.map +1 -1
- package/dist/Application.js +171 -21
- package/dist/Application.js.map +1 -1
- package/dist/ErrorBoundary.d.ts +1 -7
- package/dist/ErrorBoundary.d.ts.map +1 -1
- package/dist/ErrorBoundary.js +31 -31
- package/dist/ErrorBoundary.js.map +1 -1
- package/dist/Ignitor.d.ts +15 -46
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +178 -173
- package/dist/Ignitor.js.map +1 -1
- package/dist/env/Env.d.ts +6 -0
- package/dist/env/Env.d.ts.map +1 -1
- package/dist/env/Env.js +6 -0
- package/dist/env/Env.js.map +1 -1
- package/dist/events/Emitter.d.ts +2 -6
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +45 -42
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/native.d.ts +13 -11
- package/dist/events/native.d.ts.map +1 -1
- package/dist/events/native.js.map +1 -1
- package/dist/http/HttpContext.d.ts +1 -1
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/Request.js +0 -13
- package/dist/http/Request.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/native/generated.d.ts +243 -0
- package/dist/native/generated.d.ts.map +1 -0
- package/dist/native/generated.js +7 -0
- package/dist/native/generated.js.map +1 -0
- package/dist/session/drivers/CookieDriver.d.ts +1 -1
- package/dist/session/drivers/CookieDriver.d.ts.map +1 -1
- package/dist/session/drivers/CookieDriver.js +4 -4
- package/dist/session/drivers/CookieDriver.js.map +1 -1
- package/dist/types/index.d.ts +88 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +8 -3
- package/dist/types/index.js.map +1 -1
- package/events.win32-x64-msvc.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +3 -2
- package/scheduler.win32-x64-msvc.node +0 -0
- package/scripts/build-napi-types.mjs +68 -0
- package/scripts/generate-napi-types.mjs +171 -0
- package/src/Application.ts +221 -21
- package/src/ErrorBoundary.ts +31 -31
- package/src/Ignitor.ts +185 -172
- package/src/env/Env.ts +6 -0
- package/src/events/Emitter.ts +45 -42
- package/src/events/native.ts +21 -14
- package/src/http/HttpContext.ts +1 -1
- package/src/http/Request.ts +0 -13
- package/src/index.ts +2 -2
- package/src/native/generated.ts +291 -0
- package/src/session/drivers/CookieDriver.ts +4 -4
- package/src/types/index.ts +92 -5
- package/dist/types/authenticators.d.ts +0 -24
- package/dist/types/authenticators.d.ts.map +0 -1
- package/dist/types/authenticators.js +0 -2
- package/dist/types/authenticators.js.map +0 -1
- package/dist/types/container.d.ts +0 -64
- package/dist/types/container.d.ts.map +0 -1
- package/dist/types/container.js +0 -23
- package/dist/types/container.js.map +0 -1
- package/src/types/authenticators.ts +0 -24
- package/src/types/container.ts +0 -66
package/src/env/Env.ts
CHANGED
|
@@ -68,6 +68,12 @@ export class Env<Values extends Record<string, unknown>> {
|
|
|
68
68
|
|
|
69
69
|
readonly #values: Values
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Private on purpose: an `Env` is only ever built by {@link create}, which is
|
|
73
|
+
* what validates. `private` and not `#` because a private CONSTRUCTOR has no
|
|
74
|
+
* native form — this is the one place the keyword carries a meaning `#`
|
|
75
|
+
* cannot express.
|
|
76
|
+
*/
|
|
71
77
|
private constructor(values: Values) {
|
|
72
78
|
this.#values = values
|
|
73
79
|
}
|
package/src/events/Emitter.ts
CHANGED
|
@@ -66,10 +66,10 @@ export type UnsubscribeFunction = () => void
|
|
|
66
66
|
export type AsyncUnsubscribeFunction = () => Promise<void>
|
|
67
67
|
|
|
68
68
|
export class Emitter {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
#bus: EventBus
|
|
70
|
+
#resolver?: EmitterResolver
|
|
71
|
+
#classListeners: Map<EventConstructor, Listener[]> = new Map()
|
|
72
|
+
#stringListeners: Map<string, ListenerFn[]> = new Map()
|
|
73
73
|
/** Set while faking; every emission lands here instead of running. */
|
|
74
74
|
#buffer?: EventsBuffer
|
|
75
75
|
/** Which events are faked. `undefined` means all of them. */
|
|
@@ -78,8 +78,8 @@ export class Emitter {
|
|
|
78
78
|
readonly #anySubscriptions = new Map<(eventName: string, data: unknown) => void, Set<number>>()
|
|
79
79
|
|
|
80
80
|
constructor(bus: EventBus, resolver?: EmitterResolver) {
|
|
81
|
-
this
|
|
82
|
-
this
|
|
81
|
+
this.#bus = bus
|
|
82
|
+
this.#resolver = resolver
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// ─── Class-based events ───────────────────────────────────
|
|
@@ -102,18 +102,18 @@ export class Emitter {
|
|
|
102
102
|
on<T>(event: string, listener: ListenerFn<T>): UnsubscribeFunction
|
|
103
103
|
on(event: EventConstructor | string, listener: Listener): UnsubscribeFunction {
|
|
104
104
|
if (typeof event === 'string') {
|
|
105
|
-
const list = this
|
|
105
|
+
const list = this.#stringListeners.get(event) ?? []
|
|
106
106
|
list.push(listener as ListenerFn)
|
|
107
|
-
this
|
|
107
|
+
this.#stringListeners.set(event, list)
|
|
108
108
|
return () => {
|
|
109
109
|
this.off(event, listener as ListenerFn)
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
const list = this
|
|
112
|
+
const list = this.#classListeners.get(event) ?? []
|
|
113
113
|
list.push(listener)
|
|
114
|
-
this
|
|
114
|
+
this.#classListeners.set(event, list)
|
|
115
115
|
return () => {
|
|
116
|
-
const current = this
|
|
116
|
+
const current = this.#classListeners.get(event)
|
|
117
117
|
if (!current) return
|
|
118
118
|
const index = current.indexOf(listener)
|
|
119
119
|
if (index !== -1) current.splice(index, 1)
|
|
@@ -159,11 +159,11 @@ export class Emitter {
|
|
|
159
159
|
|
|
160
160
|
/** Remove one listener from an event (AdonisJS `off`). */
|
|
161
161
|
off(event: string, listener: ListenerFn): void {
|
|
162
|
-
const list = this
|
|
162
|
+
const list = this.#stringListeners.get(event)
|
|
163
163
|
if (!list) return
|
|
164
164
|
const index = list.indexOf(listener)
|
|
165
165
|
if (index !== -1) list.splice(index, 1)
|
|
166
|
-
if (list.length === 0) this
|
|
166
|
+
if (list.length === 0) this.#stringListeners.delete(event)
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/** Alias of {@link off} (AdonisJS `clearListener`). */
|
|
@@ -173,13 +173,13 @@ export class Emitter {
|
|
|
173
173
|
|
|
174
174
|
/** Drop every listener of one event (AdonisJS `clearListeners`). */
|
|
175
175
|
clearListeners(event: string): void {
|
|
176
|
-
this
|
|
176
|
+
this.#stringListeners.delete(event)
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
/** Drop every listener of every event (AdonisJS `clearAllListeners`). */
|
|
180
180
|
clearAllListeners(): void {
|
|
181
|
-
this
|
|
182
|
-
this
|
|
181
|
+
this.#stringListeners.clear()
|
|
182
|
+
this.#classListeners.clear()
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
/**
|
|
@@ -191,17 +191,17 @@ export class Emitter {
|
|
|
191
191
|
*/
|
|
192
192
|
get eventsListeners(): Map<EventConstructor | string, Listener[]> {
|
|
193
193
|
const all = new Map<EventConstructor | string, Listener[]>()
|
|
194
|
-
for (const [event, listeners] of this
|
|
195
|
-
for (const [event, listeners] of this
|
|
194
|
+
for (const [event, listeners] of this.#classListeners) all.set(event, [...listeners])
|
|
195
|
+
for (const [event, listeners] of this.#stringListeners) all.set(event, [...listeners])
|
|
196
196
|
return all
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/** How many listeners an event has, or all of them (AdonisJS `listenerCount`). */
|
|
200
200
|
listenerCount(event?: string): number {
|
|
201
|
-
if (event !== undefined) return this
|
|
201
|
+
if (event !== undefined) return this.#stringListeners.get(event)?.length ?? 0
|
|
202
202
|
let total = 0
|
|
203
|
-
for (const list of this
|
|
204
|
-
for (const list of this
|
|
203
|
+
for (const list of this.#stringListeners.values()) total += list.length
|
|
204
|
+
for (const list of this.#classListeners.values()) total += list.length
|
|
205
205
|
return total
|
|
206
206
|
}
|
|
207
207
|
|
|
@@ -216,7 +216,7 @@ export class Emitter {
|
|
|
216
216
|
*/
|
|
217
217
|
async #dispatchListeners(event: string, data: unknown, serial: boolean): Promise<void> {
|
|
218
218
|
const listeners = [
|
|
219
|
-
...(this
|
|
219
|
+
...(this.#stringListeners.get(event) ?? []),
|
|
220
220
|
...this.#wildcardListenersFor(event),
|
|
221
221
|
]
|
|
222
222
|
if (listeners.length === 0) return
|
|
@@ -224,7 +224,7 @@ export class Emitter {
|
|
|
224
224
|
try {
|
|
225
225
|
await fn(data)
|
|
226
226
|
} catch (err) {
|
|
227
|
-
this
|
|
227
|
+
this.#emitError(event, err)
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
if (serial) {
|
|
@@ -281,17 +281,17 @@ export class Emitter {
|
|
|
281
281
|
try {
|
|
282
282
|
payload = JSON.stringify(this.#wrapForBus(data))
|
|
283
283
|
} catch (err) {
|
|
284
|
-
this
|
|
284
|
+
this.#emitError(event, err)
|
|
285
285
|
return
|
|
286
286
|
}
|
|
287
|
-
void this
|
|
288
|
-
this
|
|
287
|
+
void this.#bus.emit(event, payload).catch((err: unknown) => {
|
|
288
|
+
this.#emitError(event, err)
|
|
289
289
|
})
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
/** Emit an error event for listener failures. */
|
|
293
|
-
|
|
294
|
-
const errorListeners = this
|
|
293
|
+
#emitError(event: string, error: unknown): void {
|
|
294
|
+
const errorListeners = this.#stringListeners.get('emitter:error')
|
|
295
295
|
if (errorListeners && errorListeners.length > 0) {
|
|
296
296
|
for (const fn of errorListeners) {
|
|
297
297
|
try {
|
|
@@ -314,7 +314,7 @@ export class Emitter {
|
|
|
314
314
|
// Faked by the class, as AdonisJS does — `fake([TaskDeclared])` catches
|
|
315
315
|
// `new TaskDeclared(...).emit()`.
|
|
316
316
|
if (this.#capture(EventClass, event)) return
|
|
317
|
-
const listeners = this
|
|
317
|
+
const listeners = this.#classListeners.get(EventClass) ?? []
|
|
318
318
|
const name = (EventClass as { eventName?: string }).eventName ?? classToEventName(EventClass)
|
|
319
319
|
|
|
320
320
|
// Per-listener error isolation — mirrors the string `emit()` contract.
|
|
@@ -326,22 +326,22 @@ export class Emitter {
|
|
|
326
326
|
try {
|
|
327
327
|
if (isListenerClass(listener)) {
|
|
328
328
|
// Listener class — resolve via container for @inject() support
|
|
329
|
-
const instance = this
|
|
330
|
-
? await this
|
|
329
|
+
const instance = this.#resolver
|
|
330
|
+
? await this.#resolver.make(listener as ListenerConstructor<T>)
|
|
331
331
|
: new (listener as ListenerConstructor<T>)()
|
|
332
332
|
await instance.handle(event)
|
|
333
333
|
} else {
|
|
334
334
|
await (listener as ListenerFn<T>)(event)
|
|
335
335
|
}
|
|
336
336
|
} catch (err) {
|
|
337
|
-
this
|
|
337
|
+
this.#emitError(name, err)
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
// Also push through EventBus — same correlation-envelope wrapping as
|
|
342
342
|
// the string-event path so distributed tracing covers class events too.
|
|
343
343
|
// Reached unconditionally: a listener failure above no longer skips it.
|
|
344
|
-
await this
|
|
344
|
+
await this.#bus.emit(name, JSON.stringify(this.#wrapForBus(event)))
|
|
345
345
|
}
|
|
346
346
|
|
|
347
347
|
// ─── Faking (AdonisJS `fake` / `restore`) ─────────────────
|
|
@@ -436,7 +436,7 @@ export class Emitter {
|
|
|
436
436
|
pattern: string,
|
|
437
437
|
listener: (eventName: string, data: unknown) => void,
|
|
438
438
|
): Promise<number> {
|
|
439
|
-
return this
|
|
439
|
+
return this.#bus.subscribe(pattern, (eventJson: string) => {
|
|
440
440
|
try {
|
|
441
441
|
const event = JSON.parse(eventJson)
|
|
442
442
|
// The bus delivers a Rust `Event` envelope whose `correlationId`
|
|
@@ -471,7 +471,7 @@ export class Emitter {
|
|
|
471
471
|
*/
|
|
472
472
|
async offAny(listenerOrId: number | ((eventName: string, data: unknown) => void)): Promise<this> {
|
|
473
473
|
if (typeof listenerOrId === 'number') {
|
|
474
|
-
await this
|
|
474
|
+
await this.#bus.unsubscribe(listenerOrId)
|
|
475
475
|
for (const ids of this.#anySubscriptions.values()) ids.delete(listenerOrId)
|
|
476
476
|
return this
|
|
477
477
|
}
|
|
@@ -479,13 +479,13 @@ export class Emitter {
|
|
|
479
479
|
const ids = this.#anySubscriptions.get(listenerOrId)
|
|
480
480
|
if (!ids) return this
|
|
481
481
|
this.#anySubscriptions.delete(listenerOrId)
|
|
482
|
-
await Promise.all([...ids].map((id) => this
|
|
482
|
+
await Promise.all([...ids].map((id) => this.#bus.unsubscribe(id)))
|
|
483
483
|
return this
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
/** Check if a pattern matches an event name (wildcard matching via Rust). */
|
|
487
487
|
matchesPattern(pattern: string, eventName: string): boolean {
|
|
488
|
-
return this
|
|
488
|
+
return this.#bus.matchesWildcard(pattern, eventName)
|
|
489
489
|
}
|
|
490
490
|
|
|
491
491
|
// ─── Request / Reply ──────────────────────────────────────
|
|
@@ -499,7 +499,7 @@ export class Emitter {
|
|
|
499
499
|
// Same correlation injection as `emit()` so a `setCorrelationId`
|
|
500
500
|
// preceding a request actually reaches the responder via the
|
|
501
501
|
// top-level `correlationId` field on the parsed payload.
|
|
502
|
-
const result = await this
|
|
502
|
+
const result = await this.#bus.request(name, JSON.stringify(this.#wrapForBus(data)), timeoutMs)
|
|
503
503
|
try {
|
|
504
504
|
return JSON.parse(result) as T
|
|
505
505
|
} catch {
|
|
@@ -519,7 +519,7 @@ export class Emitter {
|
|
|
519
519
|
name: string,
|
|
520
520
|
handler: (eventJson: string, reply: (response: string) => void) => void,
|
|
521
521
|
): void {
|
|
522
|
-
this
|
|
522
|
+
this.#bus.onRequest(name, handler)
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
// ─── Correlation context ──────────────────────────────────
|
|
@@ -565,13 +565,13 @@ export class Emitter {
|
|
|
565
565
|
// AdonisJS makes the argument optional: no argument asks whether ANY event
|
|
566
566
|
// has a listener at all.
|
|
567
567
|
if (event === undefined) return this.listenerCount() > 0
|
|
568
|
-
if (typeof event === 'string') return (this
|
|
569
|
-
return (this
|
|
568
|
+
if (typeof event === 'string') return (this.#stringListeners.get(event)?.length ?? 0) > 0
|
|
569
|
+
return (this.#classListeners.get(event)?.length ?? 0) > 0
|
|
570
570
|
}
|
|
571
571
|
|
|
572
572
|
/** Get the number of Rust-side subscriptions. */
|
|
573
573
|
async subscriptionCount(): Promise<number> {
|
|
574
|
-
return this
|
|
574
|
+
return this.#bus.subscriptionCount()
|
|
575
575
|
}
|
|
576
576
|
}
|
|
577
577
|
|
|
@@ -593,7 +593,10 @@ export class BaseEvent {
|
|
|
593
593
|
/**
|
|
594
594
|
* Subclasses declare their own payload parameters; this signature only has
|
|
595
595
|
* to be wide enough for `dispatch` to forward them (AdonisJS does the same).
|
|
596
|
+
* It widens `ConstructorParameters<typeof BaseEvent>` from `[]` to a rest
|
|
597
|
+
* parameter, which is what lets `dispatch` call `new this(...args)`.
|
|
596
598
|
*/
|
|
599
|
+
// biome-ignore lint/complexity/noUselessConstructor: it widens ConstructorParameters for dispatch — removing it fails to compile
|
|
597
600
|
constructor(..._args: unknown[]) {}
|
|
598
601
|
|
|
599
602
|
static eventName?: string
|
package/src/events/native.ts
CHANGED
|
@@ -10,22 +10,28 @@
|
|
|
10
10
|
|
|
11
11
|
import { loadNapi } from '../helpers/napi-loader.js'
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
subscriptionCount(): Promise<number>
|
|
25
|
-
}
|
|
13
|
+
/**
|
|
14
|
+
* Rust-backed bus surface.
|
|
15
|
+
*
|
|
16
|
+
* Re-exported from the generated declarations rather than restated here: the
|
|
17
|
+
* shape is derived from the `#[napi]` items themselves, so it cannot drift
|
|
18
|
+
* from the Rust. It did before — making `Bus::on_request` synchronous changed
|
|
19
|
+
* the Rust with nothing on this side to notice.
|
|
20
|
+
*
|
|
21
|
+
* Run `pnpm build:napi-types` after touching a `#[napi]` signature.
|
|
22
|
+
*/
|
|
23
|
+
import type { EventBus as NativeEventBus } from '../native/generated.js'
|
|
26
24
|
|
|
25
|
+
/**
|
|
26
|
+
* What the `events` binary exports.
|
|
27
|
+
*
|
|
28
|
+
* The instance shape comes from the generated declarations — derived from the
|
|
29
|
+
* `#[napi]` items, so it cannot drift from the Rust without the generated file
|
|
30
|
+
* changing. Only the constructor is named here, because the binary is a module
|
|
31
|
+
* object rather than a class the loader can see.
|
|
32
|
+
*/
|
|
27
33
|
interface EventsNative {
|
|
28
|
-
EventBus: new (requestHandlerTimeoutMs?: number) =>
|
|
34
|
+
EventBus: new (requestHandlerTimeoutMs?: number) => NativeEventBus
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
const native = loadNapi<EventsNative>({
|
|
@@ -35,3 +41,4 @@ const native = loadNapi<EventsNative>({
|
|
|
35
41
|
})
|
|
36
42
|
|
|
37
43
|
export const EventBus = native.EventBus
|
|
44
|
+
export type EventBus = NativeEventBus
|
package/src/http/HttpContext.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { MatchedParams } from '../router/Router.js'
|
|
|
14
14
|
import type { CookieSigner } from '../security/CookieSigner.js'
|
|
15
15
|
import type { SignedUrl } from '../security/SignedUrl.js'
|
|
16
16
|
import type { Session } from '../session/Session.js'
|
|
17
|
-
import type { Authenticators } from '../types/
|
|
17
|
+
import type { Authenticators } from '../types/index.js'
|
|
18
18
|
import { Macroable } from '../utils/Macroable.js'
|
|
19
19
|
import type { RouteUrlResolver } from './RedirectBuilder.js'
|
|
20
20
|
import { RedirectBuilder } from './RedirectBuilder.js'
|
package/src/http/Request.ts
CHANGED
|
@@ -1004,19 +1004,6 @@ function isIpLiteral(host: string): boolean {
|
|
|
1004
1004
|
return /^(\d{1,3}\.){3}\d{1,3}$/.test(host)
|
|
1005
1005
|
}
|
|
1006
1006
|
|
|
1007
|
-
/**
|
|
1008
|
-
* Decode a percent-encoded segment without throwing on malformed input.
|
|
1009
|
-
* Browsers happily send `q=%E0%A4%A` (truncated UTF-8 sequences) — refusing
|
|
1010
|
-
* the whole request would let any client knock the route handler offline.
|
|
1011
|
-
*/
|
|
1012
|
-
function safeDecode(value: string): string {
|
|
1013
|
-
try {
|
|
1014
|
-
return decodeURIComponent(value)
|
|
1015
|
-
} catch {
|
|
1016
|
-
return value
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
1007
|
interface AcceptEntry {
|
|
1021
1008
|
value: string
|
|
1022
1009
|
q: number
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import 'reflect-metadata'
|
|
|
8
8
|
|
|
9
9
|
// ─── Core ───────────────────────────────────────────────────
|
|
10
10
|
|
|
11
|
+
export type { AppEnvironment, ApplicationMode, ApplicationState } from './Application.js'
|
|
11
12
|
export { Application } from './Application.js'
|
|
12
13
|
export { ConfigStore, configProvider, defineModuleConfig, env } from './ConfigLoader.js'
|
|
13
14
|
export { Container } from './container/Container.js'
|
|
@@ -242,7 +243,6 @@ export type {
|
|
|
242
243
|
FlagMetaData,
|
|
243
244
|
} from './console/types.js'
|
|
244
245
|
export type {
|
|
245
|
-
AppEnvironment,
|
|
246
246
|
HyperServerLike,
|
|
247
247
|
IgnitorConfig,
|
|
248
248
|
ReamrcConfig,
|
|
@@ -371,4 +371,4 @@ export {
|
|
|
371
371
|
StatsTracker,
|
|
372
372
|
} from './scheduler/index.js'
|
|
373
373
|
|
|
374
|
-
export const VERSION = '0.2.
|
|
374
|
+
export const VERSION = '0.2.5'
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// GENERATED FROM THE RUST — do not edit.
|
|
2
|
+
//
|
|
3
|
+
// Produced by scripts/generate-napi-types.mjs from napi-derive's type-def
|
|
4
|
+
// output. Editing this file by hand puts it back where it started: a
|
|
5
|
+
// description that can disagree with the code it describes.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Typed response object crossing the TS→NAPI→Rust boundary.
|
|
9
|
+
*
|
|
10
|
+
* Using `#[napi(object)]` (instead of `String` carrying JSON) means napi-rs
|
|
11
|
+
* walks the JS object tree directly into Rust fields — zero JSON parse overhead.
|
|
12
|
+
*
|
|
13
|
+
* When `stream_id` is set, `body` is ignored and the hyper response is fed
|
|
14
|
+
* from the matching entry in the shared `StreamRegistry`. The handler must
|
|
15
|
+
* have called [`HyperServer::register_stream`] with that id BEFORE
|
|
16
|
+
* returning, otherwise the response collapses to a 500 (E_STREAM_UNKNOWN).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export interface NapiResponse {
|
|
20
|
+
status: number
|
|
21
|
+
headers: Record<string, string>
|
|
22
|
+
body: string
|
|
23
|
+
streamId?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Configuration for the wire-level shield filter. Mirrors the Rust
|
|
28
|
+
* `ShieldConfig` shape; the JS layer constructs it from `ShieldMiddleware`
|
|
29
|
+
* options at boot and hands it off to `HyperServer.configureShield`.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
export interface NapiShieldConfig {
|
|
33
|
+
pathTraversal: boolean
|
|
34
|
+
paramPollution: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Configuration for the wire-level rate limiter. `windowSecs` is the size
|
|
39
|
+
* of the fixed window in seconds; `max` is the request budget per key
|
|
40
|
+
* (resolved client IP) per window.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
export interface NapiRateLimitConfig {
|
|
44
|
+
max: number
|
|
45
|
+
windowSecs: number
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* NAPI-exposed event bus.
|
|
50
|
+
* Uses shared Tokio runtime (no per-instance runtime).
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
export declare class EventBus {
|
|
54
|
+
constructor(requestHandlerTimeoutMs?: number | undefined | null)
|
|
55
|
+
/** Emit an event (async — does NOT block Node.js thread). */
|
|
56
|
+
emit(name: string, data: string): Promise<string>
|
|
57
|
+
/**
|
|
58
|
+
* Subscribe to events matching a pattern. Callback receives event JSON string.
|
|
59
|
+
* Returns subscription ID.
|
|
60
|
+
*
|
|
61
|
+
* NOTE: This is `pub fn` (sync) — napi-rs cannot make `async fn` capture
|
|
62
|
+
* `JsFunction` because JsFunction isn't Send. The block_on here runs on the
|
|
63
|
+
* JS thread (no async context above), so it doesn't deadlock the runtime.
|
|
64
|
+
*/
|
|
65
|
+
subscribe(pattern: string, callback: (eventJson: string) => void): number
|
|
66
|
+
/** Unsubscribe by subscription ID. */
|
|
67
|
+
unsubscribe(subId: number): Promise<void>
|
|
68
|
+
/** Register a request handler. */
|
|
69
|
+
onRequest(
|
|
70
|
+
name: string,
|
|
71
|
+
callback: (eventJson: string, reply: (response: string) => void) => void,
|
|
72
|
+
): void
|
|
73
|
+
/** Send a request and get a response (async with timeout). */
|
|
74
|
+
request(name: string, data: string, timeoutMs?: number | undefined | null): Promise<string>
|
|
75
|
+
/** Check if a pattern matches an event name (wildcard matching via Rust). */
|
|
76
|
+
matchesWildcard(pattern: string, eventName: string): boolean
|
|
77
|
+
/** Get subscription count. */
|
|
78
|
+
subscriptionCount(): Promise<number>
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** NAPI-exposed Hyper HTTP server. */
|
|
82
|
+
|
|
83
|
+
export declare class HyperServer {
|
|
84
|
+
/**
|
|
85
|
+
* `host` is the bind address: an IPv4 literal (`0.0.0.0` to accept from
|
|
86
|
+
* every interface) or the `localhost` alias. Omitted → loopback only,
|
|
87
|
+
* the safe default for a dev machine.
|
|
88
|
+
*/
|
|
89
|
+
constructor(port?: number | undefined | null, host?: string | undefined | null)
|
|
90
|
+
/** Register the request handler. Callback receives JSON request string, must return JSON response string. */
|
|
91
|
+
onRequest(callback: (request: string) => Promise<string> | string): void
|
|
92
|
+
/**
|
|
93
|
+
* Configure the trusted-proxy CIDR list used by `request.ip` resolution.
|
|
94
|
+
* Must be called BEFORE `listen()`. Empty list = legacy permissive mode
|
|
95
|
+
* (any peer can populate `X-Forwarded-For`).
|
|
96
|
+
*/
|
|
97
|
+
configureTrustedProxies(cidrs: Array<string>): void
|
|
98
|
+
/**
|
|
99
|
+
* Install (or replace) the wire-level rate limiter. Pass `None` to
|
|
100
|
+
* disable. Must be called BEFORE `listen()`.
|
|
101
|
+
*/
|
|
102
|
+
configureRateLimit(config?: NapiRateLimitConfig | undefined | null): void
|
|
103
|
+
/**
|
|
104
|
+
* Configure the wire-level security shield. Must be called BEFORE
|
|
105
|
+
* `listen()` — the configuration is captured into the security filter
|
|
106
|
+
* when the server starts. Calling after `listen()` has no effect.
|
|
107
|
+
*/
|
|
108
|
+
configureShield(config: NapiShieldConfig): void
|
|
109
|
+
/** Start the HTTP server. */
|
|
110
|
+
listen(): Promise<void>
|
|
111
|
+
/** Get the actual bound port. */
|
|
112
|
+
port(): Promise<number>
|
|
113
|
+
/**
|
|
114
|
+
* Shut down the server and release the handles that keep the host's event
|
|
115
|
+
* loop alive.
|
|
116
|
+
*
|
|
117
|
+
* `listen()` registers the JS callback as a `ThreadsafeFunction` (which
|
|
118
|
+
* holds a libuv ref so `ream start` stays alive). Three `Arc` clones of the
|
|
119
|
+
* request handler capture it: this struct's `self.handler`, the inner
|
|
120
|
+
* `ReamServer.handler`, and the accept-loop task's clone. ALL three must
|
|
121
|
+
* drop for napi-rs to release the tsfn on `Drop` (refcount → 0). The old
|
|
122
|
+
* `close()` only signalled shutdown, leaving every clone alive — so an
|
|
123
|
+
* in-process host (test harness) leaked the handle and never drained.
|
|
124
|
+
*/
|
|
125
|
+
close(): Promise<void>
|
|
126
|
+
/**
|
|
127
|
+
* Reserve a slot in the stream registry. Returns `false` if the id
|
|
128
|
+
* already exists (caller picked a colliding UUID). Always returns
|
|
129
|
+
* before `listen()` need have run.
|
|
130
|
+
*/
|
|
131
|
+
registerStream(streamId: string): Promise<boolean>
|
|
132
|
+
/**
|
|
133
|
+
* Push a chunk onto a registered stream. Returns `false` when the
|
|
134
|
+
* stream has already finished (receiver dropped — client gone or
|
|
135
|
+
* `closeStream` called) so the caller can bail out of its push
|
|
136
|
+
* loop. Backpressure is handled silently: a full buffer drops the
|
|
137
|
+
* frame rather than awaiting — SSE is fire-and-forget by design.
|
|
138
|
+
*/
|
|
139
|
+
writeStream(streamId: string, chunk: string): Promise<boolean>
|
|
140
|
+
/**
|
|
141
|
+
* Push a BINARY chunk onto a registered stream, waiting for room.
|
|
142
|
+
*
|
|
143
|
+
* The counterpart of [`write_stream`](Self::write_stream) for a body the
|
|
144
|
+
* client reassembles — a file, an export, an archive. Two differences,
|
|
145
|
+
* both required there and both wrong for SSE:
|
|
146
|
+
*
|
|
147
|
+
* * it takes bytes, not a `String`, so a payload that is not valid UTF-8
|
|
148
|
+
* survives the crossing intact;
|
|
149
|
+
* * it AWAITS when the channel is full instead of dropping the frame, so
|
|
150
|
+
* a slow client slows the producer rather than silently receiving a
|
|
151
|
+
* truncated file.
|
|
152
|
+
*
|
|
153
|
+
* Returns `false` when the receiver is gone (client disconnected or the
|
|
154
|
+
* stream was closed), so the caller can stop reading its source.
|
|
155
|
+
*/
|
|
156
|
+
writeStreamBytes(streamId: string, chunk: Uint8Array): Promise<boolean>
|
|
157
|
+
/**
|
|
158
|
+
* Close a stream from the server side. The matching response body
|
|
159
|
+
* finishes cleanly (hyper writes the final chunk + `0
|
|
160
|
+
|
|
161
|
+
` for
|
|
162
|
+
* HTTP/1.1 chunked encoding). Idempotent.
|
|
163
|
+
*/
|
|
164
|
+
closeStream(streamId: string): Promise<boolean>
|
|
165
|
+
/**
|
|
166
|
+
* Install a one-shot callback fired the moment the matching stream
|
|
167
|
+
* receiver is dropped — i.e. the client disconnected or
|
|
168
|
+
* `closeStream` was called. Used by the JS SDK to drop subscription
|
|
169
|
+
* bookkeeping when an SSE viewer leaves.
|
|
170
|
+
*
|
|
171
|
+
* The callback runs on the libuv loop via the threadsafe-function
|
|
172
|
+
* machinery, so JS code in the callback uses regular await /
|
|
173
|
+
* reentrant container calls without crossing-thread surprises.
|
|
174
|
+
*/
|
|
175
|
+
onStreamDisconnect(streamId: string, callback: (streamId: string) => void): void
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Scheduler instance exposed to TypeScript.
|
|
180
|
+
*
|
|
181
|
+
* Usage (from TS):
|
|
182
|
+
* ```ignore
|
|
183
|
+
* const scheduler = new RustScheduler();
|
|
184
|
+
* scheduler.register('cleanup', '0 *\/5 * * *', (payload) => { ... });
|
|
185
|
+
* scheduler.start();
|
|
186
|
+
* // later
|
|
187
|
+
* scheduler.stop();
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
export declare class RustScheduler {
|
|
192
|
+
constructor()
|
|
193
|
+
/**
|
|
194
|
+
* Register a task. `cronExpr` is a standard 5-field cron expression
|
|
195
|
+
* evaluated in UTC.
|
|
196
|
+
*
|
|
197
|
+
* Throws with `DUPLICATE_TASK` if `name` already exists, or
|
|
198
|
+
* `INVALID_CRON` if the expression is malformed.
|
|
199
|
+
*/
|
|
200
|
+
register(
|
|
201
|
+
name: string,
|
|
202
|
+
cronExpr: string,
|
|
203
|
+
callback: (invocation: { taskName: string; scheduledForMs: number }) => void,
|
|
204
|
+
): void
|
|
205
|
+
/** Remove a task. Idempotent — unknown names are not an error. */
|
|
206
|
+
unregister(name: string): void
|
|
207
|
+
/** Launch the tick loop on the shared Tokio runtime. Idempotent. */
|
|
208
|
+
start(): void
|
|
209
|
+
/** Cancel the tick loop. Safe to call even if not running. */
|
|
210
|
+
stop(): void
|
|
211
|
+
/** Return the next fire time in ms epoch, or `null` if the task is unknown. */
|
|
212
|
+
nextRun(name: string): number | null
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Sign a JWT payload with HMAC-SHA256 (Rust-native).
|
|
217
|
+
* Returns the complete JWT token string.
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
export declare function jwtSign(payload: string, secret: string): string
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Verify a JWT token and return the decoded payload JSON string.
|
|
224
|
+
* Validates signature (constant-time), exp, and nbf claims.
|
|
225
|
+
*/
|
|
226
|
+
|
|
227
|
+
export declare function jwtVerify(token: string, secret: string): string
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Hash a password with Argon2id (Rust-native).
|
|
231
|
+
* Returns the PHC-formatted hash string.
|
|
232
|
+
*/
|
|
233
|
+
|
|
234
|
+
export declare function argon2Hash(password: string): string
|
|
235
|
+
|
|
236
|
+
/** Verify a password against an Argon2id hash. */
|
|
237
|
+
|
|
238
|
+
export declare function argon2Verify(password: string, hash: string): boolean
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Hash a password with bcrypt (Rust-native).
|
|
242
|
+
* `rounds` defaults to 12 when not supplied — matches the previous
|
|
243
|
+
* warden-engine default and the OWASP-recommended cost floor enforced
|
|
244
|
+
* by `sigil-engine`.
|
|
245
|
+
*/
|
|
246
|
+
|
|
247
|
+
export declare function bcryptHash(password: string, rounds?: number | undefined | null): string
|
|
248
|
+
|
|
249
|
+
/** Verify a password against a bcrypt hash. */
|
|
250
|
+
|
|
251
|
+
export declare function bcryptVerify(password: string, hash: string): boolean
|
|
252
|
+
|
|
253
|
+
/** Constant-time string comparison. */
|
|
254
|
+
|
|
255
|
+
export declare function constantTimeEq(a: string, b: string): boolean
|
|
256
|
+
|
|
257
|
+
/** HMAC-SHA256 sign. Returns base64url signature. */
|
|
258
|
+
|
|
259
|
+
export declare function hmacSign(data: string, secret: string): string
|
|
260
|
+
|
|
261
|
+
/** HMAC-SHA256 verify (constant-time). */
|
|
262
|
+
|
|
263
|
+
export declare function hmacVerify(data: string, signature: string, secret: string): boolean
|
|
264
|
+
|
|
265
|
+
/** Generate cryptographically secure random bytes as base64url. */
|
|
266
|
+
|
|
267
|
+
export declare function randomBytesBase64(len: number): string
|
|
268
|
+
|
|
269
|
+
/** Generate cryptographically secure random bytes as hex. */
|
|
270
|
+
|
|
271
|
+
export declare function randomHex(len: number): string
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Parse a GraphQL query using the Rust graphql-parser crate.
|
|
275
|
+
* Returns JSON: { operationType, operationName, fields: [...], errors: [...] }
|
|
276
|
+
* Invalid queries are rejected here — they never reach the TypeScript resolver layer.
|
|
277
|
+
*/
|
|
278
|
+
|
|
279
|
+
export declare function graphqlParse(query: string): string
|
|
280
|
+
|
|
281
|
+
/** Validate a GraphQL query string. Returns JSON array of error strings (empty = valid). */
|
|
282
|
+
|
|
283
|
+
export declare function graphqlValidate(query: string): string
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Extract argument scalar types from a GraphQL SDL schema.
|
|
287
|
+
* Returns JSON: `{ "Type.field": { "argName": "ScalarType" } }` for argument
|
|
288
|
+
* coercion in the TypeScript engine.
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
export declare function graphqlSchemaArgTypes(sdl: string): string
|