@dev.fast/whiteboard 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +146 -2
- package/THIRD_PARTY_NOTICES.md +93 -0
- package/dist/account-alias-DOHN1RSH.js +973 -0
- package/dist/agent-cli-ChOq0ZuO.js +117 -0
- package/dist/agent-cli-DzWfZr6G.js +2 -0
- package/dist/agent-client-CPQo7iTI.js +305 -0
- package/dist/authoring-tools-Cr6Kpjsx.js +234 -0
- package/dist/build-info.json +1 -0
- package/dist/cli-hVgHcdsv.js +47 -0
- package/dist/cli-runner-D8y2_luU.js +5095 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +128 -0
- package/dist/client-DFoh50W3.js +950 -0
- package/dist/desktop-discovery-DBO-PM2V.js +164 -0
- package/dist/error-message-OtiDonty.js +6 -0
- package/dist/fs-utils-BMPLt0cr.js +22 -0
- package/dist/fuzzy-match-BoAmcyak.js +30 -0
- package/dist/headless-host-BJxf4dUU.js +94 -0
- package/dist/input-error-OLgB_h31.js +11 -0
- package/dist/local-data-CxLk75rx.js +4491 -0
- package/dist/mcp-QeF8vkdf.js +140 -0
- package/dist/package-paths-B6-zxvIO.js +47 -0
- package/dist/process-error-telemetry-v9e5h6D7.js +3952 -0
- package/dist/profile-4ry2f3AM.js +76 -0
- package/dist/profile-Bh5FIrmf.js +2 -0
- package/dist/request-origin-D_4QIdoN.js +811 -0
- package/dist/review-agent-traces-DNJFYzc8.js +3866 -0
- package/dist/review-home-paths-6zZH-1c9.js +2560 -0
- package/dist/review-telemetry-DEFnQsQ2.js +1195 -0
- package/dist/runtime-CKiWhGrf.js +52 -0
- package/dist/runtime.d.ts +9 -0
- package/dist/runtime.js +2 -0
- package/dist/s3-SzLpeCG6.js +345 -0
- package/dist/s3-config-BgxkSoOy.js +2 -0
- package/dist/s3-config-CAxhO9u_.js +676 -0
- package/dist/server/desktop-host.d.ts +4 -0
- package/dist/server/desktop-host.js +1702 -0
- package/dist/server-discovery-Dbzn3w6Z.js +66 -0
- package/dist/sharing/index.d.ts +1977 -0
- package/dist/sharing/index.js +2 -0
- package/dist/src-CGP5ytbV.js +283 -0
- package/dist/src-CmdiBL20.js +3676 -0
- package/dist/src-DnwdaQ2r.js +865 -0
- package/dist/src-X9phtB2j.js +68 -0
- package/dist/stored-document-migration-DHeMpLMb.js +2671 -0
- package/dist/tool-failure-C8zB73HV.js +98 -0
- package/dist/tutorial-trace-DrBvkaeL.js +43 -0
- package/instructions/authoring.md +36 -0
- package/instructions/file-lenses.md +13 -0
- package/instructions/scratchpad.md +23 -0
- package/instructions/trace-archaeology.md +113 -0
- package/onboarding.md +8 -0
- package/package.json +106 -3
- package/src/agent-selection.ts +100 -0
- package/src/agent-session-ref.ts +80 -0
- package/src/ask/agents.ts +351 -0
- package/src/ask/checkout-files.ts +47 -0
- package/src/ask/file-refs.ts +111 -0
- package/src/ask/pi-mcp.ts +154 -0
- package/src/ask/protocol.ts +244 -0
- package/src/ask/thread-state.ts +350 -0
- package/src/ask/thread.ts +1400 -0
- package/src/ask/threads.ts +219 -0
- package/src/ask/watch.ts +79 -0
- package/src/cli-install.ts +1041 -0
- package/src/cli-runner.ts +1461 -0
- package/src/cli-runtime-info.ts +35 -0
- package/src/cli.ts +222 -0
- package/src/connect-prompts.ts +248 -0
- package/src/cursor-deeplink.ts +11 -0
- package/src/desktop-discovery.ts +355 -0
- package/src/diff-selection-migration.ts +63 -0
- package/src/embedded-posthog-key.ts +6 -0
- package/src/error-telemetry.ts +247 -0
- package/src/evidence.ts +14 -0
- package/src/exception-telemetry.ts +126 -0
- package/src/fixtures/blocks/call_stack_diff.json +27 -0
- package/src/fixtures/blocks/callout.json +11 -0
- package/src/fixtures/blocks/code.json +9 -0
- package/src/fixtures/blocks/code_peek.json +8 -0
- package/src/fixtures/blocks/database_lens.json +51 -0
- package/src/fixtures/blocks/divider.json +1 -0
- package/src/fixtures/blocks/fixtures.ts +33 -0
- package/src/fixtures/blocks/flow_diagram.json +36 -0
- package/src/fixtures/blocks/ids.ts +8 -0
- package/src/fixtures/blocks/image.json +9 -0
- package/src/fixtures/blocks/markdown.json +7 -0
- package/src/fixtures/blocks/section.json +11 -0
- package/src/fixtures/blocks/sequence.json +31 -0
- package/src/fixtures/blocks/software_map.json +7 -0
- package/src/fixtures/blocks/trace_quote.json +9 -0
- package/src/fixtures/blocks/tutorial.json +51 -0
- package/src/fs-utils.ts +32 -0
- package/src/fuzzy-match.ts +94 -0
- package/src/install.ts +29 -0
- package/src/legacy-skills.ts +133 -0
- package/src/lens-selection.ts +230 -0
- package/src/markdown-latex-math.ts +230 -0
- package/src/markdown.ts +81 -0
- package/src/package-paths.ts +53 -0
- package/src/posthog-capture-client.ts +610 -0
- package/src/review-api/README.md +295 -0
- package/src/review-api/activity.ts +340 -0
- package/src/review-api/agent-cli.ts +219 -0
- package/src/review-api/agent-client.ts +188 -0
- package/src/review-api/anchor-quotes.ts +88 -0
- package/src/review-api/ask-history.ts +242 -0
- package/src/review-api/authoring-tools.ts +211 -0
- package/src/review-api/blocks/call_stack_diff.ts +75 -0
- package/src/review-api/blocks/callout.ts +24 -0
- package/src/review-api/blocks/code.ts +9 -0
- package/src/review-api/blocks/code_peek.ts +13 -0
- package/src/review-api/blocks/database_lens.ts +150 -0
- package/src/review-api/blocks/definition.ts +40 -0
- package/src/review-api/blocks/divider.ts +6 -0
- package/src/review-api/blocks/flow_diagram.ts +111 -0
- package/src/review-api/blocks/image.ts +10 -0
- package/src/review-api/blocks/index.ts +90 -0
- package/src/review-api/blocks/markdown.ts +17 -0
- package/src/review-api/blocks/section.ts +24 -0
- package/src/review-api/blocks/sequence.ts +56 -0
- package/src/review-api/blocks/software_map.ts +9 -0
- package/src/review-api/blocks/trace_quote.ts +10 -0
- package/src/review-api/blocks/tutorial.ts +39 -0
- package/src/review-api/checkout-fs.ts +14 -0
- package/src/review-api/client.ts +1 -0
- package/src/review-api/comparison-coverage.ts +304 -0
- package/src/review-api/component-reference.ts +30 -0
- package/src/review-api/diff-lenses.ts +175 -0
- package/src/review-api/document-headings.ts +51 -0
- package/src/review-api/document-text.ts +200 -0
- package/src/review-api/document.ts +906 -0
- package/src/review-api/file-lenses.ts +100 -0
- package/src/review-api/http.ts +1877 -0
- package/src/review-api/image-decode.ts +29 -0
- package/src/review-api/input-error.ts +9 -0
- package/src/review-api/instructions.ts +89 -0
- package/src/review-api/lens-alignment.ts +52 -0
- package/src/review-api/local-data.ts +1837 -0
- package/src/review-api/map-input.ts +154 -0
- package/src/review-api/mcp-client-agent.ts +32 -0
- package/src/review-api/mcp.ts +240 -0
- package/src/review-api/origin.ts +43 -0
- package/src/review-api/profile.ts +146 -0
- package/src/review-api/public-tools.ts +102 -0
- package/src/review-api/pull-request.ts +389 -0
- package/src/review-api/read-schemas.ts +85 -0
- package/src/review-api/recovery.ts +2 -0
- package/src/review-api/request-origin.ts +33 -0
- package/src/review-api/review-progress.ts +382 -0
- package/src/review-api/status-tool.ts +10 -0
- package/src/review-api/store-schema.ts +22 -0
- package/src/review-api/store.ts +1647 -0
- package/src/review-api/tool-failure.ts +64 -0
- package/src/review-api/trace-schema.ts +13 -0
- package/src/review-api/traces.ts +119 -0
- package/src/review-api/unsupported-files.integration.ts +91 -0
- package/src/review-api/workspaces.ts +692 -0
- package/src/review-api/worktree-source.ts +170 -0
- package/src/review-api/worktree-structural.integration.ts +320 -0
- package/src/review-app-launcher.ts +432 -0
- package/src/review-app-picker.ts +168 -0
- package/src/review-app.ts +134 -0
- package/src/review-bundled-tools.ts +249 -0
- package/src/review-checkout-paths.ts +37 -0
- package/src/review-diff-files.ts +89 -0
- package/src/review-head-checkout.ts +300 -0
- package/src/review-home-paths.ts +73 -0
- package/src/review-info.ts +59 -0
- package/src/review-instances.ts +113 -0
- package/src/review-logger.ts +183 -0
- package/src/review-preferences.ts +88 -0
- package/src/review-prepare.ts +291 -0
- package/src/review-stack.ts +112 -0
- package/src/review-telemetry.ts +1066 -0
- package/src/runtime.ts +74 -0
- package/src/server/account-alias.ts +30 -0
- package/src/server/bounded-stream.ts +34 -0
- package/src/server/bug-report.ts +301 -0
- package/src/server/client-error-budget.ts +45 -0
- package/src/server/crash-report.ts +273 -0
- package/src/server/desktop-host-shutdown.ts +64 -0
- package/src/server/desktop-host.ts +190 -0
- package/src/server/desktop-server.ts +703 -0
- package/src/server/diffr-config.ts +509 -0
- package/src/server/diffr-languages.ts +97 -0
- package/src/server/global-verb-relay.ts +190 -0
- package/src/server/headless-host.ts +149 -0
- package/src/server/hono-http.ts +162 -0
- package/src/server/http-json.ts +24 -0
- package/src/server/json-review-reporting.ts +174 -0
- package/src/server/process-error-telemetry.ts +174 -0
- package/src/server/review-api-parsers.ts +90 -0
- package/src/server/review-lifecycle-telemetry.ts +73 -0
- package/src/server/review-open-watchdog.ts +46 -0
- package/src/server/review-server-core.ts +290 -0
- package/src/server/structural-comparisons.ts +153 -0
- package/src/server/structural-diff.ts +186 -0
- package/src/server/tutorial-service.ts +241 -0
- package/src/server/ui-telemetry.ts +198 -0
- package/src/server-discovery.ts +95 -0
- package/src/session-markers.ts +132 -0
- package/src/sharing/auth.ts +41 -0
- package/src/sharing/cli.ts +83 -0
- package/src/sharing/client.ts +334 -0
- package/src/sharing/export.ts +195 -0
- package/src/sharing/host.ts +316 -0
- package/src/sharing/import.ts +787 -0
- package/src/sharing/index.ts +16 -0
- package/src/sharing/repository.ts +145 -0
- package/src/sharing/routes.ts +34 -0
- package/src/slug.ts +23 -0
- package/src/software-map-diff-counts.ts +517 -0
- package/src/software-map-model.ts +1147 -0
- package/src/software-map-topology-diff.ts +260 -0
- package/src/source.ts +92 -0
- package/src/startup-trace.ts +232 -0
- package/src/stored-document-migration.ts +151 -0
- package/src/telemetry-clean-text.ts +257 -0
- package/src/telemetry-config.ts +298 -0
- package/src/telemetry-debug-sink.ts +38 -0
- package/src/telemetry.ts +13 -0
- package/src/trace-cli.ts +156 -0
- package/src/trace-storage-cli.ts +509 -0
- package/src/tutorial-conversation.ts +18 -0
- package/src/ui-telemetry-events.ts +765 -0
- package/src/unified-diff.ts +71 -0
- package/src/viewed-coverage.ts +259 -0
- package/src/windows-cli.ts +125 -0
- package/tutorial/document.json +275 -0
- package/tutorial/runtime-manifest.json +12 -0
- package/tutorial/sample-service/package.json +9 -0
- package/tutorial/sample-service/src/api/checkout-api.ts +17 -0
- package/tutorial/sample-service/src/app.ts +26 -0
- package/tutorial/sample-service/src/database/schema.ts +10 -0
- package/tutorial/sample-service/src/fulfillment/fulfillment-queue.ts +15 -0
- package/tutorial/sample-service/src/fulfillment/fulfillment-worker.ts +24 -0
- package/tutorial/sample-service/src/inventory/inventory-service.ts +11 -0
- package/tutorial/sample-service/src/orders/order-service.ts +34 -0
- package/tutorial/sample-service/src/orders/order.ts +21 -0
- package/tutorial/sample-service/src/orders/orders-repository.ts +24 -0
- package/tutorial/sample-service/src/payments/payment-gateway.ts +12 -0
- package/tutorial/sample-service/src/shipping/shipping-gateway.ts +15 -0
- package/tutorial/sample-service/tsconfig.json +12 -0
- package/tutorial/software-map.json +139 -0
- package/tutorial/trace.json +20 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { Writable } from "node:stream";
|
|
3
|
+
|
|
4
|
+
import { parseShareLink, shareIdSchema } from "@dev.fast/review-share-protocol";
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_STORE_ORIGIN,
|
|
7
|
+
clearStoreAuth,
|
|
8
|
+
openUrlInBrowser,
|
|
9
|
+
readStoreAuth,
|
|
10
|
+
runStoreLogin,
|
|
11
|
+
} from "@dev.fast/trace-core";
|
|
12
|
+
import { ReviewInputError } from "@review/review-api/document.js";
|
|
13
|
+
import type { LocalReviewData } from "@review/review-api/local-data.js";
|
|
14
|
+
import type { ReviewStore } from "@review/review-api/store.js";
|
|
15
|
+
import { readBoundedRequestJson } from "@review/server/hono-http.js";
|
|
16
|
+
import type { Hono } from "hono";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
|
|
19
|
+
import { readSharingAuth } from "./auth.js";
|
|
20
|
+
import { ShareAuthError, ShareClient, SharePreflightError } from "./client.js";
|
|
21
|
+
import { exportShare, validateShareSources } from "./export.js";
|
|
22
|
+
import { SharedReviewStore, sharedReviewId } from "./import.js";
|
|
23
|
+
import { readShareRepository, verifyShareRepository } from "./repository.js";
|
|
24
|
+
|
|
25
|
+
interface LoginState {
|
|
26
|
+
pending: boolean;
|
|
27
|
+
url?: string;
|
|
28
|
+
error?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const publishSchema = z.strictObject({
|
|
32
|
+
reviewId: z.string().min(1),
|
|
33
|
+
version: z.number().int().nonnegative().optional(),
|
|
34
|
+
requestId: z.uuid().optional(),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/** Where the host reports sharing and sign-in outcomes, for telemetry. */
|
|
38
|
+
export interface SharingHostEvents {
|
|
39
|
+
onPublished?: (event: { reviewId: string; version: number }) => void;
|
|
40
|
+
onRevoked?: (event: { shareId: string }) => void;
|
|
41
|
+
onLogin?: (
|
|
42
|
+
outcome: "started" | "succeeded" | "failed",
|
|
43
|
+
reason?: "did_not_finish" | "error",
|
|
44
|
+
) => void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface SharingHostOptions extends SharingHostEvents {
|
|
48
|
+
verifyRepository?: typeof verifyShareRepository;
|
|
49
|
+
readRepository?: typeof readShareRepository;
|
|
50
|
+
login?: typeof runStoreLogin;
|
|
51
|
+
openUrl?: typeof openUrlInBrowser;
|
|
52
|
+
fetch?: typeof fetch;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Mounted behind local host authentication. Account credentials never enter the renderer. */
|
|
56
|
+
export function mountSharingHost(
|
|
57
|
+
app: Hono,
|
|
58
|
+
store: ReviewStore,
|
|
59
|
+
data: LocalReviewData,
|
|
60
|
+
shared: SharedReviewStore,
|
|
61
|
+
options: SharingHostOptions = {},
|
|
62
|
+
) {
|
|
63
|
+
const startLogin = options.login ?? runStoreLogin;
|
|
64
|
+
const openUrl = options.openUrl ?? openUrlInBrowser;
|
|
65
|
+
|
|
66
|
+
let login: LoginState = {
|
|
67
|
+
pending: false,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
app.get("/sharing/account", async (context) => {
|
|
71
|
+
const account = await readStoreAuth();
|
|
72
|
+
|
|
73
|
+
return context.json({
|
|
74
|
+
account: account
|
|
75
|
+
? { login: account.login, origin: account.origin }
|
|
76
|
+
: null,
|
|
77
|
+
...login,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
app.post("/sharing/login", async (context) => {
|
|
81
|
+
if (!login.pending) {
|
|
82
|
+
login = { pending: true };
|
|
83
|
+
options.onLogin?.("started");
|
|
84
|
+
|
|
85
|
+
const discard = new Writable({
|
|
86
|
+
write(_chunk, _encoding, done) {
|
|
87
|
+
done();
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
void startLogin({
|
|
92
|
+
traces: false,
|
|
93
|
+
stdout: discard,
|
|
94
|
+
stderr: discard,
|
|
95
|
+
openUrl: async (url) => {
|
|
96
|
+
login.url = url;
|
|
97
|
+
await openUrl(url);
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
.then((code) => {
|
|
101
|
+
login = { pending: false };
|
|
102
|
+
|
|
103
|
+
if (code) login.error = "Sign-in did not finish. Try again.";
|
|
104
|
+
options.onLogin?.(
|
|
105
|
+
code ? "failed" : "succeeded",
|
|
106
|
+
code ? "did_not_finish" : undefined,
|
|
107
|
+
);
|
|
108
|
+
})
|
|
109
|
+
.catch(() => {
|
|
110
|
+
login = { pending: false, error: "Sign-in failed. Try again." };
|
|
111
|
+
options.onLogin?.("failed", "error");
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return context.json(login);
|
|
116
|
+
});
|
|
117
|
+
mountSharingPublisher(app, store, data, options);
|
|
118
|
+
const imports = new Map<string, Promise<void>>();
|
|
119
|
+
app.get("/sharing/import/:id", (context) => {
|
|
120
|
+
const id = context.req.param("id");
|
|
121
|
+
const status = shared.status(id);
|
|
122
|
+
|
|
123
|
+
const result = { reviewId: id, ...status };
|
|
124
|
+
|
|
125
|
+
if (status.stage === "ready")
|
|
126
|
+
return context.json({ ...result, title: shared.get(id).snapshot.title });
|
|
127
|
+
|
|
128
|
+
return context.json(result);
|
|
129
|
+
});
|
|
130
|
+
app.post("/sharing/import", async (context) => {
|
|
131
|
+
const { url } = z
|
|
132
|
+
.strictObject({ url: z.string().max(2048) })
|
|
133
|
+
.parse(await readBoundedRequestJson(context.req.raw));
|
|
134
|
+
|
|
135
|
+
const parsed = parseShareLink(url);
|
|
136
|
+
const account = await readStoreAuth();
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
parsed.origin !== DEFAULT_STORE_ORIGIN &&
|
|
140
|
+
parsed.origin !== account?.origin
|
|
141
|
+
)
|
|
142
|
+
throw new ReviewInputError(
|
|
143
|
+
"This share uses an untrusted service. Sign in to that service before opening its links.",
|
|
144
|
+
400,
|
|
145
|
+
);
|
|
146
|
+
const id = sharedReviewId(parsed.origin, parsed.shareId);
|
|
147
|
+
|
|
148
|
+
if (!imports.has(id)) {
|
|
149
|
+
shared.setStatus(id, "downloading");
|
|
150
|
+
|
|
151
|
+
const job = (async () => {
|
|
152
|
+
if (shared.has(id)) {
|
|
153
|
+
// Retained bytes survive a failed fetch and let retries work offline.
|
|
154
|
+
await shared.prepare(id);
|
|
155
|
+
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const bundle = await new ShareClient(parsed.origin).download(
|
|
160
|
+
parsed.shareId,
|
|
161
|
+
parsed.capability,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
await shared.import(parsed.origin, parsed.shareId, bundle);
|
|
165
|
+
})()
|
|
166
|
+
.catch((error) => {
|
|
167
|
+
shared.setStatus(
|
|
168
|
+
id,
|
|
169
|
+
"error",
|
|
170
|
+
error instanceof ReviewInputError
|
|
171
|
+
? error.message
|
|
172
|
+
: "This share is unavailable, revoked, or needs a newer Whiteboard version.",
|
|
173
|
+
);
|
|
174
|
+
})
|
|
175
|
+
.finally(() => imports.delete(id));
|
|
176
|
+
|
|
177
|
+
imports.set(id, job);
|
|
178
|
+
shared.trackImport(job);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return context.json({ reviewId: id, ...shared.status(id) }, 202);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Publishing needs only an authored store, never Desktop or recipient workspaces. */
|
|
186
|
+
export function mountSharingPublisher(
|
|
187
|
+
app: Hono,
|
|
188
|
+
store: ReviewStore,
|
|
189
|
+
data: LocalReviewData,
|
|
190
|
+
options: Pick<
|
|
191
|
+
SharingHostOptions,
|
|
192
|
+
| "verifyRepository"
|
|
193
|
+
| "readRepository"
|
|
194
|
+
| "fetch"
|
|
195
|
+
| "onPublished"
|
|
196
|
+
| "onRevoked"
|
|
197
|
+
> = {},
|
|
198
|
+
) {
|
|
199
|
+
const verifyRepository = options.verifyRepository ?? verifyShareRepository;
|
|
200
|
+
app.post("/sharing/publish", async (context) => {
|
|
201
|
+
const input = publishSchema.parse(
|
|
202
|
+
await readBoundedRequestJson(context.req.raw),
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
if (input.reviewId.startsWith("shared-"))
|
|
206
|
+
throw new ReviewInputError(
|
|
207
|
+
"Only the authoring review can be shared.",
|
|
208
|
+
409,
|
|
209
|
+
);
|
|
210
|
+
const snapshot = store.read(input.reviewId, input.version);
|
|
211
|
+
|
|
212
|
+
if (snapshot.target?.kind === "worktree")
|
|
213
|
+
throw new ReviewInputError(
|
|
214
|
+
"Pin this review to commits before sharing it.",
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
validateShareSources(snapshot);
|
|
218
|
+
const account = await readSharingAuth();
|
|
219
|
+
|
|
220
|
+
if (!account)
|
|
221
|
+
throw new ReviewInputError(
|
|
222
|
+
"Set DEV_REVIEW_SHARE_TOKEN for CI, or run whiteboard login before sharing.",
|
|
223
|
+
409,
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const root = snapshot.pins
|
|
227
|
+
? store.repositoryPath(snapshot.pins.repositoryId)
|
|
228
|
+
: undefined;
|
|
229
|
+
|
|
230
|
+
const repository = root
|
|
231
|
+
? await (options.readRepository ?? readShareRepository)(root)
|
|
232
|
+
: undefined;
|
|
233
|
+
|
|
234
|
+
const bundle = await exportShare({
|
|
235
|
+
store,
|
|
236
|
+
data,
|
|
237
|
+
reviewId: input.reviewId,
|
|
238
|
+
version: snapshot.version,
|
|
239
|
+
repository,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const verification =
|
|
243
|
+
root && snapshot.pins && repository
|
|
244
|
+
? verifyRepository(root, snapshot.pins, repository).then(
|
|
245
|
+
() => ({ ok: true as const }),
|
|
246
|
+
(error: Error) => ({ ok: false as const, error }),
|
|
247
|
+
)
|
|
248
|
+
: Promise.resolve({ ok: true as const });
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
const result = await new ShareClient(
|
|
252
|
+
account.origin,
|
|
253
|
+
account.token,
|
|
254
|
+
options.fetch,
|
|
255
|
+
).create(bundle, input.requestId ?? randomUUID(), async () => {
|
|
256
|
+
const result = await verification;
|
|
257
|
+
|
|
258
|
+
if (!result.ok) throw result.error;
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const url = new URL(result.url);
|
|
262
|
+
|
|
263
|
+
if (
|
|
264
|
+
process.env.DEV_FAST_REVIEW_APP_URL_PROTOCOL ===
|
|
265
|
+
"dev-fast-review-preview"
|
|
266
|
+
)
|
|
267
|
+
url.searchParams.set("app", "preview");
|
|
268
|
+
|
|
269
|
+
options.onPublished?.({
|
|
270
|
+
reviewId: input.reviewId,
|
|
271
|
+
version: snapshot.version,
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
return context.json({
|
|
275
|
+
...result,
|
|
276
|
+
url: url.href,
|
|
277
|
+
version: snapshot.version,
|
|
278
|
+
});
|
|
279
|
+
} catch (error) {
|
|
280
|
+
if (error instanceof SharePreflightError)
|
|
281
|
+
return context.json({ error: error.message }, 422);
|
|
282
|
+
|
|
283
|
+
if (error instanceof ShareAuthError) {
|
|
284
|
+
// A CI token lives in the environment; only the saved login can go stale.
|
|
285
|
+
if (process.env.DEV_REVIEW_SHARE_TOKEN === undefined)
|
|
286
|
+
await clearStoreAuth();
|
|
287
|
+
throw new ReviewInputError(
|
|
288
|
+
"Your sign-in has expired. Sign in again to share.",
|
|
289
|
+
401,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
throw new ReviewInputError(
|
|
294
|
+
"Sharing failed. Check your connection and login, then retry.",
|
|
295
|
+
409,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
app.post("/sharing/revoke", async (context) => {
|
|
300
|
+
const { shareId } = z
|
|
301
|
+
.strictObject({ shareId: shareIdSchema })
|
|
302
|
+
.parse(await readBoundedRequestJson(context.req.raw));
|
|
303
|
+
|
|
304
|
+
const account = await readSharingAuth();
|
|
305
|
+
|
|
306
|
+
if (!account)
|
|
307
|
+
throw new ReviewInputError(
|
|
308
|
+
"Set DEV_REVIEW_SHARE_TOKEN for CI, or run whiteboard login first.",
|
|
309
|
+
409,
|
|
310
|
+
);
|
|
311
|
+
await new ShareClient(account.origin, account.token).revoke(shareId);
|
|
312
|
+
options.onRevoked?.({ shareId });
|
|
313
|
+
|
|
314
|
+
return context.json({ shareId, revoked: true });
|
|
315
|
+
});
|
|
316
|
+
}
|