@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.
- package/README.md +25 -25
- package/migrations/0010_eminent_klaw.sql +37 -0
- package/migrations/0011_chief_darwin.sql +31 -0
- package/migrations/0012_backfill_blob_usage.sql +39 -0
- package/migrations/meta/0010_snapshot.json +790 -0
- package/migrations/meta/0011_snapshot.json +813 -0
- package/migrations/meta/_journal.json +22 -1
- package/package.json +24 -41
- package/src/db/blob.ts +323 -0
- package/src/db/dal.ts +224 -78
- package/src/db/repo.ts +205 -25
- package/src/db/schema.ts +14 -5
- package/src/handlers/debug.ts +4 -3
- package/src/lib/appview/auth-policy.ts +7 -24
- package/src/lib/appview/proxy.ts +56 -23
- package/src/lib/appview/types.ts +1 -6
- package/src/lib/auth-scope.ts +399 -0
- package/src/lib/auth.ts +40 -39
- package/src/lib/commit.ts +37 -15
- package/src/lib/did-document.ts +4 -5
- package/src/lib/jwt.ts +3 -1
- package/src/lib/mime.ts +9 -0
- package/src/lib/oauth/resource.ts +49 -0
- package/src/lib/preference-policy.ts +45 -0
- package/src/lib/preferences.ts +0 -4
- package/src/lib/public-host.ts +127 -0
- package/src/lib/ratelimit.ts +37 -12
- package/src/lib/relay.ts +7 -27
- package/src/lib/repo-write-blob-constraints.ts +141 -0
- package/src/lib/repo-write-data.ts +195 -0
- package/src/lib/repo-write-error.ts +46 -0
- package/src/lib/repo-write-validation.ts +463 -0
- package/src/lib/session-tokens.ts +22 -5
- package/src/lib/unsupported-routes.ts +32 -0
- package/src/lib/util.ts +57 -2
- package/src/pages/.well-known/atproto-did.ts +15 -3
- package/src/pages/.well-known/did.json.ts +13 -7
- package/src/pages/debug/db/bootstrap.ts +4 -3
- package/src/pages/debug/gc/blobs.ts +11 -8
- package/src/pages/debug/record.ts +11 -0
- package/src/pages/xrpc/[...nsid].ts +17 -9
- package/src/pages/xrpc/app.bsky.actor.getPreferences.ts +9 -3
- package/src/pages/xrpc/app.bsky.actor.putPreferences.ts +17 -4
- package/src/pages/xrpc/app.bsky.unspecced.getAgeAssuranceState.ts +4 -2
- package/src/pages/xrpc/chat.bsky.convo.getLog.ts +4 -2
- package/src/pages/xrpc/chat.bsky.convo.listConvos.ts +4 -2
- package/src/pages/xrpc/com.atproto.identity.getRecommendedDidCredentials.ts +10 -6
- package/src/pages/xrpc/com.atproto.identity.requestPlcOperationSignature.ts +4 -3
- package/src/pages/xrpc/com.atproto.identity.resolveHandle.ts +13 -5
- package/src/pages/xrpc/com.atproto.identity.signPlcOperation.ts +4 -2
- package/src/pages/xrpc/com.atproto.identity.submitPlcOperation.ts +4 -2
- package/src/pages/xrpc/com.atproto.identity.updateHandle.ts +12 -36
- package/src/pages/xrpc/com.atproto.repo.applyWrites.ts +90 -139
- package/src/pages/xrpc/com.atproto.repo.createRecord.ts +74 -47
- package/src/pages/xrpc/com.atproto.repo.deleteRecord.ts +119 -46
- package/src/pages/xrpc/com.atproto.repo.describeRepo.ts +21 -20
- package/src/pages/xrpc/com.atproto.repo.getRecord.ts +6 -1
- package/src/pages/xrpc/com.atproto.repo.listMissingBlobs.ts +4 -2
- package/src/pages/xrpc/com.atproto.repo.putRecord.ts +84 -47
- package/src/pages/xrpc/com.atproto.repo.uploadBlob.ts +199 -78
- package/src/pages/xrpc/com.atproto.server.checkAccountStatus.ts +4 -2
- package/src/pages/xrpc/com.atproto.server.getServiceAuth.ts +88 -21
- package/src/pages/xrpc/com.atproto.server.getSession.ts +3 -13
- package/src/pages/xrpc/com.atproto.sync.getBlob.ts +92 -74
- package/src/pages/xrpc/com.atproto.sync.listBlobs.ts +45 -23
- package/src/services/car.ts +13 -0
- package/src/services/repo/apply-prepared-writes.ts +185 -0
- package/src/services/repo/blob-refs.ts +48 -0
- package/src/services/repo/blockstore-ops.ts +59 -17
- package/src/services/repo/list-blobs.ts +43 -0
- package/src/services/repo-manager.ts +221 -78
- package/src/worker/runtime.ts +1 -1
- 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
|
-
|
|
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
|
-
|
|
70
|
+
deno install
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Dev server (Vite dev):
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
|
|
76
|
+
deno task dev
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
Cloudflare local dev (optional):
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
|
|
82
|
+
deno run -A npm:wrangler dev --local
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
Build and deploy:
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
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 `
|
|
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 `
|
|
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
|
-
|
|
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 `
|
|
280
|
-
- Apply schema locally: `
|
|
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
|
-
|
|
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
|
-
|
|
404
|
-
|
|
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
|
-
|
|
416
|
-
|
|
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
|
-
|
|
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
|
-
|
|
627
|
+
deno test -A tests/performance.test.ts
|
|
628
628
|
|
|
629
629
|
# Memory tests
|
|
630
|
-
|
|
630
|
+
deno test -A tests/memory.test.ts
|
|
631
631
|
|
|
632
632
|
# Blob tests
|
|
633
|
-
|
|
633
|
+
deno test -A tests/blob.test.ts
|
|
634
634
|
|
|
635
635
|
# Identity tests
|
|
636
|
-
|
|
636
|
+
deno test -A tests/identity.test.ts
|
|
637
637
|
|
|
638
638
|
# Federation tests
|
|
639
|
-
|
|
639
|
+
deno test -A tests/federation.test.ts
|
|
640
640
|
|
|
641
641
|
# Compliance tests
|
|
642
|
-
|
|
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`;
|