@sansavision/yousaid 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.
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Resumable media upload for YouSaid Proof collection drafts.
3
+ *
4
+ * Protocol (same for the hosted page, the in-app prompt and headless API
5
+ * sessions; the draft session secret comes from startSession or
6
+ * POST /api/v1/proof/submissions/sessions):
7
+ * POST /api/proof/collect/drafts/{draftId}/uploads -> { sessionId, token, partBytes, parts }
8
+ * PUT /api/proof/collect/drafts/{draftId}/uploads/{id}?part=n (exactly partBytes; last part = remainder)
9
+ * GET /api/proof/collect/drafts/{draftId}/uploads/{id} -> { received: number[], state }
10
+ * POST /api/proof/collect/drafts/{draftId}/uploads/{id} -> { media, draft }
11
+ * Bytes stream to R2 as a multipart upload (video up to 500 MB). Each part
12
+ * retries with backoff; after a dropped connection, or a reload with the same
13
+ * file, the upload continues from the parts the server already has.
14
+ */
15
+ /** @experimental */
16
+ export class ProofUploadError extends Error {
17
+ status;
18
+ code;
19
+ constructor(message, status, code) {
20
+ super(message);
21
+ this.status = status;
22
+ this.code = code;
23
+ this.name = "ProofUploadError";
24
+ }
25
+ }
26
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
27
+ function defaultResumeStore() {
28
+ try {
29
+ if (typeof window === "undefined" || !window.localStorage)
30
+ return null;
31
+ const storage = window.localStorage;
32
+ return { get: (key) => storage.getItem(key), set: (key, value) => storage.setItem(key, value), remove: (key) => storage.removeItem(key) };
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ function fingerprint(blob) {
39
+ const file = blob;
40
+ return [blob.size, blob.type, file.name ?? "", file.lastModified ?? 0].join(":");
41
+ }
42
+ function originOf(endpoint) {
43
+ if (endpoint)
44
+ return new URL(endpoint, "https://yousaid.dev").origin;
45
+ if (typeof window !== "undefined" && window.location?.origin?.startsWith("http"))
46
+ return window.location.origin;
47
+ return "https://yousaid.dev";
48
+ }
49
+ /**
50
+ * Uploads one recording or image into a draft, resumably.
51
+ * @experimental
52
+ */
53
+ export async function uploadProofMedia(draftId, sessionToken, blob, mode, options = {}) {
54
+ const request = options.fetch ?? globalThis.fetch.bind(globalThis);
55
+ const base = `${originOf(options.endpoint)}/api/proof/collect/drafts/${encodeURIComponent(draftId)}/uploads`;
56
+ const resume = options.resume === undefined ? defaultResumeStore() : options.resume;
57
+ const resumeKey = `yousaid-proof-upload:${draftId}:${mode}:${fingerprint(blob)}`;
58
+ const maxAttempts = options.maxAttempts ?? 7;
59
+ const json = async (url, init = {}) => {
60
+ const headers = new Headers(init.headers);
61
+ headers.set("x-proof-session", sessionToken);
62
+ if (init.token)
63
+ headers.set("authorization", `Bearer ${init.token}`);
64
+ if (typeof init.body === "string")
65
+ headers.set("content-type", "application/json");
66
+ const response = await request(url, { ...init, headers, credentials: "omit", cache: "no-store", signal: options.signal ?? null });
67
+ const payload = await response.json().catch(() => ({}));
68
+ if (!response.ok)
69
+ throw new ProofUploadError(payload.error ?? "The upload was refused.", response.status, payload.code);
70
+ return payload;
71
+ };
72
+ const mimeType = blob.type || (mode === "audio" ? "audio/webm" : mode === "video" || mode === "screen_recording" ? "video/webm" : "image/png");
73
+ const screen = mode === "screen_recording" && options.screenConsent
74
+ ? { screenConsent: true, screenConsentVersion: options.screenConsent.version, ...(options.screenConsent.microphone !== undefined ? { microphone: options.screenConsent.microphone } : {}) } : {};
75
+ options.onProgress?.({ sent: 0, total: blob.size, state: "starting" });
76
+ let started = null;
77
+ let received = new Set();
78
+ const remembered = resume?.get(resumeKey);
79
+ if (remembered) {
80
+ try {
81
+ const previous = JSON.parse(remembered);
82
+ if (Date.parse(previous.expiresAt) > Date.now() + 60_000 && previous.size === blob.size) {
83
+ const progress = await json(`${base}/${previous.sessionId}`);
84
+ if (progress.state === "open" || progress.state === "completed") {
85
+ started = previous;
86
+ received = new Set(progress.received);
87
+ }
88
+ }
89
+ }
90
+ catch { /* start fresh */ }
91
+ if (!started)
92
+ resume?.remove(resumeKey);
93
+ }
94
+ if (!started) {
95
+ started = await json(base, { method: "POST", body: JSON.stringify({ mode, mimeType, bytes: blob.size, capture: { source: options.source ?? "file", ...(options.durationMs !== undefined ? { durationMs: Math.round(options.durationMs) } : {}), ...screen } }) });
96
+ const file = blob;
97
+ try {
98
+ resume?.set(resumeKey, JSON.stringify({ ...started, size: blob.size, type: blob.type, name: file.name ?? "", lastModified: file.lastModified ?? 0 }));
99
+ }
100
+ catch { /* storage full or blocked */ }
101
+ }
102
+ const session = started;
103
+ const url = `${base}/${session.sessionId}`;
104
+ const sentBytes = () => [...received].reduce((sum, part) => sum + Math.min(session.partBytes, blob.size - (part - 1) * session.partBytes), 0);
105
+ for (let part = 1; part <= session.parts; part += 1) {
106
+ if (received.has(part))
107
+ continue;
108
+ const slice = blob.slice((part - 1) * session.partBytes, Math.min(blob.size, part * session.partBytes));
109
+ for (let attempt = 0;; attempt += 1) {
110
+ try {
111
+ const response = await request(`${url}?part=${part}`, { method: "PUT", body: slice, headers: { authorization: `Bearer ${session.token}`, "x-proof-session": sessionToken, "content-type": "application/octet-stream" }, credentials: "omit", signal: options.signal ?? null });
112
+ if (!response.ok && response.status < 500 && response.status !== 429 && response.status !== 409) {
113
+ const payload = await response.json().catch(() => ({}));
114
+ throw new ProofUploadError(payload.error ?? "The upload was refused.", response.status, payload.code);
115
+ }
116
+ if (!response.ok)
117
+ throw new Error("retryable");
118
+ received.add(part);
119
+ break;
120
+ }
121
+ catch (error) {
122
+ if (error instanceof ProofUploadError || options.signal?.aborted)
123
+ throw error;
124
+ if (attempt + 1 >= maxAttempts)
125
+ throw new ProofUploadError("The connection dropped. Your answer is saved; try the upload again and it will continue where it stopped.", 0, "NETWORK");
126
+ options.onProgress?.({ sent: sentBytes(), total: blob.size, state: "retrying" });
127
+ await sleep(Math.min(15_000, 500 * 2 ** attempt));
128
+ try {
129
+ const progress = await json(url);
130
+ received = new Set(progress.received);
131
+ if (received.has(part))
132
+ break;
133
+ }
134
+ catch { /* keep retrying this part */ }
135
+ }
136
+ }
137
+ options.onProgress?.({ sent: sentBytes(), total: blob.size, state: "uploading" });
138
+ }
139
+ options.onProgress?.({ sent: blob.size, total: blob.size, state: "finalizing" });
140
+ let frames = [];
141
+ try {
142
+ frames = (typeof options.frames === "function" ? await options.frames() : options.frames ?? []).slice(0, 3);
143
+ }
144
+ catch {
145
+ frames = [];
146
+ }
147
+ let done = null;
148
+ for (let attempt = 0; !done; attempt += 1) {
149
+ try {
150
+ done = await json(url, { method: "POST", token: session.token, body: JSON.stringify({ mode, ...(options.durationMs !== undefined ? { durationMs: Math.round(options.durationMs) } : {}), ...(frames.length ? { frames } : {}) }) });
151
+ }
152
+ catch (error) {
153
+ if ((error instanceof ProofUploadError && error.status !== 0 && error.status < 500) || attempt + 1 >= 4 || options.signal?.aborted)
154
+ throw error;
155
+ await sleep(1000 * 2 ** attempt);
156
+ }
157
+ }
158
+ try {
159
+ resume?.remove(resumeKey);
160
+ }
161
+ catch { /* ignore */ }
162
+ options.onProgress?.({ sent: blob.size, total: blob.size, state: "done" });
163
+ return done;
164
+ }
165
+ /**
166
+ * Cancels an in-progress upload (for example when the customer re-records).
167
+ * @experimental
168
+ */
169
+ export async function abortProofUpload(draftId, sessionToken, uploadSessionId, uploadToken, options = {}) {
170
+ const request = options.fetch ?? globalThis.fetch.bind(globalThis);
171
+ await request(`${originOf(options.endpoint)}/api/proof/collect/drafts/${encodeURIComponent(draftId)}/uploads/${encodeURIComponent(uploadSessionId)}`, {
172
+ method: "DELETE", headers: { authorization: `Bearer ${uploadToken}`, "x-proof-session": sessionToken }, credentials: "omit",
173
+ });
174
+ }
@@ -0,0 +1,356 @@
1
+ import type { YouSaidClientOptions } from "./index.js";
2
+ import { type ProofUploadMode, type ProofUploadOptions, type ProofUploadResult } from "./proof-upload.js";
3
+ /**
4
+ * Published proof: headless render manifest types, fetch helper and the
5
+ * first-party engagement beacon. Shared by @sansavision/yousaid-react proof components.
6
+ * The framework-free Web Component (public/embed/yousaid-proof.js) speaks the
7
+ * same protocol.
8
+ */
9
+ /** @experimental */
10
+ export type ProofIdentityAttribution = Partial<Record<"name" | "pronouns" | "role_title" | "company" | "company_size_industry" | "location" | "customer_since", string>> & Record<string, string>;
11
+ /** @experimental */
12
+ export type ProofMedia = {
13
+ kind: "video";
14
+ src: string;
15
+ mimeType: string;
16
+ poster: string | null;
17
+ captions: {
18
+ src: string;
19
+ lang: string;
20
+ label: string;
21
+ }[];
22
+ width: number | null;
23
+ height: number | null;
24
+ durationMs: number | null;
25
+ adaptive?: {
26
+ hls: string;
27
+ dash: string | null;
28
+ };
29
+ } | {
30
+ kind: "audio";
31
+ src: string;
32
+ mimeType: string;
33
+ captions: {
34
+ src: string;
35
+ lang: string;
36
+ label: string;
37
+ }[];
38
+ durationMs: number | null;
39
+ } | {
40
+ kind: "image";
41
+ src: string;
42
+ alt: string;
43
+ width: number | null;
44
+ height: number | null;
45
+ };
46
+ /** @experimental */
47
+ export type ProofRenderItem = {
48
+ id: string;
49
+ versionId: string;
50
+ position: number;
51
+ type: "text" | "audio" | "video" | "image" | "review" | "case_study" | "release_story";
52
+ quote: string | null;
53
+ title: string | null;
54
+ rating: number | null;
55
+ attribution: ProofIdentityAttribution;
56
+ identityFields: string[];
57
+ /** Required disclosure. Always render it when present. */
58
+ disclosure: string | null;
59
+ labels: string[];
60
+ verification: "customer_approved" | "imported_public_review" | "permission_on_file";
61
+ sourceType: string;
62
+ sourceDate: string | null;
63
+ media: ProofMedia | null;
64
+ receiptUrl: string;
65
+ /** Avatar and logo strip only: first-party portrait and logo, present only while consent allows them. */
66
+ identityImages?: {
67
+ portrait: {
68
+ src: string;
69
+ alt: string;
70
+ } | null;
71
+ companyLogo: {
72
+ src: string;
73
+ alt: string;
74
+ } | null;
75
+ };
76
+ /** Customer map only: a country or a world region the customer allowed, never finer. */
77
+ location?: ProofLocation;
78
+ };
79
+ /** @experimental */
80
+ export type ProofLocation = {
81
+ level: "country" | "region";
82
+ code: string;
83
+ label: string;
84
+ region: string;
85
+ regionLabel: string;
86
+ lat: number;
87
+ lon: number;
88
+ };
89
+ /** @experimental */
90
+ export type ProofTheme = {
91
+ scheme: "light" | "dark" | "auto";
92
+ accent: string;
93
+ background?: string;
94
+ foreground?: string;
95
+ radius: number;
96
+ font: string;
97
+ fontStack: string;
98
+ density: "comfortable" | "compact";
99
+ };
100
+ /** @experimental */
101
+ export type ProofRender = {
102
+ schema: "yousaid-proof-render-v1";
103
+ placement: {
104
+ id: string;
105
+ name: string;
106
+ format: "page" | "wall" | "carousel" | "card" | "video" | "badge" | "logo_strip" | "map" | "bubble" | "marquee";
107
+ state: string;
108
+ theme: ProofTheme;
109
+ layout: {
110
+ columns: number;
111
+ maxItems: number;
112
+ showRating: boolean;
113
+ showDate: boolean;
114
+ autoplay: boolean;
115
+ };
116
+ headline: string | null;
117
+ intro: string | null;
118
+ cta: {
119
+ label: string;
120
+ url: string;
121
+ } | null;
122
+ showBranding: boolean;
123
+ /** Walls and marquees: gentle continuous scrolling (never for reduced motion). */
124
+ motion?: "none" | "scroll";
125
+ /** Video bubble: corner and appearance delay. */
126
+ bubble?: {
127
+ position: "bottom-right" | "bottom-left";
128
+ delaySeconds: number;
129
+ };
130
+ };
131
+ version: string;
132
+ cacheVersion: number;
133
+ generatedAt: string;
134
+ expiresAt: string;
135
+ items: ProofRenderItem[];
136
+ summary: {
137
+ count: number;
138
+ ratedCount: number;
139
+ averageRating: number | null;
140
+ ratingScale: 5 | 10;
141
+ scopeNote: string;
142
+ };
143
+ fallback: {
144
+ id: string;
145
+ } | null;
146
+ preview: boolean;
147
+ eventToken: string | null;
148
+ manifestSignature: string;
149
+ /** Adaptive slot / experiment details: why these items, in this order. Absent for static placements. */
150
+ optimize?: {
151
+ mode: "static" | "rules" | "adaptive";
152
+ slot: string | null;
153
+ contextKey: string;
154
+ experiment: {
155
+ id: string;
156
+ arm: string;
157
+ } | null;
158
+ reasons: Record<string, string[]>;
159
+ fallback: "budget" | "error" | null;
160
+ };
161
+ /** Ed25519 signature a browser can verify against the published JWKS (verifiedProofFallback). */
162
+ publicSignature?: {
163
+ alg: "EdDSA";
164
+ kid: string;
165
+ signature: string;
166
+ };
167
+ /** Server-side HMAC (never verifiable in a browser: the secret stays on the server). */
168
+ signature: string;
169
+ };
170
+ /**
171
+ * Coarse, non-personal page context for adaptive proof slots (PRD 8.8, 9.9). Never pass emails or user ids.
172
+ * @experimental
173
+ */
174
+ export type ProofSlotContext = {
175
+ slot?: string;
176
+ audience?: string;
177
+ product?: string;
178
+ locale?: string;
179
+ page?: string;
180
+ };
181
+ /** @experimental */
182
+ export type ProofRenderOptions = {
183
+ endpoint?: string;
184
+ fetch?: typeof globalThis.fetch;
185
+ signal?: AbortSignal;
186
+ context?: ProofSlotContext;
187
+ /** Experiment bucket 0..99, or "random" for a per-call random bucket. Omit to stay out of experiments. */
188
+ bucket?: number | "random";
189
+ };
190
+ /**
191
+ * Fetches the eligibility-gated render manifest for a placement. No cookies are sent.
192
+ * @experimental
193
+ */
194
+ export declare function fetchProofRender(placementId: string, options?: ProofRenderOptions): Promise<ProofRender>;
195
+ /**
196
+ * A signed snapshot may be shown as a fallback only until it expires (the revocation SLA window).
197
+ * @experimental
198
+ */
199
+ export declare function isRenderFresh(render: Pick<ProofRender, "expiresAt">, now?: number): boolean;
200
+ /** @experimental */
201
+ export type ProofPublicKey = {
202
+ kty: string;
203
+ crv?: string;
204
+ x?: string;
205
+ kid?: string;
206
+ alg?: string;
207
+ };
208
+ /** @experimental */
209
+ export type ProofKeySet = {
210
+ keys: ProofPublicKey[];
211
+ };
212
+ /**
213
+ * Published proof keys (current and previous Ed25519 keys) from the same
214
+ * first-party origin as the render API, never a third party. Cached per origin
215
+ * for the page lifetime; a failed fetch is not cached.
216
+ * @experimental
217
+ */
218
+ export declare function fetchProofKeys(options?: {
219
+ endpoint?: string;
220
+ fetch?: typeof globalThis.fetch;
221
+ }): Promise<ProofKeySet>;
222
+ /**
223
+ * True only when `render.publicSignature` is a valid Ed25519 signature from a
224
+ * key in `keys` (matched by kid). Any failure, including a runtime without
225
+ * Ed25519 in WebCrypto, returns false: an unverifiable snapshot is never shown.
226
+ * @experimental
227
+ */
228
+ export declare function verifyProofRenderSignature(render: ProofRender, keys: ProofKeySet, subtle?: SubtleCrypto | undefined): Promise<boolean>;
229
+ /**
230
+ * The stored static fallback to show when the live render failed, or null.
231
+ * Shown only when it is a render for this placement, unexpired, and carries a
232
+ * valid Ed25519 signature from a key the first-party JWKS publishes (previous
233
+ * keys stay published during a rotation). Fails closed: no keys, unknown kid,
234
+ * tampered payload or no Ed25519 support all yield null.
235
+ * @experimental
236
+ */
237
+ export declare function verifiedProofFallback(fallback: unknown, options?: {
238
+ placementId?: string;
239
+ endpoint?: string;
240
+ fetch?: typeof globalThis.fetch;
241
+ now?: () => number;
242
+ subtle?: SubtleCrypto;
243
+ }): Promise<ProofRender | null>;
244
+ /** @experimental */
245
+ export type ProofBeaconEvent = {
246
+ t: "view" | "fallback" | "error";
247
+ } | {
248
+ t: "perf";
249
+ v: number;
250
+ } | {
251
+ t: "impression" | "video_start" | "video_complete";
252
+ i: string;
253
+ } | {
254
+ t: "click";
255
+ i?: string;
256
+ } | {
257
+ t: "video_progress";
258
+ i: string;
259
+ q: 25 | 50 | 75;
260
+ }
261
+ /** Site conversion: `n` is a short name (signup, trial, purchase); `a` lists items with a qualified impression earlier in this page load. */
262
+ | {
263
+ t: "conversion";
264
+ n: string;
265
+ a: string[];
266
+ };
267
+ /**
268
+ * Must match CONVERSION_NAME_PATTERN in lib/proof-publish/beacon.ts.
269
+ * @experimental
270
+ */
271
+ export declare const PROOF_CONVERSION_NAME: RegExp;
272
+ /** @experimental */
273
+ export type ProofBeacon = {
274
+ push(event: ProofBeaconEvent, onceKey?: string): void;
275
+ /**
276
+ * Reports a site conversion (for example "signup", "trial" or "purchase")
277
+ * from this page load. Each name is sent at most once per beacon. Returns
278
+ * false for an invalid name or a no-op beacon. The event names only the
279
+ * items this page load showed as qualified impressions; nothing identifies
280
+ * the visitor and nothing is stored in the browser.
281
+ */
282
+ conversion(name: string): boolean;
283
+ flush(): void;
284
+ close(): void;
285
+ };
286
+ /**
287
+ * Reports a site conversion to every proof placement rendered on this page.
288
+ * Returns how many placements received it. Call it where the conversion
289
+ * happens on the same page (for example on the signup form's success). A page
290
+ * with no proof placement sends nothing.
291
+ * @experimental
292
+ */
293
+ export declare function sendProofConversion(name: string): number;
294
+ /**
295
+ * Batched, cookie-free beacon. Flushes every 5 s, at 40 queued events and when
296
+ * the page is hidden; a conversion flushes at once. Returns a no-op beacon when
297
+ * there is no event token (previews, paused placements).
298
+ * @experimental
299
+ */
300
+ export declare function createProofBeacon(token: string | null, options?: {
301
+ endpoint?: string;
302
+ fetch?: typeof globalThis.fetch;
303
+ account?: string;
304
+ }): ProofBeacon;
305
+ /** @experimental */
306
+ export type ProofPromptPresentation = "inline" | "modal" | "drawer" | "popover" | "fullscreen";
307
+ /** @experimental */
308
+ export type ProofEligibility = {
309
+ eligible: boolean;
310
+ reason: string | null;
311
+ };
312
+ /** @experimental */
313
+ export type ProofSession = {
314
+ draftId: string;
315
+ sessionToken: string;
316
+ formId: string;
317
+ };
318
+ /** @experimental */
319
+ export type ProofPromptAction = "not_now" | "never" | "dismissed";
320
+ /** @experimental */
321
+ export type ProofPromptEvent = {
322
+ source: "yousaid-proof";
323
+ type: "open" | "step" | "abandon" | "complete" | "consent" | "resize" | "close";
324
+ formId?: string;
325
+ [key: string]: unknown;
326
+ };
327
+ /**
328
+ * YouSaid Proof collection client for the native in-app prompt. Uses the same
329
+ * signed end-user identity token as the rest of the SDK: identity is verified
330
+ * server-side and prefilled, and the customer still controls every field
331
+ * proposed for publication.
332
+ * @experimental
333
+ */
334
+ export declare class YouSaidProofClient {
335
+ #private;
336
+ constructor(options: YouSaidClientOptions);
337
+ get origin(): string;
338
+ /** Server-side frequency caps, "not now" and "never ask" across devices. */
339
+ eligibility(formId: string): Promise<ProofEligibility>;
340
+ /** Starts (or resumes on this device) the known customer's draft. Consumes one token nonce. */
341
+ startSession(formId: string, presentation?: ProofPromptPresentation): Promise<ProofSession>;
342
+ recordPreference(formId: string, action: ProofPromptAction, contactPreference?: "in_app" | "email" | "none"): Promise<void>;
343
+ /**
344
+ * Resumable upload of a recording or image into the session's draft (R2
345
+ * multipart, up to 500 MB for video). Attach the returned `media` to an
346
+ * answer when you submit through your own UI.
347
+ */
348
+ uploadMedia(session: ProofSession, blob: Blob, mode: ProofUploadMode, options?: Omit<ProofUploadOptions, "endpoint" | "fetch">): Promise<ProofUploadResult>;
349
+ /** The hosted, embeddable page. The session secret travels in the fragment, never in a request line. */
350
+ frameUrl(formId: string, session?: ProofSession | null): string;
351
+ /** Narrows a window message to a genuine event from this origin's collection frame. */
352
+ parseEvent(event: MessageEvent, frame?: {
353
+ contentWindow: unknown;
354
+ } | null): ProofPromptEvent | null;
355
+ }
356
+ //# sourceMappingURL=proof.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../src/proof.ts"],"names":[],"mappings":"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"}