@yadsh/dsh-qa-surface 0.17.0 → 0.18.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 +15 -3
- package/compatibility.json +1 -1
- package/lib/account-remotes.js +4 -0
- package/lib/account-remotes.js.map +1 -1
- package/lib/accounts/database.js +86 -1
- package/lib/accounts/database.js.map +1 -1
- package/lib/accounts/file.js.map +1 -1
- package/lib/accounts/store.js +111 -5
- package/lib/accounts/store.js.map +1 -1
- package/lib/accounts/token.js +8 -2
- package/lib/accounts/token.js.map +1 -1
- package/lib/admin/metrics.js +15 -2
- package/lib/admin/metrics.js.map +1 -1
- package/lib/admin/read-budget.js +28 -0
- package/lib/admin/read-budget.js.map +1 -0
- package/lib/admin/service.js +135 -40
- package/lib/admin/service.js.map +1 -1
- package/lib/admin/session-log.js +63 -4
- package/lib/admin/session-log.js.map +1 -1
- package/lib/chat-sharing/native-fence.js +20 -0
- package/lib/chat-sharing/native-fence.js.map +1 -1
- package/lib/chat-sharing/transport.js +8 -2
- package/lib/chat-sharing/transport.js.map +1 -1
- package/lib/chat-sharing/uploads.js +79 -6
- package/lib/chat-sharing/uploads.js.map +1 -1
- package/lib/cli.js +13 -0
- package/lib/cli.js.map +1 -1
- package/lib/client/QaAccountsController.js +61 -0
- package/lib/client/QaAccountsController.js.map +1 -1
- package/lib/client/QaRouteController.js +3 -1
- package/lib/client/QaRouteController.js.map +1 -1
- package/lib/client/QaSessionController.js +90 -26
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +40 -11
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/account-sessions.js +74 -8
- package/lib/client/account-sessions.js.map +1 -1
- package/lib/client/admin/CapabilityPicker.js +50 -0
- package/lib/client/admin/CapabilityPicker.js.map +1 -0
- package/lib/client/admin/CoverageNotice.js +9 -0
- package/lib/client/admin/CoverageNotice.js.map +1 -0
- package/lib/client/admin/QaAdmin.js +3 -150
- package/lib/client/admin/QaAdmin.js.map +1 -1
- package/lib/client/admin/RoleEditor.js +46 -0
- package/lib/client/admin/RoleEditor.js.map +1 -0
- package/lib/client/admin/capability-selection.js +63 -0
- package/lib/client/admin/capability-selection.js.map +1 -0
- package/lib/client/admin/pages/Conversations.js +35 -17
- package/lib/client/admin/pages/Conversations.js.map +1 -1
- package/lib/client/admin/pages/Overview.js +3 -2
- package/lib/client/admin/pages/Overview.js.map +1 -1
- package/lib/client/admin/pages/Quality.js +77 -20
- package/lib/client/admin/pages/Quality.js.map +1 -1
- package/lib/client/admin/pages/SkillFiles.js +14 -3
- package/lib/client/admin/pages/SkillFiles.js.map +1 -1
- package/lib/client/admin/shared.js +68 -3
- package/lib/client/admin/shared.js.map +1 -1
- package/lib/client/components/QaAuthGate.js +31 -28
- package/lib/client/components/QaAuthGate.js.map +1 -1
- package/lib/client/components/QaChangelog.js +44 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaComposer.js +27 -4
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaFormItem.js +63 -0
- package/lib/client/components/QaFormItem.js.map +1 -0
- package/lib/client/components/QaInputForm.js +281 -0
- package/lib/client/components/QaInputForm.js.map +1 -0
- package/lib/client/components/QaModal.js +17 -4
- package/lib/client/components/QaModal.js.map +1 -1
- package/lib/client/forms-styles.js +14 -0
- package/lib/client/forms-styles.js.map +1 -0
- package/lib/client/forms.js +40 -0
- package/lib/client/forms.js.map +1 -0
- package/lib/client/index.js +15 -1
- package/lib/client/index.js.map +1 -1
- package/lib/client/oidc-browser.js +39 -0
- package/lib/client/oidc-browser.js.map +1 -0
- package/lib/client/panels/PanelHost.js +23 -1
- package/lib/client/panels/PanelHost.js.map +1 -1
- package/lib/client/settings/sections/interface.js +2 -1
- package/lib/client/settings/sections/interface.js.map +1 -1
- package/lib/client/settings/sections/status.js +3 -1
- package/lib/client/settings/sections/status.js.map +1 -1
- package/lib/client/styles.js +3 -3
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +465 -72918
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/accounts.js +5 -4
- package/lib/config-resolvers/accounts.js.map +1 -1
- package/lib/config-resolvers/defaults.js +16 -0
- package/lib/config-resolvers/defaults.js.map +1 -1
- package/lib/config-resolvers/oidc.js +53 -0
- package/lib/config-resolvers/oidc.js.map +1 -0
- package/lib/config.js +71 -0
- package/lib/config.js.map +1 -1
- package/lib/forms/attachments.js +214 -0
- package/lib/forms/attachments.js.map +1 -0
- package/lib/forms/errors.js +37 -0
- package/lib/forms/errors.js.map +1 -0
- package/lib/forms/fingerprint.js +21 -0
- package/lib/forms/fingerprint.js.map +1 -0
- package/lib/forms/gate.js +125 -0
- package/lib/forms/gate.js.map +1 -0
- package/lib/forms/schema.js +182 -0
- package/lib/forms/schema.js.map +1 -0
- package/lib/forms/service.js +220 -0
- package/lib/forms/service.js.map +1 -0
- package/lib/forms/store.js +194 -0
- package/lib/forms/store.js.map +1 -0
- package/lib/forms/types.js +2 -0
- package/lib/forms/types.js.map +1 -0
- package/lib/forms/validation.js +113 -0
- package/lib/forms/validation.js.map +1 -0
- package/lib/index.js +227 -3
- package/lib/index.js.map +1 -1
- package/lib/oidc/http.js +30 -0
- package/lib/oidc/http.js.map +1 -0
- package/lib/oidc/service.js +250 -0
- package/lib/oidc/service.js.map +1 -0
- package/lib/qa-tools/activation-manager.js +24 -2
- package/lib/qa-tools/activation-manager.js.map +1 -1
- package/lib/qa-tools/catalog.js +11 -1
- package/lib/qa-tools/catalog.js.map +1 -1
- package/lib/qa-tools/index.js +27 -0
- package/lib/qa-tools/index.js.map +1 -1
- package/lib/qa-tools/request-user-form.js +121 -0
- package/lib/qa-tools/request-user-form.js.map +1 -0
- package/lib/resolve-config.js +2 -0
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +14 -8
- package/lib/secure-session.js.map +1 -1
- package/lib/typert.host.js +4587 -1101
- package/lib/typert.remote-client.d.ts +133 -3
- package/lib/typert.remote-client.js +4463 -1103
- package/lib/types/accounts/database.d.ts +8 -0
- package/lib/types/accounts/file.d.ts +2 -0
- package/lib/types/accounts/store.d.ts +17 -0
- package/lib/types/accounts/token.d.ts +3 -1
- package/lib/types/admin/metrics.d.ts +5 -1
- package/lib/types/admin/read-budget.d.ts +8 -0
- package/lib/types/admin/service.d.ts +17 -0
- package/lib/types/admin/session-log.d.ts +30 -1
- package/lib/types/chat-sharing/uploads.d.ts +2 -1
- package/lib/types/client/QaAccountsController.d.ts +4 -0
- package/lib/types/client/QaRouteController.d.ts +1 -0
- package/lib/types/client/QaSessionController.d.ts +12 -3
- package/lib/types/client/QaSurface.d.ts +2 -0
- package/lib/types/client/admin/CapabilityPicker.d.ts +14 -0
- package/lib/types/client/admin/CoverageNotice.d.ts +6 -0
- package/lib/types/client/admin/RoleEditor.d.ts +15 -0
- package/lib/types/client/admin/capability-selection.d.ts +27 -0
- package/lib/types/client/admin/shared.d.ts +39 -1
- package/lib/types/client/components/QaAuthGate.d.ts +2 -0
- package/lib/types/client/components/QaFormItem.d.ts +20 -0
- package/lib/types/client/components/QaInputForm.d.ts +18 -0
- package/lib/types/client/forms-styles.d.ts +2 -0
- package/lib/types/client/forms.d.ts +23 -0
- package/lib/types/client/oidc-browser.d.ts +12 -0
- package/lib/types/client/types.d.ts +7 -1
- package/lib/types/config-resolvers/oidc.d.ts +3 -0
- package/lib/types/forms/attachments.d.ts +48 -0
- package/lib/types/forms/errors.d.ts +11 -0
- package/lib/types/forms/fingerprint.d.ts +9 -0
- package/lib/types/forms/gate.d.ts +33 -0
- package/lib/types/forms/schema.d.ts +72 -0
- package/lib/types/forms/service.d.ts +15 -0
- package/lib/types/forms/store.d.ts +25 -0
- package/lib/types/forms/types.d.ts +215 -0
- package/lib/types/forms/validation.d.ts +20 -0
- package/lib/types/index.d.ts +28 -0
- package/lib/types/oidc/http.d.ts +5 -0
- package/lib/types/oidc/service.d.ts +30 -0
- package/lib/types/oidc.js +2 -0
- package/lib/types/oidc.js.map +1 -0
- package/lib/types/qa-tools/activation-manager.d.ts +5 -0
- package/lib/types/qa-tools/catalog.d.ts +4 -1
- package/lib/types/qa-tools/index.d.ts +5 -1
- package/lib/types/qa-tools/request-user-form.d.ts +5 -0
- package/lib/types/secure-session.d.ts +1 -0
- package/lib/types/types/accounts.d.ts +2 -0
- package/lib/types/types/admin.d.ts +6 -0
- package/lib/types/types/config.d.ts +6 -0
- package/lib/types/types/oidc.d.ts +36 -0
- package/lib/types/types.d.ts +2 -0
- package/package.json +57 -55
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import type { ToolExecution } from "@deepseek-ai/dsh-tools";
|
|
3
|
+
import type { QaFormService } from "./service.js";
|
|
4
|
+
import type { QaFormRecord, QaFormSubmission } from "./types.js";
|
|
5
|
+
type Outcome = QaFormSubmission | {
|
|
6
|
+
status: "paused";
|
|
7
|
+
form_id: string;
|
|
8
|
+
reason: string;
|
|
9
|
+
};
|
|
10
|
+
/** A parked tool call is transient. Never reconstruct one from a saved draft. */
|
|
11
|
+
export declare class QaFormGate {
|
|
12
|
+
readonly service: () => QaFormService;
|
|
13
|
+
private readonly rootOf;
|
|
14
|
+
private readonly busy;
|
|
15
|
+
private readonly allowed;
|
|
16
|
+
private readonly filesAvailable;
|
|
17
|
+
private readonly waiters;
|
|
18
|
+
private readonly disposers;
|
|
19
|
+
private closed;
|
|
20
|
+
private readonly clients;
|
|
21
|
+
constructor(service: () => QaFormService, rootOf: (id: string) => string | undefined, busy: (id: string) => boolean, allowed: (exec: ToolExecution) => boolean, filesAvailable?: () => boolean);
|
|
22
|
+
install(ctx: Context): void;
|
|
23
|
+
waiting(id: string): boolean;
|
|
24
|
+
touch(session: string): void;
|
|
25
|
+
hasSession(session: string): boolean;
|
|
26
|
+
request(raw: unknown, exec: ToolExecution): Promise<Outcome>;
|
|
27
|
+
notify(record: QaFormRecord, pause?: boolean): void;
|
|
28
|
+
cancel(session: string): void;
|
|
29
|
+
cancelAll(): void;
|
|
30
|
+
dispose(): void;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { QaFormPolicy, QaFormSchema } from "./types.js";
|
|
3
|
+
export declare const DEFAULT_FORM_POLICY: Readonly<QaFormPolicy>;
|
|
4
|
+
export declare const formSchemaParser: z.ZodObject<{
|
|
5
|
+
schema_version: z.ZodLiteral<1>;
|
|
6
|
+
title: z.ZodString;
|
|
7
|
+
description: z.ZodOptional<z.ZodString>;
|
|
8
|
+
submit_label: z.ZodOptional<z.ZodString>;
|
|
9
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
10
|
+
id: z.ZodString;
|
|
11
|
+
title: z.ZodString;
|
|
12
|
+
description: z.ZodOptional<z.ZodString>;
|
|
13
|
+
items: z.ZodArray<z.ZodObject<{
|
|
14
|
+
id: z.ZodString;
|
|
15
|
+
title: z.ZodString;
|
|
16
|
+
description: z.ZodOptional<z.ZodString>;
|
|
17
|
+
answer: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
18
|
+
type: z.ZodLiteral<"text">;
|
|
19
|
+
required: z.ZodBoolean;
|
|
20
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
21
|
+
min_length: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
max_length: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
24
|
+
type: z.ZodLiteral<"textarea">;
|
|
25
|
+
required: z.ZodBoolean;
|
|
26
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
27
|
+
min_length: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
max_length: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
30
|
+
type: z.ZodLiteral<"single_select">;
|
|
31
|
+
required: z.ZodBoolean;
|
|
32
|
+
options: z.ZodArray<z.ZodObject<{
|
|
33
|
+
value: z.ZodString;
|
|
34
|
+
label: z.ZodString;
|
|
35
|
+
description: z.ZodOptional<z.ZodString>;
|
|
36
|
+
recommended: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
}, z.core.$strict>>;
|
|
38
|
+
allow_other: z.ZodOptional<z.ZodBoolean>;
|
|
39
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
40
|
+
type: z.ZodLiteral<"multi_select">;
|
|
41
|
+
required: z.ZodBoolean;
|
|
42
|
+
options: z.ZodArray<z.ZodObject<{
|
|
43
|
+
value: z.ZodString;
|
|
44
|
+
label: z.ZodString;
|
|
45
|
+
description: z.ZodOptional<z.ZodString>;
|
|
46
|
+
recommended: z.ZodOptional<z.ZodBoolean>;
|
|
47
|
+
}, z.core.$strict>>;
|
|
48
|
+
allow_other: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
min_selected: z.ZodOptional<z.ZodNumber>;
|
|
50
|
+
max_selected: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
}, z.core.$strict>], "type">>;
|
|
52
|
+
files: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
53
|
+
requirement: z.ZodLiteral<"none">;
|
|
54
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
55
|
+
max_count: z.ZodNumber;
|
|
56
|
+
accept: z.ZodArray<z.ZodString>;
|
|
57
|
+
max_file_size_bytes: z.ZodNumber;
|
|
58
|
+
requirement: z.ZodLiteral<"required">;
|
|
59
|
+
min_count: z.ZodNumber;
|
|
60
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
61
|
+
max_count: z.ZodNumber;
|
|
62
|
+
accept: z.ZodArray<z.ZodString>;
|
|
63
|
+
max_file_size_bytes: z.ZodNumber;
|
|
64
|
+
requirement: z.ZodLiteral<"optional">;
|
|
65
|
+
}, z.core.$strict>], "requirement">;
|
|
66
|
+
}, z.core.$strict>>;
|
|
67
|
+
}, z.core.$strict>>;
|
|
68
|
+
}, z.core.$strict>;
|
|
69
|
+
/** Shared by server and browser. No Node APIs or browser-supplied readiness. */
|
|
70
|
+
export declare function parseFormSchema(input: unknown, policy: Readonly<QaFormPolicy>): QaFormSchema;
|
|
71
|
+
export declare function resolveFormPolicy(input?: Partial<QaFormPolicy>): QaFormPolicy;
|
|
72
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { QaFormPolicy, QaFormRecord, QaFormStoreApi, QaFormView } from "./types.js";
|
|
2
|
+
export declare class QaFormService {
|
|
3
|
+
readonly store: QaFormStoreApi;
|
|
4
|
+
readonly policy: () => Readonly<QaFormPolicy>;
|
|
5
|
+
private readonly ownerOf;
|
|
6
|
+
constructor(store: QaFormStoreApi, policy: () => Readonly<QaFormPolicy>, ownerOf?: (session: string) => string);
|
|
7
|
+
enabled(): void;
|
|
8
|
+
create(session: string, key: string, input: unknown): QaFormRecord;
|
|
9
|
+
view(record: QaFormRecord, waiting?: boolean): QaFormView;
|
|
10
|
+
get(session: string, id: string): QaFormRecord;
|
|
11
|
+
step(session: string, id: string, stepId: string, revision: number): void;
|
|
12
|
+
command(session: string, raw: unknown): QaFormRecord;
|
|
13
|
+
private beginUpload;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { SqliteDatabase } from "@yadsh/dsh-plugin-kit/sqlite";
|
|
2
|
+
import type { QaFormRecord, QaFormStoreApi } from "./types.js";
|
|
3
|
+
export { fingerprint } from "./fingerprint.js";
|
|
4
|
+
/** Full synchronous commits: snapshot, revision and mutation receipt share one transaction. */
|
|
5
|
+
export declare class QaFormStore implements QaFormStoreApi {
|
|
6
|
+
readonly storage: SqliteDatabase;
|
|
7
|
+
constructor(file: string);
|
|
8
|
+
list(session: string): QaFormRecord[];
|
|
9
|
+
get(session: string, id: string): QaFormRecord;
|
|
10
|
+
put(record: QaFormRecord): void;
|
|
11
|
+
create(session: string, key: string, schema: QaFormRecord["schema"], creator?: string): QaFormRecord;
|
|
12
|
+
editableOrSubmitted(record: QaFormRecord): void;
|
|
13
|
+
private mutationReceipt;
|
|
14
|
+
replayedMutation(formId: string, mutationId: string, input: unknown): QaFormRecord | null;
|
|
15
|
+
mutate(session: string, id: string, revision: number, mutationId: string, input: unknown, work: (r: QaFormRecord) => void): QaFormRecord;
|
|
16
|
+
/** Async work happens before this short final transaction; no revision captured at upload start. */
|
|
17
|
+
update(session: string, id: string, work: (r: QaFormRecord) => void): QaFormRecord;
|
|
18
|
+
resource(formId: string, id: string): Uint8Array;
|
|
19
|
+
saveResource(formId: string, id: string, data: Uint8Array): void;
|
|
20
|
+
storedBytes(session: string): number;
|
|
21
|
+
identityReservedBytes(creator: string): number;
|
|
22
|
+
cancelSession(session: string): void;
|
|
23
|
+
close(): void;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/** Browser-safe wire contract; storage and tool waiting have independent lifetimes. */
|
|
2
|
+
export interface QaFormPolicy {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
maxSteps: number;
|
|
5
|
+
maxItemsPerForm: number;
|
|
6
|
+
maxOptionsPerItem: number;
|
|
7
|
+
maxSchemaBytes: number;
|
|
8
|
+
maxTextLength: number;
|
|
9
|
+
maxTotalAnswerBytes: number;
|
|
10
|
+
maxFilesPerItem: number;
|
|
11
|
+
maxFileSizeBytes: number;
|
|
12
|
+
maxTotalFileBytesPerForm: number;
|
|
13
|
+
maxConcurrentUploadsPerSession: number;
|
|
14
|
+
uploadIntentTtlSeconds: number;
|
|
15
|
+
allowedExtensions: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export interface QaFormOption {
|
|
18
|
+
value: string;
|
|
19
|
+
label: string;
|
|
20
|
+
description?: string | undefined;
|
|
21
|
+
recommended?: boolean | undefined;
|
|
22
|
+
}
|
|
23
|
+
export type QaFormAnswerSpec = {
|
|
24
|
+
type: "text" | "textarea";
|
|
25
|
+
required: boolean;
|
|
26
|
+
placeholder?: string | undefined;
|
|
27
|
+
min_length?: number | undefined;
|
|
28
|
+
max_length?: number | undefined;
|
|
29
|
+
} | {
|
|
30
|
+
type: "single_select" | "multi_select";
|
|
31
|
+
required: boolean;
|
|
32
|
+
options: QaFormOption[];
|
|
33
|
+
allow_other?: boolean | undefined;
|
|
34
|
+
min_selected?: number | undefined;
|
|
35
|
+
max_selected?: number | undefined;
|
|
36
|
+
};
|
|
37
|
+
export type QaFormFilesSpec = {
|
|
38
|
+
requirement: "none";
|
|
39
|
+
} | {
|
|
40
|
+
requirement: "required";
|
|
41
|
+
min_count: number;
|
|
42
|
+
max_count: number;
|
|
43
|
+
accept: string[];
|
|
44
|
+
max_file_size_bytes: number;
|
|
45
|
+
} | {
|
|
46
|
+
requirement: "optional";
|
|
47
|
+
max_count: number;
|
|
48
|
+
accept: string[];
|
|
49
|
+
max_file_size_bytes: number;
|
|
50
|
+
};
|
|
51
|
+
export interface QaFormItem {
|
|
52
|
+
id: string;
|
|
53
|
+
title: string;
|
|
54
|
+
description?: string | undefined;
|
|
55
|
+
answer?: QaFormAnswerSpec | undefined;
|
|
56
|
+
files: QaFormFilesSpec;
|
|
57
|
+
}
|
|
58
|
+
export interface QaFormStep {
|
|
59
|
+
id: string;
|
|
60
|
+
title: string;
|
|
61
|
+
description?: string | undefined;
|
|
62
|
+
items: QaFormItem[];
|
|
63
|
+
}
|
|
64
|
+
export interface QaFormSchema {
|
|
65
|
+
schema_version: 1;
|
|
66
|
+
title: string;
|
|
67
|
+
description?: string | undefined;
|
|
68
|
+
submit_label?: string | undefined;
|
|
69
|
+
steps: QaFormStep[];
|
|
70
|
+
}
|
|
71
|
+
export type QaFormAnswer = {
|
|
72
|
+
type: "text" | "textarea";
|
|
73
|
+
text: string;
|
|
74
|
+
} | {
|
|
75
|
+
type: "single_select" | "multi_select";
|
|
76
|
+
selected: string[];
|
|
77
|
+
other_text?: string | undefined;
|
|
78
|
+
};
|
|
79
|
+
export interface QaFormAttachment {
|
|
80
|
+
attachment_id: string;
|
|
81
|
+
version: number;
|
|
82
|
+
name: string;
|
|
83
|
+
size_bytes: number;
|
|
84
|
+
media_type: string;
|
|
85
|
+
sha256: string;
|
|
86
|
+
resource_id: string;
|
|
87
|
+
}
|
|
88
|
+
export interface QaFormUpload {
|
|
89
|
+
id: string;
|
|
90
|
+
item_id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
size_bytes: number;
|
|
93
|
+
state: "pending" | "uploading" | "failed" | "ready" | "cancelled";
|
|
94
|
+
expires_at: number;
|
|
95
|
+
target?: {
|
|
96
|
+
attachment_id: string;
|
|
97
|
+
version: number;
|
|
98
|
+
} | undefined;
|
|
99
|
+
result?: QaFormAttachment;
|
|
100
|
+
error?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface QaFormFieldError {
|
|
103
|
+
step_id: string;
|
|
104
|
+
item_id: string;
|
|
105
|
+
component: "answer" | "files";
|
|
106
|
+
code: string;
|
|
107
|
+
message: string;
|
|
108
|
+
}
|
|
109
|
+
export interface QaFormSubmission {
|
|
110
|
+
status: "submitted";
|
|
111
|
+
form_id: string;
|
|
112
|
+
submission_id: string;
|
|
113
|
+
schema_version: 1;
|
|
114
|
+
schema_hash: string;
|
|
115
|
+
form_revision: number;
|
|
116
|
+
submitted_at: string;
|
|
117
|
+
items: {
|
|
118
|
+
step_id: string;
|
|
119
|
+
item_id: string;
|
|
120
|
+
answer: QaFormAnswer | null;
|
|
121
|
+
files: QaFormAttachment[];
|
|
122
|
+
}[];
|
|
123
|
+
empty_optional_item_ids: string[];
|
|
124
|
+
}
|
|
125
|
+
export interface QaFormRecord {
|
|
126
|
+
storage_version: 1;
|
|
127
|
+
id: string;
|
|
128
|
+
session_id: string;
|
|
129
|
+
creator_id: string;
|
|
130
|
+
request_key: string;
|
|
131
|
+
schema: QaFormSchema;
|
|
132
|
+
schema_hash: string;
|
|
133
|
+
status: "draft" | "submitted" | "cancelled" | "expired";
|
|
134
|
+
revision: number;
|
|
135
|
+
created_at: string;
|
|
136
|
+
answers: Record<string, QaFormAnswer | null>;
|
|
137
|
+
attachments: Record<string, QaFormAttachment[]>;
|
|
138
|
+
uploads: QaFormUpload[];
|
|
139
|
+
step: number;
|
|
140
|
+
submission?: QaFormSubmission;
|
|
141
|
+
}
|
|
142
|
+
export type QaFormView = QaFormRecord & {
|
|
143
|
+
waiting: boolean;
|
|
144
|
+
field_errors: QaFormFieldError[];
|
|
145
|
+
};
|
|
146
|
+
export interface QaFormMutation {
|
|
147
|
+
form_id: string;
|
|
148
|
+
expected_revision: number;
|
|
149
|
+
mutation_id: string;
|
|
150
|
+
}
|
|
151
|
+
export type QaFormCommand = (QaFormMutation & {
|
|
152
|
+
action: "save";
|
|
153
|
+
answers: Record<string, QaFormAnswer | null>;
|
|
154
|
+
step: number;
|
|
155
|
+
}) | (QaFormMutation & {
|
|
156
|
+
action: "submit" | "pause";
|
|
157
|
+
}) | (QaFormMutation & {
|
|
158
|
+
action: "begin_upload";
|
|
159
|
+
item_id: string;
|
|
160
|
+
name: string;
|
|
161
|
+
size_bytes: number;
|
|
162
|
+
target?: {
|
|
163
|
+
attachment_id: string;
|
|
164
|
+
version: number;
|
|
165
|
+
} | undefined;
|
|
166
|
+
}) | (QaFormMutation & {
|
|
167
|
+
action: "cancel_upload";
|
|
168
|
+
upload_id: string;
|
|
169
|
+
}) | (QaFormMutation & {
|
|
170
|
+
action: "remove";
|
|
171
|
+
item_id: string;
|
|
172
|
+
attachment_id: string;
|
|
173
|
+
version: number;
|
|
174
|
+
});
|
|
175
|
+
export type QaFormResult<T> = {
|
|
176
|
+
ok: true;
|
|
177
|
+
value: T;
|
|
178
|
+
} | {
|
|
179
|
+
ok: false;
|
|
180
|
+
error: {
|
|
181
|
+
code: string;
|
|
182
|
+
message: string;
|
|
183
|
+
form_revision?: number;
|
|
184
|
+
field_errors?: QaFormFieldError[];
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* The store surface the service programs against.
|
|
189
|
+
*
|
|
190
|
+
* The service must never reach into a concrete storage backend: the shipped
|
|
191
|
+
* store is sqlite (durable), and the client component tests mount an in-memory
|
|
192
|
+
* implementation, which a browser test environment could never load through
|
|
193
|
+
* the sqlite bridge.
|
|
194
|
+
*/
|
|
195
|
+
export interface QaFormStoreApi {
|
|
196
|
+
list(session: string): QaFormRecord[];
|
|
197
|
+
create(session: string, key: string, schema: QaFormRecord["schema"], creator?: string): QaFormRecord;
|
|
198
|
+
get(session: string, id: string): QaFormRecord;
|
|
199
|
+
editableOrSubmitted(record: QaFormRecord): void;
|
|
200
|
+
mutate(session: string, id: string, revision: number, mutationId: string, input: unknown, work: (r: QaFormRecord) => void): QaFormRecord;
|
|
201
|
+
update(session: string, id: string, work: (r: QaFormRecord) => void): QaFormRecord;
|
|
202
|
+
resource(formId: string, id: string): Uint8Array;
|
|
203
|
+
saveResource(formId: string, id: string, data: Uint8Array): void;
|
|
204
|
+
storedBytes(session: string): number;
|
|
205
|
+
identityReservedBytes(creator: string): number;
|
|
206
|
+
cancelSession(session: string): void;
|
|
207
|
+
/**
|
|
208
|
+
* Submit retries are idempotent: when this mutation identity was already
|
|
209
|
+
* applied, return its recorded result and refuse a reused identity that
|
|
210
|
+
* carries different data. `null` means the identity is unused.
|
|
211
|
+
*/
|
|
212
|
+
replayedMutation(formId: string, mutationId: string, input: unknown): QaFormRecord | null;
|
|
213
|
+
close(): void;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { QaFormAnswer, QaFormAnswerSpec, QaFormFieldError, QaFormPolicy, QaFormRecord } from "./types.js";
|
|
3
|
+
export declare const formAnswerParser: z.ZodUnion<readonly [z.ZodObject<{
|
|
4
|
+
type: z.ZodEnum<{
|
|
5
|
+
text: "text";
|
|
6
|
+
textarea: "textarea";
|
|
7
|
+
}>;
|
|
8
|
+
text: z.ZodString;
|
|
9
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
10
|
+
type: z.ZodEnum<{
|
|
11
|
+
multi_select: "multi_select";
|
|
12
|
+
single_select: "single_select";
|
|
13
|
+
}>;
|
|
14
|
+
selected: z.ZodArray<z.ZodString>;
|
|
15
|
+
other_text: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, z.core.$strict>]>;
|
|
17
|
+
/** Requiredness is checked at navigation/submit; invalid supplied values fail even if optional. */
|
|
18
|
+
export declare function normalizeFormAnswer(spec: QaFormAnswerSpec | undefined, raw: unknown, policy: Readonly<QaFormPolicy>, requireComplete?: boolean): QaFormAnswer | null;
|
|
19
|
+
export declare function validateForm(record: QaFormRecord, policy: Readonly<QaFormPolicy>, stepId?: string): QaFormFieldError[];
|
|
20
|
+
//# sourceMappingURL=validation.d.ts.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { SessionPageRequest, SessionFollowRequest, SessionPromptRequest, Se
|
|
|
3
3
|
import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
4
4
|
import type { Context } from "@deepseek-ai/cordis";
|
|
5
5
|
import type { QaSurfaceConfigRefs } from "./config.js";
|
|
6
|
+
import type { QaFormCommand, QaFormResult, QaFormView } from "./forms/types.js";
|
|
6
7
|
import type { QaAccountNotificationsInput } from "./types.js";
|
|
7
8
|
import type { QaTurnSources } from "./provenance/types.js";
|
|
8
9
|
import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaDocumentPreview, QaSpreadsheetPreviewSelection, QaDocumentWorkflowStatus, QaIssuedServiceToken, QaLockdownProof, QaOwnershipEntry, QaPasswordResetRequest, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaQueueStatus, QaServiceTokenCreateInput, QaServiceTokenSummary, ResolvedQaSurfaceConfig, QaAdminSkillScope, QaAdminSkillsView, QaExpertMemoryDraft, QaExpertMemoryPage, QaExpertMemoryRecord, QaExpertMemoryScope, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaWorkspaceFile, QaWorkspaceFileChunk, QaWorkspaceListing, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackHarvestEntry, QaFeedbackHarvestResult, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaModelCatalogEntry, QaModelPair, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
|
|
@@ -26,6 +27,10 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
26
27
|
private readonly approvals;
|
|
27
28
|
private readonly fileDeleteGate;
|
|
28
29
|
private readonly userQuestions;
|
|
30
|
+
private formService?;
|
|
31
|
+
private readonly formGate;
|
|
32
|
+
private readonly formAttachments;
|
|
33
|
+
private forms;
|
|
29
34
|
private readonly provenance;
|
|
30
35
|
private readonly notes;
|
|
31
36
|
/** Assigned after the admission gate; that gate only reads it per execution. */
|
|
@@ -54,6 +59,9 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
54
59
|
private readonly integrationPrincipals;
|
|
55
60
|
private webServer;
|
|
56
61
|
private disposeRoute;
|
|
62
|
+
private readonly oidc;
|
|
63
|
+
private disposeOidcRoute;
|
|
64
|
+
private oidcRouteKey;
|
|
57
65
|
private routeKey;
|
|
58
66
|
/**
|
|
59
67
|
* The HTTP API an external application asks questions through. Constructed
|
|
@@ -142,6 +150,9 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
142
150
|
*/
|
|
143
151
|
accountsRegister(email: string, password: string): QaAccountSession;
|
|
144
152
|
accountsLogin(email: string, password: string): QaAccountSession;
|
|
153
|
+
accountsOidcStart(): Promise<import("./types.js").QaOidcStart>;
|
|
154
|
+
accountsOidcComplete(handoff: string, completionKey: string): QaAccountSession;
|
|
155
|
+
accountsOidcLogout(token: string): Promise<string | null>;
|
|
145
156
|
/** Identity probe; safe to call with an empty or expired token. */
|
|
146
157
|
accountsChangePassword(token: string, currentPassword: string, nextPassword: string): QaAccountSession;
|
|
147
158
|
/**
|
|
@@ -391,6 +402,22 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
391
402
|
* deployment with unsupported questions answers with an empty list.
|
|
392
403
|
*/
|
|
393
404
|
pendingQuestions(token: string, sessionId: string): Promise<readonly QaPendingQuestion[]>;
|
|
405
|
+
/** Forms stay owner-scoped; UUIDs and a browser-supplied session never grant access. */
|
|
406
|
+
private admitForm;
|
|
407
|
+
listForms(token: string, sessionId: string): Promise<QaFormResult<QaFormView[]>>;
|
|
408
|
+
getForm(token: string, sessionId: string, formId: string): Promise<QaFormResult<QaFormView>>;
|
|
409
|
+
mutateForm(token: string, sessionId: string, command: QaFormCommand): Promise<QaFormResult<QaFormView>>;
|
|
410
|
+
validateFormStep(token: string, sessionId: string, formId: string, stepId: string, revision: number): Promise<QaFormResult<null>>;
|
|
411
|
+
formCapabilities(): Promise<{
|
|
412
|
+
enabled: boolean;
|
|
413
|
+
schemaVersion: number;
|
|
414
|
+
upload: boolean;
|
|
415
|
+
}>;
|
|
416
|
+
readFormAttachment(token: string, sessionId: string, formId: string, resourceId: string): Promise<QaFormResult<{
|
|
417
|
+
name: string;
|
|
418
|
+
media_type: string;
|
|
419
|
+
data: string;
|
|
420
|
+
}>>;
|
|
394
421
|
/**
|
|
395
422
|
* Apply the operator's answers to one parked question request. Every question
|
|
396
423
|
* of the request must be present in `answers`; one the browser omits reads as
|
|
@@ -511,6 +538,7 @@ export declare class QaSurface extends TypertRemoteService {
|
|
|
511
538
|
* immediately rather than at the next restart.
|
|
512
539
|
*/
|
|
513
540
|
private refreshIntegrationRoutes;
|
|
541
|
+
private refreshOidcRoute;
|
|
514
542
|
private refreshRoute;
|
|
515
543
|
/**
|
|
516
544
|
* A deployment that set `lockdown.allowSlashCommands: true` before this
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { WebServer } from "@deepseek-ai/dsh-host-webserver";
|
|
2
|
+
import type { ResolvedQaSurfaceConfig } from "../types.js";
|
|
3
|
+
import type { QaOidcService } from "./service.js";
|
|
4
|
+
export declare function registerQaOidcRoute(webServer: Pick<WebServer, "register">, config: ResolvedQaSurfaceConfig, service: QaOidcService): () => void;
|
|
5
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as oidc from "openid-client";
|
|
2
|
+
import type { QaAccounts } from "../accounts/store.js";
|
|
3
|
+
import type { QaAccountSession, QaOidcStart, ResolvedQaSurfaceConfig } from "../types.js";
|
|
4
|
+
/** A coarse refusal never carries provider responses, codes or tokens. */
|
|
5
|
+
export declare function oidcRefusal(): Error;
|
|
6
|
+
/** Authorization Code + PKCE with a browser-bound, single-use QA handoff. */
|
|
7
|
+
export declare class QaOidcService {
|
|
8
|
+
private readonly options;
|
|
9
|
+
private generation;
|
|
10
|
+
private key;
|
|
11
|
+
private discovery;
|
|
12
|
+
private readonly transactions;
|
|
13
|
+
private readonly handoffs;
|
|
14
|
+
private attempts;
|
|
15
|
+
constructor(options: {
|
|
16
|
+
config: () => ResolvedQaSurfaceConfig;
|
|
17
|
+
accounts: () => QaAccounts | undefined;
|
|
18
|
+
discover?: typeof oidc.discovery;
|
|
19
|
+
});
|
|
20
|
+
private sync;
|
|
21
|
+
clear(): void;
|
|
22
|
+
private prune;
|
|
23
|
+
private client;
|
|
24
|
+
start(): Promise<QaOidcStart>;
|
|
25
|
+
/** Callback is reconstructed from configured origin, never Host/Forwarded headers. */
|
|
26
|
+
callback(requestUrl: string): Promise<string>;
|
|
27
|
+
complete(handoff: string, completionKey: string): QaAccountSession;
|
|
28
|
+
logout(token: string): Promise<string | null>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.js","sourceRoot":"","sources":["../../src/types/oidc.ts"],"names":[],"mappings":""}
|
|
@@ -19,7 +19,12 @@ export interface QaToolActivationManagerOptions {
|
|
|
19
19
|
export declare class QaToolActivationManager implements QaToolActivation {
|
|
20
20
|
private readonly options;
|
|
21
21
|
private readonly states;
|
|
22
|
+
private readonly activeAgents;
|
|
23
|
+
private catalog;
|
|
22
24
|
constructor(options: QaToolActivationManagerOptions);
|
|
25
|
+
/** Reconcile feature switches only for scopes which already earned activation. */
|
|
26
|
+
replaceCatalog(catalog: readonly QaToolDescriptor[]): void;
|
|
27
|
+
disposeAll(): void;
|
|
23
28
|
/**
|
|
24
29
|
* Register the whole catalog on one agent, all or nothing.
|
|
25
30
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
2
2
|
import type { QaToolDescriptor } from "./types.js";
|
|
3
|
+
import type { QaFormGate } from "../forms/gate.js";
|
|
3
4
|
/**
|
|
4
5
|
* Deterministic catalog identity. The durable activation marker is derived from
|
|
5
6
|
* the session log rather than stored, so this version is not compared against a
|
|
@@ -8,9 +9,11 @@ import type { QaToolDescriptor } from "./types.js";
|
|
|
8
9
|
*
|
|
9
10
|
* Bump it whenever the catalog's tool set or their schemas change.
|
|
10
11
|
*/
|
|
11
|
-
export declare const QA_TOOL_CATALOG_VERSION = "
|
|
12
|
+
export declare const QA_TOOL_CATALOG_VERSION = "4";
|
|
12
13
|
/** What the catalog's definitions read, beyond the execution record. */
|
|
13
14
|
export interface QaToolsSelfcheckDeps {
|
|
15
|
+
readonly forms?: QaFormGate;
|
|
16
|
+
readonly formProjection?: (submission: import("../forms/types.js").QaFormSubmission) => Promise<unknown>;
|
|
14
17
|
readonly catalogVersion: string;
|
|
15
18
|
readonly activationMode: string;
|
|
16
19
|
/** Names the catalog contributes, in catalog order. */
|
|
@@ -3,6 +3,9 @@ import type { Context } from "@deepseek-ai/cordis";
|
|
|
3
3
|
import type { PluginLogger } from "@yadsh/dsh-plugin-log";
|
|
4
4
|
import type { QaToolActivation } from "./types.js";
|
|
5
5
|
export interface QaToolsOptions {
|
|
6
|
+
readonly forms?: import("../forms/gate.js").QaFormGate;
|
|
7
|
+
readonly formsEnabled?: () => boolean;
|
|
8
|
+
readonly formProjection?: (submission: import("../forms/types.js").QaFormSubmission) => Promise<unknown>;
|
|
6
9
|
readonly logger: PluginLogger;
|
|
7
10
|
readonly dynamicActivation: boolean;
|
|
8
11
|
readonly activationSkill: string;
|
|
@@ -31,12 +34,13 @@ export declare class QaTools implements QaToolActivation {
|
|
|
31
34
|
private readonly manager;
|
|
32
35
|
private readonly detector;
|
|
33
36
|
private readonly lifecycle;
|
|
34
|
-
private
|
|
37
|
+
private catalogTools;
|
|
35
38
|
constructor(ctx: Context, options: QaToolsOptions);
|
|
36
39
|
/** Names currently registered on one agent; the admission guard reads this per call. */
|
|
37
40
|
activeToolNames(agent: Agent): readonly string[];
|
|
38
41
|
/** Shipped scope-local names, including entries not activated on an agent yet. */
|
|
39
42
|
catalogToolNames(): readonly string[];
|
|
43
|
+
refreshForms(): void;
|
|
40
44
|
dispose(): void;
|
|
41
45
|
/**
|
|
42
46
|
* The preset gate. An empty `activationPresets` leaves it open, which is only
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@deepseek-ai/dsh-tools";
|
|
2
|
+
import type { QaFormGate } from "../forms/gate.js";
|
|
3
|
+
/** Build only; the QA activation manager owns registration and role admission. */
|
|
4
|
+
export declare function createRequestUserFormTool(gate: QaFormGate, project?: (submission: import("../forms/types.js").QaFormSubmission) => Promise<unknown>): ToolDefinition;
|
|
5
|
+
//# sourceMappingURL=request-user-form.d.ts.map
|
|
@@ -71,6 +71,7 @@ export declare class QaPolicyAdmission {
|
|
|
71
71
|
* one set answers for the whole chat.
|
|
72
72
|
*/
|
|
73
73
|
private readonly attested;
|
|
74
|
+
private readonly questionWarnings;
|
|
74
75
|
private readonly workspaceAccess;
|
|
75
76
|
/**
|
|
76
77
|
* Removers of the document input roots granted per session, so a grant lives
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { QaAccountRole } from "./policy.js";
|
|
2
2
|
/** The account fields projected to browsers; never includes credentials. */
|
|
3
3
|
export interface QaAccountUserPublic {
|
|
4
|
+
/** Corporate passwords are managed outside QA. Absent on legacy/local accounts. */
|
|
5
|
+
readonly authMethod?: "oidc";
|
|
4
6
|
readonly id: string;
|
|
5
7
|
readonly email: string;
|
|
6
8
|
readonly displayName: string;
|
|
@@ -196,6 +196,12 @@ export interface QaQualityTrendPoint {
|
|
|
196
196
|
readonly negative: number;
|
|
197
197
|
}
|
|
198
198
|
export interface QaQualityMetrics {
|
|
199
|
+
/** Counts derived from journals are incomplete until every journal was read. */
|
|
200
|
+
readonly coverage?: {
|
|
201
|
+
readonly complete: boolean;
|
|
202
|
+
readonly readConversations: number;
|
|
203
|
+
readonly totalConversations: number;
|
|
204
|
+
};
|
|
199
205
|
readonly conversations: number;
|
|
200
206
|
readonly activeUsers: number;
|
|
201
207
|
readonly assistantMessages: number;
|
|
@@ -94,6 +94,7 @@ export interface QaNotesConfig {
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
export interface QaSurfaceConfig {
|
|
97
|
+
readonly forms?: Partial<import("../forms/types.js").QaFormPolicy>;
|
|
97
98
|
readonly enabled?: boolean;
|
|
98
99
|
readonly route?: {
|
|
99
100
|
readonly path?: string;
|
|
@@ -237,6 +238,8 @@ export interface QaSurfaceConfig {
|
|
|
237
238
|
readonly frameAncestors?: string | null;
|
|
238
239
|
};
|
|
239
240
|
readonly accounts?: {
|
|
241
|
+
readonly localLogin?: boolean;
|
|
242
|
+
readonly oidc?: import("./oidc.js").QaOidcConfig;
|
|
240
243
|
/** Opt-in; the QA gate stays off until the deployment turns this on. */
|
|
241
244
|
readonly enabled?: boolean;
|
|
242
245
|
readonly allowRegistration?: boolean;
|
|
@@ -372,6 +375,7 @@ export interface QaAttachmentsConfig {
|
|
|
372
375
|
readonly extensions?: readonly string[];
|
|
373
376
|
}
|
|
374
377
|
export interface ResolvedQaSurfaceConfig {
|
|
378
|
+
readonly forms: Readonly<import("../forms/types.js").QaFormPolicy>;
|
|
375
379
|
readonly enabled: boolean;
|
|
376
380
|
readonly route: {
|
|
377
381
|
readonly path: string;
|
|
@@ -441,6 +445,8 @@ export interface ResolvedQaSurfaceConfig {
|
|
|
441
445
|
readonly frameAncestors: string | null;
|
|
442
446
|
};
|
|
443
447
|
readonly accounts: {
|
|
448
|
+
readonly localLogin: boolean;
|
|
449
|
+
readonly oidc: import("./oidc.js").ResolvedQaOidcConfig;
|
|
444
450
|
readonly enabled: boolean;
|
|
445
451
|
readonly allowRegistration: boolean;
|
|
446
452
|
readonly sessionTtlDays: number;
|