@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 ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@sansavision/yousaid` are recorded here. The project
4
+ follows semantic versioning for the stable surface listed in README.md.
5
+
6
+ ## 0.2.0
7
+
8
+ First npm release.
9
+
10
+ - Ships compiled ES2022 JavaScript with TypeScript declarations and declaration maps.
11
+ - Stable: `YouSaidClient` (`sendSignal`, `verifyInstallation`, `listInbox`, `markInboxRead`, `streamInbox`, `confirmRelease`, `mergeAnonymousHistory`), `collectDiagnostics`, `anonymousVisitorId`, `SIGNAL_ATTACHMENT_LIMITS`, `YOUSAID_SDK_VERSION` and the signal, inbox and diagnostics types.
12
+ - New: `SignalInput.context.apphelm` (`AppHelmSignalContext`) carries AppHelm workspace, product, user and session ids so YouSaid can link a conversation back to AppHelm.
13
+ - Experimental (tagged `@experimental`): Rooms, agents, approvals, moderation, proof rendering, beacons and uploads, realtime, `createSseParser` and map helpers.
package/LICENSE ADDED
@@ -0,0 +1,6 @@
1
+ Copyright (c) 2026 Sansa Group AB
2
+
3
+ All rights reserved, Sansa Group AB. Licence terms pending owner and legal review.
4
+
5
+ No licence is granted to use, copy, modify or distribute this software until
6
+ Sansa Group AB publishes licence terms for it.
package/README.md CHANGED
@@ -1,3 +1,153 @@
1
- # Temporary Holding Version
1
+ # @sansavision/yousaid
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The framework-free YouSaid client. Send customer signals from your product, show
4
+ the end user their private inbox of replies, and ask whether a release fixed
5
+ their problem. Works in any modern browser and in Node 20 or later.
6
+
7
+ ```sh
8
+ npm install @sansavision/yousaid @sansavision/yousaid-server
9
+ ```
10
+
11
+ `@sansavision/yousaid-server` runs on your server only. It signs the end user's
12
+ identity so the browser never holds your product signing secret.
13
+
14
+ ## 1. Mint an identity token on your server
15
+
16
+ ```ts
17
+ import { createYouSaidIdentityToken } from "@sansavision/yousaid-server";
18
+
19
+ // GET /api/yousaid-token, behind your own session check.
20
+ export async function GET(request: Request) {
21
+ const user = await currentUser(request);
22
+ const token = await createYouSaidIdentityToken(
23
+ { sub: user.id, org_id: "org_...", product_id: "prd_...", email: user.email, name: user.name },
24
+ process.env.YOUSAID_SIGNING_SECRET!,
25
+ { keyId: process.env.YOUSAID_KEY_ID! },
26
+ );
27
+ return new Response(token, { headers: { "cache-control": "no-store" } });
28
+ }
29
+ ```
30
+
31
+ ## 2. Create the client
32
+
33
+ ```ts
34
+ import { YouSaidClient } from "@sansavision/yousaid";
35
+
36
+ const client = new YouSaidClient({
37
+ // Prefer a function: every state-changing request consumes the token's nonce.
38
+ token: () => fetch("/api/yousaid-token").then((response) => response.text()),
39
+ });
40
+ ```
41
+
42
+ | Option | Meaning |
43
+ | --- | --- |
44
+ | `token` | A signed identity token, or a sync or async function that returns a fresh one. Required. |
45
+ | `endpoint` | The signals URL. Defaults to `https://yousaid.dev/api/signals`. Every other call uses the origin of this URL. |
46
+ | `fetch` | A custom `fetch`, for tests or runtimes without a global one. |
47
+
48
+ ## 3. Send a signal
49
+
50
+ ```ts
51
+ const receipt = await client.sendSignal({
52
+ kind: "bug", // support, bug, feature, ux or review
53
+ title: "PDF export freezes",
54
+ body: "The export hangs at 90 percent on long pages.",
55
+ context: { route: "/export", appVersion: "4.2.0" },
56
+ });
57
+ // receipt: { signalId, threadId, state: "acknowledged", receipt, inboxUrl, replayed }
58
+ ```
59
+
60
+ Retries are safe: pass your own `idempotencyKey` (one is generated otherwise) and a
61
+ replay answers `replayed: true` with the original ids.
62
+
63
+ Attachments and diagnostics are optional:
64
+
65
+ ```ts
66
+ import { collectDiagnostics, SIGNAL_ATTACHMENT_LIMITS } from "@sansavision/yousaid";
67
+
68
+ await client.sendSignal({
69
+ title: "Checkout button does nothing",
70
+ body: "Clicking Pay shows no error.",
71
+ attachments: files.slice(0, SIGNAL_ATTACHMENT_LIMITS.maxFiles),
72
+ // Only after the end user saw and agreed to what is shared. Query strings are never included.
73
+ diagnostics: collectDiagnostics({ consent: true, appVersion: "4.2.0" }),
74
+ });
75
+ ```
76
+
77
+ ### AppHelm context
78
+
79
+ If your product also reports to AppHelm, attach the AppHelm ids so your team
80
+ gets an "Open in AppHelm" link on the conversation:
81
+
82
+ ```ts
83
+ await client.sendSignal({
84
+ title: "Sync stopped",
85
+ body: "Nothing synced since this morning.",
86
+ context: {
87
+ apphelm: {
88
+ workspaceId: "ws_123", // required, ^[A-Za-z0-9_-]{1,100}$
89
+ productId: "prod_9", // optional, ^[A-Za-z0-9_-]{1,100}$
90
+ externalUserId: "user-42", // optional, ^[A-Za-z0-9._:@+-]{1,200}$
91
+ distinctHash: "9f86d081884c7d65", // optional lowercase hex, 16 to 128 characters
92
+ sessionHash: "2c26b46b68ffc68f", // optional lowercase hex, 16 to 128 characters
93
+ },
94
+ },
95
+ });
96
+ ```
97
+
98
+ Send ids and hashes only, never emails or names. Unknown keys or an invalid value
99
+ drop the whole `apphelm` object; the signal itself is always accepted. YouSaid adds
100
+ the person link (it needs `externalUserId` or `distinctHash`) and the session link
101
+ (it needs `sessionHash`) only when `workspaceId` matches the AppHelm workspace an
102
+ owner or admin connected in YouSaid.
103
+
104
+ ## 4. Inbox
105
+
106
+ ```ts
107
+ const page = await client.listInbox({ limit: 20 }); // { unread, items, nextCursor }
108
+ await client.markInboxRead(page.items.map((item) => item.id)); // or markInboxRead() for all
109
+
110
+ const stop = new AbortController();
111
+ void client.streamInbox((event) => {
112
+ if (event.type === "item") console.log("New reply", event.item.subject, event.unread);
113
+ }, stop.signal);
114
+ ```
115
+
116
+ ## 5. Release receipts
117
+
118
+ When you ship a fix, YouSaid asks the people who reported the problem whether it
119
+ works now. Record their answer:
120
+
121
+ ```ts
122
+ await client.confirmRelease("rel_...", "resolved");
123
+ await client.confirmRelease("rel_...", "still_broken", "Still freezes on Safari.");
124
+ ```
125
+
126
+ `still_broken` opens a follow-up signal for your team.
127
+
128
+ ## More
129
+
130
+ - `client.verifyInstallation()` checks the signed identity and records SDK health for onboarding.
131
+ - `anonymousVisitorId()` and `client.mergeAnonymousHistory()` join anonymous hosted-form history to the signed user after sign-in.
132
+ - `YOUSAID_SDK_VERSION` is the version of this package.
133
+
134
+ ## Stability
135
+
136
+ Version 0.2.0 marks this surface as **stable**. It follows semantic versioning:
137
+
138
+ - `YouSaidClient` with its constructor options (`token` string or async callback, `endpoint`, `fetch`) and the methods `sendSignal`, `verifyInstallation`, `listInbox`, `markInboxRead`, `streamInbox`, `confirmRelease` and `mergeAnonymousHistory`
139
+ - `collectDiagnostics`, `anonymousVisitorId`, `SIGNAL_ATTACHMENT_LIMITS`, `YOUSAID_SDK_VERSION`
140
+ - the types `SignalInput` (including `context.apphelm`), `SignalReceipt`, `SignalKind`, `InboxItem`, `InboxPage`, `InboxEvent`, `DiagnosticsCapsule`, `YouSaidClientOptions` and `AppHelmSignalContext`
141
+
142
+ Everything else is **experimental** and tagged `@experimental` in the type
143
+ declarations: Rooms methods and types, agents, approvals, moderation, `proof()`
144
+ and the proof render, beacon and upload helpers, `RoomRealtimeClient`,
145
+ `createSseParser` and the map helpers. Experimental APIs can change in any
146
+ minor release.
147
+
148
+ ## Licence
149
+
150
+ `UNLICENSED`. All rights reserved, Sansa Group AB. Licence terms are pending
151
+ owner and legal review; see LICENSE.
152
+
153
+ Documentation: https://yousaid.dev/docs/sdk