@alteran/astro 0.1.3 → 0.1.5

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 (32) hide show
  1. package/README.md +24 -3
  2. package/index.js +1 -12
  3. package/package.json +5 -1
  4. package/src/_worker.ts +3 -40
  5. package/src/pages/debug/db/commits.ts +1 -1
  6. package/src/pages/debug/gc/blobs.ts +1 -1
  7. package/src/pages/debug/record.ts +1 -1
  8. package/src/pages/xrpc/com.atproto.identity.updateHandle.ts +1 -1
  9. package/src/pages/xrpc/com.atproto.repo.applyWrites.ts +3 -3
  10. package/src/pages/xrpc/com.atproto.repo.createRecord.ts +5 -5
  11. package/src/pages/xrpc/com.atproto.repo.deleteRecord.ts +5 -5
  12. package/src/pages/xrpc/com.atproto.repo.describeRepo.ts +1 -1
  13. package/src/pages/xrpc/com.atproto.repo.getRecord.ts +1 -1
  14. package/src/pages/xrpc/com.atproto.repo.listRecords.ts +1 -1
  15. package/src/pages/xrpc/com.atproto.repo.putRecord.ts +5 -5
  16. package/src/pages/xrpc/com.atproto.repo.uploadBlob.ts +5 -5
  17. package/src/pages/xrpc/com.atproto.server.createSession.ts +3 -3
  18. package/src/pages/xrpc/com.atproto.server.refreshSession.ts +4 -4
  19. package/src/pages/xrpc/com.atproto.sync.getBlocks.json.ts +2 -2
  20. package/src/pages/xrpc/com.atproto.sync.getBlocks.ts +3 -3
  21. package/src/pages/xrpc/com.atproto.sync.getCheckout.json.ts +3 -3
  22. package/src/pages/xrpc/com.atproto.sync.getCheckout.ts +1 -1
  23. package/src/pages/xrpc/com.atproto.sync.getHead.ts +1 -1
  24. package/src/pages/xrpc/com.atproto.sync.getLatestCommit.ts +1 -1
  25. package/src/pages/xrpc/com.atproto.sync.getRecord.ts +2 -2
  26. package/src/pages/xrpc/com.atproto.sync.getRepo.json.ts +3 -3
  27. package/src/pages/xrpc/com.atproto.sync.getRepo.range.ts +1 -1
  28. package/src/pages/xrpc/com.atproto.sync.getRepo.ts +1 -1
  29. package/src/pages/xrpc/com.atproto.sync.listBlobs.ts +1 -1
  30. package/src/worker/index.ts +6 -0
  31. package/src/worker/runtime.ts +63 -0
  32. package/types/worker.d.ts +5 -0
package/README.md CHANGED
@@ -27,19 +27,40 @@ By default the integration injects all `/xrpc/*` ATProto routes, health/ready ch
27
27
  alteran({
28
28
  debugRoutes: process.env.NODE_ENV !== 'production',
29
29
  includeRootEndpoint: false,
30
- injectServerEntry: true,
30
+ injectServerEntry: true, // opt in if you don't maintain your own worker entrypoint
31
31
  });
32
32
  ```
33
33
 
34
34
  The integration automatically:
35
- - Adds a Vite alias of `@alteran/*` that points to the package runtime
35
+ - Resolves all injected routes against the packaged runtime without requiring a Vite alias
36
36
  - Registers the middleware that applies structured logging and CORS enforcement
37
37
  - Injects all PDS HTTP endpoints into the host project
38
- - Sets `build.serverEntry` to the packaged Cloudflare worker (unless you opt out)
38
+ - Offers the packaged Cloudflare worker entrypoint when you enable `{ injectServerEntry: true }`
39
39
  - Publishes ambient env typings so `Env` and `App.Locals` are available from TypeScript
40
40
 
41
41
  When deploying, continue to configure Wrangler/D1/R2 secrets exactly as before—the integration does not change the runtime requirements.
42
42
 
43
+ ### Custom Worker Entrypoint
44
+
45
+ The integration no longer overrides `build.serverEntry` by default. If you need to export additional Durable Objects or otherwise customise the worker, keep your own entrypoint and compose Alteran's runtime helpers instead of copying the internal logic.
46
+
47
+ ```ts
48
+ // src/_worker.ts in your Astro project
49
+ import { createPdsFetchHandler, Sequencer } from '@alteran/astro/worker';
50
+
51
+ const fetch = createPdsFetchHandler();
52
+
53
+ export default { fetch };
54
+
55
+ // Re-export Sequencer so Wrangler can bind the Durable Object namespace
56
+ export { Sequencer };
57
+
58
+ // Export any additional Durable Objects after this line
59
+ export { MyDurableObject } from './worker/my-durable-object';
60
+ ```
61
+
62
+ Helpers like `onRequest`, `seed`, and `validateConfigOrThrow` are also exported from `@alteran/astro/worker` if you need to build more advanced wrappers (for example, to add request instrumentation before delegating to the PDS handler).
63
+
43
64
  To install dependencies:
44
65
 
45
66
  ```bash
package/index.js CHANGED
@@ -56,10 +56,9 @@ export default function alteran(options = {}) {
56
56
  const {
57
57
  debugRoutes = false,
58
58
  includeRootEndpoint = false,
59
- injectServerEntry = true,
59
+ injectServerEntry = false,
60
60
  } = options;
61
61
 
62
- const aliasTarget = resolvePackagePath('./src');
63
62
  const middlewareEntrypoint = resolvePackagePath('./src/middleware.ts');
64
63
  const serverEntrypoint = resolvePackagePath('./src/_worker.ts');
65
64
 
@@ -79,16 +78,6 @@ export default function alteran(options = {}) {
79
78
  updateConfig({ output: 'server' });
80
79
  }
81
80
 
82
- updateConfig({
83
- vite: {
84
- resolve: {
85
- alias: {
86
- '@alteran': aliasTarget,
87
- },
88
- },
89
- },
90
- });
91
-
92
81
  if (injectServerEntry) {
93
82
  if (config.build?.serverEntry && config.build.serverEntry !== serverEntrypoint) {
94
83
  logger.info(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alteran/astro",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Astro integration for running a Cloudflare-hosted Bluesky PDS with Alteran.",
5
5
  "module": "index.js",
6
6
  "types": "index.d.ts",
@@ -8,6 +8,10 @@
8
8
  ".": {
9
9
  "types": "./index.d.ts",
10
10
  "import": "./index.js"
11
+ },
12
+ "./worker": {
13
+ "types": "./types/worker.d.ts",
14
+ "import": "./src/worker/index.ts"
11
15
  }
12
16
  },
13
17
  "type": "module",
package/src/_worker.ts CHANGED
@@ -1,44 +1,7 @@
1
- import { handle } from 'astro/internal/handler';
2
- import { onRequest } from './middleware';
3
- import { seed } from './db/seed';
4
- import { validateConfigOrThrow } from './lib/config';
5
- import type { Env } from './env';
1
+ import { createPdsFetchHandler } from './worker/runtime';
6
2
 
7
- export default {
8
- async fetch(request: Request, env: Env, ctx: ExecutionContext) {
9
- // Validate configuration on startup (fail fast if invalid)
10
- try {
11
- validateConfigOrThrow(env);
12
- } catch (error) {
13
- return new Response(
14
- JSON.stringify({
15
- error: 'ConfigurationError',
16
- message: error instanceof Error ? error.message : 'Invalid configuration',
17
- }),
18
- {
19
- status: 500,
20
- headers: { 'Content-Type': 'application/json' },
21
- }
22
- );
23
- }
3
+ const fetch = createPdsFetchHandler();
24
4
 
25
- await seed(env.DB, env.PDS_DID ?? 'did:example:single-user');
5
+ export default { fetch };
26
6
 
27
- const url = new URL(request.url);
28
- if (url.pathname === '/xrpc/com.atproto.sync.subscribeRepos') {
29
- const upgrade = request.headers.get('upgrade');
30
- if (upgrade !== 'websocket') return new Response('Expected websocket', { status: 426 });
31
- if (!env.SEQUENCER) return new Response('Sequencer not configured', { status: 503 });
32
-
33
- const id = env.SEQUENCER.idFromName('default');
34
- const stub = env.SEQUENCER.get(id);
35
- return stub.fetch(request as any);
36
- }
37
-
38
- const locals: any = { runtime: { env, ctx, request } };
39
- return await onRequest(locals as any, async () => await handle(locals as any));
40
- },
41
- };
42
-
43
- // Export Durable Object(s)
44
7
  export { Sequencer } from './worker/sequencer';
@@ -1,6 +1,6 @@
1
1
  import type { APIContext } from 'astro';
2
2
  import { drizzle } from 'drizzle-orm/d1';
3
- import { commit_log } from '@alteran/db/schema';
3
+ import { commit_log } from '../../../db/schema';
4
4
  import { desc } from 'drizzle-orm';
5
5
 
6
6
  export const prerender = false;
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { listOrphanBlobKeys, deleteBlobByKey } from '@alteran/db/dal';
2
+ import { listOrphanBlobKeys, deleteBlobByKey } from '../../../db/dal';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRecord as dalGetRecord, putRecord as dalPutRecord } from '@alteran/db/dal';
2
+ import { getRecord as dalGetRecord, putRecord as dalPutRecord } from '../../db/dal';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { readJson } from '@alteran/lib/util';
2
+ import { readJson } from '../../lib/util';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,7 +1,7 @@
1
1
  import type { APIContext } from 'astro';
2
- import { RepoManager } from '@alteran/services/repo-manager';
3
- import { readJson } from '@alteran/lib/util';
4
- import { bumpRoot } from '@alteran/db/repo';
2
+ import { RepoManager } from '../../services/repo-manager';
3
+ import { readJson } from '../../lib/util';
4
+ import { bumpRoot } from '../../db/repo';
5
5
 
6
6
  export const prerender = false;
7
7
 
@@ -1,9 +1,9 @@
1
1
  import type { APIContext } from 'astro';
2
- import { isAuthorized, unauthorized } from '@alteran/lib/auth';
3
- import { checkRate } from '@alteran/lib/ratelimit';
4
- import { readJsonBounded } from '@alteran/lib/util';
5
- import { RepoManager } from '@alteran/services/repo-manager';
6
- import { notifySequencer } from '@alteran/lib/sequencer';
2
+ import { isAuthorized, unauthorized } from '../../lib/auth';
3
+ import { checkRate } from '../../lib/ratelimit';
4
+ import { readJsonBounded } from '../../lib/util';
5
+ import { RepoManager } from '../../services/repo-manager';
6
+ import { notifySequencer } from '../../lib/sequencer';
7
7
 
8
8
  export const prerender = false;
9
9
 
@@ -1,9 +1,9 @@
1
1
  import type { APIContext } from 'astro';
2
- import { isAuthorized, unauthorized } from '@alteran/lib/auth';
3
- import { checkRate } from '@alteran/lib/ratelimit';
4
- import { readJsonBounded } from '@alteran/lib/util';
5
- import { RepoManager } from '@alteran/services/repo-manager';
6
- import { notifySequencer } from '@alteran/lib/sequencer';
2
+ import { isAuthorized, unauthorized } from '../../lib/auth';
3
+ import { checkRate } from '../../lib/ratelimit';
4
+ import { readJsonBounded } from '../../lib/util';
5
+ import { RepoManager } from '../../services/repo-manager';
6
+ import { notifySequencer } from '../../lib/sequencer';
7
7
 
8
8
  export const prerender = false;
9
9
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRoot } from '@alteran/db/repo';
2
+ import { getRoot } from '../../db/repo';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRecord as dalGetRecord } from '@alteran/db/dal';
2
+ import { getRecord as dalGetRecord } from '../../db/dal';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { RepoManager } from '@alteran/services/repo-manager';
2
+ import { RepoManager } from '../../services/repo-manager';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,9 +1,9 @@
1
1
  import type { APIContext } from 'astro';
2
- import { isAuthorized, unauthorized } from '@alteran/lib/auth';
3
- import { checkRate } from '@alteran/lib/ratelimit';
4
- import { readJsonBounded } from '@alteran/lib/util';
5
- import { RepoManager } from '@alteran/services/repo-manager';
6
- import { notifySequencer } from '@alteran/lib/sequencer';
2
+ import { isAuthorized, unauthorized } from '../../lib/auth';
3
+ import { checkRate } from '../../lib/ratelimit';
4
+ import { readJsonBounded } from '../../lib/util';
5
+ import { RepoManager } from '../../services/repo-manager';
6
+ import { notifySequencer } from '../../lib/sequencer';
7
7
 
8
8
  export const prerender = false;
9
9
 
@@ -1,9 +1,9 @@
1
1
  import type { APIContext } from 'astro';
2
- import { isAuthorized, unauthorized } from '@alteran/lib/auth';
3
- import { checkRate } from '@alteran/lib/ratelimit';
4
- import { isAllowedMime } from '@alteran/lib/util';
5
- import { R2BlobStore } from '@alteran/services/r2-blob-store';
6
- import { putBlobRef, checkBlobQuota, updateBlobQuota } from '@alteran/db/dal';
2
+ import { isAuthorized, unauthorized } from '../../lib/auth';
3
+ import { checkRate } from '../../lib/ratelimit';
4
+ import { isAllowedMime } from '../../lib/util';
5
+ import { R2BlobStore } from '../../services/r2-blob-store';
6
+ import { putBlobRef, checkBlobQuota, updateBlobQuota } from '../../db/dal';
7
7
 
8
8
  export const prerender = false;
9
9
 
@@ -1,8 +1,8 @@
1
1
  import type { APIContext } from 'astro';
2
- import { signJwt } from '@alteran/lib/jwt';
3
- import { readJson } from '@alteran/lib/util';
2
+ import { signJwt } from '../../lib/jwt';
3
+ import { readJson } from '../../lib/util';
4
4
  import { drizzle } from 'drizzle-orm/d1';
5
- import { login_attempts } from '@alteran/db/schema';
5
+ import { login_attempts } from '../../db/schema';
6
6
  import { eq } from 'drizzle-orm';
7
7
 
8
8
  export const prerender = false;
@@ -1,9 +1,9 @@
1
1
  import type { APIContext } from 'astro';
2
- import { signJwt, verifyJwt } from '@alteran/lib/jwt';
3
- import { bearerToken } from '@alteran/lib/util';
4
- import { lazyCleanupExpiredTokens } from '@alteran/lib/token-cleanup';
2
+ import { signJwt, verifyJwt } from '../../lib/jwt';
3
+ import { bearerToken } from '../../lib/util';
4
+ import { lazyCleanupExpiredTokens } from '../../lib/token-cleanup';
5
5
  import { drizzle } from 'drizzle-orm/d1';
6
- import { token_revocation } from '@alteran/db/schema';
6
+ import { token_revocation } from '../../db/schema';
7
7
  import { eq } from 'drizzle-orm';
8
8
 
9
9
  export const prerender = false;
@@ -1,6 +1,6 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRecordsByCids as dalGetByCids } from '@alteran/db/dal';
3
- import { tryParse } from '@alteran/lib/util';
2
+ import { getRecordsByCids as dalGetByCids } from '../../db/dal';
3
+ import { tryParse } from '../../lib/util';
4
4
 
5
5
  export const prerender = false;
6
6
 
@@ -1,8 +1,8 @@
1
1
  import type { APIContext } from 'astro';
2
- import { NotFound } from '@alteran/lib/errors';
3
- import { D1Blockstore } from '@alteran/lib/mst';
2
+ import { NotFound } from '../../lib/errors';
3
+ import { D1Blockstore } from '../../lib/mst';
4
4
  import { CID } from 'multiformats/cid';
5
- import { encodeExistingBlocksToCAR } from '@alteran/services/car';
5
+ import { encodeExistingBlocksToCAR } from '../../services/car';
6
6
 
7
7
  export const prerender = false;
8
8
 
@@ -1,7 +1,7 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRoot as getRepoRoot } from '@alteran/db/repo';
3
- import { listRecords as dalListRecords } from '@alteran/db/dal';
4
- import { tryParse } from '@alteran/lib/util';
2
+ import { getRoot as getRepoRoot } from '../../db/repo';
3
+ import { listRecords as dalListRecords } from '../../db/dal';
4
+ import { tryParse } from '../../lib/util';
5
5
 
6
6
  export const prerender = false;
7
7
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { buildRepoCar, buildRepoCarRange } from '@alteran/services/car';
2
+ import { buildRepoCar, buildRepoCarRange } from '../../services/car';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRoot as getRepoRoot } from '@alteran/db/repo';
2
+ import { getRoot as getRepoRoot } from '../../db/repo';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRoot } from '@alteran/db/repo';
2
+ import { getRoot } from '../../db/repo';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,6 +1,6 @@
1
1
  import type { APIContext } from 'astro';
2
- import { RepoManager } from '@alteran/services/repo-manager';
3
- import { encodeRecordBlock } from '@alteran/services/car';
2
+ import { RepoManager } from '../../services/repo-manager';
3
+ import { encodeRecordBlock } from '../../services/car';
4
4
  import * as dagCbor from '@ipld/dag-cbor';
5
5
  import { CID } from 'multiformats/cid';
6
6
  import { sha256 } from 'multiformats/hashes/sha2';
@@ -1,7 +1,7 @@
1
1
  import type { APIContext } from 'astro';
2
- import { getRoot as getRepoRoot } from '@alteran/db/repo';
3
- import { listRecords as dalListRecords } from '@alteran/db/dal';
4
- import { tryParse } from '@alteran/lib/util';
2
+ import { getRoot as getRepoRoot } from '../../db/repo';
3
+ import { listRecords as dalListRecords } from '../../db/dal';
4
+ import { tryParse } from '../../lib/util';
5
5
 
6
6
  export const prerender = false;
7
7
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { buildRepoCarRange } from '@alteran/services/car';
2
+ import { buildRepoCarRange } from '../../services/car';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { APIContext } from 'astro';
2
- import { buildRepoCar } from '@alteran/services/car';
2
+ import { buildRepoCar } from '../../services/car';
3
3
 
4
4
  export const prerender = false;
5
5
 
@@ -1,6 +1,6 @@
1
1
  import type { APIContext } from 'astro';
2
2
  import { drizzle } from 'drizzle-orm/d1';
3
- import { blob_ref } from '@alteran/db/schema';
3
+ import { blob_ref } from '../../db/schema';
4
4
  import { eq, gt, and } from 'drizzle-orm';
5
5
 
6
6
  export const prerender = false;
@@ -0,0 +1,6 @@
1
+ export { createPdsFetchHandler } from './runtime';
2
+ export type { PdsFetchHandler } from './runtime';
3
+ export { Sequencer } from './sequencer';
4
+ export { onRequest } from '../middleware';
5
+ export { seed } from '../db/seed';
6
+ export { validateConfigOrThrow } from '../lib/config';
@@ -0,0 +1,63 @@
1
+ import { handle } from 'astro/internal/handler';
2
+ import { onRequest } from '../middleware';
3
+ import { seed } from '../db/seed';
4
+ import { validateConfigOrThrow } from '../lib/config';
5
+ import type { Env } from '../env';
6
+ import type {
7
+ ExecutionContext,
8
+ Request as WorkersRequest,
9
+ Response as WorkersResponse,
10
+ } from '@cloudflare/workers-types';
11
+
12
+ export type PdsFetchHandler = (
13
+ request: WorkersRequest,
14
+ env: Env,
15
+ ctx: ExecutionContext
16
+ ) => Promise<WorkersResponse>;
17
+
18
+ /**
19
+ * Returns the Alteran PDS Worker fetch handler so downstream apps can
20
+ * compose it inside their own Cloudflare Worker entrypoint.
21
+ */
22
+ export function createPdsFetchHandler(): PdsFetchHandler {
23
+ return async function fetch(request: WorkersRequest, env: Env, ctx: ExecutionContext) {
24
+ try {
25
+ validateConfigOrThrow(env);
26
+ } catch (error) {
27
+ return new Response(
28
+ JSON.stringify({
29
+ error: 'ConfigurationError',
30
+ message: error instanceof Error ? error.message : 'Invalid configuration',
31
+ }),
32
+ {
33
+ status: 500,
34
+ headers: { 'Content-Type': 'application/json' },
35
+ }
36
+ ) as unknown as WorkersResponse;
37
+ }
38
+
39
+ await seed(env.DB, env.PDS_DID ?? 'did:example:single-user');
40
+
41
+ const url = new URL(request.url);
42
+ if (url.pathname === '/xrpc/com.atproto.sync.subscribeRepos') {
43
+ const upgrade = request.headers.get('upgrade');
44
+ if (upgrade !== 'websocket') {
45
+ return new Response('Expected websocket', { status: 426 }) as unknown as WorkersResponse;
46
+ }
47
+ if (!env.SEQUENCER) {
48
+ return new Response('Sequencer not configured', { status: 503 }) as unknown as WorkersResponse;
49
+ }
50
+
51
+ const id = env.SEQUENCER.idFromName('default');
52
+ const stub = env.SEQUENCER.get(id);
53
+ return (await stub.fetch(request as any)) as unknown as WorkersResponse;
54
+ }
55
+
56
+ const locals: any = { runtime: { env, ctx, request } };
57
+ return (await onRequest(locals as any, async () => await handle(locals as any))) as unknown as WorkersResponse;
58
+ };
59
+ }
60
+
61
+ export { onRequest };
62
+ export { seed };
63
+ export { validateConfigOrThrow };
@@ -0,0 +1,5 @@
1
+ export { createPdsFetchHandler, type PdsFetchHandler } from '../src/worker/runtime';
2
+ export { Sequencer } from '../src/worker/sequencer';
3
+ export { onRequest } from '../src/middleware';
4
+ export { seed } from '../src/db/seed';
5
+ export { validateConfigOrThrow } from '../src/lib/config';