@alteran/astro 0.3.9 → 0.6.1

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 (150) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +19 -30
  3. package/index.js +34 -28
  4. package/migrations/0007_bored_spitfire.sql +26 -0
  5. package/migrations/0008_furry_ozymandias.sql +2 -0
  6. package/migrations/meta/0007_snapshot.json +534 -0
  7. package/migrations/meta/0008_snapshot.json +548 -0
  8. package/migrations/meta/_journal.json +14 -0
  9. package/package.json +10 -9
  10. package/src/app.ts +8 -4
  11. package/src/db/account.ts +25 -6
  12. package/src/db/client.ts +1 -1
  13. package/src/db/dal.ts +34 -23
  14. package/src/db/repo.ts +38 -38
  15. package/src/db/schema.ts +5 -1
  16. package/src/db/seed.ts +5 -13
  17. package/src/entrypoints/server.ts +2 -22
  18. package/src/handlers/debug.ts +1 -1
  19. package/src/handlers/ready.ts +1 -1
  20. package/src/handlers/root.ts +4 -4
  21. package/src/handlers/xrpc.server.refreshSession.ts +6 -6
  22. package/src/lib/account-state.ts +156 -0
  23. package/src/lib/actor.ts +29 -13
  24. package/src/lib/appview/auth-policy.ts +66 -0
  25. package/src/lib/appview/did-resolver.ts +233 -0
  26. package/src/lib/appview/proxy.ts +221 -0
  27. package/src/lib/appview/service-config.ts +61 -0
  28. package/src/lib/appview/service-jwt.ts +93 -0
  29. package/src/lib/appview/types.ts +25 -0
  30. package/src/lib/appview.ts +5 -532
  31. package/src/lib/auth-errors.ts +24 -0
  32. package/src/lib/auth.ts +63 -15
  33. package/src/lib/blockstore-gc.ts +6 -5
  34. package/src/lib/cache.ts +30 -4
  35. package/src/lib/chat.ts +20 -14
  36. package/src/lib/commit-log-pruning.ts +2 -2
  37. package/src/lib/commit.ts +26 -36
  38. package/src/lib/config.ts +26 -15
  39. package/src/lib/did-document.ts +32 -0
  40. package/src/lib/errors.ts +54 -0
  41. package/src/lib/feed.ts +18 -19
  42. package/src/lib/firehose/frames.ts +87 -47
  43. package/src/lib/firehose/validation.ts +3 -3
  44. package/src/lib/jwt.ts +85 -177
  45. package/src/lib/labeler.ts +43 -30
  46. package/src/lib/logger.ts +4 -0
  47. package/src/lib/mst/block-map.ts +172 -0
  48. package/src/lib/mst/blockstore.ts +56 -93
  49. package/src/lib/mst/index.ts +1 -0
  50. package/src/lib/mst/leaf.ts +25 -0
  51. package/src/lib/mst/mst.ts +81 -237
  52. package/src/lib/mst/serialize.ts +97 -0
  53. package/src/lib/mst/types.ts +21 -0
  54. package/src/lib/oauth/clients.ts +67 -0
  55. package/src/lib/oauth/dpop-errors.ts +15 -0
  56. package/src/lib/oauth/dpop.ts +150 -0
  57. package/src/lib/oauth/resource.ts +199 -0
  58. package/src/lib/oauth/store.ts +77 -0
  59. package/src/lib/preferences.ts +12 -37
  60. package/src/lib/ratelimit.ts +4 -4
  61. package/src/lib/refresh-session.ts +161 -0
  62. package/src/lib/relay.ts +10 -8
  63. package/src/lib/secrets.ts +6 -7
  64. package/src/lib/sequencer.ts +14 -5
  65. package/src/lib/service-auth.ts +184 -0
  66. package/src/lib/session-tokens.ts +28 -76
  67. package/src/lib/streaming-car.ts +3 -0
  68. package/src/lib/tracing.ts +4 -3
  69. package/src/lib/util.ts +65 -15
  70. package/src/middleware.ts +1 -1
  71. package/src/pages/.well-known/did.json.ts +27 -30
  72. package/src/pages/.well-known/oauth-authorization-server.ts +31 -0
  73. package/src/pages/.well-known/oauth-protected-resource.ts +22 -0
  74. package/src/pages/debug/blob/[...key].ts +2 -2
  75. package/src/pages/debug/db/bootstrap.ts +1 -1
  76. package/src/pages/debug/db/commits.ts +1 -1
  77. package/src/pages/debug/gc/blobs.ts +1 -1
  78. package/src/pages/debug/record.ts +1 -1
  79. package/src/pages/debug/sequencer.ts +28 -0
  80. package/src/pages/health.ts +4 -4
  81. package/src/pages/oauth/authorize.ts +78 -0
  82. package/src/pages/oauth/consent.ts +80 -0
  83. package/src/pages/oauth/par.ts +121 -0
  84. package/src/pages/oauth/token.ts +158 -0
  85. package/src/pages/ready.ts +2 -2
  86. package/src/pages/xrpc/[...nsid].ts +61 -0
  87. package/src/pages/xrpc/app.bsky.actor.getPreferences.ts +12 -13
  88. package/src/pages/xrpc/app.bsky.actor.putPreferences.ts +23 -23
  89. package/src/pages/xrpc/app.bsky.unspecced.getAgeAssuranceState.ts +9 -2
  90. package/src/pages/xrpc/chat.bsky.convo.getLog.ts +9 -2
  91. package/src/pages/xrpc/chat.bsky.convo.listConvos.ts +9 -2
  92. package/src/pages/xrpc/com.atproto.identity.getRecommendedDidCredentials.ts +43 -41
  93. package/src/pages/xrpc/com.atproto.identity.requestPlcOperationSignature.ts +10 -3
  94. package/src/pages/xrpc/com.atproto.identity.resolveHandle.ts +40 -9
  95. package/src/pages/xrpc/com.atproto.identity.signPlcOperation.ts +41 -29
  96. package/src/pages/xrpc/com.atproto.identity.submitPlcOperation.ts +20 -6
  97. package/src/pages/xrpc/com.atproto.identity.updateHandle.ts +1 -1
  98. package/src/pages/xrpc/com.atproto.repo.applyWrites.ts +101 -11
  99. package/src/pages/xrpc/com.atproto.repo.createRecord.ts +44 -14
  100. package/src/pages/xrpc/com.atproto.repo.deleteRecord.ts +41 -13
  101. package/src/pages/xrpc/com.atproto.repo.describeRepo.ts +2 -2
  102. package/src/pages/xrpc/com.atproto.repo.getRecord.ts +14 -1
  103. package/src/pages/xrpc/com.atproto.repo.listMissingBlobs.ts +14 -6
  104. package/src/pages/xrpc/com.atproto.repo.listRecords.ts +1 -1
  105. package/src/pages/xrpc/com.atproto.repo.putRecord.ts +42 -14
  106. package/src/pages/xrpc/com.atproto.repo.uploadBlob.ts +76 -15
  107. package/src/pages/xrpc/com.atproto.server.checkAccountStatus.ts +20 -8
  108. package/src/pages/xrpc/com.atproto.server.createSession.ts +32 -12
  109. package/src/pages/xrpc/com.atproto.server.describeServer.ts +1 -1
  110. package/src/pages/xrpc/com.atproto.server.getServiceAuth.ts +12 -5
  111. package/src/pages/xrpc/com.atproto.server.getSession.ts +22 -8
  112. package/src/pages/xrpc/com.atproto.server.refreshSession.ts +30 -72
  113. package/src/pages/xrpc/com.atproto.sync.getBlob.ts +72 -23
  114. package/src/pages/xrpc/com.atproto.sync.getCheckout.json.ts +1 -1
  115. package/src/pages/xrpc/com.atproto.sync.getCheckout.ts +1 -1
  116. package/src/pages/xrpc/com.atproto.sync.getHead.ts +7 -2
  117. package/src/pages/xrpc/com.atproto.sync.getLatestCommit.ts +1 -1
  118. package/src/pages/xrpc/com.atproto.sync.getRecord.ts +5 -27
  119. package/src/pages/xrpc/com.atproto.sync.getRepo.json.ts +1 -1
  120. package/src/pages/xrpc/com.atproto.sync.getRepo.ts +50 -5
  121. package/src/pages/xrpc/com.atproto.sync.getRepoStatus.ts +58 -0
  122. package/src/pages/xrpc/com.atproto.sync.listBlobs.ts +2 -2
  123. package/src/pages/xrpc/com.atproto.sync.listRepos.ts +5 -3
  124. package/src/services/car.ts +209 -57
  125. package/src/services/r2-blob-store.ts +4 -4
  126. package/src/services/repo/blockstore-ops.ts +29 -0
  127. package/src/services/repo/operations.ts +133 -0
  128. package/src/services/repo-manager.ts +203 -254
  129. package/src/worker/runtime.ts +56 -11
  130. package/src/worker/sequencer/broadcast.ts +91 -0
  131. package/src/worker/sequencer/cid-helpers.ts +39 -0
  132. package/src/worker/sequencer/payload.ts +84 -0
  133. package/src/worker/sequencer/types.ts +36 -0
  134. package/src/worker/sequencer/upgrade.ts +141 -0
  135. package/src/worker/sequencer.ts +264 -406
  136. package/types/env.d.ts +18 -6
  137. package/src/pages/xrpc/app.bsky.actor.getProfile.ts +0 -49
  138. package/src/pages/xrpc/app.bsky.actor.getProfiles.ts +0 -51
  139. package/src/pages/xrpc/app.bsky.feed.getActorFeeds.ts +0 -25
  140. package/src/pages/xrpc/app.bsky.feed.getAuthorFeed.ts +0 -42
  141. package/src/pages/xrpc/app.bsky.feed.getFeedGenerators.ts +0 -25
  142. package/src/pages/xrpc/app.bsky.feed.getPostThread.ts +0 -37
  143. package/src/pages/xrpc/app.bsky.feed.getPosts.ts +0 -26
  144. package/src/pages/xrpc/app.bsky.feed.getSuggestedFeeds.ts +0 -23
  145. package/src/pages/xrpc/app.bsky.feed.getTimeline.ts +0 -47
  146. package/src/pages/xrpc/app.bsky.graph.getFollowers.ts +0 -29
  147. package/src/pages/xrpc/app.bsky.graph.getFollows.ts +0 -29
  148. package/src/pages/xrpc/app.bsky.notification.getUnreadCount.ts +0 -20
  149. package/src/pages/xrpc/app.bsky.notification.listNotifications.ts +0 -27
  150. package/src/pages/xrpc/app.bsky.unspecced.getSuggestedFeeds.ts +0 -23
package/types/env.d.ts CHANGED
@@ -16,35 +16,47 @@ export interface SecretsStoreSecret {
16
16
 
17
17
  declare global {
18
18
  interface Env {
19
- DB: D1Database;
20
- BLOBS: R2Bucket;
21
- SEQUENCER?: DurableObjectNamespace;
19
+ ALTERAN_DB: D1Database;
20
+ ALTERAN_BLOBS: R2Bucket;
21
+ ALTERAN_SEQUENCER?: DurableObjectNamespace;
22
+ ASSETS?: {
23
+ fetch: (req: Request | string) => Promise<Response>;
24
+ };
22
25
  // Secrets can be provided either as Wrangler Secrets (string)
23
26
  // or via Secret Store bindings (SecretsStoreSecret).
24
27
  PDS_HANDLE?: string | SecretsStoreSecret;
25
28
  PDS_DID?: string | SecretsStoreSecret;
26
29
  PDS_HOSTNAME?: string;
30
+ PDS_EMAIL?: string;
27
31
  PDS_ALLOWED_MIME?: string;
28
32
  USER_PASSWORD?: string | SecretsStoreSecret;
29
33
  PDS_MAX_BLOB_SIZE?: string;
34
+ PDS_BLOB_QUOTA_BYTES?: string;
30
35
  REFRESH_TOKEN?: string | SecretsStoreSecret;
31
36
  REFRESH_TOKEN_SECRET?: string | SecretsStoreSecret;
32
37
  SESSION_JWT_SECRET?: string | SecretsStoreSecret;
33
38
  PDS_ACCESS_TTL_SEC?: string;
34
39
  PDS_REFRESH_TTL_SEC?: string;
35
- JWT_ALGORITHM?: string;
40
+ // secp256k1 signing private key (hex or base64 32 bytes) used for commits and service-auth
36
41
  REPO_SIGNING_KEY?: string | SecretsStoreSecret;
37
- REPO_SIGNING_KEY_PUBLIC?: string | SecretsStoreSecret;
38
42
  PDS_PLC_ROTATION_KEY?: string | SecretsStoreSecret;
39
43
  PDS_RATE_LIMIT_PER_MIN?: string;
40
44
  PDS_MAX_JSON_BYTES?: string;
41
45
  PDS_CORS_ORIGIN?: string;
42
46
  PDS_SEQ_WINDOW?: string;
47
+ PDS_WS_HIBERNATE?: string;
43
48
  ENVIRONMENT?: string;
44
49
  PDS_BSKY_APP_VIEW_URL?: string;
45
50
  PDS_BSKY_APP_VIEW_DID?: string;
46
51
  PDS_BSKY_APP_VIEW_CDN_URL_PATTERN?: string;
47
- PDS_SERVICE_SIGNING_KEY_HEX?: string | SecretsStoreSecret;
52
+ PDS_APPVIEW_FORCE_FALLBACK?: string;
53
+ PDS_BSKY_CHAT_URL?: string;
54
+ PDS_BSKY_CHAT_DID?: string;
55
+ PDS_OZONE_URL?: string;
56
+ PDS_OZONE_DID?: string;
57
+ PDS_LINK_PRIVACY?: string;
58
+ PDS_LINK_TOS?: string;
59
+ PDS_CONTACT_EMAIL?: string;
48
60
  // Relay crawl configuration
49
61
  PDS_RELAY_HOSTS?: string; // CSV of relay hostnames (no scheme). Default: bsky.network
50
62
  PDS_RELAY_NOTIFY?: string; // 'false' to disable auto notify
@@ -1,49 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { buildProfileViewDetailed, getPrimaryActor, matchesPrimaryActor } from '../../lib/actor';
4
- import { countPosts } from '../../lib/feed';
5
- import { isAuthorized, unauthorized } from '../../lib/auth';
6
-
7
- export const prerender = false;
8
-
9
- export async function GET({ locals, request }: APIContext) {
10
- const { env } = locals.runtime;
11
- if (!(await isAuthorized(request, env))) return unauthorized();
12
-
13
- try {
14
- return await proxyAppView({
15
- request,
16
- env,
17
- lxm: 'app.bsky.actor.getProfile',
18
- fallback: async () => {
19
- console.log('app.bsky.actor.getProfile: Using fallback');
20
- const url = new URL(request.url);
21
- const identifier = url.searchParams.get('actor');
22
- const actor = await getPrimaryActor(env);
23
- console.log('app.bsky.actor.getProfile: actor', { did: actor.did, handle: actor.handle, identifier });
24
- if (!matchesPrimaryActor(identifier, actor)) {
25
- console.log('app.bsky.actor.getProfile: identifier does not match actor');
26
- return new Response(JSON.stringify({ error: 'ProfileNotFound' }), {
27
- status: 404,
28
- headers: { 'Content-Type': 'application/json' }
29
- });
30
- }
31
- const profile = buildProfileViewDetailed(actor, {
32
- followers: 0,
33
- follows: 0,
34
- posts: await countPosts(env),
35
- });
36
- console.log('app.bsky.actor.getProfile: returning profile', profile);
37
- return new Response(JSON.stringify(profile), {
38
- headers: { 'Content-Type': 'application/json' },
39
- });
40
- },
41
- });
42
- } catch (error) {
43
- console.error('app.bsky.actor.getProfile error:', error);
44
- return new Response(JSON.stringify({ error: 'InternalServerError', message: String(error) }), {
45
- status: 500,
46
- headers: { 'Content-Type': 'application/json' },
47
- });
48
- }
49
- }
@@ -1,51 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import {
4
- buildProfileViewDetailed,
5
- getPrimaryActor,
6
- matchesPrimaryActor,
7
- } from '../../lib/actor';
8
- import { countPosts } from '../../lib/feed';
9
- import { isAuthorized, unauthorized } from '../../lib/auth';
10
-
11
- export const prerender = false;
12
-
13
- export async function GET({ locals, request }: APIContext) {
14
- const { env } = locals.runtime;
15
- if (!(await isAuthorized(request, env))) return unauthorized();
16
-
17
- // Some clients call with an empty actors list; upstream returns 400.
18
- // For UX parity, treat missing/empty as an empty result set.
19
- const url = new URL(request.url);
20
- const requestedActors = url.searchParams.getAll('actors');
21
- if (requestedActors.length === 0) {
22
- return new Response(JSON.stringify({ profiles: [] }), {
23
- headers: { 'Content-Type': 'application/json' },
24
- });
25
- }
26
-
27
- return proxyAppView({
28
- request,
29
- env,
30
- lxm: 'app.bsky.actor.getProfiles',
31
- fallback: async () => {
32
- const actors = requestedActors;
33
- const actor = await getPrimaryActor(env);
34
- const posts = await countPosts(env);
35
-
36
- const profiles = actors
37
- .filter((identifier) => matchesPrimaryActor(identifier, actor))
38
- .map(() =>
39
- buildProfileViewDetailed(actor, {
40
- followers: 0,
41
- follows: 0,
42
- posts,
43
- }),
44
- );
45
-
46
- return new Response(JSON.stringify({ profiles }), {
47
- headers: { 'Content-Type': 'application/json' },
48
- });
49
- },
50
- });
51
- }
@@ -1,25 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { isAuthorized, unauthorized } from '../../lib/auth';
4
-
5
- export const prerender = false;
6
-
7
- // Implements: app.bsky.feed.getActorFeeds
8
- // Thin proxy to AppView with a safe empty fallback to satisfy clients.
9
- export async function GET({ locals, request }: APIContext) {
10
- const { env } = locals.runtime;
11
- if (!(await isAuthorized(request, env))) return unauthorized();
12
-
13
- return proxyAppView({
14
- request,
15
- env,
16
- lxm: 'app.bsky.feed.getActorFeeds',
17
- fallback: async () => {
18
- // Minimal valid shape per lexicon when upstream unavailable
19
- return new Response(JSON.stringify({ feeds: [] }), {
20
- headers: { 'Content-Type': 'application/json' },
21
- });
22
- },
23
- });
24
- }
25
-
@@ -1,42 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { matchesPrimaryActor, getPrimaryActor } from '../../lib/actor';
4
- import { buildFeedViewPosts, listPosts } from '../../lib/feed';
5
- import { isAuthorized, unauthorized } from '../../lib/auth';
6
-
7
- export const prerender = false;
8
-
9
- export async function GET({ locals, request }: APIContext) {
10
- const { env } = locals.runtime;
11
- if (!(await isAuthorized(request, env))) return unauthorized();
12
-
13
- return proxyAppView({
14
- request,
15
- env,
16
- lxm: 'app.bsky.feed.getAuthorFeed',
17
- fallback: async () => {
18
- const url = new URL(request.url);
19
- const identifier = url.searchParams.get('actor');
20
- const actor = await getPrimaryActor(env);
21
- if (!matchesPrimaryActor(identifier, actor)) {
22
- return new Response(JSON.stringify({ error: 'ActorNotFound' }), { status: 404 });
23
- }
24
-
25
- const limitParam = Number.parseInt(url.searchParams.get('limit') ?? '', 10);
26
- const limitInput = Number.isFinite(limitParam) ? limitParam : 50;
27
- const limit = Math.max(1, Math.min(limitInput, 100));
28
- const cursor = url.searchParams.get('cursor') ?? undefined;
29
-
30
- const posts = await listPosts(env, limit, cursor);
31
- const feed = await buildFeedViewPosts(env, posts);
32
- const nextCursor = posts.length === limit ? String(posts[posts.length - 1].rowid) : undefined;
33
-
34
- const payload: Record<string, unknown> = { feed };
35
- if (nextCursor) payload.cursor = nextCursor;
36
-
37
- return new Response(JSON.stringify(payload), {
38
- headers: { 'Content-Type': 'application/json' },
39
- });
40
- },
41
- });
42
- }
@@ -1,25 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { isAuthorized, unauthorized } from '../../lib/auth';
4
-
5
- export const prerender = false;
6
-
7
- // Implements: app.bsky.feed.getFeedGenerators
8
- // Thin proxy to AppView with a safe empty fallback to satisfy clients.
9
- export async function GET({ locals, request }: APIContext) {
10
- const { env } = locals.runtime;
11
- if (!(await isAuthorized(request, env))) return unauthorized();
12
-
13
- return proxyAppView({
14
- request,
15
- env,
16
- lxm: 'app.bsky.feed.getFeedGenerators',
17
- fallback: async () => {
18
- // Minimal valid shape per lexicon when upstream unavailable
19
- return new Response(JSON.stringify({ feeds: [] }), {
20
- headers: { 'Content-Type': 'application/json' },
21
- });
22
- },
23
- });
24
- }
25
-
@@ -1,37 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { buildThreadView, getPostByUri } from '../../lib/feed';
4
- import { isAuthorized, unauthorized } from '../../lib/auth';
5
-
6
- export const prerender = false;
7
-
8
- export async function GET({ locals, request }: APIContext) {
9
- const { env } = locals.runtime;
10
- if (!(await isAuthorized(request, env))) return unauthorized();
11
-
12
- return proxyAppView({
13
- request,
14
- env,
15
- lxm: 'app.bsky.feed.getPostThread',
16
- fallback: async () => {
17
- const url = new URL(request.url);
18
- const uri = url.searchParams.get('uri');
19
- if (!uri) {
20
- return new Response(
21
- JSON.stringify({ error: 'BadRequest', message: 'uri parameter required' }),
22
- { status: 400 },
23
- );
24
- }
25
-
26
- const post = await getPostByUri(env, uri);
27
- if (!post) {
28
- return new Response(JSON.stringify({ error: 'NotFound' }), { status: 404 });
29
- }
30
-
31
- const thread = await buildThreadView(env, post);
32
- return new Response(JSON.stringify({ thread }), {
33
- headers: { 'Content-Type': 'application/json' },
34
- });
35
- },
36
- });
37
- }
@@ -1,26 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { buildPostViews, getPostsByUris } from '../../lib/feed';
4
- import { isAuthorized, unauthorized } from '../../lib/auth';
5
-
6
- export const prerender = false;
7
-
8
- export async function GET({ locals, request }: APIContext) {
9
- const { env } = locals.runtime;
10
- if (!(await isAuthorized(request, env))) return unauthorized();
11
-
12
- return proxyAppView({
13
- request,
14
- env,
15
- lxm: 'app.bsky.feed.getPosts',
16
- fallback: async () => {
17
- const url = new URL(request.url);
18
- const uris = url.searchParams.getAll('uris').filter(Boolean);
19
- const posts = await getPostsByUris(env, uris.slice(0, 25));
20
- const views = await buildPostViews(env, posts);
21
- return new Response(JSON.stringify({ posts: views }), {
22
- headers: { 'Content-Type': 'application/json' },
23
- });
24
- },
25
- });
26
- }
@@ -1,23 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { isAuthorized, unauthorized } from '../../lib/auth';
4
-
5
- export const prerender = false;
6
-
7
- // Implements: app.bsky.feed.getSuggestedFeeds (proxy-only)
8
- export async function GET({ locals, request }: APIContext) {
9
- const { env } = locals.runtime;
10
- if (!(await isAuthorized(request, env))) return unauthorized();
11
-
12
- return proxyAppView({
13
- request,
14
- env,
15
- lxm: 'app.bsky.feed.getSuggestedFeeds',
16
- fallback: async () => {
17
- return new Response(JSON.stringify({ feeds: [] }), {
18
- headers: { 'Content-Type': 'application/json' },
19
- });
20
- },
21
- });
22
- }
23
-
@@ -1,47 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { buildFeedViewPosts, listPosts } from '../../lib/feed';
4
- import { isAuthorized, unauthorized } from '../../lib/auth';
5
-
6
- export const prerender = false;
7
-
8
- export async function GET({ locals, request }: APIContext) {
9
- const { env } = locals.runtime;
10
- if (!(await isAuthorized(request, env))) return unauthorized();
11
-
12
- try {
13
- return await proxyAppView({
14
- request,
15
- env,
16
- lxm: 'app.bsky.feed.getTimeline',
17
- fallback: async () => {
18
- console.log('app.bsky.feed.getTimeline: Using fallback');
19
- const url = new URL(request.url);
20
- const cursor = url.searchParams.get('cursor') ?? undefined;
21
- const limitParam = Number.parseInt(url.searchParams.get('limit') ?? '', 10);
22
- const limitInput = Number.isFinite(limitParam) ? limitParam : 50;
23
- const limit = Math.max(1, Math.min(limitInput, 100));
24
-
25
- console.log('app.bsky.feed.getTimeline: fetching posts', { limit, cursor });
26
- const posts = await listPosts(env, limit, cursor);
27
- console.log('app.bsky.feed.getTimeline: found posts', posts.length);
28
- const feed = await buildFeedViewPosts(env, posts);
29
- const nextCursor = posts.length === limit ? String(posts[posts.length - 1].rowid) : undefined;
30
-
31
- const payload: Record<string, unknown> = { feed };
32
- if (nextCursor) payload.cursor = nextCursor;
33
-
34
- console.log('app.bsky.feed.getTimeline: returning feed', { feedLength: feed.length, nextCursor });
35
- return new Response(JSON.stringify(payload), {
36
- headers: { 'Content-Type': 'application/json' },
37
- });
38
- },
39
- });
40
- } catch (error) {
41
- console.error('app.bsky.feed.getTimeline error:', error);
42
- return new Response(JSON.stringify({ error: 'InternalServerError', message: String(error) }), {
43
- status: 500,
44
- headers: { 'Content-Type': 'application/json' },
45
- });
46
- }
47
- }
@@ -1,29 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { buildProfileView, getPrimaryActor, matchesPrimaryActor } from '../../lib/actor';
4
- import { isAuthorized, unauthorized } from '../../lib/auth';
5
-
6
- export const prerender = false;
7
-
8
- export async function GET({ locals, request }: APIContext) {
9
- const { env } = locals.runtime;
10
- if (!(await isAuthorized(request, env))) return unauthorized();
11
-
12
- return proxyAppView({
13
- request,
14
- env,
15
- lxm: 'app.bsky.graph.getFollowers',
16
- fallback: async () => {
17
- const url = new URL(request.url);
18
- const identifier = url.searchParams.get('actor');
19
- const actor = await getPrimaryActor(env);
20
- if (!matchesPrimaryActor(identifier, actor)) {
21
- return new Response(JSON.stringify({ error: 'ActorNotFound' }), { status: 404 });
22
- }
23
- return new Response(
24
- JSON.stringify({ subject: buildProfileView(actor), followers: [] }),
25
- { headers: { 'Content-Type': 'application/json' } },
26
- );
27
- },
28
- });
29
- }
@@ -1,29 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { buildProfileView, getPrimaryActor, matchesPrimaryActor } from '../../lib/actor';
4
- import { isAuthorized, unauthorized } from '../../lib/auth';
5
-
6
- export const prerender = false;
7
-
8
- export async function GET({ locals, request }: APIContext) {
9
- const { env } = locals.runtime;
10
- if (!(await isAuthorized(request, env))) return unauthorized();
11
-
12
- return proxyAppView({
13
- request,
14
- env,
15
- lxm: 'app.bsky.graph.getFollows',
16
- fallback: async () => {
17
- const url = new URL(request.url);
18
- const identifier = url.searchParams.get('actor');
19
- const actor = await getPrimaryActor(env);
20
- if (!matchesPrimaryActor(identifier, actor)) {
21
- return new Response(JSON.stringify({ error: 'ActorNotFound' }), { status: 404 });
22
- }
23
- return new Response(
24
- JSON.stringify({ subject: buildProfileView(actor), follows: [] }),
25
- { headers: { 'Content-Type': 'application/json' } },
26
- );
27
- },
28
- });
29
- }
@@ -1,20 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { isAuthorized, unauthorized } from '../../lib/auth';
4
-
5
- export const prerender = false;
6
-
7
- export async function GET({ locals, request }: APIContext) {
8
- const { env } = locals.runtime;
9
- if (!(await isAuthorized(request, env))) return unauthorized();
10
-
11
- return proxyAppView({
12
- request,
13
- env,
14
- lxm: 'app.bsky.notification.getUnreadCount',
15
- fallback: async () =>
16
- new Response(JSON.stringify({ count: 0 }), {
17
- headers: { 'Content-Type': 'application/json' },
18
- }),
19
- });
20
- }
@@ -1,27 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { isAuthorized, unauthorized } from '../../lib/auth';
4
-
5
- export const prerender = false;
6
-
7
- export async function GET({ locals, request }: APIContext) {
8
- const { env } = locals.runtime;
9
- if (!(await isAuthorized(request, env))) return unauthorized();
10
-
11
- return proxyAppView({
12
- request,
13
- env,
14
- lxm: 'app.bsky.notification.listNotifications',
15
- fallback: async () =>
16
- new Response(
17
- JSON.stringify({
18
- notifications: [],
19
- priority: false,
20
- seenAt: new Date(0).toISOString(),
21
- }),
22
- {
23
- headers: { 'Content-Type': 'application/json' },
24
- },
25
- ),
26
- });
27
- }
@@ -1,23 +0,0 @@
1
- import type { APIContext } from 'astro';
2
- import { proxyAppView } from '../../lib/appview';
3
- import { isAuthorized, unauthorized } from '../../lib/auth';
4
-
5
- export const prerender = false;
6
-
7
- // Implements: app.bsky.unspecced.getSuggestedFeeds (proxy-only)
8
- export async function GET({ locals, request }: APIContext) {
9
- const { env } = locals.runtime;
10
- if (!(await isAuthorized(request, env))) return unauthorized();
11
-
12
- return proxyAppView({
13
- request,
14
- env,
15
- lxm: 'app.bsky.unspecced.getSuggestedFeeds',
16
- fallback: async () => {
17
- return new Response(JSON.stringify({ feeds: [] }), {
18
- headers: { 'Content-Type': 'application/json' },
19
- });
20
- },
21
- });
22
- }
23
-