@yadsh/dsh-qa-surface 0.2.0 → 0.4.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/README.md +236 -20
- package/compatibility.json +11 -3
- package/lib/account-remotes.js +100 -0
- package/lib/account-remotes.js.map +1 -0
- package/lib/accounts/credentials.js +27 -0
- package/lib/accounts/credentials.js.map +1 -0
- package/lib/accounts/errors.js +9 -0
- package/lib/accounts/errors.js.map +1 -0
- package/lib/accounts/file.js +101 -0
- package/lib/accounts/file.js.map +1 -0
- package/lib/accounts/index.js +2 -0
- package/lib/accounts/index.js.map +1 -0
- package/lib/accounts/store.js +461 -0
- package/lib/accounts/store.js.map +1 -0
- package/lib/accounts/token.js +61 -0
- package/lib/accounts/token.js.map +1 -0
- package/lib/attachment-rules.js +111 -0
- package/lib/attachment-rules.js.map +1 -0
- package/lib/attestation.js.map +1 -1
- package/lib/cli.js +256 -0
- package/lib/cli.js.map +1 -0
- package/lib/client/QaAccountsController.js +359 -0
- package/lib/client/QaAccountsController.js.map +1 -0
- package/lib/client/QaSessionController.js +238 -180
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +281 -105
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +95 -244
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/attachments.js +150 -0
- package/lib/client/attachments.js.map +1 -0
- package/lib/client/attestation.js +7 -1
- package/lib/client/attestation.js.map +1 -1
- package/lib/client/base64.js +16 -0
- package/lib/client/base64.js.map +1 -0
- package/lib/client/chat-files.js +48 -0
- package/lib/client/chat-files.js.map +1 -0
- package/lib/client/components/Markdown.js +54 -13
- package/lib/client/components/Markdown.js.map +1 -1
- package/lib/client/components/QaAuthGate.js +40 -0
- package/lib/client/components/QaAuthGate.js.map +1 -0
- package/lib/client/components/QaChangelog.js +131 -0
- package/lib/client/components/QaChangelog.js.map +1 -0
- package/lib/client/components/QaComposer.js +56 -74
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaFileAttachment.js +19 -0
- package/lib/client/components/QaFileAttachment.js.map +1 -0
- package/lib/client/components/QaFilesPanel.js +45 -0
- package/lib/client/components/QaFilesPanel.js.map +1 -0
- package/lib/client/components/QaHeader.js +34 -0
- package/lib/client/components/QaHeader.js.map +1 -0
- package/lib/client/components/QaMessage.js +61 -18
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/components/QaModal.js +31 -0
- package/lib/client/components/QaModal.js.map +1 -0
- package/lib/client/components/QaProfile.js +64 -0
- package/lib/client/components/QaProfile.js.map +1 -0
- package/lib/client/components/QaRightRail.js +15 -0
- package/lib/client/components/QaRightRail.js.map +1 -0
- package/lib/client/components/QaSidebar.js +68 -20
- package/lib/client/components/QaSidebar.js.map +1 -1
- package/lib/client/components/QaSourcesPanel.js +127 -0
- package/lib/client/components/QaSourcesPanel.js.map +1 -0
- package/lib/client/components/QaTurnRail.js +296 -0
- package/lib/client/components/QaTurnRail.js.map +1 -0
- package/lib/client/components/QaWelcomeNotice.js +125 -0
- package/lib/client/components/QaWelcomeNotice.js.map +1 -0
- package/lib/client/components/QaWidthHandle.js +147 -0
- package/lib/client/components/QaWidthHandle.js.map +1 -0
- package/lib/client/components/QaWorkGroup.js +19 -20
- package/lib/client/components/QaWorkGroup.js.map +1 -1
- package/lib/client/components/source-refs.js +78 -0
- package/lib/client/components/source-refs.js.map +1 -0
- package/lib/client/components/surface-utils.js +28 -0
- package/lib/client/components/surface-utils.js.map +1 -0
- package/lib/client/components/thinking-phrases.js +24 -0
- package/lib/client/components/thinking-phrases.js.map +1 -0
- package/lib/client/create-session.js +26 -0
- package/lib/client/create-session.js.map +1 -0
- package/lib/client/failure-copy.js +63 -0
- package/lib/client/failure-copy.js.map +1 -0
- package/lib/client/index.js +135 -16
- package/lib/client/index.js.map +1 -1
- package/lib/client/project-session-state.js +78 -0
- package/lib/client/project-session-state.js.map +1 -0
- package/lib/client/prompt-content.js +54 -0
- package/lib/client/prompt-content.js.map +1 -0
- package/lib/client/session-admission.js +38 -0
- package/lib/client/session-admission.js.map +1 -0
- package/lib/client/session-assets.js +52 -0
- package/lib/client/session-assets.js.map +1 -0
- package/lib/client/session-sources.js +61 -0
- package/lib/client/session-sources.js.map +1 -0
- package/lib/client/settings/card.js +143 -0
- package/lib/client/settings/card.js.map +1 -0
- package/lib/client/settings/fields.js +145 -0
- package/lib/client/settings/fields.js.map +1 -0
- package/lib/client/settings/format.js +255 -0
- package/lib/client/settings/format.js.map +1 -0
- package/lib/client/settings/sections/access.js +25 -0
- package/lib/client/settings/sections/access.js.map +1 -0
- package/lib/client/settings/sections/accounts.js +47 -0
- package/lib/client/settings/sections/accounts.js.map +1 -0
- package/lib/client/settings/sections/attachments.js +46 -0
- package/lib/client/settings/sections/attachments.js.map +1 -0
- package/lib/client/settings/sections/branding.js +28 -0
- package/lib/client/settings/sections/branding.js.map +1 -0
- package/lib/client/settings/sections/common.js +20 -0
- package/lib/client/settings/sections/common.js.map +1 -0
- package/lib/client/settings/sections/embedding.js +19 -0
- package/lib/client/settings/sections/embedding.js.map +1 -0
- package/lib/client/settings/sections/interface.js +60 -0
- package/lib/client/settings/sections/interface.js.map +1 -0
- package/lib/client/settings/sections/lockdown.js +82 -0
- package/lib/client/settings/sections/lockdown.js.map +1 -0
- package/lib/client/settings/sections/session.js +53 -0
- package/lib/client/settings/sections/session.js.map +1 -0
- package/lib/client/settings/sections/sources.js +72 -0
- package/lib/client/settings/sections/sources.js.map +1 -0
- package/lib/client/settings/sections/status.js +37 -0
- package/lib/client/settings/sections/status.js.map +1 -0
- package/lib/client/settings/sections.js +23 -0
- package/lib/client/settings/sections.js.map +1 -0
- package/lib/client/settings/styles.js +57 -0
- package/lib/client/settings/styles.js.map +1 -0
- package/lib/client/settlement.js +24 -0
- package/lib/client/settlement.js.map +1 -0
- package/lib/client/stream-publisher.js +47 -0
- package/lib/client/stream-publisher.js.map +1 -0
- package/lib/client/styles.js +225 -17
- package/lib/client/styles.js.map +1 -1
- package/lib/client/tool-presentation.js +102 -0
- package/lib/client/tool-presentation.js.map +1 -0
- package/lib/client/turn-sources.js +98 -0
- package/lib/client/turn-sources.js.map +1 -0
- package/lib/client/types.js +2 -0
- package/lib/client/types.js.map +1 -1
- package/lib/client/use-right-rail.js +96 -0
- package/lib/client/use-right-rail.js.map +1 -0
- package/lib/client/use-session-ui-state.js +75 -0
- package/lib/client/use-session-ui-state.js.map +1 -0
- package/lib/client/use-transcript-view.js +44 -0
- package/lib/client/use-transcript-view.js.map +1 -0
- package/lib/client.js +9052 -1345
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/accounts.js +60 -0
- package/lib/config-resolvers/accounts.js.map +1 -0
- package/lib/config-resolvers/attachments.js +28 -0
- package/lib/config-resolvers/attachments.js.map +1 -0
- package/lib/config-resolvers/basics.js +59 -0
- package/lib/config-resolvers/basics.js.map +1 -0
- package/lib/config-resolvers/defaults.js +132 -0
- package/lib/config-resolvers/defaults.js.map +1 -0
- package/lib/config-resolvers/lockdown.js +79 -0
- package/lib/config-resolvers/lockdown.js.map +1 -0
- package/lib/config-resolvers/session.js +42 -0
- package/lib/config-resolvers/session.js.map +1 -0
- package/lib/config-resolvers/shared.js +42 -0
- package/lib/config-resolvers/shared.js.map +1 -0
- package/lib/config-resolvers/sources.js +81 -0
- package/lib/config-resolvers/sources.js.map +1 -0
- package/lib/config-resolvers/ui.js +20 -0
- package/lib/config-resolvers/ui.js.map +1 -0
- package/lib/config.js +279 -102
- package/lib/config.js.map +1 -1
- package/lib/entry-redirect.js +45 -0
- package/lib/entry-redirect.js.map +1 -0
- package/lib/host-route.js +25 -1
- package/lib/host-route.js.map +1 -1
- package/lib/index.js +258 -23
- package/lib/index.js.map +1 -1
- package/lib/launch-token.js +42 -0
- package/lib/launch-token.js.map +1 -0
- package/lib/profile.js +214 -0
- package/lib/profile.js.map +1 -0
- package/lib/prompt-notes.js +231 -0
- package/lib/prompt-notes.js.map +1 -0
- package/lib/provenance/collector.js +40 -0
- package/lib/provenance/collector.js.map +1 -0
- package/lib/provenance/connectors.js +147 -0
- package/lib/provenance/connectors.js.map +1 -0
- package/lib/provenance/dedupe.js +89 -0
- package/lib/provenance/dedupe.js.map +1 -0
- package/lib/provenance/extractors.js +340 -0
- package/lib/provenance/extractors.js.map +1 -0
- package/lib/provenance/file-preview.js +39 -0
- package/lib/provenance/file-preview.js.map +1 -0
- package/lib/provenance/host-store.js +387 -0
- package/lib/provenance/host-store.js.map +1 -0
- package/lib/provenance/index.js +9 -0
- package/lib/provenance/index.js.map +1 -0
- package/lib/provenance/normalize.js +128 -0
- package/lib/provenance/normalize.js.map +1 -0
- package/lib/provenance/reported.js +53 -0
- package/lib/provenance/reported.js.map +1 -0
- package/lib/provenance/types.js +2 -0
- package/lib/provenance/types.js.map +1 -0
- package/lib/resolve-config.js +35 -249
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +122 -14
- package/lib/secure-session.js.map +1 -1
- package/lib/shared/session-key.js +18 -0
- package/lib/shared/session-key.js.map +1 -0
- package/lib/shared/settings.js +10 -0
- package/lib/shared/settings.js.map +1 -0
- package/lib/thinking-phrases.js +68 -0
- package/lib/thinking-phrases.js.map +1 -0
- package/lib/typert.host.js +749 -11
- package/lib/typert.remote-client.d.ts +23 -3
- package/lib/typert.remote-client.js +593 -6
- package/lib/types/account-remotes.d.ts +42 -0
- package/lib/types/accounts/credentials.d.ts +14 -0
- package/lib/types/accounts/errors.d.ts +11 -0
- package/lib/types/accounts/file.d.ts +82 -0
- package/lib/types/accounts/index.d.ts +2 -0
- package/lib/types/accounts/store.d.ts +144 -0
- package/lib/types/accounts/token.d.ts +31 -0
- package/lib/types/attachment-rules.d.ts +44 -0
- package/lib/types/attestation.d.ts +1 -1
- package/lib/types/cli.d.ts +9 -0
- package/lib/types/client/QaAccountsController.d.ts +102 -0
- package/lib/types/client/QaConfigController.d.ts +1 -1
- package/lib/types/client/QaSessionController.d.ts +61 -22
- package/lib/types/client/QaSurface.d.ts +14 -3
- package/lib/types/client/QaTranscriptAdapter.d.ts +5 -10
- package/lib/types/client/attachments.d.ts +54 -0
- package/lib/types/client/base64.d.ts +10 -0
- package/lib/types/client/chat-files.d.ts +30 -0
- package/lib/types/client/components/Markdown.d.ts +11 -1
- package/lib/types/client/components/QaAgentsDrawer.d.ts +1 -1
- package/lib/types/client/components/QaAuthGate.d.ts +15 -0
- package/lib/types/client/components/QaChangelog.d.ts +21 -0
- package/lib/types/client/components/QaComposer.d.ts +8 -4
- package/lib/types/client/components/QaFileAttachment.d.ts +14 -0
- package/lib/types/client/components/QaFilesPanel.d.ts +15 -0
- package/lib/types/client/components/QaHeader.d.ts +41 -0
- package/lib/types/client/components/QaMessage.d.ts +12 -3
- package/lib/types/client/components/QaModal.d.ts +26 -0
- package/lib/types/client/components/QaProfile.d.ts +25 -0
- package/lib/types/client/components/QaRightRail.d.ts +23 -0
- package/lib/types/client/components/QaSidebar.d.ts +44 -2
- package/lib/types/client/components/QaSourcesPanel.d.ts +23 -0
- package/lib/types/client/components/QaTurnRail.d.ts +65 -0
- package/lib/types/client/components/QaWelcomeNotice.d.ts +27 -0
- package/lib/types/client/components/QaWidthHandle.d.ts +43 -0
- package/lib/types/client/components/QaWorkGroup.d.ts +5 -3
- package/lib/types/client/components/source-refs.d.ts +16 -0
- package/lib/types/client/components/surface-utils.d.ts +11 -0
- package/lib/types/client/components/thinking-phrases.d.ts +9 -0
- package/lib/types/client/create-session.d.ts +13 -0
- package/lib/types/client/failure-copy.d.ts +19 -0
- package/lib/types/client/index.d.ts +1 -0
- package/lib/types/client/project-session-state.d.ts +30 -0
- package/lib/types/client/prompt-content.d.ts +30 -0
- package/lib/types/client/session-admission.d.ts +23 -0
- package/lib/types/client/session-assets.d.ts +20 -0
- package/lib/types/client/session-sources.d.ts +28 -0
- package/lib/types/client/settings/card.d.ts +23 -0
- package/lib/types/client/settings/fields.d.ts +139 -0
- package/lib/types/client/settings/format.d.ts +108 -0
- package/lib/types/client/settings/sections/access.d.ts +9 -0
- package/lib/types/client/settings/sections/accounts.d.ts +9 -0
- package/lib/types/client/settings/sections/attachments.d.ts +15 -0
- package/lib/types/client/settings/sections/branding.d.ts +8 -0
- package/lib/types/client/settings/sections/common.d.ts +28 -0
- package/lib/types/client/settings/sections/embedding.d.ts +8 -0
- package/lib/types/client/settings/sections/interface.d.ts +9 -0
- package/lib/types/client/settings/sections/lockdown.d.ts +9 -0
- package/lib/types/client/settings/sections/session.d.ts +9 -0
- package/lib/types/client/settings/sections/sources.d.ts +9 -0
- package/lib/types/client/settings/sections/status.d.ts +22 -0
- package/lib/types/client/settings/sections.d.ts +25 -0
- package/lib/types/client/settings/styles.d.ts +8 -0
- package/lib/types/client/settlement.d.ts +6 -0
- package/lib/types/client/stream-publisher.d.ts +28 -0
- package/lib/types/client/tool-presentation.d.ts +6 -0
- package/lib/types/client/turn-sources.d.ts +14 -0
- package/lib/types/client/types.d.ts +101 -9
- package/lib/types/client/use-right-rail.d.ts +56 -0
- package/lib/types/client/use-session-ui-state.d.ts +41 -0
- package/lib/types/client/use-transcript-view.d.ts +20 -0
- package/lib/types/config-resolvers/accounts.d.ts +15 -0
- package/lib/types/config-resolvers/attachments.d.ts +6 -0
- package/lib/types/config-resolvers/basics.d.ts +8 -0
- package/lib/types/config-resolvers/defaults.d.ts +4 -0
- package/lib/types/config-resolvers/lockdown.d.ts +10 -0
- package/lib/types/config-resolvers/session.d.ts +6 -0
- package/lib/types/config-resolvers/shared.d.ts +16 -0
- package/lib/types/config-resolvers/sources.d.ts +6 -0
- package/lib/types/config-resolvers/ui.d.ts +6 -0
- package/lib/types/entry-redirect.d.ts +20 -0
- package/lib/types/host-route.d.ts +14 -1
- package/lib/types/index.d.ts +54 -3
- package/lib/types/launch-token.d.ts +21 -0
- package/lib/types/profile.d.ts +76 -0
- package/lib/types/prompt-notes.d.ts +110 -0
- package/lib/types/provenance/collector.d.ts +26 -0
- package/lib/types/provenance/connectors.d.ts +11 -0
- package/lib/types/provenance/dedupe.d.ts +6 -0
- package/lib/types/provenance/extractors.d.ts +14 -0
- package/lib/types/provenance/file-preview.d.ts +10 -0
- package/lib/types/provenance/host-store.d.ts +54 -0
- package/lib/types/provenance/index.d.ts +10 -0
- package/lib/types/provenance/normalize.d.ts +13 -0
- package/lib/types/provenance/reported.d.ts +5 -0
- package/lib/types/provenance/types.d.ts +78 -0
- package/lib/types/resolve-config.d.ts +8 -3
- package/lib/types/secure-session.d.ts +36 -2
- package/lib/types/shared/session-key.d.ts +23 -0
- package/lib/types/shared/settings.d.ts +10 -0
- package/lib/types/thinking-phrases.d.ts +17 -0
- package/lib/types/types.d.ts +290 -16
- package/lib/types/user-workspace.d.ts +38 -0
- package/lib/user-workspace.js +231 -0
- package/lib/user-workspace.js.map +1 -0
- package/package.json +71 -47
- package/CHANGELOG.md +0 -93
- package/SPEC-dsh-qa-surface.md +0 -2425
- package/docs/ARCHITECTURE.md +0 -66
- package/docs/COMPATIBILITY.md +0 -14
- package/docs/CONFIGURATION.md +0 -112
- package/docs/EMBEDDING.md +0 -13
- package/lib/client/components/QaSourcesDrawer.js +0 -46
- package/lib/client/components/QaSourcesDrawer.js.map +0 -1
- package/lib/types/client/components/QaSourcesDrawer.d.ts +0 -8
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
2
|
+
import { QaAccounts } from "./accounts/store.js";
|
|
3
|
+
import type { QaAccountProfileInput, QaAccountSession, QaAccountUserPublic, QaClaimResult, QaOwnershipEntry, QaWhoamiResult, ResolvedQaSurfaceConfig } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Host-side bodies of the account remotes the `QaSurface` service exposes.
|
|
6
|
+
* The `@Remote`-decorated signatures stay on the service class (typert code
|
|
7
|
+
* generation reads the class shape); this context carries everything behind
|
|
8
|
+
* them: store construction and memoization, the disabled refusal, and the
|
|
9
|
+
* error mapping onto the shared `(reason: <code>)` wire marker.
|
|
10
|
+
*/
|
|
11
|
+
export interface QaAccountRemotes {
|
|
12
|
+
/** The accounts store behind the runtime toggle, or undefined while off. */
|
|
13
|
+
resolve(config: ResolvedQaSurfaceConfig): QaAccounts | undefined;
|
|
14
|
+
/** Map a store failure onto the shared `(reason: <code>)` wire marker. */
|
|
15
|
+
run<T>(operation: () => T, sessionIdForLog?: string): T;
|
|
16
|
+
register(email: string, password: string): QaAccountSession;
|
|
17
|
+
login(email: string, password: string): QaAccountSession;
|
|
18
|
+
/** Identity probe; safe to call with an empty or expired token. */
|
|
19
|
+
whoami(token: string): QaWhoamiResult;
|
|
20
|
+
/** Migrate a browser's local chat index into server-side ownership. */
|
|
21
|
+
claimSessions(token: string, sessionIds: readonly string[]): QaClaimResult;
|
|
22
|
+
/** The token user's owned session ids; the sidebar list authority. */
|
|
23
|
+
ownedSessions(token: string): {
|
|
24
|
+
readonly ids: readonly string[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Every chat-ownership entry with owner display names; the cross-user view
|
|
28
|
+
* admin browsers group the sidebar by. Ordinary accounts are refused with
|
|
29
|
+
* the dedicated reason, anonymous ones with auth-required.
|
|
30
|
+
*/
|
|
31
|
+
listOwnership(token: string): {
|
|
32
|
+
readonly entries: readonly QaOwnershipEntry[];
|
|
33
|
+
};
|
|
34
|
+
/** Replace the caller's own self-declared profile; the token is the identity. */
|
|
35
|
+
updateProfile(token: string, input: QaAccountProfileInput): QaAccountUserPublic;
|
|
36
|
+
}
|
|
37
|
+
/** Build the account-remotes context for one `QaSurface` service instance. */
|
|
38
|
+
export declare function createQaAccountRemotes(options: {
|
|
39
|
+
getConfig: () => ResolvedQaSurfaceConfig;
|
|
40
|
+
logger: PluginLogger;
|
|
41
|
+
}): QaAccountRemotes;
|
|
42
|
+
//# sourceMappingURL=account-remotes.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** An account request after normalization, ready to become a stored user. */
|
|
2
|
+
export interface ValidatedCredentials {
|
|
3
|
+
readonly email: string;
|
|
4
|
+
/** Trimmed display name; empty means "derive one from the address". */
|
|
5
|
+
readonly displayName: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The email/password/display-name gate shared by self-registration and the
|
|
9
|
+
* operator's addUser, so both paths reject unusable input with the same
|
|
10
|
+
* errors and messages, in the same order. Returns the normalized address and
|
|
11
|
+
* trimmed display name; the caller still decides uniqueness and role.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateCredentials(email: string, password: string, displayName: string | undefined): ValidatedCredentials;
|
|
14
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coarse, wire-safe account failure codes. They ride the `(reason: <code>)`
|
|
3
|
+
* marker pattern the attestation path established; the browser maps them to
|
|
4
|
+
* audience-safe copy and the precise cause stays in the Host logs.
|
|
5
|
+
*/
|
|
6
|
+
export type QaAccountsErrorReason = "auth-required" | "admin-required" | "invalid-credentials" | "account-disabled" | "email-taken" | "invalid-email" | "invalid-display-name" | "invalid-profile" | "profile-disabled" | "invalid-role" | "weak-password" | "registration-disabled" | "rate-limited" | "session-owned-elsewhere";
|
|
7
|
+
export declare class QaAccountsError extends Error {
|
|
8
|
+
readonly reason: QaAccountsErrorReason;
|
|
9
|
+
constructor(reason: QaAccountsErrorReason, message: string);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Stats } from "node:fs";
|
|
2
|
+
import type { QaAccountRole } from "../types.js";
|
|
3
|
+
/** One account's self-declared profile as it rests in the accounts file. */
|
|
4
|
+
export interface StoredProfile {
|
|
5
|
+
fullName?: string;
|
|
6
|
+
identities?: Record<string, string>;
|
|
7
|
+
instructions?: string;
|
|
8
|
+
updatedAt?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface StoredUser {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly email: string;
|
|
13
|
+
readonly displayName: string;
|
|
14
|
+
readonly role: QaAccountRole;
|
|
15
|
+
/** scrypt material: hex salt + hex hash. */
|
|
16
|
+
readonly passwordHash: {
|
|
17
|
+
readonly salt: string;
|
|
18
|
+
readonly hash: string;
|
|
19
|
+
};
|
|
20
|
+
readonly createdAt: string;
|
|
21
|
+
lastLoginAt: string | null;
|
|
22
|
+
/** Disabled accounts are refused at login and lose their live tokens. */
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Bumped to invalidate every token ever issued to the account: the value
|
|
26
|
+
* rides the token payload and must match at verification time.
|
|
27
|
+
*/
|
|
28
|
+
tokenVersion?: number;
|
|
29
|
+
/** Absent until the owner fills the profile form for the first time. */
|
|
30
|
+
profile?: StoredProfile;
|
|
31
|
+
}
|
|
32
|
+
export interface AccountsFile {
|
|
33
|
+
readonly version: 1;
|
|
34
|
+
/** HMAC key for account tokens; rotated on password change by rewriting it. */
|
|
35
|
+
readonly secret: string;
|
|
36
|
+
readonly users: StoredUser[];
|
|
37
|
+
readonly ownership: Record<string, {
|
|
38
|
+
readonly userId: string;
|
|
39
|
+
readonly claimedAt: string;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
/** mtime+size pair identifying one on-disk version of the accounts file. */
|
|
43
|
+
export interface FileStamp {
|
|
44
|
+
readonly mtimeMs: number;
|
|
45
|
+
readonly size: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Where the last-seen stamp lives. Load and persist keep it current in place,
|
|
49
|
+
* so a caller holds one mutable ref instead of threading the stamp through
|
|
50
|
+
* every read-modify-write.
|
|
51
|
+
*/
|
|
52
|
+
export interface FileStampRef {
|
|
53
|
+
current: FileStamp;
|
|
54
|
+
}
|
|
55
|
+
/** A stamp no real file can match, so the first load always reads the disk. */
|
|
56
|
+
export declare function createFileStampRef(): FileStampRef;
|
|
57
|
+
export declare function stampOf(stat: Stats): FileStamp;
|
|
58
|
+
/** The accounts file lives next to the DSH home the launcher exports. */
|
|
59
|
+
export declare function defaultAccountsFilePath(): string;
|
|
60
|
+
/**
|
|
61
|
+
* Read the accounts file, or create it on first run with a fresh token
|
|
62
|
+
* secret. The stamp ref is left pointing at the version just read.
|
|
63
|
+
*/
|
|
64
|
+
export declare function loadAccountsFile(filePath: string, stamp: FileStampRef): AccountsFile;
|
|
65
|
+
/**
|
|
66
|
+
* Persist the accounts file atomically (temp file + rename) and leave the
|
|
67
|
+
* stamp ref pointing at the freshly written version.
|
|
68
|
+
*/
|
|
69
|
+
export declare function persistAccountsFile(filePath: string, file: AccountsFile, stamp: FileStampRef): void;
|
|
70
|
+
/**
|
|
71
|
+
* The qa-accounts CLI runs in its own process against the same file. Re-read
|
|
72
|
+
* it whenever it changed on disk, before every read or read-modify-write:
|
|
73
|
+
* without this a running Host would keep honoring tokens the CLI revoked
|
|
74
|
+
* and its next save would resurrect the CLI's change from a stale snapshot.
|
|
75
|
+
* One file, one writer at a time remains the deployment's discipline; LAN
|
|
76
|
+
* scale keeps the stat per operation trivial.
|
|
77
|
+
*
|
|
78
|
+
* Returns the freshly loaded file, or undefined when the caller should keep
|
|
79
|
+
* serving its in-memory state.
|
|
80
|
+
*/
|
|
81
|
+
export declare function reloadAccountsFileIfChanged(filePath: string, stamp: FileStampRef): AccountsFile | undefined;
|
|
82
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { QaAccountIdentityField, QaAccountProfile, QaAccountProfileInput, QaAccountRole, QaAccountSession, QaAccountUserPublic, QaClaimResult, QaOwnershipEntry, QaWhoamiResult } from "../types.js";
|
|
2
|
+
import type { StoredUser } from "./file.js";
|
|
3
|
+
export { QaAccountsError } from "./errors.js";
|
|
4
|
+
export type { QaAccountsErrorReason } from "./errors.js";
|
|
5
|
+
export { defaultAccountsFilePath } from "./file.js";
|
|
6
|
+
export interface QaAccountsOptions {
|
|
7
|
+
readonly sessionTtlDays: number;
|
|
8
|
+
readonly allowRegistration: boolean;
|
|
9
|
+
/** Login/registration attempts accepted per rolling minute, store-wide. */
|
|
10
|
+
readonly maxAuthAttemptsPerMinute?: number;
|
|
11
|
+
/** Character cap on a stored profile's agent guidance. */
|
|
12
|
+
readonly instructionsMaxLength?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Fields the deployment declares. Self-service writes may name only these;
|
|
15
|
+
* omitting the list (the operator CLI) checks the key shape alone.
|
|
16
|
+
*/
|
|
17
|
+
readonly identityFields?: readonly QaAccountIdentityField[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Host authority for QA accounts: the file-backed user list, the session
|
|
21
|
+
* ownership map and the HMAC account tokens. All mutations are synchronous
|
|
22
|
+
* and persisted atomically (temp file + rename); LAN scale keeps this trivial.
|
|
23
|
+
*
|
|
24
|
+
* The class is the facade: token mechanics live in token.ts, the file format
|
|
25
|
+
* and its atomic persistence plus the external-change probe in file.ts, and
|
|
26
|
+
* the credential rules shared by registration and the operator CLI in
|
|
27
|
+
* credentials.ts.
|
|
28
|
+
*/
|
|
29
|
+
export declare class QaAccounts {
|
|
30
|
+
readonly filePath: string;
|
|
31
|
+
private file;
|
|
32
|
+
private readonly authAttempts;
|
|
33
|
+
private readonly maxAuthAttemptsPerMinute;
|
|
34
|
+
private readonly sessionTtlDays;
|
|
35
|
+
private readonly allowRegistration;
|
|
36
|
+
/** Character cap on a stored profile's agent guidance. */
|
|
37
|
+
private readonly instructionsMaxLength;
|
|
38
|
+
/** Declared handle fields; undefined lets an operator write any shape-valid key. */
|
|
39
|
+
private readonly identityFields;
|
|
40
|
+
/** mtime+size of the file as of the last load; the external-change probe. */
|
|
41
|
+
private readonly fileStamp;
|
|
42
|
+
constructor(filePath: string | undefined, options: QaAccountsOptions);
|
|
43
|
+
/**
|
|
44
|
+
* Re-read the accounts file when it changed on disk, before every read or
|
|
45
|
+
* read-modify-write. The probe itself and its cross-process rationale live
|
|
46
|
+
* with the file layer (reloadAccountsFileIfChanged).
|
|
47
|
+
*/
|
|
48
|
+
private reloadIfChanged;
|
|
49
|
+
private save;
|
|
50
|
+
private pruneAuthAttempts;
|
|
51
|
+
private assertAuthBudget;
|
|
52
|
+
private userByEmail;
|
|
53
|
+
register(email: string, password: string, displayName?: string): QaAccountSession;
|
|
54
|
+
login(email: string, password: string): QaAccountSession;
|
|
55
|
+
whoami(token: string): QaWhoamiResult;
|
|
56
|
+
/** Resolve a token to its user, or null for absent/invalid/expired ones. */
|
|
57
|
+
verifyToken(token: string): string | null;
|
|
58
|
+
private mintToken;
|
|
59
|
+
/** The account behind a token, or an auth-required refusal. */
|
|
60
|
+
requireUser(token: string): StoredUser;
|
|
61
|
+
/**
|
|
62
|
+
* Ownership gate for one session: claim unowned sessions for the requesting
|
|
63
|
+
* user (first come, first served — the pre-accounts migration path), refuse
|
|
64
|
+
* foreign sessions unless the caller administers the deployment.
|
|
65
|
+
*/
|
|
66
|
+
ensureSessionAccess(token: string, sessionId: string): QaAccountUserPublic;
|
|
67
|
+
/**
|
|
68
|
+
* Atomically reserve a Host-generated session id for the token user before
|
|
69
|
+
* the Session exists. Browser callers therefore never get a race window in
|
|
70
|
+
* which they can claim another user's newly created chat.
|
|
71
|
+
*/
|
|
72
|
+
reserveSession(token: string, sessionId: string): QaAccountUserPublic;
|
|
73
|
+
/** Roll back a reservation if Host creation failed before a chat existed. */
|
|
74
|
+
releaseSessionReservation(userId: string, sessionId: string): void;
|
|
75
|
+
/** Bulk-claim a browser's local chat index; foreign ids come back as conflicts. */
|
|
76
|
+
claimSessions(token: string, sessionIds: readonly string[]): QaClaimResult;
|
|
77
|
+
/** Session ids owned by the token's user, most recently claimed first. */
|
|
78
|
+
ownedSessionIds(token: string): readonly string[];
|
|
79
|
+
/**
|
|
80
|
+
* Every ownership entry with the owner's display name resolved at read
|
|
81
|
+
* time, oldest claim first. Admin-only: this is the cross-user view the
|
|
82
|
+
* admin sidebar groups chats by; ordinary accounts get a dedicated refusal.
|
|
83
|
+
*/
|
|
84
|
+
listOwnership(token: string): readonly QaOwnershipEntry[];
|
|
85
|
+
/** Every account, file order; for `qa-accounts list`. */
|
|
86
|
+
listUsers(): readonly {
|
|
87
|
+
readonly email: string;
|
|
88
|
+
readonly displayName: string;
|
|
89
|
+
readonly role: QaAccountRole;
|
|
90
|
+
readonly disabled: boolean;
|
|
91
|
+
readonly createdAt: string;
|
|
92
|
+
readonly lastLoginAt: string | null;
|
|
93
|
+
}[];
|
|
94
|
+
/** Create an account outside the self-registration gate. */
|
|
95
|
+
addUser(email: string, password: string, options?: {
|
|
96
|
+
displayName?: string;
|
|
97
|
+
role?: QaAccountRole;
|
|
98
|
+
}): QaAccountUserPublic;
|
|
99
|
+
private editUser;
|
|
100
|
+
/** Grant or revoke the admin role. */
|
|
101
|
+
setUserRole(email: string, role: QaAccountRole): QaAccountUserPublic;
|
|
102
|
+
/**
|
|
103
|
+
* Disable an account: future logins are refused and every live token is
|
|
104
|
+
* invalidated (the token version bumps). `enable` does not resurrect old
|
|
105
|
+
* tokens — the account signs in again.
|
|
106
|
+
*/
|
|
107
|
+
setUserDisabled(email: string, disabled: boolean): QaAccountUserPublic;
|
|
108
|
+
/** Invalidate every token of the account (password-leak response). */
|
|
109
|
+
revokeTokens(email: string): QaAccountUserPublic;
|
|
110
|
+
/**
|
|
111
|
+
* The account that owns one session, or undefined while nobody claimed it.
|
|
112
|
+
* The prompt renderer resolves a chat's owner through this map, so a session
|
|
113
|
+
* that predates accounts simply carries no identity.
|
|
114
|
+
*/
|
|
115
|
+
ownerIdOf(sessionId: string): string | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Email plus profile of one account, for the prompt renderer. A disabled
|
|
118
|
+
* account resolves to nothing: its identity leaves the prompt together with
|
|
119
|
+
* its access, so a revoked user is no longer addressed by name.
|
|
120
|
+
*/
|
|
121
|
+
identityOf(userId: string): {
|
|
122
|
+
readonly email: string;
|
|
123
|
+
readonly profile: QaAccountProfile;
|
|
124
|
+
} | undefined;
|
|
125
|
+
/** One account in its public shape; undefined when the address is unknown. */
|
|
126
|
+
findUser(email: string): QaAccountUserPublic | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* Operator write: replace one account's profile, addressed by email. The
|
|
129
|
+
* CLI merges field-level flags into a full profile before calling this.
|
|
130
|
+
*/
|
|
131
|
+
setProfile(email: string, input: QaAccountProfileInput): QaAccountUserPublic;
|
|
132
|
+
/**
|
|
133
|
+
* Self-service write for the token's own account. The token is verified
|
|
134
|
+
* first, so a browser can only ever edit the profile it is signed in as.
|
|
135
|
+
*/
|
|
136
|
+
updateOwnProfile(token: string, input: QaAccountProfileInput): QaAccountUserPublic;
|
|
137
|
+
/**
|
|
138
|
+
* Validate one profile write and stamp it onto the account. Throws before
|
|
139
|
+
* anything is mutated, so a rejected write leaves the stored profile, and
|
|
140
|
+
* the address it is keyed to, exactly as they were.
|
|
141
|
+
*/
|
|
142
|
+
private stampedProfile;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The account facts token verification needs: identity plus token version. */
|
|
2
|
+
interface TokenUser {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly tokenVersion?: number;
|
|
5
|
+
}
|
|
6
|
+
/** The claims carried by a v1 account token payload. */
|
|
7
|
+
export interface TokenPayload {
|
|
8
|
+
readonly uid: string;
|
|
9
|
+
/** Expiry, epoch milliseconds. */
|
|
10
|
+
readonly exp: number;
|
|
11
|
+
/** The account's token version at mint time. */
|
|
12
|
+
readonly ver: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function base64Url(value: Buffer | string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Mint a v1 account token: a base64url JSON payload plus an HMAC-SHA256
|
|
17
|
+
* signature keyed with the accounts file secret.
|
|
18
|
+
*/
|
|
19
|
+
export declare function mintToken(secret: string, payload: TokenPayload): string;
|
|
20
|
+
/**
|
|
21
|
+
* Verify a v1 account token against the current secret and account list and
|
|
22
|
+
* return its user id, or null for anything malformed, foreign-signed,
|
|
23
|
+
* expired or superseded. Signature computation, the length check and the
|
|
24
|
+
* payload decode share one try, so a hostile token can only ever resolve to
|
|
25
|
+
* null; the comparison is timing-safe (equal length first, then
|
|
26
|
+
* timingSafeEqual) so a signature guess cannot be accelerated by measuring
|
|
27
|
+
* HMAC rejection time.
|
|
28
|
+
*/
|
|
29
|
+
export declare function verifyToken(secret: string, token: string, users: readonly TokenUser[]): string | null;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attachment vocabulary shared by the Host configuration and the browser
|
|
3
|
+
* composer. The module stays free of Node and DOM imports: the client bundle
|
|
4
|
+
* imports it directly, and the Host resolver uses it to normalize the
|
|
5
|
+
* operator's configuration.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Text-file extensions the composer accepts out of the box. Compared
|
|
9
|
+
* lowercase and without the leading dot; an entry is a suffix, not a glob.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_QA_TEXT_EXTENSIONS: readonly string[];
|
|
12
|
+
/** Bounds the resolver and the settings card agree on. */
|
|
13
|
+
export declare const QA_PASTED_TEXT_LINES_MIN = 0;
|
|
14
|
+
export declare const QA_PASTED_TEXT_LINES_MAX = 10000;
|
|
15
|
+
export declare const QA_MAX_FILE_BYTES_MIN = 1024;
|
|
16
|
+
export declare const QA_MAX_FILE_BYTES_MAX = 52428800;
|
|
17
|
+
export declare const QA_MAX_PENDING_MIN = 1;
|
|
18
|
+
export declare const QA_MAX_PENDING_MAX = 40;
|
|
19
|
+
/**
|
|
20
|
+
* Normalize an operator-authored extension list: lowercase, leading dots
|
|
21
|
+
* stripped, malformed entries and duplicates dropped, order preserved.
|
|
22
|
+
* An empty result means no extension is accepted by name — the composer then
|
|
23
|
+
* still accepts whatever the browser reports as `text/*`.
|
|
24
|
+
* @param values - raw extension tokens from configuration.
|
|
25
|
+
* @returns the normalized token list.
|
|
26
|
+
*/
|
|
27
|
+
export declare function normalizeTextExtensions(values: readonly string[]): readonly string[];
|
|
28
|
+
/**
|
|
29
|
+
* Whether one file name carries an accepted text extension. The comparison is
|
|
30
|
+
* case-insensitive; a name without a dot, or with a hidden-file dot only
|
|
31
|
+
* (`.gitignore`), is matched against the whole leaf.
|
|
32
|
+
* @param name - display file name.
|
|
33
|
+
* @param extensions - normalized accepted extensions.
|
|
34
|
+
* @returns whether the name matches one accepted extension.
|
|
35
|
+
*/
|
|
36
|
+
export declare function hasTextExtension(name: string, extensions: readonly string[]): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Count the lines of a pasted blob the way a reader counts them: a single
|
|
39
|
+
* trailing newline does not open a new line, and CRLF counts once.
|
|
40
|
+
* @param text - pasted plain text.
|
|
41
|
+
* @returns the line count, at least 1 for any non-empty text.
|
|
42
|
+
*/
|
|
43
|
+
export declare function countTextLines(text: string): number;
|
|
44
|
+
//# sourceMappingURL=attachment-rules.d.ts.map
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* audience, precise enough for an operator reading the browser console to
|
|
9
9
|
* know which class of mismatch to look for in the Host logs.
|
|
10
10
|
*/
|
|
11
|
-
export type QaAttestationReason = "agent-unavailable" | "workspace-unavailable" | "composition-mismatch" | "permission-preset" | "adoption-refused" | "unknown-tools" | "attestation-failed";
|
|
11
|
+
export type QaAttestationReason = "agent-unavailable" | "workspace-unavailable" | "composition-mismatch" | "permission-preset" | "adoption-refused" | "unknown-tools" | "auth-required" | "session-owned-elsewhere" | "attestation-failed";
|
|
12
12
|
/** Host rejection whose wire message carries the coarse reason marker. */
|
|
13
13
|
export declare class QaAttestationError extends Error {
|
|
14
14
|
readonly reason: QaAttestationReason;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface CliIo {
|
|
3
|
+
out(line: string): void;
|
|
4
|
+
err(line: string): void;
|
|
5
|
+
}
|
|
6
|
+
/** Execute one management command; returns the process exit code. */
|
|
7
|
+
export declare function run(argv: readonly string[], io: CliIo, readStdin?: () => string): number;
|
|
8
|
+
export declare function main(argv: readonly string[], io?: CliIo, readStdin?: () => string): number;
|
|
9
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { QaAccountProfileInput, QaAccountUserPublic, QaOwnershipEntry, ResolvedQaSurfaceConfig } from "../types.js";
|
|
2
|
+
import type { QaAccountsApi, StorageLike } from "./types.js";
|
|
3
|
+
export type QaAccountsSnapshot = {
|
|
4
|
+
readonly stage: "checking";
|
|
5
|
+
} | {
|
|
6
|
+
readonly stage: "gate";
|
|
7
|
+
readonly mode: "login" | "register";
|
|
8
|
+
readonly busy: boolean;
|
|
9
|
+
readonly error: string | null;
|
|
10
|
+
} | {
|
|
11
|
+
readonly stage: "authed";
|
|
12
|
+
readonly user: QaAccountUserPublic;
|
|
13
|
+
/**
|
|
14
|
+
* Server-known chat ids; the sidebar list authority. Own chats always,
|
|
15
|
+
* plus every mapped chat for an admin (the cross-user grouping view).
|
|
16
|
+
*/
|
|
17
|
+
readonly ownedIds: readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* The full ownership map; admins only, empty for ordinary accounts and
|
|
20
|
+
* whenever the admin listing was refused or unavailable.
|
|
21
|
+
*/
|
|
22
|
+
readonly ownership: readonly QaOwnershipEntry[];
|
|
23
|
+
/** Bumped whenever ownedIds or ownership changes; re-projects lists. */
|
|
24
|
+
readonly ownedRevision: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Audience-safe copy for the coarse account refusal codes; anything unknown
|
|
28
|
+
* falls back to the generic line.
|
|
29
|
+
*/
|
|
30
|
+
export declare function accountsErrorMessage(code: string | null): string;
|
|
31
|
+
/** Extract the coarse account reason code from a Host wire failure. */
|
|
32
|
+
export declare function accountsReasonOf(failure: unknown): string | null;
|
|
33
|
+
export interface QaAccountsControllerOptions {
|
|
34
|
+
readonly remote: QaAccountsApi;
|
|
35
|
+
readonly storage: StorageLike | undefined;
|
|
36
|
+
/** Config snapshot getter; the token key follows the deployment identity. */
|
|
37
|
+
readonly config: () => ResolvedQaSurfaceConfig;
|
|
38
|
+
/**
|
|
39
|
+
* The legacy per-browser chat index at login time, for the one-shot
|
|
40
|
+
* ownership migration; conflicts are dropped through {@link forgetChat}.
|
|
41
|
+
*/
|
|
42
|
+
readonly legacyChatIds?: () => readonly string[];
|
|
43
|
+
readonly forgetChat?: (sessionId: string) => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Browser-side account lifecycle: token persistence, the checking → gate →
|
|
47
|
+
* authed state machine, and the ownership bookkeeping the sidebar list is
|
|
48
|
+
* built from. Anonymous/failed identity never blocks a deployment with
|
|
49
|
+
* accounts disabled — the caller simply does not mount this controller.
|
|
50
|
+
*/
|
|
51
|
+
export declare class QaAccountsController {
|
|
52
|
+
private readonly options;
|
|
53
|
+
private readonly listeners;
|
|
54
|
+
private snapshot;
|
|
55
|
+
private tokenValue;
|
|
56
|
+
private disposed;
|
|
57
|
+
constructor(options: QaAccountsControllerOptions);
|
|
58
|
+
getSnapshot: () => QaAccountsSnapshot;
|
|
59
|
+
subscribe: (listener: () => void) => (() => void);
|
|
60
|
+
dispose(): void;
|
|
61
|
+
/** The bearer token threaded into gated remotes; null while anonymous. */
|
|
62
|
+
/** The bearer token threaded into gated remotes; null while anonymous. */
|
|
63
|
+
token(): string | null;
|
|
64
|
+
/** Server-owned chat ids (empty until authed); falls back to nothing. */
|
|
65
|
+
ownedIds(): readonly string[];
|
|
66
|
+
/** Boot probe: restore the stored token and ask the Host who it is. */
|
|
67
|
+
start(): Promise<void>;
|
|
68
|
+
login(email: string, password: string): Promise<void>;
|
|
69
|
+
register(email: string, password: string): Promise<void>;
|
|
70
|
+
setMode(mode: "login" | "register"): void;
|
|
71
|
+
/** Drop the token and return to the gate (logout or expired identity). */
|
|
72
|
+
signOut(): void;
|
|
73
|
+
/** Claim one freshly created chat so the ownership map stays current. */
|
|
74
|
+
claimNewSession(sessionId: string): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Replace the signed-in user's own profile. Resolves to audience-safe
|
|
77
|
+
* refusal copy when the Host rejected the write, and to null once the
|
|
78
|
+
* snapshot carries the stored profile — the form reports the outcome inline
|
|
79
|
+
* rather than through the gate's state machine.
|
|
80
|
+
*/
|
|
81
|
+
updateProfile(input: QaAccountProfileInput): Promise<string | null>;
|
|
82
|
+
private authenticate;
|
|
83
|
+
/** Own the account, migrate the legacy index, then project authed. */
|
|
84
|
+
private enterSession;
|
|
85
|
+
/** Refresh the owned list after index changes; cheap enough to re-pull. */
|
|
86
|
+
refreshOwned(): Promise<void>;
|
|
87
|
+
/** The admin cross-user ownership view; failures degrade to an empty map. */
|
|
88
|
+
private fetchOwnership;
|
|
89
|
+
/** Session id → owner display name; empty unless an admin is signed in. */
|
|
90
|
+
ownerNames(): ReadonlyMap<string, string>;
|
|
91
|
+
/**
|
|
92
|
+
* The chat owner's display name for author labels: admins see it on
|
|
93
|
+
* foreign chats only; the owner themself and ordinary accounts see none.
|
|
94
|
+
*/
|
|
95
|
+
messageAuthorOf(sessionId: string): string | undefined;
|
|
96
|
+
private readStoredToken;
|
|
97
|
+
private saveStoredToken;
|
|
98
|
+
private clearStoredToken;
|
|
99
|
+
private tokenKey;
|
|
100
|
+
private publish;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=QaAccountsController.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SettingsScope } from "@deepseek-ai/dsh-client-
|
|
1
|
+
import type { SettingsScope } from "@deepseek-ai/dsh-client-ui-settings/client";
|
|
2
2
|
import type { QaSurfaceConfig, ResolvedQaSurfaceConfig } from "../types.js";
|
|
3
3
|
export interface QaConfigSnapshot {
|
|
4
4
|
readonly status: "loading" | "ready" | "unavailable" | "error";
|
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type { QaSecureSession, QaSessions, QaSessionsApi, StorageLike } from "./types.js";
|
|
1
|
+
import type { ConnectionGenerationState } from "@deepseek-ai/dsh-client-connection/client";
|
|
2
|
+
import type { QaAttachmentDraft, QaSessionState, ResolvedQaSurfaceConfig } from "../types.js";
|
|
3
|
+
import type { QaConversation, QaCreateSession, QaFileUpload, QaSecureSession, QaSessions, QaSessionsApi, QaSourceApi, StorageLike } from "./types.js";
|
|
4
|
+
export interface QaAccountsFacade {
|
|
5
|
+
/** The account bearer token, or null while anonymous. */
|
|
6
|
+
readonly token: () => string | null;
|
|
7
|
+
/** Server-owned chat ids; the list authority while accounts are on. */
|
|
8
|
+
readonly ownedIds: () => readonly string[];
|
|
9
|
+
/**
|
|
10
|
+
* The chat owner's display name for author labels; admins see it on
|
|
11
|
+
* foreign chats only, everyone else gets undefined.
|
|
12
|
+
*/
|
|
13
|
+
readonly messageAuthorOf: (sessionId: string) => string | undefined;
|
|
14
|
+
/** Called after a new chat binds, so ownership stays current. */
|
|
15
|
+
readonly onSessionCreated: (sessionId: string) => void;
|
|
16
|
+
/** Called when the Host refuses with auth-required (expired/rotated). */
|
|
17
|
+
readonly onAuthRequired: () => void;
|
|
18
|
+
}
|
|
4
19
|
export interface QaSessionControllerOptions {
|
|
5
20
|
readonly sessions: QaSessions;
|
|
6
21
|
readonly api: QaSessionsApi;
|
|
7
|
-
readonly
|
|
22
|
+
readonly createSession: QaCreateSession;
|
|
23
|
+
/** Conversation assembly feeding the transcript projection. */
|
|
24
|
+
readonly conversation: QaConversation;
|
|
25
|
+
readonly connection: ConnectionGenerationState;
|
|
8
26
|
readonly config: ResolvedQaSurfaceConfig;
|
|
9
27
|
readonly secureSession: QaSecureSession;
|
|
28
|
+
readonly sourceApi?: QaSourceApi;
|
|
10
29
|
readonly storage?: StorageLike;
|
|
30
|
+
/**
|
|
31
|
+
* Browser file-upload service, resolved lazily: the page may not serve the
|
|
32
|
+
* upload plugin, and a deployment without it keeps images and text only.
|
|
33
|
+
*/
|
|
34
|
+
readonly fileUpload?: () => QaFileUpload | undefined;
|
|
35
|
+
/** Present while the deployment gates QA users with accounts. */
|
|
36
|
+
readonly accounts?: QaAccountsFacade;
|
|
11
37
|
readonly timeoutMs?: number;
|
|
12
38
|
/**
|
|
13
39
|
* Minimum spacing between projections of a running turn's stream frames.
|
|
@@ -25,16 +51,26 @@ export interface QaSessionControllerOptions {
|
|
|
25
51
|
export declare class QaSessionController {
|
|
26
52
|
private readonly listeners;
|
|
27
53
|
private readonly sessions;
|
|
28
|
-
private readonly
|
|
54
|
+
private readonly createSessionRemote;
|
|
55
|
+
private readonly conversation;
|
|
29
56
|
private readonly connection;
|
|
30
57
|
private readonly config;
|
|
31
58
|
private readonly secureSessionRemote;
|
|
59
|
+
private readonly sourceApi;
|
|
32
60
|
private readonly chats;
|
|
61
|
+
private readonly accounts;
|
|
62
|
+
/** Resolved per send: a page without the upload plugin has no receipts. */
|
|
63
|
+
private readonly fileUpload;
|
|
64
|
+
/** Per-chat attachment URL cache; blob URLs die with the chat binding. */
|
|
65
|
+
private readonly assets;
|
|
33
66
|
private readonly timeoutMs;
|
|
34
|
-
|
|
67
|
+
/** Spacing for a running turn's stream frames; the policy lives there. */
|
|
68
|
+
private readonly streamPublisher;
|
|
35
69
|
private state;
|
|
36
70
|
private session;
|
|
71
|
+
private conversationBinding;
|
|
37
72
|
private unsubscribeSession;
|
|
73
|
+
private unsubscribeChat;
|
|
38
74
|
private readonly unsubscribeConnection;
|
|
39
75
|
private ensuring;
|
|
40
76
|
private materializing;
|
|
@@ -42,7 +78,6 @@ export declare class QaSessionController {
|
|
|
42
78
|
private admissionPending;
|
|
43
79
|
private policyReady;
|
|
44
80
|
private drafting;
|
|
45
|
-
private streamFlushTimer;
|
|
46
81
|
/** The chat session to return to when a subagent view closes. */
|
|
47
82
|
private chatSessionId;
|
|
48
83
|
private viewingSubagent;
|
|
@@ -50,11 +85,13 @@ export declare class QaSessionController {
|
|
|
50
85
|
private disposed;
|
|
51
86
|
private generation;
|
|
52
87
|
private chatsRevision;
|
|
88
|
+
/** Host-side provenance of the bound chat, merged into the projection. */
|
|
89
|
+
private readonly hostSources;
|
|
53
90
|
constructor(options: QaSessionControllerOptions);
|
|
54
91
|
getSnapshot: () => QaSessionState;
|
|
55
92
|
subscribe: (listener: () => void) => (() => void);
|
|
56
93
|
ensureSession(): Promise<void>;
|
|
57
|
-
send(text: string,
|
|
94
|
+
send(text: string, attachments?: readonly QaAttachmentDraft[]): Promise<boolean>;
|
|
58
95
|
/**
|
|
59
96
|
* Ask for a fresh variant of the previous answer. The session has no
|
|
60
97
|
* truncation seam, so this sends the hidden regeneration instruction as an
|
|
@@ -93,15 +130,19 @@ export declare class QaSessionController {
|
|
|
93
130
|
viewSubagent(id: string, title: string): Promise<void>;
|
|
94
131
|
/** Leave the subagent transcript and re-open the chat it was launched from. */
|
|
95
132
|
closeSubagent(): Promise<void>;
|
|
96
|
-
/** This browser's
|
|
133
|
+
/** This browser's chat ids: the owned list when accounts are on, else the
|
|
134
|
+
* local index. Both intersect the host session list at projection time. */
|
|
97
135
|
chatIds(): readonly string[];
|
|
98
136
|
/** The bound session id, or null while no chat is bound. */
|
|
99
137
|
activeSessionId(): string | null;
|
|
100
138
|
/**
|
|
101
139
|
* Resolve one durable image attachment of the bound session into a
|
|
102
|
-
* browser-usable URL.
|
|
140
|
+
* browser-usable URL. Resolutions are cached per chat in the asset
|
|
141
|
+
* repository (attachment ids repeat across chats) and revoked when the chat
|
|
142
|
+
* is unbound; failures surface as broken views and retry on demand.
|
|
103
143
|
*/
|
|
104
144
|
readImage(attachmentId: string): Promise<string>;
|
|
145
|
+
private readAttachmentUrl;
|
|
105
146
|
/**
|
|
106
147
|
* Remove one chat from this browser's index. Deleting the chat that is
|
|
107
148
|
* currently open also forgets the persisted id and starts a fresh attested
|
|
@@ -120,26 +161,24 @@ export declare class QaSessionController {
|
|
|
120
161
|
* re-opening re-materializes it. Step 2 — when that refused session is
|
|
121
162
|
* still blank (it never received the prompt, so there is nothing to lose) —
|
|
122
163
|
* starts a fresh attested session instead. A session with history is left
|
|
123
|
-
* alone: recreating it would silently drop the conversation.
|
|
164
|
+
* alone: recreating it would silently drop the conversation. Returns the
|
|
165
|
+
* attested session id, or null when nothing was attested.
|
|
124
166
|
*/
|
|
125
167
|
private recoverForSend;
|
|
126
|
-
private createSession;
|
|
127
168
|
private bind;
|
|
128
169
|
private unbind;
|
|
129
170
|
private waitForConnection;
|
|
130
|
-
/**
|
|
131
|
-
*
|
|
132
|
-
* animation-frame cadence, so re-projections are spaced at least
|
|
133
|
-
* {@link streamIntervalMs} apart: the first frame of a window projects at
|
|
134
|
-
* once and further frames are absorbed (the memoized render path replays
|
|
135
|
-
* nothing, so absorbing a frame only defers it). Everything outside a
|
|
136
|
-
* running turn - phase flips, errors, turn completion - projects
|
|
137
|
-
* immediately.
|
|
138
|
-
*/
|
|
171
|
+
/** Project one session notification; the running-turn spacing policy
|
|
172
|
+
* (first frame at once, further frames absorbed) lives in the publisher. */
|
|
139
173
|
private publishSessionUpdate;
|
|
140
|
-
private clearStreamFlush;
|
|
141
174
|
private publish;
|
|
142
175
|
private fail;
|
|
176
|
+
/**
|
|
177
|
+
* Attest the currently bound session. `ok` carries the session id the proof
|
|
178
|
+
* was issued for; `stale` means the binding changed while the request was
|
|
179
|
+
* in flight, so nothing was written — the newer binding manages its own
|
|
180
|
+
* attestation; `refused` is a genuine admission refusal of this binding.
|
|
181
|
+
*/
|
|
143
182
|
private attestPolicy;
|
|
144
183
|
private emit;
|
|
145
184
|
}
|