@claw-network/node 0.2.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 (190) hide show
  1. package/README.md +49 -0
  2. package/dist/api/api-key-store.d.ts +74 -0
  3. package/dist/api/api-key-store.d.ts.map +1 -0
  4. package/dist/api/api-key-store.js +170 -0
  5. package/dist/api/api-key-store.js.map +1 -0
  6. package/dist/api/auth.d.ts +30 -0
  7. package/dist/api/auth.d.ts.map +1 -0
  8. package/dist/api/auth.js +115 -0
  9. package/dist/api/auth.js.map +1 -0
  10. package/dist/api/legacy.d.ts +26 -0
  11. package/dist/api/legacy.d.ts.map +1 -0
  12. package/dist/api/legacy.js +281 -0
  13. package/dist/api/legacy.js.map +1 -0
  14. package/dist/api/middleware.d.ts +35 -0
  15. package/dist/api/middleware.d.ts.map +1 -0
  16. package/dist/api/middleware.js +75 -0
  17. package/dist/api/middleware.js.map +1 -0
  18. package/dist/api/response.d.ts +85 -0
  19. package/dist/api/response.d.ts.map +1 -0
  20. package/dist/api/response.js +185 -0
  21. package/dist/api/response.js.map +1 -0
  22. package/dist/api/router.d.ts +45 -0
  23. package/dist/api/router.d.ts.map +1 -0
  24. package/dist/api/router.js +183 -0
  25. package/dist/api/router.js.map +1 -0
  26. package/dist/api/routes/admin.d.ts +11 -0
  27. package/dist/api/routes/admin.d.ts.map +1 -0
  28. package/dist/api/routes/admin.js +124 -0
  29. package/dist/api/routes/admin.js.map +1 -0
  30. package/dist/api/routes/contracts.d.ts +7 -0
  31. package/dist/api/routes/contracts.d.ts.map +1 -0
  32. package/dist/api/routes/contracts.js +665 -0
  33. package/dist/api/routes/contracts.js.map +1 -0
  34. package/dist/api/routes/dao.d.ts +7 -0
  35. package/dist/api/routes/dao.d.ts.map +1 -0
  36. package/dist/api/routes/dao.js +549 -0
  37. package/dist/api/routes/dao.js.map +1 -0
  38. package/dist/api/routes/dev.d.ts +9 -0
  39. package/dist/api/routes/dev.d.ts.map +1 -0
  40. package/dist/api/routes/dev.js +273 -0
  41. package/dist/api/routes/dev.js.map +1 -0
  42. package/dist/api/routes/escrows.d.ts +7 -0
  43. package/dist/api/routes/escrows.d.ts.map +1 -0
  44. package/dist/api/routes/escrows.js +454 -0
  45. package/dist/api/routes/escrows.js.map +1 -0
  46. package/dist/api/routes/identities.d.ts +7 -0
  47. package/dist/api/routes/identities.d.ts.map +1 -0
  48. package/dist/api/routes/identities.js +245 -0
  49. package/dist/api/routes/identities.js.map +1 -0
  50. package/dist/api/routes/markets-capabilities.d.ts +7 -0
  51. package/dist/api/routes/markets-capabilities.d.ts.map +1 -0
  52. package/dist/api/routes/markets-capabilities.js +477 -0
  53. package/dist/api/routes/markets-capabilities.js.map +1 -0
  54. package/dist/api/routes/markets-disputes.d.ts +7 -0
  55. package/dist/api/routes/markets-disputes.d.ts.map +1 -0
  56. package/dist/api/routes/markets-disputes.js +102 -0
  57. package/dist/api/routes/markets-disputes.js.map +1 -0
  58. package/dist/api/routes/markets-info.d.ts +7 -0
  59. package/dist/api/routes/markets-info.d.ts.map +1 -0
  60. package/dist/api/routes/markets-info.js +523 -0
  61. package/dist/api/routes/markets-info.js.map +1 -0
  62. package/dist/api/routes/markets-search.d.ts +7 -0
  63. package/dist/api/routes/markets-search.d.ts.map +1 -0
  64. package/dist/api/routes/markets-search.js +38 -0
  65. package/dist/api/routes/markets-search.js.map +1 -0
  66. package/dist/api/routes/markets-tasks.d.ts +7 -0
  67. package/dist/api/routes/markets-tasks.d.ts.map +1 -0
  68. package/dist/api/routes/markets-tasks.js +539 -0
  69. package/dist/api/routes/markets-tasks.js.map +1 -0
  70. package/dist/api/routes/node.d.ts +7 -0
  71. package/dist/api/routes/node.d.ts.map +1 -0
  72. package/dist/api/routes/node.js +53 -0
  73. package/dist/api/routes/node.js.map +1 -0
  74. package/dist/api/routes/nonce.d.ts +10 -0
  75. package/dist/api/routes/nonce.d.ts.map +1 -0
  76. package/dist/api/routes/nonce.js +65 -0
  77. package/dist/api/routes/nonce.js.map +1 -0
  78. package/dist/api/routes/reputations.d.ts +7 -0
  79. package/dist/api/routes/reputations.d.ts.map +1 -0
  80. package/dist/api/routes/reputations.js +243 -0
  81. package/dist/api/routes/reputations.js.map +1 -0
  82. package/dist/api/routes/transfers.d.ts +7 -0
  83. package/dist/api/routes/transfers.d.ts.map +1 -0
  84. package/dist/api/routes/transfers.js +88 -0
  85. package/dist/api/routes/transfers.js.map +1 -0
  86. package/dist/api/routes/wallets.d.ts +7 -0
  87. package/dist/api/routes/wallets.d.ts.map +1 -0
  88. package/dist/api/routes/wallets.js +132 -0
  89. package/dist/api/routes/wallets.js.map +1 -0
  90. package/dist/api/schemas/common.d.ts +45 -0
  91. package/dist/api/schemas/common.d.ts.map +1 -0
  92. package/dist/api/schemas/common.js +30 -0
  93. package/dist/api/schemas/common.js.map +1 -0
  94. package/dist/api/schemas/contracts.d.ts +284 -0
  95. package/dist/api/schemas/contracts.d.ts.map +1 -0
  96. package/dist/api/schemas/contracts.js +79 -0
  97. package/dist/api/schemas/contracts.js.map +1 -0
  98. package/dist/api/schemas/dao.d.ts +271 -0
  99. package/dist/api/schemas/dao.d.ts.map +1 -0
  100. package/dist/api/schemas/dao.js +78 -0
  101. package/dist/api/schemas/dao.js.map +1 -0
  102. package/dist/api/schemas/identity.d.ts +75 -0
  103. package/dist/api/schemas/identity.d.ts.map +1 -0
  104. package/dist/api/schemas/identity.js +32 -0
  105. package/dist/api/schemas/identity.js.map +1 -0
  106. package/dist/api/schemas/markets.d.ts +822 -0
  107. package/dist/api/schemas/markets.d.ts.map +1 -0
  108. package/dist/api/schemas/markets.js +246 -0
  109. package/dist/api/schemas/markets.js.map +1 -0
  110. package/dist/api/schemas/wallet.d.ts +163 -0
  111. package/dist/api/schemas/wallet.d.ts.map +1 -0
  112. package/dist/api/schemas/wallet.js +54 -0
  113. package/dist/api/schemas/wallet.js.map +1 -0
  114. package/dist/api/server.d.ts +45 -0
  115. package/dist/api/server.d.ts.map +1 -0
  116. package/dist/api/server.js +131 -0
  117. package/dist/api/server.js.map +1 -0
  118. package/dist/api/types.d.ts +69 -0
  119. package/dist/api/types.d.ts.map +1 -0
  120. package/dist/api/types.js +196 -0
  121. package/dist/api/types.js.map +1 -0
  122. package/dist/daemon.d.ts +11 -0
  123. package/dist/daemon.d.ts.map +1 -0
  124. package/dist/daemon.js +248 -0
  125. package/dist/daemon.js.map +1 -0
  126. package/dist/index.d.ts +137 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +795 -0
  129. package/dist/index.js.map +1 -0
  130. package/dist/indexer/index.d.ts +10 -0
  131. package/dist/indexer/index.d.ts.map +1 -0
  132. package/dist/indexer/index.js +7 -0
  133. package/dist/indexer/index.js.map +1 -0
  134. package/dist/indexer/indexer.d.ts +60 -0
  135. package/dist/indexer/indexer.d.ts.map +1 -0
  136. package/dist/indexer/indexer.js +408 -0
  137. package/dist/indexer/indexer.js.map +1 -0
  138. package/dist/indexer/query.d.ts +141 -0
  139. package/dist/indexer/query.d.ts.map +1 -0
  140. package/dist/indexer/query.js +244 -0
  141. package/dist/indexer/query.js.map +1 -0
  142. package/dist/indexer/store.d.ts +95 -0
  143. package/dist/indexer/store.d.ts.map +1 -0
  144. package/dist/indexer/store.js +250 -0
  145. package/dist/indexer/store.js.map +1 -0
  146. package/dist/logger.d.ts +13 -0
  147. package/dist/logger.d.ts.map +1 -0
  148. package/dist/logger.js +37 -0
  149. package/dist/logger.js.map +1 -0
  150. package/dist/p2p/sync.d.ts +105 -0
  151. package/dist/p2p/sync.d.ts.map +1 -0
  152. package/dist/p2p/sync.js +875 -0
  153. package/dist/p2p/sync.js.map +1 -0
  154. package/dist/policy/liquidity-policy.d.ts +17 -0
  155. package/dist/policy/liquidity-policy.d.ts.map +1 -0
  156. package/dist/policy/liquidity-policy.js +112 -0
  157. package/dist/policy/liquidity-policy.js.map +1 -0
  158. package/dist/services/chain-config.d.ts +226 -0
  159. package/dist/services/chain-config.d.ts.map +1 -0
  160. package/dist/services/chain-config.js +105 -0
  161. package/dist/services/chain-config.js.map +1 -0
  162. package/dist/services/contract-provider.d.ts +44 -0
  163. package/dist/services/contract-provider.d.ts.map +1 -0
  164. package/dist/services/contract-provider.js +167 -0
  165. package/dist/services/contract-provider.js.map +1 -0
  166. package/dist/services/contracts-service.d.ts +192 -0
  167. package/dist/services/contracts-service.d.ts.map +1 -0
  168. package/dist/services/contracts-service.js +336 -0
  169. package/dist/services/contracts-service.js.map +1 -0
  170. package/dist/services/dao-service.d.ts +245 -0
  171. package/dist/services/dao-service.d.ts.map +1 -0
  172. package/dist/services/dao-service.js +389 -0
  173. package/dist/services/dao-service.js.map +1 -0
  174. package/dist/services/identity-service.d.ts +150 -0
  175. package/dist/services/identity-service.d.ts.map +1 -0
  176. package/dist/services/identity-service.js +286 -0
  177. package/dist/services/identity-service.js.map +1 -0
  178. package/dist/services/index.d.ts +20 -0
  179. package/dist/services/index.d.ts.map +1 -0
  180. package/dist/services/index.js +15 -0
  181. package/dist/services/index.js.map +1 -0
  182. package/dist/services/reputation-service.d.ts +128 -0
  183. package/dist/services/reputation-service.d.ts.map +1 -0
  184. package/dist/services/reputation-service.js +204 -0
  185. package/dist/services/reputation-service.js.map +1 -0
  186. package/dist/services/wallet-service.d.ts +201 -0
  187. package/dist/services/wallet-service.d.ts.map +1 -0
  188. package/dist/services/wallet-service.js +402 -0
  189. package/dist/services/wallet-service.js.map +1 -0
  190. package/package.json +66 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Standardized HTTP response helpers.
3
+ *
4
+ * All 2xx responses use the envelope: { data, meta?, links? }
5
+ * All errors use RFC 7807 Problem Details: { type, title, status, detail, instance }
6
+ */
7
+ // ─── Constants ──────────────────────────────────────────────────
8
+ const ERROR_BASE_URL = 'https://clawnet.dev/errors';
9
+ export const ErrorTypes = {
10
+ VALIDATION: `${ERROR_BASE_URL}/validation-error`,
11
+ UNAUTHORIZED: `${ERROR_BASE_URL}/unauthorized`,
12
+ FORBIDDEN: `${ERROR_BASE_URL}/forbidden`,
13
+ TOO_MANY_REQUESTS: `${ERROR_BASE_URL}/too-many-requests`,
14
+ NOT_FOUND: `${ERROR_BASE_URL}/not-found`,
15
+ CONFLICT: `${ERROR_BASE_URL}/conflict`,
16
+ UNPROCESSABLE: `${ERROR_BASE_URL}/unprocessable-entity`,
17
+ INTERNAL: `${ERROR_BASE_URL}/internal-error`,
18
+ METHOD_NOT_ALLOWED: `${ERROR_BASE_URL}/method-not-allowed`,
19
+ };
20
+ // ─── Response Helpers ───────────────────────────────────────────
21
+ function send(res, status, body) {
22
+ const json = JSON.stringify(body);
23
+ res.writeHead(status, {
24
+ 'Content-Type': 'application/json; charset=utf-8',
25
+ 'Content-Length': Buffer.byteLength(json),
26
+ });
27
+ res.end(json);
28
+ }
29
+ /** 200 OK — single resource */
30
+ export function ok(res, data, links) {
31
+ const body = { data };
32
+ if (links)
33
+ body.links = links;
34
+ send(res, 200, body);
35
+ }
36
+ /** 201 Created — resource just created */
37
+ export function created(res, data, links) {
38
+ const body = { data };
39
+ if (links)
40
+ body.links = links;
41
+ if (links?.self) {
42
+ res.setHeader('Location', links.self);
43
+ }
44
+ send(res, 201, body);
45
+ }
46
+ /** 204 No Content — successful action with no body (e.g. DELETE) */
47
+ export function noContent(res) {
48
+ res.writeHead(204);
49
+ res.end();
50
+ }
51
+ /** 200 OK — paginated collection */
52
+ export function paginated(res, data, opts) {
53
+ const { page, perPage, total, basePath, query = {} } = opts;
54
+ const totalPages = Math.max(1, Math.ceil(total / perPage));
55
+ const buildUrl = (p) => {
56
+ const params = new URLSearchParams({ ...query, page: String(p), per_page: String(perPage) });
57
+ return `${basePath}?${params.toString()}`;
58
+ };
59
+ const body = {
60
+ data,
61
+ meta: {
62
+ pagination: { page, perPage, total, totalPages },
63
+ },
64
+ links: {
65
+ self: buildUrl(page),
66
+ first: buildUrl(1),
67
+ last: buildUrl(totalPages),
68
+ prev: page > 1 ? buildUrl(page - 1) : null,
69
+ next: page < totalPages ? buildUrl(page + 1) : null,
70
+ },
71
+ };
72
+ send(res, 200, body);
73
+ }
74
+ // ─── Error Helpers (RFC 7807) ───────────────────────────────────
75
+ export function problem(res, p) {
76
+ send(res, p.status, {
77
+ type: p.type,
78
+ title: p.title,
79
+ status: p.status,
80
+ detail: p.detail,
81
+ instance: p.instance,
82
+ });
83
+ }
84
+ export function badRequest(res, detail, instance) {
85
+ problem(res, {
86
+ type: ErrorTypes.VALIDATION,
87
+ title: 'Bad Request',
88
+ status: 400,
89
+ detail,
90
+ instance,
91
+ });
92
+ }
93
+ export function unauthorized(res, detail, instance) {
94
+ problem(res, {
95
+ type: ErrorTypes.UNAUTHORIZED,
96
+ title: 'Unauthorized',
97
+ status: 401,
98
+ detail: detail ?? 'Authentication required',
99
+ instance,
100
+ });
101
+ }
102
+ export function forbidden(res, detail, instance) {
103
+ problem(res, {
104
+ type: ErrorTypes.FORBIDDEN,
105
+ title: 'Forbidden',
106
+ status: 403,
107
+ detail: detail ?? 'Insufficient permissions',
108
+ instance,
109
+ });
110
+ }
111
+ export function tooManyRequests(res, detail, instance, retryAfterSeconds) {
112
+ if (typeof retryAfterSeconds === 'number' &&
113
+ Number.isFinite(retryAfterSeconds) &&
114
+ retryAfterSeconds > 0) {
115
+ res.setHeader('Retry-After', String(Math.ceil(retryAfterSeconds)));
116
+ }
117
+ problem(res, {
118
+ type: ErrorTypes.TOO_MANY_REQUESTS,
119
+ title: 'Too Many Requests',
120
+ status: 429,
121
+ detail: detail ?? 'Rate limit exceeded',
122
+ instance,
123
+ });
124
+ }
125
+ export function notFound(res, detail, instance) {
126
+ problem(res, {
127
+ type: ErrorTypes.NOT_FOUND,
128
+ title: 'Not Found',
129
+ status: 404,
130
+ detail: detail ?? 'Resource not found',
131
+ instance,
132
+ });
133
+ }
134
+ export function conflict(res, detail, instance) {
135
+ problem(res, {
136
+ type: ErrorTypes.CONFLICT,
137
+ title: 'Conflict',
138
+ status: 409,
139
+ detail,
140
+ instance,
141
+ });
142
+ }
143
+ export function unprocessable(res, detail, instance) {
144
+ problem(res, {
145
+ type: ErrorTypes.UNPROCESSABLE,
146
+ title: 'Unprocessable Entity',
147
+ status: 422,
148
+ detail,
149
+ instance,
150
+ });
151
+ }
152
+ export function methodNotAllowed(res, allowed, instance) {
153
+ res.setHeader('Allow', allowed.join(', '));
154
+ problem(res, {
155
+ type: ErrorTypes.METHOD_NOT_ALLOWED,
156
+ title: 'Method Not Allowed',
157
+ status: 405,
158
+ detail: `Allowed methods: ${allowed.join(', ')}`,
159
+ instance,
160
+ });
161
+ }
162
+ export function internalError(res, detail, instance) {
163
+ problem(res, {
164
+ type: ErrorTypes.INTERNAL,
165
+ title: 'Internal Server Error',
166
+ status: 500,
167
+ detail: detail ?? 'An unexpected error occurred',
168
+ instance,
169
+ });
170
+ }
171
+ export function parsePagination(searchParams) {
172
+ const page = Math.max(1, parseInt(searchParams.get('page') ?? '1', 10) || 1);
173
+ const perPage = Math.min(100, Math.max(1, parseInt(searchParams.get('per_page') ?? '20', 10) || 20));
174
+ return { page, perPage, offset: (page - 1) * perPage };
175
+ }
176
+ export function parseSort(searchParams) {
177
+ const sort = searchParams.get('sort');
178
+ if (!sort)
179
+ return undefined;
180
+ if (sort.startsWith('-')) {
181
+ return { field: sort.slice(1), order: 'desc' };
182
+ }
183
+ return { field: sort, order: 'asc' };
184
+ }
185
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/api/response.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Lightweight path-matching router for node:http.
3
+ *
4
+ * Supports:
5
+ * - Method + path pattern matching: GET /api/v1/contracts/:id
6
+ * - Named path params: { id: "abc", idx: "0" }
7
+ * - Middleware chain (CORS, body parsing)
8
+ * - 404 / 405 fallback
9
+ */
10
+ import type { IncomingMessage, ServerResponse } from 'node:http';
11
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
12
+ export interface RouteContext {
13
+ /** Parsed URL */
14
+ url: URL;
15
+ /** Matched path parameters (e.g. { id: "abc" }) */
16
+ params: Record<string, string>;
17
+ /** Parsed query parameters */
18
+ query: URLSearchParams;
19
+ /** Parsed JSON body (only for methods with body) */
20
+ body: unknown;
21
+ }
22
+ export type RouteHandler = (req: IncomingMessage, res: ServerResponse, ctx: RouteContext) => Promise<void> | void;
23
+ export type Middleware = (req: IncomingMessage, res: ServerResponse, next: () => Promise<void>) => Promise<void> | void;
24
+ export declare class Router {
25
+ private routes;
26
+ private middlewares;
27
+ /** Register global middleware. */
28
+ use(mw: Middleware): this;
29
+ /** Register a route. Pattern supports :param segments. */
30
+ on(method: HttpMethod, pattern: string, handler: RouteHandler): this;
31
+ get(pattern: string, handler: RouteHandler): this;
32
+ post(pattern: string, handler: RouteHandler): this;
33
+ put(pattern: string, handler: RouteHandler): this;
34
+ patch(pattern: string, handler: RouteHandler): this;
35
+ delete(pattern: string, handler: RouteHandler): this;
36
+ /** Mount all routes from another router under a prefix. */
37
+ mount(prefix: string, child: Router): this;
38
+ /** Handle an incoming request. Returns true if matched. */
39
+ handle(req: IncomingMessage, res: ServerResponse): Promise<boolean>;
40
+ private matchRoute;
41
+ private findMatchingMethods;
42
+ private parseBody;
43
+ private runMiddlewareChain;
44
+ }
45
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAIjE,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1F,MAAM,WAAW,YAAY;IAC3B,iBAAiB;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,8BAA8B;IAC9B,KAAK,EAAE,eAAe,CAAC;IACvB,oDAAoD;IACpD,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GAAG,CACzB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,YAAY,KACd,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,CACvB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KACtB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAa1B,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,WAAW,CAAoB;IAEvC,kCAAkC;IAClC,GAAG,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI;IAKzB,0DAA0D;IAC1D,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAYpE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAIjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAIlD,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAIjD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAInD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAIpD,2DAA2D;IAC3D,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAa1C,2DAA2D;IACrD,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAsCzE,OAAO,CAAC,UAAU;IA6BlB,OAAO,CAAC,mBAAmB;YAiBb,SAAS;YAqCT,kBAAkB;CAmBjC"}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Lightweight path-matching router for node:http.
3
+ *
4
+ * Supports:
5
+ * - Method + path pattern matching: GET /api/v1/contracts/:id
6
+ * - Named path params: { id: "abc", idx: "0" }
7
+ * - Middleware chain (CORS, body parsing)
8
+ * - 404 / 405 fallback
9
+ */
10
+ // ─── Router ─────────────────────────────────────────────────────
11
+ const MAX_BODY_BYTES = 1_000_000;
12
+ export class Router {
13
+ routes = [];
14
+ middlewares = [];
15
+ /** Register global middleware. */
16
+ use(mw) {
17
+ this.middlewares.push(mw);
18
+ return this;
19
+ }
20
+ /** Register a route. Pattern supports :param segments. */
21
+ on(method, pattern, handler) {
22
+ const segments = pattern.split('/').filter(Boolean);
23
+ const paramNames = [];
24
+ for (const seg of segments) {
25
+ if (seg.startsWith(':')) {
26
+ paramNames.push(seg.slice(1));
27
+ }
28
+ }
29
+ this.routes.push({ method, segments, paramNames, handler });
30
+ return this;
31
+ }
32
+ get(pattern, handler) {
33
+ return this.on('GET', pattern, handler);
34
+ }
35
+ post(pattern, handler) {
36
+ return this.on('POST', pattern, handler);
37
+ }
38
+ put(pattern, handler) {
39
+ return this.on('PUT', pattern, handler);
40
+ }
41
+ patch(pattern, handler) {
42
+ return this.on('PATCH', pattern, handler);
43
+ }
44
+ delete(pattern, handler) {
45
+ return this.on('DELETE', pattern, handler);
46
+ }
47
+ /** Mount all routes from another router under a prefix. */
48
+ mount(prefix, child) {
49
+ const prefixSegments = prefix.split('/').filter(Boolean);
50
+ for (const route of child.routes) {
51
+ this.routes.push({
52
+ method: route.method,
53
+ segments: [...prefixSegments, ...route.segments],
54
+ paramNames: route.paramNames,
55
+ handler: route.handler,
56
+ });
57
+ }
58
+ return this;
59
+ }
60
+ /** Handle an incoming request. Returns true if matched. */
61
+ async handle(req, res) {
62
+ const urlStr = req.url ?? '/';
63
+ const url = new URL(urlStr, `http://${req.headers.host ?? 'localhost'}`);
64
+ const method = (req.method ?? 'GET').toUpperCase();
65
+ const reqSegments = url.pathname.split('/').filter(Boolean);
66
+ // Find matching route
67
+ const match = this.matchRoute(method, reqSegments);
68
+ if (!match) {
69
+ // Check if path matches any method (→ 405) or nothing (→ 404)
70
+ const pathMatches = this.findMatchingMethods(reqSegments);
71
+ if (pathMatches.length > 0) {
72
+ // 405 Method Not Allowed
73
+ const { methodNotAllowed } = await import('./response.js');
74
+ methodNotAllowed(res, pathMatches, url.pathname);
75
+ return true;
76
+ }
77
+ return false; // no match at all
78
+ }
79
+ // Build context
80
+ const body = await this.parseBody(req);
81
+ const ctx = {
82
+ url,
83
+ params: match.params,
84
+ query: url.searchParams,
85
+ body,
86
+ };
87
+ // Run middleware chain then handler
88
+ await this.runMiddlewareChain(req, res, () => match.handler(req, res, ctx));
89
+ return true;
90
+ }
91
+ // ─── Internal ───────────────────────────────────────────────
92
+ matchRoute(method, reqSegments) {
93
+ for (const route of this.routes) {
94
+ if (route.method !== method)
95
+ continue;
96
+ if (route.segments.length !== reqSegments.length)
97
+ continue;
98
+ const params = {};
99
+ let matched = true;
100
+ let paramIdx = 0;
101
+ for (let i = 0; i < route.segments.length; i++) {
102
+ const seg = route.segments[i];
103
+ if (seg.startsWith(':')) {
104
+ params[route.paramNames[paramIdx++]] = decodeURIComponent(reqSegments[i]);
105
+ }
106
+ else if (seg !== reqSegments[i]) {
107
+ matched = false;
108
+ break;
109
+ }
110
+ }
111
+ if (matched) {
112
+ return { handler: route.handler, params };
113
+ }
114
+ }
115
+ return null;
116
+ }
117
+ findMatchingMethods(reqSegments) {
118
+ const methods = new Set();
119
+ for (const route of this.routes) {
120
+ if (route.segments.length !== reqSegments.length)
121
+ continue;
122
+ let matched = true;
123
+ for (let i = 0; i < route.segments.length; i++) {
124
+ const seg = route.segments[i];
125
+ if (!seg.startsWith(':') && seg !== reqSegments[i]) {
126
+ matched = false;
127
+ break;
128
+ }
129
+ }
130
+ if (matched)
131
+ methods.add(route.method);
132
+ }
133
+ return [...methods];
134
+ }
135
+ async parseBody(req) {
136
+ const method = req.method ?? 'GET';
137
+ if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS' || method === 'DELETE') {
138
+ return undefined;
139
+ }
140
+ return new Promise((resolve, reject) => {
141
+ const chunks = [];
142
+ let totalBytes = 0;
143
+ req.on('data', (chunk) => {
144
+ totalBytes += chunk.length;
145
+ if (totalBytes > MAX_BODY_BYTES) {
146
+ req.destroy();
147
+ reject(new Error('Request body too large'));
148
+ return;
149
+ }
150
+ chunks.push(chunk);
151
+ });
152
+ req.on('end', () => {
153
+ if (chunks.length === 0) {
154
+ resolve(undefined);
155
+ return;
156
+ }
157
+ try {
158
+ const text = Buffer.concat(chunks).toString('utf-8');
159
+ resolve(JSON.parse(text));
160
+ }
161
+ catch {
162
+ resolve(undefined);
163
+ }
164
+ });
165
+ req.on('error', reject);
166
+ });
167
+ }
168
+ async runMiddlewareChain(req, res, final) {
169
+ let idx = 0;
170
+ const mws = this.middlewares;
171
+ const next = async () => {
172
+ if (idx < mws.length) {
173
+ const mw = mws[idx++];
174
+ await mw(req, res, next);
175
+ }
176
+ else {
177
+ await final();
178
+ }
179
+ };
180
+ await next();
181
+ }
182
+ }
183
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Admin routes — /api/v1/admin
3
+ *
4
+ * API key management endpoints. These routes are only accessible
5
+ * from localhost (127.0.0.1 / ::1) for security — they never pass
6
+ * through the Caddy reverse proxy.
7
+ */
8
+ import { Router } from '../router.js';
9
+ import type { RuntimeContext } from '../types.js';
10
+ export declare function adminRoutes(ctx: RuntimeContext): Router;
11
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../../src/api/routes/admin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAItC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgClD,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CA4GvD"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Admin routes — /api/v1/admin
3
+ *
4
+ * API key management endpoints. These routes are only accessible
5
+ * from localhost (127.0.0.1 / ::1) for security — they never pass
6
+ * through the Caddy reverse proxy.
7
+ */
8
+ import { Router } from '../router.js';
9
+ import { ok, badRequest, notFound, forbidden } from '../response.js';
10
+ import { validate } from '../schemas/common.js';
11
+ import { z } from 'zod';
12
+ // ---------------------------------------------------------------------------
13
+ // Schemas
14
+ // ---------------------------------------------------------------------------
15
+ const CreateKeySchema = z.object({
16
+ label: z.string().min(1).max(128),
17
+ });
18
+ const _RevokeKeySchema = z.object({
19
+ id: z.number().int().positive(),
20
+ });
21
+ // ---------------------------------------------------------------------------
22
+ // Helpers
23
+ // ---------------------------------------------------------------------------
24
+ function isLocalhost(req) {
25
+ const remoteAddress = req.socket.remoteAddress ?? '';
26
+ return (remoteAddress === '127.0.0.1' ||
27
+ remoteAddress === '::1' ||
28
+ remoteAddress === '::ffff:127.0.0.1');
29
+ }
30
+ // ---------------------------------------------------------------------------
31
+ // Routes
32
+ // ---------------------------------------------------------------------------
33
+ export function adminRoutes(ctx) {
34
+ const r = new Router();
35
+ // ── POST /api-keys — create new API key ───────────────────────
36
+ r.post('/api-keys', async (req, res, route) => {
37
+ if (!isLocalhost(req)) {
38
+ forbidden(res, 'Admin API is only accessible from localhost', route.url.pathname);
39
+ return;
40
+ }
41
+ const store = ctx.apiKeyStore;
42
+ if (!store) {
43
+ badRequest(res, 'API key management not enabled', route.url.pathname);
44
+ return;
45
+ }
46
+ const v = validate(CreateKeySchema, route.body);
47
+ if (!v.success) {
48
+ badRequest(res, v.error, route.url.pathname);
49
+ return;
50
+ }
51
+ const record = store.create(v.data.label);
52
+ // Return full key only on creation (not visible again)
53
+ ok(res, {
54
+ id: record.id,
55
+ key: record.key,
56
+ label: record.label,
57
+ status: record.status,
58
+ createdAt: record.createdAt,
59
+ }, { self: '/api/v1/admin/api-keys' });
60
+ });
61
+ // ── GET /api-keys — list all keys (truncated) ────────────────
62
+ r.get('/api-keys', async (req, res, route) => {
63
+ if (!isLocalhost(req)) {
64
+ forbidden(res, 'Admin API is only accessible from localhost', route.url.pathname);
65
+ return;
66
+ }
67
+ const store = ctx.apiKeyStore;
68
+ if (!store) {
69
+ badRequest(res, 'API key management not enabled', route.url.pathname);
70
+ return;
71
+ }
72
+ const includeRevoked = route.query.get('includeRevoked') === 'true';
73
+ const keys = store.list(includeRevoked);
74
+ ok(res, keys, { self: '/api/v1/admin/api-keys' });
75
+ });
76
+ // ── POST /api-keys/:id/revoke — revoke a key ─────────────────
77
+ r.post('/api-keys/:id/revoke', async (req, res, route) => {
78
+ if (!isLocalhost(req)) {
79
+ forbidden(res, 'Admin API is only accessible from localhost', route.url.pathname);
80
+ return;
81
+ }
82
+ const store = ctx.apiKeyStore;
83
+ if (!store) {
84
+ badRequest(res, 'API key management not enabled', route.url.pathname);
85
+ return;
86
+ }
87
+ const id = Number(route.params.id);
88
+ if (Number.isNaN(id) || id <= 0) {
89
+ badRequest(res, 'Invalid key ID', route.url.pathname);
90
+ return;
91
+ }
92
+ const revoked = store.revoke(id);
93
+ if (!revoked) {
94
+ notFound(res, `Key #${id} not found or already revoked`);
95
+ return;
96
+ }
97
+ ok(res, { id, status: 'revoked' }, { self: `/api/v1/admin/api-keys/${id}` });
98
+ });
99
+ // ── DELETE /api-keys/:id — permanently delete a key ───────────
100
+ r.delete('/api-keys/:id', async (req, res, route) => {
101
+ if (!isLocalhost(req)) {
102
+ forbidden(res, 'Admin API is only accessible from localhost', route.url.pathname);
103
+ return;
104
+ }
105
+ const store = ctx.apiKeyStore;
106
+ if (!store) {
107
+ badRequest(res, 'API key management not enabled', route.url.pathname);
108
+ return;
109
+ }
110
+ const id = Number(route.params.id);
111
+ if (Number.isNaN(id) || id <= 0) {
112
+ badRequest(res, 'Invalid key ID', route.url.pathname);
113
+ return;
114
+ }
115
+ const deleted = store.delete(id);
116
+ if (!deleted) {
117
+ notFound(res, `Key #${id} not found`);
118
+ return;
119
+ }
120
+ ok(res, { id, status: 'deleted' }, { self: `/api/v1/admin/api-keys/${id}` });
121
+ });
122
+ return r;
123
+ }
124
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../../../src/api/routes/admin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Service contract routes — /api/v1/contracts
3
+ */
4
+ import { Router } from '../router.js';
5
+ import type { RuntimeContext } from '../types.js';
6
+ export declare function contractRoutes(ctx: RuntimeContext): Router;
7
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../src/api/routes/contracts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAsBtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA4BlD,wBAAgB,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAusB1D"}