@package-broker/core 0.2.15

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 (217) hide show
  1. package/dist/cache/index.d.ts +2 -0
  2. package/dist/cache/index.d.ts.map +1 -0
  3. package/dist/cache/index.js +2 -0
  4. package/dist/cache/index.js.map +1 -0
  5. package/dist/cache/memory-driver.d.ts +15 -0
  6. package/dist/cache/memory-driver.d.ts.map +1 -0
  7. package/dist/cache/memory-driver.js +56 -0
  8. package/dist/cache/memory-driver.js.map +1 -0
  9. package/dist/db/d1-driver.d.ts +3 -0
  10. package/dist/db/d1-driver.d.ts.map +1 -0
  11. package/dist/db/d1-driver.js +7 -0
  12. package/dist/db/d1-driver.js.map +1 -0
  13. package/dist/db/index.d.ts +5 -0
  14. package/dist/db/index.d.ts.map +1 -0
  15. package/dist/db/index.js +4 -0
  16. package/dist/db/index.js.map +1 -0
  17. package/dist/db/schema.d.ts +696 -0
  18. package/dist/db/schema.d.ts.map +1 -0
  19. package/dist/db/schema.js +99 -0
  20. package/dist/db/schema.js.map +1 -0
  21. package/dist/factory.d.ts +34 -0
  22. package/dist/factory.d.ts.map +1 -0
  23. package/dist/factory.js +121 -0
  24. package/dist/factory.js.map +1 -0
  25. package/dist/index.d.ts +16 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +17 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/jobs/index.d.ts +2 -0
  30. package/dist/jobs/index.d.ts.map +1 -0
  31. package/dist/jobs/index.js +7 -0
  32. package/dist/jobs/index.js.map +1 -0
  33. package/dist/jobs/processor.d.ts +49 -0
  34. package/dist/jobs/processor.d.ts.map +1 -0
  35. package/dist/jobs/processor.js +118 -0
  36. package/dist/jobs/processor.js.map +1 -0
  37. package/dist/middleware/auth.d.ts +52 -0
  38. package/dist/middleware/auth.d.ts.map +1 -0
  39. package/dist/middleware/auth.js +300 -0
  40. package/dist/middleware/auth.js.map +1 -0
  41. package/dist/middleware/composer-version.d.ts +7 -0
  42. package/dist/middleware/composer-version.d.ts.map +1 -0
  43. package/dist/middleware/composer-version.js +18 -0
  44. package/dist/middleware/composer-version.js.map +1 -0
  45. package/dist/middleware/error-handler.d.ts +7 -0
  46. package/dist/middleware/error-handler.d.ts.map +1 -0
  47. package/dist/middleware/error-handler.js +45 -0
  48. package/dist/middleware/error-handler.js.map +1 -0
  49. package/dist/middleware/index.d.ts +5 -0
  50. package/dist/middleware/index.d.ts.map +1 -0
  51. package/dist/middleware/index.js +6 -0
  52. package/dist/middleware/index.js.map +1 -0
  53. package/dist/middleware/request-id.d.ts +9 -0
  54. package/dist/middleware/request-id.d.ts.map +1 -0
  55. package/dist/middleware/request-id.js +36 -0
  56. package/dist/middleware/request-id.js.map +1 -0
  57. package/dist/ports.d.ts +32 -0
  58. package/dist/ports.d.ts.map +1 -0
  59. package/dist/ports.js +4 -0
  60. package/dist/ports.js.map +1 -0
  61. package/dist/queue/consumer.d.ts +18 -0
  62. package/dist/queue/consumer.d.ts.map +1 -0
  63. package/dist/queue/consumer.js +82 -0
  64. package/dist/queue/consumer.js.map +1 -0
  65. package/dist/queue/index.d.ts +2 -0
  66. package/dist/queue/index.d.ts.map +1 -0
  67. package/dist/queue/index.js +2 -0
  68. package/dist/queue/index.js.map +1 -0
  69. package/dist/queue/memory-driver.d.ts +13 -0
  70. package/dist/queue/memory-driver.d.ts.map +1 -0
  71. package/dist/queue/memory-driver.js +22 -0
  72. package/dist/queue/memory-driver.js.map +1 -0
  73. package/dist/queue/types.d.ts +19 -0
  74. package/dist/queue/types.d.ts.map +1 -0
  75. package/dist/queue/types.js +3 -0
  76. package/dist/queue/types.js.map +1 -0
  77. package/dist/routes/api/artifacts.d.ts +25 -0
  78. package/dist/routes/api/artifacts.d.ts.map +1 -0
  79. package/dist/routes/api/artifacts.js +57 -0
  80. package/dist/routes/api/artifacts.js.map +1 -0
  81. package/dist/routes/api/auth.d.ts +50 -0
  82. package/dist/routes/api/auth.d.ts.map +1 -0
  83. package/dist/routes/api/auth.js +268 -0
  84. package/dist/routes/api/auth.js.map +1 -0
  85. package/dist/routes/api/index.d.ts +9 -0
  86. package/dist/routes/api/index.d.ts.map +1 -0
  87. package/dist/routes/api/index.js +10 -0
  88. package/dist/routes/api/index.js.map +1 -0
  89. package/dist/routes/api/packages.d.ts +47 -0
  90. package/dist/routes/api/packages.d.ts.map +1 -0
  91. package/dist/routes/api/packages.js +671 -0
  92. package/dist/routes/api/packages.js.map +1 -0
  93. package/dist/routes/api/repositories.d.ts +56 -0
  94. package/dist/routes/api/repositories.d.ts.map +1 -0
  95. package/dist/routes/api/repositories.js +317 -0
  96. package/dist/routes/api/repositories.js.map +1 -0
  97. package/dist/routes/api/settings.d.ts +28 -0
  98. package/dist/routes/api/settings.d.ts.map +1 -0
  99. package/dist/routes/api/settings.js +81 -0
  100. package/dist/routes/api/settings.js.map +1 -0
  101. package/dist/routes/api/stats.d.ts +21 -0
  102. package/dist/routes/api/stats.d.ts.map +1 -0
  103. package/dist/routes/api/stats.js +52 -0
  104. package/dist/routes/api/stats.js.map +1 -0
  105. package/dist/routes/api/tokens.d.ts +39 -0
  106. package/dist/routes/api/tokens.d.ts.map +1 -0
  107. package/dist/routes/api/tokens.js +191 -0
  108. package/dist/routes/api/tokens.js.map +1 -0
  109. package/dist/routes/api/users.d.ts +5 -0
  110. package/dist/routes/api/users.d.ts.map +1 -0
  111. package/dist/routes/api/users.js +125 -0
  112. package/dist/routes/api/users.js.map +1 -0
  113. package/dist/routes/composer.d.ts +133 -0
  114. package/dist/routes/composer.d.ts.map +1 -0
  115. package/dist/routes/composer.js +1179 -0
  116. package/dist/routes/composer.js.map +1 -0
  117. package/dist/routes/dist.d.ts +32 -0
  118. package/dist/routes/dist.d.ts.map +1 -0
  119. package/dist/routes/dist.js +761 -0
  120. package/dist/routes/dist.js.map +1 -0
  121. package/dist/routes/health.d.ts +7 -0
  122. package/dist/routes/health.d.ts.map +1 -0
  123. package/dist/routes/health.js +22 -0
  124. package/dist/routes/health.js.map +1 -0
  125. package/dist/routes/index.d.ts +5 -0
  126. package/dist/routes/index.d.ts.map +1 -0
  127. package/dist/routes/index.js +6 -0
  128. package/dist/routes/index.js.map +1 -0
  129. package/dist/services/EmailService.d.ts +20 -0
  130. package/dist/services/EmailService.d.ts.map +1 -0
  131. package/dist/services/EmailService.js +27 -0
  132. package/dist/services/EmailService.js.map +1 -0
  133. package/dist/services/UserService.d.ts +27 -0
  134. package/dist/services/UserService.d.ts.map +1 -0
  135. package/dist/services/UserService.js +164 -0
  136. package/dist/services/UserService.js.map +1 -0
  137. package/dist/storage/driver.d.ts +65 -0
  138. package/dist/storage/driver.d.ts.map +1 -0
  139. package/dist/storage/driver.js +59 -0
  140. package/dist/storage/driver.js.map +1 -0
  141. package/dist/storage/index.d.ts +4 -0
  142. package/dist/storage/index.d.ts.map +1 -0
  143. package/dist/storage/index.js +5 -0
  144. package/dist/storage/index.js.map +1 -0
  145. package/dist/storage/r2-driver.d.ts +16 -0
  146. package/dist/storage/r2-driver.d.ts.map +1 -0
  147. package/dist/storage/r2-driver.js +28 -0
  148. package/dist/storage/r2-driver.js.map +1 -0
  149. package/dist/storage/s3-driver.d.ts +22 -0
  150. package/dist/storage/s3-driver.d.ts.map +1 -0
  151. package/dist/storage/s3-driver.js +66 -0
  152. package/dist/storage/s3-driver.js.map +1 -0
  153. package/dist/sync/github-sync.d.ts +15 -0
  154. package/dist/sync/github-sync.d.ts.map +1 -0
  155. package/dist/sync/github-sync.js +39 -0
  156. package/dist/sync/github-sync.js.map +1 -0
  157. package/dist/sync/index.d.ts +5 -0
  158. package/dist/sync/index.d.ts.map +1 -0
  159. package/dist/sync/index.js +6 -0
  160. package/dist/sync/index.js.map +1 -0
  161. package/dist/sync/repository-sync.d.ts +18 -0
  162. package/dist/sync/repository-sync.d.ts.map +1 -0
  163. package/dist/sync/repository-sync.js +214 -0
  164. package/dist/sync/repository-sync.js.map +1 -0
  165. package/dist/sync/strategies/composer-repo.d.ts +11 -0
  166. package/dist/sync/strategies/composer-repo.d.ts.map +1 -0
  167. package/dist/sync/strategies/composer-repo.js +269 -0
  168. package/dist/sync/strategies/composer-repo.js.map +1 -0
  169. package/dist/sync/strategies/github-api.d.ts +6 -0
  170. package/dist/sync/strategies/github-api.d.ts.map +1 -0
  171. package/dist/sync/strategies/github-api.js +137 -0
  172. package/dist/sync/strategies/github-api.js.map +1 -0
  173. package/dist/sync/strategies/github-packages.d.ts +7 -0
  174. package/dist/sync/strategies/github-packages.d.ts.map +1 -0
  175. package/dist/sync/strategies/github-packages.js +66 -0
  176. package/dist/sync/strategies/github-packages.js.map +1 -0
  177. package/dist/sync/strategies/index.d.ts +4 -0
  178. package/dist/sync/strategies/index.d.ts.map +1 -0
  179. package/dist/sync/strategies/index.js +5 -0
  180. package/dist/sync/strategies/index.js.map +1 -0
  181. package/dist/sync/types.d.ts +60 -0
  182. package/dist/sync/types.d.ts.map +1 -0
  183. package/dist/sync/types.js +3 -0
  184. package/dist/sync/types.js.map +1 -0
  185. package/dist/utils/analytics.d.ts +142 -0
  186. package/dist/utils/analytics.d.ts.map +1 -0
  187. package/dist/utils/analytics.js +229 -0
  188. package/dist/utils/analytics.js.map +1 -0
  189. package/dist/utils/download.d.ts +10 -0
  190. package/dist/utils/download.d.ts.map +1 -0
  191. package/dist/utils/download.js +34 -0
  192. package/dist/utils/download.js.map +1 -0
  193. package/dist/utils/encryption.d.ts +20 -0
  194. package/dist/utils/encryption.d.ts.map +1 -0
  195. package/dist/utils/encryption.js +76 -0
  196. package/dist/utils/encryption.js.map +1 -0
  197. package/dist/utils/index.d.ts +5 -0
  198. package/dist/utils/index.d.ts.map +1 -0
  199. package/dist/utils/index.js +6 -0
  200. package/dist/utils/index.js.map +1 -0
  201. package/dist/utils/logger.d.ts +78 -0
  202. package/dist/utils/logger.d.ts.map +1 -0
  203. package/dist/utils/logger.js +134 -0
  204. package/dist/utils/logger.js.map +1 -0
  205. package/dist/utils/upstream-fetch.d.ts +15 -0
  206. package/dist/utils/upstream-fetch.d.ts.map +1 -0
  207. package/dist/utils/upstream-fetch.js +108 -0
  208. package/dist/utils/upstream-fetch.js.map +1 -0
  209. package/dist/workflows/index.d.ts +3 -0
  210. package/dist/workflows/index.d.ts.map +1 -0
  211. package/dist/workflows/index.js +8 -0
  212. package/dist/workflows/index.js.map +1 -0
  213. package/dist/workflows/package-storage.d.ts +47 -0
  214. package/dist/workflows/package-storage.d.ts.map +1 -0
  215. package/dist/workflows/package-storage.js +136 -0
  216. package/dist/workflows/package-storage.js.map +1 -0
  217. package/package.json +62 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/routes/api/stats.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAIlB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAW3C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,CAAyB;IACtD,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAE7B,4BAA4B;IAC5B,MAAM,CAAC,iBAAiB,CAAC,GAAG,MAAM,EAAE;SACjC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,UAAU,EAAE,CAAC;SACxC,IAAI,CAAC,YAAY,CAAC;SAClB,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE5C,MAAM,WAAW,GAAG,iBAAiB,EAAE,KAAK,IAAI,CAAC,CAAC;IAElD,8BAA8B;IAC9B,MAAM,CAAC,cAAc,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1F,MAAM,cAAc,GAAG,cAAc,EAAE,KAAK,IAAI,CAAC,CAAC;IAElD,yDAAyD;IACzD,MAAM,CAAC,eAAe,CAAC,GAAG,MAAM,EAAE;SAC/B,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,CAAQ,OAAO,SAAS,CAAC,cAAc,GAAG,EAAE,CAAC;SAChE,IAAI,CAAC,SAAS,CAAC,CAAC;IAEnB,MAAM,cAAc,GAAG,eAAe,EAAE,KAAK,IAAI,CAAC,CAAC;IAEnD,OAAO,CAAC,CAAC,IAAI,CAAC;QACZ,YAAY,EAAE,WAAW;QACzB,eAAe,EAAE,cAAc;QAC/B,eAAe,EAAE,cAAc;KAChC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,CAAyB;IAC7D,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAE7B,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE;SACxB,MAAM,CAAC;QACN,SAAS,EAAE,SAAS,CAAC,cAAc;QACnC,eAAe,EAAE,SAAS,CAAC,kBAAkB;KAC9C,CAAC;SACD,IAAI,CAAC,SAAS,CAAC;SACf,KAAK,CACJ,GAAG,CACD,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,EAChC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAC/B,CACF;SACA,KAAK,CAAC,CAAC,CAAC,CAAC;IAEZ,OAAO,CAAC,CAAC,IAAI,CAAC;QACZ,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,CAAC;QACnC,eAAe,EAAE,QAAQ,EAAE,eAAe,IAAI,IAAI;KACnD,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { Context } from 'hono';
2
+ import type { DatabasePort } from '../../ports';
3
+ export interface TokensRouteEnv {
4
+ Bindings: {
5
+ DB: D1Database;
6
+ KV?: KVNamespace;
7
+ };
8
+ Variables: {
9
+ database: DatabasePort;
10
+ requestId?: string;
11
+ session?: {
12
+ userId: string;
13
+ email: string;
14
+ };
15
+ };
16
+ }
17
+ /**
18
+ * GET /api/tokens
19
+ * List all tokens (without exposing actual tokens)
20
+ */
21
+ export declare function listTokens(c: Context<TokensRouteEnv>): Promise<Response>;
22
+ /**
23
+ * POST /api/tokens
24
+ * Create a new token
25
+ * Returns the token ONCE - it cannot be retrieved again
26
+ */
27
+ export declare function createToken(c: Context<TokensRouteEnv>): Promise<Response>;
28
+ /**
29
+ * DELETE /api/tokens/:id
30
+ * Revoke a token
31
+ */
32
+ export declare function deleteToken(c: Context<TokensRouteEnv>): Promise<Response>;
33
+ /**
34
+ * PATCH /api/tokens/:id
35
+ * Update token description and/or rate_limit_max
36
+ * Permissions cannot be changed after creation
37
+ */
38
+ export declare function updateToken(c: Context<TokensRouteEnv>): Promise<Response>;
39
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/routes/api/tokens.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAYhD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE;QACR,EAAE,EAAE,UAAU,CAAC;QACf,EAAE,CAAC,EAAE,WAAW,CAAC;KAClB,CAAC;IACF,SAAS,EAAE;QACT,QAAQ,EAAE,YAAY,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KAC7C,CAAC;CACH;AAiBD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAe9E;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2D/E;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAwB/E;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoE/E"}
@@ -0,0 +1,191 @@
1
+ /*
2
+ * PACKAGE.broker
3
+ * Copyright (C) 2025 Łukasz Bajsarowicz
4
+ * Licensed under AGPL-3.0
5
+ */
6
+ import { tokens } from '../../db/schema';
7
+ import { eq } from 'drizzle-orm';
8
+ import { createTokenSchema, updateTokenSchema } from '@package-broker/shared';
9
+ import { sha256 } from '@noble/hashes/sha256';
10
+ import { bytesToHex } from '@noble/hashes/utils';
11
+ import { nanoid, customAlphabet } from 'nanoid';
12
+ import { getAnalytics } from '../../utils/analytics';
13
+ // Generate high-entropy tokens (64 characters, URL-safe)
14
+ const generateToken = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 64);
15
+ /**
16
+ * Hash token using SHA-256
17
+ */
18
+ function hashToken(token) {
19
+ const hash = sha256(token);
20
+ return bytesToHex(hash);
21
+ }
22
+ /**
23
+ * Check if KV is available for rate limiting
24
+ */
25
+ function isKvAvailableForRateLimiting(kv) {
26
+ return kv !== undefined && kv !== null;
27
+ }
28
+ /**
29
+ * GET /api/tokens
30
+ * List all tokens (without exposing actual tokens)
31
+ */
32
+ export async function listTokens(c) {
33
+ const db = c.get('database');
34
+ const allTokens = await db.select().from(tokens).orderBy(tokens.created_at);
35
+ const tokenList = allTokens.map((token) => ({
36
+ id: token.id,
37
+ description: token.description,
38
+ permissions: token.permissions || 'readonly', // Fallback for existing tokens
39
+ rate_limit_max: token.rate_limit_max,
40
+ created_at: token.created_at,
41
+ expires_at: token.expires_at,
42
+ last_used_at: token.last_used_at,
43
+ }));
44
+ return c.json(tokenList);
45
+ }
46
+ /**
47
+ * POST /api/tokens
48
+ * Create a new token
49
+ * Returns the token ONCE - it cannot be retrieved again
50
+ */
51
+ export async function createToken(c) {
52
+ const body = await c.req.json();
53
+ const validated = createTokenSchema.parse(body);
54
+ // Validate: rate limiting requires KV
55
+ if (validated.rate_limit_max !== null &&
56
+ validated.rate_limit_max !== undefined &&
57
+ validated.rate_limit_max > 0) {
58
+ if (!isKvAvailableForRateLimiting(c.env.KV)) {
59
+ return c.json({
60
+ error: 'Bad Request',
61
+ message: 'Rate limiting requires KV namespace to be configured. Please set rate_limit_max to null or 0, or configure KV namespace in your wrangler.toml.'
62
+ }, 400);
63
+ }
64
+ }
65
+ const db = c.get('database');
66
+ const tokenId = nanoid();
67
+ const token = generateToken(); // Generate high-entropy token
68
+ const tokenHash = hashToken(token);
69
+ // Use provided rate_limit_max, or default to 1000 only if not explicitly set to null/0
70
+ const rateLimitMax = validated.rate_limit_max !== null && validated.rate_limit_max !== undefined
71
+ ? validated.rate_limit_max
72
+ : 1000;
73
+ await db.insert(tokens).values({
74
+ id: tokenId,
75
+ description: validated.description,
76
+ token_hash: tokenHash,
77
+ permissions: validated.permissions || 'readonly',
78
+ rate_limit_max: rateLimitMax,
79
+ created_at: Math.floor(Date.now() / 1000),
80
+ expires_at: validated.expires_at || null,
81
+ });
82
+ // Track token creation
83
+ const analytics = getAnalytics();
84
+ const requestId = c.get('requestId');
85
+ const session = c.get('session');
86
+ analytics.trackTokenCreated({
87
+ requestId,
88
+ tokenId,
89
+ userId: session?.userId,
90
+ });
91
+ // Return token ONCE - it's never stored in plaintext
92
+ return c.json({
93
+ id: tokenId,
94
+ token: token, // Only time token is returned
95
+ description: validated.description,
96
+ permissions: validated.permissions || 'readonly',
97
+ rate_limit_max: rateLimitMax,
98
+ created_at: Math.floor(Date.now() / 1000),
99
+ expires_at: validated.expires_at || null,
100
+ }, 201);
101
+ }
102
+ /**
103
+ * DELETE /api/tokens/:id
104
+ * Revoke a token
105
+ */
106
+ export async function deleteToken(c) {
107
+ const id = c.req.param('id');
108
+ const db = c.get('database');
109
+ // Check if exists
110
+ const [token] = await db.select().from(tokens).where(eq(tokens.id, id)).limit(1);
111
+ if (!token) {
112
+ return c.json({ error: 'Not Found', message: 'Token not found' }, 404);
113
+ }
114
+ await db.delete(tokens).where(eq(tokens.id, id));
115
+ // Track token revocation
116
+ const analytics = getAnalytics();
117
+ const requestId = c.get('requestId');
118
+ const session = c.get('session');
119
+ analytics.trackTokenDeleted({
120
+ requestId,
121
+ tokenId: id,
122
+ userId: session?.userId,
123
+ });
124
+ return c.json({ message: 'Token revoked' });
125
+ }
126
+ /**
127
+ * PATCH /api/tokens/:id
128
+ * Update token description and/or rate_limit_max
129
+ * Permissions cannot be changed after creation
130
+ */
131
+ export async function updateToken(c) {
132
+ const id = c.req.param('id');
133
+ const body = await c.req.json();
134
+ const validated = updateTokenSchema.parse(body);
135
+ // Validate: rate limiting requires KV
136
+ if (validated.rate_limit_max !== null &&
137
+ validated.rate_limit_max !== undefined &&
138
+ validated.rate_limit_max > 0) {
139
+ if (!isKvAvailableForRateLimiting(c.env.KV)) {
140
+ return c.json({
141
+ error: 'Bad Request',
142
+ message: 'Rate limiting requires KV namespace to be configured. Please set rate_limit_max to null or 0, or configure KV namespace in your wrangler.toml.'
143
+ }, 400);
144
+ }
145
+ }
146
+ const db = c.get('database');
147
+ // Check if token exists
148
+ const [token] = await db.select().from(tokens).where(eq(tokens.id, id)).limit(1);
149
+ if (!token) {
150
+ return c.json({ error: 'Not Found', message: 'Token not found' }, 404);
151
+ }
152
+ // Build update object - only update provided fields
153
+ const updateData = {};
154
+ if (validated.description !== undefined) {
155
+ updateData.description = validated.description;
156
+ }
157
+ if (validated.rate_limit_max !== undefined) {
158
+ // Allow null/0 to disable rate limiting
159
+ updateData.rate_limit_max = validated.rate_limit_max;
160
+ }
161
+ // Only update if there are fields to update
162
+ if (Object.keys(updateData).length > 0) {
163
+ await db
164
+ .update(tokens)
165
+ .set(updateData)
166
+ .where(eq(tokens.id, id));
167
+ }
168
+ // Fetch updated token
169
+ const [updatedToken] = await db.select().from(tokens).where(eq(tokens.id, id)).limit(1);
170
+ // Track token update (if analytics method exists)
171
+ const analytics = getAnalytics();
172
+ const requestId = c.get('requestId');
173
+ const session = c.get('session');
174
+ if (typeof analytics.trackTokenUpdated === 'function') {
175
+ analytics.trackTokenUpdated({
176
+ requestId,
177
+ tokenId: id,
178
+ userId: session?.userId,
179
+ });
180
+ }
181
+ return c.json({
182
+ id: updatedToken.id,
183
+ description: updatedToken.description,
184
+ permissions: updatedToken.permissions || 'readonly',
185
+ rate_limit_max: updatedToken.rate_limit_max,
186
+ created_at: updatedToken.created_at,
187
+ expires_at: updatedToken.expires_at,
188
+ last_used_at: updatedToken.last_used_at,
189
+ });
190
+ }
191
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../../src/routes/api/tokens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Context } from 'hono';
2
+ export declare function listUsers(c: Context): Promise<Response>;
3
+ export declare function createUser(c: Context): Promise<Response>;
4
+ export declare function deleteUser(c: Context): Promise<Response>;
5
+ //# sourceMappingURL=users.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/routes/api/users.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC,wBAAsB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAY7D;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuG9D;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkB9D"}
@@ -0,0 +1,125 @@
1
+ import { UserService } from '../../services/UserService';
2
+ export async function listUsers(c) {
3
+ const db = c.get('database');
4
+ const userService = new UserService(db);
5
+ // Check permissions (must be admin)
6
+ const session = c.get('session');
7
+ if (session.role !== 'admin') {
8
+ return c.json({ error: 'Forbidden' }, 403);
9
+ }
10
+ const users = await userService.list();
11
+ return c.json({ users });
12
+ }
13
+ export async function createUser(c) {
14
+ const db = c.get('database');
15
+ const userService = new UserService(db);
16
+ // Check permissions
17
+ const session = c.get('session');
18
+ if (session.role !== 'admin') {
19
+ return c.json({ error: 'Forbidden' }, 403);
20
+ }
21
+ let body;
22
+ try {
23
+ body = await c.req.json();
24
+ }
25
+ catch {
26
+ return c.json({ error: 'Invalid JSON' }, 400);
27
+ }
28
+ const { email, password, role } = body;
29
+ // Password is now optional for invites
30
+ if (!email) {
31
+ return c.json({ error: 'Email is required' }, 400);
32
+ }
33
+ try {
34
+ const user = await userService.create({
35
+ email,
36
+ password,
37
+ role: role || 'viewer',
38
+ });
39
+ // Send invite email if SMTP is configured
40
+ if (c.env.SMTP_HOST && c.env.SMTP_USER && c.env.SMTP_PASS) {
41
+ try {
42
+ const { EmailService } = await import('../../services/EmailService');
43
+ const emailService = new EmailService({
44
+ host: c.env.SMTP_HOST,
45
+ port: parseInt(c.env.SMTP_PORT || '587'),
46
+ user: c.env.SMTP_USER,
47
+ pass: c.env.SMTP_PASS,
48
+ from: c.env.SMTP_FROM || c.env.SMTP_USER,
49
+ });
50
+ let subject = 'Welcome to Composer Proxy';
51
+ let text = '';
52
+ let html = '';
53
+ if (user?.invite_token) {
54
+ // Invite Flow
55
+ const origin = c.req.header('origin') || new URL(c.req.url).origin;
56
+ const inviteLink = `${origin}/invite/${user.invite_token}`;
57
+ text = `You have been invited to the Composer Proxy.\n\nPlease accept the invitation and set your password here:\n${inviteLink}`;
58
+ html = `
59
+ <div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; color: #334155;">
60
+ <h2 style="color: #0f172a;">Welcome to Composer Proxy</h2>
61
+ <p>You have been invited to join the Composer Proxy.</p>
62
+ <p>Please click the button below to accept the invitation and set your password:</p>
63
+ <p style="margin: 24px 0;">
64
+ <a href="${inviteLink}" style="background-color: #f97316; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block; font-weight: bold;">Accept Invitation</a>
65
+ </p>
66
+ <p style="font-size: 0.9em; color: #64748b;">Or copy this link to your browser: <br> ${inviteLink}</p>
67
+ <p style="font-size: 0.8em; color: #94a3b8; margin-top: 40px; border-top: 1px solid #e2e8f0; padding-top: 20px;">
68
+ This invite expires in 7 days.
69
+ </p>
70
+ </div>
71
+ `;
72
+ }
73
+ else if (password) {
74
+ // Legacy/Manual Password Flow (if admin provided password)
75
+ text = `You have been invited to the Composer Proxy.\n\nYour temporary password is: ${password}\n\nPlease log in and change your password immediately.`;
76
+ html = `
77
+ <div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; color: #334155;">
78
+ <h2>Welcome to Composer Proxy</h2>
79
+ <p>You have been invited to the Composer Proxy.</p>
80
+ <p>Your temporary password is: <strong>${password}</strong></p>
81
+ <p>Please log in and change your password immediately.</p>
82
+ </div>
83
+ `;
84
+ }
85
+ if (text && html) {
86
+ await emailService.send({ to: email, subject, text, html });
87
+ }
88
+ }
89
+ catch (emailError) {
90
+ console.error('Failed to send invite email:', emailError);
91
+ }
92
+ }
93
+ return c.json({
94
+ message: 'User created',
95
+ user: {
96
+ id: user?.id,
97
+ email: user?.email,
98
+ role: user?.role
99
+ }
100
+ });
101
+ }
102
+ catch (error) {
103
+ if (error.message === 'User already exists') {
104
+ return c.json({ error: 'User already exists' }, 409);
105
+ }
106
+ return c.json({ error: 'Failed to create user' }, 500);
107
+ }
108
+ }
109
+ export async function deleteUser(c) {
110
+ const db = c.get('database');
111
+ const userService = new UserService(db);
112
+ const userId = c.req.param('id');
113
+ // Check permissions
114
+ const session = c.get('session');
115
+ if (session.role !== 'admin') {
116
+ return c.json({ error: 'Forbidden' }, 403);
117
+ }
118
+ // Prevent self-deletion
119
+ if (session.userId === userId) {
120
+ return c.json({ error: 'Cannot delete own account' }, 400);
121
+ }
122
+ await userService.delete(userId);
123
+ return c.json({ message: 'User deleted' });
124
+ }
125
+ //# sourceMappingURL=users.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"users.js","sourceRoot":"","sources":["../../../src/routes/api/users.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ import type { Context } from 'hono';
2
+ import type { DatabasePort } from '../ports';
3
+ import { packages } from '../db/schema';
4
+ import type { StorageDriver } from '../storage/driver';
5
+ export interface ComposerRouteEnv {
6
+ Bindings: {
7
+ DB: D1Database;
8
+ KV?: KVNamespace;
9
+ QUEUE?: Queue;
10
+ PACKAGE_STORAGE_WORKFLOW?: Workflow;
11
+ ENCRYPTION_KEY: string;
12
+ };
13
+ Variables: {
14
+ storage: StorageDriver;
15
+ database: DatabasePort;
16
+ requestId?: string;
17
+ };
18
+ }
19
+ /**
20
+ * GET /packages.json
21
+ * Serve aggregated packages.json for all private repositories
22
+ * Uses KV caching with stale-while-revalidate strategy
23
+ */
24
+ export declare function packagesJsonRoute(c: Context<ComposerRouteEnv>): Promise<Response>;
25
+ /**
26
+ * GET /p2/:vendor/:package.json
27
+ * Serve individual package metadata (Composer 2 provider format)
28
+ * Supports public Packagist mirroring with lazy loading
29
+ */
30
+ export declare function p2PackageRoute(c: Context<ComposerRouteEnv>): Promise<Response>;
31
+ /**
32
+ * Build Composer 2 provider response for a single package from stored metadata
33
+ * Generates clean response with proper types from D1 stored data
34
+ *
35
+ * NOTE: Composer 2 (p2) format expects versions as an ARRAY, not a dict keyed by version.
36
+ * See: https://packagist.org/apidoc
37
+ */
38
+ export declare function buildP2Response(packageName: string, packageVersions: Array<typeof packages.$inferSelect>): ComposerP2Response;
39
+ /**
40
+ * Ensure Packagist repository exists in database
41
+ * Creates it if it doesn't exist
42
+ */
43
+ export declare function ensurePackagistRepository(db: DatabasePort, encryptionKey: string, kv?: KVNamespace): Promise<void>;
44
+ /**
45
+ * Transform package dist URLs to proxy URLs and store in database
46
+ * Waits for all database writes to complete before returning
47
+ * Returns transformed data along with storage success metrics
48
+ */
49
+ export declare function transformPackageDistUrls(packageData: any, repoId: string, proxyBaseUrl: string, db: DatabasePort): Promise<{
50
+ transformed: any;
51
+ storedCount: number;
52
+ errors: string[];
53
+ }>;
54
+ /**
55
+ * Store package metadata in database (synchronous)
56
+ */
57
+ export declare function storeLazyPackageMetadata(db: DatabasePort, repoId: string, packageName: string, packageData: any, proxyBaseUrl: string): Promise<void>;
58
+ /**
59
+ * Store a single package in database
60
+ * Throws errors for caller to handle
61
+ */
62
+ export declare function storePackageInDB(db: DatabasePort, packageName: string, version: string, metadata: any, repoId: string, proxyDistUrl: string, sourceDistUrl: string | null): Promise<void>;
63
+ interface ComposerP2Response {
64
+ packages: Record<string, PackageVersion[]>;
65
+ }
66
+ /**
67
+ * Package version metadata in Composer p2 format
68
+ *
69
+ * Required fields:
70
+ * - name: Package name (vendor/package) - MUST be present
71
+ * - version: Version string - MUST be present
72
+ * - dist: Distribution information - MUST be present with at least type and url
73
+ *
74
+ * Optional fields:
75
+ * - time: Release timestamp (ISO 8601)
76
+ * - description: Package description
77
+ * - license: License identifier(s)
78
+ * - type: Package type (e.g., "library", "metapackage")
79
+ * - homepage: Homepage URL
80
+ * - source: Source repository information
81
+ * - require: Runtime dependencies
82
+ * - require-dev: Development dependencies
83
+ * - autoload: Autoload configuration
84
+ * - notification-url: Notification URL
85
+ */
86
+ interface PackageVersion {
87
+ /** Required: Package name in vendor/package format */
88
+ name: string;
89
+ /** Required: Version string */
90
+ version: string;
91
+ /** Required: Distribution information */
92
+ dist: {
93
+ /** Required: Distribution type (usually "zip") */
94
+ type: string;
95
+ /** Required: Download URL */
96
+ url: string;
97
+ /** Optional: Reference (commit hash, tag, etc.) for mirror URL substitution */
98
+ reference?: string;
99
+ /** Optional: SHA-1 checksum */
100
+ shasum?: string;
101
+ /** Optional: Mirror URLs (used by repository-level mirrors) */
102
+ mirrors?: Array<{
103
+ url: string;
104
+ preferred?: boolean;
105
+ }>;
106
+ };
107
+ /** Optional: Release timestamp */
108
+ time?: string;
109
+ /** Optional: Package description */
110
+ description?: string;
111
+ /** Optional: License identifier(s) */
112
+ license?: string | string[];
113
+ /** Optional: Package type */
114
+ type?: string;
115
+ /** Optional: Homepage URL */
116
+ homepage?: string;
117
+ /** Optional: Source repository information */
118
+ source?: {
119
+ type: string;
120
+ url: string;
121
+ reference: string;
122
+ };
123
+ /** Optional: Runtime dependencies */
124
+ require?: Record<string, string>;
125
+ /** Optional: Development dependencies */
126
+ 'require-dev'?: Record<string, string>;
127
+ /** Optional: Autoload configuration */
128
+ autoload?: object;
129
+ /** Optional: Notification URL */
130
+ 'notification-url'?: string | null;
131
+ }
132
+ export {};
133
+ //# sourceMappingURL=composer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../src/routes/composer.ts"],"names":[],"mappings":"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"}