@jango-blockchained/hoox-shared 1.0.8

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.
Files changed (115) hide show
  1. package/README.md +27 -0
  2. package/dist/analytics.d.ts +22 -0
  3. package/dist/analytics.d.ts.map +1 -0
  4. package/dist/analytics.js +34 -0
  5. package/dist/api-client.d.ts +34 -0
  6. package/dist/api-client.d.ts.map +1 -0
  7. package/dist/api-client.js +124 -0
  8. package/dist/colors.d.ts +34 -0
  9. package/dist/colors.d.ts.map +1 -0
  10. package/dist/colors.js +42 -0
  11. package/dist/config.d.ts +24 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +91 -0
  14. package/dist/d1/index.d.ts +5 -0
  15. package/dist/d1/index.d.ts.map +1 -0
  16. package/dist/d1/index.js +316 -0
  17. package/dist/d1/repository.d.ts +77 -0
  18. package/dist/d1/repository.d.ts.map +1 -0
  19. package/dist/d1/schemas.d.ts +85 -0
  20. package/dist/d1/schemas.d.ts.map +1 -0
  21. package/dist/errors.d.ts +39 -0
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/errors.js +106 -0
  24. package/dist/exchange-client.d.ts +84 -0
  25. package/dist/exchange-client.d.ts.map +1 -0
  26. package/dist/exchange-client.js +104 -0
  27. package/dist/format-time.d.ts +24 -0
  28. package/dist/format-time.d.ts.map +1 -0
  29. package/dist/format-time.js +57 -0
  30. package/dist/formatters.d.ts +32 -0
  31. package/dist/formatters.d.ts.map +1 -0
  32. package/dist/formatters.js +155 -0
  33. package/dist/health.d.ts +19 -0
  34. package/dist/health.d.ts.map +1 -0
  35. package/dist/health.js +117 -0
  36. package/dist/index.d.ts +45 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +2581 -0
  39. package/dist/kvKeys.d.ts +72 -0
  40. package/dist/kvKeys.d.ts.map +1 -0
  41. package/dist/kvKeys.js +107 -0
  42. package/dist/kvUtils.d.ts +26 -0
  43. package/dist/kvUtils.d.ts.map +1 -0
  44. package/dist/kvUtils.js +127 -0
  45. package/dist/legal.d.ts +11 -0
  46. package/dist/legal.d.ts.map +1 -0
  47. package/dist/legal.js +40 -0
  48. package/dist/middleware/auth.d.ts +59 -0
  49. package/dist/middleware/auth.d.ts.map +1 -0
  50. package/dist/middleware/cors.d.ts +28 -0
  51. package/dist/middleware/cors.d.ts.map +1 -0
  52. package/dist/middleware/index.d.ts +10 -0
  53. package/dist/middleware/index.d.ts.map +1 -0
  54. package/dist/middleware/index.js +375 -0
  55. package/dist/middleware/logger.d.ts +16 -0
  56. package/dist/middleware/logger.d.ts.map +1 -0
  57. package/dist/middleware/rate-limit.d.ts +24 -0
  58. package/dist/middleware/rate-limit.d.ts.map +1 -0
  59. package/dist/middleware/security-headers.d.ts +39 -0
  60. package/dist/middleware/security-headers.d.ts.map +1 -0
  61. package/dist/middleware/validate.d.ts +21 -0
  62. package/dist/middleware/validate.d.ts.map +1 -0
  63. package/dist/router.d.ts +11 -0
  64. package/dist/router.d.ts.map +1 -0
  65. package/dist/router.js +123 -0
  66. package/dist/schemas/index.d.ts +4 -0
  67. package/dist/schemas/index.d.ts.map +1 -0
  68. package/dist/schemas/index.js +656 -0
  69. package/dist/schemas/registry.d.ts +8 -0
  70. package/dist/schemas/registry.d.ts.map +1 -0
  71. package/dist/schemas/types.d.ts +79 -0
  72. package/dist/schemas/types.d.ts.map +1 -0
  73. package/dist/schemas/validators.d.ts +35 -0
  74. package/dist/schemas/validators.d.ts.map +1 -0
  75. package/dist/service-bindings.d.ts +32 -0
  76. package/dist/service-bindings.d.ts.map +1 -0
  77. package/dist/service-bindings.js +31 -0
  78. package/dist/session.d.ts +46 -0
  79. package/dist/session.d.ts.map +1 -0
  80. package/dist/session.js +79 -0
  81. package/dist/sse.d.ts +26 -0
  82. package/dist/sse.d.ts.map +1 -0
  83. package/dist/sse.js +91 -0
  84. package/dist/stores/config-store.d.ts +87 -0
  85. package/dist/stores/config-store.d.ts.map +1 -0
  86. package/dist/stores/config-store.js +132 -0
  87. package/dist/stores/service-store.d.ts +206 -0
  88. package/dist/stores/service-store.d.ts.map +1 -0
  89. package/dist/stores/service-store.js +359 -0
  90. package/dist/stores/ui-store.d.ts +63 -0
  91. package/dist/stores/ui-store.d.ts.map +1 -0
  92. package/dist/stores/ui-store.js +62 -0
  93. package/dist/types/errors.d.ts +16 -0
  94. package/dist/types/errors.d.ts.map +1 -0
  95. package/dist/types/errors.js +1 -0
  96. package/dist/types/router.d.ts +22 -0
  97. package/dist/types/router.d.ts.map +1 -0
  98. package/dist/types/router.js +1 -0
  99. package/dist/types.d.ts +317 -0
  100. package/dist/types.d.ts.map +1 -0
  101. package/dist/types.js +70 -0
  102. package/dist/wizard/engine.d.ts +42 -0
  103. package/dist/wizard/engine.d.ts.map +1 -0
  104. package/dist/wizard/index.d.ts +7 -0
  105. package/dist/wizard/index.d.ts.map +1 -0
  106. package/dist/wizard/index.js +519 -0
  107. package/dist/wizard/persistence.d.ts +14 -0
  108. package/dist/wizard/persistence.d.ts.map +1 -0
  109. package/dist/wizard/presets.d.ts +34 -0
  110. package/dist/wizard/presets.d.ts.map +1 -0
  111. package/dist/wizard/provisioner.d.ts +11 -0
  112. package/dist/wizard/provisioner.d.ts.map +1 -0
  113. package/dist/wizard/types.d.ts +72 -0
  114. package/dist/wizard/types.d.ts.map +1 -0
  115. package/package.json +83 -0
@@ -0,0 +1,375 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
+
18
+ // src/errors.ts
19
+ function toError(err, fallback = "Unknown error") {
20
+ if (err instanceof Error)
21
+ return err.message;
22
+ if (typeof err === "string")
23
+ return err;
24
+ if (err && typeof err === "object" && "message" in err && typeof err.message === "string") {
25
+ return err.message;
26
+ }
27
+ if (err === null || err === undefined)
28
+ return fallback;
29
+ try {
30
+ return JSON.stringify(err) || fallback;
31
+ } catch {
32
+ return fallback;
33
+ }
34
+ }
35
+ function sanitizeOutput(data) {
36
+ if (data instanceof Error) {
37
+ return { name: data.name, message: data.message };
38
+ }
39
+ if (data && typeof data === "object" && !Array.isArray(data)) {
40
+ const sanitized = {};
41
+ for (const [k, v] of Object.entries(data)) {
42
+ if (k === "stack" || k === "cause")
43
+ continue;
44
+ sanitized[k] = v instanceof Error ? { name: v.name, message: v.message } : sanitizeOutput(v);
45
+ }
46
+ return sanitized;
47
+ }
48
+ if (Array.isArray(data)) {
49
+ return data.map(sanitizeOutput);
50
+ }
51
+ return data;
52
+ }
53
+ function createJsonResponse(data, status = 200) {
54
+ return new Response(JSON.stringify(sanitizeOutput(data)), {
55
+ status,
56
+ headers: { "Content-Type": "application/json" }
57
+ });
58
+ }
59
+ function createSuccessResponse(result) {
60
+ return createJsonResponse({ success: true, result }, 200);
61
+ }
62
+ function createErrorResponse(error, status) {
63
+ const message = typeof error === "string" ? error : error.message;
64
+ const statusCode = typeof error === "string" ? status ?? 500 : error.status ?? 500;
65
+ const body = { success: false, error: message };
66
+ if (typeof error !== "string" && error.code)
67
+ body.code = error.code;
68
+ if (typeof error !== "string" && error.details !== undefined)
69
+ body.details = error.details;
70
+ return new Response(JSON.stringify(body), {
71
+ status: statusCode,
72
+ headers: { "Content-Type": "application/json" }
73
+ });
74
+ }
75
+ var Errors = {
76
+ badRequest: (message) => createErrorResponse({ message, status: 400, code: "BAD_REQUEST" }),
77
+ unauthorized: (message = "Unauthorized") => createErrorResponse({ message, status: 401, code: "UNAUTHORIZED" }),
78
+ forbidden: (message = "Forbidden") => createErrorResponse({ message, status: 403, code: "FORBIDDEN" }),
79
+ notFound: (message = "Not found") => createErrorResponse({ message, status: 404, code: "NOT_FOUND" }),
80
+ methodNotAllowed: (message = "Method not allowed") => createErrorResponse({ message, status: 405, code: "METHOD_NOT_ALLOWED" }),
81
+ rateLimited: (retryAfter) => {
82
+ const res = createErrorResponse({
83
+ message: "Rate limit exceeded",
84
+ status: 429,
85
+ code: "RATE_LIMITED"
86
+ });
87
+ if (retryAfter)
88
+ res.headers.set("Retry-After", String(retryAfter));
89
+ return res;
90
+ },
91
+ internal: (err) => {
92
+ const message = err ? toError(err, "Internal server error") : "Internal server error";
93
+ return createErrorResponse({
94
+ message,
95
+ status: 500,
96
+ code: "INTERNAL_ERROR"
97
+ });
98
+ }
99
+ };
100
+
101
+ // src/middleware/logger.ts
102
+ function createLogger(ctx) {
103
+ const base = { service: ctx.service, module: ctx.module };
104
+ function emit(level, message, context) {
105
+ const entry = {
106
+ level,
107
+ timestamp: new Date().toISOString(),
108
+ ...base,
109
+ message,
110
+ ...context && { context }
111
+ };
112
+ const line = JSON.stringify(entry);
113
+ if (level === "error")
114
+ console.error(line);
115
+ else if (level === "warn")
116
+ console.warn(line);
117
+ else
118
+ console.info(line);
119
+ }
120
+ return {
121
+ info: (msg, ctx2) => emit("info", msg, ctx2),
122
+ warn: (msg, ctx2) => emit("warn", msg, ctx2),
123
+ error: (msg, ctx2) => emit("error", msg, ctx2)
124
+ };
125
+ }
126
+ function withRequestLog(handler, logCtx) {
127
+ return async (request, env, ctx) => {
128
+ const start = Date.now();
129
+ const logger = createLogger(logCtx);
130
+ try {
131
+ const response = await handler(request, env, ctx);
132
+ const duration = Date.now() - start;
133
+ const url = new URL(request.url);
134
+ logger.info(`${request.method} ${url.pathname}`, {
135
+ method: request.method,
136
+ path: url.pathname,
137
+ status: response.status,
138
+ durationMs: duration
139
+ });
140
+ return response;
141
+ } catch (error) {
142
+ const duration = Date.now() - start;
143
+ logger.error("Request failed", {
144
+ method: request.method,
145
+ path: new URL(request.url).pathname,
146
+ durationMs: duration,
147
+ error: toError(error)
148
+ });
149
+ throw error;
150
+ }
151
+ };
152
+ }
153
+ // src/middleware/auth.ts
154
+ function timingSafeEqual(a, b) {
155
+ if (a.length !== b.length)
156
+ return false;
157
+ const encoder = new TextEncoder;
158
+ const aBuf = encoder.encode(a);
159
+ const bBuf = encoder.encode(b);
160
+ let result = 0;
161
+ for (let i = 0;i < aBuf.length; i++) {
162
+ result |= aBuf[i] ^ bBuf[i];
163
+ }
164
+ return result === 0;
165
+ }
166
+ async function requireAuth(request, env) {
167
+ const apiKey = env.INTERNAL_API_KEY;
168
+ if (!apiKey) {
169
+ return new Response(JSON.stringify({ error: "Internal API key not configured" }), { status: 401, headers: { "Content-Type": "application/json" } });
170
+ }
171
+ const authHeader = request.headers.get("Authorization");
172
+ const expectedHeader = `Bearer ${apiKey}`;
173
+ if (!authHeader || !timingSafeEqual(authHeader, expectedHeader)) {
174
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
175
+ status: 401,
176
+ headers: { "Content-Type": "application/json" }
177
+ });
178
+ }
179
+ return null;
180
+ }
181
+ function requireInternalAuth(request, env, keyName = "INTERNAL_KEY_BINDING") {
182
+ const expectedKey = env[keyName];
183
+ if (!expectedKey) {
184
+ return new Response(JSON.stringify({
185
+ success: false,
186
+ error: `Internal auth key ${keyName} not configured`
187
+ }), { status: 401, headers: { "Content-Type": "application/json" } });
188
+ }
189
+ const providedKey = request.headers.get("X-Internal-Auth-Key");
190
+ if (!providedKey || !timingSafeEqual(providedKey, expectedKey)) {
191
+ return new Response(JSON.stringify({ success: false, error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" } });
192
+ }
193
+ return null;
194
+ }
195
+ function createInternalAuthMiddleware(keyName = "INTERNAL_KEY_BINDING") {
196
+ return (request, env) => {
197
+ const result = requireInternalAuth(request, env, keyName);
198
+ if (result)
199
+ return result;
200
+ };
201
+ }
202
+ function checkInternalAuth(request, env, keyName = "INTERNAL_KEY_BINDING") {
203
+ const expectedKey = env[keyName];
204
+ if (!expectedKey) {
205
+ return { authorized: false, error: `${keyName} not configured` };
206
+ }
207
+ const providedKey = request.headers.get("X-Internal-Auth-Key");
208
+ if (!providedKey || !timingSafeEqual(providedKey, expectedKey)) {
209
+ return { authorized: false, error: "Unauthorized" };
210
+ }
211
+ return { authorized: true };
212
+ }
213
+ // src/middleware/rate-limit.ts
214
+ function createRateLimiter(kv, config) {
215
+ const prefix = config.keyPrefix ?? "rate-limit";
216
+ function getClientIp(request) {
217
+ return request.headers.get("CF-Connecting-IP") ?? "unknown";
218
+ }
219
+ function getWindowKey(ip) {
220
+ const windowStart = Math.floor(Date.now() / (config.windowSeconds * 1000));
221
+ return `${prefix}:${ip}:${windowStart}`;
222
+ }
223
+ async function check(request) {
224
+ const ip = getClientIp(request);
225
+ const key = getWindowKey(ip);
226
+ const current = await kv.get(key);
227
+ const count = current ? parseInt(current, 10) : 0;
228
+ if (count >= config.maxRequests) {
229
+ const retryAfter = config.windowSeconds - Date.now() % (config.windowSeconds * 1000) / 1000;
230
+ return {
231
+ allowed: false,
232
+ remaining: 0,
233
+ retryAfter: Math.ceil(retryAfter)
234
+ };
235
+ }
236
+ await kv.put(key, String(count + 1), {
237
+ expirationTtl: config.windowSeconds
238
+ });
239
+ return { allowed: true, remaining: config.maxRequests - count - 1 };
240
+ }
241
+ async function enforce(request) {
242
+ const result = await check(request);
243
+ if (!result.allowed) {
244
+ return new Response(JSON.stringify({
245
+ error: "Rate limit exceeded",
246
+ retryAfter: result.retryAfter
247
+ }), {
248
+ status: 429,
249
+ headers: {
250
+ "Content-Type": "application/json",
251
+ "Retry-After": String(result.retryAfter ?? config.windowSeconds)
252
+ }
253
+ });
254
+ }
255
+ return null;
256
+ }
257
+ return { check, enforce };
258
+ }
259
+ // src/middleware/validate.ts
260
+ function validateJson(schema, data) {
261
+ const result = schema.safeParse(data);
262
+ if (!result.success) {
263
+ return {
264
+ ok: false,
265
+ error: result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")
266
+ };
267
+ }
268
+ return { ok: true, value: result.data };
269
+ }
270
+ async function validateJsonLegacy(request) {
271
+ try {
272
+ const body = await request.json();
273
+ if (typeof body !== "object" || body === null || Array.isArray(body)) {
274
+ return { ok: false, error: "Request body must be a JSON object" };
275
+ }
276
+ return { ok: true, value: body };
277
+ } catch {
278
+ return { ok: false, error: "Invalid JSON in request body" };
279
+ }
280
+ }
281
+ function requireField(body, field) {
282
+ if (!(field in body)) {
283
+ return { ok: false, error: `Missing required field: ${field}` };
284
+ }
285
+ return { ok: true, value: body[field] };
286
+ }
287
+ function optionalField(body, field, defaultValue) {
288
+ if (!(field in body))
289
+ return defaultValue;
290
+ return body[field];
291
+ }
292
+ // src/middleware/cors.ts
293
+ var DEFAULT_OPTIONS = {
294
+ allowOrigin: "*",
295
+ allowMethods: "GET, POST, OPTIONS, PUT, DELETE",
296
+ allowHeaders: "Content-Type, Authorization, X-Request-ID, X-Internal-Auth-Key",
297
+ allowCredentials: false,
298
+ maxAge: 86400
299
+ };
300
+ function corsHeaders(options) {
301
+ const opts = { ...DEFAULT_OPTIONS, ...options };
302
+ const headers = {
303
+ "Access-Control-Allow-Origin": opts.allowOrigin,
304
+ "Access-Control-Allow-Methods": opts.allowMethods,
305
+ "Access-Control-Allow-Headers": opts.allowHeaders,
306
+ "Access-Control-Max-Age": String(opts.maxAge)
307
+ };
308
+ if (opts.allowCredentials) {
309
+ headers["Access-Control-Allow-Credentials"] = "true";
310
+ }
311
+ return headers;
312
+ }
313
+ function handleCorsPreflightRequest(request, options) {
314
+ if (request.method !== "OPTIONS")
315
+ return null;
316
+ return new Response(null, {
317
+ status: 204,
318
+ headers: corsHeaders(options)
319
+ });
320
+ }
321
+ // src/middleware/security-headers.ts
322
+ var SECURITY_HEADERS_DEFAULTS = {
323
+ xContentTypeOptions: "nosniff",
324
+ xFrameOptions: "DENY",
325
+ xXssProtection: "1; mode=block",
326
+ referrerPolicy: "strict-origin-when-cross-origin",
327
+ permissionsPolicy: "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()",
328
+ strictTransportSecurity: "max-age=31536000; includeSubDomains",
329
+ contentSecurityPolicy: "default-src 'self'"
330
+ };
331
+ function secureHeaders(options) {
332
+ const opts = { ...SECURITY_HEADERS_DEFAULTS, ...options };
333
+ const headers = {
334
+ "X-Content-Type-Options": opts.xContentTypeOptions,
335
+ "X-Frame-Options": opts.xFrameOptions,
336
+ "X-XSS-Protection": opts.xXssProtection,
337
+ "Referrer-Policy": opts.referrerPolicy,
338
+ "Permissions-Policy": opts.permissionsPolicy,
339
+ "Strict-Transport-Security": opts.strictTransportSecurity
340
+ };
341
+ if (opts.contentSecurityPolicy) {
342
+ headers["Content-Security-Policy"] = opts.contentSecurityPolicy;
343
+ }
344
+ return headers;
345
+ }
346
+ function wrapWithSecurityHeaders(response, options) {
347
+ const headers = new Headers(response.headers);
348
+ for (const [key, value] of Object.entries(secureHeaders(options))) {
349
+ headers.set(key, value);
350
+ }
351
+ return new Response(response.body, {
352
+ status: response.status,
353
+ statusText: response.statusText,
354
+ headers
355
+ });
356
+ }
357
+ export {
358
+ wrapWithSecurityHeaders,
359
+ withRequestLog,
360
+ validateJsonLegacy,
361
+ validateJson,
362
+ timingSafeEqual,
363
+ secureHeaders,
364
+ requireInternalAuth,
365
+ requireField,
366
+ requireAuth,
367
+ optionalField,
368
+ handleCorsPreflightRequest,
369
+ createRateLimiter,
370
+ createLogger,
371
+ createInternalAuthMiddleware,
372
+ corsHeaders,
373
+ checkInternalAuth,
374
+ SECURITY_HEADERS_DEFAULTS
375
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Logger middleware for Cloudflare Workers
3
+ * Adapted from workers/agent-worker/src/middleware/logger.ts
4
+ */
5
+ export interface LogContext {
6
+ service: string;
7
+ module?: string;
8
+ }
9
+ export interface Logger {
10
+ info(message: string, context?: Record<string, unknown>): void;
11
+ warn(message: string, context?: Record<string, unknown>): void;
12
+ error(message: string, context?: Record<string, unknown>): void;
13
+ }
14
+ export declare function createLogger(ctx: LogContext): Logger;
15
+ export declare function withRequestLog<E extends Record<string, unknown>>(handler: (request: Request, env: E, ctx: ExecutionContext) => Promise<Response>, logCtx: LogContext): (request: Request, env: E, ctx: ExecutionContext) => Promise<Response>;
16
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/middleware/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAWD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC/D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACjE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CA0BpD;AAED,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9D,OAAO,EAAE,CACP,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,CAAC,EACN,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,QAAQ,CAAC,EACtB,MAAM,EAAE,UAAU,GACjB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,CAAC,CA2BxE"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Rate limiting middleware for Cloudflare Workers
3
+ * Adapted from workers/agent-worker/src/middleware/rate-limit.ts
4
+ *
5
+ * @available — Available for consumer use. Import from "@jango-blockchained/hoox-shared/middleware".
6
+ */
7
+ import type { Env } from "../types";
8
+ export interface RateLimitConfig {
9
+ maxRequests: number;
10
+ windowSeconds: number;
11
+ keyPrefix?: string;
12
+ }
13
+ interface RateLimitResult {
14
+ allowed: boolean;
15
+ remaining: number;
16
+ retryAfter?: number;
17
+ }
18
+ export interface RateLimiter {
19
+ check(request: Request): Promise<RateLimitResult>;
20
+ enforce(request: Request): Promise<Response | null>;
21
+ }
22
+ export declare function createRateLimiter(kv: Env["CONFIG_KV"], config: RateLimitConfig): RateLimiter;
23
+ export {};
24
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAClD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CACrD;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,GAAG,CAAC,WAAW,CAAC,EACpB,MAAM,EAAE,eAAe,GACtB,WAAW,CA0Db"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Security Headers middleware for Cloudflare Workers
3
+ * Provides standardized security headers for all worker responses
4
+ *
5
+ * @available — Available for consumer use. Import from "@jango-blockchained/hoox-shared/middleware".
6
+ */
7
+ export interface SecurityHeadersOptions {
8
+ /** X-Content-Type-Options (default: "nosniff") */
9
+ xContentTypeOptions?: string;
10
+ /** X-Frame-Options (default: "DENY") */
11
+ xFrameOptions?: string;
12
+ /** X-XSS-Protection (default: "1; mode=block") */
13
+ xXssProtection?: string;
14
+ /** Referrer-Policy (default: "strict-origin-when-cross-origin") */
15
+ referrerPolicy?: string;
16
+ /** Permissions-Policy (default: restrictive — all disabled) */
17
+ permissionsPolicy?: string;
18
+ /** Strict-Transport-Security (default: "max-age=31536000; includeSubDomains") */
19
+ strictTransportSecurity?: string;
20
+ /** Content-Security-Policy (default: "default-src 'self'") */
21
+ contentSecurityPolicy?: string;
22
+ }
23
+ export declare const SECURITY_HEADERS_DEFAULTS: Required<SecurityHeadersOptions>;
24
+ /**
25
+ * Create security headers object for use in responses.
26
+ * Merges provided options over defaults.
27
+ */
28
+ export declare function secureHeaders(options?: SecurityHeadersOptions): Record<string, string>;
29
+ /**
30
+ * Wrap an existing Response with security headers.
31
+ * Preserves existing response headers (security headers take precedence).
32
+ *
33
+ * @example
34
+ * return wrapWithSecurityHeaders(
35
+ * createJsonResponse({ success: true }, 200)
36
+ * );
37
+ */
38
+ export declare function wrapWithSecurityHeaders(response: Response, options?: SecurityHeadersOptions): Response;
39
+ //# sourceMappingURL=security-headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,sBAAsB;IACrC,kDAAkD;IAClD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iFAAiF;IACjF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,8DAA8D;IAC9D,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,sBAAsB,CAStE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAexB;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,QAAQ,CAUV"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Validation middleware for Cloudflare Workers
3
+ * Uses Zod for runtime schema validation.
4
+ *
5
+ * @available — Available for consumer use. Import from "@jango-blockchained/hoox-shared/middleware".
6
+ */
7
+ import { z } from "zod";
8
+ import type { Result } from "../types";
9
+ /**
10
+ * Validate unknown data against a Zod schema, returning a Result type.
11
+ * Provides structured error messages from Zod issue paths.
12
+ */
13
+ export declare function validateJson<T extends z.ZodTypeAny>(schema: T, data: unknown): Result<z.infer<T>>;
14
+ /**
15
+ * Legacy signature: parse request body as JSON object.
16
+ * Kept for backward compatibility with existing workers.
17
+ */
18
+ export declare function validateJsonLegacy(request: Request): Promise<Result<Record<string, unknown>>>;
19
+ export declare function requireField<T>(body: Record<string, unknown>, field: string): Result<T>;
20
+ export declare function optionalField<T>(body: Record<string, unknown>, field: string, defaultValue: T): T;
21
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/middleware/validate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACjD,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,OAAO,GACZ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAWpB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAU1C;AAED,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,CAAC,CAAC,CAKX;AAED,wBAAgB,aAAa,CAAC,CAAC,EAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,CAAC,GACd,CAAC,CAGH"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Router implementation for Cloudflare Workers
3
+ * Provides standardized routing across all workers with path parameter support
4
+ *
5
+ * Supports exact matching (fast path) and pattern matching for `:param` segments.
6
+ * Path parameters are extracted and passed as the 4th argument to handlers.
7
+ */
8
+ import type { Router } from "./types/router";
9
+ export type { Handler, RouteParams } from "./types/router";
10
+ export declare function createRouter<TEnv = Record<string, unknown>>(): Router<TEnv>;
11
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAIV,MAAM,EACP,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE3D,wBAAgB,YAAY,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,CAsL3E"}
package/dist/router.js ADDED
@@ -0,0 +1,123 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
+
18
+ // src/router.ts
19
+ function createRouter() {
20
+ const routes = [];
21
+ function extractParams(pattern) {
22
+ const params = [];
23
+ const regex = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
24
+ let match;
25
+ while ((match = regex.exec(pattern)) !== null) {
26
+ params.push(match[1]);
27
+ }
28
+ return params;
29
+ }
30
+ function patternToRegex(pattern) {
31
+ const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32
+ const regexStr = escaped.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, "([^/]+)");
33
+ return new RegExp(`^${regexStr}$`);
34
+ }
35
+ function matchPattern(path, regex, paramNames) {
36
+ const m = path.match(regex);
37
+ if (!m)
38
+ return null;
39
+ const params = {};
40
+ for (let i = 0;i < paramNames.length; i++) {
41
+ params[paramNames[i]] = m[i + 1];
42
+ }
43
+ return params;
44
+ }
45
+ function addRoute(path, method, handler, middleware) {
46
+ const paramNames = extractParams(path);
47
+ const route = { path, method, handler, middleware };
48
+ if (paramNames.length > 0) {
49
+ route.params = paramNames;
50
+ route.regex = patternToRegex(path);
51
+ }
52
+ routes.push(route);
53
+ }
54
+ function matchRoute(path, method) {
55
+ const exact = routes.findLast ? routes.findLast((r) => r.path === path && r.method === method) : [...routes].reverse().find((r) => r.path === path && r.method === method);
56
+ if (exact)
57
+ return { route: exact };
58
+ for (let i = routes.length - 1;i >= 0; i--) {
59
+ const route = routes[i];
60
+ if (route.params && route.params.length > 0 && route.regex) {
61
+ const matched = matchPattern(path, route.regex, route.params);
62
+ if (matched && route.method === method) {
63
+ return { route, params: matched };
64
+ }
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ return {
70
+ get(path, handler, middleware) {
71
+ addRoute(path, "GET", handler, middleware);
72
+ },
73
+ post(path, handler, middleware) {
74
+ addRoute(path, "POST", handler, middleware);
75
+ },
76
+ put(path, handler, middleware) {
77
+ addRoute(path, "PUT", handler, middleware);
78
+ },
79
+ delete(path, handler, middleware) {
80
+ addRoute(path, "DELETE", handler, middleware);
81
+ },
82
+ async handle(request, env, ctx) {
83
+ const url = new URL(request.url);
84
+ const path = url.pathname;
85
+ const method = request.method;
86
+ const match = matchRoute(path, method);
87
+ if (!match) {
88
+ const pathExists = routes.some((r) => {
89
+ if (r.path === path)
90
+ return true;
91
+ if (r.params && r.params.length > 0 && r.regex) {
92
+ return r.regex.test(path);
93
+ }
94
+ return false;
95
+ });
96
+ if (pathExists) {
97
+ return new Response(JSON.stringify({
98
+ success: false,
99
+ error: `Method ${method} not allowed for ${path}`
100
+ }), {
101
+ status: 405,
102
+ headers: { "Content-Type": "application/json" }
103
+ });
104
+ }
105
+ return new Response(JSON.stringify({ success: false, error: "Not found" }), {
106
+ status: 404,
107
+ headers: { "Content-Type": "application/json" }
108
+ });
109
+ }
110
+ if (match.route.middleware) {
111
+ for (const mw of match.route.middleware) {
112
+ const result = await mw(request, env, ctx);
113
+ if (result instanceof Response)
114
+ return result;
115
+ }
116
+ }
117
+ return match.route.handler(request, env, ctx, match.params);
118
+ }
119
+ };
120
+ }
121
+ export {
122
+ createRouter
123
+ };
@@ -0,0 +1,4 @@
1
+ export type { WorkerManifest, VarDef, ServiceBindingDef, InfraBindings, KVBindingDef, D1BindingDef, R2BindingDef, QueueBindingDef, VectorizeBindingDef, DOBindingDef, ValidationError, ValidationReport, } from "./types.js";
2
+ export { WORKER_MANIFESTS, WORKER_NAMES, CALLED_BY } from "./registry.js";
3
+ export { validateWranglerJsonc, validateRootSecrets, validateDevVars, validateAll, generateWranglerJsonc, generateDevVars, } from "./validators.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schemas/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,MAAM,EACN,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1E,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,qBAAqB,EACrB,eAAe,GAChB,MAAM,iBAAiB,CAAC"}