@alteran/astro 0.3.9 → 0.5.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/LICENSE +21 -0
- package/README.md +19 -30
- package/index.js +34 -28
- package/migrations/0007_bored_spitfire.sql +26 -0
- package/migrations/0008_furry_ozymandias.sql +2 -0
- package/migrations/meta/0007_snapshot.json +534 -0
- package/migrations/meta/0008_snapshot.json +548 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +10 -9
- package/src/app.ts +8 -4
- package/src/db/account.ts +25 -6
- package/src/db/dal.ts +34 -23
- package/src/db/repo.ts +35 -35
- package/src/db/schema.ts +5 -1
- package/src/db/seed.ts +5 -13
- package/src/entrypoints/server.ts +2 -22
- package/src/handlers/root.ts +4 -4
- package/src/lib/account-state.ts +156 -0
- package/src/lib/actor.ts +28 -12
- package/src/lib/appview/auth-policy.ts +66 -0
- package/src/lib/appview/did-resolver.ts +233 -0
- package/src/lib/appview/proxy.ts +221 -0
- package/src/lib/appview/service-config.ts +61 -0
- package/src/lib/appview/service-jwt.ts +93 -0
- package/src/lib/appview/types.ts +25 -0
- package/src/lib/appview.ts +5 -532
- package/src/lib/auth-errors.ts +24 -0
- package/src/lib/auth.ts +63 -15
- package/src/lib/blockstore-gc.ts +2 -1
- package/src/lib/cache.ts +30 -4
- package/src/lib/chat.ts +14 -8
- package/src/lib/commit.ts +26 -36
- package/src/lib/config.ts +26 -15
- package/src/lib/did-document.ts +32 -0
- package/src/lib/errors.ts +54 -0
- package/src/lib/feed.ts +18 -19
- package/src/lib/firehose/frames.ts +87 -47
- package/src/lib/firehose/validation.ts +3 -3
- package/src/lib/jwt.ts +85 -177
- package/src/lib/labeler.ts +43 -30
- package/src/lib/logger.ts +4 -0
- package/src/lib/mst/block-map.ts +172 -0
- package/src/lib/mst/blockstore.ts +56 -93
- package/src/lib/mst/index.ts +1 -0
- package/src/lib/mst/leaf.ts +25 -0
- package/src/lib/mst/mst.ts +81 -237
- package/src/lib/mst/serialize.ts +97 -0
- package/src/lib/mst/types.ts +21 -0
- package/src/lib/oauth/clients.ts +67 -0
- package/src/lib/oauth/dpop-errors.ts +15 -0
- package/src/lib/oauth/dpop.ts +150 -0
- package/src/lib/oauth/resource.ts +199 -0
- package/src/lib/oauth/store.ts +77 -0
- package/src/lib/preferences.ts +9 -34
- package/src/lib/refresh-session.ts +161 -0
- package/src/lib/relay.ts +10 -8
- package/src/lib/secrets.ts +6 -7
- package/src/lib/sequencer.ts +12 -3
- package/src/lib/service-auth.ts +184 -0
- package/src/lib/session-tokens.ts +28 -76
- package/src/lib/streaming-car.ts +3 -0
- package/src/lib/tracing.ts +4 -3
- package/src/lib/util.ts +65 -15
- package/src/middleware.ts +1 -1
- package/src/pages/.well-known/did.json.ts +27 -30
- package/src/pages/.well-known/oauth-authorization-server.ts +31 -0
- package/src/pages/.well-known/oauth-protected-resource.ts +22 -0
- package/src/pages/debug/record.ts +1 -1
- package/src/pages/debug/sequencer.ts +28 -0
- package/src/pages/oauth/authorize.ts +78 -0
- package/src/pages/oauth/consent.ts +80 -0
- package/src/pages/oauth/par.ts +121 -0
- package/src/pages/oauth/token.ts +158 -0
- package/src/pages/xrpc/[...nsid].ts +61 -0
- package/src/pages/xrpc/app.bsky.actor.getPreferences.ts +12 -13
- package/src/pages/xrpc/app.bsky.actor.putPreferences.ts +23 -23
- package/src/pages/xrpc/app.bsky.unspecced.getAgeAssuranceState.ts +9 -2
- package/src/pages/xrpc/chat.bsky.convo.getLog.ts +9 -2
- package/src/pages/xrpc/chat.bsky.convo.listConvos.ts +9 -2
- package/src/pages/xrpc/com.atproto.identity.getRecommendedDidCredentials.ts +43 -41
- package/src/pages/xrpc/com.atproto.identity.requestPlcOperationSignature.ts +10 -3
- package/src/pages/xrpc/com.atproto.identity.resolveHandle.ts +40 -9
- package/src/pages/xrpc/com.atproto.identity.signPlcOperation.ts +41 -29
- package/src/pages/xrpc/com.atproto.identity.submitPlcOperation.ts +20 -6
- package/src/pages/xrpc/com.atproto.identity.updateHandle.ts +1 -1
- package/src/pages/xrpc/com.atproto.repo.applyWrites.ts +101 -11
- package/src/pages/xrpc/com.atproto.repo.createRecord.ts +44 -14
- package/src/pages/xrpc/com.atproto.repo.deleteRecord.ts +41 -13
- package/src/pages/xrpc/com.atproto.repo.describeRepo.ts +2 -2
- package/src/pages/xrpc/com.atproto.repo.getRecord.ts +14 -1
- package/src/pages/xrpc/com.atproto.repo.listMissingBlobs.ts +14 -6
- package/src/pages/xrpc/com.atproto.repo.listRecords.ts +1 -1
- package/src/pages/xrpc/com.atproto.repo.putRecord.ts +42 -14
- package/src/pages/xrpc/com.atproto.repo.uploadBlob.ts +76 -15
- package/src/pages/xrpc/com.atproto.server.checkAccountStatus.ts +20 -8
- package/src/pages/xrpc/com.atproto.server.createSession.ts +31 -11
- package/src/pages/xrpc/com.atproto.server.describeServer.ts +1 -1
- package/src/pages/xrpc/com.atproto.server.getServiceAuth.ts +12 -5
- package/src/pages/xrpc/com.atproto.server.getSession.ts +22 -8
- package/src/pages/xrpc/com.atproto.server.refreshSession.ts +30 -72
- package/src/pages/xrpc/com.atproto.sync.getBlob.ts +71 -22
- package/src/pages/xrpc/com.atproto.sync.getCheckout.json.ts +1 -1
- package/src/pages/xrpc/com.atproto.sync.getCheckout.ts +1 -1
- package/src/pages/xrpc/com.atproto.sync.getHead.ts +7 -2
- package/src/pages/xrpc/com.atproto.sync.getLatestCommit.ts +1 -1
- package/src/pages/xrpc/com.atproto.sync.getRecord.ts +5 -27
- package/src/pages/xrpc/com.atproto.sync.getRepo.json.ts +1 -1
- package/src/pages/xrpc/com.atproto.sync.getRepo.ts +50 -5
- package/src/pages/xrpc/com.atproto.sync.getRepoStatus.ts +58 -0
- package/src/pages/xrpc/com.atproto.sync.listBlobs.ts +1 -1
- package/src/pages/xrpc/com.atproto.sync.listRepos.ts +5 -3
- package/src/services/car.ts +207 -55
- package/src/services/r2-blob-store.ts +1 -1
- package/src/services/repo/blockstore-ops.ts +29 -0
- package/src/services/repo/operations.ts +133 -0
- package/src/services/repo-manager.ts +202 -253
- package/src/worker/runtime.ts +53 -8
- package/src/worker/sequencer/broadcast.ts +91 -0
- package/src/worker/sequencer/cid-helpers.ts +39 -0
- package/src/worker/sequencer/payload.ts +84 -0
- package/src/worker/sequencer/types.ts +36 -0
- package/src/worker/sequencer/upgrade.ts +141 -0
- package/src/worker/sequencer.ts +263 -405
- package/types/env.d.ts +15 -3
- package/src/pages/xrpc/app.bsky.actor.getProfile.ts +0 -49
- package/src/pages/xrpc/app.bsky.actor.getProfiles.ts +0 -51
- package/src/pages/xrpc/app.bsky.feed.getActorFeeds.ts +0 -25
- package/src/pages/xrpc/app.bsky.feed.getAuthorFeed.ts +0 -42
- package/src/pages/xrpc/app.bsky.feed.getFeedGenerators.ts +0 -25
- package/src/pages/xrpc/app.bsky.feed.getPostThread.ts +0 -37
- package/src/pages/xrpc/app.bsky.feed.getPosts.ts +0 -26
- package/src/pages/xrpc/app.bsky.feed.getSuggestedFeeds.ts +0 -23
- package/src/pages/xrpc/app.bsky.feed.getTimeline.ts +0 -47
- package/src/pages/xrpc/app.bsky.graph.getFollowers.ts +0 -29
- package/src/pages/xrpc/app.bsky.graph.getFollows.ts +0 -29
- package/src/pages/xrpc/app.bsky.notification.getUnreadCount.ts +0 -20
- package/src/pages/xrpc/app.bsky.notification.listNotifications.ts +0 -27
- package/src/pages/xrpc/app.bsky.unspecced.getSuggestedFeeds.ts +0 -23
package/types/env.d.ts
CHANGED
|
@@ -19,32 +19,44 @@ declare global {
|
|
|
19
19
|
DB: D1Database;
|
|
20
20
|
BLOBS: R2Bucket;
|
|
21
21
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|