@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.
Files changed (170) hide show
  1. package/dist/.env +7 -0
  2. package/dist/api/com/clioplaylists/alpha/actor/getProfile.js +37 -0
  3. package/dist/api/com/clioplaylists/alpha/feed/getSongs.js +37 -0
  4. package/dist/api/health.js +32 -0
  5. package/dist/api/index.js +43 -0
  6. package/dist/api/util.js +17 -0
  7. package/dist/auth-verifier.js +473 -0
  8. package/dist/client.js +40 -0
  9. package/dist/config.js +65 -0
  10. package/dist/context.js +19 -0
  11. package/dist/dataplane/bsync/index.js +150 -0
  12. package/dist/dataplane/client.js +165 -0
  13. package/dist/dataplane/index.js +18 -0
  14. package/dist/dataplane/server/background.js +51 -0
  15. package/dist/dataplane/server/db/database-schema.js +2 -0
  16. package/dist/dataplane/server/db/db.js +228 -0
  17. package/dist/dataplane/server/db/index.js +17 -0
  18. package/dist/dataplane/server/db/migrations/20230309T045948368Z-init.js +117 -0
  19. package/dist/dataplane/server/db/migrations/20230420T211446071Z-did-cache.js +15 -0
  20. package/dist/dataplane/server/db/migrations/index.js +41 -0
  21. package/dist/dataplane/server/db/migrations/provider.js +31 -0
  22. package/dist/dataplane/server/db/pagination.js +144 -0
  23. package/dist/dataplane/server/db/tables/actor-sync.js +4 -0
  24. package/dist/dataplane/server/db/tables/actor.js +4 -0
  25. package/dist/dataplane/server/db/tables/artist-list-item.js +4 -0
  26. package/dist/dataplane/server/db/tables/artist.js +4 -0
  27. package/dist/dataplane/server/db/tables/playlist-idea.js +4 -0
  28. package/dist/dataplane/server/db/tables/playlist-item.js +4 -0
  29. package/dist/dataplane/server/db/tables/playlist.js +4 -0
  30. package/dist/dataplane/server/db/tables/profile.js +4 -0
  31. package/dist/dataplane/server/db/tables/record.js +4 -0
  32. package/dist/dataplane/server/db/tables/song.js +4 -0
  33. package/dist/dataplane/server/db/types.js +2 -0
  34. package/dist/dataplane/server/db/util.js +48 -0
  35. package/dist/dataplane/server/index.js +52 -0
  36. package/dist/dataplane/server/indexing/index.js +321 -0
  37. package/dist/dataplane/server/indexing/plugins/playlist-idea.js +163 -0
  38. package/dist/dataplane/server/indexing/plugins/profile.js +81 -0
  39. package/dist/dataplane/server/indexing/processor.js +90 -0
  40. package/dist/dataplane/server/routes/blocks.js +95 -0
  41. package/dist/dataplane/server/routes/feed-gens.js +56 -0
  42. package/dist/dataplane/server/routes/feeds.js +128 -0
  43. package/dist/dataplane/server/routes/follows.js +122 -0
  44. package/dist/dataplane/server/routes/identity.js +56 -0
  45. package/dist/dataplane/server/routes/index.js +19 -0
  46. package/dist/dataplane/server/routes/interactions.js +111 -0
  47. package/dist/dataplane/server/routes/labels.js +73 -0
  48. package/dist/dataplane/server/routes/likes.js +76 -0
  49. package/dist/dataplane/server/routes/lists.js +77 -0
  50. package/dist/dataplane/server/routes/moderation.js +92 -0
  51. package/dist/dataplane/server/routes/mutes.js +166 -0
  52. package/dist/dataplane/server/routes/notifs.js +137 -0
  53. package/dist/dataplane/server/routes/posts.js +19 -0
  54. package/dist/dataplane/server/routes/profile.js +61 -0
  55. package/dist/dataplane/server/routes/quotes.js +26 -0
  56. package/dist/dataplane/server/routes/records.js +88 -0
  57. package/dist/dataplane/server/routes/relationships.js +157 -0
  58. package/dist/dataplane/server/routes/reposts.js +59 -0
  59. package/dist/dataplane/server/routes/search.js +70 -0
  60. package/dist/dataplane/server/routes/starter-packs.js +24 -0
  61. package/dist/dataplane/server/routes/suggestions.js +134 -0
  62. package/dist/dataplane/server/routes/sync.js +14 -0
  63. package/dist/dataplane/server/routes/threads.js +31 -0
  64. package/dist/dataplane/server/subscription.js +114 -0
  65. package/dist/dataplane/server/util.js +117 -0
  66. package/dist/error.js +14 -0
  67. package/dist/index.js +115 -0
  68. package/dist/lexicons/index.js +638 -0
  69. package/dist/lexicons/lexicons.js +4551 -0
  70. package/dist/lexicons/types/com/atproto/admin/defs.js +54 -0
  71. package/dist/lexicons/types/com/atproto/admin/deleteAccount.js +2 -0
  72. package/dist/lexicons/types/com/atproto/admin/disableAccountInvites.js +2 -0
  73. package/dist/lexicons/types/com/atproto/admin/disableInviteCodes.js +2 -0
  74. package/dist/lexicons/types/com/atproto/admin/enableAccountInvites.js +2 -0
  75. package/dist/lexicons/types/com/atproto/admin/getAccountInfo.js +2 -0
  76. package/dist/lexicons/types/com/atproto/admin/getAccountInfos.js +2 -0
  77. package/dist/lexicons/types/com/atproto/admin/getInviteCodes.js +2 -0
  78. package/dist/lexicons/types/com/atproto/admin/getSubjectStatus.js +2 -0
  79. package/dist/lexicons/types/com/atproto/admin/searchAccounts.js +2 -0
  80. package/dist/lexicons/types/com/atproto/admin/sendEmail.js +2 -0
  81. package/dist/lexicons/types/com/atproto/admin/updateAccountEmail.js +2 -0
  82. package/dist/lexicons/types/com/atproto/admin/updateAccountHandle.js +2 -0
  83. package/dist/lexicons/types/com/atproto/admin/updateAccountPassword.js +2 -0
  84. package/dist/lexicons/types/com/atproto/admin/updateSubjectStatus.js +2 -0
  85. package/dist/lexicons/types/com/atproto/identity/defs.js +14 -0
  86. package/dist/lexicons/types/com/atproto/identity/getRecommendedDidCredentials.js +2 -0
  87. package/dist/lexicons/types/com/atproto/identity/refreshIdentity.js +2 -0
  88. package/dist/lexicons/types/com/atproto/identity/requestPlcOperationSignature.js +2 -0
  89. package/dist/lexicons/types/com/atproto/identity/resolveDid.js +2 -0
  90. package/dist/lexicons/types/com/atproto/identity/resolveHandle.js +2 -0
  91. package/dist/lexicons/types/com/atproto/identity/resolveIdentity.js +2 -0
  92. package/dist/lexicons/types/com/atproto/identity/signPlcOperation.js +2 -0
  93. package/dist/lexicons/types/com/atproto/identity/submitPlcOperation.js +2 -0
  94. package/dist/lexicons/types/com/atproto/identity/updateHandle.js +2 -0
  95. package/dist/lexicons/types/com/atproto/label/defs.js +54 -0
  96. package/dist/lexicons/types/com/atproto/label/queryLabels.js +2 -0
  97. package/dist/lexicons/types/com/atproto/label/subscribeLabels.js +24 -0
  98. package/dist/lexicons/types/com/atproto/lexicon/schema.js +15 -0
  99. package/dist/lexicons/types/com/atproto/moderation/createReport.js +2 -0
  100. package/dist/lexicons/types/com/atproto/moderation/defs.js +20 -0
  101. package/dist/lexicons/types/com/atproto/repo/applyWrites.js +64 -0
  102. package/dist/lexicons/types/com/atproto/repo/createRecord.js +2 -0
  103. package/dist/lexicons/types/com/atproto/repo/defs.js +14 -0
  104. package/dist/lexicons/types/com/atproto/repo/deleteRecord.js +2 -0
  105. package/dist/lexicons/types/com/atproto/repo/describeRepo.js +2 -0
  106. package/dist/lexicons/types/com/atproto/repo/getRecord.js +2 -0
  107. package/dist/lexicons/types/com/atproto/repo/importRepo.js +2 -0
  108. package/dist/lexicons/types/com/atproto/repo/listMissingBlobs.js +14 -0
  109. package/dist/lexicons/types/com/atproto/repo/listRecords.js +14 -0
  110. package/dist/lexicons/types/com/atproto/repo/putRecord.js +2 -0
  111. package/dist/lexicons/types/com/atproto/repo/strongRef.js +15 -0
  112. package/dist/lexicons/types/com/atproto/repo/uploadBlob.js +2 -0
  113. package/dist/lexicons/types/com/atproto/server/activateAccount.js +2 -0
  114. package/dist/lexicons/types/com/atproto/server/checkAccountStatus.js +2 -0
  115. package/dist/lexicons/types/com/atproto/server/confirmEmail.js +2 -0
  116. package/dist/lexicons/types/com/atproto/server/createAccount.js +2 -0
  117. package/dist/lexicons/types/com/atproto/server/createAppPassword.js +14 -0
  118. package/dist/lexicons/types/com/atproto/server/createInviteCode.js +2 -0
  119. package/dist/lexicons/types/com/atproto/server/createInviteCodes.js +14 -0
  120. package/dist/lexicons/types/com/atproto/server/createSession.js +2 -0
  121. package/dist/lexicons/types/com/atproto/server/deactivateAccount.js +2 -0
  122. package/dist/lexicons/types/com/atproto/server/defs.js +24 -0
  123. package/dist/lexicons/types/com/atproto/server/deleteAccount.js +2 -0
  124. package/dist/lexicons/types/com/atproto/server/deleteSession.js +2 -0
  125. package/dist/lexicons/types/com/atproto/server/describeServer.js +24 -0
  126. package/dist/lexicons/types/com/atproto/server/getAccountInviteCodes.js +2 -0
  127. package/dist/lexicons/types/com/atproto/server/getServiceAuth.js +2 -0
  128. package/dist/lexicons/types/com/atproto/server/getSession.js +2 -0
  129. package/dist/lexicons/types/com/atproto/server/listAppPasswords.js +14 -0
  130. package/dist/lexicons/types/com/atproto/server/refreshSession.js +2 -0
  131. package/dist/lexicons/types/com/atproto/server/requestAccountDelete.js +2 -0
  132. package/dist/lexicons/types/com/atproto/server/requestEmailConfirmation.js +2 -0
  133. package/dist/lexicons/types/com/atproto/server/requestEmailUpdate.js +2 -0
  134. package/dist/lexicons/types/com/atproto/server/requestPasswordReset.js +2 -0
  135. package/dist/lexicons/types/com/atproto/server/reserveSigningKey.js +2 -0
  136. package/dist/lexicons/types/com/atproto/server/resetPassword.js +2 -0
  137. package/dist/lexicons/types/com/atproto/server/revokeAppPassword.js +2 -0
  138. package/dist/lexicons/types/com/atproto/server/updateEmail.js +2 -0
  139. package/dist/lexicons/types/com/atproto/sync/getBlob.js +2 -0
  140. package/dist/lexicons/types/com/atproto/sync/getBlocks.js +2 -0
  141. package/dist/lexicons/types/com/atproto/sync/getCheckout.js +2 -0
  142. package/dist/lexicons/types/com/atproto/sync/getHead.js +2 -0
  143. package/dist/lexicons/types/com/atproto/sync/getLatestCommit.js +2 -0
  144. package/dist/lexicons/types/com/atproto/sync/getRecord.js +2 -0
  145. package/dist/lexicons/types/com/atproto/sync/getRepo.js +2 -0
  146. package/dist/lexicons/types/com/atproto/sync/getRepoStatus.js +2 -0
  147. package/dist/lexicons/types/com/atproto/sync/listBlobs.js +2 -0
  148. package/dist/lexicons/types/com/atproto/sync/listRepos.js +14 -0
  149. package/dist/lexicons/types/com/atproto/sync/listReposByCollection.js +14 -0
  150. package/dist/lexicons/types/com/atproto/sync/notifyOfUpdate.js +2 -0
  151. package/dist/lexicons/types/com/atproto/sync/requestCrawl.js +2 -0
  152. package/dist/lexicons/types/com/atproto/sync/subscribeRepos.js +64 -0
  153. package/dist/lexicons/types/com/atproto/temp/addReservedHandle.js +2 -0
  154. package/dist/lexicons/types/com/atproto/temp/checkSignupQueue.js +2 -0
  155. package/dist/lexicons/types/com/atproto/temp/fetchLabels.js +2 -0
  156. package/dist/lexicons/types/com/atproto/temp/requestPhoneVerification.js +2 -0
  157. package/dist/lexicons/types/com/clioplaylists/alpha/actor/profile.js +15 -0
  158. package/dist/lexicons/types/com/clioplaylists/alpha/feed/defs.js +24 -0
  159. package/dist/lexicons/types/com/clioplaylists/alpha/feed/getSongs.js +2 -0
  160. package/dist/lexicons/types/com/clioplaylists/alpha/feed/playlistIdea.js +35 -0
  161. package/dist/lexicons/types/com/clioplaylists/alpha/feed/song.js +25 -0
  162. package/dist/lexicons/util.js +13 -0
  163. package/dist/logger.js +26 -0
  164. package/dist/rpc/clio_connect.js +110 -0
  165. package/dist/rpc/clio_pb.js +1365 -0
  166. package/dist/start.js +13 -0
  167. package/dist/util/retry.js +16 -0
  168. package/dist/util/uris.js +7 -0
  169. package/dist/util.js +119 -0
  170. 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;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'actor_sync';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'actor';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'artist_list_item';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'artist';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'playlist_idea';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'playlist_item';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'playlist';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'profile';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'record';
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tableName = void 0;
4
+ exports.tableName = 'song';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });