an attempt to make a lightweight, easily self-hostable, scoped bluesky appview

index server and view server split

rimar1337 0b9e1a2a 6acec0ae

+5 -1
.env
··· 1 - JETSTREAM_URL="wss://jetstream2.us-east.bsky.network" 1 + # main indexers 2 + JETSTREAM_URL="wss://jetstream.whey.party" 2 3 SPACEDUST_URL="wss://spacedust.microcosm.blue" 4 + 5 + # for backfill (useless if you just started the instance right now) 3 6 CONSTELLATION_URL="https://constellation.microcosm.blue" 7 + # i dont actually know why i need this 4 8 SLINGSHOT_URL="https://slingshot.microcosm.blue" 5 9 6 10 SERVICE_DID="did:web:local3768forumtest.whey.party"
+1 -1
index/onboardingBackfill.ts
··· 1 - import { db, handleIndex } from "../main.ts" 1 + import { systemDB, handleIndex } from "../main.ts" 2 2 import { FINEPDSAndHandleFromDid } from "../utils/identity.ts"; 3 3 4 4
+64 -64
indexclient/index.ts
··· 5 5 XrpcClient, 6 6 type FetchHandler, 7 7 type FetchHandlerOptions, 8 - } from '@atproto/xrpc' 9 - import { schemas } from './lexicons.js' 10 - import { CID } from 'multiformats/cid' 11 - import { type OmitKey, type Un$Typed } from './util.js' 12 - import * as AppBskyActorDefs from './types/app/bsky/actor/defs.js' 13 - import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile.js' 14 - import * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles.js' 15 - import * as AppBskyEmbedDefs from './types/app/bsky/embed/defs.js' 16 - import * as AppBskyEmbedExternal from './types/app/bsky/embed/external.js' 17 - import * as AppBskyEmbedImages from './types/app/bsky/embed/images.js' 18 - import * as AppBskyEmbedRecord from './types/app/bsky/embed/record.js' 19 - import * as AppBskyEmbedRecordWithMedia from './types/app/bsky/embed/recordWithMedia.js' 20 - import * as AppBskyEmbedVideo from './types/app/bsky/embed/video.js' 21 - import * as AppBskyFeedDefs from './types/app/bsky/feed/defs.js' 22 - import * as AppBskyFeedGetActorFeeds from './types/app/bsky/feed/getActorFeeds.js' 23 - import * as AppBskyFeedGetFeedGenerator from './types/app/bsky/feed/getFeedGenerator.js' 24 - import * as AppBskyFeedGetFeedGenerators from './types/app/bsky/feed/getFeedGenerators.js' 25 - import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts.js' 26 - import * as AppBskyFeedPostgate from './types/app/bsky/feed/postgate.js' 27 - import * as AppBskyFeedThreadgate from './types/app/bsky/feed/threadgate.js' 28 - import * as AppBskyGraphDefs from './types/app/bsky/graph/defs.js' 29 - import * as AppBskyNotificationDefs from './types/app/bsky/notification/defs.js' 30 - import * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet.js' 31 - import * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.js' 32 - import * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.js' 33 - import * as PartyWheyAppBskyActorDefs from './types/party/whey/app/bsky/actor/defs.js' 34 - import * as PartyWheyAppBskyFeedDefs from './types/party/whey/app/bsky/feed/defs.js' 35 - import * as PartyWheyAppBskyFeedGetActorLikesPartial from './types/party/whey/app/bsky/feed/getActorLikesPartial.js' 36 - import * as PartyWheyAppBskyFeedGetAuthorFeedPartial from './types/party/whey/app/bsky/feed/getAuthorFeedPartial.js' 37 - import * as PartyWheyAppBskyFeedGetLikesPartial from './types/party/whey/app/bsky/feed/getLikesPartial.js' 38 - import * as PartyWheyAppBskyFeedGetListFeedPartial from './types/party/whey/app/bsky/feed/getListFeedPartial.js' 39 - import * as PartyWheyAppBskyFeedGetPostThreadPartial from './types/party/whey/app/bsky/feed/getPostThreadPartial.js' 40 - import * as PartyWheyAppBskyFeedGetQuotesPartial from './types/party/whey/app/bsky/feed/getQuotesPartial.js' 41 - import * as PartyWheyAppBskyFeedGetRepostedByPartial from './types/party/whey/app/bsky/feed/getRepostedByPartial.js' 8 + } from 'npm:@atproto/xrpc' 9 + import { schemas } from './lexicons.ts' 10 + import { CID } from 'npm:multiformats/cid' 11 + import { type OmitKey, type Un$Typed } from './util.ts' 12 + import * as AppBskyActorDefs from './types/app/bsky/actor/defs.ts' 13 + import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile.ts' 14 + import * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles.ts' 15 + import * as AppBskyEmbedDefs from './types/app/bsky/embed/defs.ts' 16 + import * as AppBskyEmbedExternal from './types/app/bsky/embed/external.ts' 17 + import * as AppBskyEmbedImages from './types/app/bsky/embed/images.ts' 18 + import * as AppBskyEmbedRecord from './types/app/bsky/embed/record.ts' 19 + import * as AppBskyEmbedRecordWithMedia from './types/app/bsky/embed/recordWithMedia.ts' 20 + import * as AppBskyEmbedVideo from './types/app/bsky/embed/video.ts' 21 + import * as AppBskyFeedDefs from './types/app/bsky/feed/defs.ts' 22 + import * as AppBskyFeedGetActorFeeds from './types/app/bsky/feed/getActorFeeds.ts' 23 + import * as AppBskyFeedGetFeedGenerator from './types/app/bsky/feed/getFeedGenerator.ts' 24 + import * as AppBskyFeedGetFeedGenerators from './types/app/bsky/feed/getFeedGenerators.ts' 25 + import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts.ts' 26 + import * as AppBskyFeedPostgate from './types/app/bsky/feed/postgate.ts' 27 + import * as AppBskyFeedThreadgate from './types/app/bsky/feed/threadgate.ts' 28 + import * as AppBskyGraphDefs from './types/app/bsky/graph/defs.ts' 29 + import * as AppBskyNotificationDefs from './types/app/bsky/notification/defs.ts' 30 + import * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet.ts' 31 + import * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.ts' 32 + import * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.ts' 33 + import * as PartyWheyAppBskyActorDefs from './types/party/whey/app/bsky/actor/defs.ts' 34 + import * as PartyWheyAppBskyFeedDefs from './types/party/whey/app/bsky/feed/defs.ts' 35 + import * as PartyWheyAppBskyFeedGetActorLikesPartial from './types/party/whey/app/bsky/feed/getActorLikesPartial.ts' 36 + import * as PartyWheyAppBskyFeedGetAuthorFeedPartial from './types/party/whey/app/bsky/feed/getAuthorFeedPartial.ts' 37 + import * as PartyWheyAppBskyFeedGetLikesPartial from './types/party/whey/app/bsky/feed/getLikesPartial.ts' 38 + import * as PartyWheyAppBskyFeedGetListFeedPartial from './types/party/whey/app/bsky/feed/getListFeedPartial.ts' 39 + import * as PartyWheyAppBskyFeedGetPostThreadPartial from './types/party/whey/app/bsky/feed/getPostThreadPartial.ts' 40 + import * as PartyWheyAppBskyFeedGetQuotesPartial from './types/party/whey/app/bsky/feed/getQuotesPartial.ts' 41 + import * as PartyWheyAppBskyFeedGetRepostedByPartial from './types/party/whey/app/bsky/feed/getRepostedByPartial.ts' 42 42 43 - export * as AppBskyActorDefs from './types/app/bsky/actor/defs.js' 44 - export * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile.js' 45 - export * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles.js' 46 - export * as AppBskyEmbedDefs from './types/app/bsky/embed/defs.js' 47 - export * as AppBskyEmbedExternal from './types/app/bsky/embed/external.js' 48 - export * as AppBskyEmbedImages from './types/app/bsky/embed/images.js' 49 - export * as AppBskyEmbedRecord from './types/app/bsky/embed/record.js' 50 - export * as AppBskyEmbedRecordWithMedia from './types/app/bsky/embed/recordWithMedia.js' 51 - export * as AppBskyEmbedVideo from './types/app/bsky/embed/video.js' 52 - export * as AppBskyFeedDefs from './types/app/bsky/feed/defs.js' 53 - export * as AppBskyFeedGetActorFeeds from './types/app/bsky/feed/getActorFeeds.js' 54 - export * as AppBskyFeedGetFeedGenerator from './types/app/bsky/feed/getFeedGenerator.js' 55 - export * as AppBskyFeedGetFeedGenerators from './types/app/bsky/feed/getFeedGenerators.js' 56 - export * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts.js' 57 - export * as AppBskyFeedPostgate from './types/app/bsky/feed/postgate.js' 58 - export * as AppBskyFeedThreadgate from './types/app/bsky/feed/threadgate.js' 59 - export * as AppBskyGraphDefs from './types/app/bsky/graph/defs.js' 60 - export * as AppBskyNotificationDefs from './types/app/bsky/notification/defs.js' 61 - export * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet.js' 62 - export * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.js' 63 - export * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.js' 64 - export * as PartyWheyAppBskyActorDefs from './types/party/whey/app/bsky/actor/defs.js' 65 - export * as PartyWheyAppBskyFeedDefs from './types/party/whey/app/bsky/feed/defs.js' 66 - export * as PartyWheyAppBskyFeedGetActorLikesPartial from './types/party/whey/app/bsky/feed/getActorLikesPartial.js' 67 - export * as PartyWheyAppBskyFeedGetAuthorFeedPartial from './types/party/whey/app/bsky/feed/getAuthorFeedPartial.js' 68 - export * as PartyWheyAppBskyFeedGetLikesPartial from './types/party/whey/app/bsky/feed/getLikesPartial.js' 69 - export * as PartyWheyAppBskyFeedGetListFeedPartial from './types/party/whey/app/bsky/feed/getListFeedPartial.js' 70 - export * as PartyWheyAppBskyFeedGetPostThreadPartial from './types/party/whey/app/bsky/feed/getPostThreadPartial.js' 71 - export * as PartyWheyAppBskyFeedGetQuotesPartial from './types/party/whey/app/bsky/feed/getQuotesPartial.js' 72 - export * as PartyWheyAppBskyFeedGetRepostedByPartial from './types/party/whey/app/bsky/feed/getRepostedByPartial.js' 43 + export * as AppBskyActorDefs from './types/app/bsky/actor/defs.ts' 44 + export * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile.ts' 45 + export * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles.ts' 46 + export * as AppBskyEmbedDefs from './types/app/bsky/embed/defs.ts' 47 + export * as AppBskyEmbedExternal from './types/app/bsky/embed/external.ts' 48 + export * as AppBskyEmbedImages from './types/app/bsky/embed/images.ts' 49 + export * as AppBskyEmbedRecord from './types/app/bsky/embed/record.ts' 50 + export * as AppBskyEmbedRecordWithMedia from './types/app/bsky/embed/recordWithMedia.ts' 51 + export * as AppBskyEmbedVideo from './types/app/bsky/embed/video.ts' 52 + export * as AppBskyFeedDefs from './types/app/bsky/feed/defs.ts' 53 + export * as AppBskyFeedGetActorFeeds from './types/app/bsky/feed/getActorFeeds.ts' 54 + export * as AppBskyFeedGetFeedGenerator from './types/app/bsky/feed/getFeedGenerator.ts' 55 + export * as AppBskyFeedGetFeedGenerators from './types/app/bsky/feed/getFeedGenerators.ts' 56 + export * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts.ts' 57 + export * as AppBskyFeedPostgate from './types/app/bsky/feed/postgate.ts' 58 + export * as AppBskyFeedThreadgate from './types/app/bsky/feed/threadgate.ts' 59 + export * as AppBskyGraphDefs from './types/app/bsky/graph/defs.ts' 60 + export * as AppBskyNotificationDefs from './types/app/bsky/notification/defs.ts' 61 + export * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet.ts' 62 + export * as ComAtprotoLabelDefs from './types/com/atproto/label/defs.ts' 63 + export * as ComAtprotoRepoStrongRef from './types/com/atproto/repo/strongRef.ts' 64 + export * as PartyWheyAppBskyActorDefs from './types/party/whey/app/bsky/actor/defs.ts' 65 + export * as PartyWheyAppBskyFeedDefs from './types/party/whey/app/bsky/feed/defs.ts' 66 + export * as PartyWheyAppBskyFeedGetActorLikesPartial from './types/party/whey/app/bsky/feed/getActorLikesPartial.ts' 67 + export * as PartyWheyAppBskyFeedGetAuthorFeedPartial from './types/party/whey/app/bsky/feed/getAuthorFeedPartial.ts' 68 + export * as PartyWheyAppBskyFeedGetLikesPartial from './types/party/whey/app/bsky/feed/getLikesPartial.ts' 69 + export * as PartyWheyAppBskyFeedGetListFeedPartial from './types/party/whey/app/bsky/feed/getListFeedPartial.ts' 70 + export * as PartyWheyAppBskyFeedGetPostThreadPartial from './types/party/whey/app/bsky/feed/getPostThreadPartial.ts' 71 + export * as PartyWheyAppBskyFeedGetQuotesPartial from './types/party/whey/app/bsky/feed/getQuotesPartial.ts' 72 + export * as PartyWheyAppBskyFeedGetRepostedByPartial from './types/party/whey/app/bsky/feed/getRepostedByPartial.ts' 73 73 74 74 export const APP_BSKY_FEED = { 75 75 DefsRequestLess: 'app.bsky.feed.defs#requestLess',
+2 -2
indexclient/lexicons.ts
··· 6 6 Lexicons, 7 7 ValidationError, 8 8 type ValidationResult, 9 - } from '@atproto/lexicon' 10 - import { type $Typed, is$typed, maybe$typed } from './util.js' 9 + } from 'npm:@atproto/lexicon' 10 + import { type $Typed, is$typed, maybe$typed } from './util.ts' 11 11 12 12 export const schemaDict = { 13 13 AppBskyActorDefs: {
+11 -11
indexclient/types/app/bsky/actor/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 12 - import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' 13 - import type * as AppBskyGraphDefs from '../graph/defs.js' 14 - import type * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef.js' 15 - import type * as AppBskyNotificationDefs from '../notification/defs.js' 16 - import type * as AppBskyFeedThreadgate from '../feed/threadgate.js' 17 - import type * as AppBskyFeedPostgate from '../feed/postgate.js' 18 - import type * as AppBskyEmbedExternal from '../embed/external.js' 11 + } from '../../../../util.ts' 12 + import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.ts' 13 + import type * as AppBskyGraphDefs from '../graph/defs.ts' 14 + import type * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef.ts' 15 + import type * as AppBskyNotificationDefs from '../notification/defs.ts' 16 + import type * as AppBskyFeedThreadgate from '../feed/threadgate.ts' 17 + import type * as AppBskyFeedPostgate from '../feed/postgate.ts' 18 + import type * as AppBskyEmbedExternal from '../embed/external.ts' 19 19 20 20 const is$typed = _is$typed, 21 21 validate = _validate
+6 -6
indexclient/types/app/bsky/actor/getProfile.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../util' 13 - import type * as AppBskyActorDefs from './defs.js' 12 + } from '../../../../util.ts' 13 + import type * as AppBskyActorDefs from './defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+6 -6
indexclient/types/app/bsky/actor/getProfiles.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../util' 13 - import type * as AppBskyActorDefs from './defs.js' 12 + } from '../../../../util.ts' 13 + import type * as AppBskyActorDefs from './defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+4 -4
indexclient/types/app/bsky/embed/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+4 -4
indexclient/types/app/bsky/embed/external.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+5 -5
indexclient/types/app/bsky/embed/images.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 12 - import type * as AppBskyEmbedDefs from './defs.js' 11 + } from '../../../../util.ts' 12 + import type * as AppBskyEmbedDefs from './defs.ts' 13 13 14 14 const is$typed = _is$typed, 15 15 validate = _validate
+14 -14
indexclient/types/app/bsky/embed/record.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 12 - import type * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef.js' 13 - import type * as AppBskyFeedDefs from '../feed/defs.js' 14 - import type * as AppBskyGraphDefs from '../graph/defs.js' 15 - import type * as AppBskyLabelerDefs from '../labeler/defs.js' 16 - import type * as AppBskyActorDefs from '../actor/defs.js' 17 - import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' 18 - import type * as AppBskyEmbedImages from './images.js' 19 - import type * as AppBskyEmbedVideo from './video.js' 20 - import type * as AppBskyEmbedExternal from './external.js' 21 - import type * as AppBskyEmbedRecordWithMedia from './recordWithMedia.js' 11 + } from '../../../../util.ts' 12 + import type * as ComAtprotoRepoStrongRef from '../../../com/atproto/repo/strongRef.ts' 13 + import type * as AppBskyFeedDefs from '../feed/defs.ts' 14 + import type * as AppBskyGraphDefs from '../graph/defs.ts' 15 + import type * as AppBskyLabelerDefs from '../labeler/defs.ts' 16 + import type * as AppBskyActorDefs from '../actor/defs.ts' 17 + import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.ts' 18 + import type * as AppBskyEmbedImages from './images.ts' 19 + import type * as AppBskyEmbedVideo from './video.ts' 20 + import type * as AppBskyEmbedExternal from './external.ts' 21 + import type * as AppBskyEmbedRecordWithMedia from './recordWithMedia.ts' 22 22 23 23 const is$typed = _is$typed, 24 24 validate = _validate
+8 -8
indexclient/types/app/bsky/embed/recordWithMedia.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 12 - import type * as AppBskyEmbedRecord from './record.js' 13 - import type * as AppBskyEmbedImages from './images.js' 14 - import type * as AppBskyEmbedVideo from './video.js' 15 - import type * as AppBskyEmbedExternal from './external.js' 11 + } from '../../../../util.ts' 12 + import type * as AppBskyEmbedRecord from './record.ts' 13 + import type * as AppBskyEmbedImages from './images.ts' 14 + import type * as AppBskyEmbedVideo from './video.ts' 15 + import type * as AppBskyEmbedExternal from './external.ts' 16 16 17 17 const is$typed = _is$typed, 18 18 validate = _validate
+5 -5
indexclient/types/app/bsky/embed/video.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 12 - import type * as AppBskyEmbedDefs from './defs.js' 11 + } from '../../../../util.ts' 12 + import type * as AppBskyEmbedDefs from './defs.ts' 13 13 14 14 const is$typed = _is$typed, 15 15 validate = _validate
+13 -13
indexclient/types/app/bsky/feed/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 12 - import type * as AppBskyActorDefs from '../actor/defs.js' 13 - import type * as AppBskyEmbedImages from '../embed/images.js' 14 - import type * as AppBskyEmbedVideo from '../embed/video.js' 15 - import type * as AppBskyEmbedExternal from '../embed/external.js' 16 - import type * as AppBskyEmbedRecord from '../embed/record.js' 17 - import type * as AppBskyEmbedRecordWithMedia from '../embed/recordWithMedia.js' 18 - import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' 19 - import type * as AppBskyRichtextFacet from '../richtext/facet.js' 20 - import type * as AppBskyGraphDefs from '../graph/defs.js' 11 + } from '../../../../util.ts' 12 + import type * as AppBskyActorDefs from '../actor/defs.ts' 13 + import type * as AppBskyEmbedImages from '../embed/images.ts' 14 + import type * as AppBskyEmbedVideo from '../embed/video.ts' 15 + import type * as AppBskyEmbedExternal from '../embed/external.ts' 16 + import type * as AppBskyEmbedRecord from '../embed/record.ts' 17 + import type * as AppBskyEmbedRecordWithMedia from '../embed/recordWithMedia.ts' 18 + import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.ts' 19 + import type * as AppBskyRichtextFacet from '../richtext/facet.ts' 20 + import type * as AppBskyGraphDefs from '../graph/defs.ts' 21 21 22 22 const is$typed = _is$typed, 23 23 validate = _validate
+6 -6
indexclient/types/app/bsky/feed/getActorFeeds.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../util' 13 - import type * as AppBskyFeedDefs from './defs.js' 12 + } from '../../../../util.ts' 13 + import type * as AppBskyFeedDefs from './defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+6 -6
indexclient/types/app/bsky/feed/getFeedGenerator.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../util' 13 - import type * as AppBskyFeedDefs from './defs.js' 12 + } from '../../../../util.ts' 13 + import type * as AppBskyFeedDefs from './defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+6 -6
indexclient/types/app/bsky/feed/getFeedGenerators.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../util' 13 - import type * as AppBskyFeedDefs from './defs.js' 12 + } from '../../../../util.ts' 13 + import type * as AppBskyFeedDefs from './defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+6 -6
indexclient/types/app/bsky/feed/getPosts.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../util' 13 - import type * as AppBskyFeedDefs from './defs.js' 12 + } from '../../../../util.ts' 13 + import type * as AppBskyFeedDefs from './defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+4 -4
indexclient/types/app/bsky/feed/postgate.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+4 -4
indexclient/types/app/bsky/feed/threadgate.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+8 -8
indexclient/types/app/bsky/graph/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 12 - import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' 13 - import type * as AppBskyActorDefs from '../actor/defs.js' 14 - import type * as AppBskyRichtextFacet from '../richtext/facet.js' 15 - import type * as AppBskyFeedDefs from '../feed/defs.js' 11 + } from '../../../../util.ts' 12 + import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.ts' 13 + import type * as AppBskyActorDefs from '../actor/defs.ts' 14 + import type * as AppBskyRichtextFacet from '../richtext/facet.ts' 15 + import type * as AppBskyFeedDefs from '../feed/defs.ts' 16 16 17 17 const is$typed = _is$typed, 18 18 validate = _validate
+4 -4
indexclient/types/app/bsky/notification/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+4 -4
indexclient/types/app/bsky/richtext/facet.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+4 -4
indexclient/types/com/atproto/label/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+4 -4
indexclient/types/com/atproto/repo/strongRef.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../util' 11 + } from '../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+4 -4
indexclient/types/party/whey/app/bsky/actor/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../../../util' 11 + } from '../../../../../../util.ts' 12 12 13 13 const is$typed = _is$typed, 14 14 validate = _validate
+7 -7
indexclient/types/party/whey/app/bsky/feed/defs.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 5 - import { CID } from 'multiformats/cid' 6 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 5 + import { CID } from 'npm:multiformats/cid' 6 + import { validate as _validate } from '../../../../../../lexicons.ts' 7 7 import { 8 8 type $Typed, 9 9 is$typed as _is$typed, 10 10 type OmitKey, 11 - } from '../../../../../../util' 12 - import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.js' 13 - import type * as PartyWheyAppBskyActorDefs from '../actor/defs.js' 14 - import type * as AppBskyActorDefs from '../../../../../app/bsky/actor/defs.js' 11 + } from '../../../../../../util.ts' 12 + import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.ts' 13 + import type * as PartyWheyAppBskyActorDefs from '../actor/defs.ts' 14 + import type * as AppBskyActorDefs from '../../../../../app/bsky/actor/defs.ts' 15 15 16 16 const is$typed = _is$typed, 17 17 validate = _validate
+7 -7
indexclient/types/party/whey/app/bsky/feed/getActorLikesPartial.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../../../util' 13 - import type * as PartyWheyAppBskyFeedDefs from './defs.js' 14 - import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.js' 12 + } from '../../../../../../util.ts' 13 + import type * as PartyWheyAppBskyFeedDefs from './defs.ts' 14 + import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.ts' 15 15 16 16 const is$typed = _is$typed, 17 17 validate = _validate
+7 -7
indexclient/types/party/whey/app/bsky/feed/getAuthorFeedPartial.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../../../util' 13 - import type * as PartyWheyAppBskyFeedDefs from './defs.js' 14 - import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.js' 12 + } from '../../../../../../util.ts' 13 + import type * as PartyWheyAppBskyFeedDefs from './defs.ts' 14 + import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.ts' 15 15 16 16 const is$typed = _is$typed, 17 17 validate = _validate
+6 -6
indexclient/types/party/whey/app/bsky/feed/getLikesPartial.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../../../util' 13 - import type * as PartyWheyAppBskyActorDefs from '../actor/defs.js' 12 + } from '../../../../../../util.ts' 13 + import type * as PartyWheyAppBskyActorDefs from '../actor/defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+6 -6
indexclient/types/party/whey/app/bsky/feed/getListFeedPartial.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../../../util' 13 - import type * as PartyWheyAppBskyFeedDefs from './defs.js' 12 + } from '../../../../../../util.ts' 13 + import type * as PartyWheyAppBskyFeedDefs from './defs.ts' 14 14 15 15 const is$typed = _is$typed, 16 16 validate = _validate
+7 -7
indexclient/types/party/whey/app/bsky/feed/getPostThreadPartial.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../../../util' 13 - import type * as PartyWheyAppBskyFeedDefs from './defs.js' 14 - import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.js' 12 + } from '../../../../../../util.ts' 13 + import type * as PartyWheyAppBskyFeedDefs from './defs.ts' 14 + import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.ts' 15 15 16 16 const is$typed = _is$typed, 17 17 validate = _validate
+7 -7
indexclient/types/party/whey/app/bsky/feed/getQuotesPartial.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../../../util' 13 - import type * as PartyWheyAppBskyFeedDefs from './defs.js' 14 - import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.js' 12 + } from '../../../../../../util.ts' 13 + import type * as PartyWheyAppBskyFeedDefs from './defs.ts' 14 + import type * as AppBskyFeedDefs from '../../../../../app/bsky/feed/defs.ts' 15 15 16 16 const is$typed = _is$typed, 17 17 validate = _validate
+7 -7
indexclient/types/party/whey/app/bsky/feed/getRepostedByPartial.ts
··· 1 1 /** 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 - import { HeadersMap, XRPCError } from '@atproto/xrpc' 5 - import { type ValidationResult, BlobRef } from '@atproto/lexicon' 6 - import { CID } from 'multiformats/cid' 7 - import { validate as _validate } from '../../../../../../lexicons' 4 + import { HeadersMap, XRPCError } from 'npm:@atproto/xrpc' 5 + import { type ValidationResult, BlobRef } from 'npm:@atproto/lexicon' 6 + import { CID } from 'npm:multiformats/cid' 7 + import { validate as _validate } from '../../../../../../lexicons.ts' 8 8 import { 9 9 type $Typed, 10 10 is$typed as _is$typed, 11 11 type OmitKey, 12 - } from '../../../../../../util' 13 - import type * as PartyWheyAppBskyActorDefs from '../actor/defs.js' 14 - import type * as AppBskyActorDefs from '../../../../../app/bsky/actor/defs.js' 12 + } from '../../../../../../util.ts' 13 + import type * as PartyWheyAppBskyActorDefs from '../actor/defs.ts' 14 + import type * as AppBskyActorDefs from '../../../../../app/bsky/actor/defs.ts' 15 15 16 16 const is$typed = _is$typed, 17 17 validate = _validate
+1 -1
indexclient/util.ts
··· 2 2 * GENERATED CODE - DO NOT MODIFY 3 3 */ 4 4 5 - import { type ValidationResult } from '@atproto/lexicon' 5 + import { type ValidationResult } from 'npm:@atproto/lexicon' 6 6 7 7 export type OmitKey<T, K extends keyof T> = { 8 8 [K2 in keyof T as K2 extends K ? never : K2]: T[K2]
+9
indexserver.ts
··· 1 + export async function indexServerHandler(req: Request): Promise<Response> { 2 + const url = new URL(req.url); 3 + 4 + if (url.pathname === "/ping") { 5 + return new Response("pong", { status: 200 }); 6 + } 7 + 8 + return new Response("Not Found", { status: 404 }); 9 + }
+47 -713
main.ts
··· 1 1 import { setupAuth, getAuthenticatedDid, authVerifier } from "./utils/auth.ts"; 2 2 import { JetstreamManager, SpacedustManager } from "./utils/sharders.ts"; 3 3 import { resolveRecordFromURI, validateRecord } from "./utils/records.ts"; 4 - import dbsetup from "./utils/dbsetup.ts"; 4 + import { setupSystemDb } from "./utils/dbsystem.ts"; 5 + import { setupUserDb } from "./utils/dbuser.ts"; 5 6 import { handleSpacedust, startSpacedust } from "./index/spacedust.ts"; 6 7 import { handleJetstream, startJetstream } from "./index/jetstream.ts"; 7 8 import { Database } from "jsr:@db/sqlite@0.11"; 8 9 //import express from "npm:express"; 9 10 //import { createServer } from "./xrpc/index.ts"; 10 11 import { indexHandlerContext } from "./index/types.ts"; 11 - import * as XRPCTypes from "./utils/viewserver.ts"; 12 + import * as IndexServerTypes from "./utils/indexservertypes.ts"; 13 + import * as ViewServerTypes from "./utils/viewservertypes.ts"; 12 14 import * as ATPAPI from "npm:@atproto/api"; 13 15 import { didDocument } from "./utils/diddoc.ts"; 14 - 15 - import ky from "npm:ky"; 16 - import QuickLRU from "npm:quick-lru"; 17 - import { isGeneratorView } from "./viewserver/types/app/bsky/feed/defs.ts"; 18 - import { createHash } from "node:crypto"; 19 - 20 - const cache = new QuickLRU({ maxSize: 10000 }); 21 - 22 - function simpleHashAuth(auth: string): string { 23 - return createHash("sha256").update(auth).digest("hex"); 24 - } 25 - export async function cachedFetch(url: string, auth?: string) { 26 - const cacheKey = auth ? `${url}|${simpleHashAuth(auth)}` : url; 27 - if (cache.has(cacheKey)) return cache.get(cacheKey); 28 - 29 - const data = await ky 30 - .get(url, { 31 - headers: { 32 - Authorization: `${auth}`, // or `Basic`, etc. depending on your needs 33 - }, 34 - }) 35 - .json(); 36 - 37 - cache.set(cacheKey, data); 38 - return data; 39 - } 16 + import { cachedFetch, searchParamsToJson } from "./utils/server.ts"; 17 + import { indexServerHandler } from "./indexserver.ts"; 18 + import { viewServerHandler } from "./viewserver.ts"; 40 19 41 - const slingshoturl = Deno.env.get("SLINGSHOT_URL"); 42 - const constellationurl = Deno.env.get("CONSTELLATION_URL"); 43 - const spacedusturl = Deno.env.get("SPACEDUST_URL"); 20 + export const slingshoturl = Deno.env.get("SLINGSHOT_URL"); 21 + export const constellationurl = Deno.env.get("CONSTELLATION_URL"); 22 + export const spacedusturl = Deno.env.get("SPACEDUST_URL"); 44 23 45 24 // ------------------------------------------ 46 25 // AppView Setup 47 26 // ------------------------------------------ 48 27 49 - export const db = new Database("whatever.db"); 50 - dbsetup(); 28 + export const systemDB = new Database("system.db"); 29 + setupSystemDb(systemDB); 30 + 51 31 export const spacedustManager = new SpacedustManager((msg) => 52 32 handleSpacedust(msg) 53 33 ); ··· 68 48 // XRPC Method Implementations 69 49 // ------------------------------------------ 70 50 71 - // begin the hell of implementing api requests and incoming records 72 - //const seenStrings = new Set<string>(); 73 - 74 - type SlingshotMiniDoc = { 75 - did: string; 76 - handle: string; 77 - pds: string; 78 - signing_key: string; 79 - }; 80 - type ConstellationDistinctDids = { 81 - total: number; 82 - linking_dids: string[]; 83 - cursor: string; 84 - }; 85 - type GetRecord = { 86 - uri: string; 87 - cid: string; 88 - value: Record<string, unknown>; 89 - }; 90 - let preferences: any = undefined; 91 - 92 - function searchParamsToJson(params: URLSearchParams): Record<string, unknown> { 93 - const result: Record<string, string | string[]> = {}; 94 - 95 - for (const [key, value] of params.entries()) { 96 - if (result.hasOwnProperty(key)) { 97 - const existing = result[key]; 98 - if (Array.isArray(existing)) { 99 - existing.push(value); 100 - } else { 101 - result[key] = [existing, value]; 102 - } 103 - } else { 104 - result[key] = value; 105 - } 106 - } 107 - 108 - return result; 109 - } 110 - 111 - async function resolveIdentity(actor: string): Promise<SlingshotMiniDoc> { 112 - const url = `${slingshoturl}/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${actor}`; 113 - return (await cachedFetch(url)) as SlingshotMiniDoc; 114 - } 115 - async function getRecord({ 116 - pds, 117 - did, 118 - collection, 119 - rkey, 120 - }: { 121 - pds: string; 122 - did: string; 123 - collection: string; 124 - rkey: string; 125 - }): Promise<{ cursor?: string; records: GetRecord[] }> { 126 - const url = `${pds}/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=${collection}&rkey=${rkey}`; 127 - const result = (await cachedFetch(url)) as { 128 - cursor?: string; 129 - records: GetRecord[]; 130 - }; 131 - return result as { 132 - cursor?: string; 133 - records: { 134 - uri: string; 135 - cid: string; 136 - value: ATPAPI.AppBskyFeedPost.Record; 137 - }[]; 138 - }; 139 - } 140 - 141 - async function listPostRecords({ 142 - pds, 143 - did, 144 - limit = 50, 145 - cursor, 146 - }: { 147 - pds: string; 148 - did: string; 149 - limit: number; 150 - cursor?: string; 151 - }): Promise<{ 152 - cursor?: string; 153 - records: { uri: string; cid: string; value: ATPAPI.AppBskyFeedPost.Record }[]; 154 - }> { 155 - const url = `${pds}/xrpc/com.atproto.repo.listRecords?repo=${did}&collection=app.bsky.feed.post&limit=${limit}${ 156 - cursor ? `&cursor=${cursor}` : "" 157 - }`; 158 - const result = (await cachedFetch(url)) as { 159 - cursor?: string; 160 - records: GetRecord[]; 161 - }; 162 - return result as { 163 - cursor?: string; 164 - records: { 165 - uri: string; 166 - cid: string; 167 - value: ATPAPI.AppBskyFeedPost.Record; 168 - }[]; 169 - }; 170 - } 171 - 172 - async function getSlingshotRecord( 173 - did: string, 174 - collection: string, 175 - rkey: string 176 - ): Promise<GetRecord> { 177 - const url = `${slingshoturl}/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=${collection}&rkey=${rkey}`; 178 - const result = (await cachedFetch(url)) as GetRecord; 179 - return result as GetRecord; 180 - } 181 - 182 - // async function getProfileRecord(did: string): Promise<ATPAPI.AppBskyActorProfile.Record> { 183 - // const url = `${slingshoturl}/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=app.bsky.actor.profile&rkey=self`; 184 - // const result = await cachedFetch(url) as GetRecord; 185 - // return result.value as ATPAPI.AppBskyActorProfile.Record; 186 - // } 187 - 188 - async function getUniqueCount({ 189 - did, 190 - collection, 191 - path, 192 - }: { 193 - did: string; 194 - collection: string; 195 - path: string; 196 - }): Promise<number> { 197 - const url = `${constellationurl}/links/count/distinct-dids?target=${did}&collection=${collection}&path=${path}`; 198 - const result = (await cachedFetch(url)) as ConstellationDistinctDids; 199 - return result.total; 200 - } 201 - 202 - function buildBlobUrl( 203 - pds: string, 204 - did: string, 205 - cid: string 206 - ): string | undefined { 207 - if (!pds || !did || !cid) return undefined; 208 - return `${pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`; 209 - } 210 - 211 - function didWebToHttps(did: string) { 212 - if (!did.startsWith("did:web:")) return null; 213 - const parts = did.slice("did:web:".length).split(":"); 214 - const [domain, ...path] = parts; 215 - return `https://${domain}${path.length ? "/" + path.join("/") : ""}`; 216 - } 217 - 218 - async function sendItToApiBskyApp(req: Request): Promise<Response> { 219 - const url = new URL(req.url); 220 - const pathname = url.pathname; 221 - const searchParams = searchParamsToJson(url.searchParams); 222 - let reqBody: undefined | string; 223 - let jsonbody: undefined | Record<string, unknown>; 224 - if (req.body) { 225 - const body = await req.json(); 226 - jsonbody = body; 227 - // console.log( 228 - // `called at euh reqreqreqreq: ${pathname}\n\n${JSON.stringify(body)}` 229 - // ); 230 - reqBody = JSON.stringify(body, null, 2); 231 - } 232 - const bskyUrl = `https://api.bsky.app${pathname}${url.search}`; 233 - const proxyHeaders = new Headers(req.headers); 234 - 235 - // Remove Authorization and set browser-like User-Agent 236 - proxyHeaders.delete("authorization"); 237 - proxyHeaders.delete("Access-Control-Allow-Origin"), 238 - proxyHeaders.set( 239 - "user-agent", 240 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" 241 - ); 242 - proxyHeaders.set("Access-Control-Allow-Origin", "*"); 243 - 244 - const proxyRes = await fetch(bskyUrl, { 245 - method: req.method, 246 - headers: proxyHeaders, 247 - body: ["GET", "HEAD"].includes(req.method.toUpperCase()) 248 - ? undefined 249 - : reqBody, 250 - }); 251 - 252 - const resBody = await proxyRes.text(); 253 - 254 - // console.log( 255 - // "← Response:", 256 - // JSON.stringify(await JSON.parse(resBody), null, 2) 257 - // ); 258 - 259 - return new Response(resBody, { 260 - status: proxyRes.status, 261 - headers: proxyRes.headers, 262 - }); 263 - } 51 + const indexServerRoutes = new Set([ 52 + "/xrpc/app.bsky.actor.getProfile", 53 + "/xrpc/app.bsky.actor.getProfiles", 54 + "/xrpc/app.bsky.feed.getActorFeeds", 55 + "/xrpc/app.bsky.feed.getFeedGenerator", 56 + "/xrpc/app.bsky.feed.getFeedGenerators", 57 + "/xrpc/app.bsky.feed.getPosts", 58 + "/xrpc/party.whey.app.bsky.feed.getActorLikesPartial", 59 + "/xrpc/party.whey.app.bsky.feed.getAuthorFeedPartial", 60 + "/xrpc/party.whey.app.bsky.feed.getLikesPartial", 61 + "/xrpc/party.whey.app.bsky.feed.getPostThreadPartial", 62 + "/xrpc/party.whey.app.bsky.feed.getQuotesPartial", 63 + "/xrpc/party.whey.app.bsky.feed.getRepostedByPartial", 64 + ]); 264 65 265 66 Deno.serve( 266 67 { port: Number(`${Deno.env.get("SERVER_PORT")}`) }, 267 68 async (req: Request): Promise<Response> => { 268 69 const url = new URL(req.url); 269 70 const pathname = url.pathname; 270 - const searchParams = searchParamsToJson(url.searchParams); 271 - let reqBody: undefined | string; 272 - let jsonbody: undefined | Record<string, unknown>; 273 - try { 274 - const clone = req.clone(); 275 - jsonbody = await clone.json(); 276 - } catch (e) { 277 - console.warn("Request body is not valid JSON:", e); 278 - } 71 + // const searchParams = searchParamsToJson(url.searchParams); 72 + // let reqBody: undefined | string; 73 + // let jsonbody: undefined | Record<string, unknown>; 74 + // try { 75 + // const clone = req.clone(); 76 + // jsonbody = await clone.json(); 77 + // } catch (e) { 78 + // console.warn("Request body is not valid JSON:", e); 79 + // } 279 80 if (pathname === "/.well-known/did.json") { 280 81 return new Response(JSON.stringify(didDocument), { 281 82 headers: withCors({ "Content-Type": "application/json" }), ··· 299 100 }, 300 101 }); 301 102 } 302 - 303 - // if (seenStrings.has(url.hash)) { 304 - // // The string has been seen before 305 - // seenStrings.delete(url.hash); 306 - // return new Response("OK", { 307 - // status: 204, 308 - // headers: withCors({ 309 - // "Content-Type": "text/plain", 310 - // }), 311 - // }); 312 - // } 313 - // seenStrings.add(url.hash); 314 - //const reqBody = req.body ? await req.text() : null; 315 - 316 - console.log("→ Path:", pathname); 317 - console.log("→ Auth:", req.headers.get("authorization")); 318 - console.log("→ Body:", reqBody); 319 - console.log("→ Params:", searchParams); 320 - 321 - const bskyUrl = `https://api.bsky.app${pathname}${url.search}`; 322 - const hasAuth = req.headers.has("authorization"); 323 - const xrpcMethod = pathname.startsWith("/xrpc/") 324 - ? pathname.slice("/xrpc/".length) 325 - : null; 326 - 327 - if (xrpcMethod === "app.bsky.unspecced.getTrendingTopics") { 328 - // const jsonTyped = 329 - // jsonUntyped as XRPCTypes.AppBskyUnspeccedGetTrendingTopics.QueryParams; 330 - 331 - const faketopics: ATPAPI.AppBskyUnspeccedDefs.TrendingTopic[] = [ 332 - { 333 - $type: "app.bsky.unspecced.defs#trendingTopic", 334 - topic: "Git Repo", 335 - displayName: "Git Repo", 336 - description: "Git Repo", 337 - link: "https://tangled.sh/@whey.party/skylite", 338 - }, 339 - { 340 - $type: "app.bsky.unspecced.defs#trendingTopic", 341 - topic: "Red Dwarf Lite", 342 - displayName: "Red Dwarf Lite", 343 - description: "Red Dwarf Lite", 344 - link: "https://reddwarflite.whey.party/", 345 - }, 346 - { 347 - $type: "app.bsky.unspecced.defs#trendingTopic", 348 - topic: "whey dot party", 349 - displayName: "whey dot party", 350 - description: "whey dot party", 351 - link: "https://whey.party/", 352 - }, 353 - ]; 354 - 355 - const response: XRPCTypes.AppBskyUnspeccedGetTrendingTopics.OutputSchema = 356 - { 357 - topics: faketopics, 358 - suggested: faketopics, 359 - }; 360 - 361 - return new Response(JSON.stringify(response), { 362 - headers: withCors({ "Content-Type": "application/json" }), 363 - }); 364 - } 365 - 366 - //if (xrpcMethod !== 'app.bsky.actor.getPreferences' && xrpcMethod !== 'app.bsky.notification.listNotifications') { 367 - if ( 368 - !hasAuth 369 - // (!hasAuth || 370 - // xrpcMethod === "app.bsky.labeler.getServices" || 371 - // xrpcMethod === "app.bsky.unspecced.getConfig") && 372 - // xrpcMethod !== "app.bsky.notification.putPreferences" 373 - ) { 374 - return new Response( 375 - JSON.stringify({ 376 - error: "XRPCNotSupported", 377 - message: 378 - "HEY hello there my name is whey dot party and you have used my custom appview that is very cool but have you considered that XRPC Not Supported", 379 - }), 380 - { 381 - status: 404, 382 - headers: withCors({ "Content-Type": "application/json" }), 383 - } 384 - ); 385 - //return await sendItToApiBskyApp(req); 386 - } 387 - if ( 388 - // !hasAuth || 389 - xrpcMethod === "app.bsky.labeler.getServices" || 390 - xrpcMethod === "app.bsky.unspecced.getConfig" //&& 391 - //xrpcMethod !== "app.bsky.notification.putPreferences" 392 - ) { 393 - return new Response( 394 - JSON.stringify({ 395 - error: "XRPCNotSupported", 396 - message: 397 - "HEY hello there my name is whey dot party and you have used my custom appview that is very cool but have you considered that XRPC Not Supported", 398 - }), 399 - { 400 - status: 404, 401 - headers: withCors({ "Content-Type": "application/json" }), 402 - } 403 - ); 404 - //return await sendItToApiBskyApp(req); 405 - } 406 - 407 - const authDID = "did:plc:mn45tewwnse5btfftvd3powc"; //getAuthenticatedDid(req); 408 - 409 - const jsonUntyped = searchParams; 410 - 411 - switch (xrpcMethod) { 412 - case "app.bsky.feed.getFeedGenerators": { 413 - const jsonTyped = 414 - jsonUntyped as XRPCTypes.AppBskyFeedGetFeedGenerators.QueryParams; 415 - 416 - const feeds: ATPAPI.AppBskyFeedDefs.GeneratorView[] = ( 417 - await Promise.all( 418 - jsonTyped.feeds.map(async (feed) => { 419 - try { 420 - const did = new ATPAPI.AtUri(feed).hostname; 421 - const rkey = new ATPAPI.AtUri(feed).rkey; 422 - const identity = await resolveIdentity(did); 423 - const feedgetRecord = await getSlingshotRecord( 424 - identity.did, 425 - "app.bsky.feed.generator", 426 - rkey 427 - ); 428 - const profile = ( 429 - await getSlingshotRecord( 430 - identity.did, 431 - "app.bsky.actor.profile", 432 - "self" 433 - ) 434 - ).value as ATPAPI.AppBskyActorProfile.Record; 435 - const anyprofile = profile as any; 436 - const value = 437 - feedgetRecord.value as ATPAPI.AppBskyFeedGenerator.Record; 438 - 439 - return { 440 - $type: "app.bsky.feed.defs#generatorView", 441 - uri: feed, 442 - cid: feedgetRecord.cid, 443 - did: identity.did, 444 - creator: /*AppBskyActorDefs.ProfileView*/ { 445 - $type: "app.bsky.actor.defs#profileView", 446 - did: identity.did, 447 - handle: identity.handle, 448 - displayName: profile.displayName, 449 - description: profile.description, 450 - avatar: buildBlobUrl( 451 - identity.pds, 452 - identity.did, 453 - anyprofile.avatar.ref["$link"] 454 - ), 455 - //associated?: ProfileAssociated 456 - //indexedAt?: string 457 - //createdAt?: string 458 - //viewer?: ViewerState 459 - //labels?: ComAtprotoLabelDefs.Label[] 460 - //verification?: VerificationState 461 - //status?: StatusView 462 - }, 463 - displayName: value.displayName, 464 - description: value.description, 465 - //descriptionFacets?: AppBskyRichtextFacet.Main[] 466 - avatar: buildBlobUrl( 467 - identity.pds, 468 - identity.did, 469 - (value as any).avatar.ref["$link"] 470 - ), 471 - //likeCount?: number 472 - //acceptsInteractions?: boolean 473 - //labels?: ComAtprotoLabelDefs.Label[] 474 - //viewer?: GeneratorViewerState 475 - contentMode: value.contentMode, 476 - indexedAt: new Date().toISOString(), 477 - }; 478 - } catch (err) { 479 - return undefined; 480 - } 481 - }) 482 - ) 483 - ).filter(isGeneratorView); 484 - 485 - const response: XRPCTypes.AppBskyFeedGetFeedGenerators.OutputSchema = { 486 - feeds: feeds ? feeds : [], 487 - }; 488 - 489 - return new Response(JSON.stringify(response), { 490 - headers: withCors({ "Content-Type": "application/json" }), 491 - }); 492 - } 493 - case "app.bsky.feed.getFeed": { 494 - const jsonTyped = 495 - jsonUntyped as XRPCTypes.AppBskyFeedGetFeed.QueryParams; 496 - const cursor = jsonTyped.cursor; 497 - const feed = jsonTyped.feed; 498 - const limit = jsonTyped.limit; 499 - const proxyauth = req.headers.get("authorization") || ""; 500 - 501 - const did = new ATPAPI.AtUri(feed).hostname; 502 - const rkey = new ATPAPI.AtUri(feed).rkey; 503 - const identity = await resolveIdentity(did); 504 - const feedgetRecord = ( 505 - await getSlingshotRecord( 506 - identity.did, 507 - "app.bsky.feed.generator", 508 - rkey 509 - ) 510 - ).value as ATPAPI.AppBskyFeedGenerator.Record; 511 - 512 - const skeleton = (await cachedFetch( 513 - `${didWebToHttps( 514 - feedgetRecord.did 515 - )}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${jsonTyped.feed}${ 516 - cursor ? `&cursor=${cursor}` : "" 517 - }${limit ? `&limit=${limit}` : ""}`, 518 - proxyauth 519 - )) as ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema; 520 - 521 - const nextcursor = skeleton.cursor; 522 - const dbgrqstid = skeleton.reqId; 523 - const uriarray = skeleton.feed; 524 - 525 - // Step 1: Chunk into 25 max 526 - const chunks = []; 527 - for (let i = 0; i < uriarray.length; i += 25) { 528 - chunks.push(uriarray.slice(i, i + 25)); 529 - } 530 - 531 - // Step 2: Hydrate via getPosts 532 - const hydratedPosts: ATPAPI.AppBskyFeedDefs.FeedViewPost[] = []; 533 - 534 - for (const chunk of chunks) { 535 - const searchParams = new URLSearchParams(); 536 - for (const uri of chunk.map((item) => item.post)) { 537 - searchParams.append("uris", uri); 538 - } 539 - 540 - const postResp = await ky 541 - .get(`https://api.bsky.app/xrpc/app.bsky.feed.getPosts`, { 542 - // headers: { 543 - // Authorization: proxyauth, 544 - // }, 545 - searchParams, 546 - }) 547 - .json<ATPAPI.AppBskyFeedGetPosts.OutputSchema>(); 548 - 549 - for (const post of postResp.posts) { 550 - const matchingSkeleton = uriarray.find( 551 - (item) => item.post === post.uri 552 - ); 553 - if (matchingSkeleton) { 554 - //post.author.handle = post.author.handle + ".percent40.api.bsky.app"; // or any logic to modify it 555 - hydratedPosts.push({ 556 - post, 557 - reason: matchingSkeleton.reason, 558 - //reply: matchingSkeleton, 559 - }); 560 - } 561 - } 562 - } 563 - 564 - // Step 3: Compose final response 565 - const response: XRPCTypes.AppBskyFeedGetFeed.OutputSchema = { 566 - feed: hydratedPosts, 567 - cursor: nextcursor, 568 - }; 569 - 570 - return new Response(JSON.stringify(response), { 571 - headers: withCors({ "Content-Type": "application/json" }), 572 - }); 573 - } 574 - case "app.bsky.actor.getProfile": { 575 - const jsonTyped = 576 - jsonUntyped as XRPCTypes.AppBskyActorGetProfile.QueryParams; 577 - 578 - const userindexservice = ""; 579 - const isbskyfallback = true; 580 - if (isbskyfallback) { 581 - return sendItToApiBskyApp(req); 582 - } 583 - 584 - const response: XRPCTypes.AppBskyActorGetProfile.OutputSchema = {}; 585 - 586 - return new Response(JSON.stringify(response), { 587 - headers: withCors({ "Content-Type": "application/json" }), 588 - }); 589 - } 590 - 591 - case "app.bsky.actor.getProfiles": { 592 - const jsonTyped = 593 - jsonUntyped as XRPCTypes.AppBskyActorGetProfiles.QueryParams; 594 - 595 - const userindexservice = ""; 596 - const isbskyfallback = true; 597 - if (isbskyfallback) { 598 - return sendItToApiBskyApp(req); 599 - } 600 - 601 - const response: XRPCTypes.AppBskyActorGetProfiles.OutputSchema = {}; 602 - 603 - return new Response(JSON.stringify(response), { 604 - headers: withCors({ "Content-Type": "application/json" }), 605 - }); 606 - } 607 - case "app.bsky.feed.getAuthorFeed": { 608 - const jsonTyped = 609 - jsonUntyped as XRPCTypes.AppBskyFeedGetAuthorFeed.QueryParams; 610 - 611 - const userindexservice = ""; 612 - const isbskyfallback = true; 613 - if (isbskyfallback) { 614 - return sendItToApiBskyApp(req); 615 - } 616 - 617 - const response: XRPCTypes.AppBskyFeedGetAuthorFeed.OutputSchema = {}; 618 - 619 - return new Response(JSON.stringify(response), { 620 - headers: withCors({ "Content-Type": "application/json" }), 621 - }); 622 - } 623 - case "app.bsky.feed.getPostThread": { 624 - const jsonTyped = 625 - jsonUntyped as XRPCTypes.AppBskyFeedGetPostThread.QueryParams; 626 - 627 - const userindexservice = ""; 628 - const isbskyfallback = true; 629 - if (isbskyfallback) { 630 - return sendItToApiBskyApp(req); 631 - } 632 - 633 - const response: XRPCTypes.AppBskyFeedGetPostThread.OutputSchema = {}; 634 - 635 - return new Response(JSON.stringify(response), { 636 - headers: withCors({ "Content-Type": "application/json" }), 637 - }); 638 - } 639 - case "app.bsky.unspecced.getPostThreadV2": { 640 - const jsonTyped = 641 - jsonUntyped as XRPCTypes.AppBskyUnspeccedGetPostThreadV2.QueryParams; 642 - 643 - const userindexservice = ""; 644 - const isbskyfallback = true; 645 - if (isbskyfallback) { 646 - return sendItToApiBskyApp(req); 647 - } 648 - 649 - const response: XRPCTypes.AppBskyUnspeccedGetPostThreadV2.OutputSchema = 650 - {}; 651 - 652 - return new Response(JSON.stringify(response), { 653 - headers: withCors({ "Content-Type": "application/json" }), 654 - }); 655 - } 656 - 657 - // case "app.bsky.actor.getProfile": { 658 - // const jsonTyped = 659 - // jsonUntyped as XRPCTypes.AppBskyActorGetProfile.QueryParams; 660 - 661 - // const response: XRPCTypes.AppBskyActorGetProfile.OutputSchema= {}; 662 - 663 - // return new Response(JSON.stringify(response), { 664 - // headers: withCors({ "Content-Type": "application/json" }), 665 - // }); 666 - // } 667 - // case "app.bsky.actor.getProfiles": { 668 - // const jsonTyped = jsonUntyped as XRPCTypes.AppBskyActorGetProfiles.QueryParams; 669 - 670 - // const response: XRPCTypes.AppBskyActorGetProfiles.OutputSchema = {}; 671 - 672 - // return new Response(JSON.stringify(response), { 673 - // headers: withCors({ "Content-Type": "application/json" }), 674 - // }); 675 - // } 676 - // case "whatever": { 677 - // const jsonTyped = jsonUntyped as XRPCTypes.AppBskyFeedGetAuthorFeed.QueryParams; 678 - 679 - // const response: XRPCTypes.AppBskyFeedGetAuthorFeed.OutputSchema = {} 680 - 681 - // return new Response(JSON.stringify(response), { 682 - // headers: withCors({ "Content-Type": "application/json" }), 683 - // }); 684 - // } 685 - // case "app.bsky.notification.listNotifications": { 686 - // const jsonTyped = 687 - // jsonUntyped as XRPCTypes.AppBskyNotificationListNotifications.QueryParams; 688 - 689 - // const response: XRPCTypes.AppBskyNotificationListNotifications.OutputSchema = {}; 690 - 691 - // return new Response(JSON.stringify(response), { 692 - // headers: withCors({ "Content-Type": "application/json" }), 693 - // }); 694 - // } 695 - 696 - case "app.bsky.unspecced.getConfig": { 697 - const jsonTyped = 698 - jsonUntyped as XRPCTypes.AppBskyUnspeccedGetConfig.QueryParams; 699 - 700 - const response: XRPCTypes.AppBskyUnspeccedGetConfig.OutputSchema = { 701 - checkEmailConfirmed: true, 702 - liveNow: [ 703 - { 704 - $type: "app.bsky.unspecced.getConfig#liveNowConfig", 705 - did: "did:plc:mn45tewwnse5btfftvd3powc", 706 - domains: ["local3768forumtest.whey.party"], 707 - }, 708 - ], 709 - }; 710 - 711 - return new Response(JSON.stringify(response), { 712 - headers: withCors({ "Content-Type": "application/json" }), 713 - }); 714 - } 715 - case "app.bsky.graph.getLists": { 716 - const jsonTyped = 717 - jsonUntyped as XRPCTypes.AppBskyGraphGetLists.QueryParams; 718 - 719 - const response: XRPCTypes.AppBskyGraphGetLists.OutputSchema = { 720 - lists: [], 721 - }; 722 - 723 - return new Response(JSON.stringify(response), { 724 - headers: withCors({ "Content-Type": "application/json" }), 725 - }); 726 - } 727 - //https://shimeji.us-east.host.bsky.network/xrpc/app.bsky.unspecced.getTrendingTopics?limit=14 728 - case "app.bsky.unspecced.getTrendingTopics": { 729 - const jsonTyped = 730 - jsonUntyped as XRPCTypes.AppBskyUnspeccedGetTrendingTopics.QueryParams; 731 - 732 - const faketopics: ATPAPI.AppBskyUnspeccedDefs.TrendingTopic[] = [ 733 - { 734 - $type: "app.bsky.unspecced.defs#trendingTopic", 735 - topic: "Git Repo", 736 - displayName: "Git Repo", 737 - description: "Git Repo", 738 - link: "https://tangled.sh/@whey.party/skylite", 739 - }, 740 - { 741 - $type: "app.bsky.unspecced.defs#trendingTopic", 742 - topic: "Red Dwarf Lite", 743 - displayName: "Red Dwarf Lite", 744 - description: "Red Dwarf Lite", 745 - link: "https://reddwarf.whey.party/", 746 - }, 747 - { 748 - $type: "app.bsky.unspecced.defs#trendingTopic", 749 - topic: "whey dot party", 750 - displayName: "whey dot party", 751 - description: "whey dot party", 752 - link: "https://whey.party/", 753 - }, 754 - ]; 755 - 756 - const response: XRPCTypes.AppBskyUnspeccedGetTrendingTopics.OutputSchema = 757 - { 758 - topics: faketopics, 759 - suggested: faketopics, 760 - }; 761 - 762 - return new Response(JSON.stringify(response), { 763 - headers: withCors({ "Content-Type": "application/json" }), 764 - }); 765 - } 766 - default: { 767 - return new Response( 768 - JSON.stringify({ 769 - error: "XRPCNotSupported", 770 - message: 771 - "HEY hello there my name is whey dot party and you have used my custom appview that is very cool but have you considered that XRPC Not Supported", 772 - }), 773 - { 774 - status: 404, 775 - headers: withCors({ "Content-Type": "application/json" }), 776 - } 777 - ); 778 - } 103 + // const bskyUrl = `https://api.bsky.app${pathname}${url.search}`; 104 + // const hasAuth = req.headers.has("authorization"); 105 + // const xrpcMethod = pathname.startsWith("/xrpc/") 106 + // ? pathname.slice("/xrpc/".length) 107 + // : null; 108 + 109 + if (indexServerRoutes.has(pathname)) { 110 + return await indexServerHandler(req); 111 + } else { 112 + return await viewServerHandler(req); 779 113 } 780 114 } 781 115 ); 782 116 783 - function withCors(headers: HeadersInit = {}) { 117 + export function withCors(headers: HeadersInit = {}) { 784 118 return { 785 119 "Access-Control-Allow-Origin": "*", 786 120 ...headers,
-225
utils/dbsetup.ts
··· 1 - import { db } from "../main.ts" 2 - 3 - export default function dbsetup(){ 4 - 5 - const baseColumns = ` 6 - uri TEXT PRIMARY KEY NOT NULL, 7 - did TEXT NOT NULL, 8 - cid TEXT, 9 - rev TEXT, 10 - createdat INTEGER, 11 - indexedat INTEGER NOT NULL, 12 - json TEXT 13 - `; 14 - 15 - const innerArrayID = "id INTEGER PRIMARY KEY AUTOINCREMENT"; 16 - const createTableINE = "CREATE TABLE IF NOT EXISTS"; 17 - const createIndexINE = "CREATE INDEX IF NOT EXISTS"; 18 - 19 - db.exec(` 20 - ${createTableINE} users ( 21 - did TEXT PRIMARY KEY NOT NULL, 22 - role TEXT, 23 - registrationdate TEXT, 24 - onboardingstatus TEXT 25 - ); 26 - 27 - ${createTableINE} remoteprofileview ( 28 - did TEXT PRIMARY KEY NOT NULL, 29 - handle TEXT, 30 - displayname TEXT, 31 - description TEXT, 32 - avatar TEXT, 33 - banner TEXT 34 - ); 35 - 36 - ${createTableINE} did ( 37 - did TEXT PRIMARY KEY NOT NULL, 38 - method TEXT, 39 - string TEXT, 40 - doc TEXT, 41 - pds TEXT, 42 - handle TEXT 43 - ); 44 - ${createIndexINE} idx_did_handle ON did(handle); 45 - 46 - ${createTableINE} prefs ( 47 - did TEXT PRIMARY KEY NOT NULL, 48 - json TEXT 49 - ); 50 - ${createIndexINE} idx_prefs_did ON prefs(did); 51 - 52 - ${createTableINE} backlink_skeleton ( 53 - id INTEGER PRIMARY KEY AUTOINCREMENT, 54 - srcuri TEXT, 55 - srcdid TEXT, 56 - srcfield TEXT, 57 - srccol TEXT, 58 - suburi TEXT, 59 - subdid TEXT, 60 - subcol TEXT 61 - ); 62 - ${createIndexINE} idx_backlink_subdid_mod ON backlink_skeleton(subdid, srcdid); 63 - ${createIndexINE} idx_backlink_suburi_mod ON backlink_skeleton(suburi, srcdid); 64 - ${createIndexINE} idx_backlink_subdid_filter_mod ON backlink_skeleton(subdid, srccol, srcdid); 65 - ${createIndexINE} idx_backlink_suburi_filter_mod ON backlink_skeleton(suburi, srccol, srcdid); 66 - 67 - ${createTableINE} app_bsky_actor_profile ( 68 - ${baseColumns}, 69 - displayname TEXT, 70 - description TEXT, 71 - avatarcid TEXT, 72 - avatarmime TEXT, 73 - bannercid TEXT, 74 - bannermime TEXT 75 - ); 76 - ${createIndexINE} idx_actor_profile_did ON app_bsky_actor_profile(did); 77 - 78 - ${createTableINE} app_bsky_feed_post ( 79 - ${baseColumns}, 80 - text TEXT, 81 - replyroot TEXT, 82 - replyparent TEXT, 83 - quote TEXT, 84 - imagecount INTEGER, 85 - image1cid TEXT, 86 - image1mime TEXT, 87 - image1aspect TEXT, 88 - image2cid TEXT, 89 - image2mime TEXT, 90 - image2aspect TEXT, 91 - image3cid TEXT, 92 - image3mime TEXT, 93 - image3aspect TEXT, 94 - image4cid TEXT, 95 - image4mime TEXT, 96 - image4aspect TEXT, 97 - videocount INTEGER, 98 - videocid TEXT, 99 - videomime TEXT, 100 - videoaspect TEXT 101 - ); 102 - 103 - ${createIndexINE} idx_post_author_timeline ON app_bsky_feed_post(did, createdat DESC); 104 - ${createIndexINE} idx_post_global_timeline ON app_bsky_feed_post(indexedat DESC); 105 - ${createIndexINE} idx_post_replyroot ON app_bsky_feed_post(replyroot); 106 - ${createIndexINE} idx_post_replyparent ON app_bsky_feed_post(replyparent); 107 - ${createIndexINE} idx_post_quote ON app_bsky_feed_post(quote); 108 - 109 - ${createTableINE} app_bsky_feed_post_langs ( 110 - ${innerArrayID}, 111 - post TEXT NOT NULL, 112 - lang TEXT NOT NULL 113 - ); 114 - ${createIndexINE} idx_post_langs_lang ON app_bsky_feed_post_langs(lang); 115 - ${createIndexINE} idx_post_langs_post ON app_bsky_feed_post_langs(post); 116 - 117 - ${createTableINE} app_bsky_feed_post_hashtags ( 118 - ${innerArrayID}, 119 - post TEXT NOT NULL, 120 - hashtag TEXT NOT NULL 121 - ); 122 - ${createIndexINE} idx_post_hashtags_hashtag ON app_bsky_feed_post_hashtags(hashtag); 123 - ${createIndexINE} idx_post_hashtags_post ON app_bsky_feed_post_hashtags(post); 124 - 125 - ${createTableINE} app_bsky_feed_post_mentions ( 126 - ${innerArrayID}, 127 - post TEXT NOT NULL, 128 - mention TEXT NOT NULL 129 - ); 130 - ${createIndexINE} idx_post_mentions_mention ON app_bsky_feed_post_mentions(mention); 131 - ${createIndexINE} idx_post_mentions_post ON app_bsky_feed_post_mentions(post); 132 - 133 - 134 - ${createTableINE} app_bsky_feed_like ( 135 - ${baseColumns}, 136 - subject TEXT NOT NULL, 137 - subjectcid TEXT 138 - ); 139 - ${createIndexINE} idx_like_author_timeline ON app_bsky_feed_like(did, createdat DESC); 140 - ${createIndexINE} idx_like_subject ON app_bsky_feed_like(subject); 141 - 142 - ${createTableINE} app_bsky_feed_repost ( 143 - ${baseColumns}, 144 - subject TEXT NOT NULL, 145 - subjectcid TEXT 146 - ); 147 - ${createIndexINE} idx_repost_author_timeline ON app_bsky_feed_repost(did, createdat DESC); 148 - ${createIndexINE} idx_repost_subject ON app_bsky_feed_repost(subject); 149 - 150 - 151 - ${createTableINE} app_bsky_graph_follow ( 152 - ${baseColumns}, 153 - subject TEXT NOT NULL 154 - ); 155 - ${createIndexINE} idx_follow_author_timeline ON app_bsky_graph_follow(did, createdat DESC); 156 - ${createIndexINE} idx_follow_subject_timeline ON app_bsky_graph_follow(subject, createdat DESC); 157 - 158 - ${createTableINE} app_bsky_graph_block ( 159 - ${baseColumns}, 160 - subject TEXT NOT NULL 161 - ); 162 - ${createIndexINE} idx_block_author ON app_bsky_graph_block(did); 163 - ${createIndexINE} idx_block_subject ON app_bsky_graph_block(subject); 164 - 165 - ${createTableINE} app_bsky_graph_list ( 166 - ${baseColumns}, 167 - name TEXT, 168 - description TEXT, 169 - purpose TEXT, 170 - avatarcid TEXT, 171 - avatarmime TEXT 172 - ); 173 - ${createIndexINE} idx_list_author ON app_bsky_graph_list(did); 174 - ${createIndexINE} idx_list_purpose ON app_bsky_graph_list(purpose); 175 - 176 - ${createTableINE} app_bsky_graph_listitem ( 177 - ${baseColumns}, 178 - list TEXT NOT NULL, 179 - subject TEXT NOT NULL 180 - ); 181 - ${createIndexINE} idx_listitem_list ON app_bsky_graph_listitem(list); 182 - ${createIndexINE} idx_listitem_subject ON app_bsky_graph_listitem(subject); 183 - ${createIndexINE} idx_listitem_author ON app_bsky_graph_listitem(did); 184 - 185 - 186 - 187 - ${createTableINE} app_bsky_feed_generator ( 188 - ${baseColumns}, 189 - displayname TEXT, 190 - description TEXT, 191 - avatarcid TEXT, 192 - avatarmime TEXT 193 - ); 194 - ${createIndexINE} idx_feed_generator_author ON app_bsky_feed_generator(did); 195 - 196 - ${createTableINE} app_bsky_feed_threadgate ( 197 - ${baseColumns}, 198 - post TEXT NOT NULL 199 - ); 200 - ${createIndexINE} idx_threadgate_post ON app_bsky_feed_threadgate(post); 201 - ${createIndexINE} idx_threadgate_author ON app_bsky_feed_threadgate(did); 202 - 203 - 204 - ${createTableINE} app_bsky_feed_threadgate_hiddenreplies ( 205 - ${innerArrayID}, 206 - threadgate TEXT NOT NULL, 207 - reply TEXT NOT NULL 208 - ); 209 - ${createIndexINE} idx_threadgate_hiddenreplies_gate ON app_bsky_feed_threadgate_hiddenreplies(threadgate); 210 - 211 - ${createTableINE} app_bsky_graph_listblock ( 212 - ${baseColumns}, 213 - subject TEXT NOT NULL 214 - ); 215 - ${createIndexINE} idx_listblock_subject ON app_bsky_graph_listblock(subject); 216 - ${createIndexINE} idx_listblock_author ON app_bsky_graph_listblock(did); 217 - 218 - ${createTableINE} app_bsky_notification_declaration ( 219 - ${baseColumns}, 220 - allowSubscriptions TEXT 221 - ); 222 - ${createIndexINE} idx_notification_declaration_author ON app_bsky_notification_declaration(did); 223 - 224 - `); 225 - }
+53
utils/dbsystem.ts
··· 1 + import { Database } from "jsr:@db/sqlite@0.11"; 2 + 3 + export function setupSystemDb(db: Database) { 4 + const createTableINE = "CREATE TABLE IF NOT EXISTS"; 5 + const createIndexINE = "CREATE INDEX IF NOT EXISTS"; 6 + 7 + db.exec(` 8 + -- Master list of all users known to the system 9 + ${createTableINE} users ( 10 + did TEXT PRIMARY KEY NOT NULL, 11 + role TEXT, 12 + registrationdate TEXT, 13 + onboardingstatus TEXT 14 + ); 15 + 16 + -- Cache of profiles for *other* users, prevents storing this in every user's DB 17 + ${createTableINE} remoteprofileview ( 18 + did TEXT PRIMARY KEY NOT NULL, 19 + handle TEXT, 20 + displayname TEXT, 21 + description TEXT, 22 + avatar TEXT, 23 + banner TEXT 24 + ); 25 + 26 + -- Central DID document cache and handle resolution 27 + ${createTableINE} did ( 28 + did TEXT PRIMARY KEY NOT NULL, 29 + method TEXT, 30 + string TEXT, 31 + doc TEXT, 32 + pds TEXT, 33 + handle TEXT 34 + ); 35 + ${createIndexINE} idx_did_handle ON did(handle); 36 + 37 + -- A global index for relationships between any two pieces of content 38 + ${createTableINE} backlink_skeleton ( 39 + id INTEGER PRIMARY KEY AUTOINCREMENT, 40 + srcuri TEXT, 41 + srcdid TEXT, 42 + srcfield TEXT, 43 + srccol TEXT, 44 + suburi TEXT, 45 + subdid TEXT, 46 + subcol TEXT 47 + ); 48 + ${createIndexINE} idx_backlink_subdid_mod ON backlink_skeleton(subdid, srcdid); 49 + ${createIndexINE} idx_backlink_suburi_mod ON backlink_skeleton(suburi, srcdid); 50 + ${createIndexINE} idx_backlink_subdid_filter_mod ON backlink_skeleton(subdid, srccol, srcdid); 51 + ${createIndexINE} idx_backlink_suburi_filter_mod ON backlink_skeleton(suburi, srccol, srcdid); 52 + `); 53 + }
+135
utils/dbuser.ts
··· 1 + import { Database } from "jsr:@db/sqlite@0.11"; 2 + 3 + export function setupUserDb(db: Database) { 4 + 5 + const baseColumns = ` 6 + uri TEXT PRIMARY KEY NOT NULL, 7 + did TEXT NOT NULL, 8 + cid TEXT, 9 + rev TEXT, 10 + createdat INTEGER, 11 + indexedat INTEGER NOT NULL, 12 + json TEXT 13 + `; 14 + 15 + const innerArrayID = "id INTEGER PRIMARY KEY AUTOINCREMENT"; 16 + const createTableINE = "CREATE TABLE IF NOT EXISTS"; 17 + const createIndexINE = "CREATE INDEX IF NOT EXISTS"; 18 + 19 + db.exec(` 20 + -- User's own personal preferences 21 + ${createTableINE} prefs ( 22 + did TEXT PRIMARY KEY NOT NULL, 23 + json TEXT 24 + ); 25 + ${createIndexINE} idx_prefs_did ON prefs(did); 26 + 27 + -- The user's own profile record 28 + ${createTableINE} app_bsky_actor_profile ( 29 + ${baseColumns}, 30 + displayname TEXT, 31 + description TEXT, 32 + avatarcid TEXT, 33 + avatarmime TEXT, 34 + bannercid TEXT, 35 + bannermime TEXT 36 + ); 37 + ${createIndexINE} idx_actor_profile_did ON app_bsky_actor_profile(did); 38 + 39 + -- All posts created by the user 40 + ${createTableINE} app_bsky_feed_post ( 41 + ${baseColumns}, 42 + text TEXT, 43 + replyroot TEXT, 44 + replyparent TEXT, 45 + quote TEXT, 46 + imagecount INTEGER, 47 + image1cid TEXT, 48 + image1mime TEXT, 49 + image1aspect TEXT, 50 + image2cid TEXT, 51 + image2mime TEXT, 52 + image2aspect TEXT, 53 + image3cid TEXT, 54 + image3mime TEXT, 55 + image3aspect TEXT, 56 + image4cid TEXT, 57 + image4mime TEXT, 58 + image4aspect TEXT, 59 + videocount INTEGER, 60 + videocid TEXT, 61 + videomime TEXT, 62 + videoaspect TEXT 63 + ); 64 + ${createIndexINE} idx_post_author_timeline ON app_bsky_feed_post(did, createdat DESC); 65 + ${createIndexINE} idx_post_global_timeline ON app_bsky_feed_post(indexedat DESC); 66 + ${createIndexINE} idx_post_replyroot ON app_bsky_feed_post(replyroot); 67 + ${createIndexINE} idx_post_replyparent ON app_bsky_feed_post(replyparent); 68 + ${createIndexINE} idx_post_quote ON app_bsky_feed_post(quote); 69 + 70 + -- Data related to the user's posts 71 + ${createTableINE} app_bsky_feed_post_langs ( ${innerArrayID}, post TEXT NOT NULL, lang TEXT NOT NULL ); 72 + ${createIndexINE} idx_post_langs_lang ON app_bsky_feed_post_langs(lang); 73 + ${createIndexINE} idx_post_langs_post ON app_bsky_feed_post_langs(post); 74 + 75 + ${createTableINE} app_bsky_feed_post_hashtags ( ${innerArrayID}, post TEXT NOT NULL, hashtag TEXT NOT NULL ); 76 + ${createIndexINE} idx_post_hashtags_hashtag ON app_bsky_feed_post_hashtags(hashtag); 77 + ${createIndexINE} idx_post_hashtags_post ON app_bsky_feed_post_hashtags(post); 78 + 79 + ${createTableINE} app_bsky_feed_post_mentions ( ${innerArrayID}, post TEXT NOT NULL, mention TEXT NOT NULL ); 80 + ${createIndexINE} idx_post_mentions_mention ON app_bsky_feed_post_mentions(mention); 81 + ${createIndexINE} idx_post_mentions_post ON app_bsky_feed_post_mentions(post); 82 + 83 + -- All likes created by the user 84 + ${createTableINE} app_bsky_feed_like ( ${baseColumns}, subject TEXT NOT NULL, subjectcid TEXT ); 85 + ${createIndexINE} idx_like_author_timeline ON app_bsky_feed_like(did, createdat DESC); 86 + ${createIndexINE} idx_like_subject ON app_bsky_feed_like(subject); 87 + 88 + -- All reposts created by the user 89 + ${createTableINE} app_bsky_feed_repost ( ${baseColumns}, subject TEXT NOT NULL, subjectcid TEXT ); 90 + ${createIndexINE} idx_repost_author_timeline ON app_bsky_feed_repost(did, createdat DESC); 91 + ${createIndexINE} idx_repost_subject ON app_bsky_feed_repost(subject); 92 + 93 + -- All follows created by the user 94 + ${createTableINE} app_bsky_graph_follow ( ${baseColumns}, subject TEXT NOT NULL ); 95 + ${createIndexINE} idx_follow_author_timeline ON app_bsky_graph_follow(did, createdat DESC); 96 + ${createIndexINE} idx_follow_subject_timeline ON app_bsky_graph_follow(subject, createdat DESC); 97 + 98 + -- All blocks created by the user 99 + ${createTableINE} app_bsky_graph_block ( ${baseColumns}, subject TEXT NOT NULL ); 100 + ${createIndexINE} idx_block_author ON app_bsky_graph_block(did); 101 + ${createIndexINE} idx_block_subject ON app_bsky_graph_block(subject); 102 + 103 + -- All lists created by the user 104 + ${createTableINE} app_bsky_graph_list ( ${baseColumns}, name TEXT, description TEXT, purpose TEXT, avatarcid TEXT, avatarmime TEXT ); 105 + ${createIndexINE} idx_list_author ON app_bsky_graph_list(did); 106 + ${createIndexINE} idx_list_purpose ON app_bsky_graph_list(purpose); 107 + 108 + -- All list items created by the user 109 + ${createTableINE} app_bsky_graph_listitem ( ${baseColumns}, list TEXT NOT NULL, subject TEXT NOT NULL ); 110 + ${createIndexINE} idx_listitem_list ON app_bsky_graph_listitem(list); 111 + ${createIndexINE} idx_listitem_subject ON app_bsky_graph_listitem(subject); 112 + ${createIndexINE} idx_listitem_author ON app_bsky_graph_listitem(did); 113 + 114 + -- All feed generators created by the user 115 + ${createTableINE} app_bsky_feed_generator ( ${baseColumns}, displayname TEXT, description TEXT, avatarcid TEXT, avatarmime TEXT ); 116 + ${createIndexINE} idx_feed_generator_author ON app_bsky_feed_generator(did); 117 + 118 + -- All threadgates created by the user 119 + ${createTableINE} app_bsky_feed_threadgate ( ${baseColumns}, post TEXT NOT NULL ); 120 + ${createIndexINE} idx_threadgate_post ON app_bsky_feed_threadgate(post); 121 + ${createIndexINE} idx_threadgate_author ON app_bsky_feed_threadgate(did); 122 + 123 + ${createTableINE} app_bsky_feed_threadgate_hiddenreplies ( ${innerArrayID}, threadgate TEXT NOT NULL, reply TEXT NOT NULL ); 124 + ${createIndexINE} idx_threadgate_hiddenreplies_gate ON app_bsky_feed_threadgate_hiddenreplies(threadgate); 125 + 126 + -- All list blocks created by the user 127 + ${createTableINE} app_bsky_graph_listblock ( ${baseColumns}, subject TEXT NOT NULL ); 128 + ${createIndexINE} idx_listblock_subject ON app_bsky_graph_listblock(subject); 129 + ${createIndexINE} idx_listblock_author ON app_bsky_graph_listblock(did); 130 + 131 + -- User's notification settings declaration 132 + ${createTableINE} app_bsky_notification_declaration ( ${baseColumns}, allowSubscriptions TEXT ); 133 + ${createIndexINE} idx_notification_declaration_author ON app_bsky_notification_declaration(did); 134 + `); 135 + }
+7 -7
utils/identity.ts
··· 1 1 2 2 import { DidResolver, HandleResolver } from "npm:@atproto/identity"; 3 - import { db } from "../main.ts"; 3 + import { systemDB } from "../main.ts"; 4 4 type DidMethod = "web" | "plc"; 5 5 type DidDoc = { 6 6 "@context"?: unknown; ··· 35 35 } 36 36 37 37 function getDidFromHandle(handle: string): { did: string } | null { 38 - const row = db.prepare("SELECT did FROM did WHERE handle = ?").get(handle); 38 + const row = systemDB.prepare("SELECT did FROM did WHERE handle = ?").get(handle); 39 39 if (!row) return null; 40 40 41 41 try { ··· 65 65 function getDidDoc( 66 66 did: string 67 67 ): { method: "web" | "plc"; doc: DidDoc } | null { 68 - const row = db.prepare("SELECT method, doc FROM did WHERE did = ?").get(did); 68 + const row = systemDB.prepare("SELECT method, doc FROM did WHERE did = ?").get(did); 69 69 if (!row) return null; 70 70 71 71 try { ··· 126 126 function getPDSAndHandleFromDid( 127 127 did: string 128 128 ): { pds: string; handle?: string } | null { 129 - const row = db.prepare("SELECT pds, handle FROM did WHERE did = ?").get(did); 129 + const row = systemDB.prepare("SELECT pds, handle FROM did WHERE did = ?").get(did); 130 130 131 131 if (!row) return null; 132 132 return { ··· 144 144 const { did } = await resolveDidFromHandle(handle); 145 145 const { diddoc, didmethod } = await resolveDidDoc(did); 146 146 147 - db.prepare( 147 + systemDB.prepare( 148 148 "INSERT OR REPLACE INTO did (did, handle, doc, method) VALUES (?, ?, ?, ?)" 149 149 ).run(did, handle, JSON.stringify(diddoc), didmethod); 150 150 ··· 162 162 try { 163 163 const { diddoc, didmethod } = await resolveDidDoc(did); 164 164 165 - db.prepare( 165 + systemDB.prepare( 166 166 "INSERT OR REPLACE INTO did (did, doc, method) VALUES (?, ?, ?)" 167 167 ).run(did, JSON.stringify(diddoc), didmethod); 168 168 ··· 215 215 if (aka) handle = aka.slice("at://".length); 216 216 } 217 217 218 - db.prepare( 218 + systemDB.prepare( 219 219 "INSERT OR REPLACE INTO did (did, pds, handle) VALUES (?, ?, ?)" 220 220 ).run(did, serviceEndpoint, handle ?? null); 221 221
utils/indexserver.ts

This is a binary file and will not be displayed.

+13
utils/indexservertypes.ts
··· 1 + export * as AppBskyActorGetProfile from '../indexserver/types/app/bsky/actor/getProfile.ts' 2 + export * as AppBskyActorGetProfiles from '../indexserver/types/app/bsky/actor/getProfiles.ts' 3 + export * as AppBskyFeedGetActorFeeds from '../indexserver/types/app/bsky/feed/getActorFeeds.ts' 4 + export * as AppBskyFeedGetFeedGenerator from '../indexserver/types/app/bsky/feed/getFeedGenerator.ts' 5 + export * as AppBskyFeedGetFeedGenerators from '../indexserver/types/app/bsky/feed/getFeedGenerators.ts' 6 + export * as AppBskyFeedGetPosts from '../indexserver/types/app/bsky/feed/getPosts.ts' 7 + export * as PartyWheyAppBskyFeedGetActorLikesPartial from '../indexserver/types/party/whey/app/bsky/feed/getActorLikesPartial.ts' 8 + export * as PartyWheyAppBskyFeedGetAuthorFeedPartial from '../indexserver/types/party/whey/app/bsky/feed/getAuthorFeedPartial.ts' 9 + export * as PartyWheyAppBskyFeedGetLikesPartial from '../indexserver/types/party/whey/app/bsky/feed/getLikesPartial.ts' 10 + export * as PartyWheyAppBskyFeedGetListFeedPartial from '../indexserver/types/party/whey/app/bsky/feed/getListFeedPartial.ts' 11 + export * as PartyWheyAppBskyFeedGetPostThreadPartial from '../indexserver/types/party/whey/app/bsky/feed/getPostThreadPartial.ts' 12 + export * as PartyWheyAppBskyFeedGetQuotesPartial from '../indexserver/types/party/whey/app/bsky/feed/getQuotesPartial.ts' 13 + export * as PartyWheyAppBskyFeedGetRepostedByPartial from '../indexserver/types/party/whey/app/bsky/feed/getRepostedByPartial.ts'
+175
utils/server.ts
··· 1 + import ky from "npm:ky"; 2 + import QuickLRU from "npm:quick-lru"; 3 + import { createHash } from "node:crypto"; 4 + import { slingshoturl, constellationurl } from "../main.ts"; 5 + import * as ATPAPI from "npm:@atproto/api"; 6 + 7 + const cache = new QuickLRU({ maxSize: 10000 }); 8 + 9 + function simpleHashAuth(auth: string): string { 10 + return createHash("sha256").update(auth).digest("hex"); 11 + } 12 + export async function cachedFetch(url: string, auth?: string) { 13 + const cacheKey = auth ? `${url}|${simpleHashAuth(auth)}` : url; 14 + if (cache.has(cacheKey)) return cache.get(cacheKey); 15 + 16 + const data = await ky 17 + .get(url, { 18 + headers: { 19 + Authorization: `${auth}`, 20 + }, 21 + }) 22 + .json(); 23 + 24 + cache.set(cacheKey, data); 25 + return data; 26 + } 27 + 28 + export type SlingshotMiniDoc = { 29 + did: string; 30 + handle: string; 31 + pds: string; 32 + signing_key: string; 33 + }; 34 + let preferences: any = undefined; 35 + 36 + export function searchParamsToJson( 37 + params: URLSearchParams 38 + ): Record<string, unknown> { 39 + const result: Record<string, string | string[]> = {}; 40 + 41 + for (const [key, value] of params.entries()) { 42 + if (result.hasOwnProperty(key)) { 43 + const existing = result[key]; 44 + if (Array.isArray(existing)) { 45 + existing.push(value); 46 + } else { 47 + result[key] = [existing, value]; 48 + } 49 + } else { 50 + result[key] = value; 51 + } 52 + } 53 + 54 + return result; 55 + } 56 + 57 + export async function resolveIdentity( 58 + actor: string 59 + ): Promise<SlingshotMiniDoc> { 60 + const url = `${slingshoturl}/xrpc/com.bad-example.identity.resolveMiniDoc?identifier=${actor}`; 61 + return (await cachedFetch(url)) as SlingshotMiniDoc; 62 + } 63 + export async function getRecord({ 64 + pds, 65 + did, 66 + collection, 67 + rkey, 68 + }: { 69 + pds: string; 70 + did: string; 71 + collection: string; 72 + rkey: string; 73 + }): Promise<{ cursor?: string; records: GetRecord[] }> { 74 + const url = `${pds}/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=${collection}&rkey=${rkey}`; 75 + const result = (await cachedFetch(url)) as { 76 + cursor?: string; 77 + records: GetRecord[]; 78 + }; 79 + return result as { 80 + cursor?: string; 81 + records: { 82 + uri: string; 83 + cid: string; 84 + value: ATPAPI.AppBskyFeedPost.Record; 85 + }[]; 86 + }; 87 + } 88 + 89 + export async function listPostRecords({ 90 + pds, 91 + did, 92 + limit = 50, 93 + cursor, 94 + }: { 95 + pds: string; 96 + did: string; 97 + limit: number; 98 + cursor?: string; 99 + }): Promise<{ 100 + cursor?: string; 101 + records: { uri: string; cid: string; value: ATPAPI.AppBskyFeedPost.Record }[]; 102 + }> { 103 + const url = `${pds}/xrpc/com.atproto.repo.listRecords?repo=${did}&collection=app.bsky.feed.post&limit=${limit}${ 104 + cursor ? `&cursor=${cursor}` : "" 105 + }`; 106 + const result = (await cachedFetch(url)) as { 107 + cursor?: string; 108 + records: GetRecord[]; 109 + }; 110 + return result as { 111 + cursor?: string; 112 + records: { 113 + uri: string; 114 + cid: string; 115 + value: ATPAPI.AppBskyFeedPost.Record; 116 + }[]; 117 + }; 118 + } 119 + 120 + // async function getProfileRecord(did: string): Promise<ATPAPI.AppBskyActorProfile.Record> { 121 + // const url = `${slingshoturl}/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=app.bsky.actor.profile&rkey=self`; 122 + // const result = await cachedFetch(url) as GetRecord; 123 + // return result.value as ATPAPI.AppBskyActorProfile.Record; 124 + // } 125 + 126 + export function buildBlobUrl( 127 + pds: string, 128 + did: string, 129 + cid: string 130 + ): string | undefined { 131 + if (!pds || !did || !cid) return undefined; 132 + return `${pds}/xrpc/com.atproto.sync.getBlob?did=${did}&cid=${cid}`; 133 + } 134 + 135 + export type ConstellationDistinctDids = { 136 + total: number; 137 + linking_dids: string[]; 138 + cursor: string; 139 + }; 140 + export type GetRecord = { 141 + uri: string; 142 + cid: string; 143 + value: Record<string, unknown>; 144 + }; 145 + 146 + export function didWebToHttps(did: string) { 147 + if (!did.startsWith("did:web:")) return null; 148 + const parts = did.slice("did:web:".length).split(":"); 149 + const [domain, ...path] = parts; 150 + return `https://${domain}${path.length ? "/" + path.join("/") : ""}`; 151 + } 152 + 153 + export async function getSlingshotRecord( 154 + did: string, 155 + collection: string, 156 + rkey: string 157 + ): Promise<GetRecord> { 158 + const url = `${slingshoturl}/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=${collection}&rkey=${rkey}`; 159 + const result = (await cachedFetch(url)) as GetRecord; 160 + return result as GetRecord; 161 + } 162 + 163 + export async function getUniqueCount({ 164 + did, 165 + collection, 166 + path, 167 + }: { 168 + did: string; 169 + collection: string; 170 + path: string; 171 + }): Promise<number> { 172 + const url = `${constellationurl}/links/count/distinct-dids?target=${did}&collection=${collection}&path=${path}`; 173 + const result = (await cachedFetch(url)) as ConstellationDistinctDids; 174 + return result.total; 175 + }
utils/viewserver.ts utils/viewservertypes.ts
+525
viewserver.ts
··· 1 + import ky from "npm:ky"; 2 + import { isGeneratorView } from "./indexserver/types/app/bsky/feed/defs.ts"; 3 + import { withCors } from "./main.ts"; 4 + import * as ViewServerTypes from "./utils/viewservertypes.ts"; 5 + import * as ATPAPI from "npm:@atproto/api"; 6 + import { 7 + searchParamsToJson, 8 + resolveIdentity, 9 + buildBlobUrl, 10 + cachedFetch, 11 + didWebToHttps, 12 + getSlingshotRecord, 13 + } from "./utils/server.ts"; 14 + 15 + export async function viewServerHandler(req: Request): Promise<Response> { 16 + const url = new URL(req.url); 17 + const pathname = url.pathname; 18 + const bskyUrl = `https://api.bsky.app${pathname}${url.search}`; 19 + const hasAuth = req.headers.has("authorization"); 20 + const xrpcMethod = pathname.startsWith("/xrpc/") 21 + ? pathname.slice("/xrpc/".length) 22 + : null; 23 + const searchParams = searchParamsToJson(url.searchParams); 24 + const jsonUntyped = searchParams; 25 + 26 + if (xrpcMethod === "app.bsky.unspecced.getTrendingTopics") { 27 + // const jsonTyped = 28 + // jsonUntyped as ViewServerTypes.AppBskyUnspeccedGetTrendingTopics.QueryParams; 29 + 30 + const faketopics: ATPAPI.AppBskyUnspeccedDefs.TrendingTopic[] = [ 31 + { 32 + $type: "app.bsky.unspecced.defs#trendingTopic", 33 + topic: "Git Repo", 34 + displayName: "Git Repo", 35 + description: "Git Repo", 36 + link: "https://tangled.sh/@whey.party/skylite", 37 + }, 38 + { 39 + $type: "app.bsky.unspecced.defs#trendingTopic", 40 + topic: "Red Dwarf Lite", 41 + displayName: "Red Dwarf Lite", 42 + description: "Red Dwarf Lite", 43 + link: "https://reddwarflite.whey.party/", 44 + }, 45 + { 46 + $type: "app.bsky.unspecced.defs#trendingTopic", 47 + topic: "whey dot party", 48 + displayName: "whey dot party", 49 + description: "whey dot party", 50 + link: "https://whey.party/", 51 + }, 52 + ]; 53 + 54 + const response: ViewServerTypes.AppBskyUnspeccedGetTrendingTopics.OutputSchema = 55 + { 56 + topics: faketopics, 57 + suggested: faketopics, 58 + }; 59 + 60 + return new Response(JSON.stringify(response), { 61 + headers: withCors({ "Content-Type": "application/json" }), 62 + }); 63 + } 64 + 65 + //if (xrpcMethod !== 'app.bsky.actor.getPreferences' && xrpcMethod !== 'app.bsky.notification.listNotifications') { 66 + if ( 67 + !hasAuth 68 + // (!hasAuth || 69 + // xrpcMethod === "app.bsky.labeler.getServices" || 70 + // xrpcMethod === "app.bsky.unspecced.getConfig") && 71 + // xrpcMethod !== "app.bsky.notification.putPreferences" 72 + ) { 73 + return new Response( 74 + JSON.stringify({ 75 + error: "XRPCNotSupported", 76 + message: 77 + "HEY hello there my name is whey dot party and you have used my custom appview that is very cool but have you considered that XRPC Not Supported", 78 + }), 79 + { 80 + status: 404, 81 + headers: withCors({ "Content-Type": "application/json" }), 82 + } 83 + ); 84 + //return await sendItToApiBskyApp(req); 85 + } 86 + if ( 87 + // !hasAuth || 88 + xrpcMethod === "app.bsky.labeler.getServices" || 89 + xrpcMethod === "app.bsky.unspecced.getConfig" //&& 90 + //xrpcMethod !== "app.bsky.notification.putPreferences" 91 + ) { 92 + return new Response( 93 + JSON.stringify({ 94 + error: "XRPCNotSupported", 95 + message: 96 + "HEY hello there my name is whey dot party and you have used my custom appview that is very cool but have you considered that XRPC Not Supported", 97 + }), 98 + { 99 + status: 404, 100 + headers: withCors({ "Content-Type": "application/json" }), 101 + } 102 + ); 103 + //return await sendItToApiBskyApp(req); 104 + } 105 + 106 + const authDID = "did:plc:mn45tewwnse5btfftvd3powc"; //getAuthenticatedDid(req); 107 + 108 + switch (xrpcMethod) { 109 + case "app.bsky.feed.getFeedGenerators": { 110 + const jsonTyped = 111 + jsonUntyped as ViewServerTypes.AppBskyFeedGetFeedGenerators.QueryParams; 112 + 113 + const feeds: ATPAPI.AppBskyFeedDefs.GeneratorView[] = ( 114 + await Promise.all( 115 + jsonTyped.feeds.map(async (feed) => { 116 + try { 117 + const did = new ATPAPI.AtUri(feed).hostname; 118 + const rkey = new ATPAPI.AtUri(feed).rkey; 119 + const identity = await resolveIdentity(did); 120 + const feedgetRecord = await getSlingshotRecord( 121 + identity.did, 122 + "app.bsky.feed.generator", 123 + rkey 124 + ); 125 + const profile = ( 126 + await getSlingshotRecord( 127 + identity.did, 128 + "app.bsky.actor.profile", 129 + "self" 130 + ) 131 + ).value as ATPAPI.AppBskyActorProfile.Record; 132 + const anyprofile = profile as any; 133 + const value = 134 + feedgetRecord.value as ATPAPI.AppBskyFeedGenerator.Record; 135 + 136 + return { 137 + $type: "app.bsky.feed.defs#generatorView", 138 + uri: feed, 139 + cid: feedgetRecord.cid, 140 + did: identity.did, 141 + creator: /*AppBskyActorDefs.ProfileView*/ { 142 + $type: "app.bsky.actor.defs#profileView", 143 + did: identity.did, 144 + handle: identity.handle, 145 + displayName: profile.displayName, 146 + description: profile.description, 147 + avatar: buildBlobUrl( 148 + identity.pds, 149 + identity.did, 150 + anyprofile.avatar.ref["$link"] 151 + ), 152 + //associated?: ProfileAssociated 153 + //indexedAt?: string 154 + //createdAt?: string 155 + //viewer?: ViewerState 156 + //labels?: ComAtprotoLabelDefs.Label[] 157 + //verification?: VerificationState 158 + //status?: StatusView 159 + }, 160 + displayName: value.displayName, 161 + description: value.description, 162 + //descriptionFacets?: AppBskyRichtextFacet.Main[] 163 + avatar: buildBlobUrl( 164 + identity.pds, 165 + identity.did, 166 + (value as any).avatar.ref["$link"] 167 + ), 168 + //likeCount?: number 169 + //acceptsInteractions?: boolean 170 + //labels?: ComAtprotoLabelDefs.Label[] 171 + //viewer?: GeneratorViewerState 172 + contentMode: value.contentMode, 173 + indexedAt: new Date().toISOString(), 174 + }; 175 + } catch (err) { 176 + return undefined; 177 + } 178 + }) 179 + ) 180 + ).filter(isGeneratorView); 181 + 182 + const response: ViewServerTypes.AppBskyFeedGetFeedGenerators.OutputSchema = 183 + { 184 + feeds: feeds ? feeds : [], 185 + }; 186 + 187 + return new Response(JSON.stringify(response), { 188 + headers: withCors({ "Content-Type": "application/json" }), 189 + }); 190 + } 191 + case "app.bsky.feed.getFeed": { 192 + const jsonTyped = 193 + jsonUntyped as ViewServerTypes.AppBskyFeedGetFeed.QueryParams; 194 + const cursor = jsonTyped.cursor; 195 + const feed = jsonTyped.feed; 196 + const limit = jsonTyped.limit; 197 + const proxyauth = req.headers.get("authorization") || ""; 198 + 199 + const did = new ATPAPI.AtUri(feed).hostname; 200 + const rkey = new ATPAPI.AtUri(feed).rkey; 201 + const identity = await resolveIdentity(did); 202 + const feedgetRecord = ( 203 + await getSlingshotRecord(identity.did, "app.bsky.feed.generator", rkey) 204 + ).value as ATPAPI.AppBskyFeedGenerator.Record; 205 + 206 + const skeleton = (await cachedFetch( 207 + `${didWebToHttps( 208 + feedgetRecord.did 209 + )}/xrpc/app.bsky.feed.getFeedSkeleton?feed=${jsonTyped.feed}${ 210 + cursor ? `&cursor=${cursor}` : "" 211 + }${limit ? `&limit=${limit}` : ""}`, 212 + proxyauth 213 + )) as ATPAPI.AppBskyFeedGetFeedSkeleton.OutputSchema; 214 + 215 + const nextcursor = skeleton.cursor; 216 + const dbgrqstid = skeleton.reqId; 217 + const uriarray = skeleton.feed; 218 + 219 + // Step 1: Chunk into 25 max 220 + const chunks = []; 221 + for (let i = 0; i < uriarray.length; i += 25) { 222 + chunks.push(uriarray.slice(i, i + 25)); 223 + } 224 + 225 + // Step 2: Hydrate via getPosts 226 + const hydratedPosts: ATPAPI.AppBskyFeedDefs.FeedViewPost[] = []; 227 + 228 + for (const chunk of chunks) { 229 + const searchParams = new URLSearchParams(); 230 + for (const uri of chunk.map((item) => item.post)) { 231 + searchParams.append("uris", uri); 232 + } 233 + 234 + const postResp = await ky 235 + .get(`https://api.bsky.app/xrpc/app.bsky.feed.getPosts`, { 236 + // headers: { 237 + // Authorization: proxyauth, 238 + // }, 239 + searchParams, 240 + }) 241 + .json<ATPAPI.AppBskyFeedGetPosts.OutputSchema>(); 242 + 243 + for (const post of postResp.posts) { 244 + const matchingSkeleton = uriarray.find( 245 + (item) => item.post === post.uri 246 + ); 247 + if (matchingSkeleton) { 248 + //post.author.handle = post.author.handle + ".percent40.api.bsky.app"; // or any logic to modify it 249 + hydratedPosts.push({ 250 + post, 251 + reason: matchingSkeleton.reason, 252 + //reply: matchingSkeleton, 253 + }); 254 + } 255 + } 256 + } 257 + 258 + // Step 3: Compose final response 259 + const response: ViewServerTypes.AppBskyFeedGetFeed.OutputSchema = { 260 + feed: hydratedPosts, 261 + cursor: nextcursor, 262 + }; 263 + 264 + return new Response(JSON.stringify(response), { 265 + headers: withCors({ "Content-Type": "application/json" }), 266 + }); 267 + } 268 + case "app.bsky.actor.getProfile": { 269 + const jsonTyped = 270 + jsonUntyped as ViewServerTypes.AppBskyActorGetProfile.QueryParams; 271 + 272 + const userindexservice = ""; 273 + const isbskyfallback = true; 274 + if (isbskyfallback) { 275 + return sendItToApiBskyApp(req); 276 + } 277 + 278 + const response: ViewServerTypes.AppBskyActorGetProfile.OutputSchema = {}; 279 + 280 + return new Response(JSON.stringify(response), { 281 + headers: withCors({ "Content-Type": "application/json" }), 282 + }); 283 + } 284 + 285 + case "app.bsky.actor.getProfiles": { 286 + const jsonTyped = 287 + jsonUntyped as ViewServerTypes.AppBskyActorGetProfiles.QueryParams; 288 + 289 + const userindexservice = ""; 290 + const isbskyfallback = true; 291 + if (isbskyfallback) { 292 + return sendItToApiBskyApp(req); 293 + } 294 + 295 + const response: ViewServerTypes.AppBskyActorGetProfiles.OutputSchema = {}; 296 + 297 + return new Response(JSON.stringify(response), { 298 + headers: withCors({ "Content-Type": "application/json" }), 299 + }); 300 + } 301 + case "app.bsky.feed.getAuthorFeed": { 302 + const jsonTyped = 303 + jsonUntyped as ViewServerTypes.AppBskyFeedGetAuthorFeed.QueryParams; 304 + 305 + const userindexservice = ""; 306 + const isbskyfallback = true; 307 + if (isbskyfallback) { 308 + return sendItToApiBskyApp(req); 309 + } 310 + 311 + const response: ViewServerTypes.AppBskyFeedGetAuthorFeed.OutputSchema = 312 + {}; 313 + 314 + return new Response(JSON.stringify(response), { 315 + headers: withCors({ "Content-Type": "application/json" }), 316 + }); 317 + } 318 + case "app.bsky.feed.getPostThread": { 319 + const jsonTyped = 320 + jsonUntyped as ViewServerTypes.AppBskyFeedGetPostThread.QueryParams; 321 + 322 + const userindexservice = ""; 323 + const isbskyfallback = true; 324 + if (isbskyfallback) { 325 + return sendItToApiBskyApp(req); 326 + } 327 + 328 + const response: ViewServerTypes.AppBskyFeedGetPostThread.OutputSchema = 329 + {}; 330 + 331 + return new Response(JSON.stringify(response), { 332 + headers: withCors({ "Content-Type": "application/json" }), 333 + }); 334 + } 335 + case "app.bsky.unspecced.getPostThreadV2": { 336 + const jsonTyped = 337 + jsonUntyped as ViewServerTypes.AppBskyUnspeccedGetPostThreadV2.QueryParams; 338 + 339 + const userindexservice = ""; 340 + const isbskyfallback = true; 341 + if (isbskyfallback) { 342 + return sendItToApiBskyApp(req); 343 + } 344 + 345 + const response: ViewServerTypes.AppBskyUnspeccedGetPostThreadV2.OutputSchema = 346 + {}; 347 + 348 + return new Response(JSON.stringify(response), { 349 + headers: withCors({ "Content-Type": "application/json" }), 350 + }); 351 + } 352 + 353 + // case "app.bsky.actor.getProfile": { 354 + // const jsonTyped = 355 + // jsonUntyped as ViewServerTypes.AppBskyActorGetProfile.QueryParams; 356 + 357 + // const response: ViewServerTypes.AppBskyActorGetProfile.OutputSchema= {}; 358 + 359 + // return new Response(JSON.stringify(response), { 360 + // headers: withCors({ "Content-Type": "application/json" }), 361 + // }); 362 + // } 363 + // case "app.bsky.actor.getProfiles": { 364 + // const jsonTyped = jsonUntyped as ViewServerTypes.AppBskyActorGetProfiles.QueryParams; 365 + 366 + // const response: ViewServerTypes.AppBskyActorGetProfiles.OutputSchema = {}; 367 + 368 + // return new Response(JSON.stringify(response), { 369 + // headers: withCors({ "Content-Type": "application/json" }), 370 + // }); 371 + // } 372 + // case "whatever": { 373 + // const jsonTyped = jsonUntyped as ViewServerTypes.AppBskyFeedGetAuthorFeed.QueryParams; 374 + 375 + // const response: ViewServerTypes.AppBskyFeedGetAuthorFeed.OutputSchema = {} 376 + 377 + // return new Response(JSON.stringify(response), { 378 + // headers: withCors({ "Content-Type": "application/json" }), 379 + // }); 380 + // } 381 + // case "app.bsky.notification.listNotifications": { 382 + // const jsonTyped = 383 + // jsonUntyped as ViewServerTypes.AppBskyNotificationListNotifications.QueryParams; 384 + 385 + // const response: ViewServerTypes.AppBskyNotificationListNotifications.OutputSchema = {}; 386 + 387 + // return new Response(JSON.stringify(response), { 388 + // headers: withCors({ "Content-Type": "application/json" }), 389 + // }); 390 + // } 391 + 392 + case "app.bsky.unspecced.getConfig": { 393 + const jsonTyped = 394 + jsonUntyped as ViewServerTypes.AppBskyUnspeccedGetConfig.QueryParams; 395 + 396 + const response: ViewServerTypes.AppBskyUnspeccedGetConfig.OutputSchema = { 397 + checkEmailConfirmed: true, 398 + liveNow: [ 399 + { 400 + $type: "app.bsky.unspecced.getConfig#liveNowConfig", 401 + did: "did:plc:mn45tewwnse5btfftvd3powc", 402 + domains: ["local3768forumtest.whey.party"], 403 + }, 404 + ], 405 + }; 406 + 407 + return new Response(JSON.stringify(response), { 408 + headers: withCors({ "Content-Type": "application/json" }), 409 + }); 410 + } 411 + case "app.bsky.graph.getLists": { 412 + const jsonTyped = 413 + jsonUntyped as ViewServerTypes.AppBskyGraphGetLists.QueryParams; 414 + 415 + const response: ViewServerTypes.AppBskyGraphGetLists.OutputSchema = { 416 + lists: [], 417 + }; 418 + 419 + return new Response(JSON.stringify(response), { 420 + headers: withCors({ "Content-Type": "application/json" }), 421 + }); 422 + } 423 + //https://shimeji.us-east.host.bsky.network/xrpc/app.bsky.unspecced.getTrendingTopics?limit=14 424 + case "app.bsky.unspecced.getTrendingTopics": { 425 + const jsonTyped = 426 + jsonUntyped as ViewServerTypes.AppBskyUnspeccedGetTrendingTopics.QueryParams; 427 + 428 + const faketopics: ATPAPI.AppBskyUnspeccedDefs.TrendingTopic[] = [ 429 + { 430 + $type: "app.bsky.unspecced.defs#trendingTopic", 431 + topic: "Git Repo", 432 + displayName: "Git Repo", 433 + description: "Git Repo", 434 + link: "https://tangled.sh/@whey.party/skylite", 435 + }, 436 + { 437 + $type: "app.bsky.unspecced.defs#trendingTopic", 438 + topic: "Red Dwarf Lite", 439 + displayName: "Red Dwarf Lite", 440 + description: "Red Dwarf Lite", 441 + link: "https://reddwarf.whey.party/", 442 + }, 443 + { 444 + $type: "app.bsky.unspecced.defs#trendingTopic", 445 + topic: "whey dot party", 446 + displayName: "whey dot party", 447 + description: "whey dot party", 448 + link: "https://whey.party/", 449 + }, 450 + ]; 451 + 452 + const response: ViewServerTypes.AppBskyUnspeccedGetTrendingTopics.OutputSchema = 453 + { 454 + topics: faketopics, 455 + suggested: faketopics, 456 + }; 457 + 458 + return new Response(JSON.stringify(response), { 459 + headers: withCors({ "Content-Type": "application/json" }), 460 + }); 461 + } 462 + default: { 463 + return new Response( 464 + JSON.stringify({ 465 + error: "XRPCNotSupported", 466 + message: 467 + "HEY hello there my name is whey dot party and you have used my custom appview that is very cool but have you considered that XRPC Not Supported", 468 + }), 469 + { 470 + status: 404, 471 + headers: withCors({ "Content-Type": "application/json" }), 472 + } 473 + ); 474 + } 475 + } 476 + 477 + return new Response("Not Found", { status: 404 }); 478 + } 479 + 480 + async function sendItToApiBskyApp(req: Request): Promise<Response> { 481 + const url = new URL(req.url); 482 + const pathname = url.pathname; 483 + const searchParams = searchParamsToJson(url.searchParams); 484 + let reqBody: undefined | string; 485 + let jsonbody: undefined | Record<string, unknown>; 486 + if (req.body) { 487 + const body = await req.json(); 488 + jsonbody = body; 489 + // console.log( 490 + // `called at euh reqreqreqreq: ${pathname}\n\n${JSON.stringify(body)}` 491 + // ); 492 + reqBody = JSON.stringify(body, null, 2); 493 + } 494 + const bskyUrl = `https://api.bsky.app${pathname}${url.search}`; 495 + const proxyHeaders = new Headers(req.headers); 496 + 497 + // Remove Authorization and set browser-like User-Agent 498 + proxyHeaders.delete("authorization"); 499 + proxyHeaders.delete("Access-Control-Allow-Origin"), 500 + proxyHeaders.set( 501 + "user-agent", 502 + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" 503 + ); 504 + proxyHeaders.set("Access-Control-Allow-Origin", "*"); 505 + 506 + const proxyRes = await fetch(bskyUrl, { 507 + method: req.method, 508 + headers: proxyHeaders, 509 + body: ["GET", "HEAD"].includes(req.method.toUpperCase()) 510 + ? undefined 511 + : reqBody, 512 + }); 513 + 514 + const resBody = await proxyRes.text(); 515 + 516 + // console.log( 517 + // "← Response:", 518 + // JSON.stringify(await JSON.parse(resBody), null, 2) 519 + // ); 520 + 521 + return new Response(resBody, { 522 + status: proxyRes.status, 523 + headers: proxyRes.headers, 524 + }); 525 + }