@burdenoff/fe-libs 2026.928.2 → 2026.929.1
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/shared/assistant/adminModeSendGate.d.ts +6 -5
- package/dist/shared/assistant/adminModeSendGate.d.ts.map +1 -1
- package/dist/shared/assistant/adminModeSendGate.js +11 -11
- package/dist/shared/assistant/api.d.ts +291 -28
- package/dist/shared/assistant/api.d.ts.map +1 -1
- package/dist/shared/assistant/api.js +351 -147
- package/dist/shared/assistant/autoRouting.d.ts +11 -3
- package/dist/shared/assistant/autoRouting.d.ts.map +1 -1
- package/dist/shared/assistant/autoRouting.js +7 -7
- package/dist/shared/assistant/capabilities.d.ts +28 -0
- package/dist/shared/assistant/capabilities.d.ts.map +1 -1
- package/dist/shared/assistant/capabilities.js +19 -10
- package/dist/shared/assistant/conversation.d.ts +24 -2
- package/dist/shared/assistant/conversation.d.ts.map +1 -1
- package/dist/shared/assistant/createSandboxAssistantTransport.d.ts.map +1 -1
- package/dist/shared/assistant/createSandboxAssistantTransport.js +67 -54
- package/dist/shared/assistant/history/historyList.js +1 -1
- package/dist/shared/assistant/history/historyMapping.d.ts.map +1 -1
- package/dist/shared/assistant/history/historyMapping.js +5 -1
- package/dist/shared/assistant/history/historyResume.js +7 -7
- package/dist/shared/assistant/i18nManifest.d.ts +53 -0
- package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
- package/dist/shared/assistant/i18nManifest.js +75 -16
- package/dist/shared/assistant/index.d.ts +15 -0
- package/dist/shared/assistant/index.d.ts.map +1 -1
- package/dist/shared/assistant/modeCapabilities.js +1 -1
- package/dist/shared/assistant/operations.d.ts +22 -0
- package/dist/shared/assistant/operations.d.ts.map +1 -1
- package/dist/shared/assistant/operations.js +2 -2
- package/dist/shared/assistant/prewarm.d.ts +7 -0
- package/dist/shared/assistant/prewarm.d.ts.map +1 -1
- package/dist/shared/assistant/prewarm.js +1 -1
- package/dist/shared/assistant/product.d.ts +80 -2
- package/dist/shared/assistant/product.d.ts.map +1 -1
- package/dist/shared/assistant/product.js +10 -6
- package/dist/shared/assistant/proposalWriteRules.d.ts +40 -0
- package/dist/shared/assistant/proposalWriteRules.d.ts.map +1 -0
- package/dist/shared/assistant/proposalWriteRules.js +14 -0
- package/dist/shared/assistant/store.d.ts +17 -0
- package/dist/shared/assistant/store.d.ts.map +1 -1
- package/dist/shared/assistant/store.js +50 -43
- package/dist/shared/assistant/turnOutcome.d.ts +34 -2
- package/dist/shared/assistant/turnOutcome.d.ts.map +1 -1
- package/dist/shared/assistant/turnOutcome.js +28 -17
- package/dist/shared/assistant/turnOutcomeCopy.d.ts +29 -7
- package/dist/shared/assistant/turnOutcomeCopy.d.ts.map +1 -1
- package/dist/shared/assistant/turnOutcomeCopy.js +18 -6
- package/dist/shared/assistant/types.d.ts +5 -1
- package/dist/shared/assistant/types.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantApiCallsConsentDialog.js +4 -4
- package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantChatArea.js +989 -718
- package/dist/shared/assistant/ui/AssistantConversationList.js +6 -6
- package/dist/shared/assistant/ui/AssistantLanguageMenu.js +6 -6
- package/dist/shared/assistant/ui/AssistantMessageItem.d.ts +8 -1
- package/dist/shared/assistant/ui/AssistantMessageItem.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantMessageItem.js +77 -76
- package/dist/shared/assistant/ui/AssistantMessageList.d.ts +13 -1
- package/dist/shared/assistant/ui/AssistantMessageList.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantMessageList.js +15 -13
- package/dist/shared/assistant/ui/AssistantReplyLanguageSelector.js +5 -5
- package/dist/shared/assistant/ui/AssistantSpeechProvider.js +209 -209
- package/dist/shared/assistant/ui/AssistantWriteConfirmDialog.d.ts +62 -0
- package/dist/shared/assistant/ui/AssistantWriteConfirmDialog.d.ts.map +1 -0
- package/dist/shared/assistant/ui/AssistantWriteConfirmDialog.js +253 -0
- package/dist/shared/assistant/ui/AssistantWriteProposalCard.d.ts +72 -0
- package/dist/shared/assistant/ui/AssistantWriteProposalCard.d.ts.map +1 -0
- package/dist/shared/assistant/ui/AssistantWriteProposalCard.js +439 -0
- package/dist/shared/assistant/ui/AssistantWriteProposalSlot.d.ts +40 -0
- package/dist/shared/assistant/ui/AssistantWriteProposalSlot.d.ts.map +1 -0
- package/dist/shared/assistant/ui/AssistantWriteProposalSlot.js +35 -0
- package/dist/shared/assistant/ui/composer/AssistantComposer.js +8 -8
- package/dist/shared/assistant/ui/useVoiceSession.d.ts +28 -0
- package/dist/shared/assistant/ui/useVoiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/ui/useVoiceSession.js +159 -110
- package/dist/shared/assistant/ui/useWriteProposalConfirm.d.ts +61 -0
- package/dist/shared/assistant/ui/useWriteProposalConfirm.d.ts.map +1 -0
- package/dist/shared/assistant/ui/useWriteProposalConfirm.js +109 -0
- package/dist/shared/assistant/ui/useWriteProposals.d.ts +102 -0
- package/dist/shared/assistant/ui/useWriteProposals.d.ts.map +1 -0
- package/dist/shared/assistant/ui/useWriteProposals.js +230 -0
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +17 -1
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +141 -109
- package/dist/shared/assistant/ui/writeProposalPresentation.d.ts +76 -0
- package/dist/shared/assistant/ui/writeProposalPresentation.d.ts.map +1 -0
- package/dist/shared/assistant/ui/writeProposalPresentation.js +110 -0
- package/dist/shared/assistant/usageReporting.d.ts +108 -0
- package/dist/shared/assistant/usageReporting.d.ts.map +1 -0
- package/dist/shared/assistant/usageReporting.js +155 -0
- package/dist/shared/assistant/useAssistantApiAccess.d.ts +49 -14
- package/dist/shared/assistant/useAssistantApiAccess.d.ts.map +1 -1
- package/dist/shared/assistant/useAssistantApiAccess.js +43 -25
- package/dist/shared/assistant/useAssistantHeartbeat.d.ts.map +1 -1
- package/dist/shared/assistant/useAssistantHeartbeat.js +5 -5
- package/dist/shared/assistant/useWorkspaceWriteAccess.d.ts +5 -6
- package/dist/shared/assistant/useWorkspaceWriteAccess.d.ts.map +1 -1
- package/dist/shared/assistant/voice/voiceSession.d.ts +46 -0
- package/dist/shared/assistant/voice/voiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/voice/voiceSession.js +35 -2
- package/dist/shared/assistant/writeConfirmSeam.d.ts +32 -0
- package/dist/shared/assistant/writeConfirmSeam.d.ts.map +1 -0
- package/dist/shared/assistant/writeConfirmSeam.js +23 -0
- package/dist/shared/assistant/writeModeConsent.d.ts +16 -8
- package/dist/shared/assistant/writeModeConsent.d.ts.map +1 -1
- package/dist/shared/assistant/writeModeConsent.js +2 -2
- package/dist/shared/assistant/writeProposalDiscovery.d.ts +123 -0
- package/dist/shared/assistant/writeProposalDiscovery.d.ts.map +1 -0
- package/dist/shared/assistant/writeProposalDiscovery.js +210 -0
- package/dist/shared/assistant/writeProposalErrorCopy.d.ts +135 -0
- package/dist/shared/assistant/writeProposalErrorCopy.d.ts.map +1 -0
- package/dist/shared/assistant/writeProposalErrorCopy.js +135 -0
- package/dist/shared/assistant/writeProposalVoice.d.ts +133 -0
- package/dist/shared/assistant/writeProposalVoice.d.ts.map +1 -0
- package/dist/shared/assistant/writeProposalVoice.js +66 -0
- package/dist/shared/assistant/writeProposals.d.ts +268 -0
- package/dist/shared/assistant/writeProposals.d.ts.map +1 -0
- package/dist/shared/assistant/writeProposals.js +445 -0
- package/dist/shared/assistant/writeReplyBinder.d.ts +166 -0
- package/dist/shared/assistant/writeReplyBinder.d.ts.map +1 -0
- package/dist/shared/assistant/writeReplyBinder.js +233 -0
- package/dist/shared/assistant/writeReplySend.d.ts +110 -0
- package/dist/shared/assistant/writeReplySend.d.ts.map +1 -0
- package/dist/shared/assistant/writeReplySend.js +93 -0
- package/dist/shared/graphql/fetch.d.ts +12 -1
- package/dist/shared/graphql/fetch.d.ts.map +1 -1
- package/dist/shared/graphql/fetch.js +101 -80
- package/dist/shared/providers/shell/ActiveContextProvider.d.ts.map +1 -1
- package/dist/shared/providers/shell/ActiveContextProvider.js +28 -26
- package/dist/shared/providers/shell/PersonaSurfaceProvider.d.ts.map +1 -1
- package/dist/shared/providers/shell/PersonaSurfaceProvider.js +165 -193
- package/dist/shared/providers/shell/personaSurfaceRemote.d.ts +8 -2
- package/dist/shared/providers/shell/personaSurfaceRemote.d.ts.map +1 -1
- package/dist/shared/providers/shell/personaSurfaceRemote.js +37 -15
- package/dist/shared/providers/shell/useRemoteNavPreferences.d.ts +30 -0
- package/dist/shared/providers/shell/useRemoteNavPreferences.d.ts.map +1 -0
- package/dist/shared/providers/shell/useRemoteNavPreferences.js +43 -0
- package/dist/shared-assistant.js +167 -152
- package/dist/ui/modal-shell.d.ts +14 -1
- package/dist/ui/modal-shell.d.ts.map +1 -1
- package/dist/ui/modal-shell.js +8 -6
- package/package.json +2 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { AssistantTr } from '../i18n';
|
|
2
|
+
import { SandboxWriteCapabilities, WriteProposalRiskKind, WriteProposalRootField, WriteProposalView } from '../writeProposals';
|
|
3
|
+
/**
|
|
4
|
+
* What a write proposal shows, and when it may be confirmed (BOFF-7803 5a).
|
|
5
|
+
* Shared by the card (FE4) and the confirmation dialog (FE5), so the two
|
|
6
|
+
* surfaces cannot drift: the dialog shows exactly the values, masking and
|
|
7
|
+
* countdown the card showed, and offers a confirm under exactly the same rule.
|
|
8
|
+
*
|
|
9
|
+
* ★★ 5a is a safety floor, not the final security boundary. Nothing here
|
|
10
|
+
* authorises a change. The issuing sandbox and wspace-sandbox-svc decide; these
|
|
11
|
+
* helpers only decide what a person is SHOWN and whether a press is OFFERED.
|
|
12
|
+
*/
|
|
13
|
+
/** What a hidden value looks like. */
|
|
14
|
+
export declare const WRITE_PROPOSAL_MASK = "\u2022\u2022\u2022\u2022\u2022\u2022";
|
|
15
|
+
/** A value as the card writes it: a string as-is, anything else as JSON. */
|
|
16
|
+
export declare function formatWriteProposalValue(value: unknown): string;
|
|
17
|
+
/**
|
|
18
|
+
* The text of every sensitive value in the proposal. A gateway error can echo
|
|
19
|
+
* a variable's value ("got invalid value …"), so free text from the record is
|
|
20
|
+
* scrubbed of these before it is shown.
|
|
21
|
+
*/
|
|
22
|
+
export declare function writeProposalSensitiveTexts(view: WriteProposalView): string[];
|
|
23
|
+
/**
|
|
24
|
+
* `text` with every one of `secrets` replaced by the mask: a long one wherever
|
|
25
|
+
* it appears, a short one where it stands alone. Pass the secrets longest
|
|
26
|
+
* first (`writeProposalSensitiveTexts` does), so a longer value is masked
|
|
27
|
+
* whole before a shorter one inside it is looked for. A blank one is skipped.
|
|
28
|
+
*/
|
|
29
|
+
export declare function redactWriteProposalText(text: string, secrets: readonly string[]): string;
|
|
30
|
+
/** A risk kind in words, or null for one that says nothing a person can act on. */
|
|
31
|
+
export declare function writeProposalKindText(kind: WriteProposalRiskKind, tr: AssistantTr): string | null;
|
|
32
|
+
/** Which data the change touches, in words. */
|
|
33
|
+
export declare function writeProposalGatewayText(view: WriteProposalView, tr: AssistantTr): string;
|
|
34
|
+
/** One value a surface shows, keyed so a revision can be compared with it. */
|
|
35
|
+
export interface WriteProposalShownValue {
|
|
36
|
+
key: string;
|
|
37
|
+
label: string;
|
|
38
|
+
value: unknown;
|
|
39
|
+
sensitive: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** A root field as written in the document: `alias: field`, or `field`. */
|
|
42
|
+
export declare function writeProposalRootFieldName(field: Pick<WriteProposalRootField, "alias" | "field">): string;
|
|
43
|
+
/** A root field's arguments, as the values that will be sent. */
|
|
44
|
+
export declare function writeProposalArgumentValues(field: WriteProposalRootField): WriteProposalShownValue[];
|
|
45
|
+
/** The operation's variables, as the values that will be sent. */
|
|
46
|
+
export declare function writeProposalVariableValues(view: WriteProposalView): WriteProposalShownValue[];
|
|
47
|
+
/** "Expires in 4:59", or, under reduced motion, words that move once a minute. */
|
|
48
|
+
export declare function writeProposalCountdownText(remainingMs: number, reducedMotion: boolean, tr: AssistantTr): string;
|
|
49
|
+
/**
|
|
50
|
+
* How long until `expiresAt`, on the ISSUING sandbox's clock.
|
|
51
|
+
*
|
|
52
|
+
* `serverNow` is that sandbox's clock when the record was read
|
|
53
|
+
* (`list().serverNow`); the difference from this device's clock is measured
|
|
54
|
+
* again whenever a fresh read arrives. While `ticking`, the value moves once a
|
|
55
|
+
* second.
|
|
56
|
+
*/
|
|
57
|
+
export declare function useWriteProposalRemainingMs(expiresAt: number, serverNow: number, ticking: boolean): number;
|
|
58
|
+
/** Whether a proposal's controls, and its confirm, may be offered. */
|
|
59
|
+
export interface WriteProposalConfirmState {
|
|
60
|
+
/** The issuing sandbox speaks the v1 protocol and enforces it. */
|
|
61
|
+
available: boolean;
|
|
62
|
+
/** Execution is not enabled for this proposal or this sandbox (until 5b). */
|
|
63
|
+
fenced: boolean;
|
|
64
|
+
/** Pending, bound and on a v1 sandbox: Cancel (and maybe confirm) is shown. */
|
|
65
|
+
showControls: boolean;
|
|
66
|
+
/** A confirm press may be offered at all. */
|
|
67
|
+
offerConfirm: boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The one rule both surfaces use to decide what to OFFER. It authorises
|
|
71
|
+
* nothing: the sandbox and wspace-sandbox-svc refuse anything this lets
|
|
72
|
+
* through that they would not run. An unknown sandbox is not available and an
|
|
73
|
+
* unknown execution state is fenced, so every doubt removes the button.
|
|
74
|
+
*/
|
|
75
|
+
export declare function writeProposalConfirmState(view: WriteProposalView, capabilities: SandboxWriteCapabilities | null | undefined): WriteProposalConfirmState;
|
|
76
|
+
//# sourceMappingURL=writeProposalPresentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeProposalPresentation.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/writeProposalPresentation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EACV,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;GASG;AAEH,sCAAsC;AACtC,eAAO,MAAM,mBAAmB,yCAAW,CAAC;AAY5C,4EAA4E;AAC5E,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQ/D;AAkBD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAW7E;AAqBD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,CAUR;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,qBAAqB,EAC3B,EAAE,EAAE,WAAW,GACd,MAAM,GAAG,IAAI,CAkBf;AAED,+CAA+C;AAC/C,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,WAAW,GACd,MAAM,CAIR;AAED,8EAA8E;AAC9E,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,2EAA2E;AAC3E,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,OAAO,CAAC,GACrD,MAAM,CAER;AAED,iEAAiE;AACjE,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,sBAAsB,GAC5B,uBAAuB,EAAE,CAQ3B;AAED,kEAAkE;AAClE,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,iBAAiB,GACtB,uBAAuB,EAAE,CAO3B;AAED,kFAAkF;AAClF,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,OAAO,EACtB,EAAE,EAAE,WAAW,GACd,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,MAAM,CAmBR;AAED,sEAAsE;AACtE,MAAM,WAAW,yBAAyB;IACxC,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,MAAM,EAAE,OAAO,CAAC;IAChB,+EAA+E;IAC/E,YAAY,EAAE,OAAO,CAAC;IACtB,6CAA6C;IAC7C,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,iBAAiB,EACvB,YAAY,EAAE,wBAAwB,GAAG,IAAI,GAAG,SAAS,GACxD,yBAAyB,CAY3B"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { useEffect as e, useState as t } from "react";
|
|
2
|
+
//#region src/shared/assistant/ui/writeProposalPresentation.ts
|
|
3
|
+
var n = "••••••", r = 4, i = /[\p{L}\p{N}]/u;
|
|
4
|
+
function a(e) {
|
|
5
|
+
if (typeof e == "string") return e === "" ? "\"\"" : e;
|
|
6
|
+
if (e === void 0) return "null";
|
|
7
|
+
try {
|
|
8
|
+
return JSON.stringify(e) ?? String(e);
|
|
9
|
+
} catch {
|
|
10
|
+
return String(e);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function o(e, t) {
|
|
14
|
+
if (e != null) {
|
|
15
|
+
if (Array.isArray(e)) {
|
|
16
|
+
for (let n of e) o(n, t);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (typeof e == "object") {
|
|
20
|
+
for (let n of Object.values(e)) o(n, t);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
t.push(String(e));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function s(e) {
|
|
27
|
+
let t = [];
|
|
28
|
+
for (let n of e.description.rootFields) for (let e of n.args) e.sensitive && o(e.value, t);
|
|
29
|
+
for (let n of e.description.variables) n.sensitive && o(n.value, t);
|
|
30
|
+
return [...new Set(t)].filter((e) => e.trim().length > 0).sort((e, t) => t.length - e.length);
|
|
31
|
+
}
|
|
32
|
+
function c(e, t) {
|
|
33
|
+
let r = "", a = 0, o = e.indexOf(t);
|
|
34
|
+
for (; o !== -1;) {
|
|
35
|
+
let s = o + t.length, c = !i.test(e.charAt(o - 1)) && !i.test(e.charAt(s));
|
|
36
|
+
c && (r += e.slice(a, o) + n, a = s), o = e.indexOf(t, c ? s : o + 1);
|
|
37
|
+
}
|
|
38
|
+
return r + e.slice(a);
|
|
39
|
+
}
|
|
40
|
+
function l(e, t) {
|
|
41
|
+
let i = e;
|
|
42
|
+
for (let e of t) e.trim() && (i = e.length >= r ? i.split(e).join(n) : c(i, e));
|
|
43
|
+
return i;
|
|
44
|
+
}
|
|
45
|
+
function u(e, t) {
|
|
46
|
+
switch (e) {
|
|
47
|
+
case "destructive": return t("writeProposal.kind.destructive", "Deletes data");
|
|
48
|
+
case "financial": return t("writeProposal.kind.financial", "Involves money");
|
|
49
|
+
case "bulk": return t("writeProposal.kind.bulk", "Changes several items");
|
|
50
|
+
case "permission": return t("writeProposal.kind.permission", "Changes access");
|
|
51
|
+
case "credential": return t("writeProposal.kind.credential", "Touches credentials");
|
|
52
|
+
case "irreversible": return t("writeProposal.kind.irreversible", "Can't be undone");
|
|
53
|
+
case "unclassified": return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function d(e, t) {
|
|
57
|
+
return e.gateway === "global" ? t("writeProposal.gateway.global", "Account and organization data") : t("writeProposal.gateway.workspace", "Workspace data");
|
|
58
|
+
}
|
|
59
|
+
function f(e) {
|
|
60
|
+
return e.alias ? `${e.alias}: ${e.field}` : e.field;
|
|
61
|
+
}
|
|
62
|
+
function p(e) {
|
|
63
|
+
let t = e.alias ?? e.field;
|
|
64
|
+
return e.args.map((e) => ({
|
|
65
|
+
key: `arg:${t}.${e.name}`,
|
|
66
|
+
label: e.name,
|
|
67
|
+
value: e.value,
|
|
68
|
+
sensitive: e.sensitive
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
function m(e) {
|
|
72
|
+
return e.description.variables.map((e) => ({
|
|
73
|
+
key: `var:${e.path}`,
|
|
74
|
+
label: e.path,
|
|
75
|
+
value: e.value,
|
|
76
|
+
sensitive: e.sensitive
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
function h(e, t, n) {
|
|
80
|
+
if (t) return e < 6e4 ? n("writeProposal.expiresSoon", "Expires in under a minute") : n("writeProposal.expiresInAbout", "Expires in about {{minutes}} min", { minutes: Math.ceil(e / 6e4) });
|
|
81
|
+
let r = Math.ceil(e / 1e3);
|
|
82
|
+
return n("writeProposal.expiresIn", "Expires in {{time}}", { time: `${Math.floor(r / 60)}:${String(r % 60).padStart(2, "0")}` });
|
|
83
|
+
}
|
|
84
|
+
function g(n, r, i) {
|
|
85
|
+
let [a, o] = t(() => ({
|
|
86
|
+
serverNow: r,
|
|
87
|
+
offset: Number.isFinite(r) ? r - Date.now() : 0
|
|
88
|
+
})), s = a.offset;
|
|
89
|
+
Object.is(a.serverNow, r) || (s = Number.isFinite(r) ? r - Date.now() : 0, o({
|
|
90
|
+
serverNow: r,
|
|
91
|
+
offset: s
|
|
92
|
+
}));
|
|
93
|
+
let [c, l] = t(() => Date.now());
|
|
94
|
+
return e(() => {
|
|
95
|
+
if (!i) return;
|
|
96
|
+
let e = setInterval(() => l(Date.now()), 1e3);
|
|
97
|
+
return () => clearInterval(e);
|
|
98
|
+
}, [i]), n - (c + s);
|
|
99
|
+
}
|
|
100
|
+
function _(e, t) {
|
|
101
|
+
let n = t?.proposals === !0 && t.writeApprovalMode === "proposal-v1", r = e.execution.enabled !== !0 || t?.writeExecution !== "enabled", i = e.status === "pending" && e.approvable && n;
|
|
102
|
+
return {
|
|
103
|
+
available: n,
|
|
104
|
+
fenced: r,
|
|
105
|
+
showControls: i,
|
|
106
|
+
offerConfirm: i && !r && e.allowedMethods.includes("button")
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
export { n as WRITE_PROPOSAL_MASK, a as formatWriteProposalValue, l as redactWriteProposalText, g as useWriteProposalRemainingMs, p as writeProposalArgumentValues, _ as writeProposalConfirmState, h as writeProposalCountdownText, d as writeProposalGatewayText, u as writeProposalKindText, f as writeProposalRootFieldName, s as writeProposalSensitiveTexts, m as writeProposalVariableValues };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { AssistantSendRefusal } from './turnOutcome';
|
|
2
|
+
/** One finished turn's charge, as a product's `reportTokenUsage` receives it. */
|
|
3
|
+
export interface UsageReport {
|
|
4
|
+
workspaceId: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
messageId?: string;
|
|
7
|
+
model?: string;
|
|
8
|
+
tokens: {
|
|
9
|
+
input: number;
|
|
10
|
+
output: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Sends one report to its ledger. Rejects when the ledger did not record it. */
|
|
14
|
+
export type UsageReporter = (report: UsageReport) => Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Why a report could not be recorded.
|
|
17
|
+
*
|
|
18
|
+
* - `permission`: the ledger refused this person (HTTP 403, or a FORBIDDEN /
|
|
19
|
+
* UNAUTHORIZED / PERMISSION_DENIED code). Retrying will not help until their
|
|
20
|
+
* role, or the ledger's rule, changes.
|
|
21
|
+
* - `unavailable`: anything else — a network drop, a timeout, a 5xx. Trying
|
|
22
|
+
* again can succeed.
|
|
23
|
+
*/
|
|
24
|
+
export type UsageReportFailureKind = "permission" | "unavailable";
|
|
25
|
+
/** Set while at least one report is held: the assistant is paused. */
|
|
26
|
+
export interface UsageBlock {
|
|
27
|
+
readonly kind: UsageReportFailureKind;
|
|
28
|
+
}
|
|
29
|
+
export type UsageReportResult = {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
} | {
|
|
32
|
+
readonly ok: false;
|
|
33
|
+
readonly kind: UsageReportFailureKind;
|
|
34
|
+
};
|
|
35
|
+
export interface UsageReportingOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Which ledger the report belongs to — see `assistantUsageLedger`. A held
|
|
38
|
+
* report is only ever retried through the reporter of its own ledger.
|
|
39
|
+
*/
|
|
40
|
+
ledger?: string;
|
|
41
|
+
/** Waits between attempts. Defaults to `usageReportClock.sleep`. */
|
|
42
|
+
sleep?: (ms: number) => Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/** When each attempt starts, measured from the previous one's failure. */
|
|
45
|
+
export declare const USAGE_REPORT_RETRY_DELAYS_MS: readonly number[];
|
|
46
|
+
/**
|
|
47
|
+
* Dispatched on `window` when a report is given up on and the assistant pauses.
|
|
48
|
+
* The detail is the failure kind ONLY: no workspace, session, message or token.
|
|
49
|
+
*/
|
|
50
|
+
export declare const USAGE_REPORT_FAILED_EVENT = "assistant.usage_report_failed";
|
|
51
|
+
export interface UsageReportFailedDetail {
|
|
52
|
+
readonly kind: UsageReportFailureKind;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The wait between attempts, as a property read at call time so a test can
|
|
56
|
+
* replace it (`spyOn(usageReportClock, "sleep")`) without waiting 4 s.
|
|
57
|
+
*/
|
|
58
|
+
export declare const usageReportClock: {
|
|
59
|
+
sleep(ms: number): Promise<void>;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The ledger a charge site writes to.
|
|
63
|
+
*
|
|
64
|
+
* ★ Two sites, two ledgers, even within one product: the transport always
|
|
65
|
+
* charges through the shared `reportAiTokenUsage`, while the panel charges
|
|
66
|
+
* through the product's own seam (HealthyBowl's is a different mutation on a
|
|
67
|
+
* different row). A report held by one must never be retried through the
|
|
68
|
+
* other, or it would be billed to the wrong ledger.
|
|
69
|
+
*/
|
|
70
|
+
export declare function assistantUsageLedger(source: "panel" | "transport", product: string): string;
|
|
71
|
+
/** Where a ledger's held reports are mirrored for this tab. */
|
|
72
|
+
export declare function usagePendingStorageKey(ledger: string, workspaceId: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Classify a failed report.
|
|
75
|
+
*
|
|
76
|
+
* ★ Decided by what the failure IS — an HTTP status or a GraphQL code — never
|
|
77
|
+
* by matching its words.
|
|
78
|
+
*/
|
|
79
|
+
export declare function classifyUsageReportFailure(error: unknown): UsageReportFailureKind;
|
|
80
|
+
/**
|
|
81
|
+
* Send one report, retrying at 0 s, 1 s and 3 s.
|
|
82
|
+
*
|
|
83
|
+
* Never rejects. When every attempt fails, the report is held, the assistant is
|
|
84
|
+
* paused (`getUsageBlock`), and the result says why — the next send must call
|
|
85
|
+
* `retryPendingUsageReports` first and is refused while that still fails.
|
|
86
|
+
*/
|
|
87
|
+
export declare function reportUsageWithRetry(report: UsageReport, fn: UsageReporter, options?: UsageReportingOptions): Promise<UsageReportResult>;
|
|
88
|
+
/** Whether any report is held for this ledger and workspace. */
|
|
89
|
+
export declare function hasPendingUsageReports(ledger: string, workspaceId: string): boolean;
|
|
90
|
+
/** Why the assistant is paused for this ledger and workspace, or null. */
|
|
91
|
+
export declare function getUsageBlock(ledger: string, workspaceId: string): UsageBlock | null;
|
|
92
|
+
/**
|
|
93
|
+
* Retry every held report once, oldest first, before a send.
|
|
94
|
+
*
|
|
95
|
+
* Resolves `ok` when nothing is held any more — the send may go ahead. Stops at
|
|
96
|
+
* the first report that still fails: the rest would meet the same refusal, and
|
|
97
|
+
* each attempt is a request.
|
|
98
|
+
*/
|
|
99
|
+
export declare function retryPendingUsageReports(ledger: string, workspaceId: string, fn: UsageReporter): Promise<UsageReportResult>;
|
|
100
|
+
/**
|
|
101
|
+
* The refusal a send gets while a report is still held.
|
|
102
|
+
*
|
|
103
|
+
* Thrown as an `AssistantSendRefusal`, so the panel says it in the reader's
|
|
104
|
+
* language (`outcome.usageNotPermitted` / `outcome.usageNotRecorded`) and a
|
|
105
|
+
* widget that shows `error.message` shows the same English.
|
|
106
|
+
*/
|
|
107
|
+
export declare function usageSendRefusal(kind: UsageReportFailureKind): AssistantSendRefusal;
|
|
108
|
+
//# sourceMappingURL=usageReporting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usageReporting.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/usageReporting.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGrD,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,iFAAiF;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,aAAa,CAAC;AAElE,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;CACvC;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,0EAA0E;AAC1E,eAAO,MAAM,4BAA4B,EAAE,SAAS,MAAM,EAEzD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,kCAAkC,CAAC;AAEzE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;CACvC;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB;cACjB,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGjC,CAAC;AAMF;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,OAAO,GAAG,WAAW,EAC7B,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,MAAM,CAER;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,sBAAsB,CAmBxB;AA0KD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,WAAW,EACnB,EAAE,EAAE,aAAa,EACjB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,iBAAiB,CAAC,CAuB5B;AAED,gEAAgE;AAChE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAET;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,UAAU,GAAG,IAAI,CAGnB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,aAAa,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAwB5B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,sBAAsB,GAC3B,oBAAoB,CAUtB"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { extensionObjectsIn as e } from "./quota.js";
|
|
2
|
+
import { TURN_OUTCOME_COPY as t } from "./turnOutcomeCopy.js";
|
|
3
|
+
import { AssistantSendRefusal as n } from "./turnOutcome.js";
|
|
4
|
+
//#region src/shared/assistant/usageReporting.ts
|
|
5
|
+
var r = [
|
|
6
|
+
0,
|
|
7
|
+
1e3,
|
|
8
|
+
3e3
|
|
9
|
+
], i = "assistant.usage_report_failed", a = { sleep(e) {
|
|
10
|
+
return new Promise((t) => setTimeout(t, e));
|
|
11
|
+
} }, o = Object.freeze({ ok: !0 }), s = "default", c = "bf-assistant:usage-pending:v1:";
|
|
12
|
+
function l(e, t) {
|
|
13
|
+
return `${e}:${t}`;
|
|
14
|
+
}
|
|
15
|
+
function u(e, t) {
|
|
16
|
+
return `${c}${encodeURIComponent(e)}:${encodeURIComponent(t)}`;
|
|
17
|
+
}
|
|
18
|
+
function d(t) {
|
|
19
|
+
if (f(t)) return "permission";
|
|
20
|
+
for (let n of e(t)) {
|
|
21
|
+
let e = n.code;
|
|
22
|
+
if (e === "FORBIDDEN" || e === "UNAUTHORIZED" || e === "PERMISSION_DENIED") return "permission";
|
|
23
|
+
let t = n.http;
|
|
24
|
+
if (t && typeof t == "object" && t.status === 403) return "permission";
|
|
25
|
+
}
|
|
26
|
+
return "unavailable";
|
|
27
|
+
}
|
|
28
|
+
function f(e) {
|
|
29
|
+
return !e || typeof e != "object" ? !1 : [
|
|
30
|
+
e,
|
|
31
|
+
e.networkError,
|
|
32
|
+
e.response
|
|
33
|
+
].some((e) => {
|
|
34
|
+
if (!e || typeof e != "object") return !1;
|
|
35
|
+
let { status: t, statusCode: n } = e;
|
|
36
|
+
return t === 403 || n === 403;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
var p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map(), h = (e, t) => `${e}\u0000${t}`, g = (e) => `${e.sessionId}\u0000${e.messageId ?? ""}`;
|
|
40
|
+
function _() {
|
|
41
|
+
try {
|
|
42
|
+
return typeof window > "u" ? null : window.sessionStorage ?? null;
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
var v = (e) => typeof e == "number" && Number.isFinite(e) && e >= 0, y = (e) => e === void 0 || typeof e == "string";
|
|
48
|
+
function b(e, t) {
|
|
49
|
+
if (!e || typeof e != "object") return null;
|
|
50
|
+
let n = e, r = n.tokens;
|
|
51
|
+
return n.workspaceId !== t || typeof n.sessionId != "string" || n.sessionId.length === 0 || !y(n.messageId) || !y(n.model) || !r || typeof r != "object" || !v(r.input) || !v(r.output) ? null : {
|
|
52
|
+
workspaceId: t,
|
|
53
|
+
sessionId: n.sessionId,
|
|
54
|
+
...typeof n.messageId == "string" ? { messageId: n.messageId } : {},
|
|
55
|
+
...typeof n.model == "string" ? { model: n.model } : {},
|
|
56
|
+
tokens: {
|
|
57
|
+
input: r.input,
|
|
58
|
+
output: r.output
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function x(e, t) {
|
|
63
|
+
let n = {
|
|
64
|
+
kind: "unavailable",
|
|
65
|
+
reports: /* @__PURE__ */ new Map()
|
|
66
|
+
};
|
|
67
|
+
try {
|
|
68
|
+
let r = _()?.getItem(u(e, t));
|
|
69
|
+
if (!r) return n;
|
|
70
|
+
let i = JSON.parse(r);
|
|
71
|
+
if (i?.v !== 1 || !Array.isArray(i.reports)) return n;
|
|
72
|
+
i.kind === "permission" && (n.kind = "permission");
|
|
73
|
+
for (let e of i.reports) {
|
|
74
|
+
let r = b(e, t);
|
|
75
|
+
r && n.reports.set(g(r), r);
|
|
76
|
+
}
|
|
77
|
+
} catch {}
|
|
78
|
+
return n;
|
|
79
|
+
}
|
|
80
|
+
function S(e, t) {
|
|
81
|
+
let n = h(e, t), r = p.get(n);
|
|
82
|
+
return r || (r = x(e, t), p.set(n, r)), r;
|
|
83
|
+
}
|
|
84
|
+
function C(e, t, n) {
|
|
85
|
+
try {
|
|
86
|
+
let r = _();
|
|
87
|
+
if (!r) return;
|
|
88
|
+
let i = u(e, t);
|
|
89
|
+
if (n.reports.size === 0) {
|
|
90
|
+
r.removeItem(i);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
r.setItem(i, JSON.stringify({
|
|
94
|
+
v: 1,
|
|
95
|
+
kind: n.kind,
|
|
96
|
+
reports: [...n.reports.values()]
|
|
97
|
+
}));
|
|
98
|
+
} catch {}
|
|
99
|
+
}
|
|
100
|
+
function w(e) {
|
|
101
|
+
try {
|
|
102
|
+
if (console.error("[assistant] a turn's usage could not be recorded; the assistant is paused until it is", { kind: e }), typeof window > "u" || typeof CustomEvent != "function") return;
|
|
103
|
+
window.dispatchEvent(new CustomEvent(i, { detail: { kind: e } }));
|
|
104
|
+
} catch {}
|
|
105
|
+
}
|
|
106
|
+
async function T(e, t, n = {}) {
|
|
107
|
+
let i = n.ledger ?? s, c = n.sleep ?? ((e) => a.sleep(e)), l = "unavailable";
|
|
108
|
+
for (let n of r) {
|
|
109
|
+
n > 0 && await c(n);
|
|
110
|
+
try {
|
|
111
|
+
await t(e);
|
|
112
|
+
let n = S(i, e.workspaceId);
|
|
113
|
+
return n.reports.delete(g(e)) && C(i, e.workspaceId, n), o;
|
|
114
|
+
} catch (e) {
|
|
115
|
+
l = d(e);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
let u = S(i, e.workspaceId);
|
|
119
|
+
return u.reports.set(g(e), e), u.kind = l, C(i, e.workspaceId, u), w(l), {
|
|
120
|
+
ok: !1,
|
|
121
|
+
kind: l
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function E(e, t) {
|
|
125
|
+
return S(e, t).reports.size > 0;
|
|
126
|
+
}
|
|
127
|
+
function D(e, t) {
|
|
128
|
+
let n = S(e, t);
|
|
129
|
+
return n.reports.size > 0 ? { kind: n.kind } : null;
|
|
130
|
+
}
|
|
131
|
+
function O(e, t, n) {
|
|
132
|
+
let r = h(e, t), i = m.get(r);
|
|
133
|
+
if (i) return i;
|
|
134
|
+
let a = (async () => {
|
|
135
|
+
let r = S(e, t);
|
|
136
|
+
for (let [i, a] of [...r.reports]) try {
|
|
137
|
+
await n(a), r.reports.delete(i);
|
|
138
|
+
} catch (n) {
|
|
139
|
+
return r.kind = d(n), C(e, t, r), {
|
|
140
|
+
ok: !1,
|
|
141
|
+
kind: r.kind
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return C(e, t, r), r.reports.size === 0 ? o : {
|
|
145
|
+
ok: !1,
|
|
146
|
+
kind: r.kind
|
|
147
|
+
};
|
|
148
|
+
})().finally(() => m.delete(r));
|
|
149
|
+
return m.set(r, a), a;
|
|
150
|
+
}
|
|
151
|
+
function k(e) {
|
|
152
|
+
return e === "permission" ? new n("usage-not-permitted", t.usageNotPermitted.fallback) : new n("usage-not-recorded", t.usageNotRecorded.fallback);
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
export { i as USAGE_REPORT_FAILED_EVENT, r as USAGE_REPORT_RETRY_DELAYS_MS, l as assistantUsageLedger, d as classifyUsageReportFailure, D as getUsageBlock, E as hasPendingUsageReports, T as reportUsageWithRetry, O as retryPendingUsageReports, u as usagePendingStorageKey, a as usageReportClock, k as usageSendRefusal };
|
|
@@ -1,23 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Resolves whether the current user may use
|
|
3
|
-
*
|
|
2
|
+
* Resolves whether the current user may use an ADMIN-ONLY assistant mode: a
|
|
3
|
+
* mode a product declares with `requiresAdmin` (today only FluidGrids'
|
|
4
|
+
* `fluidgrids-node`).
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
6
|
+
* ★★ WORKSPACE-scoped, the same question the server asks (OD-2, BOFF-7803 /
|
|
7
|
+
* BOFF-7800). wspace-sandbox-svc refuses an admin-only mode unless
|
|
8
|
+
* `checkPermission` grants `sandbox:admin` at the WORKSPACE scope
|
|
9
|
+
* (`SandboxProvider.assertAssistantModeAllowed`): Workspace Owner and Workspace
|
|
10
|
+
* Admin pass; Editor, Viewer and Guest do not. This hook used to ask
|
|
11
|
+
* `myRoles` at ORG scope, which is a different question with different
|
|
12
|
+
* answers: an org admin who is only a member of this workspace was offered the
|
|
13
|
+
* mode and then refused when it provisioned, and a workspace admin who is not
|
|
14
|
+
* an org admin was never offered it at all.
|
|
11
15
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* is
|
|
16
|
+
* So it asks the workspace gateway's `checkPermissions` for exactly that pair,
|
|
17
|
+
* for the signed-in user in this workspace. The resolver only answers for the
|
|
18
|
+
* caller's own actor id in the workspace the request is scoped to, which is why
|
|
19
|
+
* the request carries `workspaceId` explicitly and the actor is the user's own
|
|
20
|
+
* id (the token's `sub`).
|
|
21
|
+
*
|
|
22
|
+
* ★ It is a UI gate, not the authority. The server re-checks on every
|
|
23
|
+
* provisioning; this only keeps the mode out of the list for someone the server
|
|
24
|
+
* would refuse, so they are not offered a mode that can only fail.
|
|
25
|
+
*
|
|
26
|
+
* Fails CLOSED: no workspace, no user, a transport error, a GraphQL error, an
|
|
27
|
+
* empty or malformed answer, anything but a single `allowed: true` — all
|
|
28
|
+
* resolve to `canUseApiCalls = false`. An answer is also only ever used for the
|
|
29
|
+
* workspace and user it was asked about: after a switch the hook reports
|
|
30
|
+
* `loading` (and `false`) until the new answer lands, never the previous
|
|
31
|
+
* workspace's yes.
|
|
32
|
+
*
|
|
33
|
+
* ★ It runs only when the product declares an admin-only mode. A product with
|
|
34
|
+
* none has nothing to gate, and no query is sent.
|
|
35
|
+
*/
|
|
36
|
+
/** The server's own pair: `sandbox:admin` (see the header). */
|
|
37
|
+
export declare const ASSISTANT_ADMIN_RESOURCE_TYPE = "sandbox";
|
|
38
|
+
export declare const ASSISTANT_ADMIN_ACTION = "admin";
|
|
39
|
+
export declare const WORKSPACE_ASSISTANT_ADMIN_QUERY = "query AssistantWorkspaceAdmin($inputs: [PermissionCheckInput!]!) {\n checkPermissions(inputs: $inputs) {\n allowed\n }\n}";
|
|
40
|
+
/**
|
|
41
|
+
* Asks whether `userId` holds `sandbox:admin` in `workspaceId`.
|
|
42
|
+
*
|
|
43
|
+
* Resolves `true` only for a clean answer of exactly one `allowed: true`;
|
|
44
|
+
* every other outcome, including a thrown error, resolves `false`. Never
|
|
45
|
+
* rejects.
|
|
15
46
|
*/
|
|
47
|
+
export declare function probeWorkspaceAssistantAdmin(workspaceId: string, userId: string): Promise<boolean>;
|
|
16
48
|
export interface AssistantApiAccess {
|
|
17
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* True only for a confirmed workspace admin (`sandbox:admin` in this
|
|
51
|
+
* workspace), and only when the product declares an admin-only mode.
|
|
52
|
+
*/
|
|
18
53
|
canUseApiCalls: boolean;
|
|
19
|
-
/** True while the
|
|
54
|
+
/** True while the check for the CURRENT workspace and user is in flight. */
|
|
20
55
|
loading: boolean;
|
|
21
56
|
}
|
|
22
|
-
export declare function useAssistantApiAccess(
|
|
57
|
+
export declare function useAssistantApiAccess(workspaceId: string, userId: string | null): AssistantApiAccess;
|
|
23
58
|
//# sourceMappingURL=useAssistantApiAccess.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssistantApiAccess.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/useAssistantApiAccess.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"useAssistantApiAccess.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/useAssistantApiAccess.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAMH,+DAA+D;AAC/D,eAAO,MAAM,6BAA6B,YAAY,CAAC;AACvD,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAE9C,eAAO,MAAM,+BAA+B,mIAI1C,CAAC;AAMH;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAChD,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAiClB;AAED,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;CAClB;AAQD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,kBAAkB,CAgCpB"}
|
|
@@ -3,35 +3,53 @@ import "../../shared-graphql.js";
|
|
|
3
3
|
import { useAssistantProduct as t } from "./product.js";
|
|
4
4
|
import { useEffect as n, useState as r } from "react";
|
|
5
5
|
//#region src/shared/assistant/useAssistantApiAccess.ts
|
|
6
|
-
var i = "query
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
var i = "sandbox", a = "admin", o = "query AssistantWorkspaceAdmin($inputs: [PermissionCheckInput!]!) {\n checkPermissions(inputs: $inputs) {\n allowed\n }\n}";
|
|
7
|
+
async function s(t, n) {
|
|
8
|
+
if (!t || !n) return !1;
|
|
9
|
+
try {
|
|
10
|
+
let r = await e({
|
|
11
|
+
gateway: "workspace",
|
|
12
|
+
query: o,
|
|
13
|
+
variables: { inputs: [{
|
|
14
|
+
actorId: n,
|
|
15
|
+
actorType: "USER",
|
|
16
|
+
scopeId: t,
|
|
17
|
+
resourceType: i,
|
|
18
|
+
action: a
|
|
19
|
+
}] },
|
|
20
|
+
workspaceId: t,
|
|
19
21
|
suppressGlobalErrorEvent: !0
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
});
|
|
23
|
+
if (r.errors?.length) return !1;
|
|
24
|
+
let s = r.data?.checkPermissions;
|
|
25
|
+
return Array.isArray(s) && s.length === 1 && s[0]?.allowed === !0;
|
|
26
|
+
} catch {
|
|
27
|
+
return !1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function c(e, i) {
|
|
31
|
+
let { modes: a } = t(), o = a.some((e) => e.requiresAdmin) && e && i ? JSON.stringify([e, i]) : null, [c, l] = r(null);
|
|
32
|
+
n(() => {
|
|
33
|
+
if (o === null || !i) return;
|
|
34
|
+
let t = !1;
|
|
35
|
+
return s(e, i).then((e) => {
|
|
36
|
+
t || l({
|
|
37
|
+
key: o,
|
|
38
|
+
allowed: e
|
|
39
|
+
});
|
|
28
40
|
}), () => {
|
|
29
41
|
t = !0;
|
|
30
42
|
};
|
|
31
|
-
}, [
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
}, [
|
|
44
|
+
o,
|
|
45
|
+
e,
|
|
46
|
+
i
|
|
47
|
+
]);
|
|
48
|
+
let u = o !== null && c?.key === o;
|
|
49
|
+
return {
|
|
50
|
+
canUseApiCalls: u && c.allowed,
|
|
51
|
+
loading: o !== null && !u
|
|
34
52
|
};
|
|
35
53
|
}
|
|
36
54
|
//#endregion
|
|
37
|
-
export { a as useAssistantApiAccess };
|
|
55
|
+
export { a as ASSISTANT_ADMIN_ACTION, i as ASSISTANT_ADMIN_RESOURCE_TYPE, o as WORKSPACE_ASSISTANT_ADMIN_QUERY, s as probeWorkspaceAssistantAdmin, c as useAssistantApiAccess };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssistantHeartbeat.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/useAssistantHeartbeat.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,IAAI,EAAE,aAAa,GAAG,IAAI,EAC1B,MAAM,EAAE,OAAO,GACd,IAAI,
|
|
1
|
+
{"version":3,"file":"useAssistantHeartbeat.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/useAssistantHeartbeat.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,IAAI,EAAE,aAAa,GAAG,IAAI,EAC1B,MAAM,EAAE,OAAO,GACd,IAAI,CAmCN"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useAuthToken as e } from "../providers/shell/AuthTokenProvider.js";
|
|
2
2
|
import "../../shared-providers-shell.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { useAssistantStore as t } from "./store.js";
|
|
4
|
+
import { extendAssistantSandboxTTL as n, sendHeartbeat as r } from "./api.js";
|
|
5
5
|
import { getWorkspaceId as i } from "./context.js";
|
|
6
6
|
import { useEffect as a } from "react";
|
|
7
7
|
//#region src/shared/assistant/useAssistantHeartbeat.ts
|
|
@@ -10,16 +10,16 @@ function s(s, c, l) {
|
|
|
10
10
|
let { getAccessToken: u, getWorkspaceToken: d } = e();
|
|
11
11
|
a(() => {
|
|
12
12
|
if (!s || !c || !l) return;
|
|
13
|
-
let e = c, a =
|
|
13
|
+
let e = c, a = t.getState().sandboxesByMode[e]?.sandboxId;
|
|
14
14
|
if (!a) return;
|
|
15
15
|
let f = i();
|
|
16
16
|
if (!f) return;
|
|
17
17
|
let p = () => {
|
|
18
|
-
let
|
|
18
|
+
let t = {
|
|
19
19
|
accessToken: u(),
|
|
20
20
|
workspaceToken: d()
|
|
21
21
|
};
|
|
22
|
-
Promise.all([
|
|
22
|
+
Promise.all([r(a, f, s, e, t), n(a, f, 600, t)]).catch((e) => {
|
|
23
23
|
console.warn("[heartbeat] Failed:", e);
|
|
24
24
|
});
|
|
25
25
|
};
|