@jango-blockchained/hoox-shared 1.0.8 → 1.1.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.
Files changed (102) hide show
  1. package/README.md +17 -0
  2. package/dist/analytics.d.ts +23 -2
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/analytics.js +14 -3
  5. package/dist/api-client.d.ts +12 -2
  6. package/dist/api-client.d.ts.map +1 -1
  7. package/dist/api-client.js +74 -7
  8. package/dist/colors.d.ts +63 -25
  9. package/dist/colors.d.ts.map +1 -1
  10. package/dist/colors.js +60 -20
  11. package/dist/config.d.ts +34 -1
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +61 -6
  14. package/dist/cron-handler.d.ts +34 -0
  15. package/dist/cron-handler.d.ts.map +1 -0
  16. package/dist/cron-handler.js +48 -0
  17. package/dist/d1/index.js +50 -6
  18. package/dist/d1/repository.d.ts +5 -0
  19. package/dist/d1/repository.d.ts.map +1 -1
  20. package/dist/d1/repository.js +297 -0
  21. package/dist/d1/schemas.js +81 -0
  22. package/dist/errors.d.ts +1 -0
  23. package/dist/errors.d.ts.map +1 -1
  24. package/dist/errors.js +48 -5
  25. package/dist/exchanges/base-exchange-client.d.ts +68 -0
  26. package/dist/exchanges/base-exchange-client.d.ts.map +1 -0
  27. package/dist/exchanges/base-exchange-client.js +120 -0
  28. package/dist/exchanges/index.d.ts +3 -0
  29. package/dist/exchanges/index.d.ts.map +1 -0
  30. package/dist/exchanges/index.js +120 -0
  31. package/dist/exchanges/types.d.ts +19 -0
  32. package/dist/exchanges/types.d.ts.map +1 -0
  33. package/dist/exchanges/types.js +1 -0
  34. package/dist/health.js +48 -5
  35. package/dist/index.d.ts +30 -11
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1058 -73
  38. package/dist/kvUtils.js +48 -5
  39. package/dist/middleware/auth.d.ts +46 -7
  40. package/dist/middleware/auth.d.ts.map +1 -1
  41. package/dist/middleware/auth.js +151 -0
  42. package/dist/middleware/cors.d.ts +28 -2
  43. package/dist/middleware/cors.d.ts.map +1 -1
  44. package/dist/middleware/cors.js +77 -0
  45. package/dist/middleware/index.d.ts +2 -2
  46. package/dist/middleware/index.d.ts.map +1 -1
  47. package/dist/middleware/index.js +361 -101
  48. package/dist/middleware/logger.d.ts +2 -1
  49. package/dist/middleware/logger.d.ts.map +1 -1
  50. package/dist/middleware/logger.js +202 -0
  51. package/dist/middleware/rate-limit.d.ts +3 -1
  52. package/dist/middleware/rate-limit.d.ts.map +1 -1
  53. package/dist/middleware/rate-limit.js +181 -0
  54. package/dist/middleware/security-headers.js +58 -0
  55. package/dist/middleware/validate.js +56 -0
  56. package/dist/operator-transport.d.ts +61 -0
  57. package/dist/operator-transport.d.ts.map +1 -0
  58. package/dist/operator-transport.js +87 -0
  59. package/dist/path-utils.d.ts +205 -0
  60. package/dist/path-utils.d.ts.map +1 -0
  61. package/dist/path-utils.js +188 -0
  62. package/dist/queue-handler.d.ts +43 -0
  63. package/dist/queue-handler.d.ts.map +1 -0
  64. package/dist/queue-handler.js +46 -0
  65. package/dist/router.d.ts +2 -2
  66. package/dist/router.d.ts.map +1 -1
  67. package/dist/router.js +15 -8
  68. package/dist/schemas/index.js +7 -4
  69. package/dist/schemas/registry.js +387 -0
  70. package/dist/schemas/types.js +1 -0
  71. package/dist/schemas/validators.d.ts.map +1 -1
  72. package/dist/schemas/validators.js +290 -0
  73. package/dist/service-bindings.d.ts +68 -26
  74. package/dist/service-bindings.d.ts.map +1 -1
  75. package/dist/service-bindings.js +219 -2
  76. package/dist/session.d.ts +9 -5
  77. package/dist/session.d.ts.map +1 -1
  78. package/dist/session.js +179 -4
  79. package/dist/sse.d.ts +12 -3
  80. package/dist/sse.d.ts.map +1 -1
  81. package/dist/sse.js +70 -7
  82. package/dist/stores/config-store.d.ts.map +1 -1
  83. package/dist/stores/config-store.js +129 -6
  84. package/dist/stores/service-store.d.ts +50 -1
  85. package/dist/stores/service-store.d.ts.map +1 -1
  86. package/dist/stores/service-store.js +162 -27
  87. package/dist/test-utils.d.ts +132 -0
  88. package/dist/test-utils.d.ts.map +1 -0
  89. package/dist/test-utils.js +128 -0
  90. package/dist/types/router.d.ts +18 -8
  91. package/dist/types/router.d.ts.map +1 -1
  92. package/dist/types.d.ts +124 -5
  93. package/dist/types.d.ts.map +1 -1
  94. package/dist/types.js +11 -0
  95. package/dist/wizard/engine.d.ts.map +1 -1
  96. package/dist/wizard/engine.js +501 -0
  97. package/dist/wizard/index.js +2 -1
  98. package/dist/wizard/persistence.js +31 -0
  99. package/dist/wizard/presets.js +199 -0
  100. package/dist/wizard/provisioner.js +1 -0
  101. package/dist/wizard/types.js +1 -0
  102. package/package.json +46 -12
@@ -15,6 +15,69 @@ var __export = (target, all) => {
15
15
  };
16
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
+ // src/operator-transport.ts
19
+ function stripTrailingSlashes(url) {
20
+ return url.replace(/\/+$/, "");
21
+ }
22
+ function parseTransport(raw) {
23
+ if (!raw)
24
+ return null;
25
+ const v = raw.trim().toLowerCase();
26
+ if (VALID_TRANSPORTS.has(v)) {
27
+ return v;
28
+ }
29
+ return null;
30
+ }
31
+ function resolveOperatorTransportProfile(env = process.env, options = {}) {
32
+ const accessClientId = env.CF_ACCESS_CLIENT_ID?.trim() ?? "";
33
+ const accessClientSecret = env.CF_ACCESS_CLIENT_SECRET?.trim() ?? "";
34
+ const hasAccess = Boolean(accessClientId && accessClientSecret);
35
+ const explicit = parseTransport(env.HOOX_TRANSPORT) ?? parseTransport(options.configTransport);
36
+ const transport = explicit ?? (hasAccess ? "access" : "public");
37
+ const apiFromEnv = env.HOOX_API_URL?.trim();
38
+ const apiFromConfig = options.configApiUrl?.trim();
39
+ const tokenFromEnv = env.HOOX_API_TOKEN?.trim();
40
+ const tokenFromConfig = options.configApiToken?.trim();
41
+ return {
42
+ transport,
43
+ apiBase: stripTrailingSlashes(apiFromEnv || apiFromConfig || DEFAULT_API_BASE),
44
+ bearerToken: tokenFromEnv || tokenFromConfig || "",
45
+ accessClientId,
46
+ accessClientSecret
47
+ };
48
+ }
49
+ function buildOperatorAuthHeaders(profile) {
50
+ const headers = {};
51
+ if (profile.bearerToken) {
52
+ headers.Authorization = `Bearer ${profile.bearerToken}`;
53
+ }
54
+ const useAccessHeaders = profile.transport === "access" || Boolean(profile.accessClientId) && Boolean(profile.accessClientSecret);
55
+ if (useAccessHeaders && profile.accessClientId && profile.accessClientSecret) {
56
+ headers["CF-Access-Client-Id"] = profile.accessClientId;
57
+ headers["CF-Access-Client-Secret"] = profile.accessClientSecret;
58
+ }
59
+ return headers;
60
+ }
61
+ function hasOperatorClientCredentials(profile) {
62
+ if (profile.bearerToken)
63
+ return true;
64
+ return Boolean(profile.accessClientId && profile.accessClientSecret);
65
+ }
66
+ function operatorUrl(profile, path) {
67
+ const base = profile.apiBase.replace(/\/+$/, "");
68
+ const p = path.startsWith("/") ? path : `/${path}`;
69
+ return `${base}${p}`;
70
+ }
71
+ var DEFAULT_API_BASE = "http://localhost:8787", VALID_TRANSPORTS;
72
+ var init_operator_transport = __esm(() => {
73
+ VALID_TRANSPORTS = new Set([
74
+ "public",
75
+ "access",
76
+ "mtls",
77
+ "tunnel"
78
+ ]);
79
+ });
80
+
18
81
  // src/api-client.ts
19
82
  var exports_api_client = {};
20
83
  __export(exports_api_client, {
@@ -40,20 +103,25 @@ function isNetworkError(error) {
40
103
  function sleep(ms) {
41
104
  return new Promise((resolve) => setTimeout(resolve, ms));
42
105
  }
106
+ function activeProfile(override) {
107
+ return override ?? resolveOperatorTransportProfile();
108
+ }
43
109
  async function hooxFetch(path, options) {
110
+ const profile = options?.transport ?? (options?.transportEnv ? resolveOperatorTransportProfile(options.transportEnv) : activeProfile());
111
+ const { transport: _t, transportEnv: _e, ...fetchInit } = options ?? {};
44
112
  let lastError;
45
113
  for (let attempt = 0;attempt <= MAX_RETRIES; attempt++) {
46
114
  const controller = new AbortController;
47
115
  const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
48
116
  try {
49
- const url = `${API_BASE}${path}`;
117
+ const url = operatorUrl(profile, path);
50
118
  const headers = {
51
119
  "Content-Type": "application/json",
52
- ...API_TOKEN ? { Authorization: `Bearer ${API_TOKEN}` } : {},
53
- ...options?.headers
120
+ ...buildOperatorAuthHeaders(profile),
121
+ ...fetchInit.headers
54
122
  };
55
123
  const response = await fetch(url, {
56
- ...options,
124
+ ...fetchInit,
57
125
  headers,
58
126
  signal: controller.signal
59
127
  });
@@ -101,10 +169,9 @@ async function hooxFetch(path, options) {
101
169
  retryable: false
102
170
  });
103
171
  }
104
- var API_BASE, API_TOKEN, FETCH_TIMEOUT_MS = 5000, MAX_RETRIES = 3, BASE_RETRY_DELAY_MS = 1000, MAX_RETRY_DELAY_MS = 16000, WorkerAPIError;
172
+ var FETCH_TIMEOUT_MS = 5000, MAX_RETRIES = 3, BASE_RETRY_DELAY_MS = 1000, MAX_RETRY_DELAY_MS = 16000, WorkerAPIError;
105
173
  var init_api_client = __esm(() => {
106
- API_BASE = process.env.HOOX_API_URL || "http://localhost:8787";
107
- API_TOKEN = process.env.HOOX_API_TOKEN || "";
174
+ init_operator_transport();
108
175
  WorkerAPIError = class WorkerAPIError extends Error {
109
176
  status;
110
177
  retryable;
@@ -122,17 +189,18 @@ var exports_sse = {};
122
189
  __export(exports_sse, {
123
190
  subscribeSSE: () => subscribeSSE
124
191
  });
125
- function subscribeSSE(path, callback, onStatus) {
192
+ function subscribeSSE(path, callback, onStatus, options) {
126
193
  let aborted = false;
194
+ const profile = options?.transport ?? (options?.transportEnv ? resolveOperatorTransportProfile(options.transportEnv) : resolveOperatorTransportProfile());
127
195
  const run = async () => {
128
196
  let attempt = 0;
129
197
  while (!aborted && attempt < MAX_RECONNECT_ATTEMPTS) {
130
198
  try {
131
- const url = `${API_BASE2}${path}`;
199
+ const url = operatorUrl(profile, path);
132
200
  const response = await fetch(url, {
133
201
  headers: {
134
202
  Accept: "text/event-stream",
135
- ...API_TOKEN2 ? { Authorization: `Bearer ${API_TOKEN2}` } : {}
203
+ ...buildOperatorAuthHeaders(profile)
136
204
  }
137
205
  });
138
206
  if (!response.ok || !response.body) {
@@ -161,7 +229,7 @@ function subscribeSSE(path, callback, onStatus) {
161
229
  }
162
230
  }
163
231
  }
164
- } catch (error) {
232
+ } catch {
165
233
  if (aborted)
166
234
  break;
167
235
  onStatus?.("reconnecting");
@@ -181,15 +249,21 @@ function subscribeSSE(path, callback, onStatus) {
181
249
  }
182
250
  };
183
251
  }
184
- var API_BASE2, API_TOKEN2, RECONNECT_BASE_MS = 1000, RECONNECT_MAX_MS = 16000, MAX_RECONNECT_ATTEMPTS = 10;
252
+ var RECONNECT_BASE_MS = 1000, RECONNECT_MAX_MS = 16000, MAX_RECONNECT_ATTEMPTS = 10;
185
253
  var init_sse = __esm(() => {
186
- API_BASE2 = process.env.HOOX_API_URL || "http://localhost:8787";
187
- API_TOKEN2 = process.env.HOOX_API_TOKEN || "";
254
+ init_operator_transport();
188
255
  });
189
256
 
190
257
  // src/stores/service-store.ts
191
258
  import { create } from "zustand";
192
259
  import { immer } from "zustand/middleware/immer";
260
+ function summarizeCliError(details) {
261
+ const raw = details.stderr.trim() || details.stdout.trim() || details.command || "Unknown CLI error";
262
+ const firstLine = raw.split(`
263
+ `, 1)[0] ?? "";
264
+ const trimmed = firstLine.slice(0, 120).trimEnd();
265
+ return trimmed.length > 0 ? trimmed : details.command;
266
+ }
193
267
  var BACKOFF_SEQUENCE = [1000, 2000, 4000, 8000, 16000];
194
268
  var MAX_RETRIES2 = 5;
195
269
  function ringPush(arr, item, max) {
@@ -210,6 +284,7 @@ var initialState = {
210
284
  selectedWorkerId: null,
211
285
  retryCount: 0,
212
286
  lastError: null,
287
+ lastErrorDetails: null,
213
288
  lastSuccessfulFetch: 0,
214
289
  reconnectDelay: 0,
215
290
  disconnectedAt: null
@@ -225,7 +300,7 @@ var useServiceStore = create()(immer((set, get) => ({
225
300
  fetchWorkers: async () => {
226
301
  const { hooxFetch: hooxFetch2 } = await Promise.resolve().then(() => (init_api_client(), exports_api_client));
227
302
  try {
228
- const data = await hooxFetch2("/workers");
303
+ const data = await hooxFetch2("/v1/workers");
229
304
  set((state) => {
230
305
  state.workers = data;
231
306
  state.lastUpdated = Date.now();
@@ -234,27 +309,42 @@ var useServiceStore = create()(immer((set, get) => ({
234
309
  state.connectionStatus = "connected";
235
310
  state.retryCount = 0;
236
311
  state.lastError = null;
312
+ state.lastErrorDetails = null;
237
313
  state.reconnectDelay = 0;
238
314
  state.disconnectedAt = null;
239
315
  }
240
316
  });
241
317
  } catch (error) {
242
318
  const msg = error instanceof Error ? error.message : "Unknown fetch error";
319
+ get().addAlert({
320
+ id: crypto.randomUUID(),
321
+ type: "connection",
322
+ severity: "error",
323
+ message: msg,
324
+ timestamp: Date.now(),
325
+ acknowledged: false
326
+ });
243
327
  set((state) => {
328
+ state.lastError = msg;
329
+ state.disconnectedAt = state.disconnectedAt ?? Date.now();
244
330
  if (state.connectionStatus === "connected" || state.connectionStatus === "polling") {
245
331
  state.connectionStatus = "reconnecting";
246
332
  state.retryCount = state.retryCount + 1;
247
- state.lastError = msg;
248
- state.disconnectedAt = state.disconnectedAt ?? Date.now();
249
333
  if (state.retryCount >= MAX_RETRIES2) {
250
334
  state.connectionStatus = "offline";
251
335
  state.lastError = `Connection lost after ${MAX_RETRIES2} retries`;
252
336
  } else {
253
337
  state.reconnectDelay = getBackoffDelay(state.retryCount);
254
338
  }
255
- }
256
- if (state.connectionStatus === "reconnecting") {
257
- state.lastError = msg;
339
+ } else if (state.connectionStatus === "reconnecting") {
340
+ state.retryCount = state.retryCount + 1;
341
+ if (state.retryCount >= MAX_RETRIES2) {
342
+ state.connectionStatus = "offline";
343
+ state.lastError = `Connection lost after ${MAX_RETRIES2} retries`;
344
+ state.reconnectDelay = 0;
345
+ } else {
346
+ state.reconnectDelay = getBackoffDelay(state.retryCount);
347
+ }
258
348
  }
259
349
  });
260
350
  }
@@ -262,18 +352,40 @@ var useServiceStore = create()(immer((set, get) => ({
262
352
  streamTrades: async () => {
263
353
  const { subscribeSSE: subscribeSSE2 } = await Promise.resolve().then(() => (init_sse(), exports_sse));
264
354
  try {
265
- await subscribeSSE2("/trades/stream", (trade) => {
355
+ await subscribeSSE2("/v1/trades/stream", (trade) => {
266
356
  get().pushTrade(trade);
267
357
  });
268
- } catch {}
358
+ } catch (error) {
359
+ const msg = error instanceof Error ? error.message : "SSE trade stream failed";
360
+ get().addAlert({
361
+ id: crypto.randomUUID(),
362
+ type: "connection",
363
+ severity: "error",
364
+ message: msg,
365
+ timestamp: Date.now(),
366
+ acknowledged: false
367
+ });
368
+ get().handleConnectionFailure(msg);
369
+ }
269
370
  },
270
371
  streamLogs: async () => {
271
372
  const { subscribeSSE: subscribeSSE2 } = await Promise.resolve().then(() => (init_sse(), exports_sse));
272
373
  try {
273
- await subscribeSSE2("/logs/stream", (log) => {
374
+ await subscribeSSE2("/v1/logs/stream", (log) => {
274
375
  get().pushLog(log);
275
376
  });
276
- } catch {}
377
+ } catch (error) {
378
+ const msg = error instanceof Error ? error.message : "SSE log stream failed";
379
+ get().addAlert({
380
+ id: crypto.randomUUID(),
381
+ type: "connection",
382
+ severity: "error",
383
+ message: msg,
384
+ timestamp: Date.now(),
385
+ acknowledged: false
386
+ });
387
+ get().handleConnectionFailure(msg);
388
+ }
277
389
  },
278
390
  addAlert: (alert) => set((state) => {
279
391
  state.alerts = ringPush(state.alerts, alert, MAX_ALERTS);
@@ -286,6 +398,7 @@ var useServiceStore = create()(immer((set, get) => ({
286
398
  if (status === "connected") {
287
399
  state.retryCount = 0;
288
400
  state.lastError = null;
401
+ state.lastErrorDetails = null;
289
402
  state.reconnectDelay = 0;
290
403
  state.disconnectedAt = null;
291
404
  }
@@ -315,11 +428,10 @@ var useServiceStore = create()(immer((set, get) => ({
315
428
  state.lastSuccessfulFetch = Date.now();
316
429
  state.retryCount = 0;
317
430
  state.lastError = null;
431
+ state.lastErrorDetails = null;
318
432
  state.reconnectDelay = 0;
319
433
  state.disconnectedAt = null;
320
- if (state.connectionStatus === "reconnecting" || state.connectionStatus === "polling") {
321
- state.connectionStatus = "connected";
322
- }
434
+ state.connectionStatus = "connected";
323
435
  }),
324
436
  handleConnectionFailure: (errorMessage) => set((state) => {
325
437
  state.lastError = errorMessage;
@@ -342,6 +454,7 @@ var useServiceStore = create()(immer((set, get) => ({
342
454
  resetRetries: () => set((state) => {
343
455
  state.retryCount = 0;
344
456
  state.lastError = null;
457
+ state.lastErrorDetails = null;
345
458
  state.reconnectDelay = 0;
346
459
  state.disconnectedAt = null;
347
460
  }),
@@ -350,8 +463,30 @@ var useServiceStore = create()(immer((set, get) => ({
350
463
  state.connectionStatus = "polling";
351
464
  state.retryCount = 0;
352
465
  state.lastError = null;
466
+ state.lastErrorDetails = null;
353
467
  state.reconnectDelay = 0;
354
468
  }
469
+ }),
470
+ setLastErrorDetails: (details) => set((state) => {
471
+ state.lastErrorDetails = details;
472
+ state.lastError = details === null ? null : summarizeCliError(details);
473
+ }),
474
+ clearError: () => set((state) => {
475
+ state.lastError = null;
476
+ state.lastErrorDetails = null;
477
+ }),
478
+ addCliErrorAlert: (details) => set((state) => {
479
+ state.lastErrorDetails = details;
480
+ state.lastError = summarizeCliError(details);
481
+ const summary = summarizeCliError(details);
482
+ state.alerts = ringPush(state.alerts, {
483
+ id: crypto.randomUUID(),
484
+ type: "connection",
485
+ severity: "error",
486
+ message: `CLI failure: ${summary}`,
487
+ timestamp: Date.now(),
488
+ acknowledged: false
489
+ }, MAX_ALERTS);
355
490
  })
356
491
  })));
357
492
  export {
@@ -0,0 +1,132 @@
1
+ export interface MockKVNamespace<T = unknown> {
2
+ get: (key: string) => Promise<T | null>;
3
+ put: (key: string, value: string | ReadableStream, options?: unknown) => Promise<void>;
4
+ delete: (key: string) => Promise<void>;
5
+ list: (options?: {
6
+ prefix?: string;
7
+ limit?: number;
8
+ }) => Promise<{
9
+ keys: {
10
+ name: string;
11
+ }[];
12
+ }>;
13
+ }
14
+ export declare function createMockKV<T = unknown>(overrides?: Partial<MockKVNamespace<T>>): MockKVNamespace<T>;
15
+ export interface MockR2Bucket {
16
+ put: (key: string, value: ReadableStream | ArrayBuffer, options?: unknown) => Promise<{
17
+ key: string;
18
+ }>;
19
+ get: (key: string) => Promise<{
20
+ body: ReadableStream;
21
+ key: string;
22
+ size: number;
23
+ } | null>;
24
+ delete: (key: string) => Promise<void>;
25
+ list: (options?: {
26
+ prefix?: string;
27
+ limit?: number;
28
+ }) => Promise<{
29
+ objects: {
30
+ key: string;
31
+ }[];
32
+ }>;
33
+ }
34
+ export declare function createMockR2(overrides?: Partial<MockR2Bucket>): MockR2Bucket;
35
+ export interface MockD1PreparedStatement {
36
+ bind: (...params: unknown[]) => MockD1PreparedStatement;
37
+ run: () => Promise<{
38
+ success: boolean;
39
+ results?: unknown[];
40
+ error?: string;
41
+ meta?: unknown;
42
+ }>;
43
+ all: () => Promise<{
44
+ success: boolean;
45
+ results?: unknown[];
46
+ error?: string;
47
+ }>;
48
+ first: <T = unknown>() => Promise<T | null>;
49
+ }
50
+ export interface MockD1Database {
51
+ prepare: (sql: string) => MockD1PreparedStatement;
52
+ dump: () => Promise<ArrayBuffer>;
53
+ batch: (statements: unknown[]) => Promise<{
54
+ success: boolean;
55
+ results?: unknown[];
56
+ error?: string;
57
+ }[]>;
58
+ exec: (sql: string) => Promise<{
59
+ success: boolean;
60
+ error?: string;
61
+ }>;
62
+ }
63
+ export declare function createMockD1(overrides?: Partial<MockD1Database>): MockD1Database;
64
+ export interface MockFetcher {
65
+ fetch: (request: Request | string, init?: RequestInit) => Promise<Response>;
66
+ }
67
+ export declare function createMockFetcher(response?: Response): MockFetcher;
68
+ export interface MockAnalyticsEngine {
69
+ writeDataPoint: (data: {
70
+ blobs?: string[];
71
+ doubles?: number[];
72
+ indexes?: string[];
73
+ }) => void;
74
+ }
75
+ export declare function createMockAnalyticsEngine(): MockAnalyticsEngine;
76
+ export interface MockAnalyticsEngineDataset {
77
+ writeDataPoint: (data: {
78
+ blobs?: string[];
79
+ doubles?: number[];
80
+ indexes?: string[];
81
+ }) => void;
82
+ }
83
+ export declare function createMockAnalyticsEngineDataset(): MockAnalyticsEngineDataset;
84
+ export interface MockQueue {
85
+ send: (body: unknown, options?: {
86
+ delay?: number;
87
+ }) => Promise<void>;
88
+ sendBatch: (messages: {
89
+ body: unknown;
90
+ }[]) => Promise<void>;
91
+ }
92
+ export declare function createMockQueue(): MockQueue;
93
+ export interface MockVectorizeIndex {
94
+ query: (vector: number[], options?: {
95
+ topK?: number;
96
+ }) => Promise<{
97
+ matches: {
98
+ id: string;
99
+ score: number;
100
+ }[];
101
+ }>;
102
+ upsert: (vectors: {
103
+ id: string;
104
+ values: number[];
105
+ }[]) => Promise<void>;
106
+ deleteByIds: (ids: string[]) => Promise<void>;
107
+ describe: () => Promise<{
108
+ dimension: number;
109
+ totalVectors?: number;
110
+ }>;
111
+ }
112
+ export declare function createMockVectorizeIndex(overrides?: Partial<MockVectorizeIndex>): MockVectorizeIndex;
113
+ export interface MockAi {
114
+ run: (model: string, input: unknown) => Promise<unknown>;
115
+ }
116
+ export declare function createMockAi(overrides?: Partial<MockAi>): MockAi;
117
+ export interface MockExecutionContext {
118
+ waitUntil: (promise: Promise<unknown>) => void;
119
+ passThroughOnException: () => void;
120
+ }
121
+ export declare function createMockExecutionContext(overrides?: Partial<MockExecutionContext>): MockExecutionContext;
122
+ export interface MockSecretsStore {
123
+ get: (key: string) => Promise<string | null>;
124
+ put: (key: string, value: string) => Promise<void>;
125
+ delete: (key: string) => Promise<void>;
126
+ }
127
+ export declare function createMockSecretsStore(overrides?: Partial<MockSecretsStore>): MockSecretsStore;
128
+ export interface ServiceBinding {
129
+ fetch: (request: Request | string, init?: RequestInit) => Promise<Response>;
130
+ }
131
+ export declare function createMockEnv<T extends Record<string, unknown>>(overrides: T): T;
132
+ //# sourceMappingURL=test-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
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/test-utils.ts
19
+ function createMockKV(overrides) {
20
+ return {
21
+ get: async (_key) => null,
22
+ put: async (_key, _value, _options) => {},
23
+ delete: async (_key) => {},
24
+ list: async (_options) => ({
25
+ keys: []
26
+ }),
27
+ ...overrides
28
+ };
29
+ }
30
+ function createMockR2(overrides) {
31
+ return {
32
+ put: async (key, _value, _options) => ({
33
+ key
34
+ }),
35
+ get: async (_key) => null,
36
+ delete: async (_key) => {},
37
+ list: async (_options) => ({
38
+ objects: []
39
+ }),
40
+ ...overrides
41
+ };
42
+ }
43
+ function createMockPreparedStatement() {
44
+ return {
45
+ bind: (..._params) => createMockPreparedStatement(),
46
+ run: async () => ({ success: true }),
47
+ all: async () => ({ success: true, results: [] }),
48
+ first: async () => null
49
+ };
50
+ }
51
+ function createMockD1(overrides) {
52
+ return {
53
+ prepare: (_sql) => createMockPreparedStatement(),
54
+ dump: async () => new ArrayBuffer(0),
55
+ batch: async (_statements) => [],
56
+ exec: async (_sql) => ({ success: true }),
57
+ ...overrides
58
+ };
59
+ }
60
+ function createMockFetcher(response) {
61
+ const defaultResponse = response ?? new Response("OK", { status: 200 });
62
+ return {
63
+ fetch: async (_request, _init) => defaultResponse
64
+ };
65
+ }
66
+ function createMockAnalyticsEngine() {
67
+ return {
68
+ writeDataPoint: (_data) => {}
69
+ };
70
+ }
71
+ function createMockAnalyticsEngineDataset() {
72
+ return createMockAnalyticsEngine();
73
+ }
74
+ function createMockQueue() {
75
+ return {
76
+ send: async (_body, _options) => {},
77
+ sendBatch: async (_messages) => {}
78
+ };
79
+ }
80
+ function createMockVectorizeIndex(overrides) {
81
+ return {
82
+ query: async (_vector, _options) => ({
83
+ matches: []
84
+ }),
85
+ upsert: async (_vectors) => {},
86
+ deleteByIds: async (_ids) => {},
87
+ describe: async () => ({ dimension: 384, totalVectors: 0 }),
88
+ ...overrides
89
+ };
90
+ }
91
+ function createMockAi(overrides) {
92
+ return {
93
+ run: async (_model, _input) => ({}),
94
+ ...overrides
95
+ };
96
+ }
97
+ function createMockExecutionContext(overrides) {
98
+ return {
99
+ waitUntil: (_promise) => {},
100
+ passThroughOnException: () => {},
101
+ ...overrides
102
+ };
103
+ }
104
+ function createMockSecretsStore(overrides) {
105
+ return {
106
+ get: async (_key) => null,
107
+ put: async (_key, _value) => {},
108
+ delete: async (_key) => {},
109
+ ...overrides
110
+ };
111
+ }
112
+ function createMockEnv(overrides) {
113
+ return overrides;
114
+ }
115
+ export {
116
+ createMockVectorizeIndex,
117
+ createMockSecretsStore,
118
+ createMockR2,
119
+ createMockQueue,
120
+ createMockKV,
121
+ createMockFetcher,
122
+ createMockExecutionContext,
123
+ createMockEnv,
124
+ createMockD1,
125
+ createMockAnalyticsEngineDataset,
126
+ createMockAnalyticsEngine,
127
+ createMockAi
128
+ };
@@ -3,20 +3,30 @@
3
3
  * Compatible with Cloudflare Workers edge runtime
4
4
  */
5
5
  export type RouteParams = Record<string, string>;
6
- export type Handler<TEnv = Record<string, unknown>> = (request: Request, env: TEnv, ctx: ExecutionContext, params?: RouteParams) => Promise<Response | void>;
7
- export interface RouteDefinition<TEnv = Record<string, unknown>> {
6
+ /**
7
+ * Handler type for route handlers.
8
+ * TEnv is the environment type with bindings.
9
+ */
10
+ export type Handler<TEnv = unknown> = (request: Request, env: TEnv, ctx: ExecutionContext, params?: RouteParams) => Promise<Response | void>;
11
+ /**
12
+ * Middleware handler type - uses any to allow compatibility with
13
+ * stricter Env types that don't have index signatures.
14
+ * This enables InternalAuthEnv middleware to be used with any Env.
15
+ */
16
+ export type MiddlewareHandler<TEnv = unknown> = (request: Request, env: TEnv, ctx: ExecutionContext) => Promise<Response | void>;
17
+ export interface RouteDefinition<TEnv = unknown> {
8
18
  path: string;
9
19
  method: string;
10
20
  handler: Handler<TEnv>;
11
- middleware?: Handler<TEnv>[];
21
+ middleware?: MiddlewareHandler<TEnv>[];
12
22
  params?: string[];
13
23
  regex?: RegExp;
14
24
  }
15
- export interface Router<TEnv = Record<string, unknown>> {
16
- get(path: string, handler: Handler<TEnv>, middleware?: Handler<TEnv>[]): void;
17
- post(path: string, handler: Handler<TEnv>, middleware?: Handler<TEnv>[]): void;
18
- put(path: string, handler: Handler<TEnv>, middleware?: Handler<TEnv>[]): void;
19
- delete(path: string, handler: Handler<TEnv>, middleware?: Handler<TEnv>[]): void;
25
+ export interface Router<TEnv = unknown> {
26
+ get(path: string, handler: Handler<TEnv>, middleware?: MiddlewareHandler<TEnv>[]): void;
27
+ post(path: string, handler: Handler<TEnv>, middleware?: MiddlewareHandler<TEnv>[]): void;
28
+ put(path: string, handler: Handler<TEnv>, middleware?: MiddlewareHandler<TEnv>[]): void;
29
+ delete(path: string, handler: Handler<TEnv>, middleware?: MiddlewareHandler<TEnv>[]): void;
20
30
  handle(request: Request, env: TEnv, ctx: ExecutionContext): Promise<Response>;
21
31
  }
22
32
  //# sourceMappingURL=router.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/types/router.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD,MAAM,MAAM,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CACpD,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,gBAAgB,EACrB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE9B,MAAM,WAAW,eAAe,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;IAC9E,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAC3B,IAAI,CAAC;IACR,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;IAC9E,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,GAC3B,IAAI,CAAC;IACR,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC/E"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/types/router.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD;;;GAGG;AACH,MAAM,MAAM,OAAO,CAAC,IAAI,GAAG,OAAO,IAAI,CACpC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,gBAAgB,EACrB,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE9B;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,CAAC,IAAI,GAAG,OAAO,IAAI,CAC9C,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE9B,MAAM,WAAW,eAAe,CAAC,IAAI,GAAG,OAAO;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,UAAU,CAAC,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,MAAM,CAAC,IAAI,GAAG,OAAO;IACpC,GAAG,CACD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,UAAU,CAAC,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,GACrC,IAAI,CAAC;IACR,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,UAAU,CAAC,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,GACrC,IAAI,CAAC;IACR,GAAG,CACD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,UAAU,CAAC,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,GACrC,IAAI,CAAC;IACR,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,UAAU,CAAC,EAAE,iBAAiB,CAAC,IAAI,CAAC,EAAE,GACrC,IAAI,CAAC;IACR,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC/E"}