@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.
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +2 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/memory-driver.d.ts +15 -0
- package/dist/cache/memory-driver.d.ts.map +1 -0
- package/dist/cache/memory-driver.js +56 -0
- package/dist/cache/memory-driver.js.map +1 -0
- package/dist/db/d1-driver.d.ts +3 -0
- package/dist/db/d1-driver.d.ts.map +1 -0
- package/dist/db/d1-driver.js +7 -0
- package/dist/db/d1-driver.js.map +1 -0
- package/dist/db/index.d.ts +5 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +4 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +696 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +99 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/factory.d.ts +34 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +121 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/index.d.ts +2 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +7 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/processor.d.ts +49 -0
- package/dist/jobs/processor.d.ts.map +1 -0
- package/dist/jobs/processor.js +118 -0
- package/dist/jobs/processor.js.map +1 -0
- package/dist/middleware/auth.d.ts +52 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +300 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/composer-version.d.ts +7 -0
- package/dist/middleware/composer-version.d.ts.map +1 -0
- package/dist/middleware/composer-version.js +18 -0
- package/dist/middleware/composer-version.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +7 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +45 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/index.d.ts +5 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +6 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/request-id.d.ts +9 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +36 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/ports.d.ts +32 -0
- package/dist/ports.d.ts.map +1 -0
- package/dist/ports.js +4 -0
- package/dist/ports.js.map +1 -0
- package/dist/queue/consumer.d.ts +18 -0
- package/dist/queue/consumer.d.ts.map +1 -0
- package/dist/queue/consumer.js +82 -0
- package/dist/queue/consumer.js.map +1 -0
- package/dist/queue/index.d.ts +2 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +2 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/memory-driver.d.ts +13 -0
- package/dist/queue/memory-driver.d.ts.map +1 -0
- package/dist/queue/memory-driver.js +22 -0
- package/dist/queue/memory-driver.js.map +1 -0
- package/dist/queue/types.d.ts +19 -0
- package/dist/queue/types.d.ts.map +1 -0
- package/dist/queue/types.js +3 -0
- package/dist/queue/types.js.map +1 -0
- package/dist/routes/api/artifacts.d.ts +25 -0
- package/dist/routes/api/artifacts.d.ts.map +1 -0
- package/dist/routes/api/artifacts.js +57 -0
- package/dist/routes/api/artifacts.js.map +1 -0
- package/dist/routes/api/auth.d.ts +50 -0
- package/dist/routes/api/auth.d.ts.map +1 -0
- package/dist/routes/api/auth.js +268 -0
- package/dist/routes/api/auth.js.map +1 -0
- package/dist/routes/api/index.d.ts +9 -0
- package/dist/routes/api/index.d.ts.map +1 -0
- package/dist/routes/api/index.js +10 -0
- package/dist/routes/api/index.js.map +1 -0
- package/dist/routes/api/packages.d.ts +47 -0
- package/dist/routes/api/packages.d.ts.map +1 -0
- package/dist/routes/api/packages.js +671 -0
- package/dist/routes/api/packages.js.map +1 -0
- package/dist/routes/api/repositories.d.ts +56 -0
- package/dist/routes/api/repositories.d.ts.map +1 -0
- package/dist/routes/api/repositories.js +317 -0
- package/dist/routes/api/repositories.js.map +1 -0
- package/dist/routes/api/settings.d.ts +28 -0
- package/dist/routes/api/settings.d.ts.map +1 -0
- package/dist/routes/api/settings.js +81 -0
- package/dist/routes/api/settings.js.map +1 -0
- package/dist/routes/api/stats.d.ts +21 -0
- package/dist/routes/api/stats.d.ts.map +1 -0
- package/dist/routes/api/stats.js +52 -0
- package/dist/routes/api/stats.js.map +1 -0
- package/dist/routes/api/tokens.d.ts +39 -0
- package/dist/routes/api/tokens.d.ts.map +1 -0
- package/dist/routes/api/tokens.js +191 -0
- package/dist/routes/api/tokens.js.map +1 -0
- package/dist/routes/api/users.d.ts +5 -0
- package/dist/routes/api/users.d.ts.map +1 -0
- package/dist/routes/api/users.js +125 -0
- package/dist/routes/api/users.js.map +1 -0
- package/dist/routes/composer.d.ts +133 -0
- package/dist/routes/composer.d.ts.map +1 -0
- package/dist/routes/composer.js +1179 -0
- package/dist/routes/composer.js.map +1 -0
- package/dist/routes/dist.d.ts +32 -0
- package/dist/routes/dist.d.ts.map +1 -0
- package/dist/routes/dist.js +761 -0
- package/dist/routes/dist.js.map +1 -0
- package/dist/routes/health.d.ts +7 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +22 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/index.d.ts +5 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +6 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/services/EmailService.d.ts +20 -0
- package/dist/services/EmailService.d.ts.map +1 -0
- package/dist/services/EmailService.js +27 -0
- package/dist/services/EmailService.js.map +1 -0
- package/dist/services/UserService.d.ts +27 -0
- package/dist/services/UserService.d.ts.map +1 -0
- package/dist/services/UserService.js +164 -0
- package/dist/services/UserService.js.map +1 -0
- package/dist/storage/driver.d.ts +65 -0
- package/dist/storage/driver.d.ts.map +1 -0
- package/dist/storage/driver.js +59 -0
- package/dist/storage/driver.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +5 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/r2-driver.d.ts +16 -0
- package/dist/storage/r2-driver.d.ts.map +1 -0
- package/dist/storage/r2-driver.js +28 -0
- package/dist/storage/r2-driver.js.map +1 -0
- package/dist/storage/s3-driver.d.ts +22 -0
- package/dist/storage/s3-driver.d.ts.map +1 -0
- package/dist/storage/s3-driver.js +66 -0
- package/dist/storage/s3-driver.js.map +1 -0
- package/dist/sync/github-sync.d.ts +15 -0
- package/dist/sync/github-sync.d.ts.map +1 -0
- package/dist/sync/github-sync.js +39 -0
- package/dist/sync/github-sync.js.map +1 -0
- package/dist/sync/index.d.ts +5 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +6 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/repository-sync.d.ts +18 -0
- package/dist/sync/repository-sync.d.ts.map +1 -0
- package/dist/sync/repository-sync.js +214 -0
- package/dist/sync/repository-sync.js.map +1 -0
- package/dist/sync/strategies/composer-repo.d.ts +11 -0
- package/dist/sync/strategies/composer-repo.d.ts.map +1 -0
- package/dist/sync/strategies/composer-repo.js +269 -0
- package/dist/sync/strategies/composer-repo.js.map +1 -0
- package/dist/sync/strategies/github-api.d.ts +6 -0
- package/dist/sync/strategies/github-api.d.ts.map +1 -0
- package/dist/sync/strategies/github-api.js +137 -0
- package/dist/sync/strategies/github-api.js.map +1 -0
- package/dist/sync/strategies/github-packages.d.ts +7 -0
- package/dist/sync/strategies/github-packages.d.ts.map +1 -0
- package/dist/sync/strategies/github-packages.js +66 -0
- package/dist/sync/strategies/github-packages.js.map +1 -0
- package/dist/sync/strategies/index.d.ts +4 -0
- package/dist/sync/strategies/index.d.ts.map +1 -0
- package/dist/sync/strategies/index.js +5 -0
- package/dist/sync/strategies/index.js.map +1 -0
- package/dist/sync/types.d.ts +60 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +3 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/utils/analytics.d.ts +142 -0
- package/dist/utils/analytics.d.ts.map +1 -0
- package/dist/utils/analytics.js +229 -0
- package/dist/utils/analytics.js.map +1 -0
- package/dist/utils/download.d.ts +10 -0
- package/dist/utils/download.d.ts.map +1 -0
- package/dist/utils/download.js +34 -0
- package/dist/utils/download.js.map +1 -0
- package/dist/utils/encryption.d.ts +20 -0
- package/dist/utils/encryption.d.ts.map +1 -0
- package/dist/utils/encryption.js +76 -0
- package/dist/utils/encryption.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +78 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +134 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/upstream-fetch.d.ts +15 -0
- package/dist/utils/upstream-fetch.d.ts.map +1 -0
- package/dist/utils/upstream-fetch.js +108 -0
- package/dist/utils/upstream-fetch.js.map +1 -0
- package/dist/workflows/index.d.ts +3 -0
- package/dist/workflows/index.d.ts.map +1 -0
- package/dist/workflows/index.js +8 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/package-storage.d.ts +47 -0
- package/dist/workflows/package-storage.d.ts.map +1 -0
- package/dist/workflows/package-storage.js +136 -0
- package/dist/workflows/package-storage.js.map +1 -0
- 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":"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"}
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/dist/ports.d.ts
ADDED
|
@@ -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 @@
|
|
|
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
|