@zero-server/sdk 0.9.1 → 0.9.2
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/LICENSE +21 -21
- package/README.md +460 -443
- package/index.js +414 -412
- package/lib/app.js +1172 -1172
- package/lib/auth/authorize.js +399 -399
- package/lib/auth/enrollment.js +367 -367
- package/lib/auth/index.js +57 -57
- package/lib/auth/jwt.js +731 -731
- package/lib/auth/oauth.js +362 -362
- package/lib/auth/session.js +588 -588
- package/lib/auth/trustedDevice.js +409 -409
- package/lib/auth/twoFactor.js +1150 -1150
- package/lib/auth/webauthn.js +946 -946
- package/lib/body/index.js +14 -14
- package/lib/body/json.js +109 -109
- package/lib/body/multipart.js +440 -440
- package/lib/body/raw.js +71 -71
- package/lib/body/rawBuffer.js +160 -160
- package/lib/body/sendError.js +25 -25
- package/lib/body/text.js +75 -75
- package/lib/body/typeMatch.js +41 -41
- package/lib/body/urlencoded.js +235 -235
- package/lib/cli.js +845 -845
- package/lib/cluster.js +666 -666
- package/lib/debug.js +372 -372
- package/lib/env/index.js +465 -465
- package/lib/errors.js +683 -683
- package/lib/fetch/index.js +256 -256
- package/lib/grpc/balancer.js +378 -378
- package/lib/grpc/call.js +708 -708
- package/lib/grpc/client.js +764 -764
- package/lib/grpc/codec.js +1221 -1221
- package/lib/grpc/credentials.js +398 -398
- package/lib/grpc/frame.js +262 -262
- package/lib/grpc/health.js +287 -287
- package/lib/grpc/index.js +121 -121
- package/lib/grpc/metadata.js +461 -461
- package/lib/grpc/proto.js +821 -821
- package/lib/grpc/reflection.js +590 -590
- package/lib/grpc/server.js +445 -445
- package/lib/grpc/status.js +118 -118
- package/lib/grpc/watch.js +173 -173
- package/lib/http/index.js +10 -10
- package/lib/http/request.js +727 -727
- package/lib/http/response.js +799 -799
- package/lib/lifecycle.js +557 -557
- package/lib/middleware/compress.js +230 -230
- package/lib/middleware/cookieParser.js +237 -237
- package/lib/middleware/cors.js +93 -93
- package/lib/middleware/csrf.js +137 -137
- package/lib/middleware/errorHandler.js +101 -101
- package/lib/middleware/helmet.js +175 -175
- package/lib/middleware/index.js +19 -17
- package/lib/middleware/logger.js +74 -74
- package/lib/middleware/rateLimit.js +88 -88
- package/lib/middleware/requestId.js +53 -53
- package/lib/middleware/static.js +326 -326
- package/lib/middleware/timeout.js +71 -71
- package/lib/middleware/validator.js +255 -255
- package/lib/observe/health.js +326 -326
- package/lib/observe/index.js +50 -50
- package/lib/observe/logger.js +359 -359
- package/lib/observe/metrics.js +805 -805
- package/lib/observe/tracing.js +592 -592
- package/lib/orm/adapters/json.js +290 -290
- package/lib/orm/adapters/memory.js +764 -764
- package/lib/orm/adapters/mongo.js +764 -764
- package/lib/orm/adapters/mysql.js +933 -933
- package/lib/orm/adapters/postgres.js +1144 -1144
- package/lib/orm/adapters/redis.js +1534 -1534
- package/lib/orm/adapters/sql-base.js +212 -212
- package/lib/orm/adapters/sqlite.js +858 -858
- package/lib/orm/audit.js +649 -649
- package/lib/orm/cache.js +394 -394
- package/lib/orm/geo.js +387 -387
- package/lib/orm/index.js +784 -784
- package/lib/orm/migrate.js +432 -432
- package/lib/orm/model.js +1706 -1706
- package/lib/orm/plugin.js +375 -375
- package/lib/orm/procedures.js +836 -836
- package/lib/orm/profiler.js +233 -233
- package/lib/orm/query.js +1772 -1772
- package/lib/orm/replicas.js +241 -241
- package/lib/orm/schema.js +307 -307
- package/lib/orm/search.js +380 -380
- package/lib/orm/seed/data/commerce.js +136 -136
- package/lib/orm/seed/data/internet.js +111 -111
- package/lib/orm/seed/data/locations.js +204 -204
- package/lib/orm/seed/data/names.js +338 -338
- package/lib/orm/seed/data/person.js +128 -128
- package/lib/orm/seed/data/phone.js +211 -211
- package/lib/orm/seed/data/words.js +134 -134
- package/lib/orm/seed/factory.js +178 -178
- package/lib/orm/seed/fake.js +1186 -1186
- package/lib/orm/seed/index.js +18 -18
- package/lib/orm/seed/rng.js +70 -70
- package/lib/orm/seed/seeder.js +124 -124
- package/lib/orm/seed/unique.js +68 -68
- package/lib/orm/snapshot.js +366 -366
- package/lib/orm/tenancy.js +605 -605
- package/lib/orm/views.js +350 -350
- package/lib/router/index.js +436 -436
- package/lib/sse/index.js +8 -8
- package/lib/sse/stream.js +349 -349
- package/lib/ws/connection.js +451 -451
- package/lib/ws/handshake.js +125 -125
- package/lib/ws/index.js +14 -14
- package/lib/ws/room.js +223 -223
- package/package.json +73 -73
- package/types/app.d.ts +223 -223
- package/types/auth.d.ts +520 -520
- package/types/cluster.d.ts +75 -75
- package/types/env.d.ts +80 -80
- package/types/errors.d.ts +316 -316
- package/types/fetch.d.ts +43 -43
- package/types/grpc.d.ts +432 -432
- package/types/index.d.ts +384 -384
- package/types/lifecycle.d.ts +60 -60
- package/types/middleware.d.ts +320 -320
- package/types/observe.d.ts +304 -304
- package/types/orm.d.ts +1887 -1887
- package/types/request.d.ts +109 -109
- package/types/response.d.ts +157 -157
- package/types/router.d.ts +78 -78
- package/types/sse.d.ts +78 -78
- package/types/websocket.d.ts +126 -126
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module middleware/rateLimit
|
|
3
|
-
* @description In-memory rate-limiting middleware.
|
|
4
|
-
* Limits requests per IP address within a fixed time window.
|
|
5
|
-
*/
|
|
6
|
-
const log = require('../debug')('zero:rateLimit');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Create a rate-limiting middleware.
|
|
10
|
-
*
|
|
11
|
-
* @param {object} [opts] - Configuration options.
|
|
12
|
-
* @param {number} [opts.windowMs=60000] - Time window in milliseconds.
|
|
13
|
-
* @param {number} [opts.max=100] - Maximum requests per window per IP.
|
|
14
|
-
* @param {string} [opts.message] - Custom error message.
|
|
15
|
-
* @param {number} [opts.statusCode=429] - HTTP status for rate-limited responses.
|
|
16
|
-
* @param {function} [opts.keyGenerator] - (req) => string; custom key extraction (default: req.ip).
|
|
17
|
-
* @param {function} [opts.skip] - (req) => boolean; return true to skip rate limiting.
|
|
18
|
-
* @param {function} [opts.handler] - (req, res) => void; custom handler for rate-limited requests.
|
|
19
|
-
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* app.use(rateLimit()); // 100 req/min per IP
|
|
23
|
-
* app.use(rateLimit({ windowMs: 15 * 60000, max: 50 })); // 50 req per 15 min
|
|
24
|
-
* app.use(rateLimit({
|
|
25
|
-
* max: 10,
|
|
26
|
-
* keyGenerator: req => req.headers['x-api-key'],
|
|
27
|
-
* skip: req => req.path === '/health',
|
|
28
|
-
* }));
|
|
29
|
-
*/
|
|
30
|
-
function rateLimit(opts = {})
|
|
31
|
-
{
|
|
32
|
-
const windowMs = opts.windowMs || 60_000;
|
|
33
|
-
const max = opts.max || 100;
|
|
34
|
-
const statusCode = opts.statusCode || 429;
|
|
35
|
-
const message = opts.message || 'Too many requests, please try again later.';
|
|
36
|
-
const keyGenerator = typeof opts.keyGenerator === 'function' ? opts.keyGenerator : (req) => req.ip || 'unknown';
|
|
37
|
-
const skipFn = typeof opts.skip === 'function' ? opts.skip : null;
|
|
38
|
-
const handlerFn = typeof opts.handler === 'function' ? opts.handler : null;
|
|
39
|
-
|
|
40
|
-
const hits = new Map(); // key → { count, resetTime }
|
|
41
|
-
|
|
42
|
-
// Periodic cleanup to prevent memory leaks
|
|
43
|
-
const cleanupInterval = setInterval(() =>
|
|
44
|
-
{
|
|
45
|
-
const now = Date.now();
|
|
46
|
-
for (const [key, entry] of hits)
|
|
47
|
-
{
|
|
48
|
-
if (now >= entry.resetTime) hits.delete(key);
|
|
49
|
-
}
|
|
50
|
-
}, windowMs);
|
|
51
|
-
if (cleanupInterval.unref) cleanupInterval.unref();
|
|
52
|
-
|
|
53
|
-
return (req, res, next) =>
|
|
54
|
-
{
|
|
55
|
-
// Allow skipping rate limit for certain requests
|
|
56
|
-
if (skipFn && skipFn(req)) return next();
|
|
57
|
-
|
|
58
|
-
const key = keyGenerator(req);
|
|
59
|
-
const now = Date.now();
|
|
60
|
-
let entry = hits.get(key);
|
|
61
|
-
|
|
62
|
-
if (!entry || now >= entry.resetTime)
|
|
63
|
-
{
|
|
64
|
-
entry = { count: 0, resetTime: now + windowMs };
|
|
65
|
-
hits.set(key, entry);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
entry.count++;
|
|
69
|
-
|
|
70
|
-
// Set rate-limit headers
|
|
71
|
-
const remaining = Math.max(0, max - entry.count);
|
|
72
|
-
res.set('X-RateLimit-Limit', String(max));
|
|
73
|
-
res.set('X-RateLimit-Remaining', String(remaining));
|
|
74
|
-
res.set('X-RateLimit-Reset', String(Math.ceil(entry.resetTime / 1000)));
|
|
75
|
-
|
|
76
|
-
if (entry.count > max)
|
|
77
|
-
{
|
|
78
|
-
log.warn('rate limit exceeded for %s', key);
|
|
79
|
-
res.set('Retry-After', String(Math.ceil(windowMs / 1000)));
|
|
80
|
-
if (handlerFn) return handlerFn(req, res);
|
|
81
|
-
return res.status(statusCode).json({ error: message });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
next();
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = rateLimit;
|
|
1
|
+
/**
|
|
2
|
+
* @module middleware/rateLimit
|
|
3
|
+
* @description In-memory rate-limiting middleware.
|
|
4
|
+
* Limits requests per IP address within a fixed time window.
|
|
5
|
+
*/
|
|
6
|
+
const log = require('../debug')('zero:rateLimit');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create a rate-limiting middleware.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} [opts] - Configuration options.
|
|
12
|
+
* @param {number} [opts.windowMs=60000] - Time window in milliseconds.
|
|
13
|
+
* @param {number} [opts.max=100] - Maximum requests per window per IP.
|
|
14
|
+
* @param {string} [opts.message] - Custom error message.
|
|
15
|
+
* @param {number} [opts.statusCode=429] - HTTP status for rate-limited responses.
|
|
16
|
+
* @param {function} [opts.keyGenerator] - (req) => string; custom key extraction (default: req.ip).
|
|
17
|
+
* @param {function} [opts.skip] - (req) => boolean; return true to skip rate limiting.
|
|
18
|
+
* @param {function} [opts.handler] - (req, res) => void; custom handler for rate-limited requests.
|
|
19
|
+
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* app.use(rateLimit()); // 100 req/min per IP
|
|
23
|
+
* app.use(rateLimit({ windowMs: 15 * 60000, max: 50 })); // 50 req per 15 min
|
|
24
|
+
* app.use(rateLimit({
|
|
25
|
+
* max: 10,
|
|
26
|
+
* keyGenerator: req => req.headers['x-api-key'],
|
|
27
|
+
* skip: req => req.path === '/health',
|
|
28
|
+
* }));
|
|
29
|
+
*/
|
|
30
|
+
function rateLimit(opts = {})
|
|
31
|
+
{
|
|
32
|
+
const windowMs = opts.windowMs || 60_000;
|
|
33
|
+
const max = opts.max || 100;
|
|
34
|
+
const statusCode = opts.statusCode || 429;
|
|
35
|
+
const message = opts.message || 'Too many requests, please try again later.';
|
|
36
|
+
const keyGenerator = typeof opts.keyGenerator === 'function' ? opts.keyGenerator : (req) => req.ip || 'unknown';
|
|
37
|
+
const skipFn = typeof opts.skip === 'function' ? opts.skip : null;
|
|
38
|
+
const handlerFn = typeof opts.handler === 'function' ? opts.handler : null;
|
|
39
|
+
|
|
40
|
+
const hits = new Map(); // key → { count, resetTime }
|
|
41
|
+
|
|
42
|
+
// Periodic cleanup to prevent memory leaks
|
|
43
|
+
const cleanupInterval = setInterval(() =>
|
|
44
|
+
{
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
for (const [key, entry] of hits)
|
|
47
|
+
{
|
|
48
|
+
if (now >= entry.resetTime) hits.delete(key);
|
|
49
|
+
}
|
|
50
|
+
}, windowMs);
|
|
51
|
+
if (cleanupInterval.unref) cleanupInterval.unref();
|
|
52
|
+
|
|
53
|
+
return (req, res, next) =>
|
|
54
|
+
{
|
|
55
|
+
// Allow skipping rate limit for certain requests
|
|
56
|
+
if (skipFn && skipFn(req)) return next();
|
|
57
|
+
|
|
58
|
+
const key = keyGenerator(req);
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
let entry = hits.get(key);
|
|
61
|
+
|
|
62
|
+
if (!entry || now >= entry.resetTime)
|
|
63
|
+
{
|
|
64
|
+
entry = { count: 0, resetTime: now + windowMs };
|
|
65
|
+
hits.set(key, entry);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
entry.count++;
|
|
69
|
+
|
|
70
|
+
// Set rate-limit headers
|
|
71
|
+
const remaining = Math.max(0, max - entry.count);
|
|
72
|
+
res.set('X-RateLimit-Limit', String(max));
|
|
73
|
+
res.set('X-RateLimit-Remaining', String(remaining));
|
|
74
|
+
res.set('X-RateLimit-Reset', String(Math.ceil(entry.resetTime / 1000)));
|
|
75
|
+
|
|
76
|
+
if (entry.count > max)
|
|
77
|
+
{
|
|
78
|
+
log.warn('rate limit exceeded for %s', key);
|
|
79
|
+
res.set('Retry-After', String(Math.ceil(windowMs / 1000)));
|
|
80
|
+
if (handlerFn) return handlerFn(req, res);
|
|
81
|
+
return res.status(statusCode).json({ error: message });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
next();
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = rateLimit;
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module requestId
|
|
3
|
-
* @description Request ID middleware.
|
|
4
|
-
* Assigns a unique identifier to each incoming request for
|
|
5
|
-
* tracing and debugging. Sets the ID on both the request
|
|
6
|
-
* object and as a response header.
|
|
7
|
-
*/
|
|
8
|
-
const crypto = require('crypto');
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Create a request ID middleware.
|
|
12
|
-
*
|
|
1
|
+
/**
|
|
2
|
+
* @module requestId
|
|
3
|
+
* @description Request ID middleware.
|
|
4
|
+
* Assigns a unique identifier to each incoming request for
|
|
5
|
+
* tracing and debugging. Sets the ID on both the request
|
|
6
|
+
* object and as a response header.
|
|
7
|
+
*/
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create a request ID middleware.
|
|
12
|
+
*
|
|
13
13
|
* @param {object} [opts] - Configuration options.
|
|
14
|
-
* @param {string} [opts.header='X-Request-Id'] - Response header name.
|
|
15
|
-
* @param {Function} [opts.generator] - Custom ID generator `() => string`.
|
|
16
|
-
* @param {boolean} [opts.trustProxy=false] - Trust incoming X-Request-Id header from proxy.
|
|
17
|
-
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* app.use(requestId());
|
|
21
|
-
* app.get('/', (req, res) => {
|
|
22
|
-
* console.log(req.id); // e.g. '7f3a2b1c-...'
|
|
23
|
-
* });
|
|
24
|
-
*/
|
|
25
|
-
function requestId(opts = {})
|
|
26
|
-
{
|
|
27
|
-
const headerName = opts.header || 'X-Request-Id';
|
|
28
|
-
const trustProxy = !!opts.trustProxy;
|
|
29
|
-
const generator = typeof opts.generator === 'function'
|
|
30
|
-
? opts.generator
|
|
31
|
-
: () => crypto.randomUUID();
|
|
32
|
-
|
|
33
|
-
return (req, res, next) =>
|
|
34
|
-
{
|
|
35
|
-
let id;
|
|
36
|
-
|
|
37
|
-
if (trustProxy)
|
|
38
|
-
{
|
|
39
|
-
const existing = req.headers[headerName.toLowerCase()];
|
|
40
|
-
if (existing && typeof existing === 'string' && existing.length <= 128)
|
|
41
|
-
{
|
|
42
|
-
id = existing;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!id) id = generator();
|
|
47
|
-
|
|
48
|
-
req.id = id;
|
|
49
|
-
res.set(headerName, id);
|
|
50
|
-
next();
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
module.exports = requestId;
|
|
14
|
+
* @param {string} [opts.header='X-Request-Id'] - Response header name.
|
|
15
|
+
* @param {Function} [opts.generator] - Custom ID generator `() => string`.
|
|
16
|
+
* @param {boolean} [opts.trustProxy=false] - Trust incoming X-Request-Id header from proxy.
|
|
17
|
+
* @returns {Function} Middleware `(req, res, next) => void`.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* app.use(requestId());
|
|
21
|
+
* app.get('/', (req, res) => {
|
|
22
|
+
* console.log(req.id); // e.g. '7f3a2b1c-...'
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
function requestId(opts = {})
|
|
26
|
+
{
|
|
27
|
+
const headerName = opts.header || 'X-Request-Id';
|
|
28
|
+
const trustProxy = !!opts.trustProxy;
|
|
29
|
+
const generator = typeof opts.generator === 'function'
|
|
30
|
+
? opts.generator
|
|
31
|
+
: () => crypto.randomUUID();
|
|
32
|
+
|
|
33
|
+
return (req, res, next) =>
|
|
34
|
+
{
|
|
35
|
+
let id;
|
|
36
|
+
|
|
37
|
+
if (trustProxy)
|
|
38
|
+
{
|
|
39
|
+
const existing = req.headers[headerName.toLowerCase()];
|
|
40
|
+
if (existing && typeof existing === 'string' && existing.length <= 128)
|
|
41
|
+
{
|
|
42
|
+
id = existing;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!id) id = generator();
|
|
47
|
+
|
|
48
|
+
req.id = id;
|
|
49
|
+
res.set(headerName, id);
|
|
50
|
+
next();
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = requestId;
|