@spfn/core 0.2.0-beta.67 → 0.2.0-beta.68
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/README.md +309 -116
- package/dist/authz/index.js +398 -3
- package/dist/authz/index.js.map +1 -1
- package/dist/codegen/index.d.ts +114 -8
- package/dist/codegen/index.js +162 -3
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/contract/index.d.ts +288 -0
- package/dist/contract/index.js +534 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/{define-middleware-DuXD8Hvu.d.ts → define-middleware-B9bFuXVU.d.ts} +1 -1
- package/dist/errors/index.js +398 -3
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +3 -3
- package/dist/event/sse/client.d.ts +2 -2
- package/dist/event/sse/index.d.ts +4 -4
- package/dist/event/sse/index.js +9 -0
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +2 -2
- package/dist/event/ws/index.d.ts +3 -3
- package/dist/middleware/index.d.ts +108 -11
- package/dist/middleware/index.js +769 -632
- package/dist/middleware/index.js.map +1 -1
- package/dist/route/index.d.ts +8 -552
- package/dist/route/index.js +36 -0
- package/dist/route/index.js.map +1 -1
- package/dist/router-DhvbMhef.d.ts +641 -0
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.js +9 -0
- package/dist/server/index.js.map +1 -1
- package/dist/{token-manager-jKD_EsSE.d.ts → token-manager-vZeqBbtA.d.ts} +7 -0
- package/dist/{types-DVjf37yO.d.ts → types-CF-37KAG.d.ts} +1 -1
- package/dist/{types-BFB72jbM.d.ts → types-D9uMxeQS.d.ts} +1 -1
- package/package.json +11 -9
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { Context, Next, MiddlewareHandler } from 'hono';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Error Handler Middleware
|
|
6
|
-
*
|
|
7
|
-
* Handles SerializableError with automatic serialization and standard errors
|
|
8
|
-
*/
|
|
2
|
+
import { N as NamedMiddlewareFactory, b as NamedMiddleware } from '../define-middleware-B9bFuXVU.js';
|
|
3
|
+
import { Redis, Cluster } from 'ioredis';
|
|
9
4
|
|
|
10
5
|
/**
|
|
11
6
|
* Options for ErrorHandler middleware
|
|
@@ -27,6 +22,21 @@ interface ErrorHandlerOptions {
|
|
|
27
22
|
* @default true
|
|
28
23
|
*/
|
|
29
24
|
enableLogging?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Attach the `error` envelope to every error response
|
|
27
|
+
*
|
|
28
|
+
* The envelope is `{ code, message, requestId }` sitting next to the
|
|
29
|
+
* existing `__type` and `message` fields, never replacing them: a web
|
|
30
|
+
* client restores its error class from `__type` while a generated client
|
|
31
|
+
* in another language classifies by `code` alone and cannot read a
|
|
32
|
+
* discriminator it has no registry for.
|
|
33
|
+
*
|
|
34
|
+
* Turn it off only to keep error bodies byte-identical to an older
|
|
35
|
+
* release. A route reached by a generated client needs it.
|
|
36
|
+
*
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
errorEnvelope?: boolean;
|
|
30
40
|
/**
|
|
31
41
|
* Callback invoked when an error occurs
|
|
32
42
|
*
|
|
@@ -57,6 +67,10 @@ interface OnErrorContext {
|
|
|
57
67
|
* SerializableError instances are serialized using their toJSON() method,
|
|
58
68
|
* preserving custom fields like `resource`, `fields`, etc.
|
|
59
69
|
*
|
|
70
|
+
* Every response also carries an `error` envelope — `{ code, message,
|
|
71
|
+
* requestId }` — for clients that classify by a single documented field
|
|
72
|
+
* instead of restoring an error class from `__type`.
|
|
73
|
+
*
|
|
60
74
|
* @param options - Configuration options
|
|
61
75
|
* @returns Error handler function for Hono's onError hook
|
|
62
76
|
*
|
|
@@ -76,7 +90,8 @@ interface OnErrorContext {
|
|
|
76
90
|
* // Throw SerializableError in routes
|
|
77
91
|
* app.get('/users/:id', (c) => {
|
|
78
92
|
* throw new NotFoundError({ message: 'User not found', resource: 'User' });
|
|
79
|
-
* // Response: { __type: 'NotFoundError', message: 'User not found', resource: 'User'
|
|
93
|
+
* // Response: { __type: 'NotFoundError', message: 'User not found', resource: 'User',
|
|
94
|
+
* // error: { code: 'NotFoundError', message: 'User not found', requestId: '…' } }
|
|
80
95
|
* });
|
|
81
96
|
* ```
|
|
82
97
|
*/
|
|
@@ -285,6 +300,8 @@ declare function createCacheNonceStore(cache: CacheClient, prefix?: string): Non
|
|
|
285
300
|
*/
|
|
286
301
|
declare function createInMemoryNonceStore(): NonceStore;
|
|
287
302
|
|
|
303
|
+
/** Test seam: forget every process-local window. */
|
|
304
|
+
declare function resetMemoryRateLimitStore(): void;
|
|
288
305
|
/**
|
|
289
306
|
* One identity dimension to limit on. A bare string uses the top-level `limit`;
|
|
290
307
|
* an object can carry its own `limit` so dimensions can differ (e.g. a loose
|
|
@@ -311,7 +328,11 @@ interface RateLimitOptions {
|
|
|
311
328
|
* client IP only.
|
|
312
329
|
*/
|
|
313
330
|
by?: (c: Context) => (RateLimitDimension | null | undefined)[] | Promise<(RateLimitDimension | null | undefined)[]>;
|
|
314
|
-
/**
|
|
331
|
+
/**
|
|
332
|
+
* Refuse with 429 when the shared cache is unavailable, instead of counting
|
|
333
|
+
* in this process. For a surface where a per-process count is not an
|
|
334
|
+
* acceptable substitute for a shared one.
|
|
335
|
+
*/
|
|
315
336
|
failClosed?: boolean;
|
|
316
337
|
/** Message for the 429 response. */
|
|
317
338
|
message?: string;
|
|
@@ -333,7 +354,8 @@ interface RateLimitOptions {
|
|
|
333
354
|
*/
|
|
334
355
|
declare function getClientIp(c: Context): string;
|
|
335
356
|
/**
|
|
336
|
-
*
|
|
357
|
+
* Fixed-window rate limiter — counters in the shared cache when there is one,
|
|
358
|
+
* in this process otherwise.
|
|
337
359
|
*
|
|
338
360
|
* @example
|
|
339
361
|
* ```typescript
|
|
@@ -380,4 +402,79 @@ declare function getRateLimitPolicy(name: string): RateLimitOptions | undefined;
|
|
|
380
402
|
*/
|
|
381
403
|
declare function rateLimitPolicy(name: string, fallback: RateLimitOptions): NamedMiddleware<string>;
|
|
382
404
|
|
|
383
|
-
|
|
405
|
+
/**
|
|
406
|
+
* The rate limiter's fixed-window counter as a pluggable store — the same
|
|
407
|
+
* pattern the clientProofV1 replay ledger and the SSE token manager already
|
|
408
|
+
* use: an in-memory default, a Redis/Valkey store on top of `getCache()`, and
|
|
409
|
+
* the cache's presence deciding which one a request gets.
|
|
410
|
+
*
|
|
411
|
+
* Why the memory default exists: without it, "no cache configured" and "cache
|
|
412
|
+
* down" both meant the limiter had nowhere to count, so the only choices were
|
|
413
|
+
* letting every request through or refusing every request. Neither is what a
|
|
414
|
+
* limiter is for. Counting in the process is worse than counting in Redis and
|
|
415
|
+
* far better than not counting.
|
|
416
|
+
*
|
|
417
|
+
* What the memory store cannot do is span processes. Behind N instances each
|
|
418
|
+
* keeps its own counters, so the effective limit is N times the configured one.
|
|
419
|
+
* That is the cost of the fallback and the reason a real deployment still
|
|
420
|
+
* points `CACHE_URL` at Redis.
|
|
421
|
+
*
|
|
422
|
+
* @module middleware/rate-limit-store
|
|
423
|
+
*/
|
|
424
|
+
|
|
425
|
+
/** One window's state for a key: how many hits, and how long the window has left. */
|
|
426
|
+
interface RateLimitHit {
|
|
427
|
+
count: number;
|
|
428
|
+
/** Milliseconds until the window resets. */
|
|
429
|
+
pttl: number;
|
|
430
|
+
}
|
|
431
|
+
/** What the limiter needs from wherever the counters live. */
|
|
432
|
+
interface RateLimitStore {
|
|
433
|
+
/** Records one hit against `key` and answers the window's state after it. */
|
|
434
|
+
hit(key: string, windowMs: number): Promise<RateLimitHit>;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Counters in Redis — shared by every instance, so the configured limit is the
|
|
438
|
+
* limit no matter how many processes serve the traffic.
|
|
439
|
+
*/
|
|
440
|
+
declare class CacheRateLimitStore implements RateLimitStore {
|
|
441
|
+
private readonly cache;
|
|
442
|
+
constructor(cache: Redis | Cluster);
|
|
443
|
+
hit(key: string, windowMs: number): Promise<RateLimitHit>;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Counters in this process.
|
|
447
|
+
*
|
|
448
|
+
* Entries are pruned lazily — a key past its window resets on its next hit, so
|
|
449
|
+
* the common path stays O(1). Keys nobody touches again would otherwise sit
|
|
450
|
+
* there forever, so a full sweep runs once the map crosses `maxKeys`; that
|
|
451
|
+
* bound is what keeps a limiter keyed by client IP from growing without end.
|
|
452
|
+
*/
|
|
453
|
+
declare class MemoryRateLimitStore implements RateLimitStore {
|
|
454
|
+
private readonly maxKeys;
|
|
455
|
+
private readonly windows;
|
|
456
|
+
/** How many live windows were dropped to stay under `maxKeys`. */
|
|
457
|
+
private evicted;
|
|
458
|
+
constructor(maxKeys?: number);
|
|
459
|
+
hit(key: string, windowMs: number): Promise<RateLimitHit>;
|
|
460
|
+
/** Drops every window that has already reset. */
|
|
461
|
+
prune(nowMillis: number): void;
|
|
462
|
+
/**
|
|
463
|
+
* Frees a slot for a new key.
|
|
464
|
+
*
|
|
465
|
+
* Expired windows go first. If every window is still live the oldest one is
|
|
466
|
+
* dropped, because a hard bound is the only thing standing between a
|
|
467
|
+
* per-IP limiter and unbounded memory. A dropped window loses its count,
|
|
468
|
+
* so a caller who can mint `maxKeys` distinct identities can push another
|
|
469
|
+
* one out — which is why `evictionCount` is worth watching: it says this
|
|
470
|
+
* process is past what an in-memory limiter should be asked to hold, and
|
|
471
|
+
* the deployment wants a real cache.
|
|
472
|
+
*/
|
|
473
|
+
private makeRoom;
|
|
474
|
+
get size(): number;
|
|
475
|
+
/** Live windows dropped for capacity — nonzero means the bound is binding. */
|
|
476
|
+
get evictionCount(): number;
|
|
477
|
+
clear(): void;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export { CacheRateLimitStore, type ClientType, ErrorHandler, type ErrorHandlerOptions, MemoryRateLimitStore, type NonceStore, type OnErrorContext, type ProxyGuardConfig, type ProxyGuardMode, type RateLimitDimension, type RateLimitHit, type RateLimitOptions, type RateLimitStore, RequestLogger, type RequestLoggerConfig, type RequestLoggerOptions, createCacheNonceStore, createInMemoryNonceStore, createProxyGuard, getClientIp, getRateLimitPolicy, maskSensitiveData, rateLimit, rateLimitPolicy, resetMemoryRateLimitStore, setRateLimitFailClosedDefault, setRateLimitPolicies };
|