@luckystack/core 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +243 -209
- package/LICENSE +21 -21
- package/README.md +93 -93
- package/dist/chunk-OZTB2RL2.js +699 -0
- package/dist/chunk-OZTB2RL2.js.map +1 -0
- package/dist/chunk-USQA6QTX.js +28 -0
- package/dist/chunk-USQA6QTX.js.map +1 -0
- package/dist/chunk-V2WKGTZH.js +357 -0
- package/dist/chunk-V2WKGTZH.js.map +1 -0
- package/dist/chunk-W62GGT2P.js +241 -0
- package/dist/chunk-W62GGT2P.js.map +1 -0
- package/dist/client.d.ts +57 -4
- package/dist/client.js +251 -705
- package/dist/client.js.map +1 -1
- package/dist/eslint/index.js +4 -3
- package/dist/eslint/index.js.map +1 -1
- package/dist/index.d.ts +671 -22
- package/dist/index.js +808 -1156
- package/dist/index.js.map +1 -1
- package/dist/{pageRouteValidation-CxZJVwZh.d.ts → pageRouteValidation-BoZ-rQWi.d.ts} +336 -7
- package/dist/projectConfig-JX563K43.js +16 -0
- package/dist/projectConfig-JX563K43.js.map +1 -0
- package/dist/sentrySetup-Q4BKUAQ3.js +16 -0
- package/dist/sentrySetup-Q4BKUAQ3.js.map +1 -0
- package/docs/app-bootstrap.md +418 -418
- package/docs/config-registry.md +350 -350
- package/docs/csrf-config.md +88 -88
- package/docs/error-tracker-registry.md +174 -174
- package/docs/hooks.md +298 -298
- package/docs/rate-limit-strategy.md +170 -170
- package/docs/redis-adapter.md +111 -111
- package/docs/session-types.md +180 -180
- package/docs/socket-bootstrap.md +366 -366
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { A as ApiMethodMap, a as AppConfig,
|
|
1
|
+
import { a6 as ErrorParam, a7 as ErrorResponseInput, a8 as NormalizedErrorResponse, a9 as HealthHashConfig, aa as DeepPartial, B as BaseSessionLayout, b as AuthProps } from './pageRouteValidation-BoZ-rQWi.js';
|
|
2
|
+
export { ab as ApiConfig, A as ApiMethodMap, a as AppConfig, ac as AuthConfig, ad as AuthRateLimitConfig, ae as CorsConfig, D as DEFAULT_PAGE_ROUTE_RULES, af as DEFAULT_PROJECT_CONFIG, ag as DevConfig, ah as HttpConfig, H as HttpMethodLiteral, ai as HttpStreamConfig, aj as INVALID_ERROR_RESPONSE_CODE, L as Logger, c as LoggerContext, d as LoggingConfig, N as Notifier, e as NotifyInput, f as NotifyParam, ak as OfflineQueueConfig, P as PagePathValidationResult, g as PageRouteRules, al as PasswordPolicyConfig, am as PathsConfig, h as ProjectConfig, an as ProjectConfigInput, ao as QueueDropReason, ap as RateLimitIdentity, aq as RateLimitIdentityParams, R as RateLimitingConfig, S as SOCKETSTATUS, ar as SecurityHeadersConfig, as as ServiceRouteParseError, at as ServiceRouteParseResult, au as ServiceRouteParseSuccess, i as SessionConfig, j as SessionLocation, av as SocketConfig, aw as SyncConfig, ax as SyncFlushPressureConfig, ay as SyncStreamThrottleConfig, az as TransportRouteParseError, aA as TransportRouteParseResult, aB as TransportRouteParseSuccess, aC as ValidationConfig, k as buildApiResponseEventName, l as buildApiStreamEventName, m as buildGetJoinedRoomsResponseEventName, n as buildJoinRoomResponseEventName, o as buildLeaveRoomResponseEventName, p as buildSyncProgressEventName, q as buildSyncResponseEventName, r as clearCsrfToken, aD as createDevLogger, aE as deepMerge, aF as defaultHttpStatusForResponse, s as enqueueApiRequest, t as enqueueSyncRequest, u as flushApiQueue, v as flushSyncQueue, w as getApiQueueSize, x as getCsrfToken, y as getLogger, z as getNotifier, C as getProjectConfig, aG as getProjectName, E as getRegisteredApiMethod, F as getSyncQueueSize, G as httpFetch, I as incrementResponseIndex, J as isApiMethodMapRegistered, aH as isErrorParamArray, aI as isLoggerRegistered, K as isOnline, aJ as isPlainObject, M as isProjectConfigRegistered, O as normalizeErrorResponseCore, Q as notify, T as parseServiceRouteName, aK as parseTransportRouteName, U as registerApiMethodMap, V as registerLogger, W as registerNotifier, X as registerProjectConfig, Y as removeApiQueueItem, Z as removeApiQueueItemsByKey, _ as removeSyncQueueItem, aL as resetLoggerForTests, $ as setSocket, a0 as sleep, a1 as socket, a2 as socketEventNames, a3 as statusContent, a4 as validatePagePath, a5 as waitForSocket } from './pageRouteValidation-BoZ-rQWi.js';
|
|
3
3
|
export { ApiTypeMap, StreamPayload, SyncTypeMap } from './apiTypeStubs.js';
|
|
4
4
|
import { Server, Socket } from 'socket.io';
|
|
5
5
|
import { z } from 'zod';
|
|
@@ -7,9 +7,100 @@ import * as _prisma_client_runtime_library from '@prisma/client/runtime/library'
|
|
|
7
7
|
import * as _prisma_client from '@prisma/client';
|
|
8
8
|
import { PrismaClient } from '@prisma/client';
|
|
9
9
|
import Redis, { Redis as Redis$1 } from 'ioredis';
|
|
10
|
-
import {
|
|
10
|
+
import { RedisAdapterOptions } from '@socket.io/redis-adapter';
|
|
11
|
+
import { ServerResponse, IncomingMessage, IncomingHttpHeaders } from 'node:http';
|
|
11
12
|
import 'socket.io-client';
|
|
12
13
|
|
|
14
|
+
declare function tryCatch<T, P = void>(func: (values: P) => Promise<T> | T, params?: P, context?: Record<string, unknown>): Promise<[Error | null, T | null]>;
|
|
15
|
+
|
|
16
|
+
declare function tryCatchSync<T, P>(func: (values: P) => T, params?: P): [Error | null, T | null];
|
|
17
|
+
|
|
18
|
+
type RequireTransform<TInput, TStored> = [TInput] extends [TStored] ? {
|
|
19
|
+
transform?: (input: TInput, current: TStored) => TStored;
|
|
20
|
+
} : {
|
|
21
|
+
transform: (input: TInput, current: TStored) => TStored;
|
|
22
|
+
};
|
|
23
|
+
interface RegistryOptionsBase<TStored> {
|
|
24
|
+
/**
|
|
25
|
+
* Called once per `register` with the freshly-stored value — used for the
|
|
26
|
+
* rate-limiter's `[RateLimiter] active strategy → …` debug line. Runs after
|
|
27
|
+
* the slot is updated so a logger registry can log through itself.
|
|
28
|
+
*/
|
|
29
|
+
onRegister?: (stored: TStored) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the value `get` returns when nothing has been registered yet.
|
|
32
|
+
* Defaults to returning `defaultValue`. `servicesConfig` throws here.
|
|
33
|
+
*/
|
|
34
|
+
resolveDefault?: () => TStored;
|
|
35
|
+
}
|
|
36
|
+
type RegistryOptions<TInput, TStored> = RegistryOptionsBase<TStored> & RequireTransform<TInput, TStored>;
|
|
37
|
+
interface Registry<TInput, TStored> {
|
|
38
|
+
/** Store a value (after the optional `transform`) and mark the slot registered. */
|
|
39
|
+
register: (input: TInput) => TStored;
|
|
40
|
+
/** Read the active value at call time (registered value, else the default). */
|
|
41
|
+
get: () => TStored;
|
|
42
|
+
/** True once `register` has been called at least once. */
|
|
43
|
+
isRegistered: () => boolean;
|
|
44
|
+
/** Restore the unregistered state (test-only). */
|
|
45
|
+
reset: () => void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a single-slot registry. `defaultValue` is returned by `get` until
|
|
49
|
+
* `register` is called (unless `resolveDefault` overrides that). When
|
|
50
|
+
* `TInput` differs from `TStored`, the `transform` option is mandatory (the
|
|
51
|
+
* `RequireTransform` constraint enforces it); when they match it is optional
|
|
52
|
+
* and defaults to identity. The second positional argument is likewise
|
|
53
|
+
* optional only in the identity case.
|
|
54
|
+
*/
|
|
55
|
+
declare function createRegistry<TStored, TInput = TStored>(defaultValue: TStored, ...optionsArg: [TInput] extends [TStored] ? [options?: RegistryOptions<TInput, TStored>] : [options: RegistryOptions<TInput, TStored>]): Registry<TInput, TStored>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Escape `&`, `<`, `>`, `"`, `'` for safe interpolation into HTML text nodes
|
|
59
|
+
* and quoted attribute values. Does NOT protect against CSS/JS/URL-context
|
|
60
|
+
* injection — use a dedicated sanitizer for those contexts.
|
|
61
|
+
*/
|
|
62
|
+
declare const escapeHtml: (str: string) => string;
|
|
63
|
+
|
|
64
|
+
/** Minimal shape of a Node `require` with the `.resolve` member these guards use. */
|
|
65
|
+
interface PeerRequire {
|
|
66
|
+
(id: string): unknown;
|
|
67
|
+
resolve: (id: string) => string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Assert that an optional peer package is installed, throwing a consistent,
|
|
71
|
+
* actionable error when it is not. Does NOT load the module — use `loadPeer`
|
|
72
|
+
* for that. Pass `requireFn` (a `createRequire(import.meta.url)` from the
|
|
73
|
+
* calling adapter) so resolution happens from the consumer's perspective.
|
|
74
|
+
*
|
|
75
|
+
* `hint` is appended to the standard "package X is not installed" sentence —
|
|
76
|
+
* e.g. `'Run `npm install resend`, or pick a different EmailSender adapter.'`.
|
|
77
|
+
*/
|
|
78
|
+
declare const ensurePeerDepInstalled: (packageName: string, hint: string, requireFn?: PeerRequire) => void;
|
|
79
|
+
/**
|
|
80
|
+
* Synchronously load an optional peer package, asserting it is installed
|
|
81
|
+
* first (so a missing dependency fails with the actionable `hint` rather than
|
|
82
|
+
* a raw `MODULE_NOT_FOUND`). Returns the module typed as `T`. Pass `requireFn`
|
|
83
|
+
* (built with `createRequire(import.meta.url)` at the call site) so resolution
|
|
84
|
+
* + load happen relative to the calling module.
|
|
85
|
+
*/
|
|
86
|
+
declare const loadPeer: <T>(packageName: string, hint: string, requireFn?: PeerRequire) => T;
|
|
87
|
+
|
|
88
|
+
interface RoomNameFormatterContext {
|
|
89
|
+
/** Why the room name is being formatted — so a formatter can branch if needed. */
|
|
90
|
+
purpose: 'join' | 'leave' | 'broadcast' | 'presence';
|
|
91
|
+
/** Session user id when known (join/leave by an authenticated socket), else null. */
|
|
92
|
+
userId?: string | null;
|
|
93
|
+
}
|
|
94
|
+
type RoomNameFormatter = (rawRoomName: string, ctx: RoomNameFormatterContext) => string;
|
|
95
|
+
/** Override how every framework room name is namespaced (multi-tenant prefixing). */
|
|
96
|
+
declare const registerRoomNameFormatter: (formatter: RoomNameFormatter) => void;
|
|
97
|
+
/** Read the active formatter (defaults to identity). */
|
|
98
|
+
declare const getRoomNameFormatter: () => RoomNameFormatter;
|
|
99
|
+
/** Apply the active formatter — the single helper framework room-sites call. */
|
|
100
|
+
declare const formatRoomName: (rawRoomName: string, ctx: RoomNameFormatterContext) => string;
|
|
101
|
+
/** The built-in identity formatter (exported for tests / explicit reset). */
|
|
102
|
+
declare const defaultRoomNameFormatter: RoomNameFormatter;
|
|
103
|
+
|
|
13
104
|
type LanguageCode = string;
|
|
14
105
|
interface TranslateInput {
|
|
15
106
|
language: LanguageCode;
|
|
@@ -68,13 +159,26 @@ interface ErrorFormatterContext {
|
|
|
68
159
|
/** Session id when available. */
|
|
69
160
|
userId?: string | null;
|
|
70
161
|
}
|
|
71
|
-
|
|
162
|
+
/** The normalized error envelope handed to every formatter. */
|
|
163
|
+
interface FormatterErrorEnvelope {
|
|
72
164
|
status: 'error';
|
|
73
165
|
errorCode?: string;
|
|
74
166
|
message?: string;
|
|
75
167
|
httpStatus?: number;
|
|
76
168
|
[key: string]: unknown;
|
|
77
|
-
}
|
|
169
|
+
}
|
|
170
|
+
type ErrorFormatter = (error: FormatterErrorEnvelope, ctx: ErrorFormatterContext) => Record<string, unknown>;
|
|
171
|
+
/**
|
|
172
|
+
* Minimal structural contract every formatter-eligible envelope satisfies:
|
|
173
|
+
* a discriminant `status` plus an open string-index so formatters can read /
|
|
174
|
+
* add arbitrary fields. Generic helpers below constrain to this so transport
|
|
175
|
+
* handlers no longer need `as unknown as` double-casts at the formatter
|
|
176
|
+
* boundary — see `applyErrorFormatter` / `buildFormattedError`.
|
|
177
|
+
*/
|
|
178
|
+
interface FormatterEnvelope {
|
|
179
|
+
status?: string;
|
|
180
|
+
[key: string]: unknown;
|
|
181
|
+
}
|
|
78
182
|
/**
|
|
79
183
|
* Register a global error-response formatter. Receives the normalized
|
|
80
184
|
* error envelope + context; return a (possibly extended) object that the
|
|
@@ -94,15 +198,13 @@ declare const getErrorFormatter: () => ErrorFormatter | null;
|
|
|
94
198
|
* are caught and logged; the un-formatted envelope is returned in that
|
|
95
199
|
* case to keep the error path crash-resistant.
|
|
96
200
|
*/
|
|
97
|
-
declare const applyErrorFormatter: (input: {
|
|
98
|
-
response:
|
|
99
|
-
status?: string;
|
|
100
|
-
};
|
|
201
|
+
declare const applyErrorFormatter: <T extends FormatterEnvelope>(input: {
|
|
202
|
+
response: T;
|
|
101
203
|
routeName: string;
|
|
102
204
|
transport: "socket" | "http";
|
|
103
205
|
userId?: string | null;
|
|
104
206
|
perRouteFormatter?: ErrorFormatter | undefined | null;
|
|
105
|
-
}) =>
|
|
207
|
+
}) => T;
|
|
106
208
|
|
|
107
209
|
interface apiMessage {
|
|
108
210
|
name: string;
|
|
@@ -138,6 +240,28 @@ declare const isRuntimeMapsProviderRegistered: () => boolean;
|
|
|
138
240
|
declare const getRuntimeApiMaps: () => Promise<RuntimeApiMapsResult>;
|
|
139
241
|
declare const getRuntimeSyncMaps: () => Promise<RuntimeSyncMapsResult>;
|
|
140
242
|
|
|
243
|
+
/**
|
|
244
|
+
* A single email attachment (email F2). Adapters (Resend, SMTP/Nodemailer, SES)
|
|
245
|
+
* thread these into their provider payload. `content` is the raw bytes
|
|
246
|
+
* (`Buffer`/`Uint8Array`) or a base64 string; provide a `path`/`href` instead
|
|
247
|
+
* for adapters that fetch externally. Shapes are intentionally permissive so a
|
|
248
|
+
* single attachment object works across providers — each adapter maps the
|
|
249
|
+
* fields it supports.
|
|
250
|
+
*/
|
|
251
|
+
interface EmailAttachment {
|
|
252
|
+
/** File name shown to the recipient (e.g. `invoice.pdf`). */
|
|
253
|
+
filename: string;
|
|
254
|
+
/** Inline bytes or base64 string. Mutually exclusive with `path`/`href`. */
|
|
255
|
+
content?: Buffer | Uint8Array | string;
|
|
256
|
+
/** Local file path the adapter reads (when it supports path-based sends). */
|
|
257
|
+
path?: string;
|
|
258
|
+
/** Remote URL the adapter fetches (when it supports href-based sends). */
|
|
259
|
+
href?: string;
|
|
260
|
+
/** MIME type (e.g. `application/pdf`). Adapter may infer from `filename` if omitted. */
|
|
261
|
+
contentType?: string;
|
|
262
|
+
/** `Content-ID` for inline/embedded images referenced by `cid:` in the HTML. */
|
|
263
|
+
cid?: string;
|
|
264
|
+
}
|
|
141
265
|
interface EmailMessage {
|
|
142
266
|
to: string | string[];
|
|
143
267
|
subject: string;
|
|
@@ -147,6 +271,20 @@ interface EmailMessage {
|
|
|
147
271
|
replyTo?: string;
|
|
148
272
|
cc?: string | string[];
|
|
149
273
|
bcc?: string | string[];
|
|
274
|
+
/**
|
|
275
|
+
* File attachments (email F2). Owned by core (not `@luckystack/email`) so the
|
|
276
|
+
* type is the single source of truth across the framework and every adapter;
|
|
277
|
+
* adapters thread these into their provider's attachment payload. Optional —
|
|
278
|
+
* a message without attachments behaves exactly as before.
|
|
279
|
+
*/
|
|
280
|
+
attachments?: EmailAttachment[];
|
|
281
|
+
/**
|
|
282
|
+
* Custom message headers (email F2) — e.g. `X-Entity-Ref-ID`,
|
|
283
|
+
* `List-Unsubscribe`, idempotency keys. Adapters merge these over the headers
|
|
284
|
+
* they set themselves (adapter-reserved headers win to avoid breaking
|
|
285
|
+
* delivery). Optional.
|
|
286
|
+
*/
|
|
287
|
+
headers?: Record<string, string>;
|
|
150
288
|
}
|
|
151
289
|
type EmailResult = {
|
|
152
290
|
ok: true;
|
|
@@ -228,6 +366,31 @@ interface DeployRoutingShape {
|
|
|
228
366
|
healthProbeTimeoutMs?: number;
|
|
229
367
|
/** Seconds the boot-UUID Redis key lives for (default 3600 = 1h). */
|
|
230
368
|
bootKeyTtlSeconds?: number;
|
|
369
|
+
/**
|
|
370
|
+
* ms before the router gives up proxying to an upstream backend (SEC-30 /
|
|
371
|
+
* router-DeployRoutingShape). Guards against slow-loris upstreams holding a
|
|
372
|
+
* router worker open. The router reads this when building its proxy request.
|
|
373
|
+
* DEFAULT undefined → router falls back to its own built-in default.
|
|
374
|
+
*/
|
|
375
|
+
upstreamTimeoutMs?: number;
|
|
376
|
+
/**
|
|
377
|
+
* Name of the service that terminates websocket (Socket.io) traffic. The
|
|
378
|
+
* router pins WS upgrade requests to this service (they cannot be load-balanced
|
|
379
|
+
* round-robin without sticky sessions). DEFAULT undefined → router uses its
|
|
380
|
+
* `system` convention.
|
|
381
|
+
*/
|
|
382
|
+
websocketService?: string;
|
|
383
|
+
/**
|
|
384
|
+
* Path the router exposes for its OWN health/liveness (distinct from the
|
|
385
|
+
* backend `/_health` boot-handshake endpoint). DEFAULT undefined → router
|
|
386
|
+
* uses its built-in default.
|
|
387
|
+
*/
|
|
388
|
+
routerHealthPath?: string;
|
|
389
|
+
/**
|
|
390
|
+
* Max request body size (bytes) the router will buffer/forward before
|
|
391
|
+
* rejecting with 413. DEFAULT undefined → router uses its built-in default.
|
|
392
|
+
*/
|
|
393
|
+
maxRequestBodyBytes?: number;
|
|
231
394
|
}
|
|
232
395
|
interface DeployDevelopmentShape {
|
|
233
396
|
enableFallbackRouting?: boolean;
|
|
@@ -283,6 +446,11 @@ declare const setSentryUser: (user: {
|
|
|
283
446
|
declare const startSpan: (name: string, op: string) => unknown;
|
|
284
447
|
|
|
285
448
|
type ErrorTrackerContext = Record<string, unknown>;
|
|
449
|
+
declare const sanitizeErrorString: (value: string) => string;
|
|
450
|
+
declare const sanitizeErrorStrings: (error: unknown) => {
|
|
451
|
+
message: string;
|
|
452
|
+
stack: string | undefined;
|
|
453
|
+
} | null;
|
|
286
454
|
interface ErrorTrackerUser {
|
|
287
455
|
id?: string;
|
|
288
456
|
email?: string;
|
|
@@ -306,15 +474,75 @@ interface ErrorTracker {
|
|
|
306
474
|
startSpan?: <T>(name: string, op: string, fn: () => T) => T;
|
|
307
475
|
recordMetric?: (name: string, value: number, tags?: Record<string, string>) => void;
|
|
308
476
|
beforeSend?: (event: ErrorTrackerEvent) => ErrorTrackerEvent | null;
|
|
477
|
+
/**
|
|
478
|
+
* Optional flush lifecycle hook (error-tracking ET batch). Called by
|
|
479
|
+
* {@link flushErrorTrackers} on graceful shutdown so a buffered adapter
|
|
480
|
+
* (PostHog batch, Sentry transport) can drain in-flight events before exit.
|
|
481
|
+
* Returns a promise that resolves when the adapter has flushed.
|
|
482
|
+
*/
|
|
483
|
+
flush?: () => Promise<void>;
|
|
309
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Open a per-request error-tracker identity scope and run `fn` inside it. Call at
|
|
487
|
+
* request ENTRY (before any await that could interleave with another request); the
|
|
488
|
+
* identity starts null and is filled in later via {@link setCurrentErrorTrackerIdentity}
|
|
489
|
+
* once the session is known. Each invocation gets an isolated box (ET-02).
|
|
490
|
+
*/
|
|
491
|
+
declare const runWithErrorTrackerIdentityScope: <T>(fn: () => T) => T;
|
|
492
|
+
/**
|
|
493
|
+
* Run `fn` with `user` bound as the ambient error-tracker identity (ET-02). Convenience
|
|
494
|
+
* wrapper that opens a scope and immediately sets the identity — used where the user is
|
|
495
|
+
* already known up front (and by the adapter regression tests).
|
|
496
|
+
*/
|
|
497
|
+
declare const runWithErrorTrackerIdentity: <T>(user: ErrorTrackerUser | null, fn: () => T) => T;
|
|
498
|
+
/**
|
|
499
|
+
* Write `user` into the active identity box opened by {@link runWithErrorTrackerIdentityScope}
|
|
500
|
+
* / {@link runWithErrorTrackerIdentity}. No-op when called outside any scope (a background /
|
|
501
|
+
* non-request capture has no per-request box; adapters fall back to their own global).
|
|
502
|
+
*/
|
|
503
|
+
declare const setCurrentErrorTrackerIdentity: (user: ErrorTrackerUser | null) => void;
|
|
504
|
+
/** Read the ambient per-event identity for the active request scope, if any. */
|
|
505
|
+
declare const getCurrentErrorTrackerIdentity: () => ErrorTrackerUser | null;
|
|
506
|
+
type PreCaptureFilter = (event: ErrorTrackerEvent) => boolean;
|
|
507
|
+
declare const registerPreCaptureFilter: (filter: PreCaptureFilter | null) => void;
|
|
310
508
|
declare const registerErrorTracker: (tracker: ErrorTracker) => void;
|
|
311
509
|
declare const registerErrorTrackers: (trackers: ErrorTracker[]) => void;
|
|
510
|
+
/**
|
|
511
|
+
* APPEND primitive (ET-05): add a tracker WITHOUT clobbering already-registered
|
|
512
|
+
* ones. Fixes the async-PostHog-vs-consumer-overlay race where the loser of
|
|
513
|
+
* `registerErrorTracker`'s replace silently vanished. De-duplicates by `name`
|
|
514
|
+
* (re-appending the same adapter name replaces that one entry in place) so a
|
|
515
|
+
* lazy adapter that registers a proxy then the real client doesn't double-fire.
|
|
516
|
+
*/
|
|
517
|
+
declare const appendErrorTracker: (tracker: ErrorTracker) => void;
|
|
312
518
|
declare const getActiveErrorTrackers: () => ErrorTracker[];
|
|
519
|
+
/**
|
|
520
|
+
* Flush lifecycle (error-tracking ET batch): drain every adapter that exposes a
|
|
521
|
+
* `flush()` before shutdown. Per-adapter failures are swallowed + logged so one
|
|
522
|
+
* stuck adapter can't block graceful shutdown. Safe to call when no adapter has
|
|
523
|
+
* `flush`.
|
|
524
|
+
*/
|
|
525
|
+
declare const flushErrorTrackers: () => Promise<void>;
|
|
313
526
|
declare const captureExceptionAcrossTrackers: (error: unknown, context?: ErrorTrackerContext) => void;
|
|
314
527
|
declare const captureMessageAcrossTrackers: (message: string, level: "info" | "warning" | "error" | "fatal", context?: ErrorTrackerContext) => void;
|
|
315
528
|
declare const setErrorTrackerUser: (user: ErrorTrackerUser | null) => void;
|
|
316
529
|
declare const recordMetricAcrossTrackers: (name: string, value: number, tags?: Record<string, string>) => void;
|
|
317
530
|
declare const startSpanAcrossTrackers: <T>(name: string, op: string, fn: () => T) => T;
|
|
531
|
+
/**
|
|
532
|
+
* Handle-style span (error-tracking ET batch): for callers that can't wrap the
|
|
533
|
+
* measured work in a single synchronous `fn` (streaming, cross-await spans).
|
|
534
|
+
* Returns a handle whose `finish()` resolves the span's duration. The default
|
|
535
|
+
* implementation is a lightweight wall-clock timer (works with any backend);
|
|
536
|
+
* an adapter can supply a richer span via the existing `startSpan` callback
|
|
537
|
+
* form when it needs native instrumentation. `finish()` is idempotent.
|
|
538
|
+
*/
|
|
539
|
+
interface SpanHandle {
|
|
540
|
+
/** Stop the span; safe to call more than once (subsequent calls are no-ops). */
|
|
541
|
+
finish: () => void;
|
|
542
|
+
/** Milliseconds elapsed at the moment `finish()` first ran (0 before). */
|
|
543
|
+
readonly durationMs: number;
|
|
544
|
+
}
|
|
545
|
+
declare const startSpanHandle: (_name: string, _op: string) => SpanHandle;
|
|
318
546
|
|
|
319
547
|
declare const EnvSchema: z.ZodObject<{
|
|
320
548
|
NODE_ENV: z.ZodDefault<z.ZodEnum<{
|
|
@@ -348,6 +576,7 @@ declare const env: {
|
|
|
348
576
|
PROJECT_NAME: string;
|
|
349
577
|
};
|
|
350
578
|
declare const isProduction: boolean;
|
|
579
|
+
declare const getEnv: () => RuntimeEnv;
|
|
351
580
|
|
|
352
581
|
declare global {
|
|
353
582
|
var __luckystackPrisma: PrismaClient | undefined;
|
|
@@ -361,6 +590,7 @@ interface RedisConnectionOptions {
|
|
|
361
590
|
password?: string;
|
|
362
591
|
}
|
|
363
592
|
declare const getRedisConnectionOptions: () => RedisConnectionOptions;
|
|
593
|
+
declare const registerStrayPrefixCommand: (...commands: string[]) => void;
|
|
364
594
|
declare const redis: Redis;
|
|
365
595
|
|
|
366
596
|
type RedisKeyFormatter = (namespace: string, suffix: string) => string;
|
|
@@ -403,26 +633,147 @@ declare const getPrismaClient: () => PrismaClient;
|
|
|
403
633
|
declare const getRedisClient: () => Redis$1;
|
|
404
634
|
declare const resetClientsForTests: () => void;
|
|
405
635
|
|
|
406
|
-
|
|
636
|
+
interface AttachSocketRedisAdapterOptions {
|
|
637
|
+
/**
|
|
638
|
+
* Options forwarded to `@socket.io/redis-adapter`'s `createAdapter`
|
|
639
|
+
* (e.g. `key` prefix, `requestsTimeout`, `publishOnSpecificResponseChannel`).
|
|
640
|
+
*/
|
|
641
|
+
adapterOptions?: Partial<RedisAdapterOptions>;
|
|
642
|
+
/**
|
|
643
|
+
* Supply a pre-built pub client instead of `redis.duplicate()`. Use this for
|
|
644
|
+
* a dedicated adapter connection, custom auth, or a sentinel/cluster handle.
|
|
645
|
+
* When omitted the framework duplicates the default `redis` handle.
|
|
646
|
+
*/
|
|
647
|
+
pubClient?: Redis$1;
|
|
648
|
+
/** Pre-built sub client (see `pubClient`). */
|
|
649
|
+
subClient?: Redis$1;
|
|
650
|
+
}
|
|
651
|
+
declare const attachSocketRedisAdapter: (io: Server, options?: AttachSocketRedisAdapterOptions) => void;
|
|
407
652
|
|
|
408
653
|
declare const BOOT_KEY_PREFIX = "luckystack:boot:";
|
|
409
654
|
declare const resolveEnvKey: () => string;
|
|
410
655
|
declare const writeBootUuid: (envKey?: string) => Promise<string>;
|
|
411
656
|
declare const readBootUuid: (envKey?: string) => Promise<string | null>;
|
|
412
657
|
|
|
658
|
+
/**
|
|
659
|
+
* Hash a synchronized value under an EXPLICIT `{ mode, salt }` (SEC-13). The
|
|
660
|
+
* shared primitive the router calls with the same config the backend used, so
|
|
661
|
+
* the cross-env compare still holds:
|
|
662
|
+
* - `'plain'` → `sha256(value)` (today's behavior; `salt` ignored).
|
|
663
|
+
* - `'salted'` → `sha256(salt + value)`.
|
|
664
|
+
* - `'hmac'` → `HMAC-SHA256(key=salt, value)`.
|
|
665
|
+
* A `'salted'`/`'hmac'` mode with an empty resolved salt falls back to `'plain'`
|
|
666
|
+
* (and is the caller's responsibility to avoid) rather than silently hashing
|
|
667
|
+
* with an empty key.
|
|
668
|
+
*/
|
|
669
|
+
declare const hashSynchronizedValueWith: (config: Pick<HealthHashConfig, "mode"> & {
|
|
670
|
+
salt: string;
|
|
671
|
+
}, value: string) => string;
|
|
672
|
+
/**
|
|
673
|
+
* Resolve the effective health-hash config from `http.healthHash`, expanding the
|
|
674
|
+
* `'@bootUuid'` salt sentinel to the supplied boot UUID. Honoured for BOTH
|
|
675
|
+
* `'salted'` and `'hmac'` (the 0.2.0 default is `hmac` + `'@bootUuid'`, so the
|
|
676
|
+
* per-boot UUID becomes the HMAC key — the synchronized-env fingerprint rotates
|
|
677
|
+
* every restart instead of being a stable, dictionary-attackable `sha256`). The
|
|
678
|
+
* server passes its current boot UUID; the router, comparing, passes the same
|
|
679
|
+
* value it read from the backend's handshake. When the sentinel is in play but
|
|
680
|
+
* no boot UUID is available the config collapses to `'plain'` so the cross-env
|
|
681
|
+
* compare never silently diverges.
|
|
682
|
+
*/
|
|
683
|
+
declare const resolveHealthHashConfig: (bootUuid?: string | null) => {
|
|
684
|
+
mode: HealthHashConfig["mode"];
|
|
685
|
+
salt: string;
|
|
686
|
+
};
|
|
687
|
+
/**
|
|
688
|
+
* Safe-to-expose descriptor of the resolved health-hash config. The router needs
|
|
689
|
+
* to hash with the SAME `{ mode, salt }` the backend used, but a static `salt`
|
|
690
|
+
* (mode `'salted'`/`'hmac'` with a non-sentinel salt) is a SECRET and must never
|
|
691
|
+
* leave the backend. So `/_health` exposes only the `mode` + whether the salt is
|
|
692
|
+
* the `'@bootUuid'` sentinel (the bootUuid itself is already in the response).
|
|
693
|
+
* From this the router can reproduce the hash for `'plain'` and `'@bootUuid'`
|
|
694
|
+
* configs, and KNOWS it cannot reproduce a static-salt config (so it skips the
|
|
695
|
+
* compare instead of reporting a false drift).
|
|
696
|
+
*/
|
|
697
|
+
interface HealthHashDescriptor {
|
|
698
|
+
mode: HealthHashConfig['mode'];
|
|
699
|
+
bootUuidSalt: boolean;
|
|
700
|
+
}
|
|
701
|
+
/** Describe the active health-hash config for the `/_health` payload (no secret salt). */
|
|
702
|
+
declare const describeHealthHashConfig: () => HealthHashDescriptor;
|
|
703
|
+
/**
|
|
704
|
+
* Reproduce the backend's resolved `{ mode, salt }` from its `/_health`
|
|
705
|
+
* descriptor + the shared boot UUID. Returns `null` when the backend uses a
|
|
706
|
+
* STATIC salt the router cannot see — the caller must then skip the compare
|
|
707
|
+
* rather than hash with a different (default) config and report a false drift.
|
|
708
|
+
*/
|
|
709
|
+
declare const resolveHealthHashConfigFromDescriptor: (descriptor: HealthHashDescriptor, bootUuid: string) => {
|
|
710
|
+
mode: HealthHashConfig["mode"];
|
|
711
|
+
salt: string;
|
|
712
|
+
} | null;
|
|
413
713
|
declare const collectSynchronizedEnvKeys: () => string[];
|
|
414
|
-
|
|
415
|
-
|
|
714
|
+
/**
|
|
715
|
+
* Compute the `/_health` hash map for every synchronized env var. Reads
|
|
716
|
+
* `http.healthHash` (call-time) so a consumer's salt/HMAC opt-in applies;
|
|
717
|
+
* `bootUuid` is consulted only when the salt is the `'@bootUuid'` sentinel.
|
|
718
|
+
* The 0.2.0 DEFAULT (`{ mode: 'hmac', salt: '@bootUuid' }`) HMAC-keys the output
|
|
719
|
+
* on `bootUuid`; pass `mode: 'plain'` to restore the historical unsalted output.
|
|
720
|
+
*/
|
|
721
|
+
declare const computeSynchronizedEnvHashes: (bootUuid?: string | null) => Record<string, string | null>;
|
|
722
|
+
declare const hashSynchronizedValue: (value: string, bootUuid?: string | null) => string;
|
|
416
723
|
|
|
417
724
|
declare const initConsolelog: () => void;
|
|
418
725
|
|
|
726
|
+
declare const DEFAULT_REDACTED_LOG_KEYS: readonly string[];
|
|
419
727
|
declare const registerRedactedLogKeys: (keys: readonly string[]) => void;
|
|
420
728
|
declare const getRedactedLogKeys: () => readonly string[];
|
|
421
729
|
declare const isRedactedLogKey: (key: string) => boolean;
|
|
422
730
|
declare const resetRedactedLogKeysForTests: () => void;
|
|
731
|
+
/** Placeholder substituted for a redacted value. */
|
|
732
|
+
declare const REDACTED_PLACEHOLDER = "[redacted]";
|
|
733
|
+
declare const DEPTH_TRUNCATED_PLACEHOLDER = "[truncated: max depth]";
|
|
734
|
+
/**
|
|
735
|
+
* Recursively deep-copy `value`, replacing any property whose key matches the
|
|
736
|
+
* registered redacted-keys set (case-insensitive) with {@link REDACTED_PLACEHOLDER}
|
|
737
|
+
* (SYNC-17 defense-in-depth). Use it at raw log / `captureException` context
|
|
738
|
+
* sites so a token/password nested anywhere in a payload never lands verbatim in
|
|
739
|
+
* a logger sink or error-tracker breadcrumb.
|
|
740
|
+
*
|
|
741
|
+
* - Primitives pass through unchanged.
|
|
742
|
+
* - Arrays are mapped element-wise (array indices are never "keys", so an
|
|
743
|
+
* element is only redacted by its own nested object keys).
|
|
744
|
+
* - Cycles / over-deep graphs are cut at {@link MAX_SANITIZE_DEPTH} with
|
|
745
|
+
* {@link DEPTH_TRUNCATED_PLACEHOLDER}; the input is never mutated.
|
|
746
|
+
*/
|
|
747
|
+
declare const sanitizeForLog: (value: unknown, depth?: number) => unknown;
|
|
423
748
|
|
|
424
749
|
declare const getCookieValue: (cookieHeader: string | undefined, cookieName: string) => string | null;
|
|
425
750
|
declare const hasCookie: (cookieHeader: string | undefined, cookieName: string) => boolean;
|
|
751
|
+
/** Attributes a cookie-builder must honour, after applying any name prefix. */
|
|
752
|
+
interface CookiePrefixConstraints {
|
|
753
|
+
/** Effective cookie name (prefix prepended when applicable). */
|
|
754
|
+
name: string;
|
|
755
|
+
/** Whether `Secure` must be set (forced true by either prefix). */
|
|
756
|
+
secure: boolean;
|
|
757
|
+
/** Whether `Path=/` is forced (true under `__Host-`). */
|
|
758
|
+
forcePathRoot: boolean;
|
|
759
|
+
/** Whether a `Domain` attribute is FORBIDDEN (true under `__Host-`). */
|
|
760
|
+
forbidDomain: boolean;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Compute the attribute constraints a `__Host-` / `__Secure-` cookie-name prefix
|
|
764
|
+
* imposes (CORE-10/39), so the server's session + CSRF cookie builders apply the
|
|
765
|
+
* browser-enforced rules consistently:
|
|
766
|
+
*
|
|
767
|
+
* - `'__Host-'` → name prefixed, `Secure` forced, `Path=/` forced, `Domain` forbidden.
|
|
768
|
+
* - `'__Secure-'` → name prefixed, `Secure` forced.
|
|
769
|
+
* - `undefined` → name unchanged, no forced attributes (today's behavior).
|
|
770
|
+
*
|
|
771
|
+
* Pure + deterministic — the builder still owns serialization; this only
|
|
772
|
+
* resolves the constraints so server and any other cookie-site can't drift.
|
|
773
|
+
* `secureOverride` lets the caller force `Secure` independent of a prefix
|
|
774
|
+
* (mirrors `http.sessionCookieSecure`).
|
|
775
|
+
*/
|
|
776
|
+
declare const applyCookiePrefixConstraints: (baseName: string, prefix: "__Host-" | "__Secure-" | undefined, secureOverride?: boolean) => CookiePrefixConstraints;
|
|
426
777
|
|
|
427
778
|
/**
|
|
428
779
|
* HTTP API Utilities
|
|
@@ -432,6 +783,13 @@ declare const hasCookie: (cookieHeader: string | undefined, cookieName: string)
|
|
|
432
783
|
* - Method validation
|
|
433
784
|
*/
|
|
434
785
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
786
|
+
/**
|
|
787
|
+
* Single source of truth for the GET-prefix naming heuristic
|
|
788
|
+
* (`get` / `fetch` / `list`). Used by both `inferHttpMethod` here and the
|
|
789
|
+
* client transport's `isGetMethod` fallback in `apiRequest.ts`, so the two
|
|
790
|
+
* prefix heuristics can't drift apart. Expects an already-lowercased leaf name.
|
|
791
|
+
*/
|
|
792
|
+
declare const isGetMethodName: (methodNameLower: string) => boolean;
|
|
435
793
|
/**
|
|
436
794
|
* Infer the HTTP method from an API name based on common naming conventions.
|
|
437
795
|
*
|
|
@@ -462,7 +820,13 @@ declare const getEffectiveHttpMethod: (apiConfig: {
|
|
|
462
820
|
*
|
|
463
821
|
* @param requestMethod - The method from the HTTP request
|
|
464
822
|
* @param allowedMethod - The method the API accepts
|
|
465
|
-
* @returns true
|
|
823
|
+
* @returns true only when the method matches the route's allowed method.
|
|
824
|
+
*
|
|
825
|
+
* NOTE: `OPTIONS` is intentionally NOT treated as allowed here. A custom-route
|
|
826
|
+
* author wiring this into their dispatch must answer CORS preflights BEFORE the
|
|
827
|
+
* route check — letting `OPTIONS` through would execute the handler on a request
|
|
828
|
+
* the CSRF middleware treats as non-state-changing (CSRF-exempt), opening a
|
|
829
|
+
* bypass on method-locked routes.
|
|
466
830
|
*/
|
|
467
831
|
declare const isMethodAllowed: (requestMethod: string, allowedMethod: HttpMethod) => boolean;
|
|
468
832
|
|
|
@@ -634,9 +998,6 @@ interface AvatarConfig {
|
|
|
634
998
|
cacheControl: string;
|
|
635
999
|
}
|
|
636
1000
|
declare const DEFAULT_AVATAR_CONFIG: AvatarConfig;
|
|
637
|
-
type DeepPartial<T> = {
|
|
638
|
-
[K in keyof T]?: T[K] extends object | undefined ? DeepPartial<NonNullable<T[K]>> : T[K];
|
|
639
|
-
};
|
|
640
1001
|
type AvatarConfigInput = DeepPartial<AvatarConfig>;
|
|
641
1002
|
declare const registerAvatarConfig: (config: AvatarConfigInput) => void;
|
|
642
1003
|
declare const getAvatarConfig: () => AvatarConfig;
|
|
@@ -673,6 +1034,90 @@ declare const extractTokenFromSocket: (socket: Pick<Socket, "handshake">) => str
|
|
|
673
1034
|
*/
|
|
674
1035
|
declare const extractTokenFromRequest: (req: IncomingMessage) => string | null;
|
|
675
1036
|
|
|
1037
|
+
/**
|
|
1038
|
+
* Stable sentinel returned when no usable client address could be resolved.
|
|
1039
|
+
* Kept as a single exported constant so every rate-limit key-site funnels
|
|
1040
|
+
* missing addresses into one deterministic bucket instead of ad-hoc literals.
|
|
1041
|
+
*/
|
|
1042
|
+
declare const UNKNOWN_CLIENT_IP = "unknown";
|
|
1043
|
+
interface ResolveClientIpParams {
|
|
1044
|
+
/**
|
|
1045
|
+
* The raw transport peer address — `socket.handshake.address` (Socket.io)
|
|
1046
|
+
* or `req.socket.remoteAddress` (raw HTTP). May be `undefined`/`null` when
|
|
1047
|
+
* the connection has already been torn down.
|
|
1048
|
+
*/
|
|
1049
|
+
rawAddress: string | null | undefined;
|
|
1050
|
+
/** Request / handshake headers. Only consulted when `trustProxy` is true. */
|
|
1051
|
+
headers: IncomingHttpHeaders;
|
|
1052
|
+
/**
|
|
1053
|
+
* Whether a known reverse proxy sits in front of this server. DEFAULT false.
|
|
1054
|
+
* When false the raw peer address is returned verbatim (only IPv4-mapped
|
|
1055
|
+
* IPv6 canonicalization is applied), preserving historical behaviour. Only
|
|
1056
|
+
* enable when a trusted proxy populates `X-Forwarded-For` / `X-Real-IP`,
|
|
1057
|
+
* otherwise a client can spoof its own IP via those headers.
|
|
1058
|
+
*/
|
|
1059
|
+
trustProxy?: boolean;
|
|
1060
|
+
/**
|
|
1061
|
+
* Number of proxy hops to skip from the RIGHT of `X-Forwarded-For` when
|
|
1062
|
+
* `trustProxy` is on (CORE-O3). The rightmost entries are appended by your own
|
|
1063
|
+
* trusted proxies; the resolved client IP is the entry that many hops in from
|
|
1064
|
+
* the end. The leftmost hop is client-controlled and is never trusted. DEFAULT
|
|
1065
|
+
* 1 (the immediate upstream proxy). Clamped to the list length so an over-large
|
|
1066
|
+
* count falls back to the leftmost trusted hop rather than the spoofable entry.
|
|
1067
|
+
*/
|
|
1068
|
+
trustedProxyHopCount?: number;
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Whether a resolved client IP is a loopback / unresolved address — used by the
|
|
1072
|
+
* api/sync transports to honour `rateLimiting.skipLoopbackInDev` (api F5/F11).
|
|
1073
|
+
* Matches IPv4 loopback (`127.0.0.0/8`), IPv6 loopback (`::1`), the IPv4-mapped
|
|
1074
|
+
* form (`::ffff:127.0.0.1`, already canonicalized away by {@link resolveClientIp}),
|
|
1075
|
+
* and the {@link UNKNOWN_CLIENT_IP} sentinel. Pass an already-resolved IP.
|
|
1076
|
+
*/
|
|
1077
|
+
declare const isLoopbackIp: (ip: string) => boolean;
|
|
1078
|
+
/**
|
|
1079
|
+
* Derive the deterministic, non-reversible bucket component for a session
|
|
1080
|
+
* token. The same token always yields the same value (bucket identity is
|
|
1081
|
+
* preserved) while the raw token never appears in the returned string.
|
|
1082
|
+
* Used by api AND sync rate-limit key builders — lives in core so both
|
|
1083
|
+
* packages can share one implementation without a cross-package dependency.
|
|
1084
|
+
*/
|
|
1085
|
+
declare const deriveTokenBucketId: (token: string) => string;
|
|
1086
|
+
declare const resolveClientIp: ({ rawAddress, headers, trustProxy, trustedProxyHopCount }: ResolveClientIpParams) => string;
|
|
1087
|
+
|
|
1088
|
+
interface SessionSaveResult {
|
|
1089
|
+
ok: boolean;
|
|
1090
|
+
errorCode?: string;
|
|
1091
|
+
}
|
|
1092
|
+
interface SessionLogoutInput {
|
|
1093
|
+
token: string | null;
|
|
1094
|
+
socket?: Socket;
|
|
1095
|
+
userId?: string | null;
|
|
1096
|
+
skipSessionDelete?: boolean;
|
|
1097
|
+
}
|
|
1098
|
+
interface SessionProvider {
|
|
1099
|
+
getSession: (token: string | null) => Promise<BaseSessionLayout | null>;
|
|
1100
|
+
saveSession: (token: string, data: BaseSessionLayout, newUser?: boolean, options?: {
|
|
1101
|
+
supersedeToken?: string;
|
|
1102
|
+
}) => Promise<SessionSaveResult>;
|
|
1103
|
+
deleteSession: (token: string, options?: {
|
|
1104
|
+
skipSocketLogout?: boolean;
|
|
1105
|
+
}) => Promise<boolean>;
|
|
1106
|
+
logout: (input: SessionLogoutInput) => Promise<void>;
|
|
1107
|
+
}
|
|
1108
|
+
declare const registerSessionProvider: (next: SessionProvider) => void;
|
|
1109
|
+
declare const getRegisteredSessionProvider: () => SessionProvider | null;
|
|
1110
|
+
declare const isSessionProviderRegistered: () => boolean;
|
|
1111
|
+
declare const resetSessionProviderForTests: () => void;
|
|
1112
|
+
declare const readSession: (token: string | null) => Promise<BaseSessionLayout | null>;
|
|
1113
|
+
declare const writeSession: (token: string, data: BaseSessionLayout, newUser?: boolean, options?: {
|
|
1114
|
+
supersedeToken?: string;
|
|
1115
|
+
}) => Promise<SessionSaveResult>;
|
|
1116
|
+
declare const removeSession: (token: string, options?: {
|
|
1117
|
+
skipSocketLogout?: boolean;
|
|
1118
|
+
}) => Promise<boolean>;
|
|
1119
|
+
declare const performLogout: (input: SessionLogoutInput) => Promise<void>;
|
|
1120
|
+
|
|
676
1121
|
/**
|
|
677
1122
|
* Shared validation utilities for API and Sync request handlers.
|
|
678
1123
|
* Extracted to avoid code duplication between handleApiRequest and handleSyncRequest.
|
|
@@ -711,7 +1156,7 @@ interface ValidationResult$1 {
|
|
|
711
1156
|
*/
|
|
712
1157
|
declare const validateRequest: ({ auth, user }: {
|
|
713
1158
|
auth: AuthProps;
|
|
714
|
-
user
|
|
1159
|
+
user?: BaseSessionLayout | null;
|
|
715
1160
|
}) => ValidationResult$1;
|
|
716
1161
|
|
|
717
1162
|
/**
|
|
@@ -798,7 +1243,10 @@ declare const getRateLimitStatus: (key: string, limit: number) => Promise<RateLi
|
|
|
798
1243
|
declare const clearRateLimit: (key: string) => Promise<void>;
|
|
799
1244
|
/**
|
|
800
1245
|
* Clear all rate limits.
|
|
801
|
-
*
|
|
1246
|
+
* Intended for testing or dev-mode server reset only.
|
|
1247
|
+
* CORE-O8: throws in production to prevent accidental global counter wipe across
|
|
1248
|
+
* all tenants. If you need a production-safe reset, pass a scoped key to
|
|
1249
|
+
* `clearRateLimit` or implement a tenant-namespaced strategy.
|
|
802
1250
|
*/
|
|
803
1251
|
declare const clearAllRateLimits: () => Promise<void>;
|
|
804
1252
|
|
|
@@ -815,6 +1263,10 @@ declare const validateInputByType: ({ typeText, value, rootKey, filePath, }: {
|
|
|
815
1263
|
filePath?: string;
|
|
816
1264
|
}) => Promise<ValidationResult>;
|
|
817
1265
|
|
|
1266
|
+
declare const normalizeOrigin: ({ value, secure }: {
|
|
1267
|
+
value: string;
|
|
1268
|
+
secure: boolean;
|
|
1269
|
+
}) => string;
|
|
818
1270
|
declare const allowedOrigin: (origin: string) => boolean;
|
|
819
1271
|
|
|
820
1272
|
declare const registerSyncAbortController: (socketId: string, cb: string, controller: AbortController) => string;
|
|
@@ -825,6 +1277,47 @@ declare const unregisterApiAbortController: (key: string) => void;
|
|
|
825
1277
|
declare const abortApiByResponseIndex: (socketId: string, responseIndex: number | string) => boolean;
|
|
826
1278
|
declare const abortAllForSocket: (socketId: string) => void;
|
|
827
1279
|
|
|
1280
|
+
/**
|
|
1281
|
+
* Handle returned by {@link issueOneTimeToken}. `token` is the RAW token to hand
|
|
1282
|
+
* to the caller (embed in the emailed URL); call `store()` to persist its hash
|
|
1283
|
+
* to Redis with the configured TTL. Persisting is a separate step so the caller
|
|
1284
|
+
* can run veto logic (hooks, validation) between minting and committing without
|
|
1285
|
+
* leaving an orphan Redis key.
|
|
1286
|
+
*/
|
|
1287
|
+
interface OneTimeTokenHandle {
|
|
1288
|
+
/** The raw, single-use token. Returned exactly once; never stored verbatim. */
|
|
1289
|
+
token: string;
|
|
1290
|
+
/** Persist `sha256(token)` -> `payload` in Redis with the issue TTL. */
|
|
1291
|
+
store(): Promise<void>;
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Mint a one-time token in `namespace` carrying `payload`, redeemable for `ttl`
|
|
1295
|
+
* seconds. Returns the raw token plus a `store()` committer. The payload is
|
|
1296
|
+
* serialised to a string (objects via JSON); on redemption it is returned as a
|
|
1297
|
+
* string and the caller parses it (or use {@link consumeOneTimeTokenJson}).
|
|
1298
|
+
*
|
|
1299
|
+
* @param namespace Key namespace (e.g. `'-pwreset'`, `'-email-change'`) — routed
|
|
1300
|
+
* through `formatKey` so the active key formatter / project prefix applies.
|
|
1301
|
+
* @param ttlSeconds Time-to-live in seconds for the stored hash.
|
|
1302
|
+
* @param payload Value bound to the token. A string is stored verbatim; any
|
|
1303
|
+
* other value is `JSON.stringify`-d.
|
|
1304
|
+
*/
|
|
1305
|
+
declare const issueOneTimeToken: (namespace: string, ttlSeconds: number, payload: string | Record<string, unknown>) => OneTimeTokenHandle;
|
|
1306
|
+
/**
|
|
1307
|
+
* Atomically validate + consume a one-time token from `namespace`. Returns the
|
|
1308
|
+
* stored payload STRING on success (and deletes the entry, so it can never be
|
|
1309
|
+
* reused), or `null` when the token is missing / expired / malformed / already
|
|
1310
|
+
* consumed. A single `MULTI` `GET`+`DEL` guarantees at-most-once redemption.
|
|
1311
|
+
*/
|
|
1312
|
+
declare const consumeOneTimeToken: (namespace: string, token: string) => Promise<string | null>;
|
|
1313
|
+
/**
|
|
1314
|
+
* Convenience wrapper over {@link consumeOneTimeToken} that JSON-parses the
|
|
1315
|
+
* stored payload into `T`. Returns `null` on miss OR on a malformed JSON
|
|
1316
|
+
* payload. Use when the token was issued with an object payload.
|
|
1317
|
+
*/
|
|
1318
|
+
declare const consumeOneTimeTokenJson: <T>(namespace: string, token: string) => Promise<T | null>;
|
|
1319
|
+
declare const oneTimeTokenKey: (namespace: string, token: string) => string;
|
|
1320
|
+
|
|
828
1321
|
/**
|
|
829
1322
|
* Core hook contract: framework-generic payload shapes + augmentable registry.
|
|
830
1323
|
*
|
|
@@ -868,6 +1361,14 @@ interface HookStopSignal {
|
|
|
868
1361
|
stop: true;
|
|
869
1362
|
errorCode: string;
|
|
870
1363
|
httpStatus?: number;
|
|
1364
|
+
/**
|
|
1365
|
+
* Optional output override for per-recipient hooks (`preSyncRecipient`).
|
|
1366
|
+
* When present on a stop signal the framework DOES NOT skip the recipient —
|
|
1367
|
+
* instead it sends this value in place of the full `serverOutput`. Use to
|
|
1368
|
+
* redact PII before delivery without excluding the socket from the fanout.
|
|
1369
|
+
* Ignored by all other hook dispatch sites.
|
|
1370
|
+
*/
|
|
1371
|
+
overrideOutput?: unknown;
|
|
871
1372
|
}
|
|
872
1373
|
/** Handlers return undefined / void to continue, or a stop signal to abort the main flow. */
|
|
873
1374
|
type HookResult = void | undefined | HookStopSignal;
|
|
@@ -948,6 +1449,41 @@ interface PostSyncAuthorizePayload {
|
|
|
948
1449
|
/** Optional transport tag — see {@link PreApiValidatePayload.transport}. */
|
|
949
1450
|
transport?: 'socket' | 'http';
|
|
950
1451
|
}
|
|
1452
|
+
interface PreSyncValidatePayload {
|
|
1453
|
+
routeName: string;
|
|
1454
|
+
data: Record<string, unknown>;
|
|
1455
|
+
user: HookSessionShape | null;
|
|
1456
|
+
receiver: string;
|
|
1457
|
+
/** Optional transport tag — see {@link PreApiValidatePayload.transport}. */
|
|
1458
|
+
transport?: 'socket' | 'http';
|
|
1459
|
+
}
|
|
1460
|
+
interface PostSyncValidatePayload extends PreSyncValidatePayload {
|
|
1461
|
+
validation: {
|
|
1462
|
+
status: 'success';
|
|
1463
|
+
} | {
|
|
1464
|
+
status: 'error';
|
|
1465
|
+
message: string;
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
interface PreSyncExecutePayload {
|
|
1469
|
+
routeName: string;
|
|
1470
|
+
data: Record<string, unknown>;
|
|
1471
|
+
user: HookSessionShape | null;
|
|
1472
|
+
receiver: string;
|
|
1473
|
+
/** Optional transport tag — see {@link PreApiValidatePayload.transport}. */
|
|
1474
|
+
transport?: 'socket' | 'http';
|
|
1475
|
+
}
|
|
1476
|
+
interface PostSyncExecutePayload {
|
|
1477
|
+
routeName: string;
|
|
1478
|
+
data: Record<string, unknown>;
|
|
1479
|
+
user: HookSessionShape | null;
|
|
1480
|
+
receiver: string;
|
|
1481
|
+
result: unknown;
|
|
1482
|
+
error: Error | null;
|
|
1483
|
+
durationMs: number;
|
|
1484
|
+
/** Optional transport tag — see {@link PreApiValidatePayload.transport}. */
|
|
1485
|
+
transport?: 'socket' | 'http';
|
|
1486
|
+
}
|
|
951
1487
|
interface PreSyncFanoutPayload {
|
|
952
1488
|
routeName: string;
|
|
953
1489
|
data: Record<string, unknown>;
|
|
@@ -1012,6 +1548,14 @@ interface CorsRejectedPayload {
|
|
|
1012
1548
|
allowLocalhost: boolean;
|
|
1013
1549
|
/** Optional route the rejected request was for. */
|
|
1014
1550
|
route?: string;
|
|
1551
|
+
/**
|
|
1552
|
+
* Why the request was rejected (server HOK-27). Distinguishes a present-but-
|
|
1553
|
+
* disallowed Origin (`'origin-not-allowed'`) from a MISSING Origin header
|
|
1554
|
+
* (`'origin-missing'`, the 403 dispatched by the server's origin gate) and the
|
|
1555
|
+
* normalization-failure case. Optional so existing `allowedOrigin()` callers
|
|
1556
|
+
* that don't set it stay source-compatible.
|
|
1557
|
+
*/
|
|
1558
|
+
reason?: 'origin-not-allowed' | 'origin-missing' | 'origin-malformed';
|
|
1015
1559
|
}
|
|
1016
1560
|
interface PreSessionRefreshPayload {
|
|
1017
1561
|
token: string;
|
|
@@ -1027,6 +1571,18 @@ interface PostSessionRefreshPayload {
|
|
|
1027
1571
|
/** True if Redis EXPIRE succeeded; false on failure or non-existent key. */
|
|
1028
1572
|
applied: boolean;
|
|
1029
1573
|
}
|
|
1574
|
+
interface SessionCreatedPayload {
|
|
1575
|
+
token: string;
|
|
1576
|
+
userId: string;
|
|
1577
|
+
/** How the session came to exist (credentials login, OAuth, refresh-mint, ...). */
|
|
1578
|
+
via?: string;
|
|
1579
|
+
}
|
|
1580
|
+
interface SessionRevokedPayload {
|
|
1581
|
+
token: string;
|
|
1582
|
+
userId: string | null;
|
|
1583
|
+
/** Why the session was revoked (logout, kicked-by-new-device, admin, expiry, ...). */
|
|
1584
|
+
reason?: string;
|
|
1585
|
+
}
|
|
1030
1586
|
interface OnUploadStartPayload {
|
|
1031
1587
|
userId: string;
|
|
1032
1588
|
contentType: string;
|
|
@@ -1039,6 +1595,20 @@ interface OnUploadCompletePayload {
|
|
|
1039
1595
|
sizeBytes: number;
|
|
1040
1596
|
uploadKind: 'avatar' | string;
|
|
1041
1597
|
}
|
|
1598
|
+
interface PreAvatarServePayload {
|
|
1599
|
+
/** The route path requested (`/avatars/:fileId`). */
|
|
1600
|
+
routePath: string;
|
|
1601
|
+
/** The allowlisted file id resolved from the route path. */
|
|
1602
|
+
fileId: string;
|
|
1603
|
+
}
|
|
1604
|
+
interface PostAvatarServePayload {
|
|
1605
|
+
routePath: string;
|
|
1606
|
+
fileId: string;
|
|
1607
|
+
/** Disk extension of the format that was served (e.g. `'webp'`). */
|
|
1608
|
+
extension: string;
|
|
1609
|
+
/** Content-Type header sent for the served file. */
|
|
1610
|
+
contentType: string;
|
|
1611
|
+
}
|
|
1042
1612
|
interface CsrfMismatchPayload {
|
|
1043
1613
|
/** Path of the rejected request. */
|
|
1044
1614
|
route: string;
|
|
@@ -1051,6 +1621,18 @@ interface CsrfMismatchPayload {
|
|
|
1051
1621
|
/** Whether a token was provided in `x-csrf-token` (presence only — never the value). */
|
|
1052
1622
|
providedToken: boolean;
|
|
1053
1623
|
}
|
|
1624
|
+
interface PreSocketMessagePayload {
|
|
1625
|
+
/** Which socket pipeline received the message. */
|
|
1626
|
+
channel: 'api' | 'sync';
|
|
1627
|
+
/** Socket.io connection id of the originator. */
|
|
1628
|
+
socketId: string;
|
|
1629
|
+
/** Handshake address of the originator (best-effort; honours no proxy trust). */
|
|
1630
|
+
ip: string;
|
|
1631
|
+
/** Whether the originating socket carried a session token (presence only — never the value). */
|
|
1632
|
+
authenticated: boolean;
|
|
1633
|
+
/** Raw route name from the message envelope, when present (un-parsed, un-trusted). */
|
|
1634
|
+
routeName?: string;
|
|
1635
|
+
}
|
|
1054
1636
|
interface PreHttpRequestPayload {
|
|
1055
1637
|
/** HTTP method (always uppercase: GET/POST/...). */
|
|
1056
1638
|
method: string;
|
|
@@ -1067,8 +1649,64 @@ interface PreHttpRequestPayload {
|
|
|
1067
1649
|
*/
|
|
1068
1650
|
headers: Record<string, string>;
|
|
1069
1651
|
}
|
|
1652
|
+
interface PostHttpRequestPayload {
|
|
1653
|
+
/** HTTP method (always uppercase). */
|
|
1654
|
+
method: string;
|
|
1655
|
+
/** Request URL (path + query). */
|
|
1656
|
+
url: string;
|
|
1657
|
+
/** Caller-supplied or framework-generated `X-Request-Id`. */
|
|
1658
|
+
requestId: string;
|
|
1659
|
+
/** Final HTTP status code written to the response. */
|
|
1660
|
+
statusCode: number;
|
|
1661
|
+
/** Wall-clock duration from request receipt to response, in ms. */
|
|
1662
|
+
durationMs: number;
|
|
1663
|
+
}
|
|
1664
|
+
interface ApiAuthRejectedPayload {
|
|
1665
|
+
/** Resolved route name (`api/billing/getInvoice/v1`). */
|
|
1666
|
+
routeName: string;
|
|
1667
|
+
/** Why auth failed. `'login-required'` = no/invalid session on a login route;
|
|
1668
|
+
* `'additional-failed'` = a session existed but an `additional[]` predicate
|
|
1669
|
+
* rejected; `'invalid-condition'` = a misconfigured predicate (setup error). */
|
|
1670
|
+
reason: 'login-required' | 'additional-failed' | 'invalid-condition';
|
|
1671
|
+
/** Session user id when a (insufficient) session was present, else null. */
|
|
1672
|
+
userId: string | null;
|
|
1673
|
+
/** Resolved client IP (honours `http.trustProxy`). */
|
|
1674
|
+
ip?: string;
|
|
1675
|
+
/** Transport the request arrived on. */
|
|
1676
|
+
transport?: 'socket' | 'http';
|
|
1677
|
+
/** The specific `additional[]` key that failed, when `reason === 'additional-failed'`. */
|
|
1678
|
+
failedKey?: string;
|
|
1679
|
+
}
|
|
1680
|
+
interface PreSyncRecipientPayload {
|
|
1681
|
+
/** Resolved route name (`sync/board/moveCard/v1`). */
|
|
1682
|
+
routeName: string;
|
|
1683
|
+
/** Room code / receiver this fanout is for. */
|
|
1684
|
+
receiver: string;
|
|
1685
|
+
/** Socket id of THIS recipient. */
|
|
1686
|
+
recipientSocketId: string;
|
|
1687
|
+
/**
|
|
1688
|
+
* Recipient's session user id. `null` by default (avoids a Redis read per
|
|
1689
|
+
* recipient on the hot path). Populated when the consumer registers a
|
|
1690
|
+
* `resolveRecipientUser` function via `registerHookHandler` options.
|
|
1691
|
+
*/
|
|
1692
|
+
recipientUserId: string | null;
|
|
1693
|
+
/** The server-validated output about to be sent. */
|
|
1694
|
+
serverOutput: unknown;
|
|
1695
|
+
}
|
|
1696
|
+
interface PreServerStopPayload {
|
|
1697
|
+
/** Why the server is stopping — the signal name, or `'manual'` for a programmatic stop. */
|
|
1698
|
+
reason: 'SIGTERM' | 'SIGINT' | 'SIGHUP' | 'manual';
|
|
1699
|
+
/**
|
|
1700
|
+
* Soft budget (ms) the server intends to wait for shutdown handlers + in-flight
|
|
1701
|
+
* requests to drain before forcing exit. Handlers should not block longer than
|
|
1702
|
+
* this. `undefined` when the server applies no deadline.
|
|
1703
|
+
*/
|
|
1704
|
+
timeoutMs?: number;
|
|
1705
|
+
}
|
|
1070
1706
|
interface HookPayloads {
|
|
1071
1707
|
preHttpRequest: PreHttpRequestPayload;
|
|
1708
|
+
postHttpRequest: PostHttpRequestPayload;
|
|
1709
|
+
preSocketMessage: PreSocketMessagePayload;
|
|
1072
1710
|
preApiValidate: PreApiValidatePayload;
|
|
1073
1711
|
postApiValidate: PostApiValidatePayload;
|
|
1074
1712
|
preApiExecute: PreApiExecutePayload;
|
|
@@ -1078,19 +1716,30 @@ interface HookPayloads {
|
|
|
1078
1716
|
postApiRespond: PostApiRespondPayload;
|
|
1079
1717
|
preSyncAuthorize: PreSyncAuthorizePayload;
|
|
1080
1718
|
postSyncAuthorize: PostSyncAuthorizePayload;
|
|
1719
|
+
preSyncValidate: PreSyncValidatePayload;
|
|
1720
|
+
postSyncValidate: PostSyncValidatePayload;
|
|
1721
|
+
preSyncExecute: PreSyncExecutePayload;
|
|
1722
|
+
postSyncExecute: PostSyncExecutePayload;
|
|
1081
1723
|
preSyncFanout: PreSyncFanoutPayload;
|
|
1082
1724
|
postSyncFanout: PostSyncFanoutPayload;
|
|
1725
|
+
preSyncRecipient: PreSyncRecipientPayload;
|
|
1083
1726
|
preSyncStream: PreSyncStreamPayload;
|
|
1084
1727
|
postSyncStream: PostSyncStreamPayload;
|
|
1085
1728
|
apiError: ApiErrorPayload;
|
|
1086
1729
|
syncError: SyncErrorPayload;
|
|
1730
|
+
apiAuthRejected: ApiAuthRejectedPayload;
|
|
1087
1731
|
rateLimitExceeded: RateLimitExceededPayload;
|
|
1088
1732
|
corsRejected: CorsRejectedPayload;
|
|
1089
1733
|
csrfMismatch: CsrfMismatchPayload;
|
|
1090
1734
|
preSessionRefresh: PreSessionRefreshPayload;
|
|
1091
1735
|
postSessionRefresh: PostSessionRefreshPayload;
|
|
1736
|
+
sessionCreated: SessionCreatedPayload;
|
|
1737
|
+
sessionRevoked: SessionRevokedPayload;
|
|
1092
1738
|
onUploadStart: OnUploadStartPayload;
|
|
1093
1739
|
onUploadComplete: OnUploadCompletePayload;
|
|
1740
|
+
preAvatarServe: PreAvatarServePayload;
|
|
1741
|
+
postAvatarServe: PostAvatarServePayload;
|
|
1742
|
+
preServerStop: PreServerStopPayload;
|
|
1094
1743
|
}
|
|
1095
1744
|
interface PreErrorNormalizePayload {
|
|
1096
1745
|
response: ErrorResponseInput;
|
|
@@ -1117,10 +1766,10 @@ type DispatchResult = {
|
|
|
1117
1766
|
stopped: true;
|
|
1118
1767
|
signal: HookStopSignal;
|
|
1119
1768
|
};
|
|
1120
|
-
declare const registerHook: <TName extends HookName>(name: TName, handler: HookHandler<HookPayloads[TName]>) => void;
|
|
1769
|
+
declare const registerHook: <TName extends HookName>(name: TName, handler: HookHandler<HookPayloads[TName]>) => (() => void);
|
|
1121
1770
|
declare const dispatchHook: <TName extends HookName>(name: TName, payload: HookPayloads[TName]) => Promise<DispatchResult>;
|
|
1122
1771
|
declare const clearAllHooks: () => void;
|
|
1123
|
-
declare const registerSyncHook: <TName extends SyncHookName>(name: TName, handler: SyncHookHandler<SyncHookPayloads[TName]>) => void;
|
|
1772
|
+
declare const registerSyncHook: <TName extends SyncHookName>(name: TName, handler: SyncHookHandler<SyncHookPayloads[TName]>) => (() => void);
|
|
1124
1773
|
declare const dispatchSyncHook: <TName extends SyncHookName>(name: TName, payload: SyncHookPayloads[TName]) => void;
|
|
1125
1774
|
|
|
1126
|
-
export { type ApiErrorPayload, type ApiResponseEnvelope, AuthProps, type AvatarConfig, type AvatarConfigInput, BOOT_KEY_PREFIX, BaseSessionLayout, type CheckRateLimitParams, type CorsRejectedPayload, type CreateLocalizedNormalizerInput, type CsrfConfig, type CsrfCookieOptions, type CsrfMismatchPayload, DEFAULT_AVATAR_CONFIG, DEFAULT_CLIENT_KEY, DEFAULT_CSRF_CONFIG, DEFAULT_ENV_FILES, type DeployConfigShape, type DeployDevelopmentShape, type DeployEnvironmentShape, type DeployResourceShape, type DeployRoutingShape, type DispatchResult, type EmailMessage, type EmailResult, type EmailSender, type EmailSenderRegistry, type ErrorFormatter, type ErrorFormatterContext, ErrorParam, ErrorResponseInput, type ErrorTracker, type ErrorTrackerContext, type ErrorTrackerEvent, type ErrorTrackerUser, GENERATED_API_DOCS_PATH, GENERATED_API_SCHEMAS_PATH, GENERATED_SOCKET_TYPES_PATH, type HookHandler, type HookName, type HookPayloads, type HookResult, type HookSessionShape, type HookStopSignal, type HttpMethod, type LanguageCode, type LocaleReloader, type LocalizedNormalizer, type NormalizeErrorResponseInput, NormalizedErrorResponse, type OnUploadCompletePayload, type OnUploadStartPayload, PUBLIC_DIR, type PostApiExecutePayload, type PostApiRespondPayload, type PostApiValidatePayload, type PostErrorNormalizePayload, type PostSessionRefreshPayload, type PostSyncFanoutPayload, type PreApiExecutePayload, type PreApiRespondPayload, type PreApiValidatePayload, type PreErrorNormalizePayload, type PreSessionRefreshPayload, type PreSyncAuthorizePayload, type PreSyncFanoutPayload, type PresetDefinition, type ProcessUploadInput, type ProcessUploadResult, ROOT_DIR, type RateLimitExceededPayload, type RateLimitResult, type RateLimitStrategy, type RedisConnectionOptions, type RedisKeyFormatter, type RuntimeApiMapsResult, type RuntimeEnv, type RuntimeMapsProvider, type RuntimeSyncMapsResult, SERVER_DIR, SERVER_FUNCTIONS_DIR, SHARED_DIR, SRC_DIR, type ServiceDefinition, type ServicesConfigShape, type SocketMiddleware, type SpanResult, type SyncErrorPayload, type SyncHookHandler, type SyncHookName, type SyncHookPayloads, TSCONFIG_ALIAS_FILES, type TranslateFunction, type TranslateInput, UPLOADS_DIR, type ValidationResult$1 as ValidationResult, abortAllForSocket, abortApiByResponseIndex, abortSyncByCb, acquireLease, allowedOrigin, type apiMessage, applyErrorFormatter, applySocketMiddlewares, applyStrayKeyPrefix, attachSocketRedisAdapter, bootstrapEnv, captureException, captureExceptionAcrossTrackers, captureMessage, captureMessageAcrossTrackers, checkRateLimit, clearAllHooks, clearAllRateLimits, clearRateLimit, clearSocketMiddlewares, collectSynchronizedEnvKeys, computeSynchronizedEnvHashes, createLocalizedNormalizer, defaultRateLimitStrategy, defaultRedisKeyFormatter, dispatchHook, dispatchSyncHook, env, extractLanguageFromHeader, extractTokenFromRequest, extractTokenFromSocket, formatKey, getActiveErrorTrackers, getAvatarConfig, getBindAddress, getCookieValue, getCsrfConfig, getDeployConfig, getEffectiveHttpMethod, getEmailSender, getEmailSenderByName, getEnvFiles, getErrorFormatter, getGeneratedApiDocsPath, getGeneratedApiSchemasPath, getGeneratedSocketTypesPath, getIoInstance, getLocaleReloader, getLocalizedNormalizer, getParams, getPrismaClient, getPrismaClientFor, getPrismaClientKeys, getPublicDir, getRateLimitStatus, getRateLimitStrategy, getRedactedLogKeys, getRedisClient, getRedisClientFor, getRedisClientKeys, getRedisConnectionOptions, getRedisKeyFormatter, getRuntimeApiMaps, getRuntimeSyncMaps, getServerDir, getServerFunctionDirs, getServerFunctionsDir, getServicesConfig, getSharedDir, getSocketMiddlewares, getSrcDir, getUploadsDir, hasCookie, hashSynchronizedValue, inferHttpMethod, initConsolelog, initSharedSentry, isDeployConfigRegistered, isEmailSenderRegistered, isFalsy, isLocalizedNormalizerRegistered, isMethodAllowed, isPrismaClientRegistered, isProduction, isRedactedLogKey, isRedisClientRegistered, isRuntimeMapsProviderRegistered, isServicesConfigRegistered, listEmailSenderNames, loadEnvFiles, normalizeErrorResponse, prisma, processUpload, readBootUuid, recordMetricAcrossTrackers, redis, registerApiAbortController, registerAvatarConfig, registerBindAddress, registerCsrfConfig, registerDeployConfig, registerEmailSender, registerEmailSenders, registerErrorFormatter, registerErrorTracker, registerErrorTrackers, registerHook, registerLocaleReloader, registerLocalizedNormalizer, registerPrismaClient, registerRateLimitStrategy, registerRedactedLogKeys, registerRedisClient, registerRedisKeyFormatter, registerRuntimeMapsProvider, registerServicesConfig, registerSocketMiddleware, registerSyncAbortController, registerSyncHook, releaseLease, renewLease, resetClientsForTests, resetCsrfConfigForTests, resetRedactedLogKeysForTests, resetRedisKeyFormatterForTests, resolveEnvKey, resolveErrorMessage, resolveFromRoot, serveAvatar, setErrorTrackerUser, setIoInstance, setSentryUser, startSpan, startSpanAcrossTrackers, type syncMessage, unregisterApiAbortController, unregisterSyncAbortController, validateInputByType, validateRequest, writeBootUuid };
|
|
1775
|
+
export { type ApiAuthRejectedPayload, type ApiErrorPayload, type ApiResponseEnvelope, AuthProps, type AvatarConfig, type AvatarConfigInput, BOOT_KEY_PREFIX, BaseSessionLayout, type CheckRateLimitParams, type CookiePrefixConstraints, type CorsRejectedPayload, type CreateLocalizedNormalizerInput, type CsrfConfig, type CsrfCookieOptions, type CsrfMismatchPayload, DEFAULT_AVATAR_CONFIG, DEFAULT_CLIENT_KEY, DEFAULT_CSRF_CONFIG, DEFAULT_ENV_FILES, DEFAULT_REDACTED_LOG_KEYS, DEPTH_TRUNCATED_PLACEHOLDER, DeepPartial, type DeployConfigShape, type DeployDevelopmentShape, type DeployEnvironmentShape, type DeployResourceShape, type DeployRoutingShape, type DispatchResult, type EmailAttachment, type EmailMessage, type EmailResult, type EmailSender, type EmailSenderRegistry, type ErrorFormatter, type ErrorFormatterContext, ErrorParam, ErrorResponseInput, type ErrorTracker, type ErrorTrackerContext, type ErrorTrackerEvent, type ErrorTrackerUser, type FormatterEnvelope, GENERATED_API_DOCS_PATH, GENERATED_API_SCHEMAS_PATH, GENERATED_SOCKET_TYPES_PATH, HealthHashConfig, type HealthHashDescriptor, type HookHandler, type HookName, type HookPayloads, type HookResult, type HookSessionShape, type HookStopSignal, type HttpMethod, type LanguageCode, type LocaleReloader, type LocalizedNormalizer, type NormalizeErrorResponseInput, NormalizedErrorResponse, type OnUploadCompletePayload, type OnUploadStartPayload, type OneTimeTokenHandle, PUBLIC_DIR, type PeerRequire, type PostApiExecutePayload, type PostApiRespondPayload, type PostApiValidatePayload, type PostAvatarServePayload, type PostErrorNormalizePayload, type PostHttpRequestPayload, type PostSessionRefreshPayload, type PostSyncAuthorizePayload, type PostSyncExecutePayload, type PostSyncFanoutPayload, type PostSyncValidatePayload, type PreApiExecutePayload, type PreApiRespondPayload, type PreApiValidatePayload, type PreAvatarServePayload, type PreCaptureFilter, type PreErrorNormalizePayload, type PreHttpRequestPayload, type PreServerStopPayload, type PreSessionRefreshPayload, type PreSocketMessagePayload, type PreSyncAuthorizePayload, type PreSyncExecutePayload, type PreSyncFanoutPayload, type PreSyncRecipientPayload, type PreSyncValidatePayload, type PresetDefinition, type ProcessUploadInput, type ProcessUploadResult, REDACTED_PLACEHOLDER, ROOT_DIR, type RateLimitExceededPayload, type RateLimitResult, type RateLimitStrategy, type RedisConnectionOptions, type RedisKeyFormatter, type Registry, type RegistryOptions, type ResolveClientIpParams, type RoomNameFormatter, type RoomNameFormatterContext, type RuntimeApiMapsResult, type RuntimeEnv, type RuntimeMapsProvider, type RuntimeSyncMapsResult, SERVER_DIR, SERVER_FUNCTIONS_DIR, SHARED_DIR, SRC_DIR, type ServiceDefinition, type ServicesConfigShape, type SessionCreatedPayload, type SessionLogoutInput, type SessionProvider, type SessionRevokedPayload, type SessionSaveResult, type SocketMiddleware, type SpanHandle, type SpanResult, type SyncErrorPayload, type SyncHookHandler, type SyncHookName, type SyncHookPayloads, TSCONFIG_ALIAS_FILES, type TranslateFunction, type TranslateInput, UNKNOWN_CLIENT_IP, UPLOADS_DIR, type ValidationResult$1 as ValidationResult, abortAllForSocket, abortApiByResponseIndex, abortSyncByCb, acquireLease, allowedOrigin, type apiMessage, appendErrorTracker, applyCookiePrefixConstraints, applyErrorFormatter, applySocketMiddlewares, applyStrayKeyPrefix, attachSocketRedisAdapter, bootstrapEnv, captureException, captureExceptionAcrossTrackers, captureMessage, captureMessageAcrossTrackers, checkRateLimit, clearAllHooks, clearAllRateLimits, clearRateLimit, clearSocketMiddlewares, collectSynchronizedEnvKeys, computeSynchronizedEnvHashes, consumeOneTimeToken, consumeOneTimeTokenJson, createLocalizedNormalizer, createRegistry, defaultRateLimitStrategy, defaultRedisKeyFormatter, defaultRoomNameFormatter, deriveTokenBucketId, describeHealthHashConfig, dispatchHook, dispatchSyncHook, ensurePeerDepInstalled, env, escapeHtml, extractLanguageFromHeader, extractTokenFromRequest, extractTokenFromSocket, flushErrorTrackers, formatKey, formatRoomName, getActiveErrorTrackers, getAvatarConfig, getBindAddress, getCookieValue, getCsrfConfig, getCurrentErrorTrackerIdentity, getDeployConfig, getEffectiveHttpMethod, getEmailSender, getEmailSenderByName, getEnv, getEnvFiles, getErrorFormatter, getGeneratedApiDocsPath, getGeneratedApiSchemasPath, getGeneratedSocketTypesPath, getIoInstance, getLocaleReloader, getLocalizedNormalizer, getParams, getPrismaClient, getPrismaClientFor, getPrismaClientKeys, getPublicDir, getRateLimitStatus, getRateLimitStrategy, getRedactedLogKeys, getRedisClient, getRedisClientFor, getRedisClientKeys, getRedisConnectionOptions, getRedisKeyFormatter, getRegisteredSessionProvider, getRoomNameFormatter, getRuntimeApiMaps, getRuntimeSyncMaps, getServerDir, getServerFunctionDirs, getServerFunctionsDir, getServicesConfig, getSharedDir, getSocketMiddlewares, getSrcDir, getUploadsDir, hasCookie, hashSynchronizedValue, hashSynchronizedValueWith, inferHttpMethod, initConsolelog, initSharedSentry, isDeployConfigRegistered, isEmailSenderRegistered, isFalsy, isGetMethodName, isLocalizedNormalizerRegistered, isLoopbackIp, isMethodAllowed, isPrismaClientRegistered, isProduction, isRedactedLogKey, isRedisClientRegistered, isRuntimeMapsProviderRegistered, isServicesConfigRegistered, isSessionProviderRegistered, issueOneTimeToken, listEmailSenderNames, loadEnvFiles, loadPeer, normalizeErrorResponse, normalizeOrigin, oneTimeTokenKey, performLogout, prisma, processUpload, readBootUuid, readSession, recordMetricAcrossTrackers, redis, registerApiAbortController, registerAvatarConfig, registerBindAddress, registerCsrfConfig, registerDeployConfig, registerEmailSender, registerEmailSenders, registerErrorFormatter, registerErrorTracker, registerErrorTrackers, registerHook, registerLocaleReloader, registerLocalizedNormalizer, registerPreCaptureFilter, registerPrismaClient, registerRateLimitStrategy, registerRedactedLogKeys, registerRedisClient, registerRedisKeyFormatter, registerRoomNameFormatter, registerRuntimeMapsProvider, registerServicesConfig, registerSessionProvider, registerSocketMiddleware, registerStrayPrefixCommand, registerSyncAbortController, registerSyncHook, releaseLease, removeSession, renewLease, resetClientsForTests, resetCsrfConfigForTests, resetRedactedLogKeysForTests, resetRedisKeyFormatterForTests, resetSessionProviderForTests, resolveClientIp, resolveEnvKey, resolveErrorMessage, resolveFromRoot, resolveHealthHashConfig, resolveHealthHashConfigFromDescriptor, runWithErrorTrackerIdentity, runWithErrorTrackerIdentityScope, sanitizeErrorString, sanitizeErrorStrings, sanitizeForLog, serveAvatar, setCurrentErrorTrackerIdentity, setErrorTrackerUser, setIoInstance, setSentryUser, startSpan, startSpanAcrossTrackers, startSpanHandle, type syncMessage, tryCatch, tryCatchSync, unregisterApiAbortController, unregisterSyncAbortController, validateInputByType, validateRequest, writeBootUuid, writeSession };
|