-1
CHANGELOG.md
-1
CHANGELOG.md
+15
-37
src/pds.js
+15
-37
src/pds.js
···
64
// Default Bluesky AppView URL
65
const BSKY_APPVIEW_URL = 'https://api.bsky.app';
66
67
-
// Cache for registered DIDs lookup (avoids repeated internal fetches)
68
-
const REGISTERED_DIDS_CACHE_TTL = 30 * 1000; // 30 seconds
69
-
/** @type {{ dids: string[], timestamp: number } | null} */
70
-
let registeredDidsCache = null;
71
-
72
/**
73
* Cloudflare Workers environment bindings
74
* @typedef {Object} Env
···
273
});
274
} catch (err) {
275
const message = err instanceof Error ? err.message : String(err);
276
-
return errorResponse('UpstreamFailure', `Failed to reach service: ${message}`, 502);
277
}
278
}
279
···
285
function getDefaultPds(env) {
286
const id = env.PDS.idFromName('default');
287
return env.PDS.get(id);
288
-
}
289
-
290
-
/**
291
-
* Check if a DID is registered on this PDS (with caching)
292
-
* @param {Env} env
293
-
* @param {string} did
294
-
* @returns {Promise<boolean>}
295
-
*/
296
-
async function isLocalDid(env, did) {
297
-
const now = Date.now();
298
-
// Use cache if fresh
299
-
if (
300
-
registeredDidsCache &&
301
-
now - registeredDidsCache.timestamp < REGISTERED_DIDS_CACHE_TTL
302
-
) {
303
-
return registeredDidsCache.dids.includes(did);
304
-
}
305
-
306
-
// Fetch fresh list
307
-
const defaultPds = getDefaultPds(env);
308
-
const res = await defaultPds.fetch(
309
-
new Request('http://internal/get-registered-dids'),
310
-
);
311
-
if (!res.ok) return false;
312
-
const { dids } = await res.json();
313
-
314
-
// Update cache
315
-
registeredDidsCache = { dids, timestamp: now };
316
-
return dids.includes(did);
317
}
318
319
/**
···
5280
const parsed = parseAtprotoProxyHeader(proxyHeader);
5281
if (!parsed) {
5282
// Header present but malformed
5283
-
return errorResponse('InvalidRequest', `Malformed atproto-proxy header: ${proxyHeader}`, 400);
5284
}
5285
const serviceUrl = getKnownServiceUrl(parsed.did, parsed.serviceId);
5286
if (serviceUrl) {
5287
return proxyToService(request, serviceUrl);
5288
}
5289
// Unknown service - could add DID resolution here in the future
5290
-
return errorResponse('InvalidRequest', `Unknown proxy service: ${proxyHeader}`, 400);
5291
}
5292
5293
// No proxy header - handle locally (returns appropriate error if DID not found)
···
64
// Default Bluesky AppView URL
65
const BSKY_APPVIEW_URL = 'https://api.bsky.app';
66
67
/**
68
* Cloudflare Workers environment bindings
69
* @typedef {Object} Env
···
268
});
269
} catch (err) {
270
const message = err instanceof Error ? err.message : String(err);
271
+
return errorResponse(
272
+
'UpstreamFailure',
273
+
`Failed to reach service: ${message}`,
274
+
502,
275
+
);
276
}
277
}
278
···
284
function getDefaultPds(env) {
285
const id = env.PDS.idFromName('default');
286
return env.PDS.get(id);
287
}
288
289
/**
···
5250
const parsed = parseAtprotoProxyHeader(proxyHeader);
5251
if (!parsed) {
5252
// Header present but malformed
5253
+
return errorResponse(
5254
+
'InvalidRequest',
5255
+
`Malformed atproto-proxy header: ${proxyHeader}`,
5256
+
400,
5257
+
);
5258
}
5259
const serviceUrl = getKnownServiceUrl(parsed.did, parsed.serviceId);
5260
if (serviceUrl) {
5261
return proxyToService(request, serviceUrl);
5262
}
5263
// Unknown service - could add DID resolution here in the future
5264
+
return errorResponse(
5265
+
'InvalidRequest',
5266
+
`Unknown proxy service: ${proxyHeader}`,
5267
+
400,
5268
+
);
5269
}
5270
5271
// No proxy header - handle locally (returns appropriate error if DID not found)
+4
-1
test/e2e.test.js
+4
-1
test/e2e.test.js
···
1472
);
1473
// Verify we got a JSON response (not an error page)
1474
const contentType = res.headers.get('content-type');
1475
-
assert.ok(contentType?.includes('application/json'), 'Should return JSON');
1476
});
1477
1478
it('handles foreign repo locally without header (returns not found)', async () => {
···
1472
);
1473
// Verify we got a JSON response (not an error page)
1474
const contentType = res.headers.get('content-type');
1475
+
assert.ok(
1476
+
contentType?.includes('application/json'),
1477
+
'Should return JSON',
1478
+
);
1479
});
1480
1481
it('handles foreign repo locally without header (returns not found)', async () => {
+6
-9
test/pds.test.js
+6
-9
test/pds.test.js
···
867
});
868
869
test('returns null for header without fragment', () => {
870
-
assert.strictEqual(
871
-
parseAtprotoProxyHeader('did:web:api.bsky.app'),
872
-
null,
873
-
);
874
});
875
876
test('returns null for header with only fragment', () => {
···
878
});
879
880
test('returns null for header with trailing fragment', () => {
881
-
assert.strictEqual(parseAtprotoProxyHeader('did:web:api.bsky.app#'), null);
882
});
883
});
884
885
describe('getKnownServiceUrl', () => {
886
test('returns URL for known Bluesky AppView', () => {
887
-
const result = getKnownServiceUrl(
888
-
'did:web:api.bsky.app',
889
-
'bsky_appview',
890
-
);
891
assert.strictEqual(result, BSKY_APPVIEW_URL);
892
});
893
···
867
});
868
869
test('returns null for header without fragment', () => {
870
+
assert.strictEqual(parseAtprotoProxyHeader('did:web:api.bsky.app'), null);
871
});
872
873
test('returns null for header with only fragment', () => {
···
875
});
876
877
test('returns null for header with trailing fragment', () => {
878
+
assert.strictEqual(
879
+
parseAtprotoProxyHeader('did:web:api.bsky.app#'),
880
+
null,
881
+
);
882
});
883
});
884
885
describe('getKnownServiceUrl', () => {
886
test('returns URL for known Bluesky AppView', () => {
887
+
const result = getKnownServiceUrl('did:web:api.bsky.app', 'bsky_appview');
888
assert.strictEqual(result, BSKY_APPVIEW_URL);
889
});
890