@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.
- package/CHANGELOG.md +13 -0
- package/LICENSE +6 -0
- package/README.md +152 -2
- package/dist/index.d.ts +532 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +383 -0
- package/dist/proof-strings.d.ts +39 -0
- package/dist/proof-strings.d.ts.map +1 -0
- package/dist/proof-strings.js +56 -0
- package/dist/proof-upload.d.ts +96 -0
- package/dist/proof-upload.d.ts.map +1 -0
- package/dist/proof-upload.js +174 -0
- package/dist/proof.d.ts +356 -0
- package/dist/proof.d.ts.map +1 -0
- package/dist/proof.js +278 -0
- package/dist/realtime.d.ts +113 -0
- package/dist/realtime.d.ts.map +1 -0
- package/dist/realtime.js +246 -0
- package/package.json +37 -4
|
@@ -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
|
+
}
|
package/dist/proof.d.ts
ADDED
|
@@ -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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"}
|