birdclaw 0.8.1 → 0.8.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.
- package/CHANGELOG.md +25 -0
- package/package.json +2 -4
- package/scripts/browser-perf.mjs +27 -0
- package/src/cli/command-context.ts +17 -0
- package/src/cli/register-analysis.ts +500 -0
- package/src/cli/register-compose.ts +40 -0
- package/src/cli/register-graph.ts +132 -0
- package/src/cli/register-inbox.ts +41 -0
- package/src/cli/register-storage.ts +106 -0
- package/src/cli.ts +30 -750
- package/src/components/AccountSwitcher.tsx +7 -15
- package/src/components/AvatarChip.tsx +1 -1
- package/src/components/AvatarPreload.ts +149 -0
- package/src/components/ConversationThread.tsx +4 -0
- package/src/components/EmbeddedTweetCard.tsx +4 -0
- package/src/components/FloatingPreview.tsx +382 -0
- package/src/components/MarkdownCitations.tsx +680 -0
- package/src/components/MarkdownViewer.tsx +7 -715
- package/src/components/ProfileAnalysisClient.ts +191 -0
- package/src/components/ProfileAnalysisStream.tsx +16 -185
- package/src/components/ProfilePreview.tsx +41 -81
- package/src/components/TimelineCard.tsx +18 -2
- package/src/components/TweetArticleCard.tsx +66 -0
- package/src/components/TweetRichText.tsx +33 -2
- package/src/components/links-controller.ts +162 -0
- package/src/components/links-model.ts +198 -0
- package/src/components/network-map-controller.ts +84 -0
- package/src/components/network-map-model.ts +255 -0
- package/src/components/useDebouncedValue.ts +12 -0
- package/src/components/useTimelineRouteData.ts +142 -170
- package/src/lib/analysis-runtime.ts +238 -0
- package/src/lib/api-client.ts +16 -100
- package/src/lib/api-contracts.ts +328 -0
- package/src/lib/archive-finder.ts +38 -0
- package/src/lib/archive-import-plan.ts +102 -0
- package/src/lib/archive-import.ts +170 -239
- package/src/lib/authored-live.ts +77 -182
- package/src/lib/backup.ts +335 -424
- package/src/lib/bird.ts +32 -1
- package/src/lib/blocks-write.ts +30 -26
- package/src/lib/blocks.ts +18 -20
- package/src/lib/database-metrics.ts +88 -0
- package/src/lib/database-migrations.ts +34 -0
- package/src/lib/database-schema.ts +312 -0
- package/src/lib/database-writer.ts +69 -0
- package/src/lib/db.ts +141 -334
- package/src/lib/dm-read-model.ts +533 -0
- package/src/lib/dms-live.ts +34 -97
- package/src/lib/follow-graph.ts +17 -27
- package/src/lib/import-repository.ts +138 -0
- package/src/lib/inbox.ts +2 -1
- package/src/lib/live-sync-engine.ts +209 -0
- package/src/lib/live-transport-gateway.ts +128 -0
- package/src/lib/mention-threads-live.ts +90 -176
- package/src/lib/mentions-export.ts +1 -1
- package/src/lib/mentions-live.ts +57 -225
- package/src/lib/moderation-target.ts +15 -4
- package/src/lib/moderation-write.ts +1 -1
- package/src/lib/mutes-write.ts +30 -26
- package/src/lib/openai-response-runtime.ts +251 -0
- package/src/lib/paginated-sync.ts +93 -0
- package/src/lib/period-digest.ts +116 -304
- package/src/lib/profile-analysis.ts +37 -111
- package/src/lib/queries.ts +6 -2380
- package/src/lib/query-actions.ts +437 -0
- package/src/lib/query-client.tsx +47 -0
- package/src/lib/query-read-model-shared.ts +52 -0
- package/src/lib/query-read-models.ts +5 -0
- package/src/lib/query-resource.ts +41 -0
- package/src/lib/query-status.ts +164 -0
- package/src/lib/research.ts +1 -1
- package/src/lib/runtime-services.ts +20 -0
- package/src/lib/search-discussion.ts +75 -279
- package/src/lib/server-runtime-services.ts +30 -0
- package/src/lib/sqlite.ts +53 -14
- package/src/lib/streaming-ingestion.ts +240 -0
- package/src/lib/sync-cache.ts +6 -1
- package/src/lib/sync-plan.ts +175 -0
- package/src/lib/timeline-collections-live.ts +83 -256
- package/src/lib/timeline-live.ts +86 -235
- package/src/lib/timeline-read-model.ts +1191 -0
- package/src/lib/tweet-render.ts +78 -0
- package/src/lib/tweet-repository.ts +156 -0
- package/src/lib/tweet-search-live.ts +63 -166
- package/src/lib/types.ts +8 -0
- package/src/lib/ui.ts +1 -1
- package/src/lib/web-sync.ts +67 -50
- package/src/lib/whois.ts +2 -1
- package/src/router.tsx +1 -1
- package/src/routes/__root.tsx +11 -21
- package/src/routes/api/action.tsx +1 -1
- package/src/routes/api/conversation.tsx +1 -1
- package/src/routes/api/query.tsx +32 -26
- package/src/routes/api/status.tsx +6 -2
- package/src/routes/api/sync.tsx +5 -2
- package/src/routes/blocks.tsx +97 -131
- package/src/routes/data-sources.tsx +17 -25
- package/src/routes/dms.tsx +168 -167
- package/src/routes/inbox.tsx +63 -57
- package/src/routes/links.tsx +31 -329
- package/src/routes/network-map.tsx +41 -344
- package/src/routes/rate-limits.tsx +17 -21
- package/vite.config.ts +0 -2
package/src/lib/web-sync.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
3
|
import { maybeAutoSyncBackupEffect } from "./backup";
|
|
4
|
-
import { getBirdclawPaths } from "./config";
|
|
5
4
|
import { syncDirectMessagesViaCachedBirdEffect } from "./dms-live";
|
|
6
5
|
import { runEffectBackground, runEffectPromise } from "./effect-runtime";
|
|
7
6
|
import { syncMentionThreadsEffect } from "./mention-threads-live";
|
|
8
7
|
import { syncMentionsEffect } from "./mentions-live";
|
|
8
|
+
import {
|
|
9
|
+
defaultServerRuntimeServices,
|
|
10
|
+
type ServerRuntimeServices,
|
|
11
|
+
} from "./server-runtime-services";
|
|
9
12
|
import NativeSqliteDatabase from "./sqlite";
|
|
10
13
|
import { syncTimelineCollectionEffect } from "./timeline-collections-live";
|
|
11
14
|
import { syncHomeTimelineEffect } from "./timeline-live";
|
|
@@ -69,6 +72,7 @@ interface WebSyncPlan {
|
|
|
69
72
|
run: (
|
|
70
73
|
accountId: string | undefined,
|
|
71
74
|
options: WebSyncOptions,
|
|
75
|
+
runtime: ServerRuntimeServices,
|
|
72
76
|
) => Effect.Effect<WebSyncStep[], unknown>;
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -132,12 +136,12 @@ const WEB_SYNC_PLANS: Record<WebSyncKind, WebSyncPlan> = {
|
|
|
132
136
|
timeline: {
|
|
133
137
|
label: "Home timeline",
|
|
134
138
|
accountAware: true,
|
|
135
|
-
run: (account) =>
|
|
139
|
+
run: (account, _options, runtime) =>
|
|
136
140
|
Effect.gen(function* () {
|
|
137
141
|
const result = yield* syncHomeTimelineEffect({
|
|
138
142
|
account,
|
|
139
143
|
mode:
|
|
140
|
-
!account || account === resolveDefaultSyncAccountId()
|
|
144
|
+
!account || account === resolveDefaultSyncAccountId(runtime)
|
|
141
145
|
? "auto"
|
|
142
146
|
: "xurl",
|
|
143
147
|
limit: 100,
|
|
@@ -201,12 +205,14 @@ const WEB_SYNC_PLANS: Record<WebSyncKind, WebSyncPlan> = {
|
|
|
201
205
|
likes: {
|
|
202
206
|
label: "Likes",
|
|
203
207
|
accountAware: true,
|
|
204
|
-
run: (account
|
|
208
|
+
run: (account, _options, runtime) =>
|
|
209
|
+
syncSavedCollection("likes", account, runtime),
|
|
205
210
|
},
|
|
206
211
|
bookmarks: {
|
|
207
212
|
label: "Bookmarks",
|
|
208
213
|
accountAware: true,
|
|
209
|
-
run: (account
|
|
214
|
+
run: (account, _options, runtime) =>
|
|
215
|
+
syncSavedCollection("bookmarks", account, runtime),
|
|
210
216
|
},
|
|
211
217
|
dms: {
|
|
212
218
|
label: "Direct messages",
|
|
@@ -242,10 +248,11 @@ const WEB_SYNC_PLANS: Record<WebSyncKind, WebSyncPlan> = {
|
|
|
242
248
|
function syncSavedCollection(
|
|
243
249
|
kind: "likes" | "bookmarks",
|
|
244
250
|
account: string | undefined,
|
|
251
|
+
runtime: ServerRuntimeServices,
|
|
245
252
|
): Effect.Effect<WebSyncStep[], unknown> {
|
|
246
253
|
return Effect.gen(function* () {
|
|
247
254
|
const isNonDefaultAccount =
|
|
248
|
-
account !== undefined && account !== resolveDefaultSyncAccountId();
|
|
255
|
+
account !== undefined && account !== resolveDefaultSyncAccountId(runtime);
|
|
249
256
|
const result = yield* syncTimelineCollectionEffect({
|
|
250
257
|
kind,
|
|
251
258
|
account,
|
|
@@ -270,13 +277,14 @@ export function performWebSyncEffect(
|
|
|
270
277
|
kind: WebSyncKind,
|
|
271
278
|
accountId?: string,
|
|
272
279
|
options: WebSyncOptions = {},
|
|
280
|
+
runtime: ServerRuntimeServices = defaultServerRuntimeServices,
|
|
273
281
|
) {
|
|
274
282
|
return Effect.gen(function* () {
|
|
275
|
-
const startedAt =
|
|
276
|
-
const steps = yield* WEB_SYNC_PLANS[kind].run(accountId, options);
|
|
283
|
+
const startedAt = runtime.now().toISOString();
|
|
284
|
+
const steps = yield* WEB_SYNC_PLANS[kind].run(accountId, options, runtime);
|
|
277
285
|
|
|
278
286
|
const backup = yield* maybeAutoSyncBackupEffect();
|
|
279
|
-
const finishedAt =
|
|
287
|
+
const finishedAt = runtime.now().toISOString();
|
|
280
288
|
return {
|
|
281
289
|
ok: true,
|
|
282
290
|
kind,
|
|
@@ -290,12 +298,12 @@ export function performWebSyncEffect(
|
|
|
290
298
|
});
|
|
291
299
|
}
|
|
292
300
|
|
|
293
|
-
function createWebSyncJobId(kind: WebSyncKind) {
|
|
294
|
-
return `sync_${kind}_${
|
|
301
|
+
function createWebSyncJobId(kind: WebSyncKind, runtime: ServerRuntimeServices) {
|
|
302
|
+
return `sync_${kind}_${runtime.now().getTime().toString(36)}_${runtime.random().toString(36).slice(2, 8)}`;
|
|
295
303
|
}
|
|
296
304
|
|
|
297
|
-
function resolveDefaultSyncAccountId() {
|
|
298
|
-
const dbPath =
|
|
305
|
+
function resolveDefaultSyncAccountId(runtime: ServerRuntimeServices) {
|
|
306
|
+
const dbPath = runtime.getPaths().dbPath;
|
|
299
307
|
if (!existsSync(dbPath)) {
|
|
300
308
|
return "acct_primary";
|
|
301
309
|
}
|
|
@@ -336,12 +344,13 @@ function getRunningSyncKey(
|
|
|
336
344
|
kind: WebSyncKind,
|
|
337
345
|
accountId: string | undefined,
|
|
338
346
|
options: WebSyncOptions = {},
|
|
347
|
+
runtime: ServerRuntimeServices = defaultServerRuntimeServices,
|
|
339
348
|
) {
|
|
340
349
|
if (!WEB_SYNC_PLANS[kind].accountAware) {
|
|
341
350
|
const optionKey = serializeSyncOptions(kind, options);
|
|
342
351
|
return optionKey ? `${kind}:${optionKey}` : kind;
|
|
343
352
|
}
|
|
344
|
-
return `${kind}:${accountId ?? resolveDefaultSyncAccountId()}`;
|
|
353
|
+
return `${kind}:${accountId ?? resolveDefaultSyncAccountId(runtime)}`;
|
|
345
354
|
}
|
|
346
355
|
|
|
347
356
|
function getEffectiveAccountId(
|
|
@@ -380,8 +389,9 @@ function toFailedResponse(
|
|
|
380
389
|
startedAt: string,
|
|
381
390
|
error: unknown,
|
|
382
391
|
accountId?: string,
|
|
392
|
+
runtime: ServerRuntimeServices = defaultServerRuntimeServices,
|
|
383
393
|
): WebSyncResponse {
|
|
384
|
-
const finishedAt =
|
|
394
|
+
const finishedAt = runtime.now().toISOString();
|
|
385
395
|
const message = messageFromError(error);
|
|
386
396
|
return {
|
|
387
397
|
ok: false,
|
|
@@ -399,17 +409,18 @@ export function startWebSync(
|
|
|
399
409
|
kind: WebSyncKind,
|
|
400
410
|
accountId?: string,
|
|
401
411
|
options: WebSyncOptions = {},
|
|
412
|
+
runtime: ServerRuntimeServices = defaultServerRuntimeServices,
|
|
402
413
|
): WebSyncJobSnapshot {
|
|
403
414
|
const effectiveAccountId = getEffectiveAccountId(kind, accountId);
|
|
404
|
-
const syncKey = getRunningSyncKey(kind, effectiveAccountId, options);
|
|
415
|
+
const syncKey = getRunningSyncKey(kind, effectiveAccountId, options, runtime);
|
|
405
416
|
const current = runningSyncs.get(syncKey);
|
|
406
417
|
if (current) {
|
|
407
418
|
return current;
|
|
408
419
|
}
|
|
409
420
|
|
|
410
|
-
const startedAt =
|
|
421
|
+
const startedAt = runtime.now().toISOString();
|
|
411
422
|
const job: WebSyncJobSnapshot = {
|
|
412
|
-
id: createWebSyncJobId(kind),
|
|
423
|
+
id: createWebSyncJobId(kind, runtime),
|
|
413
424
|
kind,
|
|
414
425
|
...(effectiveAccountId ? { accountId: effectiveAccountId } : {}),
|
|
415
426
|
status: "running",
|
|
@@ -420,35 +431,39 @@ export function startWebSync(
|
|
|
420
431
|
webSyncJobKeys.set(job.id, syncKey);
|
|
421
432
|
setJobSnapshot(job);
|
|
422
433
|
|
|
423
|
-
runEffectBackground(
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
434
|
+
runEffectBackground(
|
|
435
|
+
performWebSyncEffect(kind, effectiveAccountId, options, runtime),
|
|
436
|
+
{
|
|
437
|
+
onSuccess: (result) => {
|
|
438
|
+
setJobSnapshot({
|
|
439
|
+
...job,
|
|
440
|
+
status: "succeeded",
|
|
441
|
+
finishedAt: result.finishedAt,
|
|
442
|
+
summary: result.summary,
|
|
443
|
+
inProgress: false,
|
|
444
|
+
result,
|
|
445
|
+
});
|
|
446
|
+
},
|
|
447
|
+
onFailure: (error) => {
|
|
448
|
+
const result = toFailedResponse(
|
|
449
|
+
kind,
|
|
450
|
+
startedAt,
|
|
451
|
+
error,
|
|
452
|
+
effectiveAccountId,
|
|
453
|
+
runtime,
|
|
454
|
+
);
|
|
455
|
+
setJobSnapshot({
|
|
456
|
+
...job,
|
|
457
|
+
status: "failed",
|
|
458
|
+
finishedAt: result.finishedAt,
|
|
459
|
+
summary: result.summary,
|
|
460
|
+
inProgress: false,
|
|
461
|
+
result,
|
|
462
|
+
error: result.error,
|
|
463
|
+
});
|
|
464
|
+
},
|
|
450
465
|
},
|
|
451
|
-
|
|
466
|
+
);
|
|
452
467
|
|
|
453
468
|
return job;
|
|
454
469
|
}
|
|
@@ -461,13 +476,14 @@ export function runWebSyncEffect(
|
|
|
461
476
|
kind: WebSyncKind,
|
|
462
477
|
accountId?: string,
|
|
463
478
|
options: WebSyncOptions = {},
|
|
479
|
+
runtime: ServerRuntimeServices = defaultServerRuntimeServices,
|
|
464
480
|
): Effect.Effect<WebSyncResponse, Error> {
|
|
465
481
|
return Effect.gen(function* () {
|
|
466
482
|
const effectiveAccountId = getEffectiveAccountId(kind, accountId);
|
|
467
483
|
const current = runningSyncs.get(
|
|
468
|
-
getRunningSyncKey(kind, effectiveAccountId, options),
|
|
484
|
+
getRunningSyncKey(kind, effectiveAccountId, options, runtime),
|
|
469
485
|
);
|
|
470
|
-
const startedAt =
|
|
486
|
+
const startedAt = runtime.now().toISOString();
|
|
471
487
|
if (current) {
|
|
472
488
|
return {
|
|
473
489
|
ok: false,
|
|
@@ -480,7 +496,7 @@ export function runWebSyncEffect(
|
|
|
480
496
|
} satisfies WebSyncResponse;
|
|
481
497
|
}
|
|
482
498
|
|
|
483
|
-
const job = startWebSync(kind, effectiveAccountId, options);
|
|
499
|
+
const job = startWebSync(kind, effectiveAccountId, options, runtime);
|
|
484
500
|
while (job.inProgress) {
|
|
485
501
|
yield* Effect.sleep(25);
|
|
486
502
|
const latest = getWebSyncJob(job.id);
|
|
@@ -501,8 +517,9 @@ export function runWebSync(
|
|
|
501
517
|
kind: WebSyncKind,
|
|
502
518
|
accountId?: string,
|
|
503
519
|
options: WebSyncOptions = {},
|
|
520
|
+
runtime: ServerRuntimeServices = defaultServerRuntimeServices,
|
|
504
521
|
): Promise<WebSyncResponse> {
|
|
505
|
-
return runEffectPromise(runWebSyncEffect(kind, accountId, options));
|
|
522
|
+
return runEffectPromise(runWebSyncEffect(kind, accountId, options, runtime));
|
|
506
523
|
}
|
|
507
524
|
|
|
508
525
|
export function clearWebSyncLocksForTests() {
|
package/src/lib/whois.ts
CHANGED
|
@@ -9,7 +9,8 @@ import { fetchProfileBioEntities } from "./profile-bio-entities";
|
|
|
9
9
|
import { fetchProfileSnapshots } from "./profile-history";
|
|
10
10
|
import { resolveProfilesForIdsEffect } from "./profile-resolver";
|
|
11
11
|
import type { ProfileResolveResult } from "./profile-resolver";
|
|
12
|
-
import { listDmConversations
|
|
12
|
+
import { listDmConversations } from "./dm-read-model";
|
|
13
|
+
import { listTimelineItems } from "./timeline-read-model";
|
|
13
14
|
import { expandUrlsFromTextsEffect } from "./url-expansion";
|
|
14
15
|
import type {
|
|
15
16
|
DmConversationItem,
|
package/src/router.tsx
CHANGED
package/src/routes/__root.tsx
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { TanStackDevtools } from "@tanstack/react-devtools";
|
|
2
1
|
import {
|
|
3
2
|
createRootRoute,
|
|
4
3
|
HeadContent,
|
|
5
4
|
Scripts,
|
|
6
5
|
useRouterState,
|
|
7
6
|
} from "@tanstack/react-router";
|
|
8
|
-
import { TanStackRouterDevtoolsPanel } from "@tanstack/react-router-devtools";
|
|
9
7
|
import type { ReactNode } from "react";
|
|
10
8
|
import { AppNav } from "#/components/AppNav";
|
|
9
|
+
import { BirdclawQueryProvider } from "#/lib/query-client";
|
|
11
10
|
import { ThemeProvider, themeScript } from "#/lib/theme";
|
|
12
11
|
import {
|
|
13
12
|
bodyClass,
|
|
@@ -66,25 +65,16 @@ function RootDocument({ children }: { children: ReactNode }) {
|
|
|
66
65
|
<script suppressHydrationWarning>{themeScript}</script>
|
|
67
66
|
</head>
|
|
68
67
|
<body className={bodyClass}>
|
|
69
|
-
<
|
|
70
|
-
<
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
position: "bottom-right",
|
|
80
|
-
}}
|
|
81
|
-
plugins={[
|
|
82
|
-
{
|
|
83
|
-
name: "Tanstack Router",
|
|
84
|
-
render: <TanStackRouterDevtoolsPanel />,
|
|
85
|
-
},
|
|
86
|
-
]}
|
|
87
|
-
/>
|
|
68
|
+
<BirdclawQueryProvider>
|
|
69
|
+
<ThemeProvider>
|
|
70
|
+
<div className={wideMode ? siteShellDmClass : siteShellClass}>
|
|
71
|
+
<AppNav compact={wideMode} />
|
|
72
|
+
<main className={wideMode ? mainColumnDmClass : mainColumnClass}>
|
|
73
|
+
{children}
|
|
74
|
+
</main>
|
|
75
|
+
</div>
|
|
76
|
+
</ThemeProvider>
|
|
77
|
+
</BirdclawQueryProvider>
|
|
88
78
|
<Scripts />
|
|
89
79
|
</body>
|
|
90
80
|
</html>
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
runRouteEffect,
|
|
6
6
|
sensitiveRequestErrorResponse,
|
|
7
7
|
} from "#/lib/http-effect";
|
|
8
|
-
import { getTweetConversation } from "#/lib/
|
|
8
|
+
import { getTweetConversation } from "#/lib/timeline-read-model";
|
|
9
9
|
|
|
10
10
|
function json(data: unknown, status = 200) {
|
|
11
11
|
return new Response(JSON.stringify(data), {
|
package/src/routes/api/query.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
+
import { queryResponseSchema } from "#/lib/api-contracts";
|
|
3
4
|
import { maybeAutoUpdateBackupEffect } from "#/lib/backup";
|
|
4
5
|
import {
|
|
5
6
|
jsonResponse,
|
|
@@ -7,7 +8,7 @@ import {
|
|
|
7
8
|
runRouteEffect,
|
|
8
9
|
sensitiveRequestErrorResponse,
|
|
9
10
|
} from "#/lib/http-effect";
|
|
10
|
-
import { queryResource } from "#/lib/
|
|
11
|
+
import { queryResource } from "#/lib/query-resource";
|
|
11
12
|
import type {
|
|
12
13
|
DmQuery,
|
|
13
14
|
ReplyFilter,
|
|
@@ -78,35 +79,40 @@ export const Route = createFileRoute("/api/query")({
|
|
|
78
79
|
|
|
79
80
|
if (resource === "dms") {
|
|
80
81
|
return jsonResponse(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
url.searchParams.get("
|
|
100
|
-
|
|
82
|
+
queryResponseSchema.parse(
|
|
83
|
+
queryResource("dms", {
|
|
84
|
+
...baseFilters,
|
|
85
|
+
participant:
|
|
86
|
+
url.searchParams.get("participant") ?? undefined,
|
|
87
|
+
minFollowers: parseOptionalNumber(
|
|
88
|
+
url.searchParams.get("minFollowers"),
|
|
89
|
+
),
|
|
90
|
+
maxFollowers: parseOptionalNumber(
|
|
91
|
+
url.searchParams.get("maxFollowers"),
|
|
92
|
+
),
|
|
93
|
+
minInfluenceScore: parseOptionalNumber(
|
|
94
|
+
url.searchParams.get("minInfluenceScore"),
|
|
95
|
+
),
|
|
96
|
+
maxInfluenceScore: parseOptionalNumber(
|
|
97
|
+
url.searchParams.get("maxInfluenceScore"),
|
|
98
|
+
),
|
|
99
|
+
sort: parseDmSort(url.searchParams.get("sort")),
|
|
100
|
+
inbox: parseDmInbox(url.searchParams.get("inbox")),
|
|
101
|
+
conversationId:
|
|
102
|
+
url.searchParams.get("conversationId") ?? undefined,
|
|
103
|
+
}),
|
|
104
|
+
),
|
|
101
105
|
);
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
return jsonResponse(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
queryResponseSchema.parse(
|
|
110
|
+
queryResource(resource, {
|
|
111
|
+
...baseFilters,
|
|
112
|
+
resource,
|
|
113
|
+
untilId: url.searchParams.get("untilId") ?? undefined,
|
|
114
|
+
}),
|
|
115
|
+
),
|
|
110
116
|
);
|
|
111
117
|
}),
|
|
112
118
|
),
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
+
import { queryEnvelopeSchema } from "#/lib/api-contracts";
|
|
3
4
|
import { maybeAutoUpdateBackupEffect } from "#/lib/backup";
|
|
4
5
|
import {
|
|
5
6
|
jsonResponse,
|
|
6
7
|
runRouteEffect,
|
|
7
8
|
sensitiveRequestErrorResponse,
|
|
8
9
|
} from "#/lib/http-effect";
|
|
9
|
-
import { getQueryEnvelopeEffect } from "#/lib/
|
|
10
|
+
import { getQueryEnvelopeEffect } from "#/lib/query-status";
|
|
10
11
|
|
|
11
12
|
export const Route = createFileRoute("/api/status")({
|
|
12
13
|
server: {
|
|
@@ -18,7 +19,10 @@ export const Route = createFileRoute("/api/status")({
|
|
|
18
19
|
if (denied) return denied;
|
|
19
20
|
|
|
20
21
|
yield* maybeAutoUpdateBackupEffect();
|
|
21
|
-
|
|
22
|
+
const envelope = yield* getQueryEnvelopeEffect({
|
|
23
|
+
includeArchives: false,
|
|
24
|
+
});
|
|
25
|
+
return jsonResponse(queryEnvelopeSchema.parse(envelope));
|
|
22
26
|
}),
|
|
23
27
|
),
|
|
24
28
|
},
|
package/src/routes/api/sync.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
+
import { webSyncJobSchema } from "#/lib/api-contracts";
|
|
3
4
|
import {
|
|
4
5
|
jsonResponse,
|
|
5
6
|
requestJsonEffect,
|
|
@@ -72,7 +73,7 @@ export const Route = createFileRoute("/api/sync")({
|
|
|
72
73
|
);
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
return jsonResponse(job);
|
|
76
|
+
return jsonResponse(webSyncJobSchema.parse(job));
|
|
76
77
|
},
|
|
77
78
|
POST: ({ request }) =>
|
|
78
79
|
runRouteEffect(
|
|
@@ -97,7 +98,9 @@ export const Route = createFileRoute("/api/sync")({
|
|
|
97
98
|
parseAccountId(body.accountId),
|
|
98
99
|
parseSyncOptions(kind, body),
|
|
99
100
|
);
|
|
100
|
-
return jsonResponse(job, {
|
|
101
|
+
return jsonResponse(webSyncJobSchema.parse(job), {
|
|
102
|
+
status: job.inProgress ? 202 : 200,
|
|
103
|
+
});
|
|
101
104
|
}),
|
|
102
105
|
),
|
|
103
106
|
},
|