easy-ping 0.3.0 → 0.5.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/README.md +174 -82
- package/dist/adapter-B7R4rXtJ.d.cts +17 -0
- package/dist/adapter-B7R4rXtJ.d.ts +17 -0
- package/dist/{adapter-BfLe2J0t.d.cts → adapter-D3lTy-4E.d.cts} +6 -32
- package/dist/{adapter-BfLe2J0t.d.ts → adapter-D3lTy-4E.d.ts} +6 -32
- package/dist/adapters/drizzle.cjs +4 -4
- package/dist/adapters/drizzle.cjs.map +1 -1
- package/dist/adapters/drizzle.d.cts +35 -1
- package/dist/adapters/drizzle.d.ts +35 -1
- package/dist/adapters/drizzle.js +5 -5
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/adapters/mongodb.cjs +8 -7
- package/dist/adapters/mongodb.cjs.map +1 -1
- package/dist/adapters/mongodb.d.cts +4 -17
- package/dist/adapters/mongodb.d.ts +4 -17
- package/dist/adapters/mongodb.js +7 -7
- package/dist/adapters/mongodb.js.map +1 -1
- package/dist/adapters/mysql.cjs +605 -0
- package/dist/adapters/mysql.cjs.map +1 -0
- package/dist/adapters/mysql.d.cts +38 -0
- package/dist/adapters/mysql.d.ts +38 -0
- package/dist/adapters/mysql.js +51 -0
- package/dist/adapters/mysql.js.map +1 -0
- package/dist/adapters/postgres.cjs +19 -11
- package/dist/adapters/postgres.cjs.map +1 -1
- package/dist/adapters/postgres.d.cts +9 -54
- package/dist/adapters/postgres.d.ts +9 -54
- package/dist/adapters/postgres.js +6 -41
- package/dist/adapters/postgres.js.map +1 -1
- package/dist/adapters/sqlite.cjs +593 -0
- package/dist/adapters/sqlite.cjs.map +1 -0
- package/dist/adapters/sqlite.d.cts +37 -0
- package/dist/adapters/sqlite.d.ts +37 -0
- package/dist/adapters/sqlite.js +53 -0
- package/dist/adapters/sqlite.js.map +1 -0
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +2 -14
- package/dist/browser.d.ts +2 -14
- package/dist/browser.js.map +1 -1
- package/dist/chunk-2EYKPF5A.js +393 -0
- package/dist/chunk-2EYKPF5A.js.map +1 -0
- package/dist/{chunk-OZSOIX23.js → chunk-3VOQOGDR.js} +54 -12
- package/dist/chunk-3VOQOGDR.js.map +1 -0
- package/dist/{chunk-NYDVNMKG.js → chunk-AEYYTE5I.js} +4 -3
- package/dist/chunk-AEYYTE5I.js.map +1 -0
- package/dist/chunk-BECMTNK7.js +315 -0
- package/dist/chunk-BECMTNK7.js.map +1 -0
- package/dist/chunk-CK5UPVYP.js +48 -0
- package/dist/chunk-CK5UPVYP.js.map +1 -0
- package/dist/{chunk-BV3U542P.js → chunk-E4IZ2CQC.js} +2 -2
- package/dist/chunk-E4IZ2CQC.js.map +1 -0
- package/dist/chunk-GJNLOQJS.js +226 -0
- package/dist/chunk-GJNLOQJS.js.map +1 -0
- package/dist/chunk-HY47TQMY.js +52 -0
- package/dist/chunk-HY47TQMY.js.map +1 -0
- package/dist/chunk-M4R77BJD.js +64 -0
- package/dist/chunk-M4R77BJD.js.map +1 -0
- package/dist/{chunk-RBDW4S6F.js → chunk-XIDVLYNQ.js} +14 -4
- package/dist/chunk-XIDVLYNQ.js.map +1 -0
- package/dist/client.cjs.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +362 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -37
- package/dist/index.d.ts +56 -37
- package/dist/index.js +120 -359
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +27 -6
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +8 -2
- package/dist/node.d.ts +8 -2
- package/dist/node.js +26 -6
- package/dist/node.js.map +1 -1
- package/dist/{plugin-CmPOFVmn.d.ts → plugin-CHd2ZiGC.d.cts} +37 -25
- package/dist/{plugin-f5KaFWSN.d.cts → plugin-Cg9usuUi.d.ts} +37 -25
- package/dist/plugins/digests.cjs +1 -4
- package/dist/plugins/digests.cjs.map +1 -1
- package/dist/plugins/digests.d.cts +6 -31
- package/dist/plugins/digests.d.ts +6 -31
- package/dist/plugins/digests.js +1 -4
- package/dist/plugins/digests.js.map +1 -1
- package/dist/plugins/preferences-client.cjs.map +1 -1
- package/dist/plugins/preferences-client.d.cts +2 -2
- package/dist/plugins/preferences-client.d.ts +2 -2
- package/dist/plugins/preferences-client.js +1 -1
- package/dist/plugins/preferences-react.cjs.map +1 -1
- package/dist/plugins/preferences-react.js.map +1 -1
- package/dist/plugins/preferences.cjs +101 -17
- package/dist/plugins/preferences.cjs.map +1 -1
- package/dist/plugins/preferences.d.cts +4 -2
- package/dist/plugins/preferences.d.ts +4 -2
- package/dist/plugins/preferences.js +36 -9
- package/dist/plugins/preferences.js.map +1 -1
- package/dist/plugins/push.cjs +198 -40
- package/dist/plugins/push.cjs.map +1 -1
- package/dist/plugins/push.d.cts +20 -18
- package/dist/plugins/push.d.ts +20 -18
- package/dist/plugins/push.js +141 -41
- package/dist/plugins/push.js.map +1 -1
- package/dist/providers/web-push.cjs +37 -11
- package/dist/providers/web-push.cjs.map +1 -1
- package/dist/providers/web-push.d.cts +10 -11
- package/dist/providers/web-push.d.ts +10 -11
- package/dist/providers/web-push.js +37 -12
- package/dist/providers/web-push.js.map +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -4
- package/dist/react.d.ts +1 -4
- package/dist/react.js.map +1 -1
- package/dist/schema.cjs +121 -2
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +25 -14
- package/dist/schema.d.ts +25 -14
- package/dist/schema.js +4 -2
- package/dist/testing.cjs +3 -19
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +4 -22
- package/dist/testing.d.ts +4 -22
- package/dist/testing.js +3 -19
- package/dist/testing.js.map +1 -1
- package/package.json +12 -1
- package/dist/chunk-BV3U542P.js.map +0 -1
- package/dist/chunk-NYDVNMKG.js.map +0 -1
- package/dist/chunk-OZSOIX23.js.map +0 -1
- package/dist/chunk-RBDW4S6F.js.map +0 -1
- package/dist/chunk-W3BMEPPQ.js +0 -50
- package/dist/chunk-W3BMEPPQ.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as Channel, b as DeliveryMode, S as SkipReason, c as DeliveryRecord, D as DatabaseAdapter, R as Recipient } from './adapter-
|
|
2
|
-
export { d as ClaimArgs, e as ClaimedDelivery, f as DeliveryOutcome, g as DeliveryRelease, a as DeliveryStatus, h as FeedPage, i as FeedQuery, F as Frequency, I as InsertDelivery, j as InsertNotification, N as NotificationRecord, P as PreferenceRecord } from './adapter-
|
|
1
|
+
import { C as Channel, b as DeliveryMode, S as SkipReason, c as DeliveryRecord, D as DatabaseAdapter, R as Recipient } from './adapter-D3lTy-4E.cjs';
|
|
2
|
+
export { d as ClaimArgs, e as ClaimedDelivery, f as DeliveryOutcome, g as DeliveryRelease, a as DeliveryStatus, h as FeedPage, i as FeedQuery, F as Frequency, I as InsertDelivery, j as InsertNotification, N as NotificationRecord, P as PreferenceRecord } from './adapter-D3lTy-4E.cjs';
|
|
3
3
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
|
-
import { A as AnyPlugin, L as Logger } from './plugin-
|
|
5
|
-
export { a as ActionsOf, b as AfterDeliverContext, c as AnyClientPlugin, B as BeforeSendContext, d as BeforeSendResult, C as ChannelDecision, e as ClientFetch, f as ClientPlugin, g as ConfigError, E as EasyPingError, h as EasyPingPlugin, F as FieldDeclaration, i as FieldType,
|
|
4
|
+
import { R as RouteScope, A as AnyPlugin, P as Promisable, L as Logger } from './plugin-CHd2ZiGC.cjs';
|
|
5
|
+
export { a as ActionsOf, b as AfterDeliverContext, c as AnyClientPlugin, B as BeforeSendContext, d as BeforeSendResult, C as ChannelDecision, e as ClientFetch, f as ClientPlugin, g as ConfigError, D as DEFAULT_TOKEN_TTL_SECONDS, E as EasyPingError, h as EasyPingPlugin, F as FieldDeclaration, i as FieldType, M as MAX_TOKEN_TTL_SECONDS, j as PluginHooks, k as PrepareContext, l as ResolveChannelsContext, m as RouteContext, n as RouteDefinition, S as SchemaDeclaration, o as SignRequest, T as TableDeclaration, p as TokenClaims, U as UnionToIntersection, V as ValidationError, q as consoleLogger, r as defineClientPlugin, s as definePlugin, t as expiresIn, u as signToken, v as verifyToken } from './plugin-CHd2ZiGC.cjs';
|
|
6
6
|
import { E as EmailProvider } from './provider-CA45WVqt.cjs';
|
|
7
7
|
export { a as EmailMessage, P as ProviderSendResult } from './provider-CA45WVqt.cjs';
|
|
8
8
|
|
|
@@ -23,10 +23,7 @@ type NotificationDefinition<TSchema extends StandardSchemaV1 | undefined = Stand
|
|
|
23
23
|
};
|
|
24
24
|
/** Binds TSchema so email callbacks infer the payload; TS cannot infer from a sibling property. */
|
|
25
25
|
declare function defineNotification<TSchema extends StandardSchemaV1 | undefined = undefined>(definition: NotificationDefinition<TSchema>): NotificationDefinition<TSchema>;
|
|
26
|
-
/**
|
|
27
|
-
* Erased form. `EmailTemplate<never>` because callbacks are contravariant —
|
|
28
|
-
* anything else makes every schema-typed definition fail to assign.
|
|
29
|
-
*/
|
|
26
|
+
/** Erased form. `EmailTemplate<never>` because callbacks are contravariant. */
|
|
30
27
|
type AnyNotificationDefinition = {
|
|
31
28
|
schema?: StandardSchemaV1 | undefined;
|
|
32
29
|
channels: readonly Channel[];
|
|
@@ -38,6 +35,16 @@ type PayloadOf<TDef> = TDef extends {
|
|
|
38
35
|
schema: infer TSchema extends StandardSchemaV1;
|
|
39
36
|
} ? StandardSchemaV1.InferOutput<TSchema> : Record<string, unknown>;
|
|
40
37
|
|
|
38
|
+
type RateLimitConfig = {
|
|
39
|
+
/** Requests allowed per key per window. */
|
|
40
|
+
max: number;
|
|
41
|
+
windowMs: number;
|
|
42
|
+
/** Bucket key. Defaults to the client address from proxy headers; null exempts the request. */
|
|
43
|
+
key?: (request: Request) => string | null;
|
|
44
|
+
};
|
|
45
|
+
/** Fixed window in process memory: per isolate or replica, so a bound rather than a quota. */
|
|
46
|
+
declare function createRateLimiter(config: RateLimitConfig): (request: Request) => Response | null;
|
|
47
|
+
|
|
41
48
|
type SessionConfig = {
|
|
42
49
|
/** null yields 401; throwing yields 500. Deliberately distinct. */
|
|
43
50
|
getUserId: (request: Request) => string | null | Promise<string | null>;
|
|
@@ -51,10 +58,7 @@ type DeliveryConfig = {
|
|
|
51
58
|
/** inline mode only. */
|
|
52
59
|
throwOnError?: boolean;
|
|
53
60
|
backoff?: "exponential" | ((attempt: number) => number);
|
|
54
|
-
/**
|
|
55
|
-
* Next.js `after`, Cloudflare `ctx.waitUntil`, or @vercel/functions.
|
|
56
|
-
* Injected, not detected: importing a maybe-absent package breaks bundlers.
|
|
57
|
-
*/
|
|
61
|
+
/** Next.js `after` or Cloudflare `ctx.waitUntil`. Injected, not detected. */
|
|
58
62
|
waitUntil?: (promise: Promise<unknown>) => void;
|
|
59
63
|
};
|
|
60
64
|
type ChannelsConfig = {
|
|
@@ -77,10 +81,22 @@ type EasyPingConfig<TDefs extends NotificationDefinitions> = {
|
|
|
77
81
|
/** Required by `cron` and `deferred` modes. See RFC 0002 §4. */
|
|
78
82
|
cron?: {
|
|
79
83
|
secret: string;
|
|
84
|
+
/** Sweeps one POST /cron may run before returning. Defaults to 50. */
|
|
85
|
+
maxSweeps?: number;
|
|
80
86
|
};
|
|
87
|
+
/** Bearer secret for plugin machine routes. Falls back to `cron.secret`. */
|
|
88
|
+
machineSecret?: string;
|
|
89
|
+
/** In-process fixed-window limiter, applied before routing. */
|
|
90
|
+
rateLimit?: RateLimitConfig;
|
|
81
91
|
plugins?: readonly AnyPlugin[];
|
|
82
92
|
/** Where the handler is mounted, used to strip the prefix off incoming URLs. */
|
|
83
93
|
basePath?: string;
|
|
94
|
+
/** Origins other than the request host that may POST. `"*.example.com"` matches subdomains. */
|
|
95
|
+
trustedOrigins?: readonly string[];
|
|
96
|
+
/** Runs before routing. Return a Response to short-circuit — a rate limiter's 429, say. */
|
|
97
|
+
onRequest?: (request: Request) => Promisable<Response | undefined | void>;
|
|
98
|
+
/** Defaults to 64 KiB. */
|
|
99
|
+
maxBodyBytes?: number;
|
|
84
100
|
/** Table-name prefix; must match the one given to the adapter. */
|
|
85
101
|
tablePrefix?: string;
|
|
86
102
|
logger?: Logger;
|
|
@@ -111,6 +127,13 @@ type SendResult = {
|
|
|
111
127
|
type Worker = {
|
|
112
128
|
stop: () => Promise<void>;
|
|
113
129
|
};
|
|
130
|
+
type MountedRoute = {
|
|
131
|
+
method: "GET" | "POST";
|
|
132
|
+
path: string;
|
|
133
|
+
scope: RouteScope;
|
|
134
|
+
/** "core" for the built-in routes, otherwise the plugin id. */
|
|
135
|
+
owner: string;
|
|
136
|
+
};
|
|
114
137
|
type HealthReport = {
|
|
115
138
|
mode: DeliveryMode;
|
|
116
139
|
cronMounted: boolean;
|
|
@@ -131,13 +154,9 @@ type EasyPing<TDefs extends NotificationDefinitions> = {
|
|
|
131
154
|
batchSize?: number;
|
|
132
155
|
}): Worker;
|
|
133
156
|
healthCheck(): Promise<HealthReport>;
|
|
134
|
-
/**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
* The retry machinery is otherwise a black box: rows go quiet and the only
|
|
138
|
-
* way to ask what happened is SQL against tables the library owns. Wire this
|
|
139
|
-
* to an admin page or an alert.
|
|
140
|
-
*/
|
|
157
|
+
/** Every mounted route with its auth scope, so `custom`-scoped ones stay visible. RFC 0002 §3. */
|
|
158
|
+
listRoutes(): readonly MountedRoute[];
|
|
159
|
+
/** Deliveries that exhausted their attempts, newest first. Wire it to an admin page or an alert. */
|
|
141
160
|
getFailedDeliveries(options?: {
|
|
142
161
|
/** Defaults to the last 24 hours. */
|
|
143
162
|
since?: Date;
|
|
@@ -146,8 +165,6 @@ type EasyPing<TDefs extends NotificationDefinitions> = {
|
|
|
146
165
|
}): Promise<readonly DeliveryRecord[]>;
|
|
147
166
|
};
|
|
148
167
|
|
|
149
|
-
declare function easyPing<TDefs extends NotificationDefinitions>(config: EasyPingConfig<TDefs>): EasyPing<TDefs>;
|
|
150
|
-
|
|
151
168
|
type Backoff = "exponential" | ((attempt: number) => number);
|
|
152
169
|
|
|
153
170
|
type RunnerDeps = {
|
|
@@ -168,6 +185,8 @@ type SweepResult = {
|
|
|
168
185
|
/** Deliveries that had nothing to do. Not errors; see DeliveryOutcome. */
|
|
169
186
|
skipped: number;
|
|
170
187
|
};
|
|
188
|
+
/** Persisted to `last_error`, which admin tooling reads: addresses do not go in. */
|
|
189
|
+
declare const redactErrorMessage: (text: string) => string;
|
|
171
190
|
declare function createRunner(deps: RunnerDeps): {
|
|
172
191
|
runOnce: (options?: {
|
|
173
192
|
limit?: number;
|
|
@@ -186,20 +205,20 @@ declare function createRunner(deps: RunnerDeps): {
|
|
|
186
205
|
};
|
|
187
206
|
type Runner = ReturnType<typeof createRunner>;
|
|
188
207
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
declare const
|
|
203
|
-
declare
|
|
208
|
+
/** Every JSON body is capped here. Nothing legitimate the routes accept is bigger. */
|
|
209
|
+
declare const MAX_BODY_BYTES: number;
|
|
210
|
+
type JsonBody = {
|
|
211
|
+
body: Record<string, unknown>;
|
|
212
|
+
} | {
|
|
213
|
+
error: Response;
|
|
214
|
+
};
|
|
215
|
+
/** Reads a JSON object body with a streaming byte cap. Malformed JSON is 400; an empty body is `{}`. */
|
|
216
|
+
declare function readJsonBody(request: Request, maxBytes?: number): Promise<JsonBody>;
|
|
217
|
+
|
|
218
|
+
/** For template literals: anything a user typed goes through this, or their HTML ships from your domain. */
|
|
219
|
+
declare const escapeHtml: (value: unknown) => string;
|
|
220
|
+
|
|
221
|
+
declare const MIN_SECRET_LENGTH = 16;
|
|
222
|
+
declare function easyPing<TDefs extends NotificationDefinitions>(config: EasyPingConfig<TDefs>): EasyPing<TDefs>;
|
|
204
223
|
|
|
205
|
-
export { type AnyNotificationDefinition, AnyPlugin, Channel, type ChannelsConfig,
|
|
224
|
+
export { type AnyNotificationDefinition, AnyPlugin, Channel, type ChannelsConfig, DatabaseAdapter, type DeliveryConfig, DeliveryMode, DeliveryRecord, type EasyPing, type EasyPingConfig, EmailProvider, type EmailTemplate, type HealthReport, type JsonBody, Logger, MAX_BODY_BYTES, MIN_SECRET_LENGTH, type MountedRoute, type NotificationDefinition, type NotificationDefinitions, type PayloadFromSchema, type PayloadOf, Promisable, type RateLimitConfig, Recipient, RouteScope, type Runner, type RunnerDeps, type SendArgs, type SendResult, type SessionConfig, SkipReason, type SweepResult, type Worker, createRateLimiter, createRunner, decodeBase64Url, defineNotification, easyPing, encodeBase64Url, escapeHtml, readJsonBody, redactErrorMessage };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as Channel, b as DeliveryMode, S as SkipReason, c as DeliveryRecord, D as DatabaseAdapter, R as Recipient } from './adapter-
|
|
2
|
-
export { d as ClaimArgs, e as ClaimedDelivery, f as DeliveryOutcome, g as DeliveryRelease, a as DeliveryStatus, h as FeedPage, i as FeedQuery, F as Frequency, I as InsertDelivery, j as InsertNotification, N as NotificationRecord, P as PreferenceRecord } from './adapter-
|
|
1
|
+
import { C as Channel, b as DeliveryMode, S as SkipReason, c as DeliveryRecord, D as DatabaseAdapter, R as Recipient } from './adapter-D3lTy-4E.js';
|
|
2
|
+
export { d as ClaimArgs, e as ClaimedDelivery, f as DeliveryOutcome, g as DeliveryRelease, a as DeliveryStatus, h as FeedPage, i as FeedQuery, F as Frequency, I as InsertDelivery, j as InsertNotification, N as NotificationRecord, P as PreferenceRecord } from './adapter-D3lTy-4E.js';
|
|
3
3
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
|
-
import { A as AnyPlugin, L as Logger } from './plugin-
|
|
5
|
-
export { a as ActionsOf, b as AfterDeliverContext, c as AnyClientPlugin, B as BeforeSendContext, d as BeforeSendResult, C as ChannelDecision, e as ClientFetch, f as ClientPlugin, g as ConfigError, E as EasyPingError, h as EasyPingPlugin, F as FieldDeclaration, i as FieldType,
|
|
4
|
+
import { R as RouteScope, A as AnyPlugin, P as Promisable, L as Logger } from './plugin-Cg9usuUi.js';
|
|
5
|
+
export { a as ActionsOf, b as AfterDeliverContext, c as AnyClientPlugin, B as BeforeSendContext, d as BeforeSendResult, C as ChannelDecision, e as ClientFetch, f as ClientPlugin, g as ConfigError, D as DEFAULT_TOKEN_TTL_SECONDS, E as EasyPingError, h as EasyPingPlugin, F as FieldDeclaration, i as FieldType, M as MAX_TOKEN_TTL_SECONDS, j as PluginHooks, k as PrepareContext, l as ResolveChannelsContext, m as RouteContext, n as RouteDefinition, S as SchemaDeclaration, o as SignRequest, T as TableDeclaration, p as TokenClaims, U as UnionToIntersection, V as ValidationError, q as consoleLogger, r as defineClientPlugin, s as definePlugin, t as expiresIn, u as signToken, v as verifyToken } from './plugin-Cg9usuUi.js';
|
|
6
6
|
import { E as EmailProvider } from './provider-CA45WVqt.js';
|
|
7
7
|
export { a as EmailMessage, P as ProviderSendResult } from './provider-CA45WVqt.js';
|
|
8
8
|
|
|
@@ -23,10 +23,7 @@ type NotificationDefinition<TSchema extends StandardSchemaV1 | undefined = Stand
|
|
|
23
23
|
};
|
|
24
24
|
/** Binds TSchema so email callbacks infer the payload; TS cannot infer from a sibling property. */
|
|
25
25
|
declare function defineNotification<TSchema extends StandardSchemaV1 | undefined = undefined>(definition: NotificationDefinition<TSchema>): NotificationDefinition<TSchema>;
|
|
26
|
-
/**
|
|
27
|
-
* Erased form. `EmailTemplate<never>` because callbacks are contravariant —
|
|
28
|
-
* anything else makes every schema-typed definition fail to assign.
|
|
29
|
-
*/
|
|
26
|
+
/** Erased form. `EmailTemplate<never>` because callbacks are contravariant. */
|
|
30
27
|
type AnyNotificationDefinition = {
|
|
31
28
|
schema?: StandardSchemaV1 | undefined;
|
|
32
29
|
channels: readonly Channel[];
|
|
@@ -38,6 +35,16 @@ type PayloadOf<TDef> = TDef extends {
|
|
|
38
35
|
schema: infer TSchema extends StandardSchemaV1;
|
|
39
36
|
} ? StandardSchemaV1.InferOutput<TSchema> : Record<string, unknown>;
|
|
40
37
|
|
|
38
|
+
type RateLimitConfig = {
|
|
39
|
+
/** Requests allowed per key per window. */
|
|
40
|
+
max: number;
|
|
41
|
+
windowMs: number;
|
|
42
|
+
/** Bucket key. Defaults to the client address from proxy headers; null exempts the request. */
|
|
43
|
+
key?: (request: Request) => string | null;
|
|
44
|
+
};
|
|
45
|
+
/** Fixed window in process memory: per isolate or replica, so a bound rather than a quota. */
|
|
46
|
+
declare function createRateLimiter(config: RateLimitConfig): (request: Request) => Response | null;
|
|
47
|
+
|
|
41
48
|
type SessionConfig = {
|
|
42
49
|
/** null yields 401; throwing yields 500. Deliberately distinct. */
|
|
43
50
|
getUserId: (request: Request) => string | null | Promise<string | null>;
|
|
@@ -51,10 +58,7 @@ type DeliveryConfig = {
|
|
|
51
58
|
/** inline mode only. */
|
|
52
59
|
throwOnError?: boolean;
|
|
53
60
|
backoff?: "exponential" | ((attempt: number) => number);
|
|
54
|
-
/**
|
|
55
|
-
* Next.js `after`, Cloudflare `ctx.waitUntil`, or @vercel/functions.
|
|
56
|
-
* Injected, not detected: importing a maybe-absent package breaks bundlers.
|
|
57
|
-
*/
|
|
61
|
+
/** Next.js `after` or Cloudflare `ctx.waitUntil`. Injected, not detected. */
|
|
58
62
|
waitUntil?: (promise: Promise<unknown>) => void;
|
|
59
63
|
};
|
|
60
64
|
type ChannelsConfig = {
|
|
@@ -77,10 +81,22 @@ type EasyPingConfig<TDefs extends NotificationDefinitions> = {
|
|
|
77
81
|
/** Required by `cron` and `deferred` modes. See RFC 0002 §4. */
|
|
78
82
|
cron?: {
|
|
79
83
|
secret: string;
|
|
84
|
+
/** Sweeps one POST /cron may run before returning. Defaults to 50. */
|
|
85
|
+
maxSweeps?: number;
|
|
80
86
|
};
|
|
87
|
+
/** Bearer secret for plugin machine routes. Falls back to `cron.secret`. */
|
|
88
|
+
machineSecret?: string;
|
|
89
|
+
/** In-process fixed-window limiter, applied before routing. */
|
|
90
|
+
rateLimit?: RateLimitConfig;
|
|
81
91
|
plugins?: readonly AnyPlugin[];
|
|
82
92
|
/** Where the handler is mounted, used to strip the prefix off incoming URLs. */
|
|
83
93
|
basePath?: string;
|
|
94
|
+
/** Origins other than the request host that may POST. `"*.example.com"` matches subdomains. */
|
|
95
|
+
trustedOrigins?: readonly string[];
|
|
96
|
+
/** Runs before routing. Return a Response to short-circuit — a rate limiter's 429, say. */
|
|
97
|
+
onRequest?: (request: Request) => Promisable<Response | undefined | void>;
|
|
98
|
+
/** Defaults to 64 KiB. */
|
|
99
|
+
maxBodyBytes?: number;
|
|
84
100
|
/** Table-name prefix; must match the one given to the adapter. */
|
|
85
101
|
tablePrefix?: string;
|
|
86
102
|
logger?: Logger;
|
|
@@ -111,6 +127,13 @@ type SendResult = {
|
|
|
111
127
|
type Worker = {
|
|
112
128
|
stop: () => Promise<void>;
|
|
113
129
|
};
|
|
130
|
+
type MountedRoute = {
|
|
131
|
+
method: "GET" | "POST";
|
|
132
|
+
path: string;
|
|
133
|
+
scope: RouteScope;
|
|
134
|
+
/** "core" for the built-in routes, otherwise the plugin id. */
|
|
135
|
+
owner: string;
|
|
136
|
+
};
|
|
114
137
|
type HealthReport = {
|
|
115
138
|
mode: DeliveryMode;
|
|
116
139
|
cronMounted: boolean;
|
|
@@ -131,13 +154,9 @@ type EasyPing<TDefs extends NotificationDefinitions> = {
|
|
|
131
154
|
batchSize?: number;
|
|
132
155
|
}): Worker;
|
|
133
156
|
healthCheck(): Promise<HealthReport>;
|
|
134
|
-
/**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
* The retry machinery is otherwise a black box: rows go quiet and the only
|
|
138
|
-
* way to ask what happened is SQL against tables the library owns. Wire this
|
|
139
|
-
* to an admin page or an alert.
|
|
140
|
-
*/
|
|
157
|
+
/** Every mounted route with its auth scope, so `custom`-scoped ones stay visible. RFC 0002 §3. */
|
|
158
|
+
listRoutes(): readonly MountedRoute[];
|
|
159
|
+
/** Deliveries that exhausted their attempts, newest first. Wire it to an admin page or an alert. */
|
|
141
160
|
getFailedDeliveries(options?: {
|
|
142
161
|
/** Defaults to the last 24 hours. */
|
|
143
162
|
since?: Date;
|
|
@@ -146,8 +165,6 @@ type EasyPing<TDefs extends NotificationDefinitions> = {
|
|
|
146
165
|
}): Promise<readonly DeliveryRecord[]>;
|
|
147
166
|
};
|
|
148
167
|
|
|
149
|
-
declare function easyPing<TDefs extends NotificationDefinitions>(config: EasyPingConfig<TDefs>): EasyPing<TDefs>;
|
|
150
|
-
|
|
151
168
|
type Backoff = "exponential" | ((attempt: number) => number);
|
|
152
169
|
|
|
153
170
|
type RunnerDeps = {
|
|
@@ -168,6 +185,8 @@ type SweepResult = {
|
|
|
168
185
|
/** Deliveries that had nothing to do. Not errors; see DeliveryOutcome. */
|
|
169
186
|
skipped: number;
|
|
170
187
|
};
|
|
188
|
+
/** Persisted to `last_error`, which admin tooling reads: addresses do not go in. */
|
|
189
|
+
declare const redactErrorMessage: (text: string) => string;
|
|
171
190
|
declare function createRunner(deps: RunnerDeps): {
|
|
172
191
|
runOnce: (options?: {
|
|
173
192
|
limit?: number;
|
|
@@ -186,20 +205,20 @@ declare function createRunner(deps: RunnerDeps): {
|
|
|
186
205
|
};
|
|
187
206
|
type Runner = ReturnType<typeof createRunner>;
|
|
188
207
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
declare const
|
|
203
|
-
declare
|
|
208
|
+
/** Every JSON body is capped here. Nothing legitimate the routes accept is bigger. */
|
|
209
|
+
declare const MAX_BODY_BYTES: number;
|
|
210
|
+
type JsonBody = {
|
|
211
|
+
body: Record<string, unknown>;
|
|
212
|
+
} | {
|
|
213
|
+
error: Response;
|
|
214
|
+
};
|
|
215
|
+
/** Reads a JSON object body with a streaming byte cap. Malformed JSON is 400; an empty body is `{}`. */
|
|
216
|
+
declare function readJsonBody(request: Request, maxBytes?: number): Promise<JsonBody>;
|
|
217
|
+
|
|
218
|
+
/** For template literals: anything a user typed goes through this, or their HTML ships from your domain. */
|
|
219
|
+
declare const escapeHtml: (value: unknown) => string;
|
|
220
|
+
|
|
221
|
+
declare const MIN_SECRET_LENGTH = 16;
|
|
222
|
+
declare function easyPing<TDefs extends NotificationDefinitions>(config: EasyPingConfig<TDefs>): EasyPing<TDefs>;
|
|
204
223
|
|
|
205
|
-
export { type AnyNotificationDefinition, AnyPlugin, Channel, type ChannelsConfig,
|
|
224
|
+
export { type AnyNotificationDefinition, AnyPlugin, Channel, type ChannelsConfig, DatabaseAdapter, type DeliveryConfig, DeliveryMode, DeliveryRecord, type EasyPing, type EasyPingConfig, EmailProvider, type EmailTemplate, type HealthReport, type JsonBody, Logger, MAX_BODY_BYTES, MIN_SECRET_LENGTH, type MountedRoute, type NotificationDefinition, type NotificationDefinitions, type PayloadFromSchema, type PayloadOf, Promisable, type RateLimitConfig, Recipient, RouteScope, type Runner, type RunnerDeps, type SendArgs, type SendResult, type SessionConfig, SkipReason, type SweepResult, type Worker, createRateLimiter, createRunner, decodeBase64Url, defineNotification, easyPing, encodeBase64Url, escapeHtml, readJsonBody, redactErrorMessage };
|