@clioplaylists/clio 0.1.8 → 0.1.9

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 (126) hide show
  1. package/dist/api/com/clioplaylists/alpha/feed/getRecommendedPlaylistsByUser.d.ts +3 -0
  2. package/dist/api/com/clioplaylists/alpha/feed/getRecommendedPlaylistsByUser.js +70 -0
  3. package/dist/api/health.js +10 -3
  4. package/dist/api/index.d.ts +1 -0
  5. package/dist/api/index.js +40 -2
  6. package/dist/api/oauth.d.ts +3 -0
  7. package/dist/api/oauth.js +63 -0
  8. package/dist/api/util.d.ts +1 -0
  9. package/dist/api/util.js +11 -6
  10. package/dist/api/well-known.js +8 -4
  11. package/dist/auth-verifier.d.ts +17 -4
  12. package/dist/auth-verifier.js +171 -165
  13. package/dist/client.js +15 -8
  14. package/dist/config.d.ts +21 -0
  15. package/dist/config.js +77 -7
  16. package/dist/context.d.ts +11 -0
  17. package/dist/context.js +14 -1
  18. package/dist/dataplane/client/hosts.js +5 -1
  19. package/dist/dataplane/client/index.d.ts +2 -0
  20. package/dist/dataplane/client/index.js +40 -17
  21. package/dist/dataplane/client/util.d.ts +20 -0
  22. package/dist/dataplane/client/util.js +92 -0
  23. package/dist/dataplane/index.js +18 -2
  24. package/dist/dataplane/server/background.d.ts +1 -1
  25. package/dist/dataplane/server/background.js +12 -5
  26. package/dist/dataplane/server/db/database-schema.d.ts +5 -1
  27. package/dist/dataplane/server/db/database-schema.js +2 -1
  28. package/dist/dataplane/server/db/db.js +60 -20
  29. package/dist/dataplane/server/db/index.js +17 -1
  30. package/dist/dataplane/server/db/migrations/20250515T045948368Z-init.d.ts +3 -0
  31. package/dist/dataplane/server/db/migrations/20250515T045948368Z-init.js +170 -0
  32. package/dist/dataplane/server/db/migrations/20260119T210000000Z-song-recommendation.d.ts +3 -0
  33. package/dist/dataplane/server/db/migrations/20260119T210000000Z-song-recommendation.js +36 -0
  34. package/dist/dataplane/server/db/migrations/20260119T220000000Z-oauth.d.ts +3 -0
  35. package/dist/dataplane/server/db/migrations/20260119T220000000Z-oauth.js +25 -0
  36. package/dist/dataplane/server/db/migrations/index.d.ts +3 -2
  37. package/dist/dataplane/server/db/migrations/index.js +39 -2
  38. package/dist/dataplane/server/db/migrations/provider.js +5 -1
  39. package/dist/dataplane/server/db/pagination.d.ts +1 -1
  40. package/dist/dataplane/server/db/pagination.js +38 -25
  41. package/dist/dataplane/server/db/tables/actor-sync.d.ts +2 -2
  42. package/dist/dataplane/server/db/tables/actor-sync.js +4 -1
  43. package/dist/dataplane/server/db/tables/actor.d.ts +3 -3
  44. package/dist/dataplane/server/db/tables/actor.js +4 -1
  45. package/dist/dataplane/server/db/tables/artist-list-item.d.ts +2 -2
  46. package/dist/dataplane/server/db/tables/artist-list-item.js +4 -1
  47. package/dist/dataplane/server/db/tables/artist.js +4 -1
  48. package/dist/dataplane/server/db/tables/oauth-session.d.ts +9 -0
  49. package/dist/dataplane/server/db/tables/oauth-session.js +4 -0
  50. package/dist/dataplane/server/db/tables/oauth-state.d.ts +10 -0
  51. package/dist/dataplane/server/db/tables/oauth-state.js +4 -0
  52. package/dist/dataplane/server/db/tables/playlist-idea.d.ts +3 -3
  53. package/dist/dataplane/server/db/tables/playlist-idea.js +4 -1
  54. package/dist/dataplane/server/db/tables/playlist-item.js +4 -1
  55. package/dist/dataplane/server/db/tables/playlist.d.ts +1 -0
  56. package/dist/dataplane/server/db/tables/playlist.js +4 -1
  57. package/dist/dataplane/server/db/tables/profile.d.ts +5 -5
  58. package/dist/dataplane/server/db/tables/profile.js +4 -1
  59. package/dist/dataplane/server/db/tables/record.d.ts +1 -1
  60. package/dist/dataplane/server/db/tables/record.js +4 -1
  61. package/dist/dataplane/server/db/tables/song-recommendation.d.ts +17 -0
  62. package/dist/dataplane/server/db/tables/song-recommendation.js +4 -0
  63. package/dist/dataplane/server/db/tables/song.d.ts +2 -2
  64. package/dist/dataplane/server/db/tables/song.js +4 -1
  65. package/dist/dataplane/server/db/tables/subscription-cursor.d.ts +9 -0
  66. package/dist/dataplane/server/db/tables/subscription-cursor.js +4 -0
  67. package/dist/dataplane/server/db/types.js +2 -1
  68. package/dist/dataplane/server/db/util.d.ts +7 -3
  69. package/dist/dataplane/server/db/util.js +26 -18
  70. package/dist/dataplane/server/index.js +21 -13
  71. package/dist/dataplane/server/indexing/index.d.ts +2 -0
  72. package/dist/dataplane/server/indexing/index.js +82 -66
  73. package/dist/dataplane/server/indexing/plugins/playlist-idea.d.ts +1 -2
  74. package/dist/dataplane/server/indexing/plugins/playlist-idea.js +50 -41
  75. package/dist/dataplane/server/indexing/plugins/profile.js +45 -12
  76. package/dist/dataplane/server/indexing/plugins/song-recommendation.d.ts +9 -0
  77. package/dist/dataplane/server/indexing/plugins/song-recommendation.js +101 -0
  78. package/dist/dataplane/server/indexing/processor.js +12 -11
  79. package/dist/dataplane/server/routes/identity.d.ts +19 -0
  80. package/dist/dataplane/server/routes/identity.js +32 -25
  81. package/dist/dataplane/server/routes/index.js +15 -10
  82. package/dist/dataplane/server/routes/profile.js +17 -25
  83. package/dist/dataplane/server/routes/records.d.ts +18 -0
  84. package/dist/dataplane/server/routes/records.js +48 -22
  85. package/dist/dataplane/server/routes/sync.js +5 -3
  86. package/dist/dataplane/server/storage/subscription-cursor.d.ts +3 -0
  87. package/dist/dataplane/server/storage/subscription-cursor.js +25 -0
  88. package/dist/dataplane/server/subscription.d.ts +6 -3
  89. package/dist/dataplane/server/subscription.js +73 -63
  90. package/dist/error.js +9 -5
  91. package/dist/index.d.ts +6 -3
  92. package/dist/index.js +91 -28
  93. package/dist/lexicons/index.d.ts +3 -210
  94. package/dist/lexicons/index.js +26 -403
  95. package/dist/lexicons/lexicons.d.ts +409 -8107
  96. package/dist/lexicons/lexicons.js +134 -4276
  97. package/dist/lexicons/types/com/atproto/repo/strongRef.d.ts +4 -4
  98. package/dist/lexicons/types/com/atproto/repo/strongRef.js +13 -9
  99. package/dist/lexicons/types/com/clioplaylists/alpha/actor/profile.d.ts +10 -8
  100. package/dist/lexicons/types/com/clioplaylists/alpha/actor/profile.js +13 -9
  101. package/dist/lexicons/types/com/clioplaylists/alpha/feed/defs.d.ts +20 -11
  102. package/dist/lexicons/types/com/clioplaylists/alpha/feed/defs.js +29 -14
  103. package/dist/lexicons/types/com/clioplaylists/alpha/feed/getRecommendedPlaylistsByUser.d.ts +36 -0
  104. package/dist/lexicons/types/com/clioplaylists/alpha/feed/getRecommendedPlaylistsByUser.js +6 -0
  105. package/dist/lexicons/types/com/clioplaylists/alpha/feed/playlistIdea.d.ts +11 -14
  106. package/dist/lexicons/types/com/clioplaylists/alpha/feed/playlistIdea.js +20 -23
  107. package/dist/lexicons/types/com/clioplaylists/alpha/feed/recommendedPlaylist.d.ts +18 -0
  108. package/dist/lexicons/types/com/clioplaylists/alpha/feed/recommendedPlaylist.js +15 -0
  109. package/dist/lexicons/types/com/clioplaylists/alpha/feed/songRecommendation.d.ts +18 -0
  110. package/dist/lexicons/types/com/clioplaylists/alpha/feed/songRecommendation.js +15 -0
  111. package/dist/lexicons/util.d.ts +33 -2
  112. package/dist/lexicons/util.js +32 -4
  113. package/dist/logger.js +16 -10
  114. package/dist/oauth/client.d.ts +14 -0
  115. package/dist/oauth/client.js +126 -0
  116. package/dist/oauth/pds-agent.d.ts +3 -0
  117. package/dist/oauth/pds-agent.js +15 -0
  118. package/dist/rpc/clio_connect.d.ts +101 -11
  119. package/dist/rpc/clio_connect.js +138 -45
  120. package/dist/rpc/clio_pb.d.ts +448 -30
  121. package/dist/rpc/clio_pb.js +967 -272
  122. package/dist/util/retry.js +10 -9
  123. package/dist/util/uris.js +6 -3
  124. package/dist/util.d.ts +0 -1
  125. package/dist/util.js +61 -20
  126. package/package.json +26 -5
@@ -0,0 +1,3 @@
1
+ import AppContext from '../../../../../context';
2
+ import { Server } from '../../../../../lexicons';
3
+ export default function (server: Server, ctx: AppContext): void;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const util_1 = require("../../../../../util");
5
+ const util_2 = require("../../../../util");
6
+ function default_1(server, ctx) {
7
+ server.com.clioplaylists.alpha.feed.getRecommendedPlaylistsByUser({
8
+ handler: async ({ params, auth, req }) => {
9
+ void auth;
10
+ void req;
11
+ const userAtIdentifier = params.userAtIdentifier;
12
+ const did = userAtIdentifier.startsWith('did:')
13
+ ? userAtIdentifier
14
+ : (await ctx.dataplane.getDidsByHandles({
15
+ handles: [userAtIdentifier.toLowerCase()],
16
+ })).dids[0];
17
+ if (!did) {
18
+ const output = { recommendedPlaylists: [] };
19
+ return { encoding: 'application/json', body: output, headers: (0, util_2.resHeaders)({}) };
20
+ }
21
+ const [identity, recRes] = await Promise.all([
22
+ ctx.dataplane.getIdentityByDid({ did }).catch(() => undefined),
23
+ ctx.dataplane.getSongRecommendationRecordsByUser({ userDid: did }),
24
+ ]);
25
+ const ownerHandle = identity?.handle ?? userAtIdentifier;
26
+ const byPlaylistIdea = new Map();
27
+ for (const recordWrapper of recRes.records) {
28
+ const rec = (0, util_1.parseRecord)(recordWrapper, false);
29
+ if (!rec)
30
+ continue;
31
+ const playlistIdeaUri = rec.record.playlistIdea.uri;
32
+ const playlistIdeaCid = rec.record.playlistIdea.cid;
33
+ const song = rec.record.song;
34
+ const entry = byPlaylistIdea.get(playlistIdeaUri) ??
35
+ (() => {
36
+ const created = {
37
+ playlistIdeaUri,
38
+ playlistIdeaCid,
39
+ songsByMbId: new Map(),
40
+ };
41
+ byPlaylistIdea.set(playlistIdeaUri, created);
42
+ return created;
43
+ })();
44
+ if (!entry.songsByMbId.has(song.trackMbId)) {
45
+ entry.songsByMbId.set(song.trackMbId, {
46
+ trackName: song.trackName,
47
+ artistNames: song.artistNames,
48
+ trackMbId: song.trackMbId,
49
+ artistMbIds: song.artistMbIds,
50
+ albumArtwork: song.albumArtworkRef,
51
+ });
52
+ }
53
+ }
54
+ const output = {
55
+ recommendedPlaylists: Array.from(byPlaylistIdea.values()).map((pl) => ({
56
+ uri: pl.playlistIdeaUri,
57
+ cid: pl.playlistIdeaCid,
58
+ playlistIdeaUri: pl.playlistIdeaUri,
59
+ ownerHandle,
60
+ songs: Array.from(pl.songsByMbId.values()),
61
+ })),
62
+ };
63
+ return {
64
+ encoding: 'application/json',
65
+ body: output,
66
+ headers: (0, util_2.resHeaders)({}),
67
+ };
68
+ },
69
+ });
70
+ }
@@ -1,6 +1,12 @@
1
- import express from 'express';
2
- export const createRouter = (ctx) => {
3
- const router = express.Router();
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createRouter = void 0;
7
+ const express_1 = __importDefault(require("express"));
8
+ const createRouter = (ctx) => {
9
+ const router = express_1.default.Router();
4
10
  router.get('/', function (req, res) {
5
11
  res.type('text/plain');
6
12
  res.send(`
@@ -23,3 +29,4 @@ Most API routes are under /xrpc/
23
29
  });
24
30
  return router;
25
31
  };
32
+ exports.createRouter = createRouter;
@@ -1,4 +1,5 @@
1
1
  import AppContext from '../context';
2
2
  import { Server } from '../lexicons';
3
3
  export * as health from './health';
4
+ export * as wellKnown from './well-known';
4
5
  export default function (server: Server, ctx: AppContext): Server;
package/dist/api/index.js CHANGED
@@ -1,6 +1,44 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.wellKnown = exports.health = void 0;
37
+ exports.default = default_1;
1
38
  // import getSongs from './com/clioplaylists/alpha/feed/getSongs'
2
- export * as health from './health';
3
- export default function (server, ctx) {
39
+ exports.health = __importStar(require("./health"));
40
+ exports.wellKnown = __importStar(require("./well-known"));
41
+ function default_1(server, ctx) {
4
42
  // getSongs(server, ctx)
5
43
  return server;
6
44
  }
@@ -0,0 +1,3 @@
1
+ import { Router } from 'express';
2
+ import AppContext from '../context';
3
+ export declare const createRouter: (ctx: AppContext) => Router;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRouter = void 0;
4
+ const express_1 = require("express");
5
+ const client_1 = require("../oauth/client");
6
+ const createRouter = (ctx) => {
7
+ const router = (0, express_1.Router)();
8
+ router.get('/.well-known/atproto-oauth-client.json', (_req, res) => {
9
+ res.json((0, client_1.getOauthClientMetadata)(ctx));
10
+ });
11
+ router.get('/oauth/login', async (req, res, next) => {
12
+ try {
13
+ const identifierRaw = typeof req.query['identifier'] === 'string' ? req.query['identifier'] : undefined;
14
+ const handleRaw = typeof req.query['handle'] === 'string' ? req.query['handle'] : undefined;
15
+ const identifier = identifierRaw ?? handleRaw;
16
+ if (!identifier) {
17
+ res.status(400).json({ error: 'Missing query param: identifier' });
18
+ return;
19
+ }
20
+ const oauth = (0, client_1.getOauthClient)(ctx);
21
+ const url = await oauth.authorize(identifier, {
22
+ scope: ctx.cfg.oauthScope,
23
+ redirect_uri: (0, client_1.getOauthRedirectUri)(ctx),
24
+ });
25
+ res.redirect(url.toString());
26
+ }
27
+ catch (err) {
28
+ next(err);
29
+ }
30
+ });
31
+ router.get('/oauth/callback', async (req, res, next) => {
32
+ try {
33
+ const qs = req.originalUrl.split('?', 2)[1] ?? '';
34
+ const params = new URLSearchParams(qs);
35
+ const oauth = (0, client_1.getOauthClient)(ctx);
36
+ const { session } = await oauth.callback(params, {
37
+ redirect_uri: (0, client_1.getOauthRedirectUri)(ctx),
38
+ });
39
+ res.json({ did: session.did });
40
+ }
41
+ catch (err) {
42
+ next(err);
43
+ }
44
+ });
45
+ router.get('/oauth/session', async (req, res, next) => {
46
+ try {
47
+ const did = typeof req.query['did'] === 'string' ? req.query['did'] : undefined;
48
+ if (!did) {
49
+ res.status(400).json({ error: 'Missing query param: did' });
50
+ return;
51
+ }
52
+ const oauth = (0, client_1.getOauthClient)(ctx);
53
+ const session = await oauth.restore(did, 'auto');
54
+ const info = await session.getTokenInfo('auto');
55
+ res.json({ did: session.did, token: info });
56
+ }
57
+ catch (err) {
58
+ next(err);
59
+ }
60
+ });
61
+ return router;
62
+ };
63
+ exports.createRouter = createRouter;
@@ -1,6 +1,7 @@
1
1
  import { ParsedLabelers } from '../util';
2
2
  export declare const ATPROTO_CONTENT_LABELERS = "Atproto-Content-Labelers";
3
3
  export declare const ATPROTO_REPO_REV = "Atproto-Repo-Rev";
4
+ export declare const BSKY_USER_AGENT = "clio-appview";
4
5
  type ResHeaderOpts = {
5
6
  labelers: ParsedLabelers;
6
7
  repoRev: string | null;
package/dist/api/util.js CHANGED
@@ -1,13 +1,18 @@
1
- import { formatLabelerHeader } from '../util';
2
- export const ATPROTO_CONTENT_LABELERS = 'Atproto-Content-Labelers';
3
- export const ATPROTO_REPO_REV = 'Atproto-Repo-Rev';
4
- export const resHeaders = (opts) => {
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resHeaders = exports.BSKY_USER_AGENT = exports.ATPROTO_REPO_REV = exports.ATPROTO_CONTENT_LABELERS = void 0;
4
+ const util_1 = require("../util");
5
+ exports.ATPROTO_CONTENT_LABELERS = 'Atproto-Content-Labelers';
6
+ exports.ATPROTO_REPO_REV = 'Atproto-Repo-Rev';
7
+ exports.BSKY_USER_AGENT = 'clio-appview';
8
+ const resHeaders = (opts) => {
5
9
  const headers = {};
6
10
  if (opts.labelers) {
7
- headers[ATPROTO_CONTENT_LABELERS] = formatLabelerHeader(opts.labelers);
11
+ headers[exports.ATPROTO_CONTENT_LABELERS] = (0, util_1.formatLabelerHeader)(opts.labelers);
8
12
  }
9
13
  if (opts.repoRev) {
10
- headers[ATPROTO_REPO_REV] = opts.repoRev;
14
+ headers[exports.ATPROTO_REPO_REV] = opts.repoRev;
11
15
  }
12
16
  return headers;
13
17
  };
18
+ exports.resHeaders = resHeaders;
@@ -1,6 +1,9 @@
1
- import { Router } from 'express';
2
- export const createRouter = (ctx) => {
3
- const router = Router();
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRouter = void 0;
4
+ const express_1 = require("express");
5
+ const createRouter = (ctx) => {
6
+ const router = (0, express_1.Router)();
4
7
  const did = ctx.cfg.serverDid;
5
8
  if (did.startsWith('did:web:')) {
6
9
  const hostname = did.slice('did:web:'.length);
@@ -22,10 +25,11 @@ export const createRouter = (ctx) => {
22
25
  id: '#clio_appview',
23
26
  type: 'ClioAppView',
24
27
  serviceEndpoint,
25
- }
28
+ },
26
29
  ],
27
30
  });
28
31
  });
29
32
  }
30
33
  return router;
31
34
  };
35
+ exports.createRouter = createRouter;
@@ -1,9 +1,12 @@
1
1
  import { VerifySignatureWithKeyFn } from '@atproto/xrpc-server';
2
- import express from 'express';
2
+ import type { Request } from 'express';
3
3
  import { KeyObject } from 'node:crypto';
4
- import { DataPlaneClient } from './client';
4
+ import { DataPlaneClient } from './dataplane';
5
5
  type ReqCtx = {
6
- req: express.Request;
6
+ req: HeaderedRequest;
7
+ };
8
+ type HeaderedRequest = Request & {
9
+ headers: Record<string, string | string[] | undefined>;
7
10
  };
8
11
  type StandardAuthOpts = {
9
12
  skipAudCheck?: boolean;
@@ -62,7 +65,9 @@ export declare class AuthVerifier {
62
65
  standardOrRole: (ctx: ReqCtx) => Promise<StandardOutput | RoleOutput>;
63
66
  optionalStandardOrRole: (ctx: ReqCtx) => Promise<StandardOutput | RoleOutput | NullOutput>;
64
67
  entrywaySession: (reqCtx: ReqCtx) => Promise<StandardOutput>;
65
- parseRoleCreds(req: express.Request): {
68
+ modService: (reqCtx: ReqCtx) => Promise<ModServiceOutput>;
69
+ roleOrModService: (reqCtx: ReqCtx) => Promise<RoleOutput | ModServiceOutput>;
70
+ parseRoleCreds(req: HeaderedRequest): {
66
71
  status: RoleStatus;
67
72
  admin: boolean;
68
73
  moderator: boolean;
@@ -73,6 +78,14 @@ export declare class AuthVerifier {
73
78
  moderator?: undefined;
74
79
  triage?: undefined;
75
80
  };
81
+ verifyServiceJwt(reqCtx: ReqCtx, opts: {
82
+ iss: string[] | null;
83
+ aud: string | null;
84
+ lxmCheck?: (method?: string) => boolean;
85
+ }): Promise<{
86
+ iss: string;
87
+ aud: string;
88
+ }>;
76
89
  isModService(iss: string): boolean;
77
90
  nullCreds(): NullOutput;
78
91
  parseCreds(creds: StandardOutput | RoleOutput | ModServiceOutput | NullOutput): {