@kelpie/server 0.1.0 → 0.3.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/dist/app.d.ts +11 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +27 -0
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +8 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +5 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/errors.d.ts +1 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +3 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/ids.d.ts +5 -0
- package/dist/lib/ids.d.ts.map +1 -1
- package/dist/lib/ids.js +5 -0
- package/dist/lib/ids.js.map +1 -1
- package/dist/lib/rateLimit.d.ts +26 -0
- package/dist/lib/rateLimit.d.ts.map +1 -0
- package/dist/lib/rateLimit.js +26 -0
- package/dist/lib/rateLimit.js.map +1 -0
- package/dist/lib/securityHeaders.d.ts +3 -0
- package/dist/lib/securityHeaders.d.ts.map +1 -0
- package/dist/lib/securityHeaders.js +41 -0
- package/dist/lib/securityHeaders.js.map +1 -0
- package/dist/modules/rate-limit/middleware.d.ts +42 -0
- package/dist/modules/rate-limit/middleware.d.ts.map +1 -0
- package/dist/modules/rate-limit/middleware.js +127 -0
- package/dist/modules/rate-limit/middleware.js.map +1 -0
- package/dist/modules/rate-limit/repository.d.ts +32 -0
- package/dist/modules/rate-limit/repository.d.ts.map +1 -0
- package/dist/modules/rate-limit/repository.js +48 -0
- package/dist/modules/rate-limit/repository.js.map +1 -0
- package/dist/modules/rate-limit/schema.d.ts +125 -0
- package/dist/modules/rate-limit/schema.d.ts.map +1 -0
- package/dist/modules/rate-limit/schema.js +29 -0
- package/dist/modules/rate-limit/schema.js.map +1 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +1 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/testing/app.d.ts +5 -0
- package/dist/testing/app.d.ts.map +1 -1
- package/dist/testing/app.js +14 -0
- package/dist/testing/app.js.map +1 -1
- package/dist/webBundle.d.ts +37 -0
- package/dist/webBundle.d.ts.map +1 -0
- package/dist/webBundle.js +75 -0
- package/dist/webBundle.js.map +1 -0
- package/migrations/0016_misty_mentor.sql +11 -0
- package/migrations/meta/0016_snapshot.json +5154 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +3 -2
- package/src/app.ts +46 -0
- package/src/index.ts +4 -1
- package/src/lib/config.ts +13 -0
- package/src/lib/errors.ts +4 -0
- package/src/lib/ids.ts +5 -0
- package/src/lib/rateLimit.ts +45 -0
- package/src/lib/securityHeaders.ts +44 -0
- package/src/modules/rate-limit/middleware.ts +177 -0
- package/src/modules/rate-limit/repository.ts +64 -0
- package/src/modules/rate-limit/schema.ts +34 -0
- package/src/schema/index.ts +1 -0
- package/src/testing/app.ts +21 -0
- package/src/webBundle.ts +110 -0
package/dist/app.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
+
import type { Context } from 'hono';
|
|
2
3
|
import type { DatabaseProbe } from './lib/database.ts';
|
|
3
4
|
import type { IdFactory } from './lib/ids.ts';
|
|
4
5
|
import type { Logger } from './lib/logger.ts';
|
|
6
|
+
import type { RateLimitConfig } from './lib/rateLimit.ts';
|
|
5
7
|
import type { CredentialDependencies } from './modules/auth/credentials.ts';
|
|
6
8
|
import type { ModuleContributions } from './runtime/registry.ts';
|
|
7
9
|
/**
|
|
@@ -24,6 +26,15 @@ export interface AppDependencies {
|
|
|
24
26
|
readonly generateRequestId?: () => string;
|
|
25
27
|
/** Injected so tests can pin the ids `idempotencyMiddleware` reserves rows under. */
|
|
26
28
|
readonly createId?: IdFactory;
|
|
29
|
+
readonly rateLimit: RateLimitConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Required rather than defaulted: a wrong-but-plausible fallback (trusting a
|
|
32
|
+
* spoofable header, say) would degrade the rate limiter silently instead of
|
|
33
|
+
* failing to build. The real entry points resolve this from the actual
|
|
34
|
+
* socket (`apps/kelpie/src/server.ts`); tests resolve it from a header they
|
|
35
|
+
* control (`testing/app.ts`).
|
|
36
|
+
*/
|
|
37
|
+
readonly resolveClientIp: (context: Context) => string;
|
|
27
38
|
}
|
|
28
39
|
/** Per-request values the middleware chain sets and handlers read. */
|
|
29
40
|
export interface AppBindings {
|
package/dist/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAGnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAItD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAQ3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAEhE;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACpD,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAA;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAA;IAC5C,4DAA4D;IAC5D,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAA;IACzC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAA;CACvD;AAED,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE;QACT,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAqBD,wBAAgB,SAAS,CAAC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,CAyH1E"}
|
package/dist/app.js
CHANGED
|
@@ -3,8 +3,10 @@ import { cors } from 'hono/cors';
|
|
|
3
3
|
import { AppError, internalErrorBody, toErrorBody } from './lib/errors.js';
|
|
4
4
|
import { PUBLIC_ROUTE_PREFIX } from './lib/http.js';
|
|
5
5
|
import { createIdFactory } from './lib/ids.js';
|
|
6
|
+
import { securityHeadersMiddleware } from './lib/securityHeaders.js';
|
|
6
7
|
import { MCP_INSTRUCTIONS, MCP_ROUTE_PREFIX, MCP_SERVER_INFO } from './modules/mcp/index.js';
|
|
7
8
|
import { createMcpEndpoint } from './modules/mcp/router.js';
|
|
9
|
+
import { createAuthAndApiRateLimitMiddleware, createFormSubmitRateLimitMiddleware, } from './modules/rate-limit/middleware.js';
|
|
8
10
|
import { createIdempotencyMiddleware } from './modules/workspace/idempotencyMiddleware.js';
|
|
9
11
|
const REQUEST_ID_HEADER = 'X-Request-Id';
|
|
10
12
|
/**
|
|
@@ -42,6 +44,20 @@ export function createApp(dependencies) {
|
|
|
42
44
|
durationMs: Math.round(performance.now() - startedAt),
|
|
43
45
|
});
|
|
44
46
|
});
|
|
47
|
+
app.use('*', securityHeadersMiddleware);
|
|
48
|
+
const rateLimitDependencies = {
|
|
49
|
+
db: dependencies.credentials.db,
|
|
50
|
+
now: dependencies.credentials.now,
|
|
51
|
+
createId,
|
|
52
|
+
credentials: dependencies.credentials,
|
|
53
|
+
resolveClientIp: dependencies.resolveClientIp,
|
|
54
|
+
config: dependencies.rateLimit,
|
|
55
|
+
};
|
|
56
|
+
// Ahead of idempotency, so a rate-limited request never reserves an
|
|
57
|
+
// idempotency key it will not be allowed to spend. Skips `/v1/public/*`
|
|
58
|
+
// itself; `createFormSubmitRateLimitMiddleware` below covers it, mounted
|
|
59
|
+
// where the public CORS middleware requires.
|
|
60
|
+
app.use('/v1/*', createAuthAndApiRateLimitMiddleware(rateLimitDependencies));
|
|
45
61
|
// Every module's `POST` gets this the same way, decided once here rather than
|
|
46
62
|
// per route (`api.md`). It skips `/v1/public/*` itself — a public request has
|
|
47
63
|
// no `Actor` to scope a key to — so it is mounted ahead of the public CORS
|
|
@@ -57,6 +73,10 @@ export function createApp(dependencies) {
|
|
|
57
73
|
// module names a resource `public`, and mounting in this order means the CORS
|
|
58
74
|
// middleware is attached before anything can answer under the prefix.
|
|
59
75
|
app.use(`${PUBLIC_ROUTE_PREFIX}/*`, PUBLIC_CORS);
|
|
76
|
+
// After CORS, not before: a throw ahead of it would strip the CORS headers a
|
|
77
|
+
// cross-origin embed needs to read the 429 body, and would apply to the
|
|
78
|
+
// preflight `OPTIONS` request CORS itself answers without reaching here.
|
|
79
|
+
app.use(`${PUBLIC_ROUTE_PREFIX}/*`, createFormSubmitRateLimitMiddleware(rateLimitDependencies));
|
|
60
80
|
for (const { router } of dependencies.contributions.publicRouters) {
|
|
61
81
|
app.route(PUBLIC_ROUTE_PREFIX, router);
|
|
62
82
|
}
|
|
@@ -70,6 +90,13 @@ export function createApp(dependencies) {
|
|
|
70
90
|
instructions: MCP_INSTRUCTIONS,
|
|
71
91
|
logger: dependencies.logger,
|
|
72
92
|
});
|
|
93
|
+
// The transport takes bearer keys only (`api.md`), so every call that
|
|
94
|
+
// reaches it is already the `api_key` traffic the `api` budget above
|
|
95
|
+
// exists for. Shared with `/v1` rather than a separate budget: one key's
|
|
96
|
+
// usage is one thing to protect the workspace from, whichever surface it
|
|
97
|
+
// comes through. No CORS layer to mind the order of here, unlike the forms
|
|
98
|
+
// budget — the transport checks its own `Origin` inside the handler.
|
|
99
|
+
app.use(MCP_ROUTE_PREFIX, createAuthAndApiRateLimitMiddleware(rateLimitDependencies));
|
|
73
100
|
app.route(MCP_ROUTE_PREFIX, mcp.transport);
|
|
74
101
|
app.route('/v1', mcp.catalog);
|
|
75
102
|
app.onError((error, context) => {
|
package/dist/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { createApp } from './app.ts';
|
|
2
|
-
export type { AppDependencies } from './app.ts';
|
|
2
|
+
export type { AppDependencies, AppBindings } from './app.ts';
|
|
3
|
+
export { WebBundleError, serveWebBundle } from './webBundle.ts';
|
|
4
|
+
export type { WebBundleOptions } from './webBundle.ts';
|
|
3
5
|
export { ConfigurationError, loadConfig } from './lib/config.ts';
|
|
4
6
|
export type { Environment, KelpieConfig, LogLevel, RuntimeMode } from './lib/config.ts';
|
|
5
7
|
export { ModuleConfigFileError, readModuleConfigFile } from './lib/moduleConfig.ts';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE5D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAChE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAEvF,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAEnF,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEpF,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA;AAE3C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC3F,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5E,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAClH,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAE5E,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAE5E,OAAO,EACL,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtG,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC1D,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEjE,YAAY,EACV,YAAY,EACZ,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,kBAAkB,GACnB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAElE,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClG,YAAY,EACV,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,2BAA2B,CAAA;AAElC,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAC7F,YAAY,EACV,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AACjE,YAAY,EACV,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzD,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAE7E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5G,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,YAAY,EAAE,mBAAmB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACpG,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAC9E,YAAY,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAC3E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AACzG,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createApp } from './app.js';
|
|
2
|
+
export { WebBundleError, serveWebBundle } from './webBundle.js';
|
|
2
3
|
export { ConfigurationError, loadConfig } from './lib/config.js';
|
|
3
4
|
export { ModuleConfigFileError, readModuleConfigFile } from './lib/moduleConfig.js';
|
|
4
5
|
export { FOREIGN_KEY_VIOLATION, RESTRICT_VIOLATION, UNIQUE_VIOLATION, connectDatabase, isReferenceViolation, postgresErrorCode, } from './lib/database.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAGhE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAEnF,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA;AAE3C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAG3F,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAClH,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAE5E,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAa9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAElE,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAUlG,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAU7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AASjE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpE,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAGzD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAG5G,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAKvD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAE9E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAG/D,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAGhE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAEnF,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,mBAAmB,CAAA;AAG1B,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAA;AAE3C,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAG3F,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAClH,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAE5E,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAa9C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAElE,OAAO,EAAE,yBAAyB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAUlG,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAU7F,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAA;AASjE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpE,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAGzD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAG5G,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAKvD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC5F,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAE9E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EmailConfig } from './email.ts';
|
|
2
|
+
import type { RateLimitConfig } from './rateLimit.ts';
|
|
2
3
|
/**
|
|
3
4
|
* The single place the service reads environment variables. Every other module
|
|
4
5
|
* receives configuration as an argument. Nothing defaults silently: a missing or
|
|
@@ -20,6 +21,13 @@ export interface KelpieConfig {
|
|
|
20
21
|
* settings decide.
|
|
21
22
|
*/
|
|
22
23
|
readonly moduleConfigPath: string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Directory holding the built web bundle, served from the same origin as the
|
|
26
|
+
* API (`webBundle.ts`). Undefined is the development case: the Vite dev server
|
|
27
|
+
* builds the pages and proxies the API, so there is no bundle on disk to serve.
|
|
28
|
+
*/
|
|
29
|
+
readonly webBundleDirectory: string | undefined;
|
|
30
|
+
readonly rateLimit: RateLimitConfig;
|
|
23
31
|
}
|
|
24
32
|
/** Thrown at boot when the environment cannot produce a valid configuration. */
|
|
25
33
|
export declare class ConfigurationError extends Error {
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAEtE,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,MAAM,GAAG,YAAY,CAAA;AAE/D,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAG7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;AAEtE,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,MAAM,GAAG,YAAY,CAAA;AAE/D,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAE1D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;CACpC;AAED,gFAAgF;AAChF,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IAEpC,YAAY,QAAQ,EAAE,SAAS,MAAM,EAAE,EAItC;CACF;AAwBD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,YAAY,CAiBjE"}
|
package/dist/lib/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { emailConfigSchema } from './email.js';
|
|
3
3
|
import { describeValidationIssue } from './errors.js';
|
|
4
|
+
import { rateLimitConfigFrom, rateLimitConfigSchema } from './rateLimit.js';
|
|
4
5
|
/** Thrown at boot when the environment cannot produce a valid configuration. */
|
|
5
6
|
export class ConfigurationError extends Error {
|
|
6
7
|
problems;
|
|
@@ -27,7 +28,9 @@ const environmentSchema = z.object({
|
|
|
27
28
|
.refine(isPostgresUrl, { message: 'must be a postgres:// or postgresql:// connection string' }),
|
|
28
29
|
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']),
|
|
29
30
|
KELPIE_MODULE_CONFIG_PATH: z.string().min(1).optional(),
|
|
31
|
+
WEB_BUNDLE_DIR: z.string().min(1).optional(),
|
|
30
32
|
...emailConfigSchema.shape,
|
|
33
|
+
...rateLimitConfigSchema.shape,
|
|
31
34
|
});
|
|
32
35
|
/**
|
|
33
36
|
* Parses an environment into a validated config.
|
|
@@ -47,6 +50,8 @@ export function loadConfig(environment) {
|
|
|
47
50
|
logLevel: result.data.LOG_LEVEL,
|
|
48
51
|
email: { EMAIL_PROVIDER: result.data.EMAIL_PROVIDER, EMAIL_FROM: result.data.EMAIL_FROM },
|
|
49
52
|
moduleConfigPath: result.data.KELPIE_MODULE_CONFIG_PATH,
|
|
53
|
+
webBundleDirectory: result.data.WEB_BUNDLE_DIR,
|
|
54
|
+
rateLimit: rateLimitConfigFrom(result.data),
|
|
50
55
|
};
|
|
51
56
|
}
|
|
52
57
|
//# sourceMappingURL=config.js.map
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAqC3E,gFAAgF;AAChF,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,QAAQ,CAAmB;IAEpC,YAAY,QAA2B;QACrC,KAAK,CAAC,uCAAuC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACtG,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;QAChC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAC1B,CAAC;CACF;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QACnC,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,aAAa,CAAA;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;IACvD,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;IACnD,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,MAAM,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,0DAA0D,EAAE,CAAC;IACjG,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACrD,yBAAyB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC5C,GAAG,iBAAiB,CAAC,KAAK;IAC1B,GAAG,qBAAqB,CAAC,KAAK;CAC/B,CAAC,CAAA;AAEF;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,WAAwB;IACjD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IAEvD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAA;IAChF,CAAC;IAED,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;QACjC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI;QACtB,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY;QACrC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS;QAC/B,KAAK,EAAE,EAAE,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;QACzF,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,yBAAyB;QACvD,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,cAAc;QAC9C,SAAS,EAAE,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;KAC5C,CAAA;AACH,CAAC"}
|
package/dist/lib/errors.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ export declare class AppError extends Error {
|
|
|
36
36
|
static unauthorized(message?: string): AppError;
|
|
37
37
|
static validationFailed(message: string, details: readonly ErrorDetail[]): AppError;
|
|
38
38
|
static conflict(message: string, details?: readonly ErrorDetail[]): AppError;
|
|
39
|
+
static rateLimited(message?: string): AppError;
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
42
|
* Renders an `AppError` into the wire body from `api.md`. `details` is omitted
|
package/dist/lib/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,cAAc,GACd,WAAW,GACX,WAAW,GACX,oBAAoB,GACpB,UAAU,GACV,sBAAsB,GACtB,mBAAmB,GACnB,cAAc,GACd,gBAAgB,CAAA;AAEpB,QAAA,MAAM,YAAY;0BACH,GAAG;2BACF,GAAG;wBACN,GAAG;wBACH,GAAG;iCAIM,GAAG;uBACb,GAAG;mCAIS,GAAG;gCACN,GAAG;2BACR,GAAG;6BACD,GAAG;CACyB,CAAA;AAE9C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,SAAS,CAAC,CAAA;AAE1D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;QACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;KAC1C,CAAA;CACF;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,CAAA;IAEpD,YAAY,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,EAM7E;IAED,MAAM,CAAC,QAAQ,CAAC,OAAO,SAAc,GAAG,QAAQ,CAE/C;IAED,MAAM,CAAC,YAAY,CAAC,OAAO,SAAmC,GAAG,QAAQ,CAExE;IAED,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,QAAQ,CAElF;IAED,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,QAAQ,CAE3E;CACF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAOtD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,SAAS,CAE7C;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAItE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,WAAW,EAAE,CAazF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASrD"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,cAAc,GACd,WAAW,GACX,WAAW,GACX,oBAAoB,GACpB,UAAU,GACV,sBAAsB,GACtB,mBAAmB,GACnB,cAAc,GACd,gBAAgB,CAAA;AAEpB,QAAA,MAAM,YAAY;0BACH,GAAG;2BACF,GAAG;wBACN,GAAG;wBACH,GAAG;iCAIM,GAAG;uBACb,GAAG;mCAIS,GAAG;gCACN,GAAG;2BACR,GAAG;6BACD,GAAG;CACyB,CAAA;AAE9C,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,SAAS,CAAC,CAAA;AAE1D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;QACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;KAC1C,CAAA;CACF;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,SAAS,CAAA;IAEpD,YAAY,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,EAM7E;IAED,MAAM,CAAC,QAAQ,CAAC,OAAO,SAAc,GAAG,QAAQ,CAE/C;IAED,MAAM,CAAC,YAAY,CAAC,OAAO,SAAmC,GAAG,QAAQ,CAExE;IAED,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,QAAQ,CAElF;IAED,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,WAAW,EAAE,GAAG,QAAQ,CAE3E;IAED,MAAM,CAAC,WAAW,CAAC,OAAO,SAAsB,GAAG,QAAQ,CAE1D;CACF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,CAOtD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,SAAS,CAE7C;AAED,yEAAyE;AACzE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAItE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,WAAW,EAAE,CAazF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CASrD"}
|
package/dist/lib/errors.js
CHANGED
|
@@ -43,6 +43,9 @@ export class AppError extends Error {
|
|
|
43
43
|
static conflict(message, details) {
|
|
44
44
|
return new AppError('conflict', message, details);
|
|
45
45
|
}
|
|
46
|
+
static rateLimited(message = 'Too many requests') {
|
|
47
|
+
return new AppError('rate_limited', message);
|
|
48
|
+
}
|
|
46
49
|
}
|
|
47
50
|
/**
|
|
48
51
|
* Renders an `AppError` into the wire body from `api.md`. `details` is omitted
|
package/dist/lib/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAcH,MAAM,YAAY,GAAG;IACnB,WAAW,EAAE,GAAG;IAChB,YAAY,EAAE,GAAG;IACjB,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,6EAA6E;IAC7E,0EAA0E;IAC1E,yEAAyE;IACzE,kBAAkB,EAAE,GAAG;IACvB,QAAQ,EAAE,GAAG;IACb,2EAA2E;IAC3E,+EAA+E;IAC/E,wCAAwC;IACxC,oBAAoB,EAAE,GAAG;IACzB,iBAAiB,EAAE,GAAG;IACtB,YAAY,EAAE,GAAG;IACjB,cAAc,EAAE,GAAG;CACyB,CAAA;AAiB9C,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAW;IACf,MAAM,CAAa;IACnB,OAAO,CAAoC;IAEpD,YAAY,IAAe,EAAE,OAAe,EAAE,OAAgC;QAC5E,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,UAAU,CAAA;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QAChC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,OAAO,GAAG,WAAW;QACnC,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAC3C,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,OAAO,GAAG,gCAAgC;QAC5D,OAAO,IAAI,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,OAAe,EAAE,OAA+B;QACtE,OAAO,IAAI,QAAQ,CAAC,mBAAmB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IAC5D,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,OAAe,EAAE,OAAgC;QAC/D,OAAO,IAAI,QAAQ,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACnD,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAe;IACzC,OAAO;QACL,KAAK,EACH,KAAK,CAAC,OAAO,KAAK,SAAS;YACzB,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;YAC9C,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;KAC3E,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE,CAAA;AAChF,CAAC;AAYD,mFAAmF;AACnF,MAAM,UAAU,uBAAuB,CAAC,KAAsB;IAC5D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAE7C,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAA;AACtE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkC;IAC/D,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC9B,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACnE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAE/C,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG;gBACnD,OAAO,EAAE,eAAe;aACzB,CAAC,CAAC,CAAA;QACL,CAAC;QAED,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9E,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;IAChF,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAEjF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/ids.d.ts
CHANGED
|
@@ -44,6 +44,11 @@ export declare const idPrefixes: {
|
|
|
44
44
|
* database is generated the same, injectable way.
|
|
45
45
|
*/
|
|
46
46
|
readonly idempotencyKey: 'idem';
|
|
47
|
+
/**
|
|
48
|
+
* Not returned over the wire either, for the same reason as `idempotencyKey`:
|
|
49
|
+
* a bucket is bookkeeping the rate limiter owns, not a resource with routes.
|
|
50
|
+
*/
|
|
51
|
+
readonly rateLimitBucket: 'rl';
|
|
47
52
|
};
|
|
48
53
|
export type ObjectKind = keyof typeof idPrefixes;
|
|
49
54
|
export type IdFactory = (kind: ObjectKind) => string;
|
package/dist/lib/ids.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/lib/ids.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,UAAU;aACrB,SAAS,EAAE,IAAI;aACf,IAAI,EAAE,KAAK;aACX,OAAO,EAAE,KAAK;aACd,kBAAkB,EAAE,KAAK;aACzB,UAAU,EAAE,KAAK;aACjB,MAAM,EAAE,KAAK;aACb,MAAM,EAAE,KAAK;aACb,MAAM,EAAE,KAAK;aACb,OAAO,EAAE,KAAK;aACd,QAAQ,EAAE,KAAK;aACf,aAAa,EAAE,OAAO;aACtB,IAAI,EAAE,MAAM;aACZ,WAAW,EAAE,KAAK;aAClB,WAAW,EAAE,KAAK;aAClB,KAAK,EAAE,KAAK;aACZ,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,MAAM;aACjB,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,KAAK;aACf,IAAI,EAAE,MAAM;aACZ,QAAQ,EAAE,KAAK;aACf,YAAY,EAAE,IAAI;aAClB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,IAAI;aACf,cAAc,EAAE,KAAK;aACrB,OAAO,EAAE,IAAI;IACb,8EAA8E;aAC9E,eAAe,EAAE,KAAK;aACtB,iBAAiB,EAAE,IAAI;aACvB,QAAQ,EAAE,KAAK;aACf,SAAS,EAAE,KAAK;aAChB,qBAAqB,EAAE,KAAK;IAC5B,6FAA6F;aAC7F,aAAa,EAAE,MAAM;IACrB;;;;;OAKG;aACH,cAAc,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/lib/ids.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,UAAU;aACrB,SAAS,EAAE,IAAI;aACf,IAAI,EAAE,KAAK;aACX,OAAO,EAAE,KAAK;aACd,kBAAkB,EAAE,KAAK;aACzB,UAAU,EAAE,KAAK;aACjB,MAAM,EAAE,KAAK;aACb,MAAM,EAAE,KAAK;aACb,MAAM,EAAE,KAAK;aACb,OAAO,EAAE,KAAK;aACd,QAAQ,EAAE,KAAK;aACf,aAAa,EAAE,OAAO;aACtB,IAAI,EAAE,MAAM;aACZ,WAAW,EAAE,KAAK;aAClB,WAAW,EAAE,KAAK;aAClB,KAAK,EAAE,KAAK;aACZ,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,MAAM;aACjB,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,KAAK;aACf,IAAI,EAAE,MAAM;aACZ,QAAQ,EAAE,KAAK;aACf,YAAY,EAAE,IAAI;aAClB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,IAAI;aACf,cAAc,EAAE,KAAK;aACrB,OAAO,EAAE,IAAI;IACb,8EAA8E;aAC9E,eAAe,EAAE,KAAK;aACtB,iBAAiB,EAAE,IAAI;aACvB,QAAQ,EAAE,KAAK;aACf,SAAS,EAAE,KAAK;aAChB,qBAAqB,EAAE,KAAK;IAC5B,6FAA6F;aAC7F,aAAa,EAAE,MAAM;IACrB;;;;;OAKG;aACH,cAAc,EAAE,MAAM;IACtB;;;OAGG;aACH,eAAe,EAAE,IAAI;CACb,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,UAAU,CAAA;AAEhD,MAAM,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAA;AAEpD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,GAAE,MAAM,MAAa,GAAG,SAAS,CAE5E"}
|
package/dist/lib/ids.js
CHANGED
|
@@ -45,6 +45,11 @@ export const idPrefixes = {
|
|
|
45
45
|
* database is generated the same, injectable way.
|
|
46
46
|
*/
|
|
47
47
|
idempotencyKey: 'idem',
|
|
48
|
+
/**
|
|
49
|
+
* Not returned over the wire either, for the same reason as `idempotencyKey`:
|
|
50
|
+
* a bucket is bookkeeping the rate limiter owns, not a resource with routes.
|
|
51
|
+
*/
|
|
52
|
+
rateLimitBucket: 'rl',
|
|
48
53
|
};
|
|
49
54
|
/**
|
|
50
55
|
* Builds the id factory. The ULID generator is injected so tests can pin ids;
|
package/dist/lib/ids.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/lib/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,SAAS,EAAE,IAAI;IACf,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,KAAK;IACd,kBAAkB,EAAE,KAAK;IACzB,UAAU,EAAE,KAAK;IACjB,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,aAAa,EAAE,OAAO;IACtB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,KAAK;IAClB,WAAW,EAAE,KAAK;IAClB,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,MAAM;IACjB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,KAAK;IACf,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,KAAK;IACf,YAAY,EAAE,IAAI;IAClB,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,IAAI;IACf,cAAc,EAAE,KAAK;IACrB,OAAO,EAAE,IAAI;IACb,8EAA8E;IAC9E,eAAe,EAAE,KAAK;IACtB,iBAAiB,EAAE,IAAI;IACvB,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,KAAK;IAChB,qBAAqB,EAAE,KAAK;IAC5B,6FAA6F;IAC7F,aAAa,EAAE,MAAM;IACrB;;;;;OAKG;IACH,cAAc,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/lib/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,SAAS,EAAE,IAAI;IACf,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,KAAK;IACd,kBAAkB,EAAE,KAAK;IACzB,UAAU,EAAE,KAAK;IACjB,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,KAAK;IACb,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,KAAK;IACf,aAAa,EAAE,OAAO;IACtB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,KAAK;IAClB,WAAW,EAAE,KAAK;IAClB,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,MAAM;IACjB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,KAAK;IACf,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,KAAK;IACf,YAAY,EAAE,IAAI;IAClB,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,IAAI;IACf,cAAc,EAAE,KAAK;IACrB,OAAO,EAAE,IAAI;IACb,8EAA8E;IAC9E,eAAe,EAAE,KAAK;IACtB,iBAAiB,EAAE,IAAI;IACvB,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,KAAK;IAChB,qBAAqB,EAAE,KAAK;IAC5B,6FAA6F;IAC7F,aAAa,EAAE,MAAM;IACrB;;;;;OAKG;IACH,cAAc,EAAE,MAAM;IACtB;;;OAGG;IACH,eAAe,EAAE,IAAI;CACb,CAAA;AAMV;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,YAAY,GAAiB,IAAI;IAC/D,OAAO,CAAC,IAAgB,EAAU,EAAE,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,YAAY,EAAE,EAAE,CAAA;AAC9E,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Budgets for the three request classes `api.md` rate-limits: public form
|
|
4
|
+
* submissions, unauthenticated auth endpoints, and everything else under an
|
|
5
|
+
* API key. Roadmap Phase 6: self-host packaging calls for this with nothing to
|
|
6
|
+
* configure, so every variable here is optional and defaulted.
|
|
7
|
+
*/
|
|
8
|
+
export interface RateLimitBudget {
|
|
9
|
+
readonly limit: number;
|
|
10
|
+
readonly windowMs: number;
|
|
11
|
+
}
|
|
12
|
+
export interface RateLimitConfig {
|
|
13
|
+
readonly forms: RateLimitBudget;
|
|
14
|
+
readonly auth: RateLimitBudget;
|
|
15
|
+
readonly api: RateLimitBudget;
|
|
16
|
+
}
|
|
17
|
+
export declare const rateLimitConfigSchema: z.ZodObject<{
|
|
18
|
+
RATE_LIMIT_FORMS_LIMIT: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
19
|
+
RATE_LIMIT_FORMS_WINDOW_SECONDS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
20
|
+
RATE_LIMIT_AUTH_LIMIT: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
21
|
+
RATE_LIMIT_AUTH_WINDOW_SECONDS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
22
|
+
RATE_LIMIT_API_LIMIT: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
23
|
+
RATE_LIMIT_API_WINDOW_SECONDS: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
export declare function rateLimitConfigFrom(parsed: z.infer<typeof rateLimitConfigSchema>): RateLimitConfig;
|
|
26
|
+
//# sourceMappingURL=rateLimit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.d.ts","sourceRoot":"","sources":["../../src/lib/rateLimit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;IAC9B,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;CAC9B;AAED,eAAO,MAAM,qBAAqB;;;;;;;iBAOhC,CAAA;AAEF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GAAG,eAAe,CAelG"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const rateLimitConfigSchema = z.object({
|
|
3
|
+
RATE_LIMIT_FORMS_LIMIT: z.coerce.number().int().positive().default(20),
|
|
4
|
+
RATE_LIMIT_FORMS_WINDOW_SECONDS: z.coerce.number().int().positive().default(60),
|
|
5
|
+
RATE_LIMIT_AUTH_LIMIT: z.coerce.number().int().positive().default(10),
|
|
6
|
+
RATE_LIMIT_AUTH_WINDOW_SECONDS: z.coerce.number().int().positive().default(60),
|
|
7
|
+
RATE_LIMIT_API_LIMIT: z.coerce.number().int().positive().default(600),
|
|
8
|
+
RATE_LIMIT_API_WINDOW_SECONDS: z.coerce.number().int().positive().default(60),
|
|
9
|
+
});
|
|
10
|
+
export function rateLimitConfigFrom(parsed) {
|
|
11
|
+
return {
|
|
12
|
+
forms: {
|
|
13
|
+
limit: parsed.RATE_LIMIT_FORMS_LIMIT,
|
|
14
|
+
windowMs: parsed.RATE_LIMIT_FORMS_WINDOW_SECONDS * 1000,
|
|
15
|
+
},
|
|
16
|
+
auth: {
|
|
17
|
+
limit: parsed.RATE_LIMIT_AUTH_LIMIT,
|
|
18
|
+
windowMs: parsed.RATE_LIMIT_AUTH_WINDOW_SECONDS * 1000,
|
|
19
|
+
},
|
|
20
|
+
api: {
|
|
21
|
+
limit: parsed.RATE_LIMIT_API_LIMIT,
|
|
22
|
+
windowMs: parsed.RATE_LIMIT_API_WINDOW_SECONDS * 1000,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=rateLimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.js","sourceRoot":"","sources":["../../src/lib/rateLimit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAoBvB,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,sBAAsB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACtE,+BAA+B,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/E,qBAAqB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACrE,8BAA8B,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9E,oBAAoB,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;IACrE,6BAA6B,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CAC9E,CAAC,CAAA;AAEF,MAAM,UAAU,mBAAmB,CAAC,MAA6C;IAC/E,OAAO;QACL,KAAK,EAAE;YACL,KAAK,EAAE,MAAM,CAAC,sBAAsB;YACpC,QAAQ,EAAE,MAAM,CAAC,+BAA+B,GAAG,IAAI;SACxD;QACD,IAAI,EAAE;YACJ,KAAK,EAAE,MAAM,CAAC,qBAAqB;YACnC,QAAQ,EAAE,MAAM,CAAC,8BAA8B,GAAG,IAAI;SACvD;QACD,GAAG,EAAE;YACH,KAAK,EAAE,MAAM,CAAC,oBAAoB;YAClC,QAAQ,EAAE,MAAM,CAAC,6BAA6B,GAAG,IAAI;SACtD;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityHeaders.d.ts","sourceRoot":"","sources":["../../src/lib/securityHeaders.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAoC7C,eAAO,MAAM,yBAAyB,EAAE,iBAMvC,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { secureHeaders } from 'hono/secure-headers';
|
|
2
|
+
/**
|
|
3
|
+
* `api.md`'s security headers, in two layers.
|
|
4
|
+
*
|
|
5
|
+
* `hono/secure-headers` (bundled with `hono` already; no new dependency)
|
|
6
|
+
* covers `Strict-Transport-Security`, `X-Content-Type-Options` and
|
|
7
|
+
* `Referrer-Policy`. Every other header it can add is turned off explicitly
|
|
8
|
+
* rather than left at the library's default, so a future `hono` upgrade
|
|
9
|
+
* cannot silently change what this API sends. `Cross-Origin-Resource-Policy`
|
|
10
|
+
* in particular would break the very cross-origin iframe embedding
|
|
11
|
+
* `forms/embed.ts` exists for, on any customer page that opts into
|
|
12
|
+
* `Cross-Origin-Embedder-Policy` itself.
|
|
13
|
+
*
|
|
14
|
+
* `X-Frame-Options` cannot go through the library the same way: a mount's
|
|
15
|
+
* value is fixed once, not computed per request, and the embed page is the
|
|
16
|
+
* one response in this service that must not send it (`embed.ts:229`). The
|
|
17
|
+
* wrapper below adds it everywhere else, driven by the one signal that tells
|
|
18
|
+
* the embed page apart from every other route: it is the only handler that
|
|
19
|
+
* sets its own `Content-Security-Policy`.
|
|
20
|
+
*/
|
|
21
|
+
const baseHeaders = secureHeaders({
|
|
22
|
+
strictTransportSecurity: true,
|
|
23
|
+
xContentTypeOptions: true,
|
|
24
|
+
referrerPolicy: true,
|
|
25
|
+
crossOriginEmbedderPolicy: false,
|
|
26
|
+
crossOriginResourcePolicy: false,
|
|
27
|
+
crossOriginOpenerPolicy: false,
|
|
28
|
+
originAgentCluster: false,
|
|
29
|
+
xDnsPrefetchControl: false,
|
|
30
|
+
xDownloadOptions: false,
|
|
31
|
+
xFrameOptions: false,
|
|
32
|
+
xPermittedCrossDomainPolicies: false,
|
|
33
|
+
xXssProtection: false,
|
|
34
|
+
});
|
|
35
|
+
export const securityHeadersMiddleware = async (context, next) => {
|
|
36
|
+
await baseHeaders(context, next);
|
|
37
|
+
if (context.res.headers.get('Content-Security-Policy') === null) {
|
|
38
|
+
context.header('X-Frame-Options', 'DENY');
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=securityHeaders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"securityHeaders.js","sourceRoot":"","sources":["../../src/lib/securityHeaders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,GAAG,aAAa,CAAC;IAChC,uBAAuB,EAAE,IAAI;IAC7B,mBAAmB,EAAE,IAAI;IACzB,cAAc,EAAE,IAAI;IACpB,yBAAyB,EAAE,KAAK;IAChC,yBAAyB,EAAE,KAAK;IAChC,uBAAuB,EAAE,KAAK;IAC9B,kBAAkB,EAAE,KAAK;IACzB,mBAAmB,EAAE,KAAK;IAC1B,gBAAgB,EAAE,KAAK;IACvB,aAAa,EAAE,KAAK;IACpB,6BAA6B,EAAE,KAAK;IACpC,cAAc,EAAE,KAAK;CACtB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAsB,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;IAClF,MAAM,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAEhC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,KAAK,IAAI,EAAE,CAAC;QAChE,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAA;IAC3C,CAAC;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Context, MiddlewareHandler } from 'hono';
|
|
2
|
+
import type { Database } from '../../lib/database.ts';
|
|
3
|
+
import type { IdFactory } from '../../lib/ids.ts';
|
|
4
|
+
import type { RateLimitConfig } from '../../lib/rateLimit.ts';
|
|
5
|
+
import type { CredentialDependencies } from '../auth/credentials.ts';
|
|
6
|
+
/**
|
|
7
|
+
* The three budgets `api.md` describes for `/v1`: public form submissions,
|
|
8
|
+
* unauthenticated auth endpoints, and everything else called with an API key.
|
|
9
|
+
* Split into two middlewares rather than one, because the forms budget has to
|
|
10
|
+
* sit *inside* `PUBLIC_CORS` in `app.ts` — a throw ahead of it would strip the
|
|
11
|
+
* CORS headers a cross-origin embed needs to read the 429 body — while the
|
|
12
|
+
* auth and API budgets have no CORS concern and can run earlier.
|
|
13
|
+
*/
|
|
14
|
+
export interface RateLimitMiddlewareDependencies {
|
|
15
|
+
readonly db: Database;
|
|
16
|
+
readonly now: () => Date;
|
|
17
|
+
readonly createId: IdFactory;
|
|
18
|
+
readonly credentials: CredentialDependencies;
|
|
19
|
+
readonly resolveClientIp: (context: Context) => string;
|
|
20
|
+
readonly config: RateLimitConfig;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Guards `POST /v1/public/forms/:key/submit`, keyed by the caller's IP.
|
|
24
|
+
*
|
|
25
|
+
* Mount this **after** `PUBLIC_CORS` in `app.ts`. It only recognises the
|
|
26
|
+
* submit route; every other path under the public prefix, including the embed
|
|
27
|
+
* page itself, passes through untouched.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createFormSubmitRateLimitMiddleware(dependencies: RateLimitMiddlewareDependencies): MiddlewareHandler;
|
|
30
|
+
/**
|
|
31
|
+
* Guards the unauthenticated auth endpoints (by IP) and every other `/v1/*`
|
|
32
|
+
* request made with an API key (by that key) — the budget that protects a
|
|
33
|
+
* workspace rather than the world. Session traffic, the product's own UI,
|
|
34
|
+
* carries no budget here.
|
|
35
|
+
*
|
|
36
|
+
* Public routes are skipped: `createFormSubmitRateLimitMiddleware` already
|
|
37
|
+
* covers them, positioned where `PUBLIC_CORS` requires. Mount this one
|
|
38
|
+
* anywhere else on `/v1/*`, ahead of idempotency so a rate-limited request
|
|
39
|
+
* never reserves an idempotency key it will not be allowed to spend.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createAuthAndApiRateLimitMiddleware(dependencies: RateLimitMiddlewareDependencies): MiddlewareHandler;
|
|
42
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/modules/rate-limit/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAGrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAG9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAGpE;;;;;;;GAOG;AAEH,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,CAAA;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAA;IAC5C,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAA;IACtD,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAA;CACjC;AAmED;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,+BAA+B,GAC5C,iBAAiB,CAcnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,+BAA+B,GAC5C,iBAAiB,CA2CnB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { AppError } from '../../lib/errors.js';
|
|
2
|
+
import { PUBLIC_ROUTE_PREFIX } from '../../lib/http.js';
|
|
3
|
+
import { readBearerToken } from '../api-keys/keys.js';
|
|
4
|
+
import { resolveActorFrom } from '../auth/credentials.js';
|
|
5
|
+
import { incrementRateLimitBucket, pruneExpiredRateLimitBuckets } from './repository.js';
|
|
6
|
+
/**
|
|
7
|
+
* Every unauthenticated `/v1/auth/*` endpoint: the ones a stranger can call to
|
|
8
|
+
* attempt credential stuffing or enumerate accounts. `/auth/logout`, `/me`,
|
|
9
|
+
* `/sessions` and changing a known password all require a session already and
|
|
10
|
+
* carry no such risk, so they are not here.
|
|
11
|
+
*/
|
|
12
|
+
const UNAUTHENTICATED_AUTH_PATHS = new Set([
|
|
13
|
+
'/v1/auth/signup',
|
|
14
|
+
'/v1/auth/login',
|
|
15
|
+
'/v1/auth/password-reset',
|
|
16
|
+
'/v1/auth/password-reset/confirm',
|
|
17
|
+
]);
|
|
18
|
+
function isFormSubmitRoute(context) {
|
|
19
|
+
return context.req.method === 'POST' && context.req.path.endsWith('/submit');
|
|
20
|
+
}
|
|
21
|
+
/** Floors `now` to the start of its fixed window, so every caller in the same window shares one row. */
|
|
22
|
+
function windowStart(now, windowMs) {
|
|
23
|
+
return new Date(Math.floor(now.getTime() / windowMs) * windowMs);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The largest configured window across all three budgets. A bucket cannot be
|
|
27
|
+
* expired before its own window elapses, so this is a safe cutoff for
|
|
28
|
+
* pruning regardless of which budget created the row.
|
|
29
|
+
*/
|
|
30
|
+
function maxWindowMs(config) {
|
|
31
|
+
return Math.max(config.forms.windowMs, config.auth.windowMs, config.api.windowMs);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Increments the bucket and throws `429` with `Retry-After` once the caller is
|
|
35
|
+
* over budget. Pruning runs only when this request started a fresh window
|
|
36
|
+
* (`count === 1`) rather than on every call, which ties cleanup frequency to
|
|
37
|
+
* how often new windows open instead of to raw request volume.
|
|
38
|
+
*/
|
|
39
|
+
async function enforceBudget(dependencies, context, params) {
|
|
40
|
+
const now = dependencies.now();
|
|
41
|
+
const start = windowStart(now, params.budget.windowMs);
|
|
42
|
+
const count = await incrementRateLimitBucket(dependencies.db, {
|
|
43
|
+
id: dependencies.createId('rateLimitBucket'),
|
|
44
|
+
scope: params.scope,
|
|
45
|
+
key: params.key,
|
|
46
|
+
windowStart: start,
|
|
47
|
+
});
|
|
48
|
+
if (count === 1) {
|
|
49
|
+
await pruneExpiredRateLimitBuckets(dependencies.db, new Date(now.getTime() - maxWindowMs(dependencies.config)));
|
|
50
|
+
}
|
|
51
|
+
if (count > params.budget.limit) {
|
|
52
|
+
const resetAt = start.getTime() + params.budget.windowMs;
|
|
53
|
+
const retryAfterSeconds = Math.max(1, Math.ceil((resetAt - now.getTime()) / 1000));
|
|
54
|
+
context.header('Retry-After', String(retryAfterSeconds));
|
|
55
|
+
throw AppError.rateLimited();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Guards `POST /v1/public/forms/:key/submit`, keyed by the caller's IP.
|
|
60
|
+
*
|
|
61
|
+
* Mount this **after** `PUBLIC_CORS` in `app.ts`. It only recognises the
|
|
62
|
+
* submit route; every other path under the public prefix, including the embed
|
|
63
|
+
* page itself, passes through untouched.
|
|
64
|
+
*/
|
|
65
|
+
export function createFormSubmitRateLimitMiddleware(dependencies) {
|
|
66
|
+
return async (context, next) => {
|
|
67
|
+
if (!isFormSubmitRoute(context)) {
|
|
68
|
+
await next();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
await enforceBudget(dependencies, context, {
|
|
72
|
+
scope: 'forms',
|
|
73
|
+
key: dependencies.resolveClientIp(context),
|
|
74
|
+
budget: dependencies.config.forms,
|
|
75
|
+
});
|
|
76
|
+
await next();
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Guards the unauthenticated auth endpoints (by IP) and every other `/v1/*`
|
|
81
|
+
* request made with an API key (by that key) — the budget that protects a
|
|
82
|
+
* workspace rather than the world. Session traffic, the product's own UI,
|
|
83
|
+
* carries no budget here.
|
|
84
|
+
*
|
|
85
|
+
* Public routes are skipped: `createFormSubmitRateLimitMiddleware` already
|
|
86
|
+
* covers them, positioned where `PUBLIC_CORS` requires. Mount this one
|
|
87
|
+
* anywhere else on `/v1/*`, ahead of idempotency so a rate-limited request
|
|
88
|
+
* never reserves an idempotency key it will not be allowed to spend.
|
|
89
|
+
*/
|
|
90
|
+
export function createAuthAndApiRateLimitMiddleware(dependencies) {
|
|
91
|
+
return async (context, next) => {
|
|
92
|
+
const path = context.req.path;
|
|
93
|
+
if (path === PUBLIC_ROUTE_PREFIX || path.startsWith(`${PUBLIC_ROUTE_PREFIX}/`)) {
|
|
94
|
+
await next();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (context.req.method === 'POST' && UNAUTHENTICATED_AUTH_PATHS.has(path)) {
|
|
98
|
+
await enforceBudget(dependencies, context, {
|
|
99
|
+
scope: 'auth',
|
|
100
|
+
key: dependencies.resolveClientIp(context),
|
|
101
|
+
budget: dependencies.config.auth,
|
|
102
|
+
});
|
|
103
|
+
await next();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Only a bearer credential can resolve to an `api_key` actor, the only
|
|
107
|
+
// kind this budget applies to, so a cookie-only request — the ordinary
|
|
108
|
+
// browser session — never pays for an actor resolution here at all.
|
|
109
|
+
const bearer = readBearerToken(context.req.header('Authorization'));
|
|
110
|
+
if (bearer === undefined || bearer.length === 0) {
|
|
111
|
+
await next();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const actor = await resolveActorFrom(dependencies.credentials, context);
|
|
115
|
+
if (actor.kind !== 'api_key') {
|
|
116
|
+
await next();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
await enforceBudget(dependencies, context, {
|
|
120
|
+
scope: 'api',
|
|
121
|
+
key: actor.apiKeyId,
|
|
122
|
+
budget: dependencies.config.api,
|
|
123
|
+
});
|
|
124
|
+
await next();
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=middleware.js.map
|