birdclaw 0.9.2 → 0.9.3

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 (76) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cli/birdclaw.js +1227 -1065
  3. package/dist/client/assets/AvatarChip-C8zELEVt.js +1 -0
  4. package/dist/client/assets/ProfilePreview-CsiLpFrb.js +1 -0
  5. package/dist/client/assets/SavedTimelineView-BSnwnujP.js +1 -0
  6. package/dist/client/assets/SmartTimestamp-BypN4KPq.js +1 -0
  7. package/dist/client/assets/TimelineRouteFrame-H3D4R0Xu.js +1 -0
  8. package/dist/client/assets/blocks-WsAOmHsv.js +1 -0
  9. package/dist/client/assets/{bookmarks-DZIMTKEp.js → bookmarks-B2I0kAWY.js} +1 -1
  10. package/dist/client/assets/circle-check-BCK_qvXt.js +1 -0
  11. package/dist/client/assets/{client-stream-contracts-DcKcyZhg.js → client-stream-contracts-D1QUdWfh.js} +1 -1
  12. package/dist/client/assets/createLucideIcon-CMLcIxOz.js +1 -0
  13. package/dist/client/assets/data-sources-DI5W9oVq.js +1 -0
  14. package/dist/client/assets/discuss-t2QxXK0h.js +1 -0
  15. package/dist/client/assets/dms-DjyXURaJ.js +1 -0
  16. package/dist/client/assets/inbox-CkHVoykL.js +1 -0
  17. package/dist/client/assets/index-BR860w88.js +31 -0
  18. package/dist/client/assets/likes-CenHqxQG.js +1 -0
  19. package/dist/client/assets/links-lDqy93u8.js +1 -0
  20. package/dist/client/assets/mapbox-CVPXIYUZ.js +2 -0
  21. package/dist/client/assets/{mapbox-gl-CPemBIlO.js → mapbox-gl-DRRiLKWb.js} +1 -1
  22. package/dist/client/assets/{mentions-DBrY-UPg.js → mentions-B6BXntri.js} +1 -1
  23. package/dist/client/assets/network-map-BCUtBk8G.js +2 -0
  24. package/dist/client/assets/profile-analyze-YExKd6Lx.js +1 -0
  25. package/dist/client/assets/{profile-hydration-client-BNe0sUmK.js → profile-hydration-client-BQyC5--e.js} +1 -1
  26. package/dist/client/assets/profiles._handle-idhd3kYo.js +1 -0
  27. package/dist/client/assets/query-client-DZ5C7UNo.js +17 -0
  28. package/dist/client/assets/rate-limits-jGxIfvUD.js +1 -0
  29. package/dist/client/assets/react-BwGzW7mM.js +1 -0
  30. package/dist/client/assets/react-dom-DEMAB80t.js +1 -0
  31. package/dist/client/assets/{repeat-2-xCwHM9hD.js → repeat-2-CQ0lek01.js} +1 -1
  32. package/dist/client/assets/rolldown-runtime-B-9mzPXz.js +1 -0
  33. package/dist/client/assets/{routes-Bl-Lw2hN.js → routes-6U4Cc79j.js} +1 -1
  34. package/dist/client/assets/schemas-CntsNLmN.js +64 -0
  35. package/dist/client/assets/search-C_LqodNa.js +1 -0
  36. package/dist/client/assets/{sparkles-CQVlvHsZ.js → sparkles-Gx_BHkDX.js} +1 -1
  37. package/dist/client/assets/{styles-zihNNCGg.css → styles-DT4Pxoi-.css} +1 -1
  38. package/dist/client/assets/today-COmNSYaE.js +1 -0
  39. package/dist/client/assets/{triangle-alert-CBL7s2pf.js → triangle-alert-DJPCW6jQ.js} +1 -1
  40. package/dist/client/assets/useTimelineRouteData-BpQzU16P.js +1 -0
  41. package/dist/client/assets/{users-CHbKlqUr.js → users-DI3w8Mol.js} +1 -1
  42. package/dist/server/assets/{_tanstack-start-manifest_v-CVfs07C8.js → _tanstack-start-manifest_v-mm-2VYBo.js} +35 -35
  43. package/dist/server/assets/{empty-plugin-adapters-DzrEkdBF.js → empty-plugin-adapters-D9UWiqvJ.js} +1 -1
  44. package/dist/server/assets/{router-D8AUR_Gz.js → router-B874XqWN.js} +708 -689
  45. package/dist/server/assets/start-5Z2QO8AU.js +4 -0
  46. package/dist/server/server.js +50 -3413
  47. package/package.json +1 -1
  48. package/dist/client/assets/AvatarChip-BN3b4MhM.js +0 -1
  49. package/dist/client/assets/ProfilePreview-CHbT0U9a.js +0 -1
  50. package/dist/client/assets/SavedTimelineView-mGXE9EYJ.js +0 -1
  51. package/dist/client/assets/SmartTimestamp-DG8XJKUz.js +0 -1
  52. package/dist/client/assets/TimelineRouteFrame-BmMC7qLj.js +0 -1
  53. package/dist/client/assets/blocks-CawnB0mN.js +0 -1
  54. package/dist/client/assets/chunk-C0phanGV.js +0 -1
  55. package/dist/client/assets/circle-check-C_Vq3ElD.js +0 -1
  56. package/dist/client/assets/createLucideIcon-JV8isFFR.js +0 -1
  57. package/dist/client/assets/data-sources-BJUT2qaO.js +0 -1
  58. package/dist/client/assets/discuss-DMPJVaRk.js +0 -1
  59. package/dist/client/assets/dms-BfPFG4Qr.js +0 -1
  60. package/dist/client/assets/inbox-DmeYJ7tt.js +0 -1
  61. package/dist/client/assets/index-Bqmo4MbK.js +0 -31
  62. package/dist/client/assets/likes-BxVL-j_C.js +0 -1
  63. package/dist/client/assets/links-BeA1Wt8F.js +0 -1
  64. package/dist/client/assets/mapbox-BTSMNSry.js +0 -2
  65. package/dist/client/assets/network-map-MqbE164r.js +0 -2
  66. package/dist/client/assets/profile-analyze-DEA75Reh.js +0 -1
  67. package/dist/client/assets/profiles._handle-K34ofz9U.js +0 -1
  68. package/dist/client/assets/query-client-DUP1ZzP7.js +0 -17
  69. package/dist/client/assets/rate-limits-B8Wmpt9r.js +0 -1
  70. package/dist/client/assets/react-dom-DHl6Ug7F.js +0 -1
  71. package/dist/client/assets/react-nBylq1U5.js +0 -1
  72. package/dist/client/assets/schemas-CaALBBpc.js +0 -64
  73. package/dist/client/assets/search-Dq5kYsxA.js +0 -1
  74. package/dist/client/assets/today-DFvZ0Ys5.js +0 -1
  75. package/dist/client/assets/useTimelineRouteData-Cpf-Jqsx.js +0 -1
  76. package/dist/server/assets/start-FaDOTmto.js +0 -4
@@ -22,7 +22,7 @@ import { Readable } from "node:stream";
22
22
  import nodeHTTPS from "node:https";
23
23
  import { Bell, Bookmark, CalendarDays, Check, ChevronDown, Database, Gauge, Globe2, Heart, Home, Inbox, Link as Link$1, Mail, MessagesSquare, Monitor, Moon, ShieldOff, Sun, UserSearch } from "lucide-react";
24
24
  import { useQuery } from "@tanstack/react-query";
25
- import { Data, Effect } from "effect";
25
+ import { Data, Duration, Effect, Schedule } from "effect";
26
26
  import { z } from "zod";
27
27
  import { flushSync } from "react-dom";
28
28
  import { createHash, randomUUID } from "node:crypto";
@@ -521,7 +521,7 @@ function AppNav({ compact = false }) {
521
521
  }
522
522
  //#endregion
523
523
  //#region src/styles.css?url
524
- var styles_default = "/assets/styles-zihNNCGg.css";
524
+ var styles_default = "/assets/styles-DT4Pxoi-.css";
525
525
  //#endregion
526
526
  //#region src/routes/__root.tsx
527
527
  var Route$24 = createRootRoute({
@@ -598,7 +598,7 @@ var $$splitComponentImporter = () => import("./routes-D9226vKz.js");
598
598
  var Route$18 = createFileRoute("/")({ component: lazyRouteComponent($$splitComponentImporter, "component") });
599
599
  //#endregion
600
600
  //#region src/lib/http-effect.ts
601
- var LOCAL_HOSTS = new Set([
601
+ var LOCAL_HOSTS = /* @__PURE__ */ new Set([
602
602
  "localhost",
603
603
  "127.0.0.1",
604
604
  "::1",
@@ -2565,7 +2565,7 @@ function yearFromTimestamp(value) {
2565
2565
  function pathLeaf(relativePath) {
2566
2566
  return relativePath.split("/").at(-1) ?? "";
2567
2567
  }
2568
- var JSON_URL_KEYS = new Set([
2568
+ var JSON_URL_KEYS = /* @__PURE__ */ new Set([
2569
2569
  "url",
2570
2570
  "expandedUrl",
2571
2571
  "expanded_url",
@@ -3518,7 +3518,7 @@ function adaptLegacyTweetState(schemaVersion, tweets, collections, timelineEdges
3518
3518
  const nextTimelineEdges = [...timelineEdges];
3519
3519
  const collectionKeys = new Set(collections.map((row) => `${String(row.account_id)}\0${String(row.tweet_id)}\0${String(row.kind)}`));
3520
3520
  const edgeKeys = new Set(timelineEdges.map((row) => `${String(row.account_id)}\0${String(row.tweet_id)}\0${String(row.kind)}`));
3521
- const edgeKinds = new Set([
3521
+ const edgeKinds = /* @__PURE__ */ new Set([
3522
3522
  "home",
3523
3523
  "mention",
3524
3524
  "authored",
@@ -5086,33 +5086,62 @@ function makeBirdStdoutTempEffect() {
5086
5086
  force: true
5087
5087
  })));
5088
5088
  }
5089
- function runBirdJsonCommandEffect$1(args, timeoutMs) {
5090
- return Effect.scoped(Effect.gen(function* () {
5091
- const birdCommand = yield* Effect.try({
5092
- try: () => getBirdCommand(),
5093
- catch: (error) => error instanceof Error ? error : new Error(String(error))
5094
- });
5095
- const { stdoutPath } = yield* makeBirdStdoutTempEffect();
5096
- yield* Effect.tryPromise({
5097
- try: () => execFileAsync("/bin/bash", [
5098
- "-c",
5099
- BIRD_STDOUT_REDIRECT_SCRIPT,
5100
- "birdclaw-bird",
5101
- stdoutPath,
5102
- birdCommand,
5103
- ...args
5104
- ], {
5105
- maxBuffer: BIRD_JSON_MAX_BUFFER_BYTES,
5106
- timeout: timeoutMs
5107
- }),
5108
- catch: (error) => formatBirdCommandError(error, birdCommand)
5109
- });
5110
- return yield* Effect.try({
5111
- try: () => readFileSync(stdoutPath, "utf8"),
5112
- catch: (error) => error
5113
- });
5114
- }));
5115
- }
5089
+ var runBirdJsonCommandEffect$1 = Effect.fn("bird.runJsonCommand")((args, timeoutMs) => Effect.scoped(Effect.gen(function* () {
5090
+ const birdCommand = yield* Effect.try({
5091
+ try: () => getBirdCommand(),
5092
+ catch: (error) => error instanceof Error ? error : new Error(String(error))
5093
+ });
5094
+ const { stdoutPath } = yield* makeBirdStdoutTempEffect();
5095
+ yield* Effect.tryPromise({
5096
+ try: () => execFileAsync("/bin/bash", [
5097
+ "-c",
5098
+ BIRD_STDOUT_REDIRECT_SCRIPT,
5099
+ "birdclaw-bird",
5100
+ stdoutPath,
5101
+ birdCommand,
5102
+ ...args
5103
+ ], {
5104
+ maxBuffer: BIRD_JSON_MAX_BUFFER_BYTES,
5105
+ timeout: timeoutMs
5106
+ }),
5107
+ catch: (error) => formatBirdCommandError(error, birdCommand)
5108
+ });
5109
+ return yield* Effect.try({
5110
+ try: () => readFileSync(stdoutPath, "utf8"),
5111
+ catch: (error) => error
5112
+ });
5113
+ })));
5114
+ var runBirdJsonCommandAllowFailureEffect = Effect.fn("bird.runJsonCommandAllowFailure")((args, timeoutMs) => Effect.scoped(Effect.gen(function* () {
5115
+ const birdCommand = yield* Effect.try({
5116
+ try: () => getBirdCommand(),
5117
+ catch: (error) => error instanceof Error ? error : new Error(String(error))
5118
+ });
5119
+ const { stdoutPath } = yield* makeBirdStdoutTempEffect();
5120
+ yield* Effect.tryPromise({
5121
+ try: () => execFileAsync("/bin/bash", [
5122
+ "-c",
5123
+ BIRD_STDOUT_REDIRECT_SCRIPT,
5124
+ "birdclaw-bird",
5125
+ stdoutPath,
5126
+ birdCommand,
5127
+ ...args
5128
+ ], {
5129
+ maxBuffer: BIRD_JSON_MAX_BUFFER_BYTES,
5130
+ timeout: timeoutMs
5131
+ }).catch((error) => {
5132
+ if (readFileSync(stdoutPath, "utf8").trim().length > 0) return {
5133
+ stdout: "",
5134
+ stderr: ""
5135
+ };
5136
+ throw formatBirdCommandError(error, birdCommand);
5137
+ }),
5138
+ catch: (error) => error
5139
+ });
5140
+ return yield* Effect.try({
5141
+ try: () => readFileSync(stdoutPath, "utf8"),
5142
+ catch: (error) => error
5143
+ });
5144
+ })));
5116
5145
  function runBirdTweetJsonCommandEffect(args, timeoutMs) {
5117
5146
  return runBirdJsonCommandEffect$1([...args, "--json-full"], timeoutMs).pipe(Effect.catchAll((error) => {
5118
5147
  if (!isUnsupportedBirdOptionError(error, "--json-full")) return Effect.fail(error);
@@ -5124,6 +5153,13 @@ function getBirdTweetItems(payload, command) {
5124
5153
  if (payload && typeof payload === "object" && Array.isArray(payload.tweets)) return payload.tweets;
5125
5154
  throw new Error(`bird ${command} returned unexpected JSON`);
5126
5155
  }
5156
+ function getBirdTweetItem(payload, command) {
5157
+ if (payload && typeof payload === "object") {
5158
+ const record = payload;
5159
+ if (typeof record.id === "string" && record.id.length > 0) return payload;
5160
+ }
5161
+ throw new Error(`bird ${command} returned unexpected JSON`);
5162
+ }
5127
5163
  function toMediaEntities(media) {
5128
5164
  if (!Array.isArray(media) || media.length === 0) return;
5129
5165
  return { urls: media.filter((item) => typeof item?.url === "string" && item.url.length > 0).map((item, index) => ({
@@ -5259,29 +5295,31 @@ function normalizeBirdTweetsPayloadEffect(payload, command) {
5259
5295
  catch: (error) => error
5260
5296
  });
5261
5297
  }
5262
- function listMentionsViaBirdEffect({ maxResults }) {
5263
- return Effect.gen(function* () {
5264
- return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect([
5265
- "mentions",
5266
- "-n",
5267
- String(maxResults)
5268
- ])), "mentions");
5269
- });
5270
- }
5271
- function listTweetsViaBirdCommandEffect({ command, maxResults, all, maxPages }) {
5272
- return Effect.gen(function* () {
5273
- const args = [
5274
- command,
5275
- "-n",
5276
- String(maxResults)
5277
- ];
5278
- if (all) {
5279
- args.push("--all");
5280
- if (maxPages !== void 0) args.push("--max-pages", String(maxPages));
5281
- }
5282
- return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args)), command);
5298
+ function normalizeBirdTweetItemEffect(payload, command) {
5299
+ return Effect.try({
5300
+ try: () => getBirdTweetItem(payload, command),
5301
+ catch: (error) => error
5283
5302
  });
5284
5303
  }
5304
+ var listMentionsViaBirdEffect = Effect.fn("bird.listMentions")(function* ({ maxResults }) {
5305
+ return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect([
5306
+ "mentions",
5307
+ "-n",
5308
+ String(maxResults)
5309
+ ])), "mentions");
5310
+ });
5311
+ var listTweetsViaBirdCommandEffect = Effect.fn("bird.listTweets")(function* ({ command, maxResults, all, maxPages }) {
5312
+ const args = [
5313
+ command,
5314
+ "-n",
5315
+ String(maxResults)
5316
+ ];
5317
+ if (all) {
5318
+ args.push("--all");
5319
+ if (maxPages !== void 0) args.push("--max-pages", String(maxPages));
5320
+ }
5321
+ return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args)), command);
5322
+ });
5285
5323
  function listLikedTweetsViaBirdEffect(options) {
5286
5324
  return listTweetsViaBirdCommandEffect({
5287
5325
  command: "likes",
@@ -5294,30 +5332,32 @@ function listBookmarkedTweetsViaBirdEffect(options) {
5294
5332
  ...options
5295
5333
  });
5296
5334
  }
5297
- function searchTweetsViaBirdEffect(query, options) {
5298
- return Effect.gen(function* () {
5299
- const args = [
5300
- "search",
5301
- query,
5302
- "-n",
5303
- String(options.maxResults)
5304
- ];
5305
- if (options.all) args.push("--all");
5306
- if (options.all && options.maxPages !== void 0) args.push("--max-pages", String(options.maxPages));
5307
- return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args)), "search");
5308
- });
5309
- }
5310
- function listHomeTimelineViaBirdEffect({ maxResults, following = true }) {
5311
- return Effect.gen(function* () {
5312
- const args = [
5313
- "home",
5314
- "-n",
5315
- String(maxResults)
5316
- ];
5317
- if (following) args.push("--following");
5318
- return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args)), "home");
5319
- });
5320
- }
5335
+ var searchTweetsViaBirdEffect = Effect.fn("bird.searchTweets")(function* (query, options) {
5336
+ const args = [
5337
+ "search",
5338
+ query,
5339
+ "-n",
5340
+ String(options.maxResults)
5341
+ ];
5342
+ if (options.all) args.push("--all");
5343
+ if (options.all && options.maxPages !== void 0) args.push("--max-pages", String(options.maxPages));
5344
+ return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args)), "search");
5345
+ });
5346
+ Effect.fn("bird.lookupTweetsByIds")(function* (ids) {
5347
+ if (ids.length === 0) return { data: [] };
5348
+ return normalizeBirdTweets(yield* Effect.forEach(ids, Effect.fn("bird.readTweet")(function* (id) {
5349
+ return yield* normalizeBirdTweetItemEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(["read", id])), "read");
5350
+ }), { concurrency: "unbounded" }));
5351
+ });
5352
+ var listHomeTimelineViaBirdEffect = Effect.fn("bird.listHomeTimeline")(function* ({ maxResults, following = true }) {
5353
+ const args = [
5354
+ "home",
5355
+ "-n",
5356
+ String(maxResults)
5357
+ ];
5358
+ if (following) args.push("--following");
5359
+ return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args)), "home");
5360
+ });
5321
5361
  function normalizeBirdFollowUsers(payload, command, maxResults) {
5322
5362
  const rawPayload = payload;
5323
5363
  const users = Array.isArray(rawPayload) ? rawPayload : rawPayload.users;
@@ -5341,28 +5381,81 @@ function normalizeBirdFollowUsersEffect(payload, command, maxResults) {
5341
5381
  catch: (error) => error
5342
5382
  });
5343
5383
  }
5344
- function listFollowUsersViaBirdEffect({ direction, userId, maxResults, all, maxPages }) {
5345
- return Effect.gen(function* () {
5346
- const args = [
5347
- direction,
5348
- "-n",
5349
- String(maxResults),
5350
- "--json"
5351
- ];
5352
- if (userId) args.push("--user", userId);
5353
- if (all) args.push("--all");
5354
- if (maxPages !== void 0) args.push("--max-pages", String(maxPages));
5355
- return yield* normalizeBirdFollowUsersEffect(yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1(args)), direction, maxResults);
5356
- });
5384
+ var listFollowUsersViaBirdEffect = Effect.fn("bird.listFollowUsers")(function* ({ direction, userId, maxResults, all, maxPages }) {
5385
+ const args = [
5386
+ direction,
5387
+ "-n",
5388
+ String(maxResults),
5389
+ "--json"
5390
+ ];
5391
+ if (userId) args.push("--user", userId);
5392
+ if (all) args.push("--all");
5393
+ if (maxPages !== void 0) args.push("--max-pages", String(maxPages));
5394
+ return yield* normalizeBirdFollowUsersEffect(yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1(args)), direction, maxResults);
5395
+ });
5396
+ function normalizeBirdLists(payload) {
5397
+ if (!Array.isArray(payload)) throw new Error("bird lists returned unexpected JSON");
5398
+ const data = payload.map((value) => {
5399
+ const item = value;
5400
+ if (!item.id || !item.name) return null;
5401
+ return {
5402
+ id: item.id,
5403
+ name: item.name,
5404
+ ...item.description ? { description: item.description } : {},
5405
+ ...typeof item.memberCount === "number" ? { memberCount: item.memberCount } : {},
5406
+ ...typeof item.subscriberCount === "number" ? { followerCount: item.subscriberCount } : {},
5407
+ ...typeof item.isPrivate === "boolean" ? { isPrivate: item.isPrivate } : {},
5408
+ ...item.owner?.id ? { ownerId: item.owner.id } : {},
5409
+ ...item.owner?.username ? { ownerUsername: item.owner.username } : {},
5410
+ ...item.owner?.name ? { ownerName: item.owner.name } : {},
5411
+ ...item.createdAt ? { createdAt: item.createdAt } : {},
5412
+ raw: value
5413
+ };
5414
+ }).filter((item) => Boolean(item));
5415
+ return {
5416
+ data,
5417
+ meta: {
5418
+ result_count: data.length,
5419
+ next_token: null
5420
+ }
5421
+ };
5357
5422
  }
5358
- function listThreadViaBirdEffect({ tweetId, all, maxPages, timeoutMs }) {
5359
- return Effect.gen(function* () {
5360
- const args = ["thread", tweetId];
5361
- if (all) args.push("--all");
5362
- if (maxPages !== void 0) args.push("--max-pages", String(maxPages));
5363
- return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args, timeoutMs)), "thread");
5423
+ Effect.fn("bird.listOwnedXLists")(function* ({ maxResults }) {
5424
+ const payload = yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1([
5425
+ "lists",
5426
+ "-n",
5427
+ String(maxResults),
5428
+ "--json"
5429
+ ]));
5430
+ return yield* Effect.try({
5431
+ try: () => normalizeBirdLists(payload),
5432
+ catch: (error) => error
5364
5433
  });
5365
- }
5434
+ });
5435
+ Effect.fn("bird.listXListMembers")(function* ({ listId, maxResults, maxPages = 1 }) {
5436
+ const args = [
5437
+ "list-members",
5438
+ listId,
5439
+ "-n",
5440
+ String(maxResults),
5441
+ "--json"
5442
+ ];
5443
+ if (maxPages > 1) args.push("--all", "--max-pages", String(maxPages));
5444
+ const payload = yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1(args));
5445
+ const normalized = yield* normalizeBirdFollowUsersEffect(payload, "list-members", maxResults);
5446
+ if (Array.isArray(payload)) normalized.meta = {
5447
+ ...normalized.meta,
5448
+ pagination_known_complete: false,
5449
+ pagination_inferred_complete: normalized.data.length < maxResults
5450
+ };
5451
+ return normalized;
5452
+ });
5453
+ var listThreadViaBirdEffect = Effect.fn("bird.listThread")(function* ({ tweetId, all, maxPages, timeoutMs }) {
5454
+ const args = ["thread", tweetId];
5455
+ if (all) args.push("--all");
5456
+ if (maxPages !== void 0) args.push("--max-pages", String(maxPages));
5457
+ return yield* normalizeBirdTweetsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdTweetJsonCommandEffect(args, timeoutMs)), "thread");
5458
+ });
5366
5459
  function normalizeBirdDmsPayloadEffect(payload) {
5367
5460
  return Effect.try({
5368
5461
  try: () => {
@@ -5388,51 +5481,60 @@ function parseBirdWhoami(stdout) {
5388
5481
  ...name ? { name } : {}
5389
5482
  };
5390
5483
  }
5391
- function getAuthenticatedBirdAccountEffect() {
5392
- return Effect.gen(function* () {
5393
- const stdout = yield* runBirdJsonCommandEffect$1(["whoami"]);
5394
- return yield* Effect.try({
5395
- try: () => parseBirdWhoami(stdout),
5396
- catch: (error) => error
5397
- });
5484
+ var getAuthenticatedBirdAccountEffect = Effect.fn("bird.getAuthenticatedAccount")(function* () {
5485
+ const stdout = yield* runBirdJsonCommandEffect$1(["whoami"]);
5486
+ return yield* Effect.try({
5487
+ try: () => parseBirdWhoami(stdout),
5488
+ catch: (error) => error
5398
5489
  });
5399
- }
5400
- function listDirectMessagesViaBirdEffect({ maxResults, inbox = "all", maxPages, allPages = false, pageDelayMs }) {
5401
- return Effect.gen(function* () {
5402
- const args = [
5403
- "dms",
5404
- "-n",
5405
- String(maxResults),
5406
- "--json"
5407
- ];
5408
- if (inbox !== "all") args.push("--inbox", inbox);
5490
+ });
5491
+ var listDirectMessagesViaBirdEffect = Effect.fn("bird.listDirectMessages")(function* ({ maxResults, inbox = "all", maxPages, allPages = false, pageDelayMs }) {
5492
+ const args = [
5493
+ "dms",
5494
+ "-n",
5495
+ String(maxResults),
5496
+ "--json"
5497
+ ];
5498
+ if (inbox !== "all") args.push("--inbox", inbox);
5499
+ if (allPages) args.push("--all-pages");
5500
+ else if (typeof maxPages === "number") args.push("--max-pages", String(maxPages));
5501
+ if (typeof pageDelayMs === "number" && pageDelayMs > 0) args.push("--page-delay-ms", String(pageDelayMs));
5502
+ return yield* normalizeBirdDmsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1(args)));
5503
+ });
5504
+ Effect.fn("bird.runDirectMessageRequestMutation")(function* ({ action, conversationId, maxPages, allPages = false }) {
5505
+ const command = action === "accept" ? "dm-accept" : action === "reject" ? "dm-reject" : "dm-block";
5506
+ const args = [
5507
+ command,
5508
+ conversationId,
5509
+ "--json"
5510
+ ];
5511
+ if (action === "block") {
5409
5512
  if (allPages) args.push("--all-pages");
5410
5513
  else if (typeof maxPages === "number") args.push("--max-pages", String(maxPages));
5411
- if (typeof pageDelayMs === "number" && pageDelayMs > 0) args.push("--page-delay-ms", String(pageDelayMs));
5412
- return yield* normalizeBirdDmsPayloadEffect(yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1(args)));
5413
- });
5414
- }
5415
- function lookupProfileViaBirdEffect$1(usernameOrId) {
5416
- return Effect.gen(function* () {
5417
- const target = usernameOrId.trim().replace(/^@/, "");
5418
- if (!target) return null;
5419
- return toXurlMentionUser((yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1([
5514
+ }
5515
+ const payload = yield* parseBirdJsonEffect(yield* runBirdJsonCommandAllowFailureEffect(args));
5516
+ if (payload && typeof payload === "object" && typeof payload.success === "boolean") return payload;
5517
+ throw new Error(`bird ${command} returned unexpected JSON`);
5518
+ });
5519
+ var lookupProfileViaBirdEffect$1 = Effect.fn("bird.lookupProfile")(function* (usernameOrId) {
5520
+ const target = usernameOrId.trim().replace(/^@/, "");
5521
+ if (!target) return null;
5522
+ return toXurlMentionUser((yield* parseBirdJsonEffect(yield* runBirdJsonCommandEffect$1([
5523
+ "user",
5524
+ target,
5525
+ "--json",
5526
+ "--profile-only"
5527
+ ]).pipe(Effect.catchAll((error) => {
5528
+ if (!isUnsupportedBirdOptionError(error, "--profile-only")) return Effect.fail(error);
5529
+ return runBirdJsonCommandEffect$1([
5420
5530
  "user",
5421
5531
  target,
5422
5532
  "--json",
5423
- "--profile-only"
5424
- ]).pipe(Effect.catchAll((error) => {
5425
- if (!isUnsupportedBirdOptionError(error, "--profile-only")) return Effect.fail(error);
5426
- return runBirdJsonCommandEffect$1([
5427
- "user",
5428
- target,
5429
- "--json",
5430
- "--count",
5431
- "1"
5432
- ]);
5433
- })))).user);
5434
- });
5435
- }
5533
+ "--count",
5534
+ "1"
5535
+ ]);
5536
+ })))).user);
5537
+ });
5436
5538
  function toXurlMentionUser(user) {
5437
5539
  if (!user?.id || !user.username) return null;
5438
5540
  return {
@@ -5454,7 +5556,7 @@ function toXurlMentionUser(user) {
5454
5556
  }
5455
5557
  };
5456
5558
  }
5457
- function lookupProfilesViaBirdEffect(usernameOrIds) {
5559
+ var lookupProfilesViaBirdEffect = Effect.fn("bird.lookupProfiles")((usernameOrIds) => {
5458
5560
  const targets = Array.from(new Set(usernameOrIds.map((target) => target.trim().replace(/^@/, "")).filter((target) => target.length > 0)));
5459
5561
  if (targets.length === 0) return Effect.succeed([]);
5460
5562
  return runBirdJsonCommandEffect$1([
@@ -5486,7 +5588,7 @@ function lookupProfilesViaBirdEffect(usernameOrIds) {
5486
5588
  error: lookupError instanceof Error ? lookupError.message : String(lookupError)
5487
5589
  }))), { concurrency: "unbounded" });
5488
5590
  }));
5489
- }
5591
+ });
5490
5592
  //#endregion
5491
5593
  //#region src/lib/xurl.ts
5492
5594
  var TRANSPORT_STATUS_TTL_MS = 5 * 6e4;
@@ -5499,8 +5601,8 @@ var RICH_USER_FIELDS = "description,entities,location,public_metrics,profile_ima
5499
5601
  var DM_EVENT_FIELDS = "attachments,created_at,dm_conversation_id,entities,event_type,id,participant_ids,referenced_tweets,sender_id,text";
5500
5602
  var THREAD_TWEET_FIELDS = "created_at,conversation_id,entities,public_metrics,referenced_tweets,in_reply_to_user_id,attachments";
5501
5603
  var BOOKMARKS_MAX_RESULTS_CAP = 90;
5502
- var transportStatusCache;
5503
- var authenticatedUserCache;
5604
+ var cachedTransportStatus = Effect.runSync(Effect.cachedWithTTL(Effect.suspend(() => readTransportStatusEffect()), Duration.millis(TRANSPORT_STATUS_TTL_MS)));
5605
+ var [cachedAuthenticatedUser, invalidateAuthenticatedUser] = Effect.runSync(Effect.cachedInvalidateWithTTL(Effect.suspend(() => lookupAuthenticatedUserFreshEffect()), Duration.millis(AUTHENTICATED_USER_TTL_MS)));
5504
5606
  var oauth2CandidateCache = /* @__PURE__ */ new Map();
5505
5607
  function liveWritesDisabled$3() {
5506
5608
  return process.env.BIRDCLAW_DISABLE_LIVE_WRITES === "1";
@@ -5522,8 +5624,15 @@ function formatExecError$1(error, fallback) {
5522
5624
  if ("stderr" in error && typeof error.stderr === "string" && error.stderr.trim().length > 0) parts.push(stripAnsi$1(error.stderr).trim());
5523
5625
  return parts.join("\n");
5524
5626
  }
5525
- function formatXurlCommandError(error, args) {
5526
- return new Error(formatExecError$1(error, `xurl ${args.join(" ")} failed`));
5627
+ var XurlCommandError = class extends Data.TaggedError("XurlCommandError") {};
5628
+ function toXurlCommandError(cause, args) {
5629
+ if (cause instanceof XurlCommandError) return cause;
5630
+ return new XurlCommandError({
5631
+ message: formatExecError$1(cause, `xurl ${args.join(" ")} failed`),
5632
+ commandArgs: args,
5633
+ rateLimited: isRateLimitedFailure(cause),
5634
+ cause
5635
+ });
5527
5636
  }
5528
5637
  function normalizeError(error) {
5529
5638
  return error instanceof Error ? error : new Error(String(error));
@@ -5539,11 +5648,11 @@ function parseErrorPayload(error) {
5539
5648
  return null;
5540
5649
  }
5541
5650
  }
5542
- function getRetryDelayMs(error, attempt) {
5543
- const payload = parseErrorPayload(error);
5544
- if (Number(payload?.status ?? 0) !== 429) return null;
5545
- const baseDelay = getJsonRetryBaseDelayMs();
5546
- return Math.min(baseDelay * 2 ** attempt, 3e4);
5651
+ function isRateLimitedFailure(error) {
5652
+ return Number(parseErrorPayload(error)?.status ?? 0) === 429;
5653
+ }
5654
+ function jsonRetryDelayMs(retries) {
5655
+ return Math.min(getJsonRetryBaseDelayMs() * 2 ** retries, 3e4);
5547
5656
  }
5548
5657
  function emitJsonCommandAttempt(options, attempt) {
5549
5658
  try {
@@ -5562,93 +5671,60 @@ function hasXurlEffect() {
5562
5671
  function isUnauthenticatedXurlStatus(status) {
5563
5672
  return /no apps registered|no authenticated user|not authenticated|not logged in/i.test(status);
5564
5673
  }
5565
- function readTransportStatusEffect() {
5566
- return Effect.gen(function* () {
5567
- if (!(yield* hasXurlEffect())) return {
5568
- installed: false,
5569
- availableTransport: "local",
5570
- statusText: "xurl not installed. local mode active."
5571
- };
5572
- return yield* runSubprocessEffect({
5573
- command: "xurl",
5574
- args: ["auth", "status"]
5575
- }).pipe(Effect.map(({ stdout }) => {
5576
- const rawStatus = stdout.trim();
5577
- if (isUnauthenticatedXurlStatus(rawStatus)) return {
5578
- installed: true,
5579
- availableTransport: "local",
5580
- statusText: "xurl installed but not authenticated. local (bird) mode active.",
5581
- rawStatus
5582
- };
5583
- return {
5584
- installed: true,
5585
- availableTransport: "xurl",
5586
- statusText: "xurl available",
5587
- rawStatus
5588
- };
5589
- }), Effect.catchAll((error) => Effect.succeed({
5674
+ var readTransportStatusEffect = Effect.fn("xurl.readTransportStatus")(function* () {
5675
+ if (!(yield* hasXurlEffect())) return {
5676
+ installed: false,
5677
+ availableTransport: "local",
5678
+ statusText: "xurl not installed. local mode active."
5679
+ };
5680
+ return yield* runSubprocessEffect({
5681
+ command: "xurl",
5682
+ args: ["auth", "status"]
5683
+ }).pipe(Effect.map(({ stdout }) => {
5684
+ const rawStatus = stdout.trim();
5685
+ if (isUnauthenticatedXurlStatus(rawStatus)) return {
5590
5686
  installed: true,
5591
5687
  availableTransport: "local",
5592
- statusText: `xurl detected but auth unavailable: ${error instanceof Error && !(error instanceof SubprocessError && !error.causeWasError) ? error.message : "unknown error"}`
5593
- })));
5594
- });
5595
- }
5596
- function getTransportStatusEffect() {
5597
- return Effect.gen(function* () {
5598
- const now = Date.now();
5599
- if (transportStatusCache?.value && transportStatusCache.expiresAt > now) return transportStatusCache.value;
5600
- if (transportStatusCache?.pending) {
5601
- const status = yield* Effect.tryPromise({
5602
- try: () => transportStatusCache?.pending ?? Promise.resolve(void 0),
5603
- catch: normalizeError
5604
- });
5605
- if (status) return status;
5606
- }
5607
- const pending = runEffectPromise(readTransportStatusEffect());
5608
- transportStatusCache = {
5609
- expiresAt: 0,
5610
- pending
5688
+ statusText: "xurl installed but not authenticated. local (bird) mode active.",
5689
+ rawStatus
5611
5690
  };
5612
- const status = yield* Effect.tryPromise({
5613
- try: () => pending,
5614
- catch: normalizeError
5615
- }).pipe(Effect.catchAll((error) => Effect.sync(() => {
5616
- transportStatusCache = void 0;
5617
- }).pipe(Effect.flatMap(() => Effect.fail(error)))));
5618
- transportStatusCache = {
5619
- expiresAt: Date.now() + TRANSPORT_STATUS_TTL_MS,
5620
- value: status
5691
+ return {
5692
+ installed: true,
5693
+ availableTransport: "xurl",
5694
+ statusText: "xurl available",
5695
+ rawStatus
5621
5696
  };
5622
- return status;
5623
- });
5624
- }
5625
- function getTransportStatus() {
5626
- return runEffectPromise(getTransportStatusEffect());
5697
+ }), Effect.catchAll((error) => Effect.succeed({
5698
+ installed: true,
5699
+ availableTransport: "local",
5700
+ statusText: `xurl detected but auth unavailable: ${error instanceof Error && !(error instanceof SubprocessError && !error.causeWasError) ? error.message : "unknown error"}`
5701
+ })));
5702
+ });
5703
+ function getTransportStatusEffect() {
5704
+ return cachedTransportStatus;
5627
5705
  }
5628
- function runShortcutEffect(args) {
5629
- return Effect.gen(function* () {
5630
- if (liveWritesDisabled$3()) {
5631
- if (e2eFakeLiveWritesEnabled$2()) return {
5632
- ok: true,
5633
- output: "e2e fake live write"
5634
- };
5635
- return {
5636
- ok: false,
5637
- output: "live writes disabled"
5638
- };
5639
- }
5640
- return yield* runSubprocessEffect({
5641
- command: "xurl",
5642
- args
5643
- }).pipe(Effect.map(({ stdout, stderr }) => ({
5706
+ var runShortcutEffect = Effect.fn("xurl.runShortcut")(function* (args) {
5707
+ if (liveWritesDisabled$3()) {
5708
+ if (e2eFakeLiveWritesEnabled$2()) return {
5644
5709
  ok: true,
5645
- output: stdout || stderr
5646
- })), Effect.catchAll((error) => Effect.succeed({
5710
+ output: "e2e fake live write"
5711
+ };
5712
+ return {
5647
5713
  ok: false,
5648
- output: formatExecError$1(error, "xurl execution failed")
5649
- })));
5650
- });
5651
- }
5714
+ output: "live writes disabled"
5715
+ };
5716
+ }
5717
+ return yield* runSubprocessEffect({
5718
+ command: "xurl",
5719
+ args
5720
+ }).pipe(Effect.map(({ stdout, stderr }) => ({
5721
+ ok: true,
5722
+ output: stdout || stderr
5723
+ })), Effect.catchAll((error) => Effect.succeed({
5724
+ ok: false,
5725
+ output: formatExecError$1(error, "xurl execution failed")
5726
+ })));
5727
+ });
5652
5728
  function execXurlJsonEffect(args, timeoutMs, signal) {
5653
5729
  return runSubprocessEffect({
5654
5730
  command: "xurl",
@@ -5679,35 +5755,31 @@ function execXurlTextEffect(args, deadlineMs) {
5679
5755
  function parseJsonPayloadEffect(stdout, args) {
5680
5756
  return Effect.try({
5681
5757
  try: () => JSON.parse(stdout),
5682
- catch: (error) => formatXurlCommandError(error, args)
5758
+ catch: (error) => toXurlCommandError(error, args)
5683
5759
  });
5684
5760
  }
5685
- function runJsonCommandEffect(args, options = {}, attempt = 0) {
5686
- return Effect.gen(function* () {
5687
- const deadlineMs = options.deadlineMs ?? (typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? Date.now() + options.timeoutMs : void 0);
5688
- return yield* execXurlJsonEffect(args, deadlineMs ? Math.max(0, deadlineMs - Date.now()) : void 0, options.signal).pipe(Effect.flatMap(({ stdout }) => parseJsonPayloadEffect(stdout, args)), Effect.tap(() => Effect.sync(() => emitJsonCommandAttempt(options, {
5761
+ var runJsonCommandEffect = Effect.fn("xurl.runJsonCommand")(function* (args, options = {}) {
5762
+ const deadlineMs = options.deadlineMs ?? (typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? Date.now() + options.timeoutMs : void 0);
5763
+ let attempt = 0;
5764
+ const attemptCommand = Effect.suspend(() => execXurlJsonEffect(args, deadlineMs === void 0 ? void 0 : Math.max(0, deadlineMs - Date.now()), options.signal)).pipe(Effect.flatMap(({ stdout }) => parseJsonPayloadEffect(stdout, args)), Effect.mapError((error) => toXurlCommandError(error, args)), Effect.tap(() => Effect.sync(() => emitJsonCommandAttempt(options, {
5765
+ args,
5766
+ attempt,
5767
+ status: "ok"
5768
+ }))), Effect.tapError((error) => Effect.sync(() => {
5769
+ emitJsonCommandAttempt(options, {
5689
5770
  args,
5690
5771
  attempt,
5691
- status: "ok"
5692
- }))), Effect.catchAll((error) => {
5693
- const retryDelayMs = getRetryDelayMs(error, attempt);
5694
- emitJsonCommandAttempt(options, {
5695
- args,
5696
- attempt,
5697
- status: retryDelayMs === null ? "error" : "rate_limited",
5698
- error
5699
- });
5700
- if (retryDelayMs === null || attempt >= JSON_RETRY_LIMIT - 1) return Effect.fail(formatXurlCommandError(error, args));
5701
- if (options.signal?.aborted) return Effect.fail(formatXurlCommandError(error, args));
5702
- const remainingMs = deadlineMs ? Math.max(0, deadlineMs - Date.now()) : void 0;
5703
- if (remainingMs !== void 0 && retryDelayMs >= remainingMs) return Effect.fail(formatXurlCommandError(error, args));
5704
- return Effect.sleep(retryDelayMs).pipe(Effect.flatMap(() => runJsonCommandEffect(args, {
5705
- ...options,
5706
- deadlineMs
5707
- }, attempt + 1)));
5708
- }));
5709
- });
5710
- }
5772
+ status: error.rateLimited ? "rate_limited" : "error",
5773
+ error
5774
+ });
5775
+ attempt += 1;
5776
+ })));
5777
+ const rateLimitRetries = Schedule.recurs(JSON_RETRY_LIMIT - 1).pipe(Schedule.whileInput((error) => error.rateLimited && options.signal?.aborted !== true), Schedule.check((_error, retries) => {
5778
+ if (deadlineMs === void 0) return true;
5779
+ return jsonRetryDelayMs(retries) < Math.max(0, deadlineMs - Date.now());
5780
+ }), Schedule.addDelay((retries) => Duration.millis(jsonRetryDelayMs(retries))));
5781
+ return yield* Effect.retry(attemptCommand, rateLimitRetries);
5782
+ });
5711
5783
  function cleanXurlUsernameLabel(username) {
5712
5784
  const label = username?.trim().replace(/^@/, "");
5713
5785
  return label && label !== "-" && label !== "–" && label !== "(none)" && label.toLowerCase() !== "none" && label.toLowerCase() !== "unknown" && /^[^\s]{1,128}$/.test(label) ? label : void 0;
@@ -5744,29 +5816,25 @@ function parseOAuth2UsernamesFromStatus(rawStatus) {
5744
5816
  }
5745
5817
  return usernames;
5746
5818
  }
5747
- function readOAuth2UsernameCandidatesEffect(deadlineMs) {
5748
- return execXurlTextEffect(["auth", "status"], deadlineMs).pipe(Effect.map(({ stdout }) => parseOAuth2UsernamesFromStatus(stdout)), Effect.catchAll(() => Effect.succeed([])));
5749
- }
5819
+ var readOAuth2UsernameCandidatesEffect = Effect.fn("xurl.readOAuth2UsernameCandidates")((deadlineMs) => execXurlTextEffect(["auth", "status"], deadlineMs).pipe(Effect.map(({ stdout }) => parseOAuth2UsernamesFromStatus(stdout)), Effect.catchAll(() => Effect.succeed([]))));
5750
5820
  function readXurlOAuth2AccountsEffect() {
5751
5821
  return readOAuth2UsernameCandidatesEffect().pipe(Effect.map((candidates) => candidates.map((candidate) => ({
5752
5822
  ...candidate.app ? { app: candidate.app } : {},
5753
5823
  ...candidate.username ? { username: candidate.username } : {}
5754
5824
  }))));
5755
5825
  }
5756
- function lookupOAuth2UsernameForAccountEffect(expectedUsername, attemptedUsernames, deadlineMs, knownCandidates) {
5757
- return Effect.gen(function* () {
5758
- const expected = comparableXurlUsername(expectedUsername);
5759
- if (!expected) return void 0;
5760
- const candidates = knownCandidates ?? (yield* readOAuth2UsernameCandidatesEffect(deadlineMs));
5761
- for (const candidate of candidates) {
5762
- const candidateKey = `${candidate.app ?? "default"}:${candidate.username}`;
5763
- if (attemptedUsernames.has(candidateKey)) continue;
5764
- const payload = yield* runJsonCommandEffect(oauth2ArgsForCandidate(candidate, ["/2/users/me"]), { deadlineMs }).pipe(Effect.catchAll(() => Effect.succeed(null)));
5765
- const user = payload ? authenticatedUserFromPayload(payload) : null;
5766
- if (comparableXurlUsername(String(user?.username ?? "")) === expected) return candidate;
5767
- }
5768
- });
5769
- }
5826
+ var lookupOAuth2UsernameForAccountEffect = Effect.fn("xurl.lookupOAuth2UsernameForAccount")(function* (expectedUsername, attemptedUsernames, deadlineMs, knownCandidates) {
5827
+ const expected = comparableXurlUsername(expectedUsername);
5828
+ if (!expected) return void 0;
5829
+ const candidates = knownCandidates ?? (yield* readOAuth2UsernameCandidatesEffect(deadlineMs));
5830
+ for (const candidate of candidates) {
5831
+ const candidateKey = `${candidate.app ?? "default"}:${candidate.username}`;
5832
+ if (attemptedUsernames.has(candidateKey)) continue;
5833
+ const payload = yield* runJsonCommandEffect(oauth2ArgsForCandidate(candidate, ["/2/users/me"]), { deadlineMs }).pipe(Effect.catchAll(() => Effect.succeed(null)));
5834
+ const user = payload ? authenticatedUserFromPayload(payload) : null;
5835
+ if (comparableXurlUsername(String(user?.username ?? "")) === expected) return candidate;
5836
+ }
5837
+ });
5770
5838
  function oauth2ArgsForCandidate(candidate, args) {
5771
5839
  return [
5772
5840
  ...candidate?.app ? ["--app", candidate.app] : [],
@@ -5787,88 +5855,136 @@ function configuredOAuth2Candidate(primaryUsername) {
5787
5855
  ...effectiveUsername ? { username: effectiveUsername } : {}
5788
5856
  };
5789
5857
  }
5790
- function runOAuth2JsonCommandEffect({ args, username, options, useConfiguredCandidate = true }) {
5858
+ var runOAuth2JsonCommandEffect = Effect.fn("xurl.runOAuth2JsonCommand")(function* ({ args, username, options, useConfiguredCandidate = true }) {
5791
5859
  const primaryUsername = cleanXurlUsernameLabel(username);
5792
- return Effect.gen(function* () {
5793
- const deadlineMs = options?.deadlineMs ?? (typeof options?.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? Date.now() + options.timeoutMs : void 0);
5794
- const scopedOptions = {
5795
- ...options,
5796
- deadlineMs
5797
- };
5798
- let authCandidate = primaryUsername ? { username: primaryUsername } : void 0;
5799
- const configuredCandidate = useConfiguredCandidate ? configuredOAuth2Candidate(primaryUsername) : void 0;
5800
- if (configuredCandidate) authCandidate = configuredCandidate;
5801
- else if (primaryUsername) {
5802
- const cacheKey = primaryUsername.toLowerCase();
5803
- const cachedCandidate = oauth2CandidateCache.get(cacheKey);
5804
- if (cachedCandidate && cachedCandidate.expiresAt > Date.now()) authCandidate = cachedCandidate.value;
5860
+ const deadlineMs = options?.deadlineMs ?? (typeof options?.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? Date.now() + options.timeoutMs : void 0);
5861
+ const scopedOptions = {
5862
+ ...options,
5863
+ deadlineMs
5864
+ };
5865
+ let authCandidate = primaryUsername ? { username: primaryUsername } : void 0;
5866
+ const configuredCandidate = useConfiguredCandidate ? configuredOAuth2Candidate(primaryUsername) : void 0;
5867
+ if (configuredCandidate) authCandidate = configuredCandidate;
5868
+ else if (primaryUsername) {
5869
+ const cacheKey = primaryUsername.toLowerCase();
5870
+ const cachedCandidate = oauth2CandidateCache.get(cacheKey);
5871
+ if (cachedCandidate && cachedCandidate.expiresAt > Date.now()) authCandidate = cachedCandidate.value;
5872
+ else {
5873
+ const candidates = yield* readOAuth2UsernameCandidatesEffect(deadlineMs);
5874
+ const primaryCandidates = candidates.filter((candidate) => candidate.username === primaryUsername);
5875
+ if (primaryCandidates.length === 1) authCandidate = primaryCandidates[0];
5876
+ else if (primaryCandidates.length > 1) authCandidate = (yield* lookupOAuth2UsernameForAccountEffect(primaryUsername, /* @__PURE__ */ new Set(), deadlineMs, candidates)) ?? primaryCandidates[0] ?? { username: primaryUsername };
5805
5877
  else {
5806
- const candidates = yield* readOAuth2UsernameCandidatesEffect(deadlineMs);
5807
- const primaryCandidates = candidates.filter((candidate) => candidate.username === primaryUsername);
5808
- if (primaryCandidates.length === 1) authCandidate = primaryCandidates[0];
5809
- else if (primaryCandidates.length > 1) authCandidate = (yield* lookupOAuth2UsernameForAccountEffect(primaryUsername, /* @__PURE__ */ new Set(), deadlineMs, candidates)) ?? primaryCandidates[0] ?? { username: primaryUsername };
5810
- else {
5811
- const fallbackUsername = yield* lookupOAuth2UsernameForAccountEffect(primaryUsername, /* @__PURE__ */ new Set(), deadlineMs, candidates);
5812
- if (fallbackUsername) authCandidate = fallbackUsername;
5813
- }
5814
- if (authCandidate) oauth2CandidateCache.set(cacheKey, {
5815
- expiresAt: Date.now() + AUTHENTICATED_USER_TTL_MS,
5816
- value: authCandidate
5817
- });
5878
+ const fallbackUsername = yield* lookupOAuth2UsernameForAccountEffect(primaryUsername, /* @__PURE__ */ new Set(), deadlineMs, candidates);
5879
+ if (fallbackUsername) authCandidate = fallbackUsername;
5818
5880
  }
5881
+ if (authCandidate) oauth2CandidateCache.set(cacheKey, {
5882
+ expiresAt: Date.now() + AUTHENTICATED_USER_TTL_MS,
5883
+ value: authCandidate
5884
+ });
5819
5885
  }
5820
- if (deadlineMs !== void 0 && Date.now() >= deadlineMs) return yield* Effect.fail(/* @__PURE__ */ new Error("xurl OAuth2 fallback timed out"));
5821
- return yield* runJsonCommandEffect(oauth2ArgsForCandidate(authCandidate, args), scopedOptions).pipe(Effect.catchAll((error) => {
5822
- if (!primaryUsername) return Effect.fail(error);
5823
- oauth2CandidateCache.delete(primaryUsername.toLowerCase());
5824
- const attempted = new Set([authCandidate ? `${authCandidate.app ?? "default"}:${authCandidate.username}` : `default:${primaryUsername}`]);
5825
- if (authCandidate?.username !== primaryUsername) attempted.add(`default:${primaryUsername}`);
5826
- return lookupOAuth2UsernameForAccountEffect(primaryUsername, attempted, deadlineMs).pipe(Effect.flatMap((fallbackUsername) => {
5827
- if (!fallbackUsername) return Effect.fail(error);
5828
- oauth2CandidateCache.set(primaryUsername.toLowerCase(), {
5829
- expiresAt: Date.now() + AUTHENTICATED_USER_TTL_MS,
5830
- value: fallbackUsername
5831
- });
5832
- return runJsonCommandEffect(oauth2ArgsForCandidate(fallbackUsername, args), scopedOptions);
5833
- }), Effect.catchAll(() => Effect.fail(error)));
5834
- }));
5886
+ }
5887
+ if (deadlineMs !== void 0 && Date.now() >= deadlineMs) return yield* new XurlCommandError({
5888
+ message: "xurl OAuth2 fallback timed out",
5889
+ commandArgs: args,
5890
+ rateLimited: false,
5891
+ cause: void 0
5835
5892
  });
5836
- }
5837
- function runMutationCommandEffect(args) {
5838
- return Effect.gen(function* () {
5839
- if (liveWritesDisabled$3()) {
5840
- if (e2eFakeLiveWritesEnabled$2()) return {
5841
- ok: true,
5842
- output: "e2e fake live write"
5843
- };
5844
- return {
5845
- ok: false,
5846
- output: "live writes disabled"
5847
- };
5848
- }
5849
- return yield* runSubprocessEffect({
5850
- command: "xurl",
5851
- args
5852
- }).pipe(Effect.map(({ stdout, stderr }) => ({
5893
+ return yield* runJsonCommandEffect(oauth2ArgsForCandidate(authCandidate, args), scopedOptions).pipe(Effect.catchAll((error) => {
5894
+ if (!primaryUsername) return Effect.fail(error);
5895
+ oauth2CandidateCache.delete(primaryUsername.toLowerCase());
5896
+ const attempted = /* @__PURE__ */ new Set([authCandidate ? `${authCandidate.app ?? "default"}:${authCandidate.username}` : `default:${primaryUsername}`]);
5897
+ if (authCandidate?.username !== primaryUsername) attempted.add(`default:${primaryUsername}`);
5898
+ return lookupOAuth2UsernameForAccountEffect(primaryUsername, attempted, deadlineMs).pipe(Effect.flatMap((fallbackUsername) => {
5899
+ if (!fallbackUsername) return Effect.fail(error);
5900
+ oauth2CandidateCache.set(primaryUsername.toLowerCase(), {
5901
+ expiresAt: Date.now() + AUTHENTICATED_USER_TTL_MS,
5902
+ value: fallbackUsername
5903
+ });
5904
+ return runJsonCommandEffect(oauth2ArgsForCandidate(fallbackUsername, args), scopedOptions);
5905
+ }), Effect.catchAll(() => Effect.fail(error)));
5906
+ }));
5907
+ });
5908
+ var runMutationCommandEffect = Effect.fn("xurl.runMutationCommand")(function* (args) {
5909
+ if (liveWritesDisabled$3()) {
5910
+ if (e2eFakeLiveWritesEnabled$2()) return {
5853
5911
  ok: true,
5854
- output: stdout || stderr || "ok"
5855
- })), Effect.catchAll((error) => Effect.succeed({
5912
+ output: "e2e fake live write"
5913
+ };
5914
+ return {
5856
5915
  ok: false,
5857
- output: formatExecError$1(error, "xurl execution failed")
5858
- })));
5859
- });
5860
- }
5861
- function lookupUsersByIdsEffect(ids) {
5916
+ output: "live writes disabled"
5917
+ };
5918
+ }
5919
+ return yield* runSubprocessEffect({
5920
+ command: "xurl",
5921
+ args
5922
+ }).pipe(Effect.map(({ stdout, stderr }) => ({
5923
+ ok: true,
5924
+ output: stdout || stderr || "ok"
5925
+ })), Effect.catchAll((error) => Effect.succeed({
5926
+ ok: false,
5927
+ output: formatExecError$1(error, "xurl execution failed")
5928
+ })));
5929
+ });
5930
+ var lookupUsersByIdsEffect = Effect.fn("xurl.lookupUsersByIds")((ids) => {
5862
5931
  if (ids.length === 0) return Effect.succeed([]);
5863
5932
  return runJsonCommandEffect([`/2/users?${new URLSearchParams({
5864
5933
  ids: ids.join(","),
5865
5934
  "user.fields": "description,entities,location,public_metrics,profile_image_url,url,created_at,verified,verified_type"
5866
5935
  }).toString()}`]).pipe(Effect.map((payload) => Array.isArray(payload.data) ? payload.data : []));
5936
+ });
5937
+ function normalizeXListPage(payload) {
5938
+ const data = (Array.isArray(payload.data) ? payload.data : []).map((value) => {
5939
+ const item = value;
5940
+ if (typeof item.id !== "string" || typeof item.name !== "string") return null;
5941
+ return {
5942
+ id: item.id,
5943
+ name: item.name,
5944
+ ...typeof item.description === "string" ? { description: item.description } : {},
5945
+ ...typeof item.member_count === "number" ? { memberCount: item.member_count } : {},
5946
+ ...typeof item.follower_count === "number" ? { followerCount: item.follower_count } : {},
5947
+ ...typeof item.private === "boolean" ? { isPrivate: item.private } : {},
5948
+ ...typeof item.owner_id === "string" ? { ownerId: item.owner_id } : {},
5949
+ ...typeof item.created_at === "string" ? { createdAt: item.created_at } : {},
5950
+ raw: item
5951
+ };
5952
+ }).filter((item) => Boolean(item));
5953
+ const meta = payload.meta && typeof payload.meta === "object" ? payload.meta : {};
5954
+ return {
5955
+ data,
5956
+ meta: {
5957
+ result_count: data.length,
5958
+ ...typeof meta.next_token === "string" ? { next_token: meta.next_token } : { next_token: null }
5959
+ }
5960
+ };
5867
5961
  }
5868
- function lookupUsersByIds(ids) {
5869
- return runEffectPromise(lookupUsersByIdsEffect(ids));
5870
- }
5871
- function lookupUsersByHandlesEffect(handles, options = {}) {
5962
+ Effect.fn("xurl.listOwnedXLists")(({ userId, username, maxResults, paginationToken }) => {
5963
+ const query = new URLSearchParams({
5964
+ max_results: String(maxResults),
5965
+ "list.fields": "created_at,description,follower_count,member_count,name,owner_id,private"
5966
+ });
5967
+ if (paginationToken) query.set("pagination_token", paginationToken);
5968
+ return runOAuth2JsonCommandEffect({
5969
+ args: [`/2/users/${userId}/owned_lists?${query.toString()}`],
5970
+ username
5971
+ }).pipe(Effect.map(normalizeXListPage));
5972
+ });
5973
+ Effect.fn("xurl.listXListMembers")(({ listId, username, maxResults, paginationToken }) => {
5974
+ const query = new URLSearchParams({
5975
+ max_results: String(maxResults),
5976
+ "user.fields": RICH_USER_FIELDS
5977
+ });
5978
+ if (paginationToken) query.set("pagination_token", paginationToken);
5979
+ return runOAuth2JsonCommandEffect({
5980
+ args: [`/2/lists/${listId}/members?${query.toString()}`],
5981
+ username
5982
+ }).pipe(Effect.map((payload) => ({
5983
+ data: Array.isArray(payload.data) ? payload.data : [],
5984
+ meta: payload.meta && typeof payload.meta === "object" ? payload.meta : {}
5985
+ })));
5986
+ });
5987
+ var lookupUsersByHandlesEffect = Effect.fn("xurl.lookupUsersByHandles")((handles, options = {}) => {
5872
5988
  if (handles.length === 0) return Effect.succeed([]);
5873
5989
  const args = [`/2/users/by?${new URLSearchParams({
5874
5990
  usernames: handles.map((item) => item.replace(/^@/, "")).join(","),
@@ -5880,114 +5996,72 @@ function lookupUsersByHandlesEffect(handles, options = {}) {
5880
5996
  options: { signal: options.signal },
5881
5997
  useConfiguredCandidate: options.useConfiguredCandidate
5882
5998
  }) : runJsonCommandEffect(args, { signal: options.signal })).pipe(Effect.map((payload) => Array.isArray(payload.data) ? payload.data : []));
5883
- }
5884
- function lookupUsersByHandles(handles, options = {}) {
5885
- return runEffectPromise(lookupUsersByHandlesEffect(handles, options));
5886
- }
5999
+ });
5887
6000
  function authenticatedUserFromPayload(payload) {
5888
6001
  const data = payload.data;
5889
6002
  return data && typeof data === "object" ? data : null;
5890
6003
  }
5891
- function lookupAuthenticatedUserFreshEffect() {
5892
- return runJsonCommandEffect(["whoami"]).pipe(Effect.map(authenticatedUserFromPayload));
5893
- }
5894
- function lookupAuthenticatedOAuth2UserEffect(username) {
5895
- return runOAuth2JsonCommandEffect({
5896
- args: ["whoami"],
5897
- username
5898
- }).pipe(Effect.map(authenticatedUserFromPayload));
5899
- }
6004
+ var lookupAuthenticatedUserFreshEffect = Effect.fn("xurl.lookupAuthenticatedUserFresh")(() => runJsonCommandEffect(["whoami"]).pipe(Effect.map(authenticatedUserFromPayload)));
6005
+ var lookupAuthenticatedOAuth2UserEffect = Effect.fn("xurl.lookupAuthenticatedOAuth2User")((username) => runOAuth2JsonCommandEffect({
6006
+ args: ["whoami"],
6007
+ username
6008
+ }).pipe(Effect.map(authenticatedUserFromPayload)));
5900
6009
  function lookupAuthenticatedUserEffect() {
5901
- return Effect.gen(function* () {
5902
- const now = Date.now();
5903
- if (authenticatedUserCache && "value" in authenticatedUserCache && authenticatedUserCache.expiresAt > now) return authenticatedUserCache.value ?? null;
5904
- if (authenticatedUserCache?.pending) return yield* Effect.tryPromise({
5905
- try: () => authenticatedUserCache?.pending ?? Promise.resolve(null),
5906
- catch: normalizeError
5907
- });
5908
- const pending = runEffectPromise(lookupAuthenticatedUserFreshEffect());
5909
- authenticatedUserCache = {
5910
- expiresAt: 0,
5911
- pending
5912
- };
5913
- const value = yield* Effect.tryPromise({
5914
- try: () => pending,
5915
- catch: normalizeError
5916
- }).pipe(Effect.catchAll((error) => Effect.sync(() => {
5917
- authenticatedUserCache = void 0;
5918
- }).pipe(Effect.flatMap(() => Effect.fail(error)))));
5919
- authenticatedUserCache = {
5920
- expiresAt: Date.now() + AUTHENTICATED_USER_TTL_MS,
5921
- value
5922
- };
5923
- return value;
5924
- });
5925
- }
5926
- function lookupAuthenticatedUser() {
5927
- return runEffectPromise(lookupAuthenticatedUserEffect());
6010
+ return cachedAuthenticatedUser.pipe(Effect.tapError(() => invalidateAuthenticatedUser));
5928
6011
  }
5929
6012
  function lookupAuthenticatedUserFresh() {
5930
6013
  return runEffectPromise(lookupAuthenticatedUserFreshEffect());
5931
6014
  }
5932
- function resolveUserIdEffect({ username, userId }) {
5933
- return Effect.gen(function* () {
5934
- if (userId) return userId;
5935
- if (username) {
5936
- const [user] = yield* lookupUsersByHandlesEffect([username]);
5937
- if (!user?.id) return yield* Effect.fail(/* @__PURE__ */ new Error(`Could not resolve Twitter user id for @${username}`));
5938
- return String(user.id);
5939
- }
5940
- const user = yield* lookupAuthenticatedUserEffect();
5941
- if (!user?.id) return yield* Effect.fail(/* @__PURE__ */ new Error("Could not resolve authenticated Twitter user id"));
6015
+ var resolveUserIdEffect = Effect.fn("xurl.resolveUserId")(function* ({ username, userId }) {
6016
+ if (userId) return userId;
6017
+ if (username) {
6018
+ const [user] = yield* lookupUsersByHandlesEffect([username]);
6019
+ if (!user?.id) return yield* Effect.fail(/* @__PURE__ */ new Error(`Could not resolve Twitter user id for @${username}`));
5942
6020
  return String(user.id);
6021
+ }
6022
+ const user = yield* lookupAuthenticatedUserEffect();
6023
+ if (!user?.id) return yield* Effect.fail(/* @__PURE__ */ new Error("Could not resolve authenticated Twitter user id"));
6024
+ return String(user.id);
6025
+ });
6026
+ var listMentionsViaXurlEffect = Effect.fn("xurl.listMentions")(function* ({ maxResults, username, userId, paginationToken, sinceId, startTime }) {
6027
+ const resolvedUserId = yield* resolveUserIdEffect({
6028
+ username,
6029
+ userId
5943
6030
  });
5944
- }
5945
- function listMentionsViaXurlEffect({ maxResults, username, userId, paginationToken, sinceId, startTime }) {
5946
- return Effect.gen(function* () {
5947
- const resolvedUserId = yield* resolveUserIdEffect({
5948
- username,
5949
- userId
5950
- });
5951
- const query = new URLSearchParams({
5952
- max_results: String(maxResults),
5953
- expansions: AUTHOR_MEDIA_EXPANSIONS,
5954
- "tweet.fields": "created_at,conversation_id,entities,public_metrics",
5955
- "media.fields": MEDIA_FIELDS,
5956
- "user.fields": "description,entities,location,public_metrics,profile_image_url,url,created_at,verified,verified_type"
5957
- });
5958
- if (paginationToken) query.set("pagination_token", paginationToken);
5959
- if (sinceId) query.set("since_id", sinceId);
5960
- if (startTime) query.set("start_time", startTime);
5961
- return toXurlMentionsResponse(yield* runOAuth2JsonCommandEffect({
5962
- args: [`/2/users/${resolvedUserId}/mentions?${query.toString()}`],
5963
- username
5964
- }));
6031
+ const query = new URLSearchParams({
6032
+ max_results: String(maxResults),
6033
+ expansions: AUTHOR_MEDIA_EXPANSIONS,
6034
+ "tweet.fields": "created_at,conversation_id,entities,public_metrics",
6035
+ "media.fields": MEDIA_FIELDS,
6036
+ "user.fields": "description,entities,location,public_metrics,profile_image_url,url,created_at,verified,verified_type"
5965
6037
  });
5966
- }
5967
- function listMentionsViaXurl(options) {
5968
- return runEffectPromise(listMentionsViaXurlEffect(options));
5969
- }
5970
- function listHomeTimelineViaXurlEffect({ maxResults, username, userId, paginationToken, timeoutMs }) {
5971
- return Effect.gen(function* () {
5972
- const resolvedUserId = yield* resolveUserIdEffect({
5973
- username,
5974
- userId
5975
- });
5976
- const query = new URLSearchParams({
5977
- max_results: String(maxResults),
5978
- expansions: AUTHOR_MEDIA_EXPANSIONS,
5979
- "tweet.fields": "created_at,conversation_id,entities,public_metrics,referenced_tweets",
5980
- "media.fields": MEDIA_FIELDS,
5981
- "user.fields": RICH_USER_FIELDS
5982
- });
5983
- if (paginationToken) query.set("pagination_token", paginationToken);
5984
- return toXurlMentionsResponse(yield* runOAuth2JsonCommandEffect({
5985
- args: [`/2/users/${resolvedUserId}/timelines/reverse_chronological?${query.toString()}`],
5986
- username,
5987
- options: { timeoutMs }
5988
- }));
6038
+ if (paginationToken) query.set("pagination_token", paginationToken);
6039
+ if (sinceId) query.set("since_id", sinceId);
6040
+ if (startTime) query.set("start_time", startTime);
6041
+ return toXurlMentionsResponse(yield* runOAuth2JsonCommandEffect({
6042
+ args: [`/2/users/${resolvedUserId}/mentions?${query.toString()}`],
6043
+ username
6044
+ }));
6045
+ });
6046
+ var listHomeTimelineViaXurlEffect = Effect.fn("xurl.listHomeTimeline")(function* ({ maxResults, username, userId, paginationToken, timeoutMs }) {
6047
+ const resolvedUserId = yield* resolveUserIdEffect({
6048
+ username,
6049
+ userId
5989
6050
  });
5990
- }
6051
+ const query = new URLSearchParams({
6052
+ max_results: String(maxResults),
6053
+ expansions: AUTHOR_MEDIA_EXPANSIONS,
6054
+ "tweet.fields": "created_at,conversation_id,entities,public_metrics,referenced_tweets",
6055
+ "media.fields": MEDIA_FIELDS,
6056
+ "user.fields": RICH_USER_FIELDS
6057
+ });
6058
+ if (paginationToken) query.set("pagination_token", paginationToken);
6059
+ return toXurlMentionsResponse(yield* runOAuth2JsonCommandEffect({
6060
+ args: [`/2/users/${resolvedUserId}/timelines/reverse_chronological?${query.toString()}`],
6061
+ username,
6062
+ options: { timeoutMs }
6063
+ }));
6064
+ });
5991
6065
  function toXurlMentionsResponse(payload) {
5992
6066
  return {
5993
6067
  data: Array.isArray(payload.data) ? payload.data : [],
@@ -5995,45 +6069,37 @@ function toXurlMentionsResponse(payload) {
5995
6069
  meta: payload.meta && typeof payload.meta === "object" ? payload.meta : void 0
5996
6070
  };
5997
6071
  }
5998
- function listTimelineCollectionViaXurlEffect({ collection, maxResults, username, userId, isPaginatedWalk = false, paginationToken }) {
5999
- return Effect.gen(function* () {
6000
- const resolvedUserId = yield* resolveUserIdEffect({
6001
- username,
6002
- userId
6003
- });
6004
- const requestMaxResults = capTimelineCollectionMaxResults(collection, maxResults, isPaginatedWalk);
6005
- const query = new URLSearchParams({
6006
- max_results: String(requestMaxResults),
6007
- expansions: AUTHOR_MEDIA_EXPANSIONS,
6008
- "tweet.fields": "created_at,conversation_id,entities,public_metrics,referenced_tweets",
6009
- "media.fields": MEDIA_FIELDS,
6010
- "user.fields": "description,entities,location,public_metrics,profile_image_url,url,created_at,verified,verified_type"
6011
- });
6012
- if (paginationToken) query.set("pagination_token", paginationToken);
6013
- return toXurlMentionsResponse(yield* runOAuth2JsonCommandEffect({
6014
- args: [`/2/users/${resolvedUserId}/${collection}?${query.toString()}`],
6015
- username
6016
- }));
6072
+ var listTimelineCollectionViaXurlEffect = Effect.fn("xurl.listTimelineCollection")(function* ({ collection, maxResults, username, userId, isPaginatedWalk = false, paginationToken }) {
6073
+ const resolvedUserId = yield* resolveUserIdEffect({
6074
+ username,
6075
+ userId
6017
6076
  });
6018
- }
6077
+ const requestMaxResults = capTimelineCollectionMaxResults(collection, maxResults, isPaginatedWalk);
6078
+ const query = new URLSearchParams({
6079
+ max_results: String(requestMaxResults),
6080
+ expansions: AUTHOR_MEDIA_EXPANSIONS,
6081
+ "tweet.fields": "created_at,conversation_id,entities,public_metrics,referenced_tweets",
6082
+ "media.fields": MEDIA_FIELDS,
6083
+ "user.fields": "description,entities,location,public_metrics,profile_image_url,url,created_at,verified,verified_type"
6084
+ });
6085
+ if (paginationToken) query.set("pagination_token", paginationToken);
6086
+ return toXurlMentionsResponse(yield* runOAuth2JsonCommandEffect({
6087
+ args: [`/2/users/${resolvedUserId}/${collection}?${query.toString()}`],
6088
+ username
6089
+ }));
6090
+ });
6019
6091
  function listLikedTweetsViaXurlEffect(options) {
6020
6092
  return listTimelineCollectionViaXurlEffect({
6021
6093
  ...options,
6022
6094
  collection: "liked_tweets"
6023
6095
  });
6024
6096
  }
6025
- function listLikedTweetsViaXurl(options) {
6026
- return runEffectPromise(listLikedTweetsViaXurlEffect(options));
6027
- }
6028
6097
  function listBookmarkedTweetsViaXurlEffect(options) {
6029
6098
  return listTimelineCollectionViaXurlEffect({
6030
6099
  ...options,
6031
6100
  collection: "bookmarks"
6032
6101
  });
6033
6102
  }
6034
- function listBookmarkedTweetsViaXurl(options) {
6035
- return runEffectPromise(listBookmarkedTweetsViaXurlEffect(options));
6036
- }
6037
6103
  function listDirectMessageEventsViaXurlEffect({ maxResults, username, paginationToken }) {
6038
6104
  const query = new URLSearchParams({
6039
6105
  max_results: String(maxResults),
@@ -6052,31 +6118,26 @@ function listDirectMessageEventsViaXurlEffect({ maxResults, username, pagination
6052
6118
  meta: payload.meta && typeof payload.meta === "object" ? payload.meta : void 0
6053
6119
  })));
6054
6120
  }
6055
- function listFollowUsersViaXurlEffect({ direction, maxResults, username, userId, paginationToken }) {
6056
- return Effect.gen(function* () {
6057
- const resolvedUserId = yield* resolveUserIdEffect({
6058
- username,
6059
- userId
6060
- });
6061
- const query = new URLSearchParams({
6062
- max_results: String(maxResults),
6063
- "user.fields": "id,username,name,description,verified,protected,public_metrics,profile_image_url,created_at"
6064
- });
6065
- if (paginationToken) query.set("pagination_token", paginationToken);
6066
- const payload = yield* runOAuth2JsonCommandEffect({
6067
- args: [`/2/users/${resolvedUserId}/${direction}?${query.toString()}`],
6068
- username
6069
- });
6070
- return {
6071
- data: Array.isArray(payload.data) ? payload.data : [],
6072
- meta: payload.meta && typeof payload.meta === "object" ? payload.meta : void 0
6073
- };
6121
+ var listFollowUsersViaXurlEffect = Effect.fn("xurl.listFollowUsers")(function* ({ direction, maxResults, username, userId, paginationToken }) {
6122
+ const resolvedUserId = yield* resolveUserIdEffect({
6123
+ username,
6124
+ userId
6074
6125
  });
6075
- }
6076
- function listFollowUsersViaXurl(options) {
6077
- return runEffectPromise(listFollowUsersViaXurlEffect(options));
6078
- }
6079
- function listBlockedUsersEffect(userId, paginationToken) {
6126
+ const query = new URLSearchParams({
6127
+ max_results: String(maxResults),
6128
+ "user.fields": "id,username,name,description,verified,protected,public_metrics,profile_image_url,created_at"
6129
+ });
6130
+ if (paginationToken) query.set("pagination_token", paginationToken);
6131
+ const payload = yield* runOAuth2JsonCommandEffect({
6132
+ args: [`/2/users/${resolvedUserId}/${direction}?${query.toString()}`],
6133
+ username
6134
+ });
6135
+ return {
6136
+ data: Array.isArray(payload.data) ? payload.data : [],
6137
+ meta: payload.meta && typeof payload.meta === "object" ? payload.meta : void 0
6138
+ };
6139
+ });
6140
+ var listBlockedUsersEffect = Effect.fn("xurl.listBlockedUsers")((userId, paginationToken) => {
6080
6141
  const query = new URLSearchParams({
6081
6142
  max_results: "100",
6082
6143
  "user.fields": "description,entities,location,public_metrics,profile_image_url,url,created_at,verified,verified_type"
@@ -6090,11 +6151,8 @@ function listBlockedUsersEffect(userId, paginationToken) {
6090
6151
  nextToken: typeof meta?.next_token === "string" ? String(meta.next_token) : null
6091
6152
  };
6092
6153
  }));
6093
- }
6094
- function listBlockedUsers(userId, paginationToken) {
6095
- return runEffectPromise(listBlockedUsersEffect(userId, paginationToken));
6096
- }
6097
- function listUserTweetsEffect(userId, { maxResults, paginationToken, excludeRetweets = true, sinceId, untilId, tweetFields, expansions, userFields, mediaFields, auth, username, signal, onAttempt, useConfiguredCandidate }) {
6154
+ });
6155
+ var listUserTweetsEffect = Effect.fn("xurl.listUserTweets")((userId, { maxResults, paginationToken, excludeRetweets = true, sinceId, untilId, tweetFields, expansions, userFields, mediaFields, auth, username, signal, onAttempt, useConfiguredCandidate }) => {
6098
6156
  const query = new URLSearchParams({
6099
6157
  max_results: String(maxResults),
6100
6158
  expansions: MEDIA_EXPANSION,
@@ -6130,10 +6188,7 @@ function listUserTweetsEffect(userId, { maxResults, paginationToken, excludeRetw
6130
6188
  ...includes ? { includes } : {}
6131
6189
  };
6132
6190
  }));
6133
- }
6134
- function listUserTweets(userId, options) {
6135
- return runEffectPromise(listUserTweetsEffect(userId, options));
6136
- }
6191
+ });
6137
6192
  function toXurlTweetsResponse(payload) {
6138
6193
  return {
6139
6194
  data: Array.isArray(payload.data) ? payload.data : [],
@@ -6141,7 +6196,17 @@ function toXurlTweetsResponse(payload) {
6141
6196
  meta: payload.meta && typeof payload.meta === "object" ? payload.meta : void 0
6142
6197
  };
6143
6198
  }
6144
- function searchRecentByConversationIdEffect(conversationId, { maxResults, paginationToken, timeoutMs, auth, username, signal, onAttempt }) {
6199
+ Effect.fn("xurl.lookupTweetsByIds")((ids) => {
6200
+ if (ids.length === 0) return Effect.succeed({ data: [] });
6201
+ return runJsonCommandEffect([`/2/tweets?${new URLSearchParams({
6202
+ ids: ids.join(","),
6203
+ expansions: AUTHOR_MEDIA_EXPANSIONS,
6204
+ "tweet.fields": "created_at,conversation_id,entities,public_metrics,referenced_tweets",
6205
+ "media.fields": MEDIA_FIELDS,
6206
+ "user.fields": "description,entities,location,public_metrics,profile_image_url,url,created_at,verified,verified_type"
6207
+ }).toString()}`]).pipe(Effect.map(toXurlTweetsResponse));
6208
+ });
6209
+ var searchRecentByConversationIdEffect = Effect.fn("xurl.searchRecentByConversationId")((conversationId, { maxResults, paginationToken, timeoutMs, auth, username, signal, onAttempt }) => {
6145
6210
  const query = new URLSearchParams({
6146
6211
  query: `conversation_id:${conversationId}`,
6147
6212
  max_results: String(maxResults),
@@ -6166,8 +6231,8 @@ function searchRecentByConversationIdEffect(conversationId, { maxResults, pagina
6166
6231
  signal,
6167
6232
  onAttempt
6168
6233
  })).pipe(Effect.map(toXurlTweetsResponse));
6169
- }
6170
- function searchRecentTweetsEffect(searchQuery, { maxResults, paginationToken, startTime, endTime, username, timeoutMs }) {
6234
+ });
6235
+ var searchRecentTweetsEffect = Effect.fn("xurl.searchRecentTweets")((searchQuery, { maxResults, paginationToken, startTime, endTime, username, timeoutMs }) => {
6171
6236
  const query = new URLSearchParams({
6172
6237
  query: searchQuery,
6173
6238
  max_results: String(maxResults),
@@ -6185,8 +6250,8 @@ function searchRecentTweetsEffect(searchQuery, { maxResults, paginationToken, st
6185
6250
  options: { timeoutMs },
6186
6251
  useConfiguredCandidate: false
6187
6252
  }).pipe(Effect.map(toXurlTweetsResponse));
6188
- }
6189
- function getTweetByIdEffect(id, { timeoutMs } = {}) {
6253
+ });
6254
+ var getTweetByIdEffect = Effect.fn("xurl.getTweetById")((id, { timeoutMs } = {}) => {
6190
6255
  return runJsonCommandEffect([`/2/tweets/${id}?${new URLSearchParams({
6191
6256
  expansions: AUTHOR_MEDIA_EXPANSIONS,
6192
6257
  "tweet.fields": THREAD_TWEET_FIELDS,
@@ -6199,7 +6264,7 @@ function getTweetByIdEffect(id, { timeoutMs } = {}) {
6199
6264
  meta: payload.meta && typeof payload.meta === "object" ? payload.meta : void 0
6200
6265
  };
6201
6266
  }));
6202
- }
6267
+ });
6203
6268
  function postViaXurlEffect(text) {
6204
6269
  return runShortcutEffect(["post", text]);
6205
6270
  }
@@ -6226,9 +6291,6 @@ function blockUserViaXurlEffect(sourceUserId, targetUserId) {
6226
6291
  JSON.stringify({ target_user_id: targetUserId })
6227
6292
  ]);
6228
6293
  }
6229
- function blockUserViaXurl(sourceUserId, targetUserId) {
6230
- return runEffectPromise(blockUserViaXurlEffect(sourceUserId, targetUserId));
6231
- }
6232
6294
  function unblockUserViaXurlEffect(sourceUserId, targetUserId) {
6233
6295
  return runMutationCommandEffect([
6234
6296
  "-X",
@@ -6236,9 +6298,6 @@ function unblockUserViaXurlEffect(sourceUserId, targetUserId) {
6236
6298
  `/2/users/${sourceUserId}/blocking/${targetUserId}`
6237
6299
  ]);
6238
6300
  }
6239
- function unblockUserViaXurl(sourceUserId, targetUserId) {
6240
- return runEffectPromise(unblockUserViaXurlEffect(sourceUserId, targetUserId));
6241
- }
6242
6301
  function muteUserViaXurlEffect(sourceUserId, targetUserId) {
6243
6302
  return runMutationCommandEffect([
6244
6303
  "-X",
@@ -6248,9 +6307,6 @@ function muteUserViaXurlEffect(sourceUserId, targetUserId) {
6248
6307
  JSON.stringify({ target_user_id: targetUserId })
6249
6308
  ]);
6250
6309
  }
6251
- function muteUserViaXurl(sourceUserId, targetUserId) {
6252
- return runEffectPromise(muteUserViaXurlEffect(sourceUserId, targetUserId));
6253
- }
6254
6310
  function unmuteUserViaXurlEffect(sourceUserId, targetUserId) {
6255
6311
  return runMutationCommandEffect([
6256
6312
  "-X",
@@ -6258,44 +6314,35 @@ function unmuteUserViaXurlEffect(sourceUserId, targetUserId) {
6258
6314
  `/2/users/${sourceUserId}/muting/${targetUserId}`
6259
6315
  ]);
6260
6316
  }
6261
- function unmuteUserViaXurl(sourceUserId, targetUserId) {
6262
- return runEffectPromise(unmuteUserViaXurlEffect(sourceUserId, targetUserId));
6263
- }
6264
6317
  //#endregion
6265
6318
  //#region src/lib/live-transport-gateway.ts
6266
- function fromPromise(run) {
6267
- return Effect.tryPromise({
6268
- try: run,
6269
- catch: (error) => error instanceof Error ? error : new Error(String(error))
6270
- });
6271
- }
6272
6319
  var liveTransportGateway = {
6273
6320
  bird: {
6274
- getAuthenticatedAccount: () => getAuthenticatedBirdAccountEffect(),
6275
- listBookmarks: (options) => listBookmarkedTweetsViaBirdEffect(options),
6276
- listDirectMessages: (options) => listDirectMessagesViaBirdEffect(options),
6277
- listFollowUsers: (options) => listFollowUsersViaBirdEffect(options),
6278
- listHomeTimeline: (options) => listHomeTimelineViaBirdEffect(options),
6279
- listLikes: (options) => listLikedTweetsViaBirdEffect(options),
6280
- listMentions: (options) => listMentionsViaBirdEffect(options),
6281
- listThread: (options) => listThreadViaBirdEffect(options),
6282
- searchTweets: (query, options) => searchTweetsViaBirdEffect(query, options)
6321
+ getAuthenticatedAccount: (...args) => getAuthenticatedBirdAccountEffect(...args),
6322
+ listBookmarks: (...args) => listBookmarkedTweetsViaBirdEffect(...args),
6323
+ listDirectMessages: (...args) => listDirectMessagesViaBirdEffect(...args),
6324
+ listFollowUsers: (...args) => listFollowUsersViaBirdEffect(...args),
6325
+ listHomeTimeline: (...args) => listHomeTimelineViaBirdEffect(...args),
6326
+ listLikes: (...args) => listLikedTweetsViaBirdEffect(...args),
6327
+ listMentions: (...args) => listMentionsViaBirdEffect(...args),
6328
+ listThread: (...args) => listThreadViaBirdEffect(...args),
6329
+ searchTweets: (...args) => searchTweetsViaBirdEffect(...args)
6283
6330
  },
6284
6331
  xurl: {
6285
- getTransportStatus: (...args) => fromPromise(() => getTransportStatus(...args)),
6286
- getTweetById: (id, options) => getTweetByIdEffect(id, options),
6287
- listBookmarks: (...args) => fromPromise(() => listBookmarkedTweetsViaXurl(...args)),
6288
- listDirectMessages: (options) => listDirectMessageEventsViaXurlEffect(options),
6289
- listFollowUsers: (...args) => fromPromise(() => listFollowUsersViaXurl(...args)),
6290
- listHomeTimeline: (options) => listHomeTimelineViaXurlEffect(options),
6291
- listLikes: (...args) => fromPromise(() => listLikedTweetsViaXurl(...args)),
6292
- listMentions: (...args) => fromPromise(() => listMentionsViaXurl(...args)),
6293
- listUserTweets: (...args) => fromPromise(() => listUserTweets(...args)),
6294
- lookupAuthenticatedOAuth2User: (username) => lookupAuthenticatedOAuth2UserEffect(username),
6295
- lookupAuthenticatedUser: (...args) => fromPromise(() => lookupAuthenticatedUser(...args)),
6296
- lookupUsersByHandles: (...args) => fromPromise(() => lookupUsersByHandles(...args)),
6297
- searchConversation: (conversationId, options) => searchRecentByConversationIdEffect(conversationId, options),
6298
- searchRecentTweets: (query, options) => searchRecentTweetsEffect(query, options)
6332
+ getTransportStatus: (...args) => getTransportStatusEffect(...args),
6333
+ getTweetById: (...args) => getTweetByIdEffect(...args),
6334
+ listBookmarks: (...args) => listBookmarkedTweetsViaXurlEffect(...args),
6335
+ listDirectMessages: (...args) => listDirectMessageEventsViaXurlEffect(...args),
6336
+ listFollowUsers: (...args) => listFollowUsersViaXurlEffect(...args),
6337
+ listHomeTimeline: (...args) => listHomeTimelineViaXurlEffect(...args),
6338
+ listLikes: (...args) => listLikedTweetsViaXurlEffect(...args),
6339
+ listMentions: (...args) => listMentionsViaXurlEffect(...args),
6340
+ listUserTweets: (...args) => listUserTweetsEffect(...args),
6341
+ lookupAuthenticatedOAuth2User: (...args) => lookupAuthenticatedOAuth2UserEffect(...args),
6342
+ lookupAuthenticatedUser: (...args) => lookupAuthenticatedUserEffect(...args),
6343
+ lookupUsersByHandles: (...args) => lookupUsersByHandlesEffect(...args),
6344
+ searchConversation: (...args) => searchRecentByConversationIdEffect(...args),
6345
+ searchRecentTweets: (...args) => searchRecentTweetsEffect(...args)
6299
6346
  }
6300
6347
  };
6301
6348
  //#endregion
@@ -6457,8 +6504,8 @@ var MAX_AVATAR_BYTES = 2 * 1024 * 1024;
6457
6504
  var MAX_AVATAR_DATA_URL_CHARS = MAX_AVATAR_BYTES * 4;
6458
6505
  var REMOTE_AVATAR_TIMEOUT_MS = 1e4;
6459
6506
  var DEFAULT_AVATAR_PREFETCH_CONCURRENCY = 8;
6460
- var ALLOWED_REMOTE_AVATAR_HOSTS = new Set(["pbs.twimg.com"]);
6461
- var RASTER_CONTENT_TYPES = new Set([
6507
+ var ALLOWED_REMOTE_AVATAR_HOSTS = /* @__PURE__ */ new Set(["pbs.twimg.com"]);
6508
+ var RASTER_CONTENT_TYPES = /* @__PURE__ */ new Set([
6462
6509
  "image/jpeg",
6463
6510
  "image/png",
6464
6511
  "image/webp",
@@ -8256,7 +8303,7 @@ function listMentionsByIds(db, accountId, tweetIds, limit) {
8256
8303
  }
8257
8304
  function mergeMentionThreadIntoLocalStore({ db, accountId, accountHandle, mentionIds, payload, source = "bird", writeThreadContextEdges = false }) {
8258
8305
  const usersById = new Map((payload.includes?.users ?? []).map((user) => [user.id, user]));
8259
- const groups = new Map([
8306
+ const groups = /* @__PURE__ */ new Map([
8260
8307
  ["mention", []],
8261
8308
  ["home", []],
8262
8309
  ["thread", []]
@@ -8317,7 +8364,7 @@ function fetchParentChainViaXurlEffect({ mention, maxDepth, timeoutMs, deadlineM
8317
8364
  return Effect.gen(function* () {
8318
8365
  const pages = [];
8319
8366
  const warnings = [];
8320
- const seenTweetIds = new Set([mention.id]);
8367
+ const seenTweetIds = /* @__PURE__ */ new Set([mention.id]);
8321
8368
  let nextParentId = mention.replyToId;
8322
8369
  let fallbackDepth = 0;
8323
8370
  let generalReadTweets = 0;
@@ -8363,7 +8410,7 @@ function fetchParentChainViaXurlEffect({ mention, maxDepth, timeoutMs, deadlineM
8363
8410
  }
8364
8411
  function findMissingAncestorId(mention, payload) {
8365
8412
  const tweetsById = new Map(payload.data.map((tweet) => [tweet.id, tweet]));
8366
- const seenTweetIds = new Set([mention.id]);
8413
+ const seenTweetIds = /* @__PURE__ */ new Set([mention.id]);
8367
8414
  const anchorTweet = tweetsById.get(mention.id) ?? mention.rawTweet;
8368
8415
  let nextParentId = anchorTweet ? getReplyToId(anchorTweet) : mention.replyToId;
8369
8416
  while (nextParentId) {
@@ -11476,7 +11523,7 @@ function runModeEffect(mode, options) {
11476
11523
  }
11477
11524
  function combineTweetSearchResults(left, right, limit) {
11478
11525
  if (left.ok && right.ok) {
11479
- const tweetIds = [...new Set([...left.tweetIds, ...right.tweetIds])].slice(0, limit);
11526
+ const tweetIds = [.../* @__PURE__ */ new Set([...left.tweetIds, ...right.tweetIds])].slice(0, limit);
11480
11527
  const liveSources = new Set([left.source, right.source].filter((source) => source !== "cache"));
11481
11528
  return {
11482
11529
  ok: true,
@@ -12279,7 +12326,7 @@ function resolveProfilesForHandlesEffect(handles, options = {}) {
12279
12326
  unresolved = [];
12280
12327
  }
12281
12328
  if (unresolved.length > 0 && xurlFallback) {
12282
- const xurlResult = yield* tryPromise(() => lookupUsersByHandles(unresolved)).pipe(Effect.map((users) => ({
12329
+ const xurlResult = yield* lookupUsersByHandlesEffect(unresolved).pipe(Effect.map((users) => ({
12283
12330
  ok: true,
12284
12331
  users
12285
12332
  })), Effect.catchAll((error) => Effect.succeed({
@@ -12378,6 +12425,8 @@ function toError$9(error) {
12378
12425
  return error instanceof Error ? error : new Error(String(error));
12379
12426
  }
12380
12427
  function isXurlRateLimitError(error) {
12428
+ const tagged = error;
12429
+ if (tagged._tag === "XurlCommandError" && tagged.rateLimited === true) return true;
12381
12430
  return error.message.includes("Too Many Requests") || error.message.includes("\"status\":429") || /\b429\b/.test(error.message);
12382
12431
  }
12383
12432
  function tryProfileSync(try_) {
@@ -13083,7 +13132,7 @@ var Route$11 = createFileRoute("/api/profile-analysis")({ server: { handlers: {
13083
13132
  //#region src/lib/link-insights.ts
13084
13133
  var DEFAULT_LIMIT$1 = 30;
13085
13134
  var DEFAULT_COMMENTS_LIMIT = 8;
13086
- var TRACKING_PARAMS = new Set([
13135
+ var TRACKING_PARAMS = /* @__PURE__ */ new Set([
13087
13136
  "fbclid",
13088
13137
  "gclid",
13089
13138
  "igshid",
@@ -13102,17 +13151,17 @@ var VIDEO_HOST_SUFFIXES = [
13102
13151
  "tiktok.com",
13103
13152
  "loom.com"
13104
13153
  ];
13105
- var VIDEO_EXACT_HOSTS = new Set([
13154
+ var VIDEO_EXACT_HOSTS = /* @__PURE__ */ new Set([
13106
13155
  "youtu.be",
13107
13156
  "clips.twitch.tv",
13108
13157
  "vm.tiktok.com"
13109
13158
  ]);
13110
13159
  var EXCLUDED_HOST_SUFFIXES = ["x.com", "twitter.com"];
13111
- var EXCLUDED_EXACT_HOSTS = new Set(["t.co"]);
13160
+ var EXCLUDED_EXACT_HOSTS = /* @__PURE__ */ new Set(["t.co"]);
13112
13161
  var URL_WHITESPACE = /\s+/g;
13113
13162
  var RAW_URL_PATTERN = /https?:\/\/[^\s<>"'`]+/g;
13114
13163
  var SQL_URL_EXPRESSION = "lower(coalesce(nullif(e.final_url, ''), nullif(e.expanded_url, ''), e.short_url))";
13115
- var TITLE_SEGMENT_STOPWORDS = new Set([
13164
+ var TITLE_SEGMENT_STOPWORDS = /* @__PURE__ */ new Set([
13116
13165
  "a",
13117
13166
  "about",
13118
13167
  "blog",
@@ -13125,7 +13174,7 @@ var TITLE_SEGMENT_STOPWORDS = new Set([
13125
13174
  "story",
13126
13175
  "watch"
13127
13176
  ]);
13128
- var TITLE_WORD_OVERRIDES = new Map([
13177
+ var TITLE_WORD_OVERRIDES = /* @__PURE__ */ new Map([
13129
13178
  ["ai", "AI"],
13130
13179
  ["api", "API"],
13131
13180
  ["codex", "Codex"],
@@ -13136,7 +13185,7 @@ var TITLE_WORD_OVERRIDES = new Map([
13136
13185
  ["url", "URL"],
13137
13186
  ["wwdc", "WWDC"]
13138
13187
  ]);
13139
- var TITLE_SMALL_WORDS = new Set([
13188
+ var TITLE_SMALL_WORDS = /* @__PURE__ */ new Set([
13140
13189
  "a",
13141
13190
  "an",
13142
13191
  "and",
@@ -13285,7 +13334,7 @@ function stripUrls(text, urls) {
13285
13334
  let output = text;
13286
13335
  for (const url of urls) {
13287
13336
  if (!url) continue;
13288
- const variants = new Set([url]);
13337
+ const variants = /* @__PURE__ */ new Set([url]);
13289
13338
  try {
13290
13339
  const parsed = new URL(url);
13291
13340
  variants.add(parsed.href);
@@ -13672,9 +13721,9 @@ function getLinkInsights(query = {}) {
13672
13721
  kind: rowKind,
13673
13722
  lastSeenAt: row.created_at,
13674
13723
  mentions: [mention],
13675
- seenMentions: new Set([mention.id]),
13676
- sharers: new Set([sharerKey]),
13677
- sharerProfiles: mention.sharedBy ? new Map([[mention.sharedBy.id, mention.sharedBy]]) : /* @__PURE__ */ new Map(),
13724
+ seenMentions: /* @__PURE__ */ new Set([mention.id]),
13725
+ sharers: /* @__PURE__ */ new Set([sharerKey]),
13726
+ sharerProfiles: mention.sharedBy ? /* @__PURE__ */ new Map([[mention.sharedBy.id, mention.sharedBy]]) : /* @__PURE__ */ new Map(),
13678
13727
  shareCount: 1,
13679
13728
  title: row.title,
13680
13729
  topSharer: mention.sharedBy ?? null,
@@ -14540,7 +14589,7 @@ var LETTER_PATTERN = /[a-z]/i;
14540
14589
  var URL_OR_HANDLE_PATTERN = /(https?:\/\/|@|[A-Z0-9._%+-]+@[A-Z0-9.-]+)/i;
14541
14590
  var MONEY_PATTERN = /\$\s?\d/;
14542
14591
  var EMOJI_BLOCK_PATTERN = /[\u{1f1e6}-\u{1f1ff}\u{1f300}-\u{1faff}\u{2600}-\u{27bf}]/gu;
14543
- var GENERIC_LOCATIONS = new Set([
14592
+ var GENERIC_LOCATIONS = /* @__PURE__ */ new Set([
14544
14593
  "earth",
14545
14594
  "everywhere",
14546
14595
  "internet",
@@ -14558,7 +14607,7 @@ var GENERIC_LOCATIONS = new Set([
14558
14607
  "world",
14559
14608
  "world wide web"
14560
14609
  ]);
14561
- var DROP_WORDS = new Set([
14610
+ var DROP_WORDS = /* @__PURE__ */ new Set([
14562
14611
  "a",
14563
14612
  "an",
14564
14613
  "and",
@@ -15112,7 +15161,7 @@ function upsertUrlExpansion(db, item) {
15112
15161
  var FETCH_TIMEOUT_MS = 12e3;
15113
15162
  var MAX_HTML_CHARS = 2e6;
15114
15163
  var MAX_REDIRECTS = 4;
15115
- var NO_BODY_STATUS_CODES = new Set([
15164
+ var NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([
15116
15165
  204,
15117
15166
  205,
15118
15167
  304
@@ -15182,15 +15231,6 @@ function isInjectedFetchAllowed() {
15182
15231
  function stripAddressBrackets(value) {
15183
15232
  return value.replace(/^\[|\]$/g, "");
15184
15233
  }
15185
- function withTimeout(promise, ms) {
15186
- let timer = null;
15187
- const timeout = new Promise((_resolve, reject) => {
15188
- timer = setTimeout(() => reject(/* @__PURE__ */ new Error("Link preview request timed out")), ms);
15189
- });
15190
- return Promise.race([promise, timeout]).finally(() => {
15191
- if (timer) clearTimeout(timer);
15192
- });
15193
- }
15194
15234
  async function resolvePublicAddresses(hostname) {
15195
15235
  const normalized = stripAddressBrackets(hostname);
15196
15236
  if (net.isIP(normalized)) return [normalized];
@@ -15203,19 +15243,24 @@ function validateResolvedAddresses(addresses) {
15203
15243
  if (addresses.length === 0) throw new Error("Link preview host did not resolve");
15204
15244
  if (addresses.some(isBlockedAddress)) throw new Error("Link preview URL resolves to a private address");
15205
15245
  }
15206
- async function resolveSafeAddresses(hostname, resolveHost, timeoutMs) {
15207
- const addresses = await withTimeout(resolveHost(stripAddressBrackets(hostname)), timeoutMs);
15208
- validateResolvedAddresses(addresses);
15209
- return addresses.map((address) => {
15210
- const normalized = stripAddressBrackets(address);
15211
- const family = net.isIP(normalized);
15212
- if (family !== 4 && family !== 6) throw new Error("Link preview host resolved to an invalid address");
15213
- return {
15214
- address: normalized,
15215
- family
15216
- };
15217
- });
15218
- }
15246
+ var resolveSafeAddressesEffect = Effect.fn("linkPreview.resolveSafeAddresses")((hostname, resolveHost, timeoutMs) => tryPromise(() => resolveHost(stripAddressBrackets(hostname))).pipe(Effect.timeoutFail({
15247
+ duration: timeoutMs,
15248
+ onTimeout: () => /* @__PURE__ */ new Error("Link preview request timed out")
15249
+ }), Effect.flatMap((addresses) => Effect.try({
15250
+ try: () => {
15251
+ validateResolvedAddresses(addresses);
15252
+ return addresses.map((address) => {
15253
+ const normalized = stripAddressBrackets(address);
15254
+ const family = net.isIP(normalized);
15255
+ if (family !== 4 && family !== 6) throw new Error("Link preview host resolved to an invalid address");
15256
+ return {
15257
+ address: normalized,
15258
+ family
15259
+ };
15260
+ });
15261
+ },
15262
+ catch: (error) => error
15263
+ }))));
15219
15264
  function headersFromIncoming(headers) {
15220
15265
  const result = new Headers();
15221
15266
  for (const [key, value] of Object.entries(headers)) if (Array.isArray(value)) for (const item of value) result.append(key, item);
@@ -15311,7 +15356,7 @@ function nodeSafeFetch(url, options) {
15311
15356
  return fetchAddress(address, Math.max(1, Math.ceil(remainingMs / remainingAddresses)));
15312
15357
  }), Promise.reject(/* @__PURE__ */ new Error("Link preview host did not resolve")));
15313
15358
  }
15314
- function safePreviewFetchEffect(url, options) {
15359
+ var safePreviewFetchEffect = Effect.fn("linkPreview.safePreviewFetch")(function* (url, options) {
15315
15360
  const resolveHost = options.resolveHost ?? (options.fetchImpl ? null : (hostname) => resolvePublicAddresses(hostname));
15316
15361
  const timeoutMs = options.timeoutMs ?? FETCH_TIMEOUT_MS;
15317
15362
  const method = options.method ?? "GET";
@@ -15322,43 +15367,39 @@ function safePreviewFetchEffect(url, options) {
15322
15367
  accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
15323
15368
  "accept-language": "en-US,en;q=0.9"
15324
15369
  };
15325
- return Effect.gen(function* () {
15326
- if (options.fetchImpl && !isInjectedFetchAllowed()) return yield* Effect.fail(/* @__PURE__ */ new Error("Custom link preview fetch is only available in tests"));
15327
- let currentUrl = url;
15328
- for (let redirect = 0; redirect <= MAX_REDIRECTS; redirect += 1) {
15329
- if (Date.now() >= deadline) return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview request timed out"));
15330
- let remainingMs = remainingTimeoutMs();
15331
- const parsed = yield* Effect.try({
15332
- try: () => assertSafePreviewUrl(currentUrl),
15333
- catch: (error) => error
15334
- });
15335
- if (options.fetchImpl && resolveHost) yield* tryPromise(() => resolveSafeAddresses(parsed.hostname, resolveHost, remainingMs));
15336
- if (Date.now() >= deadline) return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview request timed out"));
15337
- remainingMs = remainingTimeoutMs();
15338
- const response = options.fetchImpl ? yield* tryPromise(() => options.fetchImpl?.(parsed.toString(), {
15339
- headers,
15340
- method,
15341
- redirect: "manual",
15342
- signal: AbortSignal.timeout(remainingMs)
15343
- })) : yield* tryPromise(() => resolveSafeAddresses(parsed.hostname, options.resolveHost ?? resolvePublicAddresses, remainingMs).then((addresses) => Date.now() >= deadline ? Promise.reject(/* @__PURE__ */ new Error("Link preview request timed out")) : nodeSafeFetch(parsed, {
15344
- addresses,
15345
- headers,
15346
- method,
15347
- timeoutMs: remainingTimeoutMs()
15348
- })));
15349
- if (response.status < 300 || response.status >= 400) return response;
15350
- const location = response.headers.get("location");
15351
- if (!location) return response;
15352
- yield* cancelResponseBodyEffect(response);
15353
- if (redirect === MAX_REDIRECTS) return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview redirected too many times"));
15354
- currentUrl = yield* Effect.try({
15355
- try: () => new URL(location, parsed).toString(),
15356
- catch: (error) => error
15357
- });
15358
- }
15359
- return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview redirected too many times"));
15360
- });
15361
- }
15370
+ if (options.fetchImpl && !isInjectedFetchAllowed()) return yield* Effect.fail(/* @__PURE__ */ new Error("Custom link preview fetch is only available in tests"));
15371
+ let currentUrl = url;
15372
+ for (let redirect = 0; redirect <= MAX_REDIRECTS; redirect += 1) {
15373
+ if (Date.now() >= deadline) return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview request timed out"));
15374
+ const parsed = yield* Effect.try({
15375
+ try: () => assertSafePreviewUrl(currentUrl),
15376
+ catch: (error) => error
15377
+ });
15378
+ if (options.fetchImpl && resolveHost) yield* resolveSafeAddressesEffect(parsed.hostname, resolveHost, remainingTimeoutMs());
15379
+ if (Date.now() >= deadline) return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview request timed out"));
15380
+ const response = options.fetchImpl ? yield* tryPromise(() => options.fetchImpl?.(parsed.toString(), {
15381
+ headers,
15382
+ method,
15383
+ redirect: "manual",
15384
+ signal: AbortSignal.timeout(remainingTimeoutMs())
15385
+ })) : yield* resolveSafeAddressesEffect(parsed.hostname, options.resolveHost ?? resolvePublicAddresses, remainingTimeoutMs()).pipe(Effect.filterOrFail(() => Date.now() < deadline, () => /* @__PURE__ */ new Error("Link preview request timed out")), Effect.flatMap((addresses) => tryPromise(() => nodeSafeFetch(parsed, {
15386
+ addresses,
15387
+ headers,
15388
+ method,
15389
+ timeoutMs: remainingTimeoutMs()
15390
+ }))));
15391
+ if (response.status < 300 || response.status >= 400) return response;
15392
+ const location = response.headers.get("location");
15393
+ if (!location) return response;
15394
+ yield* cancelResponseBodyEffect(response);
15395
+ if (redirect === MAX_REDIRECTS) return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview redirected too many times"));
15396
+ currentUrl = yield* Effect.try({
15397
+ try: () => new URL(location, parsed).toString(),
15398
+ catch: (error) => error
15399
+ });
15400
+ }
15401
+ return yield* Effect.fail(/* @__PURE__ */ new Error("Link preview redirected too many times"));
15402
+ });
15362
15403
  function readResponseTextEffect(response) {
15363
15404
  const contentLength = Number(response.headers.get("content-length") ?? 0);
15364
15405
  if (Number.isFinite(contentLength) && contentLength > MAX_HTML_CHARS) return tryPromise(() => response.body?.cancel() ?? Promise.resolve()).pipe(Effect.flatMap(() => Effect.fail(/* @__PURE__ */ new Error("Link preview response is too large"))));
@@ -15422,39 +15463,37 @@ function extractLinkPreviewMetadata(html, url) {
15422
15463
  siteName
15423
15464
  };
15424
15465
  }
15425
- function fetchLinkPreviewMetadataEffect(url, options = {}) {
15426
- return Effect.gen(function* () {
15427
- const response = yield* safePreviewFetchEffect(url, options);
15428
- const finalUrl = response.url || url;
15429
- const contentType = response.headers.get("content-type") ?? "";
15430
- if (!response.ok) {
15431
- yield* cancelResponseBodyEffect(response);
15432
- return yield* Effect.fail(/* @__PURE__ */ new Error(`HTTP ${response.status}`));
15433
- }
15434
- if (contentType.toLowerCase().startsWith("image/")) {
15435
- yield* cancelResponseBodyEffect(response);
15436
- return {
15437
- url: finalUrl,
15438
- title: hostLabel(finalUrl),
15439
- description: null,
15440
- imageUrl: finalUrl,
15441
- siteName: hostLabel(finalUrl)
15442
- };
15443
- }
15444
- const content = yield* readResponseTextEffect(response);
15445
- return yield* Effect.try({
15446
- try: () => extractLinkPreviewMetadata(content.slice(0, MAX_HTML_CHARS), finalUrl),
15447
- catch: (error) => error
15448
- });
15449
- }).pipe(Effect.catchAll((error) => Effect.succeed({
15450
- url,
15451
- title: hostLabel(url),
15452
- description: null,
15453
- imageUrl: youtubeThumbnail(url),
15454
- siteName: hostLabel(url),
15455
- error: error instanceof Error ? error.message : String(error)
15456
- })));
15457
- }
15466
+ var fetchLinkPreviewMetadataEffect = Effect.fn("linkPreview.fetchMetadata")(function* (url, _options = {}) {
15467
+ const response = yield* safePreviewFetchEffect(url, _options);
15468
+ const finalUrl = response.url || url;
15469
+ const contentType = response.headers.get("content-type") ?? "";
15470
+ if (!response.ok) {
15471
+ yield* cancelResponseBodyEffect(response);
15472
+ return yield* Effect.fail(/* @__PURE__ */ new Error(`HTTP ${response.status}`));
15473
+ }
15474
+ if (contentType.toLowerCase().startsWith("image/")) {
15475
+ yield* cancelResponseBodyEffect(response);
15476
+ return {
15477
+ url: finalUrl,
15478
+ title: hostLabel(finalUrl),
15479
+ description: null,
15480
+ imageUrl: finalUrl,
15481
+ siteName: hostLabel(finalUrl)
15482
+ };
15483
+ }
15484
+ const content = yield* readResponseTextEffect(response);
15485
+ return yield* Effect.try({
15486
+ try: () => extractLinkPreviewMetadata(content.slice(0, MAX_HTML_CHARS), finalUrl),
15487
+ catch: (error) => error
15488
+ });
15489
+ }, (effect, url) => Effect.catchAll(effect, (error) => Effect.succeed({
15490
+ url,
15491
+ title: hostLabel(url),
15492
+ description: null,
15493
+ imageUrl: youtubeThumbnail(url),
15494
+ siteName: hostLabel(url),
15495
+ error: error instanceof Error ? error.message : String(error)
15496
+ })));
15458
15497
  function readCachedPreview(db, url, shortUrl) {
15459
15498
  return db.prepare(`
15460
15499
  select short_url, expanded_url, final_url, status, title, description,
@@ -15508,16 +15547,14 @@ function persistPreview(db, url, shortUrl, cached, preview) {
15508
15547
  updatedAt: now
15509
15548
  }));
15510
15549
  }
15511
- function getOrFetchLinkPreviewEffect(url, options = {}) {
15512
- return Effect.gen(function* () {
15513
- const db = getNativeDb({ seedDemoData: false });
15514
- const cached = readCachedPreview(db, url, options.shortUrl);
15515
- if (cached && hasUsefulPreview(cached) && !options.refresh) return rowToPreview(cached);
15516
- const preview = yield* fetchLinkPreviewMetadataEffect(cached?.final_url || cached?.expanded_url || url, options);
15517
- persistPreview(db, url, options.shortUrl, cached, preview);
15518
- return preview;
15519
- });
15520
- }
15550
+ var getOrFetchLinkPreviewEffect = Effect.fn("linkPreview.getOrFetch")(function* (url, options = {}) {
15551
+ const db = getNativeDb({ seedDemoData: false });
15552
+ const cached = readCachedPreview(db, url, options.shortUrl);
15553
+ if (cached && hasUsefulPreview(cached) && !options.refresh) return rowToPreview(cached);
15554
+ const preview = yield* fetchLinkPreviewMetadataEffect(cached?.final_url || cached?.expanded_url || url, options);
15555
+ persistPreview(db, url, options.shortUrl, cached, preview);
15556
+ return preview;
15557
+ });
15521
15558
  ({ ...__test__$1 });
15522
15559
  //#endregion
15523
15560
  //#region src/routes/api/link-preview.tsx
@@ -16116,9 +16153,6 @@ function readBirdStatusViaBirdEffect(query) {
16116
16153
  ]);
16117
16154
  }).pipe(Effect.catchAll(() => Effect.succeed(null)));
16118
16155
  }
16119
- function readBirdStatusViaBird(query) {
16120
- return runEffectPromise(readBirdStatusViaBirdEffect(query));
16121
- }
16122
16156
  function toBirdLookupUser(payload) {
16123
16157
  const user = payload.user && typeof payload.user === "object" ? payload.user : null;
16124
16158
  if (!user) throw new Error("bird user payload missing user object");
@@ -16164,9 +16198,6 @@ function lookupProfileViaBirdEffect(query) {
16164
16198
  });
16165
16199
  }).pipe(Effect.catchAll(() => Effect.succeed(null)));
16166
16200
  }
16167
- function lookupProfileViaBird(query) {
16168
- return runEffectPromise(lookupProfileViaBirdEffect(query));
16169
- }
16170
16201
  function runVerifiedBirdMutationEffect({ action, query, verifyField, expectedValue }) {
16171
16202
  return Effect.gen(function* () {
16172
16203
  const safeQuery = yield* Effect.try({
@@ -16215,9 +16246,6 @@ function blockUserViaBirdEffect(query) {
16215
16246
  expectedValue: true
16216
16247
  });
16217
16248
  }
16218
- function blockUserViaBird(query) {
16219
- return runEffectPromise(blockUserViaBirdEffect(query));
16220
- }
16221
16249
  function unblockUserViaBirdEffect(query) {
16222
16250
  return runVerifiedBirdMutationEffect({
16223
16251
  action: "unblock",
@@ -16226,9 +16254,6 @@ function unblockUserViaBirdEffect(query) {
16226
16254
  expectedValue: false
16227
16255
  });
16228
16256
  }
16229
- function unblockUserViaBird(query) {
16230
- return runEffectPromise(unblockUserViaBirdEffect(query));
16231
- }
16232
16257
  function muteUserViaBirdEffect(query) {
16233
16258
  return runVerifiedBirdMutationEffect({
16234
16259
  action: "mute",
@@ -16237,9 +16262,6 @@ function muteUserViaBirdEffect(query) {
16237
16262
  expectedValue: true
16238
16263
  });
16239
16264
  }
16240
- function muteUserViaBird(query) {
16241
- return runEffectPromise(muteUserViaBirdEffect(query));
16242
- }
16243
16265
  function unmuteUserViaBirdEffect(query) {
16244
16266
  return runVerifiedBirdMutationEffect({
16245
16267
  action: "unmute",
@@ -16248,9 +16270,6 @@ function unmuteUserViaBirdEffect(query) {
16248
16270
  expectedValue: false
16249
16271
  });
16250
16272
  }
16251
- function unmuteUserViaBird(query) {
16252
- return runEffectPromise(unmuteUserViaBirdEffect(query));
16253
- }
16254
16273
  //#endregion
16255
16274
  //#region src/lib/moderation-target.ts
16256
16275
  function toError$4(error) {
@@ -16306,7 +16325,7 @@ function resolveProfileEffect(query, providedDb) {
16306
16325
  if (local && !local.profile.id.startsWith("profile_group_") && local.externalUserId) return local;
16307
16326
  let user;
16308
16327
  let lastError;
16309
- const birdResult = yield* tryPromise(() => lookupProfileViaBird(local?.profile.handle ?? normalizedQuery)).pipe(Effect.map((value) => ({
16328
+ const birdResult = yield* lookupProfileViaBirdEffect(local?.profile.handle ?? normalizedQuery).pipe(Effect.map((value) => ({
16310
16329
  ok: true,
16311
16330
  value
16312
16331
  })), Effect.catchAll((error) => Effect.succeed({
@@ -16316,7 +16335,7 @@ function resolveProfileEffect(query, providedDb) {
16316
16335
  if (birdResult.ok) user = birdResult.value ?? void 0;
16317
16336
  else lastError = birdResult.error;
16318
16337
  if (!user) {
16319
- const xurlResult = yield* tryPromise(() => /^\d+$/.test(normalizedQuery) ? lookupUsersByIds([normalizedQuery]) : lookupUsersByHandles([local?.profile.handle ?? normalizedQuery])).pipe(Effect.map((value) => ({
16338
+ const xurlResult = yield* (/^\d+$/.test(normalizedQuery) ? lookupUsersByIdsEffect([normalizedQuery]) : lookupUsersByHandlesEffect([local?.profile.handle ?? normalizedQuery])).pipe(Effect.map((value) => ({
16320
16339
  ok: true,
16321
16340
  value
16322
16341
  })), Effect.catchAll((error) => Effect.succeed({
@@ -16363,7 +16382,7 @@ function verifyExpectedAccountEffect(expectedAccount) {
16363
16382
  return Effect.gen(function* () {
16364
16383
  if (!expectedAccount) return null;
16365
16384
  if (liveWritesDisabled$1()) return null;
16366
- const sourceUser = yield* tryPromise(() => lookupAuthenticatedUserFresh());
16385
+ const sourceUser = yield* lookupAuthenticatedUserFreshEffect();
16367
16386
  const sourceUserId = sourceUser && typeof sourceUser.id === "string" ? sourceUser.id : "";
16368
16387
  const sourceUsername = sourceUser && typeof sourceUser.username === "string" ? profileHandleKey(sourceUser.username) : "";
16369
16388
  const expectedExternalUserId = expectedAccount.externalUserId?.trim() ?? "";
@@ -16379,7 +16398,7 @@ function verifyExpectedAccountEffect(expectedAccount) {
16379
16398
  function runBirdActionEffect(action, query) {
16380
16399
  return Effect.gen(function* () {
16381
16400
  return {
16382
- ...yield* tryPromise(() => action === "block" ? blockUserViaBird(query) : action === "unblock" ? unblockUserViaBird(query) : action === "mute" ? muteUserViaBird(query) : unmuteUserViaBird(query)),
16401
+ ...yield* action === "block" ? blockUserViaBirdEffect(query) : action === "unblock" ? unblockUserViaBirdEffect(query) : action === "mute" ? muteUserViaBirdEffect(query) : unmuteUserViaBirdEffect(query),
16383
16402
  transport: "bird"
16384
16403
  };
16385
16404
  });
@@ -16402,7 +16421,7 @@ function runXurlActionEffect(action, query, targetUserId, verifiedSourceUserId)
16402
16421
  };
16403
16422
  let sourceUserId = verifiedSourceUserId ?? "";
16404
16423
  if (!sourceUserId) {
16405
- const sourceUser = yield* tryPromise(() => lookupAuthenticatedUserFresh());
16424
+ const sourceUser = yield* lookupAuthenticatedUserFreshEffect();
16406
16425
  sourceUserId = sourceUser && typeof sourceUser.id === "string" ? sourceUser.id : "";
16407
16426
  }
16408
16427
  if (!sourceUserId) return {
@@ -16410,12 +16429,12 @@ function runXurlActionEffect(action, query, targetUserId, verifiedSourceUserId)
16410
16429
  output: "xurl authenticated user unavailable",
16411
16430
  transport: "xurl"
16412
16431
  };
16413
- const result = yield* tryPromise(() => action === "block" ? blockUserViaXurl(sourceUserId, targetUserId) : action === "unblock" ? unblockUserViaXurl(sourceUserId, targetUserId) : action === "mute" ? muteUserViaXurl(sourceUserId, targetUserId) : unmuteUserViaXurl(sourceUserId, targetUserId));
16432
+ const result = yield* action === "block" ? blockUserViaXurlEffect(sourceUserId, targetUserId) : action === "unblock" ? unblockUserViaXurlEffect(sourceUserId, targetUserId) : action === "mute" ? muteUserViaXurlEffect(sourceUserId, targetUserId) : unmuteUserViaXurlEffect(sourceUserId, targetUserId);
16414
16433
  if (!result.ok) return {
16415
16434
  ...result,
16416
16435
  transport: "xurl"
16417
16436
  };
16418
- const status = yield* tryPromise(() => readBirdStatusViaBird(query));
16437
+ const status = yield* readBirdStatusViaBirdEffect(query);
16419
16438
  const { field: verifyField, expected: expectedValue } = getVerifyExpectation(action);
16420
16439
  const actualValue = status && typeof status[verifyField] === "boolean" ? Boolean(status[verifyField]) : null;
16421
16440
  if (actualValue === null) return {
@@ -16819,7 +16838,7 @@ function syncBlocksEffect(accountId) {
16819
16838
  }
16820
16839
  };
16821
16840
  return yield* Effect.gen(function* () {
16822
- const me = yield* tryPromise(() => lookupAuthenticatedUserFresh()).pipe(Effect.mapError(toError$1));
16841
+ const me = yield* lookupAuthenticatedUserFreshEffect();
16823
16842
  const sourceUserId = typeof me?.id === "string" && me.id.length > 0 ? me.id : null;
16824
16843
  const sourceUsername = typeof me?.username === "string" ? me.username.replace(/^@/, "") : "";
16825
16844
  const accountExternalUserId = account?.external_user_id?.trim() ?? "";
@@ -16857,7 +16876,7 @@ function syncBlocksEffect(accountId) {
16857
16876
  let pageCount = 0;
16858
16877
  let completed = false;
16859
16878
  do {
16860
- const page = yield* tryPromise(() => listBlockedUsers(sourceUserId, nextToken ?? void 0)).pipe(Effect.mapError(toError$1));
16879
+ const page = yield* listBlockedUsersEffect(sourceUserId, nextToken ?? void 0);
16861
16880
  const pageProfileIds = yield* databaseWriteEffect((writeDb) => {
16862
16881
  return page.items.map((user) => {
16863
16882
  const resolved = upsertProfileFromXUser(writeDb, user);