@atproto/pds 0.5.11 → 0.5.14
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/CHANGELOG.md +46 -0
- package/dist/api/app/bsky/notification/index.d.ts.map +1 -1
- package/dist/api/app/bsky/notification/index.js +2 -0
- package/dist/api/app/bsky/notification/index.js.map +1 -1
- package/dist/api/app/bsky/notification/unregisterPush.d.ts +4 -0
- package/dist/api/app/bsky/notification/unregisterPush.d.ts.map +1 -0
- package/dist/api/app/bsky/notification/unregisterPush.js +48 -0
- package/dist/api/app/bsky/notification/unregisterPush.js.map +1 -0
- package/package.json +42 -38
- package/build.templates.cjs +0 -22
- package/example.env +0 -42
- package/jest.config.cjs +0 -27
- package/src/account-manager/account-manager.ts +0 -916
- package/src/account-manager/db/index.ts +0 -21
- package/src/account-manager/db/migrations/001-init.ts +0 -115
- package/src/account-manager/db/migrations/002-account-deactivation.ts +0 -17
- package/src/account-manager/db/migrations/003-privileged-app-passwords.ts +0 -12
- package/src/account-manager/db/migrations/004-oauth.ts +0 -122
- package/src/account-manager/db/migrations/005-oauth-account-management.ts +0 -136
- package/src/account-manager/db/migrations/006-oauth-permission-sets.ts +0 -20
- package/src/account-manager/db/migrations/007-lexicon-failures-index.ts +0 -14
- package/src/account-manager/db/migrations/index.ts +0 -17
- package/src/account-manager/db/schema/account-device.ts +0 -14
- package/src/account-manager/db/schema/account.ts +0 -16
- package/src/account-manager/db/schema/actor.ts +0 -17
- package/src/account-manager/db/schema/app-password.ts +0 -13
- package/src/account-manager/db/schema/authorization-request.ts +0 -30
- package/src/account-manager/db/schema/authorized-client.ts +0 -23
- package/src/account-manager/db/schema/device.ts +0 -18
- package/src/account-manager/db/schema/email-token.ts +0 -19
- package/src/account-manager/db/schema/index.ts +0 -43
- package/src/account-manager/db/schema/invite-code.ts +0 -24
- package/src/account-manager/db/schema/lexicon.ts +0 -15
- package/src/account-manager/db/schema/refresh-token.ts +0 -11
- package/src/account-manager/db/schema/repo-root.ts +0 -12
- package/src/account-manager/db/schema/token.ts +0 -38
- package/src/account-manager/db/schema/used-refresh-token.ts +0 -13
- package/src/account-manager/helpers/account-device.ts +0 -63
- package/src/account-manager/helpers/account.ts +0 -355
- package/src/account-manager/helpers/auth.ts +0 -222
- package/src/account-manager/helpers/authorization-request.ts +0 -90
- package/src/account-manager/helpers/authorized-client.ts +0 -75
- package/src/account-manager/helpers/device.ts +0 -47
- package/src/account-manager/helpers/email-token.ts +0 -87
- package/src/account-manager/helpers/invite.ts +0 -263
- package/src/account-manager/helpers/lexicon.ts +0 -67
- package/src/account-manager/helpers/password.ts +0 -136
- package/src/account-manager/helpers/repo.ts +0 -24
- package/src/account-manager/helpers/scrypt.ts +0 -53
- package/src/account-manager/helpers/token.ts +0 -158
- package/src/account-manager/helpers/used-refresh-token.ts +0 -30
- package/src/account-manager/oauth-store.ts +0 -880
- package/src/account-manager/scope-reference-getter.ts +0 -106
- package/src/actor-store/actor-store-reader.ts +0 -45
- package/src/actor-store/actor-store-resources.ts +0 -8
- package/src/actor-store/actor-store-transactor.ts +0 -31
- package/src/actor-store/actor-store-writer.ts +0 -17
- package/src/actor-store/actor-store.ts +0 -210
- package/src/actor-store/blob/reader.ts +0 -160
- package/src/actor-store/blob/transactor.ts +0 -383
- package/src/actor-store/db/index.ts +0 -20
- package/src/actor-store/db/migrations/001-init.ts +0 -105
- package/src/actor-store/db/migrations/index.ts +0 -5
- package/src/actor-store/db/schema/account-pref.ts +0 -11
- package/src/actor-store/db/schema/backlink.ts +0 -9
- package/src/actor-store/db/schema/blob.ts +0 -14
- package/src/actor-store/db/schema/index.ts +0 -23
- package/src/actor-store/db/schema/record-blob.ts +0 -8
- package/src/actor-store/db/schema/record.ts +0 -14
- package/src/actor-store/db/schema/repo-block.ts +0 -10
- package/src/actor-store/db/schema/repo-root.ts +0 -10
- package/src/actor-store/migrate.ts +0 -39
- package/src/actor-store/preference/reader.ts +0 -48
- package/src/actor-store/preference/transactor.ts +0 -55
- package/src/actor-store/preference/util.ts +0 -39
- package/src/actor-store/record/reader.ts +0 -374
- package/src/actor-store/record/transactor.ts +0 -111
- package/src/actor-store/repo/reader.ts +0 -31
- package/src/actor-store/repo/sql-repo-reader.ts +0 -150
- package/src/actor-store/repo/sql-repo-transactor.ts +0 -105
- package/src/actor-store/repo/transactor.ts +0 -227
- package/src/api/app/bsky/actor/getPreferences.ts +0 -57
- package/src/api/app/bsky/actor/getProfile.ts +0 -41
- package/src/api/app/bsky/actor/getProfiles.ts +0 -51
- package/src/api/app/bsky/actor/index.ts +0 -13
- package/src/api/app/bsky/actor/putPreferences.ts +0 -62
- package/src/api/app/bsky/feed/getActorLikes.ts +0 -63
- package/src/api/app/bsky/feed/getAuthorFeed.ts +0 -84
- package/src/api/app/bsky/feed/getFeed.ts +0 -47
- package/src/api/app/bsky/feed/getPostThread.ts +0 -251
- package/src/api/app/bsky/feed/getTimeline.ts +0 -50
- package/src/api/app/bsky/feed/index.ts +0 -15
- package/src/api/app/bsky/index.ts +0 -11
- package/src/api/app/bsky/notification/index.ts +0 -7
- package/src/api/app/bsky/notification/registerPush.ts +0 -71
- package/src/api/app/bsky/util/resolver.ts +0 -20
- package/src/api/com/atproto/admin/deleteAccount.ts +0 -22
- package/src/api/com/atproto/admin/disableAccountInvites.ts +0 -18
- package/src/api/com/atproto/admin/disableInviteCodes.ts +0 -21
- package/src/api/com/atproto/admin/enableAccountInvites.ts +0 -18
- package/src/api/com/atproto/admin/getAccountInfo.ts +0 -32
- package/src/api/com/atproto/admin/getAccountInfos.ts +0 -34
- package/src/api/com/atproto/admin/getInviteCodes.ts +0 -126
- package/src/api/com/atproto/admin/getSubjectStatus.ts +0 -76
- package/src/api/com/atproto/admin/index.ts +0 -31
- package/src/api/com/atproto/admin/sendEmail.ts +0 -47
- package/src/api/com/atproto/admin/updateAccountEmail.ts +0 -32
- package/src/api/com/atproto/admin/updateAccountHandle.ts +0 -47
- package/src/api/com/atproto/admin/updateAccountPassword.ts +0 -34
- package/src/api/com/atproto/admin/updateSubjectStatus.ts +0 -68
- package/src/api/com/atproto/admin/util.ts +0 -66
- package/src/api/com/atproto/identity/getRecommendedDidCredentials.ts +0 -50
- package/src/api/com/atproto/identity/index.ts +0 -17
- package/src/api/com/atproto/identity/requestPlcOperationSignature.ts +0 -59
- package/src/api/com/atproto/identity/resolveHandle.ts +0 -50
- package/src/api/com/atproto/identity/signPlcOperation.ts +0 -85
- package/src/api/com/atproto/identity/submitPlcOperation.ts +0 -65
- package/src/api/com/atproto/identity/updateHandle.ts +0 -66
- package/src/api/com/atproto/index.ts +0 -19
- package/src/api/com/atproto/moderation/createReport.ts +0 -41
- package/src/api/com/atproto/moderation/index.ts +0 -7
- package/src/api/com/atproto/repo/applyWrites.ts +0 -226
- package/src/api/com/atproto/repo/createRecord.ts +0 -143
- package/src/api/com/atproto/repo/deleteRecord.ts +0 -122
- package/src/api/com/atproto/repo/describeRepo.ts +0 -43
- package/src/api/com/atproto/repo/getRecord.ts +0 -40
- package/src/api/com/atproto/repo/importRepo.ts +0 -101
- package/src/api/com/atproto/repo/index.ts +0 -25
- package/src/api/com/atproto/repo/listMissingBlobs.ts +0 -29
- package/src/api/com/atproto/repo/listRecords.ts +0 -36
- package/src/api/com/atproto/repo/putRecord.ts +0 -211
- package/src/api/com/atproto/repo/uploadBlob.ts +0 -60
- package/src/api/com/atproto/server/activateAccount.ts +0 -37
- package/src/api/com/atproto/server/checkAccountStatus.ts +0 -51
- package/src/api/com/atproto/server/confirmEmail.ts +0 -39
- package/src/api/com/atproto/server/createAccount.ts +0 -327
- package/src/api/com/atproto/server/createAppPassword.ts +0 -53
- package/src/api/com/atproto/server/createInviteCode.ts +0 -38
- package/src/api/com/atproto/server/createInviteCodes.ts +0 -42
- package/src/api/com/atproto/server/createSession.ts +0 -97
- package/src/api/com/atproto/server/deactivateAccount.ts +0 -41
- package/src/api/com/atproto/server/deleteAccount.ts +0 -85
- package/src/api/com/atproto/server/deleteSession.ts +0 -23
- package/src/api/com/atproto/server/describeServer.ts +0 -29
- package/src/api/com/atproto/server/getAccountInviteCodes.ts +0 -142
- package/src/api/com/atproto/server/getServiceAuth.ts +0 -111
- package/src/api/com/atproto/server/getSession.ts +0 -80
- package/src/api/com/atproto/server/index.ts +0 -55
- package/src/api/com/atproto/server/listAppPasswords.ts +0 -45
- package/src/api/com/atproto/server/refreshSession.ts +0 -72
- package/src/api/com/atproto/server/requestAccountDelete.ts +0 -66
- package/src/api/com/atproto/server/requestEmailConfirmation.ts +0 -68
- package/src/api/com/atproto/server/requestEmailUpdate.ts +0 -86
- package/src/api/com/atproto/server/requestPasswordReset.ts +0 -52
- package/src/api/com/atproto/server/reserveSigningKey.ts +0 -15
- package/src/api/com/atproto/server/resetPassword.ts +0 -50
- package/src/api/com/atproto/server/revokeAppPassword.ts +0 -42
- package/src/api/com/atproto/server/updateEmail.ts +0 -52
- package/src/api/com/atproto/server/util.ts +0 -136
- package/src/api/com/atproto/sync/deprecated/getCheckout.ts +0 -27
- package/src/api/com/atproto/sync/deprecated/getHead.ts +0 -33
- package/src/api/com/atproto/sync/getBlob.ts +0 -61
- package/src/api/com/atproto/sync/getBlocks.ts +0 -37
- package/src/api/com/atproto/sync/getLatestCommit.ts +0 -33
- package/src/api/com/atproto/sync/getRecord.ts +0 -49
- package/src/api/com/atproto/sync/getRepo.ts +0 -75
- package/src/api/com/atproto/sync/getRepoStatus.ts +0 -34
- package/src/api/com/atproto/sync/index.ts +0 -27
- package/src/api/com/atproto/sync/listBlobs.ts +0 -33
- package/src/api/com/atproto/sync/listRepos.ts +0 -74
- package/src/api/com/atproto/sync/subscribeRepos.ts +0 -73
- package/src/api/com/atproto/sync/util.ts +0 -37
- package/src/api/com/atproto/temp/checkSignupQueue.ts +0 -34
- package/src/api/com/atproto/temp/index.ts +0 -7
- package/src/api/index.ts +0 -10
- package/src/api/proxy.ts +0 -44
- package/src/app-view.ts +0 -24
- package/src/auth-output.ts +0 -52
- package/src/auth-routes.ts +0 -64
- package/src/auth-scope.ts +0 -40
- package/src/auth-verifier.ts +0 -668
- package/src/background.ts +0 -65
- package/src/basic-routes.ts +0 -52
- package/src/bsky-app-view.ts +0 -33
- package/src/config/config.ts +0 -553
- package/src/config/env.ts +0 -167
- package/src/config/index.ts +0 -3
- package/src/config/secrets.ts +0 -54
- package/src/context.ts +0 -523
- package/src/crawlers.ts +0 -46
- package/src/db/cast.ts +0 -52
- package/src/db/db.ts +0 -140
- package/src/db/index.ts +0 -4
- package/src/db/migrator.ts +0 -40
- package/src/db/pagination.ts +0 -132
- package/src/db/tables/moderation.ts +0 -80
- package/src/db/util.ts +0 -108
- package/src/did-cache/db/index.ts +0 -21
- package/src/did-cache/db/migrations.ts +0 -17
- package/src/did-cache/db/schema.ts +0 -9
- package/src/did-cache/index.ts +0 -131
- package/src/disk-blobstore.ts +0 -172
- package/src/error.ts +0 -19
- package/src/handle/explicit-slurs.ts +0 -22
- package/src/handle/index.ts +0 -49
- package/src/handle/reserved.ts +0 -1059
- package/src/image/image-url-builder.ts +0 -16
- package/src/index.ts +0 -189
- package/src/lexicons.ts +0 -4
- package/src/logger.ts +0 -35
- package/src/mailer/index.ts +0 -111
- package/src/mailer/moderation.ts +0 -33
- package/src/mailer/templates/confirm-email.d.ts +0 -4
- package/src/mailer/templates/confirm-email.hbs +0 -158
- package/src/mailer/templates/delete-account.d.ts +0 -4
- package/src/mailer/templates/delete-account.hbs +0 -156
- package/src/mailer/templates/plc-operation.d.ts +0 -4
- package/src/mailer/templates/plc-operation.hbs +0 -153
- package/src/mailer/templates/reset-password.d.ts +0 -4
- package/src/mailer/templates/reset-password.hbs +0 -154
- package/src/mailer/templates/update-email.d.ts +0 -4
- package/src/mailer/templates/update-email.hbs +0 -153
- package/src/mailer/templates.ts +0 -17
- package/src/pipethrough.ts +0 -716
- package/src/rate-limits.ts +0 -59
- package/src/read-after-write/index.ts +0 -3
- package/src/read-after-write/types.ts +0 -35
- package/src/read-after-write/util.ts +0 -101
- package/src/read-after-write/viewer.ts +0 -290
- package/src/redis.ts +0 -25
- package/src/repo/index.ts +0 -2
- package/src/repo/prepare.ts +0 -266
- package/src/repo/types.ts +0 -65
- package/src/scripts/README.md +0 -40
- package/src/scripts/index.ts +0 -20
- package/src/scripts/publish-identity.ts +0 -60
- package/src/scripts/rebuild-repo.ts +0 -119
- package/src/scripts/rotate-keys.ts +0 -146
- package/src/scripts/sequencer-recovery/index.ts +0 -23
- package/src/scripts/sequencer-recovery/recoverer.ts +0 -297
- package/src/scripts/sequencer-recovery/recovery-db.ts +0 -65
- package/src/scripts/sequencer-recovery/repair-repos.ts +0 -49
- package/src/scripts/sequencer-recovery/user-queues.ts +0 -44
- package/src/scripts/util.ts +0 -7
- package/src/sequencer/db/index.ts +0 -21
- package/src/sequencer/db/migrations/001-init.ts +0 -35
- package/src/sequencer/db/migrations/index.ts +0 -5
- package/src/sequencer/db/schema.ts +0 -19
- package/src/sequencer/events.ts +0 -199
- package/src/sequencer/index.ts +0 -3
- package/src/sequencer/outbox.ts +0 -123
- package/src/sequencer/sequencer.ts +0 -290
- package/src/util/compression.ts +0 -16
- package/src/util/debug.ts +0 -10
- package/src/util/http.ts +0 -31
- package/src/util/types.ts +0 -7
- package/src/well-known.ts +0 -30
- package/test.env +0 -2
- package/tests/__snapshots__/takedown-appeal.test.ts.snap +0 -43
- package/tests/_oauth_client_assets_middleware.ts +0 -23
- package/tests/_puppeteer.ts +0 -147
- package/tests/_types.d.ts +0 -16
- package/tests/_util.ts +0 -191
- package/tests/account-deactivation.test.ts +0 -204
- package/tests/account-deletion.test.ts +0 -300
- package/tests/account-manager.test.ts +0 -462
- package/tests/account-migration.test.ts +0 -221
- package/tests/account-status.test.ts +0 -206
- package/tests/account.test.ts +0 -595
- package/tests/app-passwords.test.ts +0 -262
- package/tests/auth.test.ts +0 -405
- package/tests/blob-deletes.test.ts +0 -204
- package/tests/create-post.test.ts +0 -79
- package/tests/crud.test.ts +0 -1595
- package/tests/db.test.ts +0 -170
- package/tests/email-confirmation.test.ts +0 -227
- package/tests/entryway-mock.ts +0 -323
- package/tests/entryway.test.ts +0 -145
- package/tests/file-uploads.test.ts +0 -301
- package/tests/get-service-auth.test.ts +0 -81
- package/tests/handle-validation.test.ts +0 -56
- package/tests/handles.test.ts +0 -274
- package/tests/invite-codes.test.ts +0 -367
- package/tests/invites-admin.test.ts +0 -252
- package/tests/moderation.test.ts +0 -280
- package/tests/moderator-auth.test.ts +0 -177
- package/tests/oauth.test.ts +0 -334
- package/tests/plc-operations.test.ts +0 -239
- package/tests/preferences.test.ts +0 -352
- package/tests/proxied/__snapshots__/admin.test.ts.snap +0 -516
- package/tests/proxied/__snapshots__/feedgen.test.ts.snap +0 -215
- package/tests/proxied/__snapshots__/views.test.ts.snap +0 -4456
- package/tests/proxied/admin.test.ts +0 -340
- package/tests/proxied/feedgen.test.ts +0 -66
- package/tests/proxied/notif.test.ts +0 -85
- package/tests/proxied/procedures.test.ts +0 -175
- package/tests/proxied/proxy-catchall.test.ts +0 -256
- package/tests/proxied/proxy-header.test.ts +0 -239
- package/tests/proxied/proxy-oauth-aud.test.ts +0 -182
- package/tests/proxied/read-after-write.test.ts +0 -382
- package/tests/proxied/views.test.ts +0 -608
- package/tests/races.test.ts +0 -89
- package/tests/rate-limits.test.ts +0 -70
- package/tests/recovery.test.ts +0 -180
- package/tests/seeds/basic.ts +0 -165
- package/tests/seeds/follows.ts +0 -57
- package/tests/seeds/likes.ts +0 -14
- package/tests/seeds/reposts.ts +0 -18
- package/tests/seeds/thread.ts +0 -40
- package/tests/seeds/users-bulk.ts +0 -246
- package/tests/seeds/users.ts +0 -67
- package/tests/sequencer.test.ts +0 -251
- package/tests/server.test.ts +0 -151
- package/tests/sync/invertible-ops.test.ts +0 -99
- package/tests/sync/list.test.ts +0 -43
- package/tests/sync/subscribe-repos.test.ts +0 -672
- package/tests/sync/sync.test.ts +0 -316
- package/tests/takedown-appeal.test.ts +0 -166
- package/tsconfig.build.json +0 -9
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
package/src/db/db.ts
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import SqliteDB from 'better-sqlite3'
|
|
3
|
-
import {
|
|
4
|
-
Kysely,
|
|
5
|
-
KyselyPlugin,
|
|
6
|
-
PluginTransformQueryArgs,
|
|
7
|
-
PluginTransformResultArgs,
|
|
8
|
-
QueryResult,
|
|
9
|
-
RootOperationNode,
|
|
10
|
-
SqliteDialect,
|
|
11
|
-
UnknownRow,
|
|
12
|
-
sql,
|
|
13
|
-
} from 'kysely'
|
|
14
|
-
import { dbLogger } from '../logger.js'
|
|
15
|
-
import { retrySqlite } from './util.js'
|
|
16
|
-
|
|
17
|
-
const DEFAULT_PRAGMAS = {
|
|
18
|
-
// strict: 'ON', // @TODO strictness should live on table defs instead
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class Database<Schema> {
|
|
22
|
-
destroyed = false
|
|
23
|
-
commitHooks: CommitHook[] = []
|
|
24
|
-
|
|
25
|
-
constructor(public db: Kysely<Schema>) {}
|
|
26
|
-
|
|
27
|
-
static sqlite<T>(
|
|
28
|
-
location: string,
|
|
29
|
-
opts?: { pragmas?: Record<string, string> },
|
|
30
|
-
): Database<T> {
|
|
31
|
-
const sqliteDb = new SqliteDB(location, {
|
|
32
|
-
timeout: 0, // handled by application
|
|
33
|
-
})
|
|
34
|
-
const pragmas = {
|
|
35
|
-
...DEFAULT_PRAGMAS,
|
|
36
|
-
...(opts?.pragmas ?? {}),
|
|
37
|
-
}
|
|
38
|
-
for (const pragma of Object.keys(pragmas)) {
|
|
39
|
-
sqliteDb.pragma(`${pragma} = ${pragmas[pragma]}`)
|
|
40
|
-
}
|
|
41
|
-
const db = new Kysely<T>({
|
|
42
|
-
dialect: new SqliteDialect({
|
|
43
|
-
database: sqliteDb,
|
|
44
|
-
}),
|
|
45
|
-
})
|
|
46
|
-
return new Database(db)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async ensureWal() {
|
|
50
|
-
await sql`PRAGMA journal_mode = WAL`.execute(this.db)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async transactionNoRetry<T>(
|
|
54
|
-
fn: (db: Database<Schema>) => T | PromiseLike<T>,
|
|
55
|
-
): Promise<T> {
|
|
56
|
-
this.assertNotTransaction()
|
|
57
|
-
const leakyTxPlugin = new LeakyTxPlugin()
|
|
58
|
-
const { hooks, txRes } = await this.db
|
|
59
|
-
.withPlugin(leakyTxPlugin)
|
|
60
|
-
.transaction()
|
|
61
|
-
.execute(async (txn) => {
|
|
62
|
-
const dbTxn = new Database(txn)
|
|
63
|
-
try {
|
|
64
|
-
const txRes = await fn(dbTxn)
|
|
65
|
-
leakyTxPlugin.endTx()
|
|
66
|
-
const hooks = dbTxn.commitHooks
|
|
67
|
-
return { hooks, txRes }
|
|
68
|
-
} catch (err) {
|
|
69
|
-
leakyTxPlugin.endTx()
|
|
70
|
-
// ensure that all in-flight queries are flushed & the connection is open
|
|
71
|
-
await txn.getExecutor().provideConnection(async () => {})
|
|
72
|
-
throw err
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
hooks.map((hook) => hook())
|
|
76
|
-
return txRes
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async transaction<T>(
|
|
80
|
-
fn: (db: Database<Schema>) => T | PromiseLike<T>,
|
|
81
|
-
): Promise<T> {
|
|
82
|
-
return retrySqlite(() => this.transactionNoRetry(fn))
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async executeWithRetry<T>(query: { execute: () => Promise<T> }) {
|
|
86
|
-
if (this.isTransaction) {
|
|
87
|
-
// transaction() ensures retry on entire transaction, no need to retry individual statements.
|
|
88
|
-
return query.execute()
|
|
89
|
-
}
|
|
90
|
-
return retrySqlite(() => query.execute())
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
onCommit(fn: () => void) {
|
|
94
|
-
this.assertTransaction()
|
|
95
|
-
this.commitHooks.push(fn)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
get isTransaction() {
|
|
99
|
-
return this.db.isTransaction
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
assertTransaction() {
|
|
103
|
-
assert(this.isTransaction, 'Transaction required')
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
assertNotTransaction() {
|
|
107
|
-
assert(!this.isTransaction, 'Cannot be in a transaction')
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
close(): void {
|
|
111
|
-
if (this.destroyed) return
|
|
112
|
-
this.db
|
|
113
|
-
.destroy()
|
|
114
|
-
.then(() => (this.destroyed = true))
|
|
115
|
-
.catch((err) => dbLogger.error({ err }, 'error closing db'))
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
type CommitHook = () => void
|
|
120
|
-
|
|
121
|
-
class LeakyTxPlugin implements KyselyPlugin {
|
|
122
|
-
private txOver = false
|
|
123
|
-
|
|
124
|
-
endTx() {
|
|
125
|
-
this.txOver = true
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
transformQuery(args: PluginTransformQueryArgs): RootOperationNode {
|
|
129
|
-
if (this.txOver) {
|
|
130
|
-
throw new Error('tx already failed')
|
|
131
|
-
}
|
|
132
|
-
return args.node
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async transformResult(
|
|
136
|
-
args: PluginTransformResultArgs,
|
|
137
|
-
): Promise<QueryResult<UnknownRow>> {
|
|
138
|
-
return args.result
|
|
139
|
-
}
|
|
140
|
-
}
|
package/src/db/index.ts
DELETED
package/src/db/migrator.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { Kysely } from 'kysely'
|
|
2
|
-
import { Migration, Migrator as KyselyMigrator } from 'kysely/migration'
|
|
3
|
-
|
|
4
|
-
export class Migrator<T> extends KyselyMigrator {
|
|
5
|
-
constructor(
|
|
6
|
-
public db: Kysely<T>,
|
|
7
|
-
migrations: Record<string, Migration>,
|
|
8
|
-
) {
|
|
9
|
-
super({
|
|
10
|
-
db,
|
|
11
|
-
provider: {
|
|
12
|
-
async getMigrations() {
|
|
13
|
-
return migrations
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async migrateToOrThrow(migration: string) {
|
|
20
|
-
const { error, results } = await this.migrateTo(migration)
|
|
21
|
-
if (error) {
|
|
22
|
-
throw error
|
|
23
|
-
}
|
|
24
|
-
if (!results) {
|
|
25
|
-
throw new Error('An unknown failure occurred while migrating')
|
|
26
|
-
}
|
|
27
|
-
return results
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async migrateToLatestOrThrow() {
|
|
31
|
-
const { error, results } = await this.migrateToLatest()
|
|
32
|
-
if (error) {
|
|
33
|
-
throw error
|
|
34
|
-
}
|
|
35
|
-
if (!results) {
|
|
36
|
-
throw new Error('An unknown failure occurred while migrating')
|
|
37
|
-
}
|
|
38
|
-
return results
|
|
39
|
-
}
|
|
40
|
-
}
|
package/src/db/pagination.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { SqlBool, sql } from 'kysely'
|
|
2
|
-
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
3
|
-
import { AnyQb, DbRef } from './util.js'
|
|
4
|
-
|
|
5
|
-
export type Cursor = { primary: string; secondary: string }
|
|
6
|
-
export type LabeledResult = {
|
|
7
|
-
primary: string | number
|
|
8
|
-
secondary: string | number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* The GenericKeyset is an abstract class that sets-up the interface and partial implementation
|
|
13
|
-
* of a keyset-paginated cursor with two parts. There are three types involved:
|
|
14
|
-
* - Result: a raw result (i.e. a row from the db) containing data that will make-up a cursor.
|
|
15
|
-
* - E.g. { createdAt: '2022-01-01T12:00:00Z', cid: 'bafyx' }
|
|
16
|
-
* - LabeledResult: a Result processed such that the "primary" and "secondary" parts of the cursor are labeled.
|
|
17
|
-
* - E.g. { primary: '2022-01-01T12:00:00Z', secondary: 'bafyx' }
|
|
18
|
-
* - Cursor: the two string parts that make-up the packed/string cursor.
|
|
19
|
-
* - E.g. packed cursor '1641038400000::bafyx' in parts { primary: '1641038400000', secondary: 'bafyx' }
|
|
20
|
-
*
|
|
21
|
-
* These types relate as such. Implementers define the relations marked with a *:
|
|
22
|
-
* Result -*-> LabeledResult <-*-> Cursor <--> packed/string cursor
|
|
23
|
-
* ↳ SQL Condition
|
|
24
|
-
*/
|
|
25
|
-
export abstract class GenericKeyset<R, LR extends LabeledResult> {
|
|
26
|
-
constructor(
|
|
27
|
-
public primary: DbRef,
|
|
28
|
-
public secondary: DbRef,
|
|
29
|
-
) {}
|
|
30
|
-
abstract labelResult(result: R): LR
|
|
31
|
-
abstract labeledResultToCursor(labeled: LR): Cursor
|
|
32
|
-
abstract cursorToLabeledResult(cursor: Cursor): LR
|
|
33
|
-
packFromResult(results: R | R[]): string | undefined {
|
|
34
|
-
const result = Array.isArray(results) ? results.at(-1) : results
|
|
35
|
-
if (!result) return
|
|
36
|
-
return this.pack(this.labelResult(result))
|
|
37
|
-
}
|
|
38
|
-
pack(labeled?: LR): string | undefined {
|
|
39
|
-
if (!labeled) return
|
|
40
|
-
const cursor = this.labeledResultToCursor(labeled)
|
|
41
|
-
return this.packCursor(cursor)
|
|
42
|
-
}
|
|
43
|
-
unpack(cursorStr?: string): LR | undefined {
|
|
44
|
-
const cursor = this.unpackCursor(cursorStr)
|
|
45
|
-
if (!cursor) return
|
|
46
|
-
return this.cursorToLabeledResult(cursor)
|
|
47
|
-
}
|
|
48
|
-
packCursor(cursor?: Cursor): string | undefined {
|
|
49
|
-
if (!cursor) return
|
|
50
|
-
return `${cursor.primary}::${cursor.secondary}`
|
|
51
|
-
}
|
|
52
|
-
unpackCursor(cursorStr?: string): Cursor | undefined {
|
|
53
|
-
if (!cursorStr) return
|
|
54
|
-
const result = cursorStr.split('::')
|
|
55
|
-
const [primary, secondary, ...others] = result
|
|
56
|
-
if (!primary || !secondary || others.length > 0) {
|
|
57
|
-
throw new InvalidRequestError('Malformed cursor')
|
|
58
|
-
}
|
|
59
|
-
return {
|
|
60
|
-
primary,
|
|
61
|
-
secondary,
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
getSql(labeled?: LR, direction?: 'asc' | 'desc', tryIndex?: boolean) {
|
|
65
|
-
if (labeled === undefined) return
|
|
66
|
-
if (tryIndex) {
|
|
67
|
-
// The tryIndex param will likely disappear and become the default implementation: here for now for gradual rollout query-by-query.
|
|
68
|
-
if (direction === 'asc') {
|
|
69
|
-
return sql<SqlBool>`((${this.primary}, ${this.secondary}) > (${labeled.primary}, ${labeled.secondary}))`
|
|
70
|
-
} else {
|
|
71
|
-
return sql<SqlBool>`((${this.primary}, ${this.secondary}) < (${labeled.primary}, ${labeled.secondary}))`
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
// @NOTE this implementation can struggle to use an index on (primary, secondary) for pagination due to the "or" usage.
|
|
75
|
-
if (direction === 'asc') {
|
|
76
|
-
return sql<SqlBool>`((${this.primary} > ${labeled.primary}) or (${this.primary} = ${labeled.primary} and ${this.secondary} > ${labeled.secondary}))`
|
|
77
|
-
} else {
|
|
78
|
-
return sql<SqlBool>`((${this.primary} < ${labeled.primary}) or (${this.primary} = ${labeled.primary} and ${this.secondary} < ${labeled.secondary}))`
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
type CreatedAtCidResult = { createdAt: string; cid: string }
|
|
85
|
-
type TimeCidLabeledResult = Cursor
|
|
86
|
-
|
|
87
|
-
export class TimeCidKeyset<
|
|
88
|
-
TimeCidResult = CreatedAtCidResult,
|
|
89
|
-
> extends GenericKeyset<TimeCidResult, TimeCidLabeledResult> {
|
|
90
|
-
labelResult(result: TimeCidResult): TimeCidLabeledResult
|
|
91
|
-
labelResult<TimeCidResult extends CreatedAtCidResult>(result: TimeCidResult) {
|
|
92
|
-
return { primary: result.createdAt, secondary: result.cid }
|
|
93
|
-
}
|
|
94
|
-
labeledResultToCursor(labeled: TimeCidLabeledResult) {
|
|
95
|
-
return {
|
|
96
|
-
primary: new Date(labeled.primary).getTime().toString(),
|
|
97
|
-
secondary: labeled.secondary,
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
cursorToLabeledResult(cursor: Cursor) {
|
|
101
|
-
const primaryDate = new Date(parseInt(cursor.primary, 10))
|
|
102
|
-
if (isNaN(primaryDate.getTime())) {
|
|
103
|
-
throw new InvalidRequestError('Malformed cursor')
|
|
104
|
-
}
|
|
105
|
-
return {
|
|
106
|
-
primary: primaryDate.toISOString(),
|
|
107
|
-
secondary: cursor.secondary,
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export const paginate = <
|
|
113
|
-
QB extends AnyQb,
|
|
114
|
-
K extends GenericKeyset<unknown, any>,
|
|
115
|
-
>(
|
|
116
|
-
qb: QB,
|
|
117
|
-
opts: {
|
|
118
|
-
limit?: number
|
|
119
|
-
cursor?: string
|
|
120
|
-
direction?: 'asc' | 'desc'
|
|
121
|
-
keyset: K
|
|
122
|
-
tryIndex?: boolean
|
|
123
|
-
},
|
|
124
|
-
): QB => {
|
|
125
|
-
const { limit, cursor, keyset, direction = 'desc', tryIndex } = opts
|
|
126
|
-
const keysetSql = keyset.getSql(keyset.unpack(cursor), direction, tryIndex)
|
|
127
|
-
return qb
|
|
128
|
-
.$if(!!limit, (q) => q.limit(limit as number))
|
|
129
|
-
.orderBy(keyset.primary, direction)
|
|
130
|
-
.orderBy(keyset.secondary, direction)
|
|
131
|
-
.$if(!!keysetSql, (qb) => (keysetSql ? qb.where(keysetSql) : qb)) as QB
|
|
132
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { Generated } from 'kysely'
|
|
2
|
-
import { com } from '../../lexicons/index.js'
|
|
3
|
-
|
|
4
|
-
export const actionTableName = 'moderation_action'
|
|
5
|
-
export const actionSubjectBlobTableName = 'moderation_action_subject_blob'
|
|
6
|
-
export const reportTableName = 'moderation_report'
|
|
7
|
-
export const reportResolutionTableName = 'moderation_report_resolution'
|
|
8
|
-
|
|
9
|
-
export interface ModerationAction {
|
|
10
|
-
id: Generated<number>
|
|
11
|
-
action:
|
|
12
|
-
| 'tools.ozone.moderation.defs#modEventTakedown'
|
|
13
|
-
| 'tools.ozone.moderation.defs#modEventAcknowledge'
|
|
14
|
-
| 'tools.ozone.moderation.defs#modEventEscalate'
|
|
15
|
-
| 'tools.ozone.moderation.defs#modEventComment'
|
|
16
|
-
| 'tools.ozone.moderation.defs#modEventLabel'
|
|
17
|
-
| 'tools.ozone.moderation.defs#modEventReport'
|
|
18
|
-
| 'tools.ozone.moderation.defs#modEventMute'
|
|
19
|
-
| 'tools.ozone.moderation.defs#modEventUnmute'
|
|
20
|
-
| 'tools.ozone.moderation.defs#modEventMuteReporter'
|
|
21
|
-
| 'tools.ozone.moderation.defs#modEventUnmuteReporter'
|
|
22
|
-
| 'tools.ozone.moderation.defs#modEventReverseTakedown'
|
|
23
|
-
| 'tools.ozone.moderation.defs#modEventEmail'
|
|
24
|
-
| 'tools.ozone.moderation.defs#modEventResolveAppeal'
|
|
25
|
-
| 'tools.ozone.moderation.defs#modEventDivert'
|
|
26
|
-
| 'tools.ozone.moderation.defs#accountEvent'
|
|
27
|
-
| 'tools.ozone.moderation.defs#identityEvent'
|
|
28
|
-
| 'tools.ozone.moderation.defs#recordEvent'
|
|
29
|
-
| 'tools.ozone.moderation.defs#modEventPriorityScore'
|
|
30
|
-
subjectType: 'com.atproto.admin.defs#repoRef' | 'com.atproto.repo.strongRef'
|
|
31
|
-
subjectDid: string
|
|
32
|
-
subjectUri: string | null
|
|
33
|
-
subjectCid: string | null
|
|
34
|
-
createLabelVals: string | null
|
|
35
|
-
negateLabelVals: string | null
|
|
36
|
-
comment: string | null
|
|
37
|
-
createdAt: string
|
|
38
|
-
createdBy: string
|
|
39
|
-
durationInHours: number | null
|
|
40
|
-
expiresAt: string | null
|
|
41
|
-
meta: Record<string, string | boolean> | null
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface ModerationActionSubjectBlob {
|
|
45
|
-
actionId: number
|
|
46
|
-
cid: string
|
|
47
|
-
recordUri: string
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface ModerationReport {
|
|
51
|
-
id: Generated<number>
|
|
52
|
-
subjectType: 'com.atproto.admin.defs#repoRef' | 'com.atproto.repo.strongRef'
|
|
53
|
-
subjectDid: string
|
|
54
|
-
subjectUri: string | null
|
|
55
|
-
subjectCid: string | null
|
|
56
|
-
reasonType:
|
|
57
|
-
| com.atproto.moderation.defs.ReasonSpam
|
|
58
|
-
| com.atproto.moderation.defs.ReasonOther
|
|
59
|
-
| com.atproto.moderation.defs.ReasonMisleading
|
|
60
|
-
| com.atproto.moderation.defs.ReasonRude
|
|
61
|
-
| com.atproto.moderation.defs.ReasonSexual
|
|
62
|
-
| com.atproto.moderation.defs.ReasonViolation
|
|
63
|
-
reason: string | null
|
|
64
|
-
reportedByDid: string
|
|
65
|
-
createdAt: string
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface ModerationReportResolution {
|
|
69
|
-
reportId: number
|
|
70
|
-
actionId: number
|
|
71
|
-
createdAt: string
|
|
72
|
-
createdBy: string
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export type PartialDB = {
|
|
76
|
-
[actionTableName]: ModerationAction
|
|
77
|
-
[actionSubjectBlobTableName]: ModerationActionSubjectBlob
|
|
78
|
-
[reportTableName]: ModerationReport
|
|
79
|
-
[reportResolutionTableName]: ModerationReportResolution
|
|
80
|
-
}
|
package/src/db/util.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DummyDriver,
|
|
3
|
-
DynamicModule,
|
|
4
|
-
Kysely,
|
|
5
|
-
RawBuilder,
|
|
6
|
-
ReferenceExpression,
|
|
7
|
-
SelectQueryBuilder,
|
|
8
|
-
SqlBool,
|
|
9
|
-
SqliteAdapter,
|
|
10
|
-
SqliteIntrospector,
|
|
11
|
-
SqliteQueryCompiler,
|
|
12
|
-
sql,
|
|
13
|
-
} from 'kysely'
|
|
14
|
-
import { retry } from '@atproto/common'
|
|
15
|
-
|
|
16
|
-
// Applies to repo_root or record table
|
|
17
|
-
export const notSoftDeletedClause = (alias: DbRef) => {
|
|
18
|
-
return sql<SqlBool>`${alias}."takedownRef" is null`
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const softDeleted = (repoOrRecord: { takedownRef: string | null }) => {
|
|
22
|
-
return repoOrRecord.takedownRef !== null
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const countAll = sql<number>`count(*)`
|
|
26
|
-
export const countDistinct = (ref: DbRef) => sql<number>`count(distinct ${ref})`
|
|
27
|
-
|
|
28
|
-
// For use with doUpdateSet()
|
|
29
|
-
export const excluded = <T, S>(db: Kysely<S>, col) => {
|
|
30
|
-
return sql<T>`${db.dynamic.ref(`excluded.${col}`)}`
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Can be useful for large where-in clauses, to get the db to use a hash lookup on the list
|
|
34
|
-
export const valuesList = (vals: unknown[]) => {
|
|
35
|
-
return sql`(values (${sql.join(vals, sql`), (`)}))`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const dummyDialect = {
|
|
39
|
-
createAdapter() {
|
|
40
|
-
return new SqliteAdapter()
|
|
41
|
-
},
|
|
42
|
-
createDriver() {
|
|
43
|
-
return new DummyDriver()
|
|
44
|
-
},
|
|
45
|
-
createIntrospector(db) {
|
|
46
|
-
return new SqliteIntrospector(db)
|
|
47
|
-
},
|
|
48
|
-
createQueryCompiler() {
|
|
49
|
-
return new SqliteQueryCompiler()
|
|
50
|
-
},
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const retrySqlite = <T>(fn: () => Promise<T>): Promise<T> => {
|
|
54
|
-
return retry(fn, {
|
|
55
|
-
retryable: retryableSqlite,
|
|
56
|
-
getWaitMs: getWaitMsSqlite,
|
|
57
|
-
maxRetries: 60, // a safety measure: getWaitMsSqlite() times out before this after 5000ms of waiting.
|
|
58
|
-
})
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const retryableSqlite = (err: unknown) => {
|
|
62
|
-
return typeof err?.['code'] === 'string' && RETRY_ERRORS.has(err['code'])
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// based on sqlite's backoff strategy https://github.com/sqlite/sqlite/blob/91c8e65dd4bf17d21fbf8f7073565fe1a71c8948/src/main.c#L1704-L1713
|
|
66
|
-
const getWaitMsSqlite = (n: number, timeout = 5000) => {
|
|
67
|
-
if (n < 0) return null
|
|
68
|
-
let delay: number
|
|
69
|
-
let prior: number
|
|
70
|
-
if (n < DELAYS.length) {
|
|
71
|
-
delay = DELAYS[n]
|
|
72
|
-
prior = TOTALS[n]
|
|
73
|
-
} else {
|
|
74
|
-
delay = last(DELAYS)
|
|
75
|
-
prior = last(TOTALS) + delay * (n - (DELAYS.length - 1))
|
|
76
|
-
}
|
|
77
|
-
if (prior + delay > timeout) {
|
|
78
|
-
delay = timeout - prior
|
|
79
|
-
if (delay <= 0) return null
|
|
80
|
-
}
|
|
81
|
-
return delay
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const last = <T>(arr: T[]) => arr[arr.length - 1]
|
|
85
|
-
const DELAYS = [1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100]
|
|
86
|
-
const TOTALS = [0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228]
|
|
87
|
-
const RETRY_ERRORS = new Set([
|
|
88
|
-
'SQLITE_BUSY',
|
|
89
|
-
'SQLITE_BUSY_SNAPSHOT',
|
|
90
|
-
'SQLITE_BUSY_RECOVERY',
|
|
91
|
-
'SQLITE_BUSY_TIMEOUT',
|
|
92
|
-
])
|
|
93
|
-
|
|
94
|
-
export type Ref = ReferenceExpression<any, any>
|
|
95
|
-
|
|
96
|
-
export type DbRef =
|
|
97
|
-
| RawBuilder<unknown>
|
|
98
|
-
| ReturnType<DynamicModule<unknown>['ref']>
|
|
99
|
-
|
|
100
|
-
export type AnyQb = SelectQueryBuilder<any, any, any>
|
|
101
|
-
|
|
102
|
-
export const isErrUniqueViolation = (err: unknown) => {
|
|
103
|
-
const code = err?.['code']
|
|
104
|
-
return (
|
|
105
|
-
code === '23505' || // postgres, see https://www.postgresql.org/docs/current/errcodes-appendix.html
|
|
106
|
-
code === 'SQLITE_CONSTRAINT_UNIQUE' // sqlite, see https://www.sqlite.org/rescode.html#constraint_unique
|
|
107
|
-
)
|
|
108
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Database, Migrator } from '../../db/index.js'
|
|
2
|
-
import migrations from './migrations.js'
|
|
3
|
-
import { DidCacheSchema } from './schema.js'
|
|
4
|
-
|
|
5
|
-
export * from './schema.js'
|
|
6
|
-
|
|
7
|
-
export type DidCacheDb = Database<DidCacheSchema>
|
|
8
|
-
|
|
9
|
-
export const getDb = (
|
|
10
|
-
location: string,
|
|
11
|
-
disableWalAutoCheckpoint = false,
|
|
12
|
-
): DidCacheDb => {
|
|
13
|
-
const pragmas: Record<string, string> = disableWalAutoCheckpoint
|
|
14
|
-
? { wal_autocheckpoint: '0', synchronous: 'NORMAL' }
|
|
15
|
-
: { synchronous: 'NORMAL' }
|
|
16
|
-
return Database.sqlite(location, { pragmas })
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const getMigrator = (db: DidCacheDb) => {
|
|
20
|
-
return new Migrator(db.db, migrations)
|
|
21
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Kysely } from 'kysely'
|
|
2
|
-
|
|
3
|
-
export default {
|
|
4
|
-
'001': {
|
|
5
|
-
up: async (db: Kysely<unknown>) => {
|
|
6
|
-
await db.schema
|
|
7
|
-
.createTable('did_doc')
|
|
8
|
-
.addColumn('did', 'varchar', (col) => col.primaryKey())
|
|
9
|
-
.addColumn('doc', 'text', (col) => col.notNull())
|
|
10
|
-
.addColumn('updatedAt', 'bigint', (col) => col.notNull())
|
|
11
|
-
.execute()
|
|
12
|
-
},
|
|
13
|
-
down: async (db: Kysely<unknown>) => {
|
|
14
|
-
await db.schema.dropTable('did_doc').execute()
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
}
|
package/src/did-cache/index.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import PQueue from 'p-queue'
|
|
2
|
-
import { CacheResult, DidCache, DidDocument } from '@atproto/identity'
|
|
3
|
-
import { excluded } from '../db/util.js'
|
|
4
|
-
import { didCacheLogger } from '../logger.js'
|
|
5
|
-
import { DidCacheDb, getDb, getMigrator } from './db/index.js'
|
|
6
|
-
|
|
7
|
-
export class DidSqliteCache implements DidCache {
|
|
8
|
-
db: DidCacheDb
|
|
9
|
-
public pQueue: PQueue | null //null during teardown
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
dbLocation: string,
|
|
13
|
-
public staleTTL: number,
|
|
14
|
-
public maxTTL: number,
|
|
15
|
-
disableWalAutoCheckpoint = false,
|
|
16
|
-
) {
|
|
17
|
-
this.db = getDb(dbLocation, disableWalAutoCheckpoint)
|
|
18
|
-
this.pQueue = new PQueue()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async cacheDid(
|
|
22
|
-
did: string,
|
|
23
|
-
doc: DidDocument,
|
|
24
|
-
prevResult?: CacheResult,
|
|
25
|
-
): Promise<void> {
|
|
26
|
-
try {
|
|
27
|
-
if (prevResult) {
|
|
28
|
-
await this.db.executeWithRetry(
|
|
29
|
-
this.db.db
|
|
30
|
-
.updateTable('did_doc')
|
|
31
|
-
.set({ doc: JSON.stringify(doc), updatedAt: Date.now() })
|
|
32
|
-
.where('did', '=', did)
|
|
33
|
-
.where('updatedAt', '=', prevResult.updatedAt),
|
|
34
|
-
)
|
|
35
|
-
} else {
|
|
36
|
-
await this.db.executeWithRetry(
|
|
37
|
-
this.db.db
|
|
38
|
-
.insertInto('did_doc')
|
|
39
|
-
.values({ did, doc: JSON.stringify(doc), updatedAt: Date.now() })
|
|
40
|
-
.onConflict((oc) =>
|
|
41
|
-
oc.column('did').doUpdateSet({
|
|
42
|
-
doc: excluded(this.db.db, 'doc'),
|
|
43
|
-
updatedAt: excluded(this.db.db, 'updatedAt'),
|
|
44
|
-
}),
|
|
45
|
-
),
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
} catch (err) {
|
|
49
|
-
didCacheLogger.error({ did, doc, err }, 'failed to cache did')
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async refreshCache(
|
|
54
|
-
did: string,
|
|
55
|
-
getDoc: () => Promise<DidDocument | null>,
|
|
56
|
-
prevResult?: CacheResult,
|
|
57
|
-
): Promise<void> {
|
|
58
|
-
this.pQueue?.add(async () => {
|
|
59
|
-
try {
|
|
60
|
-
const doc = await getDoc()
|
|
61
|
-
if (doc) {
|
|
62
|
-
await this.cacheDid(did, doc, prevResult)
|
|
63
|
-
} else {
|
|
64
|
-
await this.clearEntry(did)
|
|
65
|
-
}
|
|
66
|
-
} catch (err) {
|
|
67
|
-
didCacheLogger.error({ did, err }, 'refreshing did cache failed')
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async checkCache(did: string): Promise<CacheResult | null> {
|
|
73
|
-
try {
|
|
74
|
-
return await this.checkCacheInternal(did)
|
|
75
|
-
} catch (err) {
|
|
76
|
-
didCacheLogger.error({ did, err }, 'failed to check did cache')
|
|
77
|
-
return null
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async checkCacheInternal(did: string): Promise<CacheResult | null> {
|
|
82
|
-
const res = await this.db.db
|
|
83
|
-
.selectFrom('did_doc')
|
|
84
|
-
.where('did', '=', did)
|
|
85
|
-
.selectAll()
|
|
86
|
-
.executeTakeFirst()
|
|
87
|
-
if (!res) return null
|
|
88
|
-
const now = Date.now()
|
|
89
|
-
const updatedAt = new Date(res.updatedAt).getTime()
|
|
90
|
-
const expired = now > updatedAt + this.maxTTL
|
|
91
|
-
const stale = now > updatedAt + this.staleTTL
|
|
92
|
-
return {
|
|
93
|
-
doc: JSON.parse(res.doc) as DidDocument,
|
|
94
|
-
updatedAt,
|
|
95
|
-
did,
|
|
96
|
-
stale,
|
|
97
|
-
expired,
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async clearEntry(did: string): Promise<void> {
|
|
102
|
-
try {
|
|
103
|
-
await this.db.executeWithRetry(
|
|
104
|
-
this.db.db.deleteFrom('did_doc').where('did', '=', did),
|
|
105
|
-
)
|
|
106
|
-
} catch (err) {
|
|
107
|
-
didCacheLogger.error({ did, err }, 'clearing did cache entry failed')
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async clear(): Promise<void> {
|
|
112
|
-
await this.db.db.deleteFrom('did_doc').execute()
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async processAll() {
|
|
116
|
-
await this.pQueue?.onIdle()
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async migrateOrThrow() {
|
|
120
|
-
await this.db.ensureWal()
|
|
121
|
-
await getMigrator(this.db).migrateToLatestOrThrow()
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async destroy() {
|
|
125
|
-
const pQueue = this.pQueue
|
|
126
|
-
this.pQueue = null
|
|
127
|
-
pQueue?.pause()
|
|
128
|
-
pQueue?.clear()
|
|
129
|
-
await pQueue?.onIdle()
|
|
130
|
-
}
|
|
131
|
-
}
|