@jango-blockchained/hoox-shared 1.0.9 → 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 (74) hide show
  1. package/README.md +17 -0
  2. package/dist/analytics.d.ts +23 -1
  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 -24
  9. package/dist/colors.d.ts.map +1 -1
  10. package/dist/colors.js +60 -19
  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 +2 -2
  15. package/dist/cron-handler.d.ts.map +1 -1
  16. package/dist/d1/index.js +1 -0
  17. package/dist/d1/repository.js +297 -0
  18. package/dist/d1/schemas.js +81 -0
  19. package/dist/exchanges/base-exchange-client.js +120 -0
  20. package/dist/exchanges/types.js +1 -0
  21. package/dist/index.d.ts +21 -11
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +580 -60
  24. package/dist/middleware/auth.d.ts +42 -6
  25. package/dist/middleware/auth.d.ts.map +1 -1
  26. package/dist/middleware/auth.js +151 -0
  27. package/dist/middleware/cors.d.ts +28 -2
  28. package/dist/middleware/cors.d.ts.map +1 -1
  29. package/dist/middleware/cors.js +77 -0
  30. package/dist/middleware/index.d.ts +2 -2
  31. package/dist/middleware/index.d.ts.map +1 -1
  32. package/dist/middleware/index.js +192 -107
  33. package/dist/middleware/logger.js +202 -0
  34. package/dist/middleware/rate-limit.d.ts.map +1 -1
  35. package/dist/middleware/rate-limit.js +181 -0
  36. package/dist/middleware/security-headers.js +58 -0
  37. package/dist/middleware/validate.js +56 -0
  38. package/dist/operator-transport.d.ts +61 -0
  39. package/dist/operator-transport.d.ts.map +1 -0
  40. package/dist/operator-transport.js +87 -0
  41. package/dist/path-utils.d.ts +59 -1
  42. package/dist/path-utils.d.ts.map +1 -1
  43. package/dist/path-utils.js +89 -2
  44. package/dist/queue-handler.d.ts +3 -3
  45. package/dist/queue-handler.d.ts.map +1 -1
  46. package/dist/router.d.ts +2 -2
  47. package/dist/router.d.ts.map +1 -1
  48. package/dist/schemas/index.js +7 -4
  49. package/dist/schemas/registry.js +387 -0
  50. package/dist/schemas/types.js +1 -0
  51. package/dist/schemas/validators.d.ts.map +1 -1
  52. package/dist/schemas/validators.js +290 -0
  53. package/dist/service-bindings.d.ts +65 -0
  54. package/dist/service-bindings.d.ts.map +1 -1
  55. package/dist/service-bindings.js +216 -1
  56. package/dist/session.d.ts.map +1 -1
  57. package/dist/session.js +97 -2
  58. package/dist/sse.d.ts +12 -3
  59. package/dist/sse.d.ts.map +1 -1
  60. package/dist/sse.js +70 -7
  61. package/dist/stores/config-store.d.ts.map +1 -1
  62. package/dist/stores/config-store.js +129 -6
  63. package/dist/stores/service-store.d.ts.map +1 -1
  64. package/dist/stores/service-store.js +96 -25
  65. package/dist/types.d.ts +66 -1
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/types.js +11 -0
  68. package/dist/wizard/engine.js +501 -0
  69. package/dist/wizard/index.js +2 -1
  70. package/dist/wizard/persistence.js +31 -0
  71. package/dist/wizard/presets.js +199 -0
  72. package/dist/wizard/provisioner.js +1 -0
  73. package/dist/wizard/types.js +1 -0
  74. package/package.json +38 -12
@@ -0,0 +1,290 @@
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/schemas/validators.ts
19
+ import { parse } from "jsonc-parser";
20
+ function validateWranglerJsonc(workerName, manifest, jsoncContent) {
21
+ const errors = [];
22
+ let parsed;
23
+ try {
24
+ parsed = parse(jsoncContent);
25
+ } catch {
26
+ errors.push({
27
+ worker: workerName,
28
+ severity: "error",
29
+ message: "Failed to parse wrangler.jsonc",
30
+ file: "wrangler.jsonc"
31
+ });
32
+ return errors;
33
+ }
34
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
35
+ errors.push({
36
+ worker: workerName,
37
+ severity: "error",
38
+ message: "Failed to parse wrangler.jsonc \u2014 result is not a valid object",
39
+ file: "wrangler.jsonc"
40
+ });
41
+ return errors;
42
+ }
43
+ const wrangler = parsed;
44
+ const declaredVars = wrangler.vars ?? {};
45
+ for (const [name, def] of Object.entries(manifest.vars)) {
46
+ if (!(name in declaredVars)) {
47
+ errors.push({
48
+ worker: workerName,
49
+ severity: "error",
50
+ message: `Missing var: ${name} (${def.description})`,
51
+ file: "wrangler.jsonc"
52
+ });
53
+ }
54
+ }
55
+ for (const [name, def] of Object.entries(manifest.vars)) {
56
+ if (def.type === "secret" && !name.endsWith("_BINDING") && !name.endsWith("_SECRET") && !name.startsWith("CLOUDFLARE_") && name !== "TELEGRAM_SECRET_TOKEN" && name !== "MAILGUN_API_KEY" && name !== "EMAIL_SCAN_SUBJECT" && name !== "DASHBOARD_USER" && name !== "DASHBOARD_PASS" && name !== "SESSION_SECRET" && name !== "AGENT_INTERNAL_KEY") {
57
+ errors.push({
58
+ worker: workerName,
59
+ severity: "warning",
60
+ message: `Secret var "${name}" does not end with _BINDING or _SECRET suffix`,
61
+ file: "wrangler.jsonc"
62
+ });
63
+ }
64
+ }
65
+ const declaredServices = wrangler.services ?? [];
66
+ for (const expected of manifest.services) {
67
+ const match = declaredServices.find((s) => s.binding === expected.binding && s.service === expected.service);
68
+ if (!match) {
69
+ const declared = declaredServices.find((s) => s.binding === expected.binding);
70
+ if (declared) {
71
+ errors.push({
72
+ worker: workerName,
73
+ severity: "error",
74
+ message: `Service "${expected.binding}" points to "${declared.service}" but manifest expects "${expected.service}"`,
75
+ file: "wrangler.jsonc"
76
+ });
77
+ } else {
78
+ errors.push({
79
+ worker: workerName,
80
+ severity: "error",
81
+ message: `Missing service binding: ${expected.binding} -> ${expected.service}`,
82
+ file: "wrangler.jsonc"
83
+ });
84
+ }
85
+ }
86
+ }
87
+ for (const declared of declaredServices) {
88
+ const expected = manifest.services.find((s) => s.binding === declared.binding);
89
+ if (!expected) {
90
+ errors.push({
91
+ worker: workerName,
92
+ severity: "warning",
93
+ message: `Unexpected service binding: ${declared.binding}`,
94
+ file: "wrangler.jsonc"
95
+ });
96
+ }
97
+ }
98
+ return errors;
99
+ }
100
+ function validateRootSecrets(workerName, manifest, rootJsoncContent) {
101
+ const errors = [];
102
+ let parsed;
103
+ try {
104
+ parsed = parse(rootJsoncContent);
105
+ } catch {
106
+ errors.push({
107
+ worker: workerName,
108
+ severity: "error",
109
+ message: "Failed to parse root wrangler.jsonc"
110
+ });
111
+ return errors;
112
+ }
113
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
114
+ errors.push({
115
+ worker: workerName,
116
+ severity: "error",
117
+ message: "Failed to parse root wrangler.jsonc \u2014 result is not a valid object"
118
+ });
119
+ return errors;
120
+ }
121
+ const rootWrangler = parsed;
122
+ const rootSecrets = rootWrangler.workers?.[workerName]?.secrets ?? [];
123
+ const expectedSecrets = Object.entries(manifest.vars).filter(([_, def]) => def.type === "secret").map(([name]) => name);
124
+ for (const expected of expectedSecrets) {
125
+ if (!rootSecrets.includes(expected)) {
126
+ errors.push({
127
+ worker: workerName,
128
+ severity: "error",
129
+ message: `Secret "${expected}" missing from root wrangler.jsonc workers.${workerName}.secrets`,
130
+ file: "wrangler.jsonc (root)"
131
+ });
132
+ }
133
+ }
134
+ return errors;
135
+ }
136
+ function validateDevVars(workerName, manifest, devVarsContent) {
137
+ const errors = [];
138
+ const vars = new Map;
139
+ for (const line of devVarsContent.split(`
140
+ `)) {
141
+ const trimmed = line.trim();
142
+ if (trimmed === "" || trimmed.startsWith("#"))
143
+ continue;
144
+ const eqIdx = trimmed.indexOf("=");
145
+ if (eqIdx < 1)
146
+ continue;
147
+ vars.set(trimmed.substring(0, eqIdx).trim(), trimmed.substring(eqIdx + 1).trim());
148
+ }
149
+ for (const [name, def] of Object.entries(manifest.vars)) {
150
+ if (def.type !== "secret")
151
+ continue;
152
+ if (!vars.has(name)) {
153
+ errors.push({
154
+ worker: workerName,
155
+ severity: "error",
156
+ message: `Missing "${name}" in .dev.vars`,
157
+ file: ".dev.vars"
158
+ });
159
+ }
160
+ }
161
+ return errors;
162
+ }
163
+ function generateWranglerJsonc(manifest) {
164
+ const parts = [];
165
+ parts.push(`{`);
166
+ parts.push(` "name": "${manifest.name}",`);
167
+ parts.push(` "main": "src/index.ts",`);
168
+ const varKeys = Object.keys(manifest.vars);
169
+ if (varKeys.length > 0) {
170
+ parts.push(` "vars": {`);
171
+ for (const [i, name] of varKeys.entries()) {
172
+ const def = manifest.vars[name];
173
+ const comma = i < varKeys.length - 1 ? "," : "";
174
+ const val = def.type === "secret" ? "__SECRET__" : JSON.stringify(def.default ?? "");
175
+ parts.push(` "${name}": ${val}${comma}`);
176
+ }
177
+ parts.push(` },`);
178
+ }
179
+ if (manifest.services.length > 0) {
180
+ parts.push(` "services": [`);
181
+ for (const [i, svc] of manifest.services.entries()) {
182
+ const comma = i < manifest.services.length - 1 ? "," : "";
183
+ parts.push(` { "binding": "${svc.binding}", "service": "${svc.service}" }${comma}`);
184
+ }
185
+ parts.push(` ],`);
186
+ }
187
+ const infra = manifest.infrastructure;
188
+ if (infra.kv && infra.kv.length > 0) {
189
+ parts.push(` "kv_namespaces": [`);
190
+ for (const [i, binding] of infra.kv.entries()) {
191
+ const comma = i < infra.kv.length - 1 ? "," : "";
192
+ parts.push(` { "binding": "${binding.binding}", "id": "" }${comma}`);
193
+ }
194
+ parts.push(` ],`);
195
+ }
196
+ if (infra.d1 && infra.d1.length > 0) {
197
+ parts.push(` "d1_databases": [`);
198
+ for (const [i, binding] of infra.d1.entries()) {
199
+ const comma = i < infra.d1.length - 1 ? "," : "";
200
+ parts.push(` { "binding": "${binding.binding}", "database_name": "${binding.database}", "database_id": "" }${comma}`);
201
+ }
202
+ parts.push(` ],`);
203
+ }
204
+ if (infra.r2 && infra.r2.length > 0) {
205
+ parts.push(` "r2_buckets": [`);
206
+ for (const [i, binding] of infra.r2.entries()) {
207
+ const comma = i < infra.r2.length - 1 ? "," : "";
208
+ parts.push(` { "binding": "${binding.binding}", "bucket_name": "${binding.bucket}" }${comma}`);
209
+ }
210
+ parts.push(` ],`);
211
+ }
212
+ if (infra.ai) {
213
+ parts.push(` "ai": { "binding": "AI" },`);
214
+ }
215
+ if (infra.analyticsEngine) {
216
+ parts.push(` "analytics_engine_datasets": [{ "binding": "ANALYTICS_ENGINE", "dataset": "hoox-analytics" }],`);
217
+ }
218
+ if (infra.vectorize && infra.vectorize.length > 0) {
219
+ parts.push(` "vectorize": [`);
220
+ for (const [i, binding] of infra.vectorize.entries()) {
221
+ const comma = i < infra.vectorize.length - 1 ? "," : "";
222
+ parts.push(` { "binding": "${binding.binding}", "index_name": "${binding.index}" }${comma}`);
223
+ }
224
+ parts.push(` ],`);
225
+ }
226
+ if (infra.queues) {
227
+ if (infra.queues.producer && infra.queues.producer.length > 0) {
228
+ parts.push(` "queues": { "producers": [`);
229
+ for (const [i, q] of infra.queues.producer.entries()) {
230
+ const comma = i < infra.queues.producer.length - 1 ? "," : "";
231
+ parts.push(` { "queue": "${q}", "binding": "" }${comma}`);
232
+ }
233
+ parts.push(` ] },`);
234
+ }
235
+ if (infra.queues.consumer && infra.queues.consumer.length > 0) {
236
+ parts.push(` "queues": { "consumers": [`);
237
+ for (const [i, q] of infra.queues.consumer.entries()) {
238
+ const comma = i < infra.queues.consumer.length - 1 ? "," : "";
239
+ parts.push(` { "queue": "${q}" }${comma}`);
240
+ }
241
+ parts.push(` ] },`);
242
+ }
243
+ }
244
+ if (infra.durableObjects && infra.durableObjects.length > 0) {
245
+ parts.push(` "durable_objects": { "bindings": [`);
246
+ for (const [i, doBinding] of infra.durableObjects.entries()) {
247
+ const comma = i < infra.durableObjects.length - 1 ? "," : "";
248
+ parts.push(` { "name": "${doBinding.name}", "class_name": "${doBinding.className}" }${comma}`);
249
+ }
250
+ parts.push(` ] },`);
251
+ }
252
+ parts.push(`}`);
253
+ return parts.join(`
254
+ `) + `
255
+ `;
256
+ }
257
+ function generateDevVars(manifest) {
258
+ const lines = [];
259
+ lines.push(`# ${manifest.name} \u2014 Environment Variables`);
260
+ lines.push(`# Auto-generated from worker manifest schema`);
261
+ lines.push(``);
262
+ for (const [name, def] of Object.entries(manifest.vars)) {
263
+ if (def.type === "secret") {
264
+ lines.push(`${name}=placeholder_${name.toLowerCase()}`);
265
+ }
266
+ }
267
+ lines.push(``);
268
+ return lines.join(`
269
+ `);
270
+ }
271
+ function validateAll(workerName, manifest, files) {
272
+ const errors = [
273
+ ...validateWranglerJsonc(workerName, manifest, files.wranglerJsonc),
274
+ ...validateRootSecrets(workerName, manifest, files.rootWranglerJsonc),
275
+ ...validateDevVars(workerName, manifest, files.devVars)
276
+ ];
277
+ return {
278
+ worker: workerName,
279
+ passed: errors.filter((e) => e.severity === "error").length === 0,
280
+ errors
281
+ };
282
+ }
283
+ export {
284
+ validateWranglerJsonc,
285
+ validateRootSecrets,
286
+ validateDevVars,
287
+ validateAll,
288
+ generateWranglerJsonc,
289
+ generateDevVars
290
+ };
@@ -1,6 +1,71 @@
1
+ import type { InternalAuthKeyName } from "./middleware/auth";
1
2
  export interface ServiceBinding {
2
3
  fetch(request: Request | string, init?: RequestInit): Promise<Response>;
3
4
  }
5
+ /** Env binding names for scoped internal auth keys. */
6
+ export declare const InternalAuthKeyFields: {
7
+ readonly DEFAULT: "INTERNAL_KEY_BINDING";
8
+ readonly D1_READ: "D1_READ_KEY_BINDING";
9
+ readonly D1_WRITE: "D1_WRITE_KEY_BINDING";
10
+ readonly TRADE_EXECUTE: "TRADE_EXECUTE_KEY_BINDING";
11
+ readonly TRADE_READ: "TRADE_READ_KEY_BINDING";
12
+ readonly TELEGRAM_ALERT: "TELEGRAM_INTERNAL_KEY_BINDING";
13
+ readonly WALLET_EXECUTE: "WALLET_EXECUTE_KEY_BINDING";
14
+ readonly AGENT: "AGENT_INTERNAL_KEY";
15
+ /** Dashboard Pages secret aliases (legacy naming). */
16
+ readonly D1_INTERNAL_ALIAS: "D1_INTERNAL_KEY";
17
+ readonly TRADE_INTERNAL_ALIAS: "TRADE_INTERNAL_KEY";
18
+ readonly TELEGRAM_INTERNAL_ALIAS: "TELEGRAM_INTERNAL_KEY";
19
+ };
20
+ /** d1-worker read routes: prefer read-only key, fall back to legacy full key. */
21
+ export declare const D1_READ_AUTH_KEY_FIELDS: readonly ["D1_READ_KEY_BINDING", "INTERNAL_KEY_BINDING"];
22
+ /** d1-worker write/RPC routes: prefer write key, fall back to legacy full key. */
23
+ export declare const D1_WRITE_AUTH_KEY_FIELDS: readonly ["D1_WRITE_KEY_BINDING", "INTERNAL_KEY_BINDING"];
24
+ /** trade-worker execute routes (/webhook, /process, POST /api/signals). */
25
+ export declare const TRADE_EXECUTE_AUTH_KEY_FIELDS: readonly ["TRADE_EXECUTE_KEY_BINDING", "INTERNAL_KEY_BINDING", "AGENT_INTERNAL_KEY"];
26
+ /** trade-worker read routes (GET /api/signals, GET /report). */
27
+ export declare const TRADE_READ_AUTH_KEY_FIELDS: readonly ["TRADE_READ_KEY_BINDING", "INTERNAL_KEY_BINDING"];
28
+ /** telegram-worker /alert notification endpoint. */
29
+ export declare const TELEGRAM_ALERT_AUTH_KEY_FIELDS: readonly ["TELEGRAM_INTERNAL_KEY_BINDING", "INTERNAL_KEY_BINDING"];
30
+ /** web3-wallet-worker privileged routes. */
31
+ export declare const WALLET_EXECUTE_AUTH_KEY_FIELDS: readonly ["WALLET_EXECUTE_KEY_BINDING", "INTERNAL_KEY_BINDING"];
32
+ /** Dashboard → d1-worker read calls (includes Pages secret aliases). */
33
+ export declare const DASHBOARD_D1_READ_AUTH_KEY_FIELDS: readonly ["D1_READ_KEY_BINDING", "D1_INTERNAL_KEY", "INTERNAL_KEY_BINDING"];
34
+ /** Dashboard → trade-worker execute calls. */
35
+ export declare const DASHBOARD_TRADE_EXECUTE_AUTH_KEY_FIELDS: readonly ["TRADE_EXECUTE_KEY_BINDING", "TRADE_INTERNAL_KEY", "INTERNAL_KEY_BINDING"];
36
+ /** Dashboard → telegram-worker /alert calls. */
37
+ export declare const DASHBOARD_TELEGRAM_ALERT_AUTH_KEY_FIELDS: readonly ["TELEGRAM_INTERNAL_KEY_BINDING", "TELEGRAM_INTERNAL_KEY", "INTERNAL_KEY_BINDING"];
38
+ /** First configured key from an ordered fallback list. */
39
+ export declare function resolveInternalAuthKey(env: object, keyFields: InternalAuthKeyName): string | undefined;
40
+ export interface AuthenticatedServiceEnv {
41
+ INTERNAL_KEY_BINDING?: string;
42
+ D1_READ_KEY_BINDING?: string;
43
+ D1_WRITE_KEY_BINDING?: string;
44
+ TRADE_EXECUTE_KEY_BINDING?: string;
45
+ TRADE_READ_KEY_BINDING?: string;
46
+ TELEGRAM_INTERNAL_KEY_BINDING?: string;
47
+ WALLET_EXECUTE_KEY_BINDING?: string;
48
+ AGENT_INTERNAL_KEY?: string;
49
+ D1_INTERNAL_KEY?: string;
50
+ TRADE_INTERNAL_KEY?: string;
51
+ TELEGRAM_INTERNAL_KEY?: string;
52
+ }
53
+ export declare class ServiceAuthError extends Error {
54
+ constructor(message: string);
55
+ }
56
+ /**
57
+ * serviceFetch with fail-closed internal auth.
58
+ * Injects X-Internal-Auth-Key from env.INTERNAL_KEY_BINDING.
59
+ */
60
+ export declare function authenticatedServiceFetch<E extends AuthenticatedServiceEnv>(binding: ServiceBinding, env: E, path: string, body?: unknown, options?: {
61
+ method?: string;
62
+ headers?: Record<string, string>;
63
+ timeout?: number;
64
+ /** Override env key (e.g. TELEGRAM_INTERNAL_KEY_BINDING, AGENT_INTERNAL_KEY) */
65
+ internalKey?: string;
66
+ /** Ordered env fields to try when internalKey is not set */
67
+ internalKeyFields?: InternalAuthKeyName;
68
+ }): Promise<Response>;
4
69
  export declare function serviceFetch(binding: ServiceBinding, path: string, body?: unknown, options?: {
5
70
  method?: string;
6
71
  headers?: Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"service-bindings.d.ts","sourceRoot":"","sources":["../src/service-bindings.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzE;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,QAAQ,CAAC,CAWnB"}
1
+ {"version":3,"file":"service-bindings.d.ts","sourceRoot":"","sources":["../src/service-bindings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzE;AAED,uDAAuD;AACvD,eAAO,MAAM,qBAAqB;;;;;;;;;IAShC,sDAAsD;;;;CAI9C,CAAC;AAEX,iFAAiF;AACjF,eAAO,MAAM,uBAAuB,0DAG1B,CAAC;AAEX,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,2DAG3B,CAAC;AAEX,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,sFAIhC,CAAC;AAEX,gEAAgE;AAChE,eAAO,MAAM,0BAA0B,6DAG7B,CAAC;AAEX,oDAAoD;AACpD,eAAO,MAAM,8BAA8B,oEAGjC,CAAC;AAEX,4CAA4C;AAC5C,eAAO,MAAM,8BAA8B,iEAGjC,CAAC;AAEX,wEAAwE;AACxE,eAAO,MAAM,iCAAiC,6EAIpC,CAAC;AAEX,8CAA8C;AAC9C,eAAO,MAAM,uCAAuC,sFAI1C,CAAC;AAEX,gDAAgD;AAChD,eAAO,MAAM,wCAAwC,6FAI3C,CAAC;AAEX,0DAA0D;AAC1D,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,mBAAmB,GAC7B,MAAM,GAAG,SAAS,CAEpB;AAED,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS,uBAAuB,EACzE,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;CACzC,GACA,OAAO,CAAC,QAAQ,CAAC,CAsBnB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,QAAQ,CAAC,CAWnB"}
@@ -15,7 +15,209 @@ var __export = (target, all) => {
15
15
  };
16
16
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
17
 
18
+ // src/middleware/auth.ts
19
+ function timingSafeEqual(a, b) {
20
+ const encoder = new TextEncoder;
21
+ const aBuf = encoder.encode(a);
22
+ const bBuf = encoder.encode(b);
23
+ const len = Math.max(aBuf.length, bBuf.length);
24
+ let result = aBuf.length === bBuf.length ? 0 : 1;
25
+ for (let i = 0;i < len; i++) {
26
+ const av = i < aBuf.length ? aBuf[i] : 0;
27
+ const bv = i < bBuf.length ? bBuf[i] : 0;
28
+ result |= av ^ bv;
29
+ }
30
+ return result === 0;
31
+ }
32
+ function resolveOperatorApiKey(env) {
33
+ const preferred = env.OPERATOR_API_KEY;
34
+ if (typeof preferred === "string" && preferred.length > 0) {
35
+ return preferred;
36
+ }
37
+ const legacy = env.INTERNAL_API_KEY;
38
+ if (typeof legacy === "string" && legacy.length > 0) {
39
+ return legacy;
40
+ }
41
+ return;
42
+ }
43
+ async function requireAuth(request, env) {
44
+ return requireOperatorAuth(request, env);
45
+ }
46
+ async function requireOperatorAuth(request, env) {
47
+ const apiKey = resolveOperatorApiKey(env);
48
+ if (!apiKey) {
49
+ return new Response(JSON.stringify({
50
+ error: "Operator API key not configured",
51
+ hint: "Set OPERATOR_API_KEY (preferred) or INTERNAL_API_KEY on the Worker"
52
+ }), { status: 401, headers: { "Content-Type": "application/json" } });
53
+ }
54
+ const authHeader = request.headers.get("Authorization");
55
+ const expectedHeader = `Bearer ${apiKey}`;
56
+ if (!authHeader || !timingSafeEqual(authHeader, expectedHeader)) {
57
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
58
+ status: 401,
59
+ headers: { "Content-Type": "application/json" }
60
+ });
61
+ }
62
+ return null;
63
+ }
64
+ function createOperatorAuthMiddleware() {
65
+ return async (request, env, _ctx) => {
66
+ const denied = await requireOperatorAuth(request, env);
67
+ if (denied)
68
+ return denied;
69
+ return;
70
+ };
71
+ }
72
+ function normalizeKeyNames(keyName) {
73
+ if (typeof keyName === "string") {
74
+ return [keyName];
75
+ }
76
+ return [...keyName];
77
+ }
78
+ function collectInternalAuthKeys(env, keyNames) {
79
+ const keys = [];
80
+ for (const name of normalizeKeyNames(keyNames)) {
81
+ const value = env[name];
82
+ if (typeof value === "string" && value.length > 0) {
83
+ keys.push(value);
84
+ }
85
+ }
86
+ return keys;
87
+ }
88
+ function matchesAnyInternalAuthKey(providedKey, expectedKeys) {
89
+ for (const expected of expectedKeys) {
90
+ if (timingSafeEqual(providedKey, expected)) {
91
+ return true;
92
+ }
93
+ }
94
+ return false;
95
+ }
96
+ function internalAuthNotConfiguredResponse(keyNames) {
97
+ const label = normalizeKeyNames(keyNames).join(" | ");
98
+ return new Response(JSON.stringify({
99
+ success: false,
100
+ error: `Internal auth key(s) not configured: ${label}`
101
+ }), { status: 401, headers: { "Content-Type": "application/json" } });
102
+ }
103
+ function requireInternalAuth(request, env, keyName = "INTERNAL_KEY_BINDING") {
104
+ const expectedKeys = collectInternalAuthKeys(env, keyName);
105
+ if (expectedKeys.length === 0) {
106
+ return internalAuthNotConfiguredResponse(keyName);
107
+ }
108
+ const providedKey = request.headers.get("X-Internal-Auth-Key");
109
+ if (!providedKey || !matchesAnyInternalAuthKey(providedKey, expectedKeys)) {
110
+ return new Response(JSON.stringify({ success: false, error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" } });
111
+ }
112
+ return null;
113
+ }
114
+ function createInternalAuthMiddleware(keyName = "INTERNAL_KEY_BINDING") {
115
+ return async (request, env, _ctx) => {
116
+ const expectedKeys = collectInternalAuthKeys(env, keyName);
117
+ if (expectedKeys.length === 0) {
118
+ return internalAuthNotConfiguredResponse(keyName);
119
+ }
120
+ const providedKey = request.headers.get("X-Internal-Auth-Key");
121
+ if (!providedKey || !matchesAnyInternalAuthKey(providedKey, expectedKeys)) {
122
+ return new Response(JSON.stringify({ success: false, error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" } });
123
+ }
124
+ return;
125
+ };
126
+ }
127
+ function checkInternalAuth(request, env, keyName = "INTERNAL_KEY_BINDING") {
128
+ const expectedKeys = collectInternalAuthKeys(env, keyName);
129
+ if (expectedKeys.length === 0) {
130
+ return {
131
+ authorized: false,
132
+ error: `${normalizeKeyNames(keyName).join(" | ")} not configured`
133
+ };
134
+ }
135
+ const providedKey = request.headers.get("X-Internal-Auth-Key");
136
+ if (!providedKey || !matchesAnyInternalAuthKey(providedKey, expectedKeys)) {
137
+ return { authorized: false, error: "Unauthorized" };
138
+ }
139
+ return { authorized: true };
140
+ }
141
+
18
142
  // src/service-bindings.ts
143
+ var InternalAuthKeyFields = {
144
+ DEFAULT: "INTERNAL_KEY_BINDING",
145
+ D1_READ: "D1_READ_KEY_BINDING",
146
+ D1_WRITE: "D1_WRITE_KEY_BINDING",
147
+ TRADE_EXECUTE: "TRADE_EXECUTE_KEY_BINDING",
148
+ TRADE_READ: "TRADE_READ_KEY_BINDING",
149
+ TELEGRAM_ALERT: "TELEGRAM_INTERNAL_KEY_BINDING",
150
+ WALLET_EXECUTE: "WALLET_EXECUTE_KEY_BINDING",
151
+ AGENT: "AGENT_INTERNAL_KEY",
152
+ D1_INTERNAL_ALIAS: "D1_INTERNAL_KEY",
153
+ TRADE_INTERNAL_ALIAS: "TRADE_INTERNAL_KEY",
154
+ TELEGRAM_INTERNAL_ALIAS: "TELEGRAM_INTERNAL_KEY"
155
+ };
156
+ var D1_READ_AUTH_KEY_FIELDS = [
157
+ InternalAuthKeyFields.D1_READ,
158
+ InternalAuthKeyFields.DEFAULT
159
+ ];
160
+ var D1_WRITE_AUTH_KEY_FIELDS = [
161
+ InternalAuthKeyFields.D1_WRITE,
162
+ InternalAuthKeyFields.DEFAULT
163
+ ];
164
+ var TRADE_EXECUTE_AUTH_KEY_FIELDS = [
165
+ InternalAuthKeyFields.TRADE_EXECUTE,
166
+ InternalAuthKeyFields.DEFAULT,
167
+ InternalAuthKeyFields.AGENT
168
+ ];
169
+ var TRADE_READ_AUTH_KEY_FIELDS = [
170
+ InternalAuthKeyFields.TRADE_READ,
171
+ InternalAuthKeyFields.DEFAULT
172
+ ];
173
+ var TELEGRAM_ALERT_AUTH_KEY_FIELDS = [
174
+ InternalAuthKeyFields.TELEGRAM_ALERT,
175
+ InternalAuthKeyFields.DEFAULT
176
+ ];
177
+ var WALLET_EXECUTE_AUTH_KEY_FIELDS = [
178
+ InternalAuthKeyFields.WALLET_EXECUTE,
179
+ InternalAuthKeyFields.DEFAULT
180
+ ];
181
+ var DASHBOARD_D1_READ_AUTH_KEY_FIELDS = [
182
+ InternalAuthKeyFields.D1_READ,
183
+ InternalAuthKeyFields.D1_INTERNAL_ALIAS,
184
+ InternalAuthKeyFields.DEFAULT
185
+ ];
186
+ var DASHBOARD_TRADE_EXECUTE_AUTH_KEY_FIELDS = [
187
+ InternalAuthKeyFields.TRADE_EXECUTE,
188
+ InternalAuthKeyFields.TRADE_INTERNAL_ALIAS,
189
+ InternalAuthKeyFields.DEFAULT
190
+ ];
191
+ var DASHBOARD_TELEGRAM_ALERT_AUTH_KEY_FIELDS = [
192
+ InternalAuthKeyFields.TELEGRAM_ALERT,
193
+ InternalAuthKeyFields.TELEGRAM_INTERNAL_ALIAS,
194
+ InternalAuthKeyFields.DEFAULT
195
+ ];
196
+ function resolveInternalAuthKey(env, keyFields) {
197
+ return collectInternalAuthKeys(env, keyFields)[0];
198
+ }
199
+
200
+ class ServiceAuthError extends Error {
201
+ constructor(message) {
202
+ super(message);
203
+ this.name = "ServiceAuthError";
204
+ }
205
+ }
206
+ function authenticatedServiceFetch(binding, env, path, body, options) {
207
+ const key = options?.internalKey ?? (options?.internalKeyFields ? resolveInternalAuthKey(env, options.internalKeyFields) : env.INTERNAL_KEY_BINDING);
208
+ if (!key) {
209
+ const label = options?.internalKeyFields ? Array.isArray(options.internalKeyFields) ? options.internalKeyFields.join(" | ") : options.internalKeyFields : "INTERNAL_KEY_BINDING";
210
+ return Promise.reject(new ServiceAuthError(`${label} not configured`));
211
+ }
212
+ return serviceFetch(binding, path, body, {
213
+ method: options?.method,
214
+ timeout: options?.timeout,
215
+ headers: {
216
+ ...options?.headers,
217
+ "X-Internal-Auth-Key": key
218
+ }
219
+ });
220
+ }
19
221
  function serviceFetch(binding, path, body, options) {
20
222
  const timeout = options?.timeout ?? 30000;
21
223
  return binding.fetch(`http://internal${path}`, {
@@ -29,5 +231,18 @@ function serviceFetch(binding, path, body, options) {
29
231
  });
30
232
  }
31
233
  export {
32
- serviceFetch
234
+ serviceFetch,
235
+ resolveInternalAuthKey,
236
+ authenticatedServiceFetch,
237
+ WALLET_EXECUTE_AUTH_KEY_FIELDS,
238
+ TRADE_READ_AUTH_KEY_FIELDS,
239
+ TRADE_EXECUTE_AUTH_KEY_FIELDS,
240
+ TELEGRAM_ALERT_AUTH_KEY_FIELDS,
241
+ ServiceAuthError,
242
+ InternalAuthKeyFields,
243
+ DASHBOARD_TRADE_EXECUTE_AUTH_KEY_FIELDS,
244
+ DASHBOARD_TELEGRAM_ALERT_AUTH_KEY_FIELDS,
245
+ DASHBOARD_D1_READ_AUTH_KEY_FIELDS,
246
+ D1_WRITE_AUTH_KEY_FIELDS,
247
+ D1_READ_AUTH_KEY_FIELDS
33
248
  };
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAItC,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,eAAe,EAAE,OAAO,CAAC;IACzB,+CAA+C;IAC/C,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AA2BD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,OAAO,EACxB,UAAU,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC1C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkBf;AAID;;;;;GAKG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC,CA6B5D"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKtC,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,eAAe,EAAE,OAAO,CAAC;IACzB,+CAA+C;IAC/C,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AA+CD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,OAAO,EACxB,UAAU,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC1C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkBf;AAID;;;;;GAKG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,YAAY,CAAC,CA8B5D"}