@alteran/astro 0.7.7 → 0.8.2

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 (73) hide show
  1. package/README.md +25 -25
  2. package/migrations/0010_eminent_klaw.sql +37 -0
  3. package/migrations/0011_chief_darwin.sql +31 -0
  4. package/migrations/0012_backfill_blob_usage.sql +39 -0
  5. package/migrations/meta/0010_snapshot.json +790 -0
  6. package/migrations/meta/0011_snapshot.json +813 -0
  7. package/migrations/meta/_journal.json +22 -1
  8. package/package.json +24 -41
  9. package/src/db/blob.ts +323 -0
  10. package/src/db/dal.ts +224 -78
  11. package/src/db/repo.ts +205 -25
  12. package/src/db/schema.ts +14 -5
  13. package/src/handlers/debug.ts +4 -3
  14. package/src/lib/appview/auth-policy.ts +7 -24
  15. package/src/lib/appview/proxy.ts +56 -23
  16. package/src/lib/appview/types.ts +1 -6
  17. package/src/lib/auth-scope.ts +399 -0
  18. package/src/lib/auth.ts +40 -39
  19. package/src/lib/commit.ts +37 -15
  20. package/src/lib/did-document.ts +4 -5
  21. package/src/lib/jwt.ts +3 -1
  22. package/src/lib/mime.ts +9 -0
  23. package/src/lib/oauth/resource.ts +49 -0
  24. package/src/lib/preference-policy.ts +45 -0
  25. package/src/lib/preferences.ts +0 -4
  26. package/src/lib/public-host.ts +127 -0
  27. package/src/lib/ratelimit.ts +37 -12
  28. package/src/lib/relay.ts +7 -27
  29. package/src/lib/repo-write-blob-constraints.ts +141 -0
  30. package/src/lib/repo-write-data.ts +195 -0
  31. package/src/lib/repo-write-error.ts +46 -0
  32. package/src/lib/repo-write-validation.ts +463 -0
  33. package/src/lib/session-tokens.ts +22 -5
  34. package/src/lib/unsupported-routes.ts +32 -0
  35. package/src/lib/util.ts +57 -2
  36. package/src/pages/.well-known/atproto-did.ts +15 -3
  37. package/src/pages/.well-known/did.json.ts +13 -7
  38. package/src/pages/debug/db/bootstrap.ts +4 -3
  39. package/src/pages/debug/gc/blobs.ts +11 -8
  40. package/src/pages/debug/record.ts +11 -0
  41. package/src/pages/xrpc/[...nsid].ts +17 -9
  42. package/src/pages/xrpc/app.bsky.actor.getPreferences.ts +9 -3
  43. package/src/pages/xrpc/app.bsky.actor.putPreferences.ts +17 -4
  44. package/src/pages/xrpc/app.bsky.unspecced.getAgeAssuranceState.ts +4 -2
  45. package/src/pages/xrpc/chat.bsky.convo.getLog.ts +4 -2
  46. package/src/pages/xrpc/chat.bsky.convo.listConvos.ts +4 -2
  47. package/src/pages/xrpc/com.atproto.identity.getRecommendedDidCredentials.ts +10 -6
  48. package/src/pages/xrpc/com.atproto.identity.requestPlcOperationSignature.ts +4 -3
  49. package/src/pages/xrpc/com.atproto.identity.resolveHandle.ts +13 -5
  50. package/src/pages/xrpc/com.atproto.identity.signPlcOperation.ts +4 -2
  51. package/src/pages/xrpc/com.atproto.identity.submitPlcOperation.ts +4 -2
  52. package/src/pages/xrpc/com.atproto.identity.updateHandle.ts +12 -36
  53. package/src/pages/xrpc/com.atproto.repo.applyWrites.ts +90 -139
  54. package/src/pages/xrpc/com.atproto.repo.createRecord.ts +74 -47
  55. package/src/pages/xrpc/com.atproto.repo.deleteRecord.ts +119 -46
  56. package/src/pages/xrpc/com.atproto.repo.describeRepo.ts +21 -20
  57. package/src/pages/xrpc/com.atproto.repo.getRecord.ts +6 -1
  58. package/src/pages/xrpc/com.atproto.repo.listMissingBlobs.ts +4 -2
  59. package/src/pages/xrpc/com.atproto.repo.putRecord.ts +84 -47
  60. package/src/pages/xrpc/com.atproto.repo.uploadBlob.ts +199 -78
  61. package/src/pages/xrpc/com.atproto.server.checkAccountStatus.ts +4 -2
  62. package/src/pages/xrpc/com.atproto.server.getServiceAuth.ts +88 -21
  63. package/src/pages/xrpc/com.atproto.server.getSession.ts +3 -13
  64. package/src/pages/xrpc/com.atproto.sync.getBlob.ts +92 -74
  65. package/src/pages/xrpc/com.atproto.sync.listBlobs.ts +45 -23
  66. package/src/services/car.ts +13 -0
  67. package/src/services/repo/apply-prepared-writes.ts +185 -0
  68. package/src/services/repo/blob-refs.ts +48 -0
  69. package/src/services/repo/blockstore-ops.ts +59 -17
  70. package/src/services/repo/list-blobs.ts +43 -0
  71. package/src/services/repo-manager.ts +221 -78
  72. package/src/worker/runtime.ts +1 -1
  73. package/src/worker/sequencer/upgrade.ts +4 -1
package/README.md CHANGED
@@ -9,8 +9,8 @@ This repository now ships an Astro integration that turns any Cloudflare Worker-
9
9
 
10
10
  ```bash
11
11
  npm install @alteran/astro
12
- # or
13
- bun add @alteran/astro
12
+ # or, in a Deno project
13
+ deno add npm:@alteran/astro
14
14
  ```
15
15
 
16
16
  ```ts
@@ -67,26 +67,26 @@ Helpers like `onRequest`, `seed`, and `validateConfigOrThrow` are also exported
67
67
  To install dependencies:
68
68
 
69
69
  ```bash
70
- bun install
70
+ deno install
71
71
  ```
72
72
 
73
73
  Dev server (Vite dev):
74
74
 
75
75
  ```bash
76
- bun run dev
76
+ deno task dev
77
77
  ```
78
78
 
79
79
  Cloudflare local dev (optional):
80
80
 
81
81
  ```bash
82
- bunx wrangler dev --local
82
+ deno run -A npm:wrangler dev --local
83
83
  ```
84
84
 
85
85
  Build and deploy:
86
86
 
87
87
  ```bash
88
- bun run build
89
- bun run deploy
88
+ deno task build
89
+ deno task deploy
90
90
  ```
91
91
 
92
92
  Health endpoints: `GET /health` and `GET /ready` return `200 ok`.
@@ -105,7 +105,7 @@ Rate limiting & limits
105
105
  - JSON body size cap via `PDS_MAX_JSON_BYTES` (default 65536/64 KiB).
106
106
  - CORS: allow `*` by default in dev. In production, set `PDS_CORS_ORIGIN` to a CSV of allowed origins (e.g., `https://example.com,https://app.example.com`). Requests with an `Origin` not in this set are denied at the CORS layer (no wildcard fallback).
107
107
 
108
- This project was created using `bun init` in bun v1.2.22 and configured for Cloudflare Workers with Vite and `@cloudflare/vite-plugin`.
108
+ This project targets Cloudflare Workers via Astro with `@cloudflare/vite-plugin`, and is developed with Deno as the task runner / package manager.
109
109
 
110
110
  ## Database Migrations
111
111
 
@@ -114,9 +114,9 @@ This project uses Drizzle Kit for database schema management and migrations.
114
114
  ### Migration Workflow
115
115
 
116
116
  1. **Modify Schema**: Edit [`src/db/schema.ts`](src/db/schema.ts:1) to add/modify tables or indexes
117
- 2. **Generate Migration**: Run `bun run db:generate` to create a new migration file in `migrations/`
117
+ 2. **Generate Migration**: Run `deno task db:generate` to create a new migration file in `migrations/`
118
118
  3. **Review Migration**: Check the generated SQL in `migrations/XXXX_*.sql`
119
- 4. **Apply Locally**: Run `bun run db:apply:local` to apply to local D1 database
119
+ 4. **Apply Locally**: Run `deno task db:apply:local` to apply to local D1 database
120
120
  5. **Apply to Production**: Run `wrangler d1 migrations apply pds --remote` after deployment
121
121
 
122
122
  ### Migration Versioning
@@ -190,7 +190,7 @@ Set these secrets for each environment using `wrangler secret put <NAME> --env <
190
190
  ```bash
191
191
  # One-shot bootstrap (recommended)
192
192
  # Generates all required secrets and prints wrangler commands
193
- bun run scripts/setup-secrets.ts --env production --did did:web:example.com --handle user.example.com
193
+ deno run -A scripts/setup-secrets.ts --env production --did did:web:example.com --handle user.example.com
194
194
 
195
195
  # After generation, set secrets (example for production)
196
196
  wrangler secret put PDS_DID --env production
@@ -276,8 +276,8 @@ See [`wrangler.jsonc`](wrangler.jsonc:40) for environment-specific configuration
276
276
 
277
277
 
278
278
  Debugging & storage
279
- - D1 schema/migrations: generated with Drizzle Kit into `drizzle/`. Generate with `bunx drizzle-kit generate`.
280
- - Apply schema locally: `bunx wrangler d1 migrations apply pds --local` (requires dev DB named `pds`).
279
+ - D1 schema/migrations: generated with Drizzle Kit into `drizzle/`. Generate with `deno run -A npm:drizzle-kit generate`.
280
+ - Apply schema locally: `deno run -A npm:wrangler d1 migrations apply pds --local` (requires dev DB named `pds`).
281
281
  - Bootstrap route (alt): `POST /debug/db/bootstrap` creates a minimal `record` table.
282
282
  - Insert a test record: `POST /debug/record` with `{ "uri": "at://did:example/app.bsky.feed.post/123", "json": {"msg":"hi"} }`.
283
283
  - Get a record: `GET /debug/record?uri=at://did:example/app.bsky.feed.post/123`.
@@ -366,7 +366,7 @@ This PDS now implements full AT Protocol core compliance with:
366
366
  ### 1. Generate Secrets
367
367
  ```bash
368
368
  # Recommended: bootstrap all secrets (prints wrangler commands)
369
- bun run scripts/setup-secrets.ts --env production --did did:web:example.com --handle user.example.com
369
+ deno run -A scripts/setup-secrets.ts --env production --did did:web:example.com --handle user.example.com
370
370
 
371
371
  # Alternatively, supply your own secp256k1 key (32‑byte hex/base64)
372
372
  ```
@@ -400,8 +400,8 @@ limits, and timeouts.
400
400
 
401
401
  ### 3. Run Database Migration
402
402
  ```bash
403
- bun run db:generate
404
- bun run db:apply:local
403
+ deno task db:generate
404
+ deno task db:apply:local
405
405
  ```
406
406
 
407
407
  Upgrade note: migration `0009_oauth_session_state` revokes existing refresh
@@ -412,13 +412,13 @@ flows.
412
412
 
413
413
  ### 4. Run Tests
414
414
  ```bash
415
- bun test tests/mst.test.ts
416
- bun test tests/commit.test.ts
415
+ deno test -A tests/mst.test.ts
416
+ deno test -A tests/commit.test.ts
417
417
  ```
418
418
 
419
419
  ### 5. Start Development
420
420
  ```bash
421
- bun run dev
421
+ deno task dev
422
422
  ```
423
423
 
424
424
  ## Testing the Implementation
@@ -624,22 +624,22 @@ PDS_BLOB_QUOTA_BYTES=10737418240 # Default: 10GB
624
624
 
625
625
  ```bash
626
626
  # Performance tests
627
- bun test tests/performance.test.ts
627
+ deno test -A tests/performance.test.ts
628
628
 
629
629
  # Memory tests
630
- bun test tests/memory.test.ts
630
+ deno test -A tests/memory.test.ts
631
631
 
632
632
  # Blob tests
633
- bun test tests/blob.test.ts
633
+ deno test -A tests/blob.test.ts
634
634
 
635
635
  # Identity tests
636
- bun test tests/identity.test.ts
636
+ deno test -A tests/identity.test.ts
637
637
 
638
638
  # Federation tests
639
- bun test tests/federation.test.ts
639
+ deno test -A tests/federation.test.ts
640
640
 
641
641
  # Compliance tests
642
- bun test tests/compliance.test.ts
642
+ deno test -A tests/compliance.test.ts
643
643
  ```
644
644
 
645
645
  ### Documentation
@@ -0,0 +1,37 @@
1
+ PRAGMA foreign_keys=OFF;--> statement-breakpoint
2
+ CREATE TABLE `__new_blob_usage` (
3
+ `did` text NOT NULL,
4
+ `record_uri` text NOT NULL,
5
+ `key` text NOT NULL,
6
+ PRIMARY KEY(`did`, `record_uri`, `key`)
7
+ );
8
+ --> statement-breakpoint
9
+ INSERT INTO `__new_blob_usage`("did", "record_uri", "key")
10
+ SELECT
11
+ COALESCE(
12
+ `record`.`did`,
13
+ substr(`blob_usage`.`record_uri`, 6, instr(substr(`blob_usage`.`record_uri`, 6), '/') - 1)
14
+ ),
15
+ `blob_usage`.`record_uri`,
16
+ `blob_usage`.`key`
17
+ FROM `blob_usage`
18
+ LEFT JOIN `record` ON `record`.`uri` = `blob_usage`.`record_uri`;--> statement-breakpoint
19
+ DROP TABLE `blob_usage`;--> statement-breakpoint
20
+ ALTER TABLE `__new_blob_usage` RENAME TO `blob_usage`;--> statement-breakpoint
21
+ PRAGMA foreign_keys=ON;--> statement-breakpoint
22
+ CREATE INDEX `blob_usage_record_uri_idx` ON `blob_usage` (`did`,`record_uri`);--> statement-breakpoint
23
+ CREATE INDEX `blob_usage_did_key_idx` ON `blob_usage` (`did`,`key`);--> statement-breakpoint
24
+ CREATE TABLE `__new_blob` (
25
+ `cid` text NOT NULL,
26
+ `did` text NOT NULL,
27
+ `key` text NOT NULL,
28
+ `mime` text NOT NULL,
29
+ `size` integer NOT NULL,
30
+ `uploaded_at` integer DEFAULT 0 NOT NULL,
31
+ PRIMARY KEY(`did`, `cid`)
32
+ );
33
+ --> statement-breakpoint
34
+ INSERT INTO `__new_blob`("cid", "did", "key", "mime", "size", "uploaded_at") SELECT "cid", "did", "key", "mime", "size", 0 FROM `blob`;--> statement-breakpoint
35
+ DROP TABLE `blob`;--> statement-breakpoint
36
+ ALTER TABLE `__new_blob` RENAME TO `blob`;--> statement-breakpoint
37
+ CREATE INDEX `blob_key_idx` ON `blob` (`key`);
@@ -0,0 +1,31 @@
1
+ PRAGMA foreign_keys=OFF;--> statement-breakpoint
2
+ CREATE TABLE `__new_blob_usage` (
3
+ `did` text NOT NULL,
4
+ `record_uri` text NOT NULL,
5
+ `key` text NOT NULL,
6
+ `cid` text NOT NULL,
7
+ `repo_rev` text NOT NULL,
8
+ PRIMARY KEY(`did`, `record_uri`, `key`)
9
+ );
10
+ --> statement-breakpoint
11
+ INSERT INTO `__new_blob_usage`("did", "record_uri", "key", "cid", "repo_rev")
12
+ SELECT
13
+ `blob_usage`.`did`,
14
+ `blob_usage`.`record_uri`,
15
+ `blob_usage`.`key`,
16
+ `blob`.`cid`,
17
+ COALESCE(`repo_root`.`rev`, '')
18
+ FROM `blob_usage`
19
+ INNER JOIN `blob`
20
+ ON `blob`.`did` = `blob_usage`.`did`
21
+ AND `blob`.`key` = `blob_usage`.`key`
22
+ LEFT JOIN `repo_root`
23
+ ON `repo_root`.`did` = `blob_usage`.`did`
24
+ WHERE `blob`.`cid` IS NOT NULL
25
+ AND `blob`.`cid` <> '';--> statement-breakpoint
26
+ DROP TABLE `blob_usage`;--> statement-breakpoint
27
+ ALTER TABLE `__new_blob_usage` RENAME TO `blob_usage`;--> statement-breakpoint
28
+ PRAGMA foreign_keys=ON;--> statement-breakpoint
29
+ CREATE INDEX `blob_usage_record_uri_idx` ON `blob_usage` (`did`,`record_uri`);--> statement-breakpoint
30
+ CREATE INDEX `blob_usage_did_key_idx` ON `blob_usage` (`did`,`key`);--> statement-breakpoint
31
+ CREATE INDEX `blob_usage_did_repo_rev_cid_idx` ON `blob_usage` (`did`,`repo_rev`,`cid`);
@@ -0,0 +1,39 @@
1
+ WITH `record_blob_ref` AS (
2
+ SELECT
3
+ `record`.`did` AS `did`,
4
+ `record`.`uri` AS `record_uri`,
5
+ `link_node`.`value` AS `cid`,
6
+ `mime_node`.`value` AS `mime`,
7
+ `size_node`.`value` AS `size`
8
+ FROM `record`
9
+ INNER JOIN json_tree(CASE WHEN json_valid(`record`.`json`) THEN `record`.`json` ELSE '{}' END) AS `type_node`
10
+ ON `type_node`.`key` = '$type'
11
+ AND `type_node`.`value` = 'blob'
12
+ INNER JOIN json_tree(CASE WHEN json_valid(`record`.`json`) THEN `record`.`json` ELSE '{}' END) AS `link_node`
13
+ ON `link_node`.`path` = `type_node`.`path` || '.ref'
14
+ AND `link_node`.`key` IN ('$link', '/')
15
+ INNER JOIN json_tree(CASE WHEN json_valid(`record`.`json`) THEN `record`.`json` ELSE '{}' END) AS `mime_node`
16
+ ON `mime_node`.`path` = `type_node`.`path`
17
+ AND `mime_node`.`key` = 'mimeType'
18
+ INNER JOIN json_tree(CASE WHEN json_valid(`record`.`json`) THEN `record`.`json` ELSE '{}' END) AS `size_node`
19
+ ON `size_node`.`path` = `type_node`.`path`
20
+ AND `size_node`.`key` = 'size'
21
+ WHERE `link_node`.`type` = 'text'
22
+ AND `mime_node`.`type` = 'text'
23
+ AND `size_node`.`type` = 'integer'
24
+ )
25
+ INSERT OR IGNORE INTO `blob_usage` ("did", "record_uri", "key", "cid", "repo_rev")
26
+ SELECT
27
+ `record_blob_ref`.`did`,
28
+ `record_blob_ref`.`record_uri`,
29
+ `blob`.`key`,
30
+ `blob`.`cid`,
31
+ COALESCE(`repo_root`.`rev`, '')
32
+ FROM `record_blob_ref`
33
+ INNER JOIN `blob`
34
+ ON `blob`.`did` = `record_blob_ref`.`did`
35
+ AND `blob`.`cid` = `record_blob_ref`.`cid`
36
+ AND `blob`.`mime` = `record_blob_ref`.`mime`
37
+ AND `blob`.`size` = `record_blob_ref`.`size`
38
+ LEFT JOIN `repo_root`
39
+ ON `repo_root`.`did` = `record_blob_ref`.`did`;