@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,300 @@
1
+ // Authentication middleware
2
+ import { sha256 } from '@noble/hashes/sha256';
3
+ import { bytesToHex } from '@noble/hashes/utils';
4
+ import { tokens } from '../db/schema';
5
+ import { eq } from 'drizzle-orm';
6
+ /**
7
+ * Extract Basic Auth credentials from request
8
+ */
9
+ function extractBasicAuth(authHeader) {
10
+ if (!authHeader || !authHeader.startsWith('Basic ')) {
11
+ return null;
12
+ }
13
+ try {
14
+ const encoded = authHeader.slice(6);
15
+ const decoded = atob(encoded);
16
+ const [username, password] = decoded.split(':', 2);
17
+ return { username, password };
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ /**
24
+ * Hash token using SHA-256 (for high-entropy tokens)
25
+ */
26
+ function hashToken(token) {
27
+ const hash = sha256(token);
28
+ return bytesToHex(hash);
29
+ }
30
+ /**
31
+ * Check rate limit in KV
32
+ * Note: KV has eventual consistency (up to 60s), rate limiting is approximate
33
+ * If rateLimitMax is null, 0, or falsy, rate limiting is disabled and no KV operations are performed
34
+ * If KV is unavailable, gracefully allows all requests (rate limiting not enforced)
35
+ */
36
+ async function checkRateLimit(kv, tokenId, rateLimitMax) {
37
+ // If rate limiting is disabled (null, 0, or falsy), skip all operations
38
+ if (!rateLimitMax || rateLimitMax <= 0) {
39
+ return { allowed: true, remaining: Infinity };
40
+ }
41
+ // If KV is not available, allow request (graceful degradation)
42
+ if (!kv) {
43
+ return { allowed: true, remaining: Infinity };
44
+ }
45
+ const hour = Math.floor(Date.now() / (1000 * 60 * 60));
46
+ const key = `rate_limit:${tokenId}:${hour}`;
47
+ const current = await kv.get(key);
48
+ const count = current ? parseInt(current, 10) : 0;
49
+ if (count >= rateLimitMax) {
50
+ return { allowed: false, remaining: 0 };
51
+ }
52
+ // Increment count (eventual consistency is acceptable)
53
+ await kv.put(key, String(count + 1), { expirationTtl: 3600 });
54
+ return { allowed: true, remaining: rateLimitMax - count - 1 };
55
+ }
56
+ /**
57
+ * Check if request has valid admin session (Bearer token)
58
+ * Sessions require KV - if KV is unavailable, sessions won't work
59
+ */
60
+ async function checkAdminSession(kv, authHeader) {
61
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
62
+ return { valid: false };
63
+ }
64
+ // Sessions require KV - if unavailable, no sessions can be validated
65
+ if (!kv) {
66
+ return { valid: false };
67
+ }
68
+ const token = authHeader.slice(7);
69
+ const sessionData = await kv.get(`session:${token}`, 'json');
70
+ if (!sessionData) {
71
+ return { valid: false };
72
+ }
73
+ return { valid: true, session: sessionData };
74
+ }
75
+ /**
76
+ * Dual authentication middleware for dist route
77
+ * Accepts either Composer token (Basic Auth) OR admin session (Bearer token)
78
+ */
79
+ export async function distAuthMiddleware(c, next) {
80
+ const authHeader = c.req.header('Authorization');
81
+ // Try admin session first (Bearer token) - for UI downloads
82
+ const sessionResult = await checkAdminSession(c.env.KV, authHeader);
83
+ if (sessionResult.valid && sessionResult.session) {
84
+ c.set('session', sessionResult.session);
85
+ return await next();
86
+ }
87
+ // Fall back to Composer token auth (Basic Auth) - for composer CLI
88
+ const credentials = extractBasicAuth(authHeader);
89
+ if (!credentials) {
90
+ return c.json({ error: 'Unauthorized', message: 'Authentication required (Bearer session or Basic token)' }, 401);
91
+ }
92
+ // Token is passed as password, username should be "token"
93
+ if (credentials.username !== 'token') {
94
+ return c.json({ error: 'Unauthorized', message: 'Username must be "token"' }, 401);
95
+ }
96
+ const token = credentials.password;
97
+ if (!token) {
98
+ return c.json({ error: 'Unauthorized', message: 'Token required in password field' }, 401);
99
+ }
100
+ const tokenHash = hashToken(token);
101
+ // Check cache first (5 second TTL for burst request optimization)
102
+ const cacheKey = `token:${tokenHash}`;
103
+ let tokenRecord = null;
104
+ try {
105
+ const cached = c.env.KV ? await c.env.KV.get(cacheKey, 'json') : null;
106
+ if (cached) {
107
+ // Verify token hasn't expired
108
+ if (!cached.expires_at || cached.expires_at >= Date.now() / 1000) {
109
+ tokenRecord = cached;
110
+ }
111
+ }
112
+ }
113
+ catch {
114
+ // Cache miss or error - fall through to D1 query
115
+ }
116
+ // If not in cache, query D1
117
+ if (!tokenRecord) {
118
+ const db = c.get('database');
119
+ const [dbToken] = await db
120
+ .select()
121
+ .from(tokens)
122
+ .where(eq(tokens.token_hash, tokenHash))
123
+ .limit(1);
124
+ if (dbToken) {
125
+ tokenRecord = dbToken;
126
+ // Cache for 5 seconds to handle burst requests (if KV available)
127
+ if (c.env.KV) {
128
+ c.executionCtx.waitUntil(c.env.KV.put(cacheKey, JSON.stringify(dbToken), { expirationTtl: 5 }).catch(() => {
129
+ // Ignore cache errors
130
+ }));
131
+ }
132
+ }
133
+ }
134
+ if (!tokenRecord) {
135
+ return c.json({ error: 'Unauthorized', message: 'Invalid token' }, 401);
136
+ }
137
+ // Check expiration
138
+ if (tokenRecord.expires_at && tokenRecord.expires_at < Date.now() / 1000) {
139
+ return c.json({ error: 'Unauthorized', message: 'Token expired' }, 401);
140
+ }
141
+ // Check rate limit (skip if null/0 to avoid KV operations)
142
+ const rateLimitMax = tokenRecord.rate_limit_max;
143
+ const rateLimit = await checkRateLimit(c.env.KV, tokenRecord.id, rateLimitMax);
144
+ if (!rateLimit.allowed) {
145
+ return c.json({ error: 'Too Many Requests', message: 'Rate limit exceeded' }, 429);
146
+ }
147
+ // Attach token info to context
148
+ c.set('auth', {
149
+ tokenId: tokenRecord.id,
150
+ tokenDescription: tokenRecord.description,
151
+ tokenPermissions: (tokenRecord.permissions || 'readonly'),
152
+ });
153
+ // Update last_used_at (non-blocking)
154
+ c.executionCtx.waitUntil((async () => {
155
+ const db = c.get('database');
156
+ if (c.env.QUEUE && typeof c.env.QUEUE.send === 'function') {
157
+ await c.env.QUEUE.send({
158
+ type: 'update_token_last_used',
159
+ tokenId: tokenRecord.id,
160
+ timestamp: Math.floor(Date.now() / 1000),
161
+ });
162
+ }
163
+ else {
164
+ await db
165
+ .update(tokens)
166
+ .set({ last_used_at: Math.floor(Date.now() / 1000) })
167
+ .where(eq(tokens.id, tokenRecord.id));
168
+ }
169
+ })());
170
+ return await next();
171
+ }
172
+ /**
173
+ * Authentication middleware
174
+ * Validates Basic Auth -> D1 Token -> KV Rate Limit
175
+ */
176
+ export async function authMiddleware(c, next) {
177
+ const authHeader = c.req.header('Authorization');
178
+ const credentials = extractBasicAuth(authHeader);
179
+ if (!credentials) {
180
+ return c.json({ error: 'Unauthorized', message: 'Basic authentication required' }, 401);
181
+ }
182
+ // Token is passed as password, username should be "token"
183
+ if (credentials.username !== 'token') {
184
+ return c.json({ error: 'Unauthorized', message: 'Username must be "token"' }, 401);
185
+ }
186
+ const token = credentials.password;
187
+ if (!token) {
188
+ return c.json({ error: 'Unauthorized', message: 'Token required in password field' }, 401);
189
+ }
190
+ const tokenHash = hashToken(token);
191
+ // Check cache first (5 second TTL for burst request optimization)
192
+ const cacheKey = `token:${tokenHash}`;
193
+ let tokenRecord = null;
194
+ try {
195
+ const cached = c.env.KV ? await c.env.KV.get(cacheKey, 'json') : null;
196
+ if (cached) {
197
+ // Verify token hasn't expired
198
+ if (!cached.expires_at || cached.expires_at >= Date.now() / 1000) {
199
+ tokenRecord = cached;
200
+ }
201
+ }
202
+ }
203
+ catch {
204
+ // Cache miss or error - fall through to D1 query
205
+ }
206
+ // If not in cache, query D1
207
+ if (!tokenRecord) {
208
+ const db = c.get('database');
209
+ const [dbToken] = await db
210
+ .select()
211
+ .from(tokens)
212
+ .where(eq(tokens.token_hash, tokenHash))
213
+ .limit(1);
214
+ if (dbToken) {
215
+ tokenRecord = dbToken;
216
+ // Cache for 5 seconds to handle burst requests (if KV available)
217
+ if (c.env.KV) {
218
+ c.executionCtx.waitUntil(c.env.KV.put(cacheKey, JSON.stringify(dbToken), { expirationTtl: 5 }).catch(() => {
219
+ // Ignore cache errors
220
+ }));
221
+ }
222
+ }
223
+ }
224
+ if (!tokenRecord) {
225
+ return c.json({ error: 'Unauthorized', message: 'Invalid token' }, 401);
226
+ }
227
+ // Check expiration
228
+ if (tokenRecord.expires_at && tokenRecord.expires_at < Date.now() / 1000) {
229
+ return c.json({ error: 'Unauthorized', message: 'Token expired' }, 401);
230
+ }
231
+ // Check rate limit (skip if null/0 to avoid KV operations)
232
+ const rateLimitMax = tokenRecord.rate_limit_max;
233
+ const rateLimit = await checkRateLimit(c.env.KV, tokenRecord.id, rateLimitMax);
234
+ if (!rateLimit.allowed) {
235
+ return c.json({
236
+ error: 'Too Many Requests',
237
+ message: 'Rate limit exceeded',
238
+ }, 429);
239
+ }
240
+ // Attach token info to context
241
+ c.set('auth', {
242
+ tokenId: tokenRecord.id,
243
+ tokenDescription: tokenRecord.description,
244
+ tokenPermissions: (tokenRecord.permissions || 'readonly'),
245
+ });
246
+ // Track token usage analytics
247
+ const { getAnalytics } = await import('../utils/analytics');
248
+ const analytics = getAnalytics();
249
+ const requestId = c.get('requestId');
250
+ analytics.trackAuthTokenUsed({
251
+ requestId,
252
+ tokenId: tokenRecord.id,
253
+ });
254
+ // Update last_used_at (non-blocking)
255
+ const updateTokenLastUsed = async () => {
256
+ const db = c.get('database');
257
+ if (c.env.QUEUE && typeof c.env.QUEUE.send === 'function') {
258
+ // Use Queue for async processing (Paid plan)
259
+ await c.env.QUEUE.send({
260
+ type: 'update_token_last_used',
261
+ tokenId: tokenRecord.id,
262
+ timestamp: Math.floor(Date.now() / 1000),
263
+ });
264
+ }
265
+ else {
266
+ // Fallback: update directly in database (Free tier)
267
+ await db
268
+ .update(tokens)
269
+ .set({ last_used_at: Math.floor(Date.now() / 1000) })
270
+ .where(eq(tokens.id, tokenRecord.id));
271
+ }
272
+ };
273
+ // Run in background to not block the response
274
+ c.executionCtx.waitUntil(updateTokenLastUsed());
275
+ return await next();
276
+ }
277
+ /**
278
+ * Middleware to check token permissions
279
+ * Requires write permission for certain operations
280
+ */
281
+ export function checkTokenPermissions(requiredPermission) {
282
+ return async (c, next) => {
283
+ const auth = c.get('auth');
284
+ if (!auth) {
285
+ return c.json({
286
+ error: 'Unauthorized',
287
+ message: 'Authentication required'
288
+ }, 401);
289
+ }
290
+ const tokenPermission = auth.tokenPermissions || 'readonly';
291
+ if (requiredPermission === 'write' && tokenPermission === 'readonly') {
292
+ return c.json({
293
+ error: 'Forbidden',
294
+ message: 'This operation requires write permissions. Your token has read-only access.'
295
+ }, 403);
296
+ }
297
+ return await next();
298
+ };
299
+ }
300
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAG5B,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EAAE,MAAM,EAA8B,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAQjC;;GAEG;AACH,SAAS,gBAAgB,CAAC,UAA8B;IAItD,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACnD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,cAAc,CAC3B,EAA2B,EAC3B,OAAe,EACf,YAA2B;IAE3B,wEAAwE;IACxE,IAAI,CAAC,YAAY,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IAChD,CAAC;IAED,+DAA+D;IAC/D,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IAChD,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,cAAc,OAAO,IAAI,IAAI,EAAE,CAAC;IAE5C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAElD,IAAI,KAAK,IAAI,YAAY,EAAE,CAAC;QAC1B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IAC1C,CAAC;IAED,uDAAuD;IACvD,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,iBAAiB,CAC9B,EAA2B,EAC3B,UAA8B;IAE9B,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED,qEAAqE;IACrE,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClC,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,WAAW,KAAK,EAAE,EAAE,MAAM,CAA6C,CAAC;IAEzG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,CAWE,EACF,IAA6B;IAE7B,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAEjD,4DAA4D;IAC5D,MAAM,aAAa,GAAG,MAAM,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IACpE,IAAI,aAAa,CAAC,KAAK,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;QACjD,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAED,mEAAmE;IACnE,MAAM,WAAW,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,yDAAyD,EAAE,EAAE,GAAG,CAAC,CAAC;IACpH,CAAC;IAED,0DAA0D;IAC1D,IAAI,WAAW,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,0BAA0B,EAAE,EAAE,GAAG,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,kCAAkC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAEnC,kEAAkE;IAClE,MAAM,QAAQ,GAAG,SAAS,SAAS,EAAE,CAAC;IACtC,IAAI,WAAW,GAAwC,IAAI,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAwC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7G,IAAI,MAAM,EAAE,CAAC;YACX,8BAA8B;YAC9B,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;gBACjE,WAAW,GAAG,MAAM,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,iDAAiD;IACnD,CAAC;IAED,4BAA4B;IAC5B,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE;aACvB,MAAM,EAAE;aACR,IAAI,CAAC,MAAM,CAAC;aACZ,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;aACvC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,OAAO,EAAE,CAAC;YACZ,WAAW,GAAG,OAAO,CAAC;YACtB,iEAAiE;YACjE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACb,CAAC,CAAC,YAAY,CAAC,SAAS,CACtB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;oBAC/E,sBAAsB;gBACxB,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,mBAAmB;IACnB,IAAI,WAAW,CAAC,UAAU,IAAI,WAAW,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;QACzE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,2DAA2D;IAC3D,MAAM,YAAY,GAAG,WAAW,CAAC,cAAc,CAAC;IAChD,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IAC/E,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,qBAAqB,EAAE,EAAE,GAAG,CAAC,CAAC;IACrF,CAAC;IAED,+BAA+B;IAC/B,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;QACZ,OAAO,EAAE,WAAW,CAAC,EAAE;QACvB,gBAAgB,EAAE,WAAW,CAAC,WAAW;QACzC,gBAAgB,EAAE,CAAC,WAAW,CAAC,WAAW,IAAI,UAAU,CAAyB;KAClF,CAAC,CAAC;IAEH,qCAAqC;IACrC,CAAC,CAAC,YAAY,CAAC,SAAS,CACtB,CAAC,KAAK,IAAI,EAAE;QACV,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC1D,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBACrB,IAAI,EAAE,wBAAwB;gBAC9B,OAAO,EAAE,WAAW,CAAC,EAAE;gBACvB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;aACzC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,EAAE;iBACL,MAAM,CAAC,MAAM,CAAC;iBACd,GAAG,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;iBACpD,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC,EAAE,CACL,CAAC;IAEF,OAAO,MAAM,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,CAWE,EACF,IAA6B;IAE7B,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAEjD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,+BAA+B,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1F,CAAC;IAED,0DAA0D;IAC1D,IAAI,WAAW,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACrC,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,0BAA0B,EAAE,EAC9D,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,kCAAkC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAEnC,kEAAkE;IAClE,MAAM,QAAQ,GAAG,SAAS,SAAS,EAAE,CAAC;IACtC,IAAI,WAAW,GAAwC,IAAI,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAwC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7G,IAAI,MAAM,EAAE,CAAC;YACX,8BAA8B;YAC9B,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;gBACjE,WAAW,GAAG,MAAM,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,iDAAiD;IACnD,CAAC;IAED,4BAA4B;IAC5B,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE;aACvB,MAAM,EAAE;aACR,IAAI,CAAC,MAAM,CAAC;aACZ,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;aACvC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEZ,IAAI,OAAO,EAAE,CAAC;YACZ,WAAW,GAAG,OAAO,CAAC;YACtB,iEAAiE;YACjE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACb,CAAC,CAAC,YAAY,CAAC,SAAS,CACtB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;oBAC/E,sBAAsB;gBACxB,CAAC,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,mBAAmB;IACnB,IAAI,WAAW,CAAC,UAAU,IAAI,WAAW,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;QACzE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1E,CAAC;IAED,2DAA2D;IAC3D,MAAM,YAAY,GAAG,WAAW,CAAC,cAAc,CAAC;IAChD,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IAC/E,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,CAAC,CAAC,IAAI,CACX;YACE,KAAK,EAAE,mBAAmB;YAC1B,OAAO,EAAE,qBAAqB;SAC/B,EACD,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,+BAA+B;IAC/B,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;QACZ,OAAO,EAAE,WAAW,CAAC,EAAE;QACvB,gBAAgB,EAAE,WAAW,CAAC,WAAW;QACzC,gBAAgB,EAAE,CAAC,WAAW,CAAC,WAAW,IAAI,UAAU,CAAyB;KAClF,CAAC,CAAC;IAEH,8BAA8B;IAC9B,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAuB,CAAC;IAC3D,SAAS,CAAC,kBAAkB,CAAC;QAC3B,SAAS;QACT,OAAO,EAAE,WAAW,CAAC,EAAE;KACxB,CAAC,CAAC;IAEH,qCAAqC;IACrC,MAAM,mBAAmB,GAAG,KAAK,IAAI,EAAE;QACrC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC1D,6CAA6C;YAC7C,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBACrB,IAAI,EAAE,wBAAwB;gBAC9B,OAAO,EAAE,WAAW,CAAC,EAAE;gBACvB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;aACzC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,oDAAoD;YACpD,MAAM,EAAE;iBACL,MAAM,CAAC,MAAM,CAAC;iBACd,GAAG,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;iBACpD,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC,CAAC;IAEF,8CAA8C;IAC9C,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAEhD,OAAO,MAAM,IAAI,EAAE,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,kBAAwC;IAC5E,OAAO,KAAK,EACV,CAIE,EACF,IAA6B,EACV,EAAE;QACrB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAE3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,cAAc;gBACrB,OAAO,EAAE,yBAAyB;aACnC,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,IAAI,UAAU,CAAC;QAE5D,IAAI,kBAAkB,KAAK,OAAO,IAAI,eAAe,KAAK,UAAU,EAAE,CAAC;YACrE,OAAO,CAAC,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE,6EAA6E;aACvF,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QAED,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Context } from 'hono';
2
+ /**
3
+ * Middleware to reject Composer 1.x requests
4
+ * Returns 406 Not Acceptable for Composer/1.* User-Agent
5
+ */
6
+ export declare function composerVersionMiddleware(c: Context, next: () => Promise<Response>): Promise<Response>;
7
+ //# sourceMappingURL=composer-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer-version.d.ts","sourceRoot":"","sources":["../../src/middleware/composer-version.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAQ,MAAM,MAAM,CAAC;AAE1C;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAgBnB"}
@@ -0,0 +1,18 @@
1
+ // Composer version middleware - reject Composer 1.x
2
+ /**
3
+ * Middleware to reject Composer 1.x requests
4
+ * Returns 406 Not Acceptable for Composer/1.* User-Agent
5
+ */
6
+ export async function composerVersionMiddleware(c, next) {
7
+ const userAgent = c.req.header('User-Agent') || '';
8
+ // Reject Composer 1.x
9
+ if (userAgent.startsWith('Composer/1.')) {
10
+ return c.json({
11
+ error: 'Composer 2.x required',
12
+ message: 'This proxy only supports Composer 2.x. Please upgrade your Composer installation.',
13
+ }, 406);
14
+ }
15
+ // Allow Composer 2.x and other clients
16
+ return await next();
17
+ }
18
+ //# sourceMappingURL=composer-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer-version.js","sourceRoot":"","sources":["../../src/middleware/composer-version.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAIpD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,CAAU,EACV,IAA6B;IAE7B,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IAEnD,sBAAsB;IACtB,IAAI,SAAS,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,OAAO,CAAC,CAAC,IAAI,CACX;YACE,KAAK,EAAE,uBAAuB;YAC9B,OAAO,EAAE,mFAAmF;SAC7F,EACD,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,uCAAuC;IACvC,OAAO,MAAM,IAAI,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Context } from 'hono';
2
+ /**
3
+ * Error handling middleware
4
+ * Catches errors, logs to Workers Logs (free tier), and returns appropriate HTTP status
5
+ */
6
+ export declare function errorHandlerMiddleware(c: Context, next: () => Promise<Response>): Promise<Response>;
7
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAGpC;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAC5B,OAAO,CAAC,QAAQ,CAAC,CA0CnB"}
@@ -0,0 +1,45 @@
1
+ /*
2
+ * PACKAGE.broker
3
+ * Copyright (C) 2025 Łukasz Bajsarowicz
4
+ * Licensed under AGPL-3.0
5
+ */
6
+ import { getLogger } from '../utils/logger';
7
+ /**
8
+ * Error handling middleware
9
+ * Catches errors, logs to Workers Logs (free tier), and returns appropriate HTTP status
10
+ */
11
+ export async function errorHandlerMiddleware(c, next) {
12
+ try {
13
+ return await next();
14
+ }
15
+ catch (error) {
16
+ const logger = getLogger();
17
+ const requestId = c.get('requestId');
18
+ // Log error with structured context
19
+ logger.error('Request error', {
20
+ url: c.req.url,
21
+ method: c.req.method,
22
+ path: new URL(c.req.url).pathname,
23
+ }, error instanceof Error ? error : new Error(String(error)));
24
+ // Return appropriate error response
25
+ if (error instanceof Error) {
26
+ // Known error types
27
+ if (error.message.includes('Unauthorized')) {
28
+ return c.json({ error: 'Unauthorized', message: error.message }, 401);
29
+ }
30
+ if (error.message.includes('Not Found')) {
31
+ return c.json({ error: 'Not Found', message: error.message }, 404);
32
+ }
33
+ if (error.message.includes('Rate limit')) {
34
+ return c.json({ error: 'Too Many Requests', message: error.message }, 429);
35
+ }
36
+ }
37
+ // Generic error
38
+ return c.json({
39
+ error: 'Internal Server Error',
40
+ message: 'An unexpected error occurred',
41
+ ...(requestId && { requestId }),
42
+ }, 500);
43
+ }
44
+ }
45
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,CAAU,EACV,IAA6B;IAE7B,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAuB,CAAC;QAE3D,oCAAoC;QACpC,MAAM,CAAC,KAAK,CACV,eAAe,EACf;YACE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG;YACd,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;YACpB,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ;SAClC,EACD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAC1D,CAAC;QAEF,oCAAoC;QACpC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,oBAAoB;YACpB,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC3C,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;YACxE,CAAC;YACD,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBACxC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;YACrE,CAAC;YACD,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;YAC7E,CAAC;QACH,CAAC;QAED,gBAAgB;QAChB,OAAO,CAAC,CAAC,IAAI,CACX;YACE,KAAK,EAAE,uBAAuB;YAC9B,OAAO,EAAE,8BAA8B;YACvC,GAAG,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;SAChC,EACD,GAAG,CACJ,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './composer-version';
2
+ export * from './auth';
3
+ export * from './error-handler';
4
+ export * from './request-id';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AACA,cAAc,oBAAoB,CAAC;AACnC,cAAc,QAAQ,CAAC;AACvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ // Middleware exports
2
+ export * from './composer-version';
3
+ export * from './auth';
4
+ export * from './error-handler';
5
+ export * from './request-id';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/middleware/index.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,cAAc,oBAAoB,CAAC;AACnC,cAAc,QAAQ,CAAC;AACvB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { Context, Next } from 'hono';
2
+ /**
3
+ * Request ID middleware
4
+ *
5
+ * Generates a unique request ID for each request and stores it in context.
6
+ * This ID is used for log correlation across the request lifecycle.
7
+ */
8
+ export declare function requestIdMiddleware(c: Context, next: Next): Promise<void>;
9
+ //# sourceMappingURL=request-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.d.ts","sourceRoot":"","sources":["../../src/middleware/request-id.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI1C;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -0,0 +1,36 @@
1
+ /*
2
+ * PACKAGE.broker
3
+ * Copyright (C) 2025 Łukasz Bajsarowicz
4
+ * Licensed under AGPL-3.0
5
+ */
6
+ import { nanoid } from 'nanoid';
7
+ import { getLogger } from '../utils/logger';
8
+ /**
9
+ * Request ID middleware
10
+ *
11
+ * Generates a unique request ID for each request and stores it in context.
12
+ * This ID is used for log correlation across the request lifecycle.
13
+ */
14
+ export async function requestIdMiddleware(c, next) {
15
+ // Generate unique request ID
16
+ const requestId = nanoid(16);
17
+ // Store in context variables
18
+ c.set('requestId', requestId);
19
+ // Set request ID in logger for automatic inclusion in all logs
20
+ const logger = getLogger();
21
+ logger.setRequestId(requestId);
22
+ // Log request start
23
+ logger.info('Request started', {
24
+ method: c.req.method,
25
+ url: c.req.url,
26
+ path: new URL(c.req.url).pathname,
27
+ });
28
+ // Call next middleware/handler
29
+ await next();
30
+ // Add request ID to response headers for debugging
31
+ // Response is available after next() completes
32
+ if (c.res) {
33
+ c.res.headers.set('X-Request-ID', requestId);
34
+ }
35
+ }
36
+ //# sourceMappingURL=request-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-id.js","sourceRoot":"","sources":["../../src/middleware/request-id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,CAAU,EACV,IAAU;IAEV,6BAA6B;IAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAE7B,6BAA6B;IAC7B,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAE9B,+DAA+D;IAC/D,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IAE/B,oBAAoB;IACpB,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;QAC7B,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;QACpB,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG;QACd,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ;KAClC,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,IAAI,EAAE,CAAC;IAEb,mDAAmD;IACnD,+CAA+C;IAC/C,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACV,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { Database } from './db/index';
2
+ /**
3
+ * Database Port
4
+ * Represents the database connection/ORM instance.
5
+ * Currently just aliasing the Drizzle type, but allows for future abstraction.
6
+ */
7
+ export type DatabasePort = Database;
8
+ /**
9
+ * Cache Port
10
+ * Abstract interface for caching (KV, Redis, Memory)
11
+ */
12
+ export interface CachePort {
13
+ get(key: string): Promise<string | null>;
14
+ get<T>(key: string, type: 'json'): Promise<T | null>;
15
+ put(key: string, value: string | ReadableStream | ArrayBuffer | FormData, options?: {
16
+ expirationTtl?: number;
17
+ }): Promise<void>;
18
+ delete(key: string): Promise<void>;
19
+ }
20
+ /**
21
+ * Queue Port
22
+ * Abstract interface for job queues (Cloudflare Queues, BullMQ, SQS)
23
+ */
24
+ export interface QueuePort {
25
+ send(message: any): Promise<void>;
26
+ sendBatch(messages: any[]): Promise<void>;
27
+ }
28
+ export interface AnalyticsPort {
29
+ track(event: string, properties?: Record<string, any>): void;
30
+ }
31
+ export type { StorageDriver as StoragePort } from './storage/driver';
32
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../src/ports.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;AAEpC;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACrD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,WAAW,GAAG,QAAQ,EAAE,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/H,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,SAAS,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAGD,MAAM,WAAW,aAAa;IAC1B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;CAChE;AAED,YAAY,EAAE,aAAa,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/ports.js ADDED
@@ -0,0 +1,4 @@
1
+ // Core ports (interfaces) for external infrastructure
2
+ // adhering to Hexagonal Architecture (Ports & Adapters)
3
+ export {};
4
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../src/ports.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,wDAAwD"}
@@ -0,0 +1,18 @@
1
+ import type { QueueMessage } from './types';
2
+ export interface QueueConsumerEnv {
3
+ DB: D1Database;
4
+ }
5
+ /**
6
+ * Process queue messages for async database updates
7
+ * Optimized for free tier: batch operations where possible
8
+ */
9
+ export declare function processQueueMessage(message: QueueMessage, env: QueueConsumerEnv): Promise<void>;
10
+ /**
11
+ * Queue consumer worker entry point
12
+ * This will be called by Cloudflare Queue when messages are available
13
+ */
14
+ declare const _default: {
15
+ queue(batch: MessageBatch<QueueMessage>, env: QueueConsumerEnv): Promise<void>;
16
+ };
17
+ export default _default;
18
+ //# sourceMappingURL=consumer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consumer.d.ts","sourceRoot":"","sources":["../../src/queue/consumer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,UAAU,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,IAAI,CAAC,CAkDf;AAED;;;GAGG;;iBAEkB,YAAY,CAAC,YAAY,CAAC,OAAO,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;;AADtF,wBAgBE"}
@@ -0,0 +1,82 @@
1
+ /*
2
+ * PACKAGE.broker
3
+ * Copyright (C) 2025 Łukasz Bajsarowicz
4
+ * Licensed under AGPL-3.0
5
+ */
6
+ // Queue consumer for async database updates
7
+ import { createD1Database } from '../db';
8
+ import { tokens, artifacts, repositories } from '../db/schema';
9
+ import { eq } from 'drizzle-orm';
10
+ import { getLogger } from '../utils/logger';
11
+ /**
12
+ * Process queue messages for async database updates
13
+ * Optimized for free tier: batch operations where possible
14
+ */
15
+ export async function processQueueMessage(message, env) {
16
+ const db = createD1Database(env.DB);
17
+ switch (message.type) {
18
+ case 'update_token_last_used': {
19
+ await db
20
+ .update(tokens)
21
+ .set({ last_used_at: message.timestamp })
22
+ .where(eq(tokens.id, message.tokenId));
23
+ break;
24
+ }
25
+ case 'update_artifact_download': {
26
+ // Update download_count and last_downloaded_at
27
+ // First, get current count
28
+ const [artifact] = await db
29
+ .select()
30
+ .from(artifacts)
31
+ .where(eq(artifacts.id, message.artifactId))
32
+ .limit(1);
33
+ if (artifact) {
34
+ await db
35
+ .update(artifacts)
36
+ .set({
37
+ download_count: (artifact.download_count ?? 0) + 1,
38
+ last_downloaded_at: message.timestamp,
39
+ })
40
+ .where(eq(artifacts.id, message.artifactId));
41
+ }
42
+ break;
43
+ }
44
+ case 'update_repository_sync': {
45
+ await db
46
+ .update(repositories)
47
+ .set({
48
+ status: message.status,
49
+ error_message: message.errorMessage || null,
50
+ last_synced_at: message.timestamp,
51
+ })
52
+ .where(eq(repositories.id, message.repoId));
53
+ break;
54
+ }
55
+ default: {
56
+ const logger = getLogger();
57
+ logger.warn('Unknown queue message type', { messageType: message.type });
58
+ }
59
+ }
60
+ }
61
+ /**
62
+ * Queue consumer worker entry point
63
+ * This will be called by Cloudflare Queue when messages are available
64
+ */
65
+ export default {
66
+ async queue(batch, env) {
67
+ // Process messages in batch (optimize for free tier)
68
+ const promises = batch.messages.map((msg) => {
69
+ try {
70
+ return processQueueMessage(msg.body, env);
71
+ }
72
+ catch (error) {
73
+ const logger = getLogger();
74
+ logger.error('Error processing queue message', { messageType: msg.body.type }, error instanceof Error ? error : new Error(String(error)));
75
+ // Don't retry on error - log and continue
76
+ return Promise.resolve();
77
+ }
78
+ });
79
+ await Promise.all(promises);
80
+ },
81
+ };
82
+ //# sourceMappingURL=consumer.js.map