@runtypelabs/persona 4.22.1 → 4.23.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/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/index.cjs +18 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.global.js +16 -16
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +19 -19
- package/dist/index.js.map +1 -1
- package/dist/launcher.global.js.map +1 -1
- package/dist/theme-editor-preview.cjs +19 -19
- package/dist/theme-editor-preview.d.cts +6 -0
- package/dist/theme-editor-preview.d.ts +6 -0
- package/dist/theme-editor-preview.js +12 -12
- package/package.json +1 -1
- package/src/client-visitor-history.test.ts +86 -0
- package/src/launcher-global.ts +1 -1
- package/src/ui.ts +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/persona",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.23.0",
|
|
4
4
|
"description": "Themeable, pluggable streaming agent widget for websites, in plain JS with support for voice input and reasoning / tool output.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -1080,3 +1080,89 @@ describe('client visitor history - dedupe', () => {
|
|
|
1080
1080
|
expect(h.sessionInits).toHaveLength(1);
|
|
1081
1081
|
});
|
|
1082
1082
|
});
|
|
1083
|
+
|
|
1084
|
+
describe('voice integration visitor credential access', () => {
|
|
1085
|
+
const controllers: ReturnType<typeof createAgentExperience>[] = [];
|
|
1086
|
+
const mountWidget = (config: Partial<AgentWidgetConfig> = {}) => {
|
|
1087
|
+
const mount = document.createElement('div');
|
|
1088
|
+
document.body.appendChild(mount);
|
|
1089
|
+
const controller = createAgentExperience(mount, {
|
|
1090
|
+
apiUrl: API_URL,
|
|
1091
|
+
clientToken: CLIENT_TOKEN,
|
|
1092
|
+
launcher: { enabled: false },
|
|
1093
|
+
...config,
|
|
1094
|
+
});
|
|
1095
|
+
controllers.push(controller);
|
|
1096
|
+
return controller;
|
|
1097
|
+
};
|
|
1098
|
+
|
|
1099
|
+
afterEach(() => {
|
|
1100
|
+
controllers.forEach((controller) => controller.destroy());
|
|
1101
|
+
controllers.length = 0;
|
|
1102
|
+
document.body.innerHTML = '';
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
it('reads minted proof after the claim response omits it without enriching the callback', async () => {
|
|
1106
|
+
const minted = { id: 'vis_1', token: 'cvt_minted', expiresAt: futureIso(), endUserId: null };
|
|
1107
|
+
installFetch([
|
|
1108
|
+
ok({ sessionId: 'sess_first', visitor: minted }),
|
|
1109
|
+
ok({ sessionId: 'sess_claimed', visitor: { ...minted, token: undefined } }),
|
|
1110
|
+
]);
|
|
1111
|
+
const onSessionInit = vi.fn();
|
|
1112
|
+
const controller = mountWidget({ persistState: false, onSessionInit });
|
|
1113
|
+
await vi.waitFor(() => expect(onSessionInit).toHaveBeenCalledOnce());
|
|
1114
|
+
expect(onSessionInit.mock.calls[0][0].visitor.token).toBeUndefined();
|
|
1115
|
+
await expect(controller.getVisitorToken()).resolves.toBe('cvt_minted');
|
|
1116
|
+
expect(JSON.stringify(controller.getState())).not.toContain('cvt_minted');
|
|
1117
|
+
expect(window.localStorage.getItem(await storageKeyFor())).toBeNull();
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
it('reads the current persisted credential after reload and after rotation or removal', async () => {
|
|
1121
|
+
await seedToken('cvt_stored');
|
|
1122
|
+
installFetch([ok()]);
|
|
1123
|
+
const controller = mountWidget();
|
|
1124
|
+
await expect(controller.getVisitorToken()).resolves.toBe('cvt_stored');
|
|
1125
|
+
await seedToken('cvt_rotated');
|
|
1126
|
+
await expect(controller.getVisitorToken()).resolves.toBe('cvt_rotated');
|
|
1127
|
+
window.localStorage.removeItem(await storageKeyFor());
|
|
1128
|
+
await expect(controller.getVisitorToken()).resolves.toBeNull();
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
it('does not return credentials from a replaced client-token scope', async () => {
|
|
1132
|
+
await seedToken('cvt_stored');
|
|
1133
|
+
installFetch([ok(), ok()]);
|
|
1134
|
+
const controller = mountWidget();
|
|
1135
|
+
await vi.waitFor(() => expect(requests).toHaveLength(1));
|
|
1136
|
+
const pending = controller.getVisitorToken();
|
|
1137
|
+
controller.update({ clientToken: 'ct_other' });
|
|
1138
|
+
await expect(pending).resolves.toBeNull();
|
|
1139
|
+
await expect(controller.getVisitorToken()).resolves.toBeNull();
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
it('returns null after teardown, including a read already in flight', async () => {
|
|
1143
|
+
await seedToken('cvt_stored');
|
|
1144
|
+
installFetch([ok()]);
|
|
1145
|
+
const controller = mountWidget();
|
|
1146
|
+
await vi.waitFor(() => expect(requests).toHaveLength(1));
|
|
1147
|
+
const pending = controller.getVisitorToken();
|
|
1148
|
+
controller.destroy();
|
|
1149
|
+
controllers.length = 0;
|
|
1150
|
+
await expect(pending).resolves.toBeNull();
|
|
1151
|
+
await expect(controller.getVisitorToken()).resolves.toBeNull();
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
it('returns null when no credential has been minted', async () => {
|
|
1155
|
+
installFetch([ok()]);
|
|
1156
|
+
const controller = mountWidget({ persistState: false });
|
|
1157
|
+
await expect(controller.getVisitorToken()).resolves.toBeNull();
|
|
1158
|
+
});
|
|
1159
|
+
|
|
1160
|
+
it('does not fetch or mint a visitor outside client-token mode', async () => {
|
|
1161
|
+
const fetch = vi.fn();
|
|
1162
|
+
vi.stubGlobal('fetch', fetch);
|
|
1163
|
+
const controller = mountWidget({ clientToken: undefined });
|
|
1164
|
+
await expect(controller.getVisitorToken()).resolves.toBeNull();
|
|
1165
|
+
expect(fetch).not.toHaveBeenCalled();
|
|
1166
|
+
vi.unstubAllGlobals();
|
|
1167
|
+
});
|
|
1168
|
+
});
|
package/src/launcher-global.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* EXTRA-tier icon (`launcher.agentIconName: "shopping-cart"`) paints a
|
|
14
14
|
* correctly-sized empty placeholder and fills within one round-trip of the
|
|
15
15
|
* `icons-extra.js` sibling chunk (loader registered below). See the
|
|
16
|
-
* "Deferred Launcher Loading" pattern in
|
|
16
|
+
* "Deferred Launcher Loading" pattern in AGENTS.md.
|
|
17
17
|
*
|
|
18
18
|
* Public global (via tsup `--global-name AgentWidgetLauncher`):
|
|
19
19
|
*
|
package/src/ui.ts
CHANGED
|
@@ -731,6 +731,12 @@ type Controller = {
|
|
|
731
731
|
* Required host logout wiring.
|
|
732
732
|
*/
|
|
733
733
|
resetHistoryIdentity: () => Promise<{ remoteRevocationConfirmed: boolean }>;
|
|
734
|
+
/**
|
|
735
|
+
* Read the current browser visitor credential for a trusted voice integration.
|
|
736
|
+
* Returns null before minting, outside client-token mode, or after teardown.
|
|
737
|
+
* Never put this bearer credential in logs, URLs, or model context.
|
|
738
|
+
*/
|
|
739
|
+
getVisitorToken: () => Promise<string | null>;
|
|
734
740
|
/** Latest sanitized identity state; carries no token, proof, or identity id. */
|
|
735
741
|
getHistoryIdentityStatus: () => HistoryIdentityStatus;
|
|
736
742
|
/** `focus: false` keeps focus where it is (programmatic/preview opens). */
|
|
@@ -8982,6 +8988,7 @@ export const createAgentExperience = (
|
|
|
8982
8988
|
destroyCallbacks.push(() => {
|
|
8983
8989
|
session.destroy();
|
|
8984
8990
|
visitorStore?.destroy();
|
|
8991
|
+
visitorStore = null;
|
|
8985
8992
|
});
|
|
8986
8993
|
|
|
8987
8994
|
// Mirror read-aloud playback state into the action buttons, and surface it as
|
|
@@ -15215,6 +15222,12 @@ export const createAgentExperience = (
|
|
|
15215
15222
|
resetHistoryIdentity(): Promise<{ remoteRevocationConfirmed: boolean }> {
|
|
15216
15223
|
return resetHistoryIdentity();
|
|
15217
15224
|
},
|
|
15225
|
+
async getVisitorToken(): Promise<string | null> {
|
|
15226
|
+
const store = visitorStore;
|
|
15227
|
+
if (!store) return null;
|
|
15228
|
+
const token = await store.get();
|
|
15229
|
+
return store === visitorStore ? token : null;
|
|
15230
|
+
},
|
|
15218
15231
|
getHistoryIdentityStatus(): HistoryIdentityStatus {
|
|
15219
15232
|
if (!historyProvider) {
|
|
15220
15233
|
return historyFeatureEnabled()
|