@clioplaylists/clio 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.env +7 -0
- package/dist/api/com/clioplaylists/alpha/actor/getProfile.d.ts +0 -0
- package/dist/api/com/clioplaylists/alpha/actor/getProfile.js +37 -0
- package/dist/api/com/clioplaylists/alpha/feed/getSongs.d.ts +0 -0
- package/dist/api/com/clioplaylists/alpha/feed/getSongs.js +37 -0
- package/dist/api/health.d.ts +3 -0
- package/dist/api/health.js +25 -0
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.js +6 -0
- package/dist/api/util.d.ts +9 -0
- package/dist/api/util.js +13 -0
- package/dist/auth-verifier.d.ts +92 -0
- package/dist/auth-verifier.js +365 -0
- package/dist/client.d.ts +9 -0
- package/dist/client.js +33 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.js +49 -0
- package/dist/context.d.ts +11 -0
- package/dist/context.js +12 -0
- package/dist/dataplane/client.d.ts +27 -0
- package/dist/dataplane/client.js +120 -0
- package/dist/dataplane/index.d.ts +2 -0
- package/dist/dataplane/index.js +2 -0
- package/dist/dataplane/server/background.d.ts +13 -0
- package/dist/dataplane/server/background.js +30 -0
- package/dist/dataplane/server/db/database-schema.d.ts +13 -0
- package/dist/dataplane/server/db/database-schema.js +1 -0
- package/dist/dataplane/server/db/db.d.ts +32 -0
- package/dist/dataplane/server/db/db.js +152 -0
- package/dist/dataplane/server/db/index.d.ts +1 -0
- package/dist/dataplane/server/db/index.js +1 -0
- package/dist/dataplane/server/db/migrations/20230309T045948368Z-init.d.ts +3 -0
- package/dist/dataplane/server/db/migrations/20230309T045948368Z-init.js +113 -0
- package/dist/dataplane/server/db/migrations/20230420T211446071Z-did-cache.d.ts +3 -0
- package/dist/dataplane/server/db/migrations/20230420T211446071Z-did-cache.js +11 -0
- package/dist/dataplane/server/db/migrations/index.d.ts +2 -0
- package/dist/dataplane/server/db/migrations/index.js +5 -0
- package/dist/dataplane/server/db/migrations/provider.d.ts +11 -0
- package/dist/dataplane/server/db/migrations/provider.js +19 -0
- package/dist/dataplane/server/db/pagination.d.ts +86 -0
- package/dist/dataplane/server/db/pagination.js +128 -0
- package/dist/dataplane/server/db/tables/actor-sync.d.ts +9 -0
- package/dist/dataplane/server/db/tables/actor-sync.js +1 -0
- package/dist/dataplane/server/db/tables/actor.d.ts +11 -0
- package/dist/dataplane/server/db/tables/actor.js +1 -0
- package/dist/dataplane/server/db/tables/artist-list-item.d.ts +11 -0
- package/dist/dataplane/server/db/tables/artist-list-item.js +1 -0
- package/dist/dataplane/server/db/tables/artist.d.ts +10 -0
- package/dist/dataplane/server/db/tables/artist.js +1 -0
- package/dist/dataplane/server/db/tables/playlist-idea.d.ts +14 -0
- package/dist/dataplane/server/db/tables/playlist-idea.js +1 -0
- package/dist/dataplane/server/db/tables/playlist-item.d.ts +11 -0
- package/dist/dataplane/server/db/tables/playlist-item.js +1 -0
- package/dist/dataplane/server/db/tables/playlist.d.ts +10 -0
- package/dist/dataplane/server/db/tables/playlist.js +1 -0
- package/dist/dataplane/server/db/tables/profile.d.ts +15 -0
- package/dist/dataplane/server/db/tables/profile.js +1 -0
- package/dist/dataplane/server/db/tables/record.d.ts +12 -0
- package/dist/dataplane/server/db/tables/record.js +1 -0
- package/dist/dataplane/server/db/tables/song.d.ts +12 -0
- package/dist/dataplane/server/db/tables/song.js +1 -0
- package/dist/dataplane/server/db/types.d.ts +9 -0
- package/dist/dataplane/server/db/types.js +1 -0
- package/dist/dataplane/server/db/util.d.ts +20 -0
- package/dist/dataplane/server/db/util.js +40 -0
- package/dist/dataplane/server/index.d.ts +11 -0
- package/dist/dataplane/server/index.js +36 -0
- package/dist/dataplane/server/indexing/index.d.ts +32 -0
- package/dist/dataplane/server/indexing/index.js +271 -0
- package/dist/dataplane/server/indexing/plugins/playlist-idea.d.ts +14 -0
- package/dist/dataplane/server/indexing/plugins/playlist-idea.js +126 -0
- package/dist/dataplane/server/indexing/plugins/profile.d.ts +8 -0
- package/dist/dataplane/server/indexing/plugins/profile.js +44 -0
- package/dist/dataplane/server/indexing/processor.d.ts +22 -0
- package/dist/dataplane/server/indexing/processor.js +72 -0
- package/dist/dataplane/server/routes/identity.d.ts +6 -0
- package/dist/dataplane/server/routes/identity.js +54 -0
- package/dist/dataplane/server/routes/index.d.ts +5 -0
- package/dist/dataplane/server/routes/index.js +14 -0
- package/dist/dataplane/server/routes/profile.d.ts +5 -0
- package/dist/dataplane/server/routes/profile.js +59 -0
- package/dist/dataplane/server/routes/records.d.ts +11 -0
- package/dist/dataplane/server/routes/records.js +51 -0
- package/dist/dataplane/server/routes/sync.d.ts +5 -0
- package/dist/dataplane/server/routes/sync.js +12 -0
- package/dist/dataplane/server/subscription.d.ts +25 -0
- package/dist/dataplane/server/subscription.js +86 -0
- package/dist/error.d.ts +2 -0
- package/dist/error.js +10 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +55 -0
- package/dist/lexicons/index.d.ts +278 -0
- package/dist/lexicons/index.js +463 -0
- package/dist/lexicons/lexicons.d.ts +8466 -0
- package/dist/lexicons/lexicons.js +4548 -0
- package/dist/lexicons/types/com/atproto/admin/defs.d.ts +50 -0
- package/dist/lexicons/types/com/atproto/admin/defs.js +42 -0
- package/dist/lexicons/types/com/atproto/admin/deleteAccount.d.ts +29 -0
- package/dist/lexicons/types/com/atproto/admin/deleteAccount.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/disableAccountInvites.d.ts +31 -0
- package/dist/lexicons/types/com/atproto/admin/disableAccountInvites.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/disableInviteCodes.d.ts +30 -0
- package/dist/lexicons/types/com/atproto/admin/disableInviteCodes.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/enableAccountInvites.d.ts +31 -0
- package/dist/lexicons/types/com/atproto/admin/enableAccountInvites.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/getAccountInfo.d.ts +33 -0
- package/dist/lexicons/types/com/atproto/admin/getAccountInfo.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/getAccountInfos.d.ts +36 -0
- package/dist/lexicons/types/com/atproto/admin/getAccountInfos.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/getInviteCodes.d.ts +39 -0
- package/dist/lexicons/types/com/atproto/admin/getInviteCodes.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/getSubjectStatus.d.ts +44 -0
- package/dist/lexicons/types/com/atproto/admin/getSubjectStatus.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/searchAccounts.d.ts +39 -0
- package/dist/lexicons/types/com/atproto/admin/searchAccounts.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/sendEmail.d.ts +45 -0
- package/dist/lexicons/types/com/atproto/admin/sendEmail.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountEmail.d.ts +31 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountEmail.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountHandle.d.ts +30 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountHandle.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountPassword.d.ts +30 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountPassword.js +1 -0
- package/dist/lexicons/types/com/atproto/admin/updateSubjectStatus.d.ts +51 -0
- package/dist/lexicons/types/com/atproto/admin/updateSubjectStatus.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/defs.d.ts +14 -0
- package/dist/lexicons/types/com/atproto/identity/defs.js +10 -0
- package/dist/lexicons/types/com/atproto/identity/getRecommendedDidCredentials.d.ts +38 -0
- package/dist/lexicons/types/com/atproto/identity/getRecommendedDidCredentials.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/refreshIdentity.d.ts +39 -0
- package/dist/lexicons/types/com/atproto/identity/refreshIdentity.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/requestPlcOperationSignature.d.ts +23 -0
- package/dist/lexicons/types/com/atproto/identity/requestPlcOperationSignature.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/resolveDid.d.ts +38 -0
- package/dist/lexicons/types/com/atproto/identity/resolveDid.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/resolveHandle.d.ts +37 -0
- package/dist/lexicons/types/com/atproto/identity/resolveHandle.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/resolveIdentity.d.ts +35 -0
- package/dist/lexicons/types/com/atproto/identity/resolveIdentity.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/signPlcOperation.d.ts +46 -0
- package/dist/lexicons/types/com/atproto/identity/signPlcOperation.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/submitPlcOperation.d.ts +29 -0
- package/dist/lexicons/types/com/atproto/identity/submitPlcOperation.js +1 -0
- package/dist/lexicons/types/com/atproto/identity/updateHandle.d.ts +30 -0
- package/dist/lexicons/types/com/atproto/identity/updateHandle.js +1 -0
- package/dist/lexicons/types/com/atproto/label/defs.d.ts +73 -0
- package/dist/lexicons/types/com/atproto/label/defs.js +42 -0
- package/dist/lexicons/types/com/atproto/label/queryLabels.d.ts +42 -0
- package/dist/lexicons/types/com/atproto/label/queryLabels.js +1 -0
- package/dist/lexicons/types/com/atproto/label/subscribeLabels.d.ts +38 -0
- package/dist/lexicons/types/com/atproto/label/subscribeLabels.js +18 -0
- package/dist/lexicons/types/com/atproto/lexicon/schema.d.ts +11 -0
- package/dist/lexicons/types/com/atproto/lexicon/schema.js +11 -0
- package/dist/lexicons/types/com/atproto/moderation/createReport.d.ts +57 -0
- package/dist/lexicons/types/com/atproto/moderation/createReport.js +1 -0
- package/dist/lexicons/types/com/atproto/moderation/defs.d.ts +20 -0
- package/dist/lexicons/types/com/atproto/moderation/defs.js +17 -0
- package/dist/lexicons/types/com/atproto/repo/applyWrites.d.ts +98 -0
- package/dist/lexicons/types/com/atproto/repo/applyWrites.js +50 -0
- package/dist/lexicons/types/com/atproto/repo/createRecord.d.ts +56 -0
- package/dist/lexicons/types/com/atproto/repo/createRecord.js +1 -0
- package/dist/lexicons/types/com/atproto/repo/defs.d.ts +11 -0
- package/dist/lexicons/types/com/atproto/repo/defs.js +10 -0
- package/dist/lexicons/types/com/atproto/repo/deleteRecord.d.ts +51 -0
- package/dist/lexicons/types/com/atproto/repo/deleteRecord.js +1 -0
- package/dist/lexicons/types/com/atproto/repo/describeRepo.d.ts +43 -0
- package/dist/lexicons/types/com/atproto/repo/describeRepo.js +1 -0
- package/dist/lexicons/types/com/atproto/repo/getRecord.d.ts +45 -0
- package/dist/lexicons/types/com/atproto/repo/getRecord.js +1 -0
- package/dist/lexicons/types/com/atproto/repo/importRepo.d.ts +27 -0
- package/dist/lexicons/types/com/atproto/repo/importRepo.js +1 -0
- package/dist/lexicons/types/com/atproto/repo/listMissingBlobs.d.ts +45 -0
- package/dist/lexicons/types/com/atproto/repo/listMissingBlobs.js +10 -0
- package/dist/lexicons/types/com/atproto/repo/listRecords.d.ts +53 -0
- package/dist/lexicons/types/com/atproto/repo/listRecords.js +10 -0
- package/dist/lexicons/types/com/atproto/repo/putRecord.d.ts +58 -0
- package/dist/lexicons/types/com/atproto/repo/putRecord.js +1 -0
- package/dist/lexicons/types/com/atproto/repo/strongRef.d.ts +11 -0
- package/dist/lexicons/types/com/atproto/repo/strongRef.js +11 -0
- package/dist/lexicons/types/com/atproto/repo/uploadBlob.d.ts +39 -0
- package/dist/lexicons/types/com/atproto/repo/uploadBlob.js +1 -0
- package/dist/lexicons/types/com/atproto/server/activateAccount.d.ts +23 -0
- package/dist/lexicons/types/com/atproto/server/activateAccount.js +1 -0
- package/dist/lexicons/types/com/atproto/server/checkAccountStatus.d.ts +42 -0
- package/dist/lexicons/types/com/atproto/server/checkAccountStatus.js +1 -0
- package/dist/lexicons/types/com/atproto/server/confirmEmail.d.ts +31 -0
- package/dist/lexicons/types/com/atproto/server/confirmEmail.js +1 -0
- package/dist/lexicons/types/com/atproto/server/createAccount.d.ts +61 -0
- package/dist/lexicons/types/com/atproto/server/createAccount.js +1 -0
- package/dist/lexicons/types/com/atproto/server/createAppPassword.d.ts +51 -0
- package/dist/lexicons/types/com/atproto/server/createAppPassword.js +10 -0
- package/dist/lexicons/types/com/atproto/server/createInviteCode.d.ts +41 -0
- package/dist/lexicons/types/com/atproto/server/createInviteCode.js +1 -0
- package/dist/lexicons/types/com/atproto/server/createInviteCodes.d.ts +50 -0
- package/dist/lexicons/types/com/atproto/server/createInviteCodes.js +10 -0
- package/dist/lexicons/types/com/atproto/server/createSession.d.ts +56 -0
- package/dist/lexicons/types/com/atproto/server/createSession.js +1 -0
- package/dist/lexicons/types/com/atproto/server/deactivateAccount.d.ts +30 -0
- package/dist/lexicons/types/com/atproto/server/deactivateAccount.js +1 -0
- package/dist/lexicons/types/com/atproto/server/defs.d.ts +23 -0
- package/dist/lexicons/types/com/atproto/server/defs.js +18 -0
- package/dist/lexicons/types/com/atproto/server/deleteAccount.d.ts +32 -0
- package/dist/lexicons/types/com/atproto/server/deleteAccount.js +1 -0
- package/dist/lexicons/types/com/atproto/server/deleteSession.d.ts +23 -0
- package/dist/lexicons/types/com/atproto/server/deleteSession.js +1 -0
- package/dist/lexicons/types/com/atproto/server/describeServer.d.ts +56 -0
- package/dist/lexicons/types/com/atproto/server/describeServer.js +18 -0
- package/dist/lexicons/types/com/atproto/server/getAccountInviteCodes.d.ts +39 -0
- package/dist/lexicons/types/com/atproto/server/getAccountInviteCodes.js +1 -0
- package/dist/lexicons/types/com/atproto/server/getServiceAuth.d.ts +41 -0
- package/dist/lexicons/types/com/atproto/server/getServiceAuth.js +1 -0
- package/dist/lexicons/types/com/atproto/server/getSession.d.ts +42 -0
- package/dist/lexicons/types/com/atproto/server/getSession.js +1 -0
- package/dist/lexicons/types/com/atproto/server/listAppPasswords.d.ts +44 -0
- package/dist/lexicons/types/com/atproto/server/listAppPasswords.js +10 -0
- package/dist/lexicons/types/com/atproto/server/refreshSession.d.ts +42 -0
- package/dist/lexicons/types/com/atproto/server/refreshSession.js +1 -0
- package/dist/lexicons/types/com/atproto/server/requestAccountDelete.d.ts +23 -0
- package/dist/lexicons/types/com/atproto/server/requestAccountDelete.js +1 -0
- package/dist/lexicons/types/com/atproto/server/requestEmailConfirmation.d.ts +23 -0
- package/dist/lexicons/types/com/atproto/server/requestEmailConfirmation.js +1 -0
- package/dist/lexicons/types/com/atproto/server/requestEmailUpdate.d.ts +34 -0
- package/dist/lexicons/types/com/atproto/server/requestEmailUpdate.js +1 -0
- package/dist/lexicons/types/com/atproto/server/requestPasswordReset.d.ts +29 -0
- package/dist/lexicons/types/com/atproto/server/requestPasswordReset.js +1 -0
- package/dist/lexicons/types/com/atproto/server/reserveSigningKey.d.ts +42 -0
- package/dist/lexicons/types/com/atproto/server/reserveSigningKey.js +1 -0
- package/dist/lexicons/types/com/atproto/server/resetPassword.d.ts +31 -0
- package/dist/lexicons/types/com/atproto/server/resetPassword.js +1 -0
- package/dist/lexicons/types/com/atproto/server/revokeAppPassword.d.ts +29 -0
- package/dist/lexicons/types/com/atproto/server/revokeAppPassword.js +1 -0
- package/dist/lexicons/types/com/atproto/server/updateEmail.d.ts +33 -0
- package/dist/lexicons/types/com/atproto/server/updateEmail.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getBlob.d.ts +36 -0
- package/dist/lexicons/types/com/atproto/sync/getBlob.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getBlocks.d.ts +35 -0
- package/dist/lexicons/types/com/atproto/sync/getBlocks.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getCheckout.d.ts +33 -0
- package/dist/lexicons/types/com/atproto/sync/getCheckout.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getHead.d.ts +37 -0
- package/dist/lexicons/types/com/atproto/sync/getHead.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getLatestCommit.d.ts +38 -0
- package/dist/lexicons/types/com/atproto/sync/getLatestCommit.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getRecord.d.ts +37 -0
- package/dist/lexicons/types/com/atproto/sync/getRecord.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getRepo.d.ts +36 -0
- package/dist/lexicons/types/com/atproto/sync/getRepo.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/getRepoStatus.d.ts +42 -0
- package/dist/lexicons/types/com/atproto/sync/getRepoStatus.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/listBlobs.d.ts +42 -0
- package/dist/lexicons/types/com/atproto/sync/listBlobs.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/listRepos.d.ts +50 -0
- package/dist/lexicons/types/com/atproto/sync/listRepos.js +10 -0
- package/dist/lexicons/types/com/atproto/sync/listReposByCollection.d.ts +46 -0
- package/dist/lexicons/types/com/atproto/sync/listReposByCollection.js +10 -0
- package/dist/lexicons/types/com/atproto/sync/notifyOfUpdate.d.ts +30 -0
- package/dist/lexicons/types/com/atproto/sync/notifyOfUpdate.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/requestCrawl.d.ts +30 -0
- package/dist/lexicons/types/com/atproto/sync/requestCrawl.js +1 -0
- package/dist/lexicons/types/com/atproto/sync/subscribeRepos.d.ts +111 -0
- package/dist/lexicons/types/com/atproto/sync/subscribeRepos.js +50 -0
- package/dist/lexicons/types/com/atproto/temp/addReservedHandle.d.ts +39 -0
- package/dist/lexicons/types/com/atproto/temp/addReservedHandle.js +1 -0
- package/dist/lexicons/types/com/atproto/temp/checkSignupQueue.d.ts +36 -0
- package/dist/lexicons/types/com/atproto/temp/checkSignupQueue.js +1 -0
- package/dist/lexicons/types/com/atproto/temp/fetchLabels.d.ts +37 -0
- package/dist/lexicons/types/com/atproto/temp/fetchLabels.js +1 -0
- package/dist/lexicons/types/com/atproto/temp/requestPhoneVerification.d.ts +29 -0
- package/dist/lexicons/types/com/atproto/temp/requestPhoneVerification.js +1 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/actor/profile.d.ts +19 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/actor/profile.js +11 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/defs.d.ts +32 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/defs.js +18 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/getSongs.d.ts +37 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/getSongs.js +1 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/playlistIdea.d.ts +32 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/playlistIdea.js +27 -0
- package/dist/lexicons/util.d.ts +5 -0
- package/dist/lexicons/util.js +9 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.js +20 -0
- package/dist/rpc/clio_connect.d.ts +103 -0
- package/dist/rpc/clio_connect.js +107 -0
- package/dist/rpc/clio_pb.d.ts +457 -0
- package/dist/rpc/clio_pb.js +811 -0
- package/dist/start.d.ts +1 -0
- package/dist/util/retry.d.ts +2 -0
- package/dist/util/retry.js +13 -0
- package/dist/util/uris.d.ts +1 -0
- package/dist/util/uris.js +4 -0
- package/dist/util.d.ts +23 -0
- package/dist/util.js +76 -0
- package/package.json +7 -7
- /package/{start.js → dist/start.js} +0 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { Agent, ComAtprotoSyncGetLatestCommit } from '@atproto/api';
|
|
2
|
+
import { DAY, HOUR } from '@atproto/common';
|
|
3
|
+
import { getPds } from '@atproto/identity';
|
|
4
|
+
import { ValidationError } from '@atproto/lexicon';
|
|
5
|
+
import { WriteOpAction, getAndParseRecord, readCarWithRoot, verifyRepo, } from '@atproto/repo';
|
|
6
|
+
import { AtUri } from '@atproto/syntax';
|
|
7
|
+
import { sql } from 'kysely';
|
|
8
|
+
import { CID } from 'multiformats/cid';
|
|
9
|
+
import { httpLogger } from '../../../logger';
|
|
10
|
+
import { retryXrpc } from '../../../util/retry';
|
|
11
|
+
import * as PlaylistIdea from './plugins/playlist-idea';
|
|
12
|
+
import * as Profile from './plugins/profile';
|
|
13
|
+
export class IndexingService {
|
|
14
|
+
db;
|
|
15
|
+
idResolver;
|
|
16
|
+
records;
|
|
17
|
+
constructor(db, idResolver) {
|
|
18
|
+
this.db = db;
|
|
19
|
+
this.idResolver = idResolver;
|
|
20
|
+
this.records = {
|
|
21
|
+
playlistIdea: PlaylistIdea.makePlugin(this.db),
|
|
22
|
+
profile: Profile.makePlugin(this.db),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
transact(txn) {
|
|
26
|
+
txn.assertTransaction();
|
|
27
|
+
return new IndexingService(txn, this.idResolver);
|
|
28
|
+
}
|
|
29
|
+
async indexRecord(uri, cid, obj, action, timestamp) {
|
|
30
|
+
this.db.assertNotTransaction();
|
|
31
|
+
await this.db.transaction(async (txn) => {
|
|
32
|
+
const indexingTx = this.transact(txn);
|
|
33
|
+
const indexer = indexingTx.findIndexerForCollection(uri.collection);
|
|
34
|
+
if (!indexer)
|
|
35
|
+
return;
|
|
36
|
+
if (action === WriteOpAction.Create) {
|
|
37
|
+
await indexer.insertRecord(uri, cid, obj, timestamp);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
await indexer.updateRecord(uri, cid, obj, timestamp);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async deleteRecord(uri, cascading = false) {
|
|
45
|
+
this.db.assertNotTransaction();
|
|
46
|
+
await this.db.transaction(async (txn) => {
|
|
47
|
+
const indexingTx = this.transact(txn);
|
|
48
|
+
const indexer = indexingTx.findIndexerForCollection(uri.collection);
|
|
49
|
+
if (!indexer)
|
|
50
|
+
return;
|
|
51
|
+
await indexer.deleteRecord(uri, cascading);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async indexHandle(did, timestamp, force = false) {
|
|
55
|
+
this.db.assertNotTransaction();
|
|
56
|
+
const actor = await this.db.db
|
|
57
|
+
.selectFrom('actor')
|
|
58
|
+
.where('did', '=', did)
|
|
59
|
+
.selectAll()
|
|
60
|
+
.executeTakeFirst();
|
|
61
|
+
if (!force && !needsHandleReindex(actor, timestamp)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const atpData = await this.idResolver.did.resolveAtprotoData(did, true);
|
|
65
|
+
const handleToDid = await this.idResolver.handle.resolve(atpData.handle);
|
|
66
|
+
const handle = did === handleToDid ? atpData.handle.toLowerCase() : null;
|
|
67
|
+
const actorWithHandle = handle !== null
|
|
68
|
+
? await this.db.db
|
|
69
|
+
.selectFrom('actor')
|
|
70
|
+
.where('handle', '=', handle)
|
|
71
|
+
.selectAll()
|
|
72
|
+
.executeTakeFirst()
|
|
73
|
+
: null;
|
|
74
|
+
// handle contention
|
|
75
|
+
if (handle && actorWithHandle && did !== actorWithHandle.did) {
|
|
76
|
+
await this.db.db
|
|
77
|
+
.updateTable('actor')
|
|
78
|
+
.where('actor.did', '=', actorWithHandle.did)
|
|
79
|
+
.set({ handle: null })
|
|
80
|
+
.execute();
|
|
81
|
+
}
|
|
82
|
+
const actorInfo = { handle, indexed_at: timestamp };
|
|
83
|
+
await this.db.db
|
|
84
|
+
.insertInto('actor')
|
|
85
|
+
.values({ did, ...actorInfo })
|
|
86
|
+
.onConflict((oc) => oc.column('did').doUpdateSet(actorInfo))
|
|
87
|
+
.returning('did')
|
|
88
|
+
.executeTakeFirst();
|
|
89
|
+
}
|
|
90
|
+
async indexRepo(did, commit) {
|
|
91
|
+
this.db.assertNotTransaction();
|
|
92
|
+
const now = new Date().toISOString();
|
|
93
|
+
const { pds, signingKey } = await this.idResolver.did.resolveAtprotoData(did, true);
|
|
94
|
+
const agent = new Agent(pds);
|
|
95
|
+
const { data: car } = await retryXrpc(() => agent.com.atproto.sync.getRepo({ did }));
|
|
96
|
+
const { root, blocks } = await readCarWithRoot(car);
|
|
97
|
+
const verifiedRepo = await verifyRepo(blocks, root, did, signingKey);
|
|
98
|
+
const currRecords = await this.getCurrentRecords(did);
|
|
99
|
+
const repoRecords = formatCheckout(did, verifiedRepo);
|
|
100
|
+
const diff = findDiffFromCheckout(currRecords, repoRecords);
|
|
101
|
+
await Promise.all(diff.map(async (op) => {
|
|
102
|
+
const { uri, cid } = op;
|
|
103
|
+
try {
|
|
104
|
+
if (op.op === 'delete') {
|
|
105
|
+
await this.deleteRecord(uri);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const parsed = await getAndParseRecord(blocks, cid);
|
|
109
|
+
await this.indexRecord(uri, cid, parsed.record, op.op === 'create' ? WriteOpAction.Create : WriteOpAction.Update, now);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (err instanceof ValidationError) {
|
|
114
|
+
httpLogger.warn({ did, commit, uri: uri.toString(), cid: cid.toString() }, 'skipping indexing of invalid record');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
httpLogger.error({ err, did, commit, uri: uri.toString(), cid: cid.toString() }, 'skipping indexing due to error processing record');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
async updateActorStatus(did, active, status = '') {
|
|
123
|
+
let upstreamStatus;
|
|
124
|
+
if (active) {
|
|
125
|
+
upstreamStatus = null;
|
|
126
|
+
}
|
|
127
|
+
else if (['deactivated', 'suspended', 'takendown'].includes(status)) {
|
|
128
|
+
upstreamStatus = status;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
throw new Error(`Unrecognized account status: ${status}`);
|
|
132
|
+
}
|
|
133
|
+
await this.db.db
|
|
134
|
+
.updateTable('actor')
|
|
135
|
+
.set({ upstreamStatus })
|
|
136
|
+
.where('did', '=', did)
|
|
137
|
+
.execute();
|
|
138
|
+
}
|
|
139
|
+
async setCommitLastSeen(did, commit, rev) {
|
|
140
|
+
const { ref } = this.db.db.dynamic;
|
|
141
|
+
await this.db.db
|
|
142
|
+
.insertInto('actor_sync')
|
|
143
|
+
.values({
|
|
144
|
+
did,
|
|
145
|
+
commitCid: commit.toString(),
|
|
146
|
+
repoRev: rev ?? null,
|
|
147
|
+
})
|
|
148
|
+
.onConflict((oc) => {
|
|
149
|
+
const excluded = (col) => ref(`excluded.${col}`);
|
|
150
|
+
return oc.column('did').doUpdateSet({
|
|
151
|
+
commitCid: sql `${excluded('commitCid')}`,
|
|
152
|
+
repoRev: sql `${excluded('repoRev')}`,
|
|
153
|
+
});
|
|
154
|
+
})
|
|
155
|
+
.execute();
|
|
156
|
+
}
|
|
157
|
+
async getCurrentRecords(did) {
|
|
158
|
+
const res = await this.db.db
|
|
159
|
+
.selectFrom('record')
|
|
160
|
+
.where('did', '=', did)
|
|
161
|
+
.select(['uri', 'cid'])
|
|
162
|
+
.execute();
|
|
163
|
+
return res.reduce((acc, cur) => {
|
|
164
|
+
acc[cur.uri] = {
|
|
165
|
+
uri: new AtUri(cur.uri),
|
|
166
|
+
cid: CID.parse(cur.cid),
|
|
167
|
+
};
|
|
168
|
+
return acc;
|
|
169
|
+
}, {});
|
|
170
|
+
}
|
|
171
|
+
findIndexerForCollection(collection) {
|
|
172
|
+
const indexers = Object.values(this.records);
|
|
173
|
+
return indexers.find((indexer) => indexer.collection === collection);
|
|
174
|
+
}
|
|
175
|
+
async deleteActor(did) {
|
|
176
|
+
this.db.assertNotTransaction();
|
|
177
|
+
const actorIsHosted = await this.getActorIsHosted(did);
|
|
178
|
+
if (actorIsHosted === false) {
|
|
179
|
+
await this.db.db.deleteFrom('actor').where('did', '=', did).execute();
|
|
180
|
+
await this.unindexActor(did);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async getActorIsHosted(did) {
|
|
184
|
+
const doc = await this.idResolver.did.resolve(did, true);
|
|
185
|
+
const pds = doc && getPds(doc);
|
|
186
|
+
if (!pds)
|
|
187
|
+
return false;
|
|
188
|
+
const agent = new Agent(pds);
|
|
189
|
+
try {
|
|
190
|
+
await retryXrpc(() => agent.com.atproto.sync.getLatestCommit({ did }));
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
if (err instanceof ComAtprotoSyncGetLatestCommit.RepoNotFoundError) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async unindexActor(did) {
|
|
201
|
+
this.db.assertNotTransaction();
|
|
202
|
+
await this.db.db.deleteFrom('profile').where('creator', '=', did).execute();
|
|
203
|
+
await this.db.db.deleteFrom('record').where('did', '=', did).execute();
|
|
204
|
+
const deletedPlaylistIdeas = await this.db.db
|
|
205
|
+
.deleteFrom('playlist_idea')
|
|
206
|
+
.where('owner_did', '=', did)
|
|
207
|
+
.returningAll()
|
|
208
|
+
.execute();
|
|
209
|
+
const deletedPlaylistIdeaUris = deletedPlaylistIdeas.map((deletedPlaylistIdea) => {
|
|
210
|
+
return deletedPlaylistIdea.uri;
|
|
211
|
+
});
|
|
212
|
+
const deletedPlaylists = await this.db.db
|
|
213
|
+
.deleteFrom('playlist')
|
|
214
|
+
.where('playlist_idea_uri', 'in', deletedPlaylistIdeaUris)
|
|
215
|
+
.returningAll()
|
|
216
|
+
.execute();
|
|
217
|
+
const deletedPlaylistIds = deletedPlaylists.map((deletedPlaylist) => {
|
|
218
|
+
return deletedPlaylist.id;
|
|
219
|
+
});
|
|
220
|
+
await this.db.db
|
|
221
|
+
.deleteFrom('playlist_item')
|
|
222
|
+
.where('playlist_id', 'in', deletedPlaylistIds)
|
|
223
|
+
.execute();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const findDiffFromCheckout = (curr, checkout) => {
|
|
227
|
+
const ops = [];
|
|
228
|
+
for (const uri of Object.keys(checkout)) {
|
|
229
|
+
const record = checkout[uri];
|
|
230
|
+
if (!curr[uri]) {
|
|
231
|
+
ops.push({ op: 'create', ...record });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
if (curr[uri].cid.equals(record.cid)) {
|
|
235
|
+
// no-op
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
ops.push({ op: 'update', ...record });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
for (const uri of Object.keys(curr)) {
|
|
242
|
+
const record = curr[uri];
|
|
243
|
+
if (!checkout[uri]) {
|
|
244
|
+
ops.push({ op: 'delete', ...record });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return ops;
|
|
248
|
+
};
|
|
249
|
+
const formatCheckout = (did, verifiedRepo) => {
|
|
250
|
+
const records = {};
|
|
251
|
+
for (const create of verifiedRepo.creates) {
|
|
252
|
+
const uri = AtUri.make(did, create.collection, create.rkey);
|
|
253
|
+
records[uri.toString()] = {
|
|
254
|
+
uri,
|
|
255
|
+
cid: create.cid,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return records;
|
|
259
|
+
};
|
|
260
|
+
const needsHandleReindex = (actor, timestamp) => {
|
|
261
|
+
if (!actor)
|
|
262
|
+
return true;
|
|
263
|
+
const timeDiff = new Date(timestamp).getTime() - new Date(actor.indexed_at).getTime();
|
|
264
|
+
// revalidate daily
|
|
265
|
+
if (timeDiff > DAY)
|
|
266
|
+
return true;
|
|
267
|
+
// revalidate more aggressively for invalidated handles
|
|
268
|
+
if (actor.handle === null && timeDiff > HOUR)
|
|
269
|
+
return true;
|
|
270
|
+
return false;
|
|
271
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Selectable } from 'kysely';
|
|
2
|
+
import { MasterPlaylist, Record as PlaylistIdeaRecord, RecommendedPlaylist } from '../../../../lexicons/types/com/clioplaylists/alpha/feed/playlistIdea';
|
|
3
|
+
import { Database } from '../../db';
|
|
4
|
+
import { DatabaseSchemaType } from '../../db/database-schema';
|
|
5
|
+
import { RecordProcessor } from '../processor';
|
|
6
|
+
type PlaylistIdea = Selectable<DatabaseSchemaType['playlist_idea']>;
|
|
7
|
+
type IndexedPlaylistIdea = {
|
|
8
|
+
playlistIdea: PlaylistIdea;
|
|
9
|
+
masterPlaylist?: MasterPlaylist;
|
|
10
|
+
recommendedPlaylist?: RecommendedPlaylist;
|
|
11
|
+
};
|
|
12
|
+
export type PluginType = RecordProcessor<PlaylistIdeaRecord, IndexedPlaylistIdea>;
|
|
13
|
+
export declare const makePlugin: (db: Database) => PluginType;
|
|
14
|
+
export default makePlugin;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { normalizeDatetimeAlways } from '@atproto/syntax';
|
|
2
|
+
import * as lex from '../../../../lexicons/lexicons';
|
|
3
|
+
import { RecordProcessor } from '../processor';
|
|
4
|
+
const lexId = lex.ids.ComClioplaylistsAlphaFeedPlaylistIdea;
|
|
5
|
+
const insertFn = async (db, uri, cid, obj, timestamp) => {
|
|
6
|
+
const masterPlaylist = obj.masterPlaylist;
|
|
7
|
+
const recommendedPlaylist = obj.recommendedPlaylist;
|
|
8
|
+
let masterPlaylistId;
|
|
9
|
+
let recommendedPlaylistId;
|
|
10
|
+
if (masterPlaylist) {
|
|
11
|
+
const playlist = {
|
|
12
|
+
playlist_idea_uri: uri.toString(),
|
|
13
|
+
type: 'master',
|
|
14
|
+
};
|
|
15
|
+
const insertedPlaylistIdResponse = await db
|
|
16
|
+
.insertInto('playlist')
|
|
17
|
+
.values(playlist)
|
|
18
|
+
.onConflict((oc) => oc.doNothing())
|
|
19
|
+
.returning('id')
|
|
20
|
+
.executeTakeFirst();
|
|
21
|
+
let songs = masterPlaylist.songs.map((song) => {
|
|
22
|
+
return {
|
|
23
|
+
track_name: song.trackName,
|
|
24
|
+
track_mb_id: song.trackMbId,
|
|
25
|
+
album_artwork_ref: song.albumArtwork?.ref.toString(),
|
|
26
|
+
created_at: song.createdAt,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
const insertedSongIdsResponse = await db
|
|
30
|
+
.insertInto('song')
|
|
31
|
+
.values(songs)
|
|
32
|
+
.onConflict((oc) => oc.doNothing())
|
|
33
|
+
.returning('id')
|
|
34
|
+
.execute();
|
|
35
|
+
if (insertedPlaylistIdResponse?.id) {
|
|
36
|
+
const playlistItems = insertedSongIdsResponse.map((songIdResponse, index) => {
|
|
37
|
+
return {
|
|
38
|
+
playlist_id: insertedPlaylistIdResponse.id,
|
|
39
|
+
song_id: songIdResponse.id,
|
|
40
|
+
position: index + 1,
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
await db.insertInto('playlist_item').values(playlistItems).execute();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (recommendedPlaylist) {
|
|
47
|
+
const playlist = {
|
|
48
|
+
playlist_idea_uri: uri.toString(),
|
|
49
|
+
type: 'recommended',
|
|
50
|
+
};
|
|
51
|
+
await db
|
|
52
|
+
.insertInto('playlist')
|
|
53
|
+
.values(playlist)
|
|
54
|
+
.onConflict((oc) => oc.doNothing())
|
|
55
|
+
.execute();
|
|
56
|
+
}
|
|
57
|
+
const playlistIdea = {
|
|
58
|
+
uri: uri.toString(),
|
|
59
|
+
title: obj.title,
|
|
60
|
+
description: obj.description,
|
|
61
|
+
creator_did: obj.creatorDid,
|
|
62
|
+
owner_did: obj.ownerDid,
|
|
63
|
+
master_playlist_id: masterPlaylistId,
|
|
64
|
+
recommended_playlist_id: recommendedPlaylistId,
|
|
65
|
+
created_at: normalizeDatetimeAlways(obj.createdAt),
|
|
66
|
+
};
|
|
67
|
+
const [insertedPlaylistIdea] = await Promise.all([
|
|
68
|
+
db
|
|
69
|
+
.insertInto('playlist_idea')
|
|
70
|
+
.values(playlistIdea)
|
|
71
|
+
.onConflict((oc) => oc.doNothing())
|
|
72
|
+
.returningAll()
|
|
73
|
+
.executeTakeFirst(),
|
|
74
|
+
]);
|
|
75
|
+
if (!insertedPlaylistIdea) {
|
|
76
|
+
return null; // PlaylistIdea already indexed
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
playlistIdea: insertedPlaylistIdea,
|
|
80
|
+
masterPlaylist: masterPlaylist,
|
|
81
|
+
recommendedPlaylist: recommendedPlaylist,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
const findDuplicate = async () => {
|
|
85
|
+
return null;
|
|
86
|
+
};
|
|
87
|
+
const deleteFn = async (db, uri) => {
|
|
88
|
+
const uriStr = uri.toString();
|
|
89
|
+
const [deletedPlaylistIdea, deletedPlaylists] = await Promise.all([
|
|
90
|
+
db
|
|
91
|
+
.deleteFrom('playlist_idea')
|
|
92
|
+
.where('uri', '=', uriStr)
|
|
93
|
+
.returningAll()
|
|
94
|
+
.executeTakeFirst(),
|
|
95
|
+
db
|
|
96
|
+
.deleteFrom('playlist')
|
|
97
|
+
.where('playlist_idea_uri', '=', uriStr)
|
|
98
|
+
.returningAll()
|
|
99
|
+
.execute(),
|
|
100
|
+
]);
|
|
101
|
+
const deletedPlaylistIds = deletedPlaylists.map((deletedPlaylist) => {
|
|
102
|
+
return deletedPlaylist.id;
|
|
103
|
+
});
|
|
104
|
+
if (deletedPlaylists) {
|
|
105
|
+
await db
|
|
106
|
+
.deleteFrom('playlist_item')
|
|
107
|
+
.where('playlist_id', 'in', deletedPlaylistIds)
|
|
108
|
+
.execute();
|
|
109
|
+
}
|
|
110
|
+
return deletedPlaylistIdea
|
|
111
|
+
? {
|
|
112
|
+
playlistIdea: deletedPlaylistIdea,
|
|
113
|
+
masterPlaylist: undefined, // TODO: Figure out if this should be undefined
|
|
114
|
+
recommendedPlaylist: undefined, // TODO: Figure out if this should be undefined
|
|
115
|
+
}
|
|
116
|
+
: null;
|
|
117
|
+
};
|
|
118
|
+
export const makePlugin = (db) => {
|
|
119
|
+
return new RecordProcessor(db, {
|
|
120
|
+
lexId,
|
|
121
|
+
insertFn,
|
|
122
|
+
findDuplicate,
|
|
123
|
+
deleteFn,
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
export default makePlugin;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as Profile from '../../../../lexicons/types/com/clioplaylists/alpha/actor/profile';
|
|
2
|
+
import { Database } from '../../db';
|
|
3
|
+
import { DatabaseSchemaType } from '../../db/database-schema';
|
|
4
|
+
import { RecordProcessor } from '../processor';
|
|
5
|
+
type IndexedProfile = DatabaseSchemaType['profile'];
|
|
6
|
+
export type PluginType = RecordProcessor<Profile.Record, IndexedProfile>;
|
|
7
|
+
export declare const makePlugin: (db: Database) => PluginType;
|
|
8
|
+
export default makePlugin;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as lex from '../../../../lexicons/lexicons';
|
|
2
|
+
import { RecordProcessor } from '../processor';
|
|
3
|
+
const lexId = lex.ids.ComClioplaylistsAlphaActorProfile;
|
|
4
|
+
const insertFn = async (db, uri, cid, obj, timestamp) => {
|
|
5
|
+
if (uri.rkey !== 'self')
|
|
6
|
+
return null;
|
|
7
|
+
const inserted = await db
|
|
8
|
+
.insertInto('profile')
|
|
9
|
+
.values({
|
|
10
|
+
uri: uri.toString(),
|
|
11
|
+
cid: cid.toString(),
|
|
12
|
+
creator: uri.host,
|
|
13
|
+
display_name: obj.displayName,
|
|
14
|
+
description: obj.description,
|
|
15
|
+
avatar_cid: obj.avatar?.ref.toString(),
|
|
16
|
+
banner_cid: obj.banner?.ref.toString(),
|
|
17
|
+
created_at: obj.createdAt ?? new Date().toISOString(),
|
|
18
|
+
indexed_at: timestamp,
|
|
19
|
+
})
|
|
20
|
+
.onConflict((oc) => oc.doNothing())
|
|
21
|
+
.returningAll()
|
|
22
|
+
.executeTakeFirst();
|
|
23
|
+
return inserted || null;
|
|
24
|
+
};
|
|
25
|
+
const findDuplicate = async () => {
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
28
|
+
const deleteFn = async (db, uri) => {
|
|
29
|
+
const deleted = await db
|
|
30
|
+
.deleteFrom('profile')
|
|
31
|
+
.where('uri', '=', uri.toString())
|
|
32
|
+
.returningAll()
|
|
33
|
+
.executeTakeFirst();
|
|
34
|
+
return deleted || null;
|
|
35
|
+
};
|
|
36
|
+
export const makePlugin = (db) => {
|
|
37
|
+
return new RecordProcessor(db, {
|
|
38
|
+
lexId,
|
|
39
|
+
insertFn,
|
|
40
|
+
findDuplicate,
|
|
41
|
+
deleteFn,
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
export default makePlugin;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AtUri } from '@atproto/syntax';
|
|
2
|
+
import { CID } from 'multiformats/cid';
|
|
3
|
+
import { Database } from '../db';
|
|
4
|
+
import { DatabaseSchema } from '../db/database-schema';
|
|
5
|
+
type RecordProcessorParams<T, S> = {
|
|
6
|
+
lexId: string;
|
|
7
|
+
insertFn: (db: DatabaseSchema, uri: AtUri, cid: CID, obj: T, timestamp: string) => Promise<S | null>;
|
|
8
|
+
findDuplicate: (db: DatabaseSchema, uri: AtUri, obj: T) => Promise<AtUri | null>;
|
|
9
|
+
deleteFn: (db: DatabaseSchema, uri: AtUri) => Promise<S | null>;
|
|
10
|
+
};
|
|
11
|
+
export declare class RecordProcessor<T, S> {
|
|
12
|
+
private params;
|
|
13
|
+
collection: string;
|
|
14
|
+
db: DatabaseSchema;
|
|
15
|
+
constructor(appDb: Database, params: RecordProcessorParams<T, S>);
|
|
16
|
+
matchesSchema(obj: unknown): obj is T;
|
|
17
|
+
assertValidRecord(obj: unknown): asserts obj is T;
|
|
18
|
+
insertRecord(uri: AtUri, cid: CID, obj: unknown, timestamp: string): Promise<void>;
|
|
19
|
+
updateRecord(uri: AtUri, cid: CID, obj: unknown, timestamp: string): Promise<void>;
|
|
20
|
+
deleteRecord(uri: AtUri, cascading?: boolean): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export default RecordProcessor;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { stringifyLex } from '@atproto/lexicon';
|
|
2
|
+
import { lexicons } from '../../../lexicons/lexicons';
|
|
3
|
+
export class RecordProcessor {
|
|
4
|
+
params;
|
|
5
|
+
collection;
|
|
6
|
+
db;
|
|
7
|
+
constructor(appDb, params) {
|
|
8
|
+
this.params = params;
|
|
9
|
+
this.db = appDb.db;
|
|
10
|
+
this.collection = this.params.lexId;
|
|
11
|
+
}
|
|
12
|
+
matchesSchema(obj) {
|
|
13
|
+
try {
|
|
14
|
+
this.assertValidRecord(obj);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
assertValidRecord(obj) {
|
|
22
|
+
lexicons.assertValidRecord(this.params.lexId, obj);
|
|
23
|
+
}
|
|
24
|
+
async insertRecord(uri, cid, obj, timestamp) {
|
|
25
|
+
this.assertValidRecord(obj);
|
|
26
|
+
await this.db
|
|
27
|
+
.insertInto('record')
|
|
28
|
+
.values({
|
|
29
|
+
uri: uri.toString(),
|
|
30
|
+
cid: cid.toString(),
|
|
31
|
+
did: uri.host,
|
|
32
|
+
json: stringifyLex(obj),
|
|
33
|
+
indexed_at: timestamp,
|
|
34
|
+
})
|
|
35
|
+
.onConflict((oc) => oc.doNothing())
|
|
36
|
+
.execute();
|
|
37
|
+
await this.params.insertFn(this.db, uri, cid, obj, timestamp);
|
|
38
|
+
}
|
|
39
|
+
// Currently using a very simple strategy for updates: purge the existing index
|
|
40
|
+
// for the uri then replace it. The main upside is that this allows the indexer
|
|
41
|
+
// for each collection to avoid bespoke logic for in-place updates, which isn't
|
|
42
|
+
// straightforward in the general case. We still get nice control over notifications.
|
|
43
|
+
async updateRecord(uri, cid, obj, timestamp) {
|
|
44
|
+
this.assertValidRecord(obj);
|
|
45
|
+
await this.db
|
|
46
|
+
.updateTable('record')
|
|
47
|
+
.where('uri', '=', uri.toString())
|
|
48
|
+
.set({
|
|
49
|
+
cid: cid.toString(),
|
|
50
|
+
json: stringifyLex(obj),
|
|
51
|
+
indexed_at: timestamp,
|
|
52
|
+
})
|
|
53
|
+
.execute();
|
|
54
|
+
const deleted = await this.params.deleteFn(this.db, uri);
|
|
55
|
+
if (!deleted) {
|
|
56
|
+
// If a record was updated but hadn't been indexed yet, treat it like a plain insert.
|
|
57
|
+
return this.insertRecord(uri, cid, obj, timestamp);
|
|
58
|
+
}
|
|
59
|
+
const inserted = await this.params.insertFn(this.db, uri, cid, obj, timestamp);
|
|
60
|
+
if (!inserted) {
|
|
61
|
+
throw new Error('Record update failed: removed from index but could not be replaced');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async deleteRecord(uri, cascading = false) {
|
|
65
|
+
await this.db
|
|
66
|
+
.deleteFrom('record')
|
|
67
|
+
.where('uri', '=', uri.toString())
|
|
68
|
+
.execute();
|
|
69
|
+
await this.params.deleteFn(this.db, uri);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export default RecordProcessor;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IdResolver } from '@atproto/identity';
|
|
2
|
+
import { ServiceImpl } from '@connectrpc/connect';
|
|
3
|
+
import { ClioService } from '../../../rpc/clio_connect';
|
|
4
|
+
import { Database } from '../db';
|
|
5
|
+
declare const _default: (_db: Database, idResolver: IdResolver) => Partial<ServiceImpl<typeof ClioService>>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getDid, getHandle } from '@atproto/identity';
|
|
2
|
+
import { Timestamp } from '@bufbuild/protobuf';
|
|
3
|
+
import { Code, ConnectError } from '@connectrpc/connect';
|
|
4
|
+
export default (_db, idResolver) => ({
|
|
5
|
+
async getIdentityByDid(req) {
|
|
6
|
+
const doc = await idResolver.did.resolve(req.did);
|
|
7
|
+
if (!doc) {
|
|
8
|
+
throw new ConnectError('identity not found', Code.NotFound);
|
|
9
|
+
}
|
|
10
|
+
return getResultFromDoc(doc);
|
|
11
|
+
},
|
|
12
|
+
async getIdentityByHandle(req) {
|
|
13
|
+
const did = await idResolver.handle.resolve(req.handle);
|
|
14
|
+
if (!did) {
|
|
15
|
+
throw new ConnectError('identity not found', Code.NotFound);
|
|
16
|
+
}
|
|
17
|
+
const doc = await idResolver.did.resolve(did);
|
|
18
|
+
if (!doc || did !== getDid(doc)) {
|
|
19
|
+
throw new ConnectError('identity not found', Code.NotFound);
|
|
20
|
+
}
|
|
21
|
+
return getResultFromDoc(doc);
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
const getResultFromDoc = (doc) => {
|
|
25
|
+
const keys = {};
|
|
26
|
+
doc.verificationMethod?.forEach((method) => {
|
|
27
|
+
const id = method.id.split('#').at(1);
|
|
28
|
+
if (!id)
|
|
29
|
+
return;
|
|
30
|
+
keys[id] = {
|
|
31
|
+
Type: method.type,
|
|
32
|
+
PublicKeyMultibase: method.publicKeyMultibase || '',
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
const services = {};
|
|
36
|
+
doc.service?.forEach((service) => {
|
|
37
|
+
const id = service.id.split('#').at(1);
|
|
38
|
+
if (!id)
|
|
39
|
+
return;
|
|
40
|
+
if (typeof service.serviceEndpoint !== 'string')
|
|
41
|
+
return;
|
|
42
|
+
services[id] = {
|
|
43
|
+
Type: service.type,
|
|
44
|
+
URL: service.serviceEndpoint,
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
did: getDid(doc),
|
|
49
|
+
handle: getHandle(doc),
|
|
50
|
+
keys: Buffer.from(JSON.stringify(keys)),
|
|
51
|
+
services: Buffer.from(JSON.stringify(services)),
|
|
52
|
+
updated: Timestamp.fromDate(new Date()),
|
|
53
|
+
};
|
|
54
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IdResolver } from '@atproto/identity';
|
|
2
|
+
import { ConnectRouter } from '@connectrpc/connect';
|
|
3
|
+
import { Database } from '../db';
|
|
4
|
+
declare const _default: (db: Database, idResolver: IdResolver) => (router: ConnectRouter) => ConnectRouter;
|
|
5
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ClioService } from '../../../rpc/clio_connect';
|
|
2
|
+
import identity from './identity';
|
|
3
|
+
import profile from './profile';
|
|
4
|
+
import records from './records';
|
|
5
|
+
import sync from './sync';
|
|
6
|
+
export default (db, idResolver) => (router) => router.service(ClioService, {
|
|
7
|
+
...identity(db, idResolver),
|
|
8
|
+
...profile(db),
|
|
9
|
+
...records(db),
|
|
10
|
+
...sync(db),
|
|
11
|
+
async healthCheck() {
|
|
12
|
+
return {};
|
|
13
|
+
},
|
|
14
|
+
});
|