@clioplaylists/clio 0.1.0
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.js +37 -0
- package/dist/api/com/clioplaylists/alpha/feed/getSongs.js +37 -0
- package/dist/api/health.js +32 -0
- package/dist/api/index.js +43 -0
- package/dist/api/util.js +17 -0
- package/dist/auth-verifier.js +473 -0
- package/dist/client.js +40 -0
- package/dist/config.js +65 -0
- package/dist/context.js +19 -0
- package/dist/dataplane/bsync/index.js +150 -0
- package/dist/dataplane/client.js +165 -0
- package/dist/dataplane/index.js +18 -0
- package/dist/dataplane/server/background.js +51 -0
- package/dist/dataplane/server/db/database-schema.js +2 -0
- package/dist/dataplane/server/db/db.js +228 -0
- package/dist/dataplane/server/db/index.js +17 -0
- package/dist/dataplane/server/db/migrations/20230309T045948368Z-init.js +117 -0
- package/dist/dataplane/server/db/migrations/20230420T211446071Z-did-cache.js +15 -0
- package/dist/dataplane/server/db/migrations/index.js +41 -0
- package/dist/dataplane/server/db/migrations/provider.js +31 -0
- package/dist/dataplane/server/db/pagination.js +144 -0
- package/dist/dataplane/server/db/tables/actor-sync.js +4 -0
- package/dist/dataplane/server/db/tables/actor.js +4 -0
- package/dist/dataplane/server/db/tables/artist-list-item.js +4 -0
- package/dist/dataplane/server/db/tables/artist.js +4 -0
- package/dist/dataplane/server/db/tables/playlist-idea.js +4 -0
- package/dist/dataplane/server/db/tables/playlist-item.js +4 -0
- package/dist/dataplane/server/db/tables/playlist.js +4 -0
- package/dist/dataplane/server/db/tables/profile.js +4 -0
- package/dist/dataplane/server/db/tables/record.js +4 -0
- package/dist/dataplane/server/db/tables/song.js +4 -0
- package/dist/dataplane/server/db/types.js +2 -0
- package/dist/dataplane/server/db/util.js +48 -0
- package/dist/dataplane/server/index.js +52 -0
- package/dist/dataplane/server/indexing/index.js +321 -0
- package/dist/dataplane/server/indexing/plugins/playlist-idea.js +163 -0
- package/dist/dataplane/server/indexing/plugins/profile.js +81 -0
- package/dist/dataplane/server/indexing/processor.js +90 -0
- package/dist/dataplane/server/routes/blocks.js +95 -0
- package/dist/dataplane/server/routes/feed-gens.js +56 -0
- package/dist/dataplane/server/routes/feeds.js +128 -0
- package/dist/dataplane/server/routes/follows.js +122 -0
- package/dist/dataplane/server/routes/identity.js +56 -0
- package/dist/dataplane/server/routes/index.js +19 -0
- package/dist/dataplane/server/routes/interactions.js +111 -0
- package/dist/dataplane/server/routes/labels.js +73 -0
- package/dist/dataplane/server/routes/likes.js +76 -0
- package/dist/dataplane/server/routes/lists.js +77 -0
- package/dist/dataplane/server/routes/moderation.js +92 -0
- package/dist/dataplane/server/routes/mutes.js +166 -0
- package/dist/dataplane/server/routes/notifs.js +137 -0
- package/dist/dataplane/server/routes/posts.js +19 -0
- package/dist/dataplane/server/routes/profile.js +61 -0
- package/dist/dataplane/server/routes/quotes.js +26 -0
- package/dist/dataplane/server/routes/records.js +88 -0
- package/dist/dataplane/server/routes/relationships.js +157 -0
- package/dist/dataplane/server/routes/reposts.js +59 -0
- package/dist/dataplane/server/routes/search.js +70 -0
- package/dist/dataplane/server/routes/starter-packs.js +24 -0
- package/dist/dataplane/server/routes/suggestions.js +134 -0
- package/dist/dataplane/server/routes/sync.js +14 -0
- package/dist/dataplane/server/routes/threads.js +31 -0
- package/dist/dataplane/server/subscription.js +114 -0
- package/dist/dataplane/server/util.js +117 -0
- package/dist/error.js +14 -0
- package/dist/index.js +115 -0
- package/dist/lexicons/index.js +638 -0
- package/dist/lexicons/lexicons.js +4551 -0
- package/dist/lexicons/types/com/atproto/admin/defs.js +54 -0
- package/dist/lexicons/types/com/atproto/admin/deleteAccount.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/disableAccountInvites.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/disableInviteCodes.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/enableAccountInvites.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/getAccountInfo.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/getAccountInfos.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/getInviteCodes.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/getSubjectStatus.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/searchAccounts.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/sendEmail.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountEmail.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountHandle.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/updateAccountPassword.js +2 -0
- package/dist/lexicons/types/com/atproto/admin/updateSubjectStatus.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/defs.js +14 -0
- package/dist/lexicons/types/com/atproto/identity/getRecommendedDidCredentials.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/refreshIdentity.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/requestPlcOperationSignature.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/resolveDid.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/resolveHandle.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/resolveIdentity.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/signPlcOperation.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/submitPlcOperation.js +2 -0
- package/dist/lexicons/types/com/atproto/identity/updateHandle.js +2 -0
- package/dist/lexicons/types/com/atproto/label/defs.js +54 -0
- package/dist/lexicons/types/com/atproto/label/queryLabels.js +2 -0
- package/dist/lexicons/types/com/atproto/label/subscribeLabels.js +24 -0
- package/dist/lexicons/types/com/atproto/lexicon/schema.js +15 -0
- package/dist/lexicons/types/com/atproto/moderation/createReport.js +2 -0
- package/dist/lexicons/types/com/atproto/moderation/defs.js +20 -0
- package/dist/lexicons/types/com/atproto/repo/applyWrites.js +64 -0
- package/dist/lexicons/types/com/atproto/repo/createRecord.js +2 -0
- package/dist/lexicons/types/com/atproto/repo/defs.js +14 -0
- package/dist/lexicons/types/com/atproto/repo/deleteRecord.js +2 -0
- package/dist/lexicons/types/com/atproto/repo/describeRepo.js +2 -0
- package/dist/lexicons/types/com/atproto/repo/getRecord.js +2 -0
- package/dist/lexicons/types/com/atproto/repo/importRepo.js +2 -0
- package/dist/lexicons/types/com/atproto/repo/listMissingBlobs.js +14 -0
- package/dist/lexicons/types/com/atproto/repo/listRecords.js +14 -0
- package/dist/lexicons/types/com/atproto/repo/putRecord.js +2 -0
- package/dist/lexicons/types/com/atproto/repo/strongRef.js +15 -0
- package/dist/lexicons/types/com/atproto/repo/uploadBlob.js +2 -0
- package/dist/lexicons/types/com/atproto/server/activateAccount.js +2 -0
- package/dist/lexicons/types/com/atproto/server/checkAccountStatus.js +2 -0
- package/dist/lexicons/types/com/atproto/server/confirmEmail.js +2 -0
- package/dist/lexicons/types/com/atproto/server/createAccount.js +2 -0
- package/dist/lexicons/types/com/atproto/server/createAppPassword.js +14 -0
- package/dist/lexicons/types/com/atproto/server/createInviteCode.js +2 -0
- package/dist/lexicons/types/com/atproto/server/createInviteCodes.js +14 -0
- package/dist/lexicons/types/com/atproto/server/createSession.js +2 -0
- package/dist/lexicons/types/com/atproto/server/deactivateAccount.js +2 -0
- package/dist/lexicons/types/com/atproto/server/defs.js +24 -0
- package/dist/lexicons/types/com/atproto/server/deleteAccount.js +2 -0
- package/dist/lexicons/types/com/atproto/server/deleteSession.js +2 -0
- package/dist/lexicons/types/com/atproto/server/describeServer.js +24 -0
- package/dist/lexicons/types/com/atproto/server/getAccountInviteCodes.js +2 -0
- package/dist/lexicons/types/com/atproto/server/getServiceAuth.js +2 -0
- package/dist/lexicons/types/com/atproto/server/getSession.js +2 -0
- package/dist/lexicons/types/com/atproto/server/listAppPasswords.js +14 -0
- package/dist/lexicons/types/com/atproto/server/refreshSession.js +2 -0
- package/dist/lexicons/types/com/atproto/server/requestAccountDelete.js +2 -0
- package/dist/lexicons/types/com/atproto/server/requestEmailConfirmation.js +2 -0
- package/dist/lexicons/types/com/atproto/server/requestEmailUpdate.js +2 -0
- package/dist/lexicons/types/com/atproto/server/requestPasswordReset.js +2 -0
- package/dist/lexicons/types/com/atproto/server/reserveSigningKey.js +2 -0
- package/dist/lexicons/types/com/atproto/server/resetPassword.js +2 -0
- package/dist/lexicons/types/com/atproto/server/revokeAppPassword.js +2 -0
- package/dist/lexicons/types/com/atproto/server/updateEmail.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getBlob.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getBlocks.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getCheckout.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getHead.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getLatestCommit.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getRecord.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getRepo.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/getRepoStatus.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/listBlobs.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/listRepos.js +14 -0
- package/dist/lexicons/types/com/atproto/sync/listReposByCollection.js +14 -0
- package/dist/lexicons/types/com/atproto/sync/notifyOfUpdate.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/requestCrawl.js +2 -0
- package/dist/lexicons/types/com/atproto/sync/subscribeRepos.js +64 -0
- package/dist/lexicons/types/com/atproto/temp/addReservedHandle.js +2 -0
- package/dist/lexicons/types/com/atproto/temp/checkSignupQueue.js +2 -0
- package/dist/lexicons/types/com/atproto/temp/fetchLabels.js +2 -0
- package/dist/lexicons/types/com/atproto/temp/requestPhoneVerification.js +2 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/actor/profile.js +15 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/defs.js +24 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/getSongs.js +2 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/playlistIdea.js +35 -0
- package/dist/lexicons/types/com/clioplaylists/alpha/feed/song.js +25 -0
- package/dist/lexicons/util.js +13 -0
- package/dist/logger.js +26 -0
- package/dist/rpc/clio_connect.js +110 -0
- package/dist/rpc/clio_pb.js +1365 -0
- package/dist/start.js +13 -0
- package/dist/util/retry.js +16 -0
- package/dist/util/uris.js +7 -0
- package/dist/util.js +119 -0
- package/package.json +73 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.Database = void 0;
|
|
40
|
+
const kysely_1 = require("kysely");
|
|
41
|
+
const node_assert_1 = __importDefault(require("node:assert"));
|
|
42
|
+
const node_events_1 = __importDefault(require("node:events"));
|
|
43
|
+
const pg_1 = require("pg");
|
|
44
|
+
const logger_1 = require("../../../logger");
|
|
45
|
+
const migrations = __importStar(require("./migrations"));
|
|
46
|
+
const provider_1 = require("./migrations/provider");
|
|
47
|
+
class Database {
|
|
48
|
+
constructor(opts, instances) {
|
|
49
|
+
Object.defineProperty(this, "opts", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
configurable: true,
|
|
52
|
+
writable: true,
|
|
53
|
+
value: opts
|
|
54
|
+
});
|
|
55
|
+
Object.defineProperty(this, "pool", {
|
|
56
|
+
enumerable: true,
|
|
57
|
+
configurable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: void 0
|
|
60
|
+
});
|
|
61
|
+
Object.defineProperty(this, "db", {
|
|
62
|
+
enumerable: true,
|
|
63
|
+
configurable: true,
|
|
64
|
+
writable: true,
|
|
65
|
+
value: void 0
|
|
66
|
+
});
|
|
67
|
+
Object.defineProperty(this, "migrator", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
configurable: true,
|
|
70
|
+
writable: true,
|
|
71
|
+
value: void 0
|
|
72
|
+
});
|
|
73
|
+
Object.defineProperty(this, "txEvt", {
|
|
74
|
+
enumerable: true,
|
|
75
|
+
configurable: true,
|
|
76
|
+
writable: true,
|
|
77
|
+
value: new node_events_1.default()
|
|
78
|
+
});
|
|
79
|
+
Object.defineProperty(this, "destroyed", {
|
|
80
|
+
enumerable: true,
|
|
81
|
+
configurable: true,
|
|
82
|
+
writable: true,
|
|
83
|
+
value: false
|
|
84
|
+
});
|
|
85
|
+
// if instances are provided, use those
|
|
86
|
+
if (instances) {
|
|
87
|
+
this.db = instances.db;
|
|
88
|
+
this.pool = instances.pool;
|
|
89
|
+
this.migrator = instances.migrator;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// else create a pool & connect
|
|
93
|
+
const { schema, url } = opts;
|
|
94
|
+
const pool = opts.pool ??
|
|
95
|
+
new pg_1.Pool({
|
|
96
|
+
connectionString: url,
|
|
97
|
+
max: opts.poolSize,
|
|
98
|
+
maxUses: opts.poolMaxUses,
|
|
99
|
+
idleTimeoutMillis: opts.poolIdleTimeoutMs,
|
|
100
|
+
});
|
|
101
|
+
// Select count(*) and other pg bigints as js integer
|
|
102
|
+
pg_1.types.setTypeParser(pg_1.types.builtins.INT8, (n) => parseInt(n, 10));
|
|
103
|
+
// Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema)
|
|
104
|
+
if (schema && !/^[a-z_]+$/i.test(schema)) {
|
|
105
|
+
throw new Error(`Postgres schema must only contain [A-Za-z_]: ${schema}`);
|
|
106
|
+
}
|
|
107
|
+
pool.on('error', onPoolError);
|
|
108
|
+
pool.on('connect', (client) => {
|
|
109
|
+
client.on('error', onClientError);
|
|
110
|
+
// Used for trigram indexes, e.g. on actor search
|
|
111
|
+
client.query('SET pg_trgm.word_similarity_threshold TO .4;');
|
|
112
|
+
if (schema) {
|
|
113
|
+
// Shared objects such as extensions will go in the public schema
|
|
114
|
+
client.query(`SET search_path TO "${schema}",public;`);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
this.pool = pool;
|
|
118
|
+
this.db = new kysely_1.Kysely({
|
|
119
|
+
dialect: new kysely_1.PostgresDialect({ pool }),
|
|
120
|
+
});
|
|
121
|
+
this.migrator = new kysely_1.Migrator({
|
|
122
|
+
db: this.db,
|
|
123
|
+
migrationTableSchema: opts.schema,
|
|
124
|
+
provider: new provider_1.CtxMigrationProvider(migrations, 'pg'),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
get schema() {
|
|
128
|
+
return this.opts.schema;
|
|
129
|
+
}
|
|
130
|
+
async transaction(fn) {
|
|
131
|
+
const leakyTxPlugin = new LeakyTxPlugin();
|
|
132
|
+
const { dbTxn, txRes } = await this.db
|
|
133
|
+
.withPlugin(leakyTxPlugin)
|
|
134
|
+
.transaction()
|
|
135
|
+
.execute(async (txn) => {
|
|
136
|
+
const dbTxn = new Database(this.opts, {
|
|
137
|
+
db: txn,
|
|
138
|
+
pool: this.pool,
|
|
139
|
+
migrator: this.migrator,
|
|
140
|
+
});
|
|
141
|
+
const txRes = await fn(dbTxn)
|
|
142
|
+
.catch(async (err) => {
|
|
143
|
+
leakyTxPlugin.endTx();
|
|
144
|
+
// ensure that all in-flight queries are flushed & the connection is open
|
|
145
|
+
await dbTxn.db.getExecutor().provideConnection(noopAsync);
|
|
146
|
+
throw err;
|
|
147
|
+
})
|
|
148
|
+
.finally(() => leakyTxPlugin.endTx());
|
|
149
|
+
return { dbTxn, txRes };
|
|
150
|
+
});
|
|
151
|
+
dbTxn?.txEvt.emit('commit');
|
|
152
|
+
return txRes;
|
|
153
|
+
}
|
|
154
|
+
get isTransaction() {
|
|
155
|
+
return this.db.isTransaction;
|
|
156
|
+
}
|
|
157
|
+
assertTransaction() {
|
|
158
|
+
(0, node_assert_1.default)(this.isTransaction, 'Transaction required');
|
|
159
|
+
}
|
|
160
|
+
assertNotTransaction() {
|
|
161
|
+
(0, node_assert_1.default)(!this.isTransaction, 'Cannot be in a transaction');
|
|
162
|
+
}
|
|
163
|
+
onCommit(fn) {
|
|
164
|
+
this.assertTransaction();
|
|
165
|
+
this.txEvt.once('commit', fn);
|
|
166
|
+
}
|
|
167
|
+
async migrateToOrThrow(migration) {
|
|
168
|
+
if (this.schema) {
|
|
169
|
+
await this.db.schema.createSchema(this.schema).ifNotExists().execute();
|
|
170
|
+
}
|
|
171
|
+
const { error, results } = await this.migrator.migrateTo(migration);
|
|
172
|
+
if (error) {
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
if (!results) {
|
|
176
|
+
throw new Error('An unknown failure occurred while migrating');
|
|
177
|
+
}
|
|
178
|
+
return results;
|
|
179
|
+
}
|
|
180
|
+
async migrateToLatestOrThrow() {
|
|
181
|
+
if (this.schema) {
|
|
182
|
+
await this.db.schema.createSchema(this.schema).ifNotExists().execute();
|
|
183
|
+
}
|
|
184
|
+
const { error, results } = await this.migrator.migrateToLatest();
|
|
185
|
+
if (error) {
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
if (!results) {
|
|
189
|
+
throw new Error('An unknown failure occurred while migrating');
|
|
190
|
+
}
|
|
191
|
+
return results;
|
|
192
|
+
}
|
|
193
|
+
async close() {
|
|
194
|
+
if (this.destroyed)
|
|
195
|
+
return;
|
|
196
|
+
await this.db.destroy();
|
|
197
|
+
this.destroyed = true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
exports.Database = Database;
|
|
201
|
+
exports.default = Database;
|
|
202
|
+
const onPoolError = (err) => logger_1.dbLogger.error({ err }, 'db pool error');
|
|
203
|
+
const onClientError = (err) => logger_1.dbLogger.error({ err }, 'db client error');
|
|
204
|
+
// utils
|
|
205
|
+
// -------
|
|
206
|
+
class LeakyTxPlugin {
|
|
207
|
+
constructor() {
|
|
208
|
+
Object.defineProperty(this, "txOver", {
|
|
209
|
+
enumerable: true,
|
|
210
|
+
configurable: true,
|
|
211
|
+
writable: true,
|
|
212
|
+
value: false
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
endTx() {
|
|
216
|
+
this.txOver = true;
|
|
217
|
+
}
|
|
218
|
+
transformQuery(args) {
|
|
219
|
+
if (this.txOver) {
|
|
220
|
+
throw new Error('tx already failed');
|
|
221
|
+
}
|
|
222
|
+
return args.node;
|
|
223
|
+
}
|
|
224
|
+
async transformResult(args) {
|
|
225
|
+
return args.result;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const noopAsync = async () => { };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./db"), exports);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.up = up;
|
|
4
|
+
exports.down = down;
|
|
5
|
+
const kysely_1 = require("kysely");
|
|
6
|
+
// @TODO subject indexes, naming?
|
|
7
|
+
// @TODO drop indexes in down()?
|
|
8
|
+
async function up(db) {
|
|
9
|
+
try {
|
|
10
|
+
// Add trigram support, supporting user search.
|
|
11
|
+
// Explicitly add to public schema, so the extension can be seen in all schemas.
|
|
12
|
+
await (0, kysely_1.sql) `create extension if not exists pg_trgm with schema public`.execute(db);
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
// The "if not exists" isn't bulletproof against races, and we see test suites racing to
|
|
16
|
+
// create the extension. So we can just ignore errors indicating the extension already exists.
|
|
17
|
+
if (!err?.['detail']?.includes?.('(pg_trgm) already exists'))
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
// profile
|
|
21
|
+
await db.schema
|
|
22
|
+
.createTable('profile')
|
|
23
|
+
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
|
24
|
+
.addColumn('cid', 'varchar', (col) => col.notNull())
|
|
25
|
+
.addColumn('creator_did', 'varchar', (col) => col.notNull())
|
|
26
|
+
.addColumn('display_name', 'varchar')
|
|
27
|
+
.addColumn('description', 'varchar')
|
|
28
|
+
.addColumn('avatar_cid', 'varchar')
|
|
29
|
+
.addColumn('banner_cid', 'varchar')
|
|
30
|
+
.addColumn('indexed_at', 'varchar', (col) => col.notNull())
|
|
31
|
+
.execute();
|
|
32
|
+
// follow
|
|
33
|
+
await db.schema
|
|
34
|
+
.createTable('follow')
|
|
35
|
+
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
|
36
|
+
.addColumn('cid', 'varchar', (col) => col.notNull())
|
|
37
|
+
.addColumn('creator', 'varchar', (col) => col.notNull())
|
|
38
|
+
.addColumn('subjectDid', 'varchar', (col) => col.notNull())
|
|
39
|
+
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
|
40
|
+
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
|
41
|
+
.addColumn('sortAt', 'varchar', (col) => col
|
|
42
|
+
.generatedAlwaysAs((0, kysely_1.sql) `least("createdAt", "indexedAt")`)
|
|
43
|
+
.stored()
|
|
44
|
+
.notNull())
|
|
45
|
+
.addUniqueConstraint('follow_unique_subject', ['creator', 'subjectDid'])
|
|
46
|
+
.execute();
|
|
47
|
+
// for, eg, "followersCount" on profile views
|
|
48
|
+
await db.schema
|
|
49
|
+
.createIndex('follow_subjectdid_idx')
|
|
50
|
+
.on('follow')
|
|
51
|
+
.column('subjectDid')
|
|
52
|
+
.execute();
|
|
53
|
+
// like
|
|
54
|
+
await db.schema
|
|
55
|
+
.createTable('like')
|
|
56
|
+
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
|
57
|
+
.addColumn('cid', 'varchar', (col) => col.notNull())
|
|
58
|
+
.addColumn('creator', 'varchar', (col) => col.notNull())
|
|
59
|
+
.addColumn('subject', 'varchar', (col) => col.notNull())
|
|
60
|
+
.addColumn('subjectCid', 'varchar', (col) => col.notNull())
|
|
61
|
+
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
|
62
|
+
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
|
63
|
+
.addColumn('sortAt', 'varchar', (col) => col
|
|
64
|
+
.generatedAlwaysAs((0, kysely_1.sql) `least("createdAt", "indexedAt")`)
|
|
65
|
+
.stored()
|
|
66
|
+
.notNull())
|
|
67
|
+
// Aids in index uniqueness plus post like counts
|
|
68
|
+
.addUniqueConstraint('like_unique_subject', ['subject', 'creator'])
|
|
69
|
+
.execute();
|
|
70
|
+
// subscription
|
|
71
|
+
await db.schema
|
|
72
|
+
.createTable('subscription')
|
|
73
|
+
.addColumn('service', 'varchar', (col) => col.notNull())
|
|
74
|
+
.addColumn('method', 'varchar', (col) => col.notNull())
|
|
75
|
+
.addColumn('state', 'varchar', (col) => col.notNull())
|
|
76
|
+
.addPrimaryKeyConstraint('subscription_pkey', ['service', 'method'])
|
|
77
|
+
.execute();
|
|
78
|
+
// actor
|
|
79
|
+
await db.schema
|
|
80
|
+
.createTable('actor')
|
|
81
|
+
.addColumn('did', 'varchar', (col) => col.primaryKey())
|
|
82
|
+
.addColumn('handle', 'varchar', (col) => col.unique())
|
|
83
|
+
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
|
84
|
+
.execute();
|
|
85
|
+
await db.schema // Supports user search
|
|
86
|
+
.createIndex(`actor_handle_tgrm_idx`)
|
|
87
|
+
.on('actor')
|
|
88
|
+
.using('gist')
|
|
89
|
+
.expression((0, kysely_1.sql) `"handle" gist_trgm_ops`)
|
|
90
|
+
.execute();
|
|
91
|
+
//record
|
|
92
|
+
await db.schema
|
|
93
|
+
.createTable('record')
|
|
94
|
+
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
|
95
|
+
.addColumn('cid', 'varchar', (col) => col.notNull())
|
|
96
|
+
.addColumn('did', 'varchar', (col) => col.notNull())
|
|
97
|
+
.addColumn('json', 'text', (col) => col.notNull())
|
|
98
|
+
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
|
99
|
+
.addColumn('takedownId', 'integer') // foreign key created in moderation-init migration
|
|
100
|
+
.execute();
|
|
101
|
+
}
|
|
102
|
+
async function down(db) {
|
|
103
|
+
// record
|
|
104
|
+
await db.schema.dropTable('record').execute();
|
|
105
|
+
// actor
|
|
106
|
+
await db.schema.dropTable('actor').execute();
|
|
107
|
+
// subscription
|
|
108
|
+
await db.schema.dropTable('subscription').execute();
|
|
109
|
+
// like
|
|
110
|
+
await db.schema.dropTable('like').execute();
|
|
111
|
+
// follow
|
|
112
|
+
await db.schema.dropTable('follow').execute();
|
|
113
|
+
// post
|
|
114
|
+
await db.schema.dropTable('post').execute();
|
|
115
|
+
// profile
|
|
116
|
+
await db.schema.dropTable('profile').execute();
|
|
117
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.up = up;
|
|
4
|
+
exports.down = down;
|
|
5
|
+
async function up(db) {
|
|
6
|
+
await db.schema
|
|
7
|
+
.createTable('did_cache')
|
|
8
|
+
.addColumn('did', 'varchar', (col) => col.primaryKey())
|
|
9
|
+
.addColumn('doc', 'jsonb', (col) => col.notNull())
|
|
10
|
+
.addColumn('updatedAt', 'bigint', (col) => col.notNull())
|
|
11
|
+
.execute();
|
|
12
|
+
}
|
|
13
|
+
async function down(db) {
|
|
14
|
+
await db.schema.dropTable('did_cache').execute();
|
|
15
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// NOTE this file can be edited by hand, but it is also appended to by the migration:create command.
|
|
3
|
+
// It's important that every migration is exported from here with the proper name. We'd simplify
|
|
4
|
+
// this with kysely's FileMigrationProvider, but it doesn't play nicely with the build process.
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports._20230420T211446071Z = exports._20230309T045948368Z = void 0;
|
|
40
|
+
exports._20230309T045948368Z = __importStar(require("./20230309T045948368Z-init"));
|
|
41
|
+
exports._20230420T211446071Z = __importStar(require("./20230420T211446071Z-did-cache"));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CtxMigrationProvider = void 0;
|
|
4
|
+
// Passes a context argument to migrations. We use this to thread the dialect into migrations
|
|
5
|
+
class CtxMigrationProvider {
|
|
6
|
+
constructor(migrations, ctx) {
|
|
7
|
+
Object.defineProperty(this, "migrations", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
writable: true,
|
|
11
|
+
value: migrations
|
|
12
|
+
});
|
|
13
|
+
Object.defineProperty(this, "ctx", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
value: ctx
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async getMigrations() {
|
|
21
|
+
const ctxMigrations = {};
|
|
22
|
+
Object.entries(this.migrations).forEach(([name, migration]) => {
|
|
23
|
+
ctxMigrations[name] = {
|
|
24
|
+
up: async (db) => await migration.up(db, this.ctx),
|
|
25
|
+
down: async (db) => await migration.down?.(db, this.ctx),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
return ctxMigrations;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.CtxMigrationProvider = CtxMigrationProvider;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.paginate = exports.IndexedAtDidKeyset = exports.CreatedAtDidKeyset = exports.TimeCidKeyset = exports.GenericKeyset = void 0;
|
|
4
|
+
const xrpc_server_1 = require("@atproto/xrpc-server");
|
|
5
|
+
const kysely_1 = require("kysely");
|
|
6
|
+
/**
|
|
7
|
+
* The GenericKeyset is an abstract class that sets-up the interface and partial implementation
|
|
8
|
+
* of a keyset-paginated cursor with two parts. There are three types involved:
|
|
9
|
+
* - Result: a raw result (i.e. a row from the db) containing data that will make-up a cursor.
|
|
10
|
+
* - E.g. { createdAt: '2022-01-01T12:00:00Z', cid: 'bafyx' }
|
|
11
|
+
* - LabeledResult: a Result processed such that the "primary" and "secondary" parts of the cursor are labeled.
|
|
12
|
+
* - E.g. { primary: '2022-01-01T12:00:00Z', secondary: 'bafyx' }
|
|
13
|
+
* - Cursor: the two string parts that make-up the packed/string cursor.
|
|
14
|
+
* - E.g. packed cursor '1641038400000__bafyx' in parts { primary: '1641038400000', secondary: 'bafyx' }
|
|
15
|
+
*
|
|
16
|
+
* These types relate as such. Implementers define the relations marked with a *:
|
|
17
|
+
* Result -*-> LabeledResult <-*-> Cursor <--> packed/string cursor
|
|
18
|
+
* ↳ SQL Condition
|
|
19
|
+
*/
|
|
20
|
+
class GenericKeyset {
|
|
21
|
+
constructor(primary, secondary) {
|
|
22
|
+
Object.defineProperty(this, "primary", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: primary
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(this, "secondary", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
configurable: true,
|
|
31
|
+
writable: true,
|
|
32
|
+
value: secondary
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
packFromResult(results) {
|
|
36
|
+
const result = Array.isArray(results) ? results.at(-1) : results;
|
|
37
|
+
if (!result)
|
|
38
|
+
return;
|
|
39
|
+
return this.pack(this.labelResult(result));
|
|
40
|
+
}
|
|
41
|
+
pack(labeled) {
|
|
42
|
+
if (!labeled)
|
|
43
|
+
return;
|
|
44
|
+
const cursor = this.labeledResultToCursor(labeled);
|
|
45
|
+
return this.packCursor(cursor);
|
|
46
|
+
}
|
|
47
|
+
unpack(cursorStr) {
|
|
48
|
+
const cursor = this.unpackCursor(cursorStr);
|
|
49
|
+
if (!cursor)
|
|
50
|
+
return;
|
|
51
|
+
return this.cursorToLabeledResult(cursor);
|
|
52
|
+
}
|
|
53
|
+
packCursor(cursor) {
|
|
54
|
+
if (!cursor)
|
|
55
|
+
return;
|
|
56
|
+
return `${cursor.primary}__${cursor.secondary}`;
|
|
57
|
+
}
|
|
58
|
+
unpackCursor(cursorStr) {
|
|
59
|
+
if (!cursorStr)
|
|
60
|
+
return;
|
|
61
|
+
const result = cursorStr.split('__');
|
|
62
|
+
const [primary, secondary, ...others] = result;
|
|
63
|
+
if (!primary || !secondary || others.length > 0) {
|
|
64
|
+
throw new xrpc_server_1.InvalidRequestError('Malformed cursor');
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
primary,
|
|
68
|
+
secondary,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
getSql(labeled, direction, tryIndex) {
|
|
72
|
+
if (labeled === undefined)
|
|
73
|
+
return;
|
|
74
|
+
if (tryIndex) {
|
|
75
|
+
// The tryIndex param will likely disappear and become the default implementation: here for now for gradual rollout query-by-query.
|
|
76
|
+
if (direction === 'asc') {
|
|
77
|
+
return (0, kysely_1.sql) `((${this.primary}, ${this.secondary}) > (${labeled.primary}, ${labeled.secondary}))`;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return (0, kysely_1.sql) `((${this.primary}, ${this.secondary}) < (${labeled.primary}, ${labeled.secondary}))`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// @NOTE this implementation can struggle to use an index on (primary, secondary) for pagination due to the "or" usage.
|
|
85
|
+
if (direction === 'asc') {
|
|
86
|
+
return (0, kysely_1.sql) `((${this.primary} > ${labeled.primary}) or (${this.primary} = ${labeled.primary} and ${this.secondary} > ${labeled.secondary}))`;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
return (0, kysely_1.sql) `((${this.primary} < ${labeled.primary}) or (${this.primary} = ${labeled.primary} and ${this.secondary} < ${labeled.secondary}))`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.GenericKeyset = GenericKeyset;
|
|
95
|
+
class TimeCidKeyset extends GenericKeyset {
|
|
96
|
+
labelResult(result) {
|
|
97
|
+
return { primary: result.sortAt, secondary: result.cid };
|
|
98
|
+
}
|
|
99
|
+
labeledResultToCursor(labeled) {
|
|
100
|
+
return {
|
|
101
|
+
primary: new Date(labeled.primary).getTime().toString(),
|
|
102
|
+
secondary: labeled.secondary,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
cursorToLabeledResult(cursor) {
|
|
106
|
+
const primaryDate = new Date(parseInt(cursor.primary, 10));
|
|
107
|
+
if (isNaN(primaryDate.getTime())) {
|
|
108
|
+
throw new xrpc_server_1.InvalidRequestError('Malformed cursor');
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
primary: primaryDate.toISOString(),
|
|
112
|
+
secondary: cursor.secondary,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.TimeCidKeyset = TimeCidKeyset;
|
|
117
|
+
class CreatedAtDidKeyset extends TimeCidKeyset {
|
|
118
|
+
labelResult(result) {
|
|
119
|
+
return { primary: result.createdAt, secondary: result.did };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
exports.CreatedAtDidKeyset = CreatedAtDidKeyset;
|
|
123
|
+
class IndexedAtDidKeyset extends TimeCidKeyset {
|
|
124
|
+
labelResult(result) {
|
|
125
|
+
return { primary: result.indexedAt, secondary: result.did };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.IndexedAtDidKeyset = IndexedAtDidKeyset;
|
|
129
|
+
const paginate = (qb, opts) => {
|
|
130
|
+
const { limit, cursor, keyset, direction = 'desc', tryIndex, nullsLast, } = opts;
|
|
131
|
+
const keysetSql = keyset.getSql(keyset.unpack(cursor), direction, tryIndex);
|
|
132
|
+
return qb
|
|
133
|
+
.if(!!limit, (q) => q.limit(limit))
|
|
134
|
+
.if(!nullsLast, (q) => q.orderBy(keyset.primary, direction).orderBy(keyset.secondary, direction))
|
|
135
|
+
.if(!!nullsLast, (q) => q
|
|
136
|
+
.orderBy(direction === 'asc'
|
|
137
|
+
? (0, kysely_1.sql) `${keyset.primary} asc nulls last`
|
|
138
|
+
: (0, kysely_1.sql) `${keyset.primary} desc nulls last`)
|
|
139
|
+
.orderBy(direction === 'asc'
|
|
140
|
+
? (0, kysely_1.sql) `${keyset.secondary} asc nulls last`
|
|
141
|
+
: (0, kysely_1.sql) `${keyset.secondary} desc nulls last`))
|
|
142
|
+
.if(!!keysetSql, (qb) => (keysetSql ? qb.where(keysetSql) : qb));
|
|
143
|
+
};
|
|
144
|
+
exports.paginate = paginate;
|