@yadsh/dsh-qa-surface 0.17.0 → 0.19.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.
Files changed (213) hide show
  1. package/README.md +35 -25
  2. package/compatibility.json +1 -1
  3. package/lib/account-remotes.js +4 -0
  4. package/lib/account-remotes.js.map +1 -1
  5. package/lib/accounts/database.js +86 -1
  6. package/lib/accounts/database.js.map +1 -1
  7. package/lib/accounts/file.js.map +1 -1
  8. package/lib/accounts/store.js +111 -5
  9. package/lib/accounts/store.js.map +1 -1
  10. package/lib/accounts/token.js +8 -2
  11. package/lib/accounts/token.js.map +1 -1
  12. package/lib/admin/metrics.js +15 -2
  13. package/lib/admin/metrics.js.map +1 -1
  14. package/lib/admin/read-budget.js +28 -0
  15. package/lib/admin/read-budget.js.map +1 -0
  16. package/lib/admin/service.js +135 -40
  17. package/lib/admin/service.js.map +1 -1
  18. package/lib/admin/session-log.js +63 -4
  19. package/lib/admin/session-log.js.map +1 -1
  20. package/lib/attachment-access.js +147 -0
  21. package/lib/attachment-access.js.map +1 -0
  22. package/lib/chat-sharing/native-fence.js +20 -0
  23. package/lib/chat-sharing/native-fence.js.map +1 -1
  24. package/lib/chat-sharing/search.js +89 -0
  25. package/lib/chat-sharing/search.js.map +1 -0
  26. package/lib/chat-sharing/transport.js +10 -9
  27. package/lib/chat-sharing/transport.js.map +1 -1
  28. package/lib/chat-sharing/uploads.js +79 -6
  29. package/lib/chat-sharing/uploads.js.map +1 -1
  30. package/lib/cli.js +13 -0
  31. package/lib/cli.js.map +1 -1
  32. package/lib/client/QaAccountsController.js +61 -0
  33. package/lib/client/QaAccountsController.js.map +1 -1
  34. package/lib/client/QaRouteController.js +3 -1
  35. package/lib/client/QaRouteController.js.map +1 -1
  36. package/lib/client/QaSessionController.js +141 -35
  37. package/lib/client/QaSessionController.js.map +1 -1
  38. package/lib/client/QaSurface.js +43 -13
  39. package/lib/client/QaSurface.js.map +1 -1
  40. package/lib/client/account-sessions.js +74 -8
  41. package/lib/client/account-sessions.js.map +1 -1
  42. package/lib/client/admin/CapabilityPicker.js +50 -0
  43. package/lib/client/admin/CapabilityPicker.js.map +1 -0
  44. package/lib/client/admin/CoverageNotice.js +9 -0
  45. package/lib/client/admin/CoverageNotice.js.map +1 -0
  46. package/lib/client/admin/QaAdmin.js +3 -150
  47. package/lib/client/admin/QaAdmin.js.map +1 -1
  48. package/lib/client/admin/RoleEditor.js +46 -0
  49. package/lib/client/admin/RoleEditor.js.map +1 -0
  50. package/lib/client/admin/capability-selection.js +63 -0
  51. package/lib/client/admin/capability-selection.js.map +1 -0
  52. package/lib/client/admin/pages/Conversations.js +35 -17
  53. package/lib/client/admin/pages/Conversations.js.map +1 -1
  54. package/lib/client/admin/pages/Overview.js +3 -2
  55. package/lib/client/admin/pages/Overview.js.map +1 -1
  56. package/lib/client/admin/pages/Quality.js +77 -20
  57. package/lib/client/admin/pages/Quality.js.map +1 -1
  58. package/lib/client/admin/pages/SkillFiles.js +14 -3
  59. package/lib/client/admin/pages/SkillFiles.js.map +1 -1
  60. package/lib/client/admin/shared.js +68 -3
  61. package/lib/client/admin/shared.js.map +1 -1
  62. package/lib/client/components/QaAuthGate.js +31 -28
  63. package/lib/client/components/QaAuthGate.js.map +1 -1
  64. package/lib/client/components/QaChangelog.js +71 -0
  65. package/lib/client/components/QaChangelog.js.map +1 -1
  66. package/lib/client/components/QaComposer.js +27 -4
  67. package/lib/client/components/QaComposer.js.map +1 -1
  68. package/lib/client/components/QaFormItem.js +63 -0
  69. package/lib/client/components/QaFormItem.js.map +1 -0
  70. package/lib/client/components/QaInputForm.js +281 -0
  71. package/lib/client/components/QaInputForm.js.map +1 -0
  72. package/lib/client/components/QaModal.js +17 -4
  73. package/lib/client/components/QaModal.js.map +1 -1
  74. package/lib/client/components/QaRequestWait.js +15 -0
  75. package/lib/client/components/QaRequestWait.js.map +1 -0
  76. package/lib/client/forms-styles.js +14 -0
  77. package/lib/client/forms-styles.js.map +1 -0
  78. package/lib/client/forms.js +40 -0
  79. package/lib/client/forms.js.map +1 -0
  80. package/lib/client/index.js +18 -2
  81. package/lib/client/index.js.map +1 -1
  82. package/lib/client/oidc-browser.js +39 -0
  83. package/lib/client/oidc-browser.js.map +1 -0
  84. package/lib/client/panels/PanelHost.js +23 -1
  85. package/lib/client/panels/PanelHost.js.map +1 -1
  86. package/lib/client/project-session-state.js.map +1 -1
  87. package/lib/client/request-wait-styles.js +7 -0
  88. package/lib/client/request-wait-styles.js.map +1 -0
  89. package/lib/client/settings/sections/interface.js +2 -1
  90. package/lib/client/settings/sections/interface.js.map +1 -1
  91. package/lib/client/settings/sections/status.js +3 -1
  92. package/lib/client/settings/sections/status.js.map +1 -1
  93. package/lib/client/styles.js +5 -3
  94. package/lib/client/styles.js.map +1 -1
  95. package/lib/client/types.js.map +1 -1
  96. package/lib/client.js +471 -72918
  97. package/lib/client.js.map +1 -1
  98. package/lib/config-resolvers/accounts.js +5 -4
  99. package/lib/config-resolvers/accounts.js.map +1 -1
  100. package/lib/config-resolvers/defaults.js +16 -0
  101. package/lib/config-resolvers/defaults.js.map +1 -1
  102. package/lib/config-resolvers/oidc.js +53 -0
  103. package/lib/config-resolvers/oidc.js.map +1 -0
  104. package/lib/config.js +71 -0
  105. package/lib/config.js.map +1 -1
  106. package/lib/filesystem-intent.js +39 -0
  107. package/lib/filesystem-intent.js.map +1 -0
  108. package/lib/forms/attachments.js +230 -0
  109. package/lib/forms/attachments.js.map +1 -0
  110. package/lib/forms/errors.js +37 -0
  111. package/lib/forms/errors.js.map +1 -0
  112. package/lib/forms/fingerprint.js +21 -0
  113. package/lib/forms/fingerprint.js.map +1 -0
  114. package/lib/forms/gate.js +125 -0
  115. package/lib/forms/gate.js.map +1 -0
  116. package/lib/forms/schema.js +182 -0
  117. package/lib/forms/schema.js.map +1 -0
  118. package/lib/forms/service.js +220 -0
  119. package/lib/forms/service.js.map +1 -0
  120. package/lib/forms/store.js +194 -0
  121. package/lib/forms/store.js.map +1 -0
  122. package/lib/forms/types.js +2 -0
  123. package/lib/forms/types.js.map +1 -0
  124. package/lib/forms/validation.js +113 -0
  125. package/lib/forms/validation.js.map +1 -0
  126. package/lib/index.js +271 -81
  127. package/lib/index.js.map +1 -1
  128. package/lib/oidc/http.js +30 -0
  129. package/lib/oidc/http.js.map +1 -0
  130. package/lib/oidc/service.js +250 -0
  131. package/lib/oidc/service.js.map +1 -0
  132. package/lib/qa-tools/activation-manager.js +24 -2
  133. package/lib/qa-tools/activation-manager.js.map +1 -1
  134. package/lib/qa-tools/catalog.js +11 -1
  135. package/lib/qa-tools/catalog.js.map +1 -1
  136. package/lib/qa-tools/index.js +27 -0
  137. package/lib/qa-tools/index.js.map +1 -1
  138. package/lib/qa-tools/request-user-form.js +121 -0
  139. package/lib/qa-tools/request-user-form.js.map +1 -0
  140. package/lib/request-scheduler.js +235 -0
  141. package/lib/request-scheduler.js.map +1 -0
  142. package/lib/resolve-config.js +2 -0
  143. package/lib/resolve-config.js.map +1 -1
  144. package/lib/secure-session.js +60 -60
  145. package/lib/secure-session.js.map +1 -1
  146. package/lib/session-create.js +125 -0
  147. package/lib/session-create.js.map +1 -0
  148. package/lib/typert.host.js +4636 -1103
  149. package/lib/typert.remote-client.d.ts +135 -5
  150. package/lib/typert.remote-client.js +4502 -1095
  151. package/lib/types/accounts/database.d.ts +8 -0
  152. package/lib/types/accounts/file.d.ts +2 -0
  153. package/lib/types/accounts/store.d.ts +17 -0
  154. package/lib/types/accounts/token.d.ts +3 -1
  155. package/lib/types/admin/metrics.d.ts +5 -1
  156. package/lib/types/admin/read-budget.d.ts +8 -0
  157. package/lib/types/admin/service.d.ts +17 -0
  158. package/lib/types/admin/session-log.d.ts +30 -1
  159. package/lib/types/attachment-access.d.ts +29 -0
  160. package/lib/types/chat-sharing/search.d.ts +5 -0
  161. package/lib/types/chat-sharing/uploads.d.ts +2 -1
  162. package/lib/types/client/QaAccountsController.d.ts +4 -0
  163. package/lib/types/client/QaRouteController.d.ts +1 -0
  164. package/lib/types/client/QaSessionController.d.ts +24 -12
  165. package/lib/types/client/QaSurface.d.ts +2 -0
  166. package/lib/types/client/admin/CapabilityPicker.d.ts +14 -0
  167. package/lib/types/client/admin/CoverageNotice.d.ts +6 -0
  168. package/lib/types/client/admin/RoleEditor.d.ts +15 -0
  169. package/lib/types/client/admin/capability-selection.d.ts +27 -0
  170. package/lib/types/client/admin/shared.d.ts +39 -1
  171. package/lib/types/client/components/QaAuthGate.d.ts +2 -0
  172. package/lib/types/client/components/QaFormItem.d.ts +20 -0
  173. package/lib/types/client/components/QaInputForm.d.ts +18 -0
  174. package/lib/types/client/components/QaRequestWait.d.ts +6 -0
  175. package/lib/types/client/forms-styles.d.ts +2 -0
  176. package/lib/types/client/forms.d.ts +23 -0
  177. package/lib/types/client/oidc-browser.d.ts +12 -0
  178. package/lib/types/client/project-session-state.d.ts +2 -4
  179. package/lib/types/client/request-wait-styles.d.ts +2 -0
  180. package/lib/types/client/types.d.ts +10 -4
  181. package/lib/types/config-resolvers/oidc.d.ts +3 -0
  182. package/lib/types/filesystem-intent.d.ts +12 -0
  183. package/lib/types/forms/attachments.d.ts +51 -0
  184. package/lib/types/forms/errors.d.ts +11 -0
  185. package/lib/types/forms/fingerprint.d.ts +9 -0
  186. package/lib/types/forms/gate.d.ts +33 -0
  187. package/lib/types/forms/schema.d.ts +72 -0
  188. package/lib/types/forms/service.d.ts +15 -0
  189. package/lib/types/forms/store.d.ts +25 -0
  190. package/lib/types/forms/types.d.ts +215 -0
  191. package/lib/types/forms/validation.d.ts +20 -0
  192. package/lib/types/index.d.ts +33 -12
  193. package/lib/types/oidc/http.d.ts +5 -0
  194. package/lib/types/oidc/service.d.ts +30 -0
  195. package/lib/types/oidc.js +2 -0
  196. package/lib/types/oidc.js.map +1 -0
  197. package/lib/types/qa-tools/activation-manager.d.ts +5 -0
  198. package/lib/types/qa-tools/catalog.d.ts +4 -1
  199. package/lib/types/qa-tools/index.d.ts +5 -1
  200. package/lib/types/qa-tools/request-user-form.d.ts +5 -0
  201. package/lib/types/request-scheduler.d.ts +28 -0
  202. package/lib/types/secure-session.d.ts +13 -26
  203. package/lib/types/session-create.d.ts +29 -0
  204. package/lib/types/types/accounts.d.ts +2 -0
  205. package/lib/types/types/admin.d.ts +6 -0
  206. package/lib/types/types/config.d.ts +6 -0
  207. package/lib/types/types/oidc.d.ts +36 -0
  208. package/lib/types/types/session.d.ts +8 -0
  209. package/lib/types/types.d.ts +2 -0
  210. package/lib/types/user-workspace.d.ts +4 -6
  211. package/lib/user-workspace.js +13 -67
  212. package/lib/user-workspace.js.map +1 -1
  213. package/package.json +66 -62
@@ -74,6 +74,14 @@ export declare class QaAccountsDatabase {
74
74
  insertUser(user: StoredUser): void;
75
75
  /** Replace one account's row in place. */
76
76
  updateUser(user: StoredUser): void;
77
+ oidcUserId(issuer: string, subject: string): string | undefined;
78
+ isOidcUser(userId: string): boolean;
79
+ /** Account creation and identity attachment must commit together. */
80
+ attachOidcIdentity(issuer: string, subject: string, user: StoredUser, create: boolean): void;
81
+ /** Re-read and update authentication facts under the same write transaction. */
82
+ authenticateOidc(userId: string, email: string, displayName: string, role: StoredUser["role"], sid: string, expiresAt: number): StoredUser | undefined;
83
+ oidcSessionActive(id: string, userId: string): boolean;
84
+ revokeOidcSession(id: string): void;
77
85
  /**
78
86
  * Record one forgotten-password request. A repeat from the same account
79
87
  * moves the row up the queue and counts up, so the console shows "asked
@@ -25,6 +25,8 @@ export interface StoredNotifications {
25
25
  desktop?: boolean;
26
26
  }
27
27
  export interface StoredUser {
28
+ /** Derived from the identity table when the database is loaded. */
29
+ readonly authMethod?: "oidc";
28
30
  readonly id: string;
29
31
  readonly email: string;
30
32
  readonly displayName: string;
@@ -6,6 +6,8 @@ export type { QaAccountsErrorReason } from "./errors.js";
6
6
  export { defaultAccountsFilePath } from "./file.js";
7
7
  export type { QaIssuedServiceToken, QaServiceTokenSummary } from "../types.js";
8
8
  export interface QaAccountsOptions {
9
+ readonly oidcEnabled?: boolean;
10
+ readonly localLogin?: boolean;
9
11
  readonly sessionTtlDays: number;
10
12
  readonly allowRegistration: boolean;
11
13
  /** Login/registration attempts accepted per rolling minute, store-wide. */
@@ -85,6 +87,8 @@ export declare class QaAccounts {
85
87
  private readonly maxAuthAttemptsPerMinute;
86
88
  private readonly sessionTtlDays;
87
89
  private readonly allowRegistration;
90
+ private readonly oidcEnabled;
91
+ private readonly localLogin;
88
92
  /** Character cap on a stored profile's agent guidance. */
89
93
  private readonly instructionsMaxLength;
90
94
  /** Whether a deployment declares which identity handles an account may hold. */
@@ -126,6 +130,19 @@ export declare class QaAccounts {
126
130
  /** Resolve a token to its user, or null for absent/invalid/expired ones. */
127
131
  verifyToken(token: string): string | null;
128
132
  private mintToken;
133
+ /** Only the server OIDC verifier calls this with authenticated claims. */
134
+ loginOidc(identity: {
135
+ issuer: string;
136
+ subject: string;
137
+ email: string;
138
+ displayName: string;
139
+ role: QaAccountRole;
140
+ expiresAt: number;
141
+ autoProvision: boolean;
142
+ }): QaAccountSession;
143
+ /** Operator-confirmed attachment preserves ownership and revokes old credentials. */
144
+ linkOidcIdentity(email: string, issuer: string, subject: string): QaAccountUserPublic;
145
+ logoutOidc(token: string): boolean;
129
146
  /**
130
147
  * The account behind a token, or an auth-required refusal.
131
148
  *
@@ -5,6 +5,8 @@ interface TokenUser {
5
5
  }
6
6
  /** The claims carried by a v1 account token payload. */
7
7
  export interface TokenPayload {
8
+ /** OIDC-backed QA session; checked against the account database on every use. */
9
+ readonly sid?: string;
8
10
  readonly uid: string;
9
11
  /** Expiry, epoch milliseconds. */
10
12
  readonly exp: number;
@@ -26,6 +28,6 @@ export declare function mintToken(secret: string, payload: TokenPayload): string
26
28
  * timingSafeEqual) so a signature guess cannot be accelerated by measuring
27
29
  * HMAC rejection time.
28
30
  */
29
- export declare function verifyToken(secret: string, token: string, users: readonly TokenUser[]): string | null;
31
+ export declare function verifyToken(secret: string, token: string, users: readonly TokenUser[], sessionActive?: (id: string, userId: string) => boolean): string | null;
30
32
  export {};
31
33
  //# sourceMappingURL=token.d.ts.map
@@ -13,6 +13,8 @@ export interface QaConversationFact {
13
13
  readonly userId: string;
14
14
  readonly subroleId: string;
15
15
  readonly assistantMessages: number;
16
+ readonly readable?: boolean;
17
+ readonly assistantMessageIds?: readonly string[];
16
18
  /** Epoch ms of the conversation's creation, for the activity window. */
17
19
  readonly createdAt: number;
18
20
  }
@@ -22,8 +24,10 @@ export interface QaAggregationInput {
22
24
  readonly reviews: readonly QaConversationReview[];
23
25
  /** Days of feedback history the trend shows; older buckets are dropped. */
24
26
  readonly trendDays?: number;
27
+ /** False when the request could not read every conversation in its population. */
28
+ readonly complete?: boolean;
25
29
  }
26
- export declare function aggregateQuality({ conversations, feedback, reviews, trendDays, }: QaAggregationInput): QaQualityMetrics;
30
+ export declare function aggregateQuality({ conversations, feedback, reviews, trendDays, complete, }: QaAggregationInput): QaQualityMetrics;
27
31
  /** One rating's contribution to a conversation row, without re-reading logs. */
28
32
  export declare function countRatings(feedback: readonly QaMessageFeedback[]): Readonly<Record<QaFeedbackRating, number>>;
29
33
  //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1,8 @@
1
+ /** One deadline shared by every storage phase of an administrative request. */
2
+ export interface QaReadBudget {
3
+ remaining(): number;
4
+ read<T>(work: () => Promise<T>, fallback: T): Promise<T>;
5
+ }
6
+ export declare const QA_ADMIN_REQUEST_BUDGET_MS = 15000;
7
+ export declare function readBudget(now: () => number, ms?: number): QaReadBudget;
8
+ //# sourceMappingURL=read-budget.d.ts.map
@@ -24,6 +24,18 @@ export declare const QA_ADMIN_PAGE_MAX = 100;
24
24
  * says so; moving these counters onto a real index is the next iteration.
25
25
  */
26
26
  export declare const QA_ADMIN_SCAN_LIMIT = 200;
27
+ /**
28
+ * How long one page may spend reading conversation logs before it answers with
29
+ * what it already has. The newest logs are read until this budget is spent; the
30
+ * rest of the rows are marked unread instead of the page waiting for a store
31
+ * that may never answer. Without this,
32
+ * one conversation whose log cannot be read — a blank chat its process holds
33
+ * open is the usual case on a stand — parked the page for as long as the
34
+ * deployment runs.
35
+ */
36
+ export declare const QA_ADMIN_PAGE_BUDGET_MS = 10000;
37
+ /** The same budget for the aggregate window the overview and metrics read. */
38
+ export declare const QA_ADMIN_SCAN_BUDGET_MS = 10000;
27
39
  interface QaServiceClock {
28
40
  now(): number;
29
41
  }
@@ -101,6 +113,7 @@ export declare class QaAdminService {
101
113
  * reads the log — and what the aggregate pages show instead is the newest
102
114
  * projection of every finished conversation, which is the cheaper lie.
103
115
  */
116
+ private now;
104
117
  private transcript;
105
118
  /** Insert or re-touch one projection, keeping the cache inside its budget. */
106
119
  private retain;
@@ -121,6 +134,10 @@ export declare class QaAdminService {
121
134
  * up between two reads once every caller has left, so a reviewer who abandons a
122
135
  * page that has not answered does not keep the deployment reading logs for an
123
136
  * answer nobody will see.
137
+ *
138
+ * `within` is the pass's read budget. A log the budget no longer covers is not
139
+ * opened: the conversation keeps its row and is marked unread. Metrics then
140
+ * disclose the incomplete population instead of treating it as zero answers.
124
141
  */
125
142
  private walk;
126
143
  overview(token: string, signal?: AbortSignal): Promise<QaAdminOverview>;
@@ -36,7 +36,27 @@ export type QaSessionReadResult = {
36
36
  } | {
37
37
  readonly ok: false;
38
38
  readonly reason: QaTranscriptUnavailableReason;
39
+ /**
40
+ * True when the answer is "storage did not answer in time" rather than a
41
+ * verdict about the log. A caller that scans many logs skips such a
42
+ * conversation and keeps the rest of its rows; the wire reason stays one
43
+ * of the shared three, so no page learns a new word.
44
+ */
45
+ readonly timedOut?: boolean;
39
46
  };
47
+ /**
48
+ * How long one stored log may take before the console stops waiting for it.
49
+ *
50
+ * The durable backend answers a read by listing every session the deployment
51
+ * keeps and replaying the log; a log whose owning process is mid-flush — a
52
+ * blank chat created and left open is the usual case on a stand — can hold that
53
+ * answer indefinitely. The console is a reading surface, so a conversation it
54
+ * cannot read in this budget is reported and skipped rather than allowed to
55
+ * park the whole page.
56
+ */
57
+ export declare const QA_SESSION_READ_TIMEOUT_MS = 5000;
58
+ /** The same budget for the one listing every administrative page needs. */
59
+ export declare const QA_SESSION_LIST_TIMEOUT_MS = 8000;
40
60
  /**
41
61
  * One listing of the deployment's sessions together with what the answer
42
62
  * covers. The distinction is load-bearing: on a deployment that serves no
@@ -111,8 +131,17 @@ export interface QaStoredSessionEraser {
111
131
  * Build the reader for one plugin instance. The services are looked up per
112
132
  * call rather than captured: a cordis provider is only visible once its fiber
113
133
  * is active, and a reference taken at construction time would stay dead.
134
+ *
135
+ * Every call that reaches storage is bounded. The bounded answer is a shape the
136
+ * callers already understand — a listing that answers only for the live store,
137
+ * a log that is "storage-unavailable" — so a store that never replies costs a
138
+ * page its detail instead of its whole payload. The budgets are options only so
139
+ * a test can watch the transition without waiting five seconds for it.
114
140
  */
115
- export declare function createSessionLogReader(ctx: Context): QaSessionLogReader;
141
+ export declare function createSessionLogReader(ctx: Context, options?: {
142
+ readonly readTimeoutMs?: number;
143
+ readonly listTimeoutMs?: number;
144
+ }): QaSessionLogReader;
116
145
  /** A reader over an explicit set of logs; the tests' seam, and the empty default. */
117
146
  export declare function staticSessionLogReader(input: {
118
147
  readonly sessions?: readonly QaStoredSessionHeader[];
@@ -0,0 +1,29 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ interface SessionSource {
3
+ readonly id: unknown;
4
+ snapshotEvents?(): readonly unknown[];
5
+ }
6
+ export interface QaAttachmentRecovery {
7
+ readonly readEvents?: (sessionId: string) => Promise<readonly unknown[]>;
8
+ readonly restoreFiles?: (sessionId: string) => Promise<void>;
9
+ }
10
+ /** Exact attachment capabilities, owned by one admitted conversation. */
11
+ export declare class QaAttachmentAccess {
12
+ private readonly ctx;
13
+ private readonly recovery;
14
+ private readonly bindings;
15
+ constructor(ctx: Context, recovery?: QaAttachmentRecovery);
16
+ root(): string | undefined;
17
+ admit(session: SessionSource): Promise<void>;
18
+ inherit(session: SessionSource, parentId: string): void;
19
+ /** Only Host-admitted file blocks are authority; text and tool output are not. */
20
+ observe(sessionId: string, events: readonly unknown[]): void;
21
+ /** Called only after a durable form's bytes and session ownership are verified. */
22
+ grantFile(sessionId: string, file: string): void;
23
+ files(sessionId: string): readonly string[];
24
+ private publish;
25
+ revoke(sessionId: string): void;
26
+ dispose(): void;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=attachment-access.d.ts.map
@@ -0,0 +1,5 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { SessionSearchValue } from "@deepseek-ai/dsh-api-session-controller/types";
3
+ /** Apply account scope before the provider's ranking/limit, then recheck each read. */
4
+ export declare function searchQaChats(ctx: Context, query: string, visible: () => Promise<ReadonlySet<string>>, signal: AbortSignal): Promise<SessionSearchValue>;
5
+ //# sourceMappingURL=search.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import type { Context } from "@deepseek-ai/cordis";
2
2
  import type { QaChatSharingStore } from "./store.js";
3
+ import type { QaFormAttachmentAdapter } from "../forms/attachments.js";
3
4
  /** Authenticate before transferring the body, and fence every uploaded chunk. */
4
- export declare function installQaChatUploads(ctx: Context, store: () => QaChatSharingStore, admit: (token: string, id: string) => Promise<unknown>): () => Promise<void>;
5
+ export declare function installQaChatUploads(ctx: Context, store: () => QaChatSharingStore, admit: (token: string, id: string) => Promise<unknown>, forms?: QaFormAttachmentAdapter): () => Promise<void>;
5
6
  //# sourceMappingURL=uploads.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import type { QaAccountNotificationsInput, QaAccountProfileInput, QaAccountStartersInput, QaAccountUserPublic, QaIssuedServiceToken, QaOwnershipEntry, QaServiceTokenCreateInput, QaServiceTokenSummary, ResolvedQaSurfaceConfig } from "../types.js";
2
+ import type { QaOidcBrowser } from "./oidc-browser.js";
2
3
  import type { QaAccountsApi, QaIntegrationTokenResult, StorageLike } from "./types.js";
3
4
  /**
4
5
  * What the sign-in card says after a forgotten-password request. It names the
@@ -49,6 +50,7 @@ export declare function accountsErrorMessage(code: string | null): string;
49
50
  /** Extract the coarse account reason code from a Host wire failure. */
50
51
  export declare function accountsReasonOf(failure: unknown): string | null;
51
52
  export interface QaAccountsControllerOptions {
53
+ readonly oidcBrowser?: QaOidcBrowser;
52
54
  readonly remote: QaAccountsApi;
53
55
  readonly storage: StorageLike | undefined;
54
56
  /** Config snapshot getter; the token key follows the deployment identity. */
@@ -79,6 +81,7 @@ export interface QaAccountsControllerOptions {
79
81
  */
80
82
  export declare class QaAccountsController {
81
83
  private readonly options;
84
+ private logoutGeneration;
82
85
  private readonly listeners;
83
86
  private snapshot;
84
87
  private tokenValue;
@@ -101,6 +104,7 @@ export declare class QaAccountsController {
101
104
  /** Boot probe: restore the stored token and ask the Host who it is. */
102
105
  start(): Promise<void>;
103
106
  login(email: string, password: string): Promise<void>;
107
+ loginOidc(): Promise<void>;
104
108
  register(email: string, password: string): Promise<void>;
105
109
  setMode(mode: "login" | "register" | "reset"): void;
106
110
  /**
@@ -11,6 +11,7 @@ interface NavigationWindow {
11
11
  readonly location: {
12
12
  readonly pathname: string;
13
13
  readonly search?: string;
14
+ readonly hash?: string;
14
15
  };
15
16
  readonly history: NavigationHistory;
16
17
  addEventListener(type: "popstate", listener: () => void): void;
@@ -54,13 +54,13 @@ export interface QaSessionControllerOptions {
54
54
  */
55
55
  readonly slashApi?: QaSlashApi;
56
56
  /**
57
- * The Host's live read of the request ceiling. Absent on a Host build that
58
- * predates it — and unanswered, or answered by a deployment that sets no
59
- * ceiling — the surface sends the way it always did: the ceiling is an
60
- * arrangement between browsers about how much this stand can take, never a
61
- * reason a question cannot be asked.
57
+ * Global admission snapshot. Managed queues accept sends even while full;
58
+ * legacy Hosts retain the courtesy refusal. A failed read still submits the
59
+ * prompt through the server's own admission boundary.
62
60
  */
63
61
  readonly queueStatus?: QaQueueStatusRemote;
62
+ /** Authorized per-chat queue status, polled while the Host driver is live. */
63
+ readonly requestStatus?: QaQueueStatusRemote;
64
64
  readonly storage?: StorageLike;
65
65
  /**
66
66
  * Browser file-upload service, resolved lazily: the page may not serve the
@@ -120,7 +120,10 @@ export declare class QaSessionController {
120
120
  private readonly unsubscribeConnection;
121
121
  private ensuring;
122
122
  private materializing;
123
+ /** A successful create survives a failed adoption; retry must not create again. */
124
+ private draftSessionId;
123
125
  private operationError;
126
+ private operationDiagnostic;
124
127
  private admissionPending;
125
128
  private pendingSubmission;
126
129
  private pendingSequence;
@@ -161,9 +164,9 @@ export declare class QaSessionController {
161
164
  * both a failed adoption and {@link unbind} take it back. The converse does
162
165
  * not hold: a held session may name nothing, which is the transcript of an
163
166
  * attestation this chat could not pass and whose caller still reads it. So a
164
- * chat whose first send fell short keeps its identity while naming no session,
165
- * and the retry — which brings a fresh id — stays in the composer the question
166
- * was typed into instead of reading as a move to another chat.
167
+ * chat whose first send fell short keeps its identity while naming no session;
168
+ * a retry adopts the successful create it already holds and preserves the
169
+ * composer the question was typed into.
167
170
  */
168
171
  private namedSession;
169
172
  /**
@@ -184,6 +187,10 @@ export declare class QaSessionController {
184
187
  /** Host-side question requests of the bound chat waiting for the operator. */
185
188
  private readonly hostQuestions;
186
189
  private readonly queueRemote;
190
+ private readonly requestRemote;
191
+ private requestWaitStatus;
192
+ private requestReadRevision;
193
+ private requestReading;
187
194
  /** Last send the stand had no room for; drives the request-ceiling dialog. */
188
195
  private requestQueueNotice;
189
196
  /** Set while a running turn is polled for parked requests. */
@@ -212,6 +219,12 @@ export declare class QaSessionController {
212
219
  getSnapshot: () => QaSessionState;
213
220
  subscribe: (listener: () => void) => (() => void);
214
221
  ensureSession(): Promise<void>;
222
+ /** Retry opening a failed draft without abandoning its successful create. */
223
+ retrySession(): Promise<void>;
224
+ failureDiagnostic(): {
225
+ readonly reason: string;
226
+ readonly id: string;
227
+ } | null;
215
228
  /**
216
229
  * Select a different capability profile for the next agent. The current
217
230
  * agent is never mutated: even a blank materialized chat is abandoned in
@@ -235,12 +248,11 @@ export declare class QaSessionController {
235
248
  /**
236
249
  * What the stand answers about its load, or null when it does not answer.
237
250
  *
238
- * Every failure here sends the question anyway. The ceiling exists to keep a
239
- * weak model from drowning, not to be a door a browser cannot open: an
240
- * unreadable count says nothing about the load, and refusing a visitor on
241
- * that would be a worse answer than the one they would have got.
251
+ * A failed status read does not bypass the server queue. Submit normally;
252
+ * the Host owns admission even when the browser cannot read its load.
242
253
  */
243
254
  private readQueueStatus;
255
+ private refreshRequestStatus;
244
256
  /**
245
257
  * Close the request-ceiling dialog. Nothing is retried and nothing is
246
258
  * dropped: the held-back question is still the composer's own text, so asking
@@ -4,6 +4,7 @@ import type { QaConfigController } from "./QaConfigController.js";
4
4
  import type { QaRouteController } from "./QaRouteController.js";
5
5
  import type { QaAccountsController } from "./QaAccountsController.js";
6
6
  import type { QaApprovalApi, QaAccessApi, QaAdminApi, QaConversation, QaCreateSession, QaForkSession, QaFileUpload, QaQueueStatusRemote, QaSecureSession, QaSessions, QaSessionsApi, QaQuestionApi, QaSkillApi, QaSlashApi, QaSourceApi } from "./types.js";
7
+ import type { QaFormApi } from "./forms.js";
7
8
  import type { QaSurfacePanelRegistry } from "./panels/registry.js";
8
9
  import type { QaUserSettingsSections } from "./settings-extensions/index.js";
9
10
  import type { QaAuditController } from "./audit/controller.js";
@@ -40,6 +41,7 @@ export interface QaSurfaceFace {
40
41
  readonly approvalApi?: QaApprovalApi;
41
42
  /** Question half of the plugin's namespace, when the Host answers it. */
42
43
  readonly questionApi?: QaQuestionApi;
44
+ readonly formApi?: QaFormApi;
43
45
  /**
44
46
  * Slash half of the plugin's namespace. Absent on a Host build that predates
45
47
  * it: the composer then never opens a palette and ordinary prompts are
@@ -0,0 +1,14 @@
1
+ import type { QaCapabilityDescriptor, QaSkillAccess } from "../../types.js";
2
+ import type { CapabilityType } from "./capability-selection.js";
3
+ export declare function CapabilityPicker(props: {
4
+ readonly type: CapabilityType;
5
+ /** The zone this picker is mounted in, so its rows stay addressable. */
6
+ readonly testId?: string;
7
+ readonly catalog: readonly QaCapabilityDescriptor[];
8
+ readonly selected: readonly string[];
9
+ readonly inherited?: readonly string[];
10
+ readonly system?: readonly string[];
11
+ readonly skillDetails?: readonly QaSkillAccess[];
12
+ readonly onChange?: (next: readonly string[]) => void;
13
+ }): import("react/jsx-runtime").JSX.Element;
14
+ //# sourceMappingURL=CapabilityPicker.d.ts.map
@@ -0,0 +1,6 @@
1
+ import type { QaQualityMetrics } from "../../types.js";
2
+ /** A missing journal cannot be presented as a conversation with no answers. */
3
+ export declare function CoverageNotice({ metrics, }: {
4
+ readonly metrics: QaQualityMetrics;
5
+ }): import("react/jsx-runtime").JSX.Element | null;
6
+ //# sourceMappingURL=CoverageNotice.d.ts.map
@@ -0,0 +1,15 @@
1
+ import type { QaCapabilityDescriptor, QaCapabilitySelection, QaSkillAccess, QaSubrole } from "../../types.js";
2
+ import type { QaAccessApi } from "../types.js";
3
+ export declare function RoleEditor(props: {
4
+ readonly role: QaSubrole | null;
5
+ readonly api: QaAccessApi;
6
+ readonly token: string;
7
+ readonly catalog: readonly QaCapabilityDescriptor[];
8
+ readonly common: QaCapabilitySelection;
9
+ readonly system: QaCapabilitySelection;
10
+ readonly skills: readonly QaSkillAccess[];
11
+ readonly subroles: readonly QaSubrole[];
12
+ readonly onCancel: () => void;
13
+ readonly onSave: (role: QaSubrole) => Promise<void>;
14
+ }): import("react/jsx-runtime").JSX.Element;
15
+ //# sourceMappingURL=RoleEditor.d.ts.map
@@ -0,0 +1,27 @@
1
+ import type { QaCapabilitySelection, QaSkillAccess, QaSubrole } from "../../types.js";
2
+ export type CapabilityType = "tool" | "skill";
3
+ /**
4
+ * The three tool classes: visible immediately, reachable through a loaded
5
+ * skill, or withdrawn from the profile whatever grants them.
6
+ */
7
+ export type ToolBucket = "always" | "skillGrantable" | "deny";
8
+ export declare const TOOL_BUCKET_LABELS: Record<ToolBucket, string>;
9
+ export declare function unique(values: readonly string[]): string[];
10
+ export declare function bucketOf(selection: QaCapabilitySelection, bucket: ToolBucket): readonly string[];
11
+ export declare function emptySelection(): QaCapabilitySelection;
12
+ export declare function emptyRole(): QaSubrole;
13
+ /** Tools and skills one role would receive, and where each one comes from. */
14
+ export declare function roleEffective(props: {
15
+ readonly system: QaCapabilitySelection;
16
+ readonly common: QaCapabilitySelection;
17
+ readonly role: QaCapabilitySelection;
18
+ readonly skills: readonly QaSkillAccess[];
19
+ }, roleId: string): {
20
+ alwaysTools: string[];
21
+ grantable: string[];
22
+ denied: string[];
23
+ via: Map<string, string[]>;
24
+ managed: string[];
25
+ declared: string[];
26
+ };
27
+ //# sourceMappingURL=capability-selection.d.ts.map
@@ -19,6 +19,37 @@ export declare function useRequestSlot(): {
19
19
  readonly start: () => AbortController;
20
20
  readonly cancel: () => void;
21
21
  };
22
+ /**
23
+ * How long a page waits for one Host answer before it stops waiting.
24
+ *
25
+ * The aggregate pages read conversation logs on the Host, and a log the store
26
+ * cannot answer for used to leave the request pending forever: the page then sat
27
+ * on «Загружаю…» with nothing to click. The Host bounds its own reads well
28
+ * inside this budget, so hitting it means the answer is lost, not that the
29
+ * deployment is merely slow.
30
+ */
31
+ export declare const ADMIN_REQUEST_TIMEOUT_MS = 20000;
32
+ /** The copy a page shows once its deadline has passed. */
33
+ export declare function adminTimeoutMessage(timeoutMs?: number): string;
34
+ /** What one Host call did inside its deadline. */
35
+ export type BoundedOutcome<T> = {
36
+ readonly status: "ok";
37
+ readonly value: T;
38
+ } | {
39
+ readonly status: "timeout";
40
+ } | {
41
+ readonly status: "aborted";
42
+ };
43
+ /**
44
+ * Run one Host call under a deadline.
45
+ *
46
+ * A promise that never settles is the shape of the hang this exists for, so the
47
+ * deadline is a race rather than an abort alone: aborting the request is what
48
+ * asks the Host to stop working, and the timer is what lets the page go on
49
+ * without an answer. The abandoned call keeps running on its own; its eventual
50
+ * rejection is observed here so it never surfaces as an unhandled one.
51
+ */
52
+ export declare function callWithDeadline<T>(call: (signal: AbortSignal) => Promise<T>, outer: AbortSignal, timeoutMs?: number): Promise<BoundedOutcome<T>>;
22
53
  /**
23
54
  * Load one administrative resource, keeping the previous value visible while
24
55
  * it refreshes. Reviewers page through lists while new conversations arrive;
@@ -26,8 +57,15 @@ export declare function useRequestSlot(): {
26
57
  *
27
58
  * `load` receives the cancellation of the call it is making: pass it on to the
28
59
  * Remote, and a page the reviewer left stops being read on the server.
60
+ *
61
+ * The call is bounded by {@link ADMIN_REQUEST_TIMEOUT_MS}: a Host that does not
62
+ * answer leaves a stated error and a retry instead of an endless «Загружаю…».
63
+ * Whatever this page already held stays on screen — a partial answer is what a
64
+ * reviewer can still work with.
29
65
  */
30
- export declare function useAdminResource<T>(load: (signal: AbortSignal) => Promise<RemoteResult<T>>, deps: readonly unknown[]): {
66
+ export declare function useAdminResource<T>(load: (signal: AbortSignal) => Promise<RemoteResult<T>>, deps: readonly unknown[], options?: {
67
+ readonly timeoutMs?: number;
68
+ }): {
31
69
  readonly data: T | undefined;
32
70
  readonly error: string | undefined;
33
71
  readonly loading: boolean;
@@ -5,6 +5,8 @@ export interface QaAuthGateProps {
5
5
  readonly title: string;
6
6
  readonly logoUrl: string | null;
7
7
  readonly allowRegistration: boolean;
8
+ readonly localLogin?: boolean;
9
+ readonly oidcLabel?: string | null;
8
10
  }
9
11
  /**
10
12
  * The full-frame login/registration card shown instead of the chat while the
@@ -0,0 +1,20 @@
1
+ import type { QaFormAnswer, QaFormItem as Item, QaFormAttachment, QaFormUpload } from "../../forms/types.js";
2
+ interface Props {
3
+ item: Item;
4
+ answer: QaFormAnswer | null;
5
+ files: QaFormAttachment[];
6
+ uploads: QaFormUpload[];
7
+ disabled: boolean;
8
+ onAnswer(answer: QaFormAnswer | null): void;
9
+ onUpload(file: File, target?: {
10
+ attachment_id: string;
11
+ version: number;
12
+ }): void;
13
+ onRemove(file: QaFormAttachment): void;
14
+ onCancel(upload: QaFormUpload): void;
15
+ onOpen(file: QaFormAttachment): void;
16
+ }
17
+ /** Input requirements are separate from file requirements, including in the labels. */
18
+ export declare function QaFormItem(props: Props): import("react/jsx-runtime").JSX.Element;
19
+ export {};
20
+ //# sourceMappingURL=QaFormItem.d.ts.map
@@ -0,0 +1,18 @@
1
+ import type { QaFormView } from "../../forms/types.js";
2
+ import { type QaFormApi } from "../forms.js";
3
+ interface Props {
4
+ policy?: Readonly<import("../../forms/types.js").QaFormPolicy>;
5
+ api: QaFormApi;
6
+ session: string;
7
+ token: string;
8
+ form: QaFormView;
9
+ canStop: boolean;
10
+ onStop(): Promise<void>;
11
+ onResume(id: string): void;
12
+ onTakeover(active: boolean): void;
13
+ }
14
+ export declare function QaInputForm(props: Props): import("react/jsx-runtime").JSX.Element;
15
+ /** Session/identity-keyed parent discards account-local state and aborts transfers on switch. */
16
+ export declare function QaInputForms(props: Omit<Props, "form">): import("react/jsx-runtime").JSX.Element | null;
17
+ export {};
18
+ //# sourceMappingURL=QaInputForm.d.ts.map
@@ -0,0 +1,6 @@
1
+ import type { QaQueueStatus } from "../../types.js";
2
+ /** A queued turn belongs to the Host and starts without resending the question. */
3
+ export declare function QaRequestWait({ status, }: {
4
+ readonly status: QaQueueStatus | null;
5
+ }): import("react/jsx-runtime").JSX.Element | null;
6
+ //# sourceMappingURL=QaRequestWait.d.ts.map
@@ -0,0 +1,2 @@
1
+ export declare const QA_FORM_STYLES = "\n.dsh-qa-form{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;max-height:75vh;overflow:hidden;overflow-wrap:anywhere;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column}\n.dsh-qa-form__content{overflow:auto;min-height:0;padding:0 2px}.dsh-qa-form>header,.dsh-qa-form>footer,.dsh-qa-form>nav,.dsh-qa-form>p{flex-shrink:0}.dsh-qa-form>footer{border-top:1px solid var(--dsw-alias-border-l2);padding-top:12px;margin-top:8px}\n.dsh-qa-form>header{max-height:96px;overflow:auto}\n.dsh-qa-form header,.dsh-qa-form footer,.dsh-qa-form nav{display:flex;gap:8px;align-items:center;flex-wrap:wrap}\n.dsh-qa-form header{justify-content:space-between}.dsh-qa-form nav{margin:12px 0}.dsh-qa-form h3{margin:12px 0}\n.dsh-qa-form button{font:inherit;color:inherit;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px 12px;cursor:pointer}\n.dsh-qa-form button:disabled{opacity:.55;cursor:default}.dsh-qa-form button:focus-visible,.dsh-qa-form input:focus-visible,.dsh-qa-form textarea:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}\n.dsh-qa-form__item{min-width:0;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);padding:12px 0;margin:0 0 12px}.dsh-qa-form legend{font-weight:600}.dsh-qa-form small{font-weight:400;display:block;color:var(--dsw-alias-label-tertiary)}\n.dsh-qa-form__hint{font-size:13px;color:var(--dsw-alias-label-secondary)}.dsh-qa-form label{display:block}.dsh-qa-form input[type=text],.dsh-qa-form textarea{display:block;box-sizing:border-box;width:100%;font:inherit;color:inherit;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:10px;margin:6px 0}\n.dsh-qa-form__choices>label{display:flex;gap:8px;align-items:baseline;margin:8px 0}.dsh-qa-form__files{border:1px dashed var(--dsw-alias-border-l2);border-radius:8px;padding:12px;margin-top:12px}.dsh-qa-form input[type=file]{max-width:100%;display:block;margin:8px 0}.dsh-qa-form__files ul{padding-left:18px}.dsh-qa-form__files li{margin:10px 0}.dsh-qa-form__files button{margin:4px}.dsh-qa-form__review>div{border-bottom:1px solid var(--dsw-alias-border-l2);margin-bottom:12px}.dsh-qa-form [role=alert]{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);padding:10px;border-radius:8px}\n@media(max-width:600px){.dsh-qa-form{padding:12px;max-height:80vh}.dsh-qa-form footer button{flex:1 1 auto}.dsh-qa-form nav button{font-size:12px}}\n";
2
+ //# sourceMappingURL=forms-styles.d.ts.map
@@ -0,0 +1,23 @@
1
+ import type { QaFormCommand, QaFormResult, QaFormView } from "../forms/types.js";
2
+ import type { RemoteResult } from "./types.js";
3
+ import type { QaUploadCarrier } from "./account-upload.js";
4
+ /** Typert adds an outer transport result; domain refusals remain stable codes. */
5
+ export interface QaFormApi {
6
+ list(token: string, session: string): Promise<RemoteResult<QaFormResult<QaFormView[]>>>;
7
+ get(token: string, session: string, id: string): Promise<RemoteResult<QaFormResult<QaFormView>>>;
8
+ mutate(token: string, session: string, command: QaFormCommand): Promise<RemoteResult<QaFormResult<QaFormView>>>;
9
+ upload(token: string, session: string, id: string, file: File, signal: AbortSignal): Promise<void>;
10
+ file(token: string, session: string, formId: string, resourceId: string): Promise<RemoteResult<QaFormResult<{
11
+ name: string;
12
+ media_type: string;
13
+ data: string;
14
+ }>>>;
15
+ }
16
+ export declare class QaFormClientError extends Error {
17
+ readonly code: string;
18
+ constructor(code: string, message: string);
19
+ }
20
+ export declare function unwrapForm<T>(result: RemoteResult<QaFormResult<T>>): T;
21
+ /** Same protected carrier and route as ordinary QA uploads; no fabricated percentage. */
22
+ export declare function uploadQaFormFile(carrier: QaUploadCarrier | undefined, token: string, session: string, uploadId: string, file: File, signal: AbortSignal): Promise<void>;
23
+ //# sourceMappingURL=forms.d.ts.map
@@ -0,0 +1,12 @@
1
+ import type { QaOidcStart, ResolvedQaSurfaceConfig } from "../types.js";
2
+ export interface QaOidcBrowser {
3
+ begin(start: QaOidcStart): void;
4
+ takeHandoff(): {
5
+ handoff: string;
6
+ completionKey: string;
7
+ } | null;
8
+ logout(url: string): void;
9
+ }
10
+ /** Completion proof is isolated to the initiating tab and never goes in a URL. */
11
+ export declare function createQaOidcBrowser(browser: Pick<Window, "location" | "history" | "sessionStorage">, config: () => ResolvedQaSurfaceConfig): QaOidcBrowser;
12
+ //# sourceMappingURL=oidc-browser.d.ts.map
@@ -40,10 +40,8 @@ export interface QaBoundProjectionInput {
40
40
  readonly questions: readonly QaPendingQuestion[];
41
41
  readonly operationError: string | null;
42
42
  /**
43
- * A send the stand had no room for. The dialog is the whole of what the
44
- * visitor learns: the question never reached the Host, so the transcript has
45
- * no row to carry the refusal on. Distinct from `queue`, the waiting rows of
46
- * this chat.
43
+ * Server admission status for this waiting chat, or a legacy Host's
44
+ * pre-send refusal. Distinct from `queue`, the next messages of this chat.
47
45
  */
48
46
  readonly requestQueue: QaQueueStatus | null;
49
47
  readonly policyReady: boolean;
@@ -0,0 +1,2 @@
1
+ export declare const requestWaitStyles = "\n.dsh-qa-request-wait{display:flex;align-items:center;gap:8px;align-self:flex-start;width:fit-content;max-width:100%;box-sizing:border-box;margin:0 0 10px;padding:6px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.45;overflow-wrap:anywhere}\n.dsh-qa-request-wait__spinner{width:12px;height:12px;flex:none;border:1.5px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-label-secondary);border-radius:50%;animation:dsh-qa-request-spin 1s linear infinite}\n@keyframes dsh-qa-request-spin{to{transform:rotate(360deg)}}\n@media(prefers-reduced-motion:reduce){.dsh-qa-request-wait__spinner{animation:none}}\n";
2
+ //# sourceMappingURL=request-wait-styles.d.ts.map