@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.
- package/README.md +35 -25
- 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/attachment-access.js +147 -0
- package/lib/attachment-access.js.map +1 -0
- package/lib/chat-sharing/native-fence.js +20 -0
- package/lib/chat-sharing/native-fence.js.map +1 -1
- package/lib/chat-sharing/search.js +89 -0
- package/lib/chat-sharing/search.js.map +1 -0
- package/lib/chat-sharing/transport.js +10 -9
- 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 +141 -35
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +43 -13
- 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 +71 -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/components/QaRequestWait.js +15 -0
- package/lib/client/components/QaRequestWait.js.map +1 -0
- 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 +18 -2
- 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/project-session-state.js.map +1 -1
- package/lib/client/request-wait-styles.js +7 -0
- package/lib/client/request-wait-styles.js.map +1 -0
- 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 +5 -3
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +471 -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/filesystem-intent.js +39 -0
- package/lib/filesystem-intent.js.map +1 -0
- package/lib/forms/attachments.js +230 -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 +271 -81
- 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/request-scheduler.js +235 -0
- package/lib/request-scheduler.js.map +1 -0
- package/lib/resolve-config.js +2 -0
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +60 -60
- package/lib/secure-session.js.map +1 -1
- package/lib/session-create.js +125 -0
- package/lib/session-create.js.map +1 -0
- package/lib/typert.host.js +4636 -1103
- package/lib/typert.remote-client.d.ts +135 -5
- package/lib/typert.remote-client.js +4502 -1095
- 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/attachment-access.d.ts +29 -0
- package/lib/types/chat-sharing/search.d.ts +5 -0
- 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 +24 -12
- 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/components/QaRequestWait.d.ts +6 -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/project-session-state.d.ts +2 -4
- package/lib/types/client/request-wait-styles.d.ts +2 -0
- package/lib/types/client/types.d.ts +10 -4
- package/lib/types/config-resolvers/oidc.d.ts +3 -0
- package/lib/types/filesystem-intent.d.ts +12 -0
- package/lib/types/forms/attachments.d.ts +51 -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 +33 -12
- 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/request-scheduler.d.ts +28 -0
- package/lib/types/secure-session.d.ts +13 -26
- package/lib/types/session-create.d.ts +29 -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/session.d.ts +8 -0
- package/lib/types/types.d.ts +2 -0
- package/lib/types/user-workspace.d.ts +4 -6
- package/lib/user-workspace.js +13 -67
- package/lib/user-workspace.js.map +1 -1
- package/package.json +66 -62
package/lib/index.js
CHANGED
|
@@ -32,7 +32,6 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
32
32
|
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
33
|
done = true;
|
|
34
34
|
};
|
|
35
|
-
import { randomUUID } from "node:crypto";
|
|
36
35
|
import { readSourceImage as readSourceImagePreview } from "./provenance/source-image.js";
|
|
37
36
|
import path from "node:path";
|
|
38
37
|
import { defaultAccountsFilePath } from "./accounts/store.js";
|
|
@@ -44,9 +43,9 @@ import { QaIntegrationQuestionPolicy } from "./integration/question-policy.js";
|
|
|
44
43
|
import { qaChatPublishedFile, qaChatAttachmentPath, } from "./chat-sharing/resources.js";
|
|
45
44
|
import { installQaChatUploads } from "./chat-sharing/uploads.js";
|
|
46
45
|
import { forkQaSession } from "./session-fork-host.js";
|
|
46
|
+
import { createQaSession } from "./session-create.js";
|
|
47
47
|
import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
48
48
|
import { SessionId } from "@deepseek-ai/dsh-session/types";
|
|
49
|
-
import { WorkspaceId } from "@deepseek-ai/dsh-workspace";
|
|
50
49
|
import { createHostLoggerSink, getPluginLogger, } from "@yadsh/dsh-plugin-log";
|
|
51
50
|
import { ConfigSchema, qaSurfaceVersion, readConfigRefs, resolveConfig, } from "./config.js";
|
|
52
51
|
import { createQaAccountRemotes } from "./account-remotes.js";
|
|
@@ -55,15 +54,22 @@ import { QaQualityStore } from "./admin/quality-store.js";
|
|
|
55
54
|
import { createSessionEraser, createSessionLogReader, } from "./admin/session-log.js";
|
|
56
55
|
import { createQaPersonalSkillRemotes, QaPersonalSkillsHost, } from "./personal-skills/index.js";
|
|
57
56
|
import { QaApprovalGate } from "./approvals.js";
|
|
58
|
-
import { QaAttestationError
|
|
57
|
+
import { QaAttestationError } from "./attestation.js";
|
|
59
58
|
import { QaFileDeleteGate } from "./qa-tools/file-delete-gate.js";
|
|
60
59
|
import { QaQuestionGate } from "./questions.js";
|
|
60
|
+
import { QaFormStore } from "./forms/store.js";
|
|
61
|
+
import { QaFormService } from "./forms/service.js";
|
|
62
|
+
import { QaFormGate } from "./forms/gate.js";
|
|
63
|
+
import { QaFormAttachmentAdapter, } from "./forms/attachments.js";
|
|
64
|
+
import { formFailure, QaFormError } from "./forms/errors.js";
|
|
61
65
|
import { QaSessionOwnership } from "./session-ownership.js";
|
|
62
66
|
import { QaLlmIdentity } from "./llm-identity.js";
|
|
63
67
|
import { registerTurnFailureLog } from "./turn-failure-log.js";
|
|
64
68
|
import { entryRedirectRow } from "./entry-redirect.js";
|
|
65
69
|
import { qaKioskDeployment } from "./ui-mode.js";
|
|
66
70
|
import { registerQaNavigationRoute } from "./host-route.js";
|
|
71
|
+
import { QaOidcService, oidcRefusal } from "./oidc/service.js";
|
|
72
|
+
import { registerQaOidcRoute } from "./oidc/http.js";
|
|
67
73
|
import { makeLaunchTokenSource } from "./launch-token.js";
|
|
68
74
|
import { QaIntegrationPrincipalBindings } from "./integration-principals.js";
|
|
69
75
|
import { registerQaIntegrationRoutes } from "./integration/http.js";
|
|
@@ -71,11 +77,10 @@ import { createQaIntegrationRunner } from "./integration/host-runner.js";
|
|
|
71
77
|
import { QaIntegrationService } from "./integration/service.js";
|
|
72
78
|
import { QaPolicyAdmission } from "./secure-session.js";
|
|
73
79
|
import { QaAccessService } from "./access/service.js";
|
|
74
|
-
import { applySessionModelPolicy } from "./session-model.js";
|
|
75
80
|
import { userInvocableSkillNames } from "./access/model.js";
|
|
76
81
|
import { createQaSlashRemotes } from "./slash/remotes.js";
|
|
77
82
|
import { QaPromptNotes } from "./prompt-notes.js";
|
|
78
|
-
import {
|
|
83
|
+
import { QaRequestScheduler, qaRequestFamilyBusy, qaRequestRoots, } from "./request-scheduler.js";
|
|
79
84
|
import { QaTools } from "./qa-tools/index.js";
|
|
80
85
|
import { docsDefaultVersionOf } from "./config-resolvers/tools.js";
|
|
81
86
|
import { QaProvenanceHost } from "./provenance/host-store.js";
|
|
@@ -83,7 +88,7 @@ import { defaultLegacyProvenanceFilePath, defaultQaProvenanceDirectoryPath, File
|
|
|
83
88
|
import { previewConvertibleDocument, previewSourceDocument, } from "./provenance/document-preview.js";
|
|
84
89
|
import { readWorkspaceFileChunk } from "./provenance/file-download.js";
|
|
85
90
|
import { listWorkspaceDirectory, readSourceFilePreview, readWorkspaceFile, QaSourcePreviewError, } from "./provenance/file-preview.js";
|
|
86
|
-
import { existingQaUserWorkspace
|
|
91
|
+
import { existingQaUserWorkspace } from "./user-workspace.js";
|
|
87
92
|
export const name = "qa-surface";
|
|
88
93
|
export const inject = [
|
|
89
94
|
"agents",
|
|
@@ -139,6 +144,9 @@ let QaSurface = (() => {
|
|
|
139
144
|
let _instanceExtraInitializers = [];
|
|
140
145
|
let _accountsRegister_decorators;
|
|
141
146
|
let _accountsLogin_decorators;
|
|
147
|
+
let _accountsOidcStart_decorators;
|
|
148
|
+
let _accountsOidcComplete_decorators;
|
|
149
|
+
let _accountsOidcLogout_decorators;
|
|
142
150
|
let _accountsChangePassword_decorators;
|
|
143
151
|
let _accountsRequestPasswordReset_decorators;
|
|
144
152
|
let _accountsWhoami_decorators;
|
|
@@ -219,6 +227,12 @@ let QaSurface = (() => {
|
|
|
219
227
|
let _pendingApprovals_decorators;
|
|
220
228
|
let _answerApproval_decorators;
|
|
221
229
|
let _pendingQuestions_decorators;
|
|
230
|
+
let _listForms_decorators;
|
|
231
|
+
let _getForm_decorators;
|
|
232
|
+
let _mutateForm_decorators;
|
|
233
|
+
let _validateFormStep_decorators;
|
|
234
|
+
let _formCapabilities_decorators;
|
|
235
|
+
let _readFormAttachment_decorators;
|
|
222
236
|
let _answerQuestion_decorators;
|
|
223
237
|
let _cancelQuestion_decorators;
|
|
224
238
|
let _readSourceFile_decorators;
|
|
@@ -243,6 +257,9 @@ let QaSurface = (() => {
|
|
|
243
257
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
244
258
|
_accountsRegister_decorators = [Remote("accountsRegister")];
|
|
245
259
|
_accountsLogin_decorators = [Remote("accountsLogin")];
|
|
260
|
+
_accountsOidcStart_decorators = [Remote("accountsOidcStart")];
|
|
261
|
+
_accountsOidcComplete_decorators = [Remote("accountsOidcComplete")];
|
|
262
|
+
_accountsOidcLogout_decorators = [Remote("accountsOidcLogout")];
|
|
246
263
|
_accountsChangePassword_decorators = [Remote("accountsChangePassword")];
|
|
247
264
|
_accountsRequestPasswordReset_decorators = [Remote("accountsRequestPasswordReset")];
|
|
248
265
|
_accountsWhoami_decorators = [Remote("accountsWhoami")];
|
|
@@ -323,6 +340,12 @@ let QaSurface = (() => {
|
|
|
323
340
|
_pendingApprovals_decorators = [Remote("pendingApprovals")];
|
|
324
341
|
_answerApproval_decorators = [Remote("answerApproval")];
|
|
325
342
|
_pendingQuestions_decorators = [Remote("pendingQuestions")];
|
|
343
|
+
_listForms_decorators = [Remote("listForms")];
|
|
344
|
+
_getForm_decorators = [Remote("getForm")];
|
|
345
|
+
_mutateForm_decorators = [Remote("mutateForm")];
|
|
346
|
+
_validateFormStep_decorators = [Remote("validateFormStep")];
|
|
347
|
+
_formCapabilities_decorators = [Remote("formCapabilities")];
|
|
348
|
+
_readFormAttachment_decorators = [Remote("readFormAttachment")];
|
|
326
349
|
_answerQuestion_decorators = [Remote("answerQuestion")];
|
|
327
350
|
_cancelQuestion_decorators = [Remote("cancelQuestion")];
|
|
328
351
|
_readSourceFile_decorators = [Remote("readSourceFile")];
|
|
@@ -344,6 +367,9 @@ let QaSurface = (() => {
|
|
|
344
367
|
_slashExecute_decorators = [Remote("slashExecute")];
|
|
345
368
|
__esDecorate(this, null, _accountsRegister_decorators, { kind: "method", name: "accountsRegister", static: false, private: false, access: { has: obj => "accountsRegister" in obj, get: obj => obj.accountsRegister }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
346
369
|
__esDecorate(this, null, _accountsLogin_decorators, { kind: "method", name: "accountsLogin", static: false, private: false, access: { has: obj => "accountsLogin" in obj, get: obj => obj.accountsLogin }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
370
|
+
__esDecorate(this, null, _accountsOidcStart_decorators, { kind: "method", name: "accountsOidcStart", static: false, private: false, access: { has: obj => "accountsOidcStart" in obj, get: obj => obj.accountsOidcStart }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
371
|
+
__esDecorate(this, null, _accountsOidcComplete_decorators, { kind: "method", name: "accountsOidcComplete", static: false, private: false, access: { has: obj => "accountsOidcComplete" in obj, get: obj => obj.accountsOidcComplete }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
372
|
+
__esDecorate(this, null, _accountsOidcLogout_decorators, { kind: "method", name: "accountsOidcLogout", static: false, private: false, access: { has: obj => "accountsOidcLogout" in obj, get: obj => obj.accountsOidcLogout }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
347
373
|
__esDecorate(this, null, _accountsChangePassword_decorators, { kind: "method", name: "accountsChangePassword", static: false, private: false, access: { has: obj => "accountsChangePassword" in obj, get: obj => obj.accountsChangePassword }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
348
374
|
__esDecorate(this, null, _accountsRequestPasswordReset_decorators, { kind: "method", name: "accountsRequestPasswordReset", static: false, private: false, access: { has: obj => "accountsRequestPasswordReset" in obj, get: obj => obj.accountsRequestPasswordReset }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
349
375
|
__esDecorate(this, null, _accountsWhoami_decorators, { kind: "method", name: "accountsWhoami", static: false, private: false, access: { has: obj => "accountsWhoami" in obj, get: obj => obj.accountsWhoami }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -424,6 +450,12 @@ let QaSurface = (() => {
|
|
|
424
450
|
__esDecorate(this, null, _pendingApprovals_decorators, { kind: "method", name: "pendingApprovals", static: false, private: false, access: { has: obj => "pendingApprovals" in obj, get: obj => obj.pendingApprovals }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
425
451
|
__esDecorate(this, null, _answerApproval_decorators, { kind: "method", name: "answerApproval", static: false, private: false, access: { has: obj => "answerApproval" in obj, get: obj => obj.answerApproval }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
426
452
|
__esDecorate(this, null, _pendingQuestions_decorators, { kind: "method", name: "pendingQuestions", static: false, private: false, access: { has: obj => "pendingQuestions" in obj, get: obj => obj.pendingQuestions }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
453
|
+
__esDecorate(this, null, _listForms_decorators, { kind: "method", name: "listForms", static: false, private: false, access: { has: obj => "listForms" in obj, get: obj => obj.listForms }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
454
|
+
__esDecorate(this, null, _getForm_decorators, { kind: "method", name: "getForm", static: false, private: false, access: { has: obj => "getForm" in obj, get: obj => obj.getForm }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
455
|
+
__esDecorate(this, null, _mutateForm_decorators, { kind: "method", name: "mutateForm", static: false, private: false, access: { has: obj => "mutateForm" in obj, get: obj => obj.mutateForm }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
456
|
+
__esDecorate(this, null, _validateFormStep_decorators, { kind: "method", name: "validateFormStep", static: false, private: false, access: { has: obj => "validateFormStep" in obj, get: obj => obj.validateFormStep }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
457
|
+
__esDecorate(this, null, _formCapabilities_decorators, { kind: "method", name: "formCapabilities", static: false, private: false, access: { has: obj => "formCapabilities" in obj, get: obj => obj.formCapabilities }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
458
|
+
__esDecorate(this, null, _readFormAttachment_decorators, { kind: "method", name: "readFormAttachment", static: false, private: false, access: { has: obj => "readFormAttachment" in obj, get: obj => obj.readFormAttachment }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
427
459
|
__esDecorate(this, null, _answerQuestion_decorators, { kind: "method", name: "answerQuestion", static: false, private: false, access: { has: obj => "answerQuestion" in obj, get: obj => obj.answerQuestion }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
428
460
|
__esDecorate(this, null, _cancelQuestion_decorators, { kind: "method", name: "cancelQuestion", static: false, private: false, access: { has: obj => "cancelQuestion" in obj, get: obj => obj.cancelQuestion }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
429
461
|
__esDecorate(this, null, _readSourceFile_decorators, { kind: "method", name: "readSourceFile", static: false, private: false, access: { has: obj => "readSourceFile" in obj, get: obj => obj.readSourceFile }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -453,6 +485,13 @@ let QaSurface = (() => {
|
|
|
453
485
|
approvals;
|
|
454
486
|
fileDeleteGate;
|
|
455
487
|
userQuestions;
|
|
488
|
+
formService;
|
|
489
|
+
formGate;
|
|
490
|
+
formAttachments;
|
|
491
|
+
forms() {
|
|
492
|
+
return (this.formService ??= new QaFormService(new QaFormStore(path.join(path.dirname(defaultAccountsFilePath()), "qa-forms.db")), () => this.getConfig().forms, (session) => this.accountRemotes.resolve(this.getConfig())?.ownerIdOf(session) ??
|
|
493
|
+
session));
|
|
494
|
+
}
|
|
456
495
|
provenance;
|
|
457
496
|
notes;
|
|
458
497
|
/** Assigned after the admission gate; that gate only reads it per execution. */
|
|
@@ -481,6 +520,12 @@ let QaSurface = (() => {
|
|
|
481
520
|
integrationPrincipals = new QaIntegrationPrincipalBindings();
|
|
482
521
|
webServer;
|
|
483
522
|
disposeRoute;
|
|
523
|
+
oidc = new QaOidcService({
|
|
524
|
+
config: () => this.getConfig(),
|
|
525
|
+
accounts: () => this.accountRemotes.resolve(this.getConfig()),
|
|
526
|
+
});
|
|
527
|
+
disposeOidcRoute;
|
|
528
|
+
oidcRouteKey;
|
|
484
529
|
routeKey;
|
|
485
530
|
/**
|
|
486
531
|
* The HTTP API an external application asks questions through. Constructed
|
|
@@ -498,6 +543,7 @@ let QaSurface = (() => {
|
|
|
498
543
|
chatSharingStore;
|
|
499
544
|
chatTransport;
|
|
500
545
|
chatTurnGuard;
|
|
546
|
+
requestScheduler;
|
|
501
547
|
sharing() {
|
|
502
548
|
const accounts = () => {
|
|
503
549
|
const store = this.accountRemotes.resolve(this.getConfig());
|
|
@@ -514,10 +560,13 @@ let QaSurface = (() => {
|
|
|
514
560
|
// the one live source: each read folds its current snapshots, and a settings
|
|
515
561
|
// write is visible on the next read without reloading the plugin.
|
|
516
562
|
this.source = () => readConfigRefs(entry);
|
|
563
|
+
this.requestScheduler = new QaRequestScheduler(() => this.getConfig().session.maxActiveRequests, () => qaRequestRoots(ctx, this.getConfig().session.maxActiveRequests > 0), Date.now, (agent) => qaRequestFamilyBusy(ctx, agent));
|
|
564
|
+
ctx.effect(() => this.requestScheduler.install(ctx), "dsh-qa-surface.request-queue");
|
|
517
565
|
this.logger = getPluginLogger({
|
|
518
566
|
pluginId: "dsh-qa-surface",
|
|
519
567
|
consoleSink: createHostLoggerSink(ctx.logger),
|
|
520
568
|
});
|
|
569
|
+
this.formAttachments = new QaFormAttachmentAdapter(() => this.forms(), () => ctx.get("attachments"), (sessionId, file) => this.admission.grantAttachmentFile(sessionId, file));
|
|
521
570
|
this.accountRemotes = createQaAccountRemotes({
|
|
522
571
|
getConfig: () => this.getConfig(),
|
|
523
572
|
logger: this.logger,
|
|
@@ -617,7 +666,16 @@ let QaSurface = (() => {
|
|
|
617
666
|
// that is where the caller's account has just been matched against the
|
|
618
667
|
// ownership record. The browser's `secureSession` remote keeps its own
|
|
619
668
|
// write: there the compared identity is the token's.
|
|
620
|
-
this.integrationPrincipals
|
|
669
|
+
this.integrationPrincipals, {
|
|
670
|
+
readEvents: async (sessionId) => {
|
|
671
|
+
const result = await sessionLog.read(sessionId);
|
|
672
|
+
return result.ok ? result.events : [];
|
|
673
|
+
},
|
|
674
|
+
restoreFiles: async (sessionId) => {
|
|
675
|
+
if (this.getConfig().forms.enabled)
|
|
676
|
+
await this.formAttachments.restore(sessionId);
|
|
677
|
+
},
|
|
678
|
+
});
|
|
621
679
|
this.provenance = new QaProvenanceHost(ctx, () => this.getConfig(),
|
|
622
680
|
// Sharded per chat and bounded by the resolved retention policy: the
|
|
623
681
|
// turn path must never rewrite history it did not touch.
|
|
@@ -632,7 +690,7 @@ let QaSurface = (() => {
|
|
|
632
690
|
}, "dsh-qa-surface.chat-sharing");
|
|
633
691
|
ctx.inject(["typertGateway", "connection"], () => {
|
|
634
692
|
const dispose = installQaNativeFence(ctx, () => this.getConfig().accounts.enabled);
|
|
635
|
-
const disposeUploads = installQaChatUploads(ctx, () => this.sharing(), (token, id) => this.secureSession(token, id));
|
|
693
|
+
const disposeUploads = installQaChatUploads(ctx, () => this.sharing(), (token, id) => this.secureSession(token, id), this.formAttachments);
|
|
636
694
|
return async () => {
|
|
637
695
|
dispose();
|
|
638
696
|
await disposeUploads();
|
|
@@ -671,7 +729,20 @@ let QaSurface = (() => {
|
|
|
671
729
|
this.approvals = new QaApprovalGate(ctx, () => this.getConfig().interaction.approvals === "interactive", ownership, this.logger);
|
|
672
730
|
const integrationQuestionPolicy = new QaIntegrationQuestionPolicy(ctx, () => this.accountRemotes.resolve(this.getConfig()), (id) => ownership.rootOf(id));
|
|
673
731
|
ctx.effect(() => () => integrationQuestionPolicy.dispose(), "qa-surface: integration question policy");
|
|
674
|
-
this.userQuestions = new QaQuestionGate(ctx, () => this.getConfig().interaction.questions === "interactive", ownership, this.logger, (agent) => integrationQuestionPolicy.allowed(agent)
|
|
732
|
+
this.userQuestions = new QaQuestionGate(ctx, () => this.getConfig().interaction.questions === "interactive", ownership, this.logger, (agent) => integrationQuestionPolicy.allowed(agent) &&
|
|
733
|
+
!this.formGate?.hasSession(ownership.rootOf(String(agent.session.id)) ?? ""));
|
|
734
|
+
this.formGate = new QaFormGate(() => this.forms(), (id) => ownership.rootOf(id), (id) => this.userQuestions.list(id).length > 0 ||
|
|
735
|
+
this.approvals.list(id).length > 0, (exec) => this.getConfig().forms.enabled &&
|
|
736
|
+
exec.agent !== undefined &&
|
|
737
|
+
integrationQuestionPolicy.allowed(exec.agent) &&
|
|
738
|
+
this.admission.knowsSession(String(exec.agent.session.id)), () => this.getConfig().accounts.enabled &&
|
|
739
|
+
this.ctx.get("fileUploads") !== undefined &&
|
|
740
|
+
this.formAttachments.available());
|
|
741
|
+
this.formGate.install(ctx);
|
|
742
|
+
ctx.effect(() => () => {
|
|
743
|
+
this.formGate.dispose();
|
|
744
|
+
this.formService?.store.close();
|
|
745
|
+
}, "dsh-qa-surface.forms");
|
|
675
746
|
// The destructive tool of the QA catalog composes the same approval flow
|
|
676
747
|
// around itself: registered without `prepend`, it sits inside the approval
|
|
677
748
|
// gate and answers `ask` for every file_delete call of an attested chat,
|
|
@@ -722,6 +793,9 @@ let QaSurface = (() => {
|
|
|
722
793
|
// The QA tool catalog is attached per agent, never at boot: nothing here
|
|
723
794
|
// reaches the model until a managed agent loads the activation skill.
|
|
724
795
|
this.tools = new QaTools(ctx, {
|
|
796
|
+
forms: this.formGate,
|
|
797
|
+
formsEnabled: () => this.getConfig().forms.enabled,
|
|
798
|
+
formProjection: (submission, sessionId) => this.formAttachments.readable(submission, sessionId),
|
|
725
799
|
logger: this.logger,
|
|
726
800
|
dynamicActivation: this.getConfig().tools.dynamicActivation,
|
|
727
801
|
activationSkill: this.getConfig().tools.activationSkill,
|
|
@@ -734,6 +808,12 @@ let QaSurface = (() => {
|
|
|
734
808
|
docsDefaultVersion: () => docsDefaultVersionOf(this.getConfig().tools),
|
|
735
809
|
});
|
|
736
810
|
ctx.effect(() => () => this.tools.dispose(), "dsh-qa-surface.qa-tools");
|
|
811
|
+
const listenVolatile = ctx.on.bind(ctx);
|
|
812
|
+
ctx.effect(() => listenVolatile("loader/volatile-update", () => {
|
|
813
|
+
this.tools.refreshForms();
|
|
814
|
+
if (!this.getConfig().forms.enabled)
|
|
815
|
+
this.formGate.cancelAll();
|
|
816
|
+
}), "dsh-qa-surface.form-policy");
|
|
737
817
|
// The root index gains one head script: non-loopback hostnames continue
|
|
738
818
|
// into /qa, the loopback operator keeps the full harness UI. Not in the
|
|
739
819
|
// kiosk composition: there the index itself is served under /qa, so the
|
|
@@ -760,6 +840,7 @@ let QaSurface = (() => {
|
|
|
760
840
|
const config = this.getConfig();
|
|
761
841
|
this.refreshRoute();
|
|
762
842
|
this.refreshIntegrationRoutes();
|
|
843
|
+
this.refreshOidcRoute();
|
|
763
844
|
this.warnDocumentsMoved();
|
|
764
845
|
this.warnLegacySlashDefaults();
|
|
765
846
|
this.logger.info("config.updated", {
|
|
@@ -772,11 +853,16 @@ let QaSurface = (() => {
|
|
|
772
853
|
this.webServer = webContext.webServer;
|
|
773
854
|
this.refreshRoute();
|
|
774
855
|
this.refreshIntegrationRoutes();
|
|
856
|
+
this.refreshOidcRoute();
|
|
775
857
|
webContext.effect(() => () => {
|
|
776
858
|
this.disposeRoute?.();
|
|
777
859
|
this.disposeRoute = undefined;
|
|
778
860
|
this.routeKey = undefined;
|
|
779
861
|
this.disposeIntegrationRoutes?.();
|
|
862
|
+
this.disposeOidcRoute?.();
|
|
863
|
+
this.disposeOidcRoute = undefined;
|
|
864
|
+
this.oidcRouteKey = undefined;
|
|
865
|
+
this.oidc.clear();
|
|
780
866
|
this.disposeIntegrationRoutes = undefined;
|
|
781
867
|
this.integrationRouteKey = undefined;
|
|
782
868
|
this.webServer = undefined;
|
|
@@ -827,6 +913,10 @@ let QaSurface = (() => {
|
|
|
827
913
|
* cannot be opened must not fail the page that triggered it.
|
|
828
914
|
*/
|
|
829
915
|
dropVanishedChats(sessionIds) {
|
|
916
|
+
for (const id of sessionIds) {
|
|
917
|
+
this.formGate?.cancel(id);
|
|
918
|
+
this.formService?.store.cancelSession(id);
|
|
919
|
+
}
|
|
830
920
|
try {
|
|
831
921
|
const rows = this.quality().dropConversations(sessionIds);
|
|
832
922
|
this.logger.info("quality.vanished-conversations-dropped", {
|
|
@@ -927,6 +1017,17 @@ let QaSurface = (() => {
|
|
|
927
1017
|
accountsLogin(email, password) {
|
|
928
1018
|
return this.accountRemotes.login(email, password);
|
|
929
1019
|
}
|
|
1020
|
+
accountsOidcStart() {
|
|
1021
|
+
if (!this.disposeOidcRoute)
|
|
1022
|
+
return Promise.reject(oidcRefusal());
|
|
1023
|
+
return this.oidc.start();
|
|
1024
|
+
}
|
|
1025
|
+
accountsOidcComplete(handoff, completionKey) {
|
|
1026
|
+
return this.oidc.complete(handoff, completionKey);
|
|
1027
|
+
}
|
|
1028
|
+
accountsOidcLogout(token) {
|
|
1029
|
+
return this.oidc.logout(token);
|
|
1030
|
+
}
|
|
930
1031
|
/** Identity probe; safe to call with an empty or expired token. */
|
|
931
1032
|
accountsChangePassword(token, currentPassword, nextPassword) {
|
|
932
1033
|
return this.accountRemotes.changePassword(token, currentPassword, nextPassword);
|
|
@@ -1028,20 +1129,15 @@ let QaSurface = (() => {
|
|
|
1028
1129
|
return this.getConfig();
|
|
1029
1130
|
}
|
|
1030
1131
|
/**
|
|
1031
|
-
* Report
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
* The count is the Host's, not the browser's: a visitor cannot see another
|
|
1036
|
-
* account's chats, and the HTTP API's questions are invisible to every chat
|
|
1037
|
-
* view. Read-only, and a ceiling rather than a lock — a prompt rides the
|
|
1038
|
-
* native session RPC this plugin does not own, so the boundary is the
|
|
1039
|
-
* browser's own courtesy, and two questions sent in the same instant can
|
|
1040
|
-
* still overshoot by one. What the ceiling buys is that steady state, not a
|
|
1041
|
-
* strict bound.
|
|
1132
|
+
* Report server admission. Global reads expose counts only; a chat's FIFO
|
|
1133
|
+
* position requires that account's current read access to the chat. The
|
|
1134
|
+
* scheduler gates every root turn, including native and integration sends.
|
|
1042
1135
|
*/
|
|
1043
|
-
queueStatus() {
|
|
1044
|
-
|
|
1136
|
+
queueStatus(token, sessionId) {
|
|
1137
|
+
if (sessionId !== undefined && this.getConfig().accounts.enabled) {
|
|
1138
|
+
this.sharing().access(token ?? "", sessionId);
|
|
1139
|
+
}
|
|
1140
|
+
return this.requestScheduler.status(sessionId);
|
|
1045
1141
|
}
|
|
1046
1142
|
/**
|
|
1047
1143
|
* Create a QA session from Host-owned inputs. With account workspaces on,
|
|
@@ -1050,65 +1146,26 @@ let QaSurface = (() => {
|
|
|
1050
1146
|
*/
|
|
1051
1147
|
async createSession(token, subroleId, adminPreview) {
|
|
1052
1148
|
const config = this.getConfig();
|
|
1053
|
-
if (config.session.policy === "fixed") {
|
|
1054
|
-
throw new Error("Fixed QA sessions cannot be created.");
|
|
1055
|
-
}
|
|
1056
|
-
const id = SessionId(`session-${randomUUID()}`);
|
|
1057
1149
|
const accounts = this.accountRemotes.resolve(config);
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
const created = await this.ctx.sessionController.create({
|
|
1078
|
-
sessionId: id,
|
|
1079
|
-
...(userCwd !== undefined
|
|
1080
|
-
? { cwd: userCwd }
|
|
1081
|
-
: config.session.workspaceId !== null
|
|
1082
|
-
? { workspaceId: WorkspaceId(config.session.workspaceId) }
|
|
1083
|
-
: config.session.cwd !== null
|
|
1084
|
-
? { cwd: config.session.cwd }
|
|
1085
|
-
: {}),
|
|
1086
|
-
...(config.session.agentPreset === null
|
|
1087
|
-
? {}
|
|
1088
|
-
: { agentPreset: config.session.agentPreset }),
|
|
1089
|
-
});
|
|
1090
|
-
await applySessionModelPolicy(this.ctx, created.sessionId, this.access.modelPolicyFor(String(created.sessionId)), this.logger);
|
|
1091
|
-
const sessionId = String(created.sessionId);
|
|
1092
|
-
await this.admission.secureSession(token, sessionId);
|
|
1093
|
-
this.integrationPrincipals.attest(sessionId, owner?.id, accounts?.ownerIdOf(sessionId));
|
|
1094
|
-
return sessionId;
|
|
1095
|
-
}
|
|
1096
|
-
catch (error) {
|
|
1097
|
-
// This call is the only way the browser could have learned the id, so a
|
|
1098
|
-
// failure at any stage — the Host creating the session, selecting the
|
|
1099
|
-
// model, the admission refusing the composition — leaves no chat behind
|
|
1100
|
-
// and the reservation goes with it. A kept record would put an empty
|
|
1101
|
-
// chat in the account's list, and nothing else would ever remove it.
|
|
1102
|
-
if (owner !== undefined) {
|
|
1103
|
-
accounts?.releaseSessionReservation(owner.id, String(id));
|
|
1104
|
-
}
|
|
1105
|
-
this.logger.error("session.create-rejected", {
|
|
1106
|
-
sessionId: String(id),
|
|
1107
|
-
reason: error instanceof QaAttestationError ? error.reason : undefined,
|
|
1108
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1109
|
-
});
|
|
1110
|
-
throw new Error(qaAttestationFailureMessage("Unable to create a QA session.", error), { cause: error });
|
|
1111
|
-
}
|
|
1150
|
+
return createQaSession({
|
|
1151
|
+
ctx: this.ctx,
|
|
1152
|
+
config,
|
|
1153
|
+
logger: this.logger,
|
|
1154
|
+
sessionFiles: createSessionEraser(),
|
|
1155
|
+
reserve: (id) => accounts === undefined
|
|
1156
|
+
? undefined
|
|
1157
|
+
: this.accountRemotes.run(() => this.access.reserveSession(token, id, subroleId, adminPreview)),
|
|
1158
|
+
release: (owner, id) => accounts?.releaseSessionReservation(owner, id),
|
|
1159
|
+
modelPolicy: (id) => this.access.modelPolicyFor(id),
|
|
1160
|
+
preflight: () => this.admission.preflightDeployment(),
|
|
1161
|
+
admit: (id) => this.admission.secureSession(token, id),
|
|
1162
|
+
attest: (id, owner) => this.integrationPrincipals.attest(id, owner, accounts?.ownerIdOf(id)),
|
|
1163
|
+
reject: (id) => {
|
|
1164
|
+
this.integrationPrincipals.attest(id, undefined, undefined);
|
|
1165
|
+
this.admission.rejectSession(id);
|
|
1166
|
+
},
|
|
1167
|
+
forget: (id) => this.admission.forgetRejectedSession(id),
|
|
1168
|
+
});
|
|
1112
1169
|
}
|
|
1113
1170
|
/** Create an independently admitted ordinary branch of the caller's own chat. */
|
|
1114
1171
|
async forkSession(token, sourceId, answerSeq) {
|
|
@@ -1406,7 +1463,9 @@ let QaSurface = (() => {
|
|
|
1406
1463
|
}
|
|
1407
1464
|
async chatAudit(token, sessionId, full) {
|
|
1408
1465
|
this.requireChatOwner(token, sessionId);
|
|
1409
|
-
|
|
1466
|
+
// Sidebar summaries read stored audit metadata; they do not need an agent.
|
|
1467
|
+
if (full)
|
|
1468
|
+
await this.secureSession(token, sessionId);
|
|
1410
1469
|
this.requireChatOwner(token, sessionId);
|
|
1411
1470
|
const audit = this.ctx.get("sessionAudit");
|
|
1412
1471
|
if (audit === undefined)
|
|
@@ -1523,6 +1582,115 @@ let QaSurface = (() => {
|
|
|
1523
1582
|
return [];
|
|
1524
1583
|
return this.userQuestions.list(sessionId);
|
|
1525
1584
|
}
|
|
1585
|
+
/** Forms stay owner-scoped; UUIDs and a browser-supplied session never grant access. */
|
|
1586
|
+
async admitForm(token, sessionId) {
|
|
1587
|
+
try {
|
|
1588
|
+
this.requireChatOwner(token, sessionId);
|
|
1589
|
+
await this.secureSession(token, sessionId);
|
|
1590
|
+
this.requireChatOwner(token, sessionId);
|
|
1591
|
+
}
|
|
1592
|
+
catch {
|
|
1593
|
+
throw new QaFormError("ACCESS_DENIED", "Form access is unavailable.");
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
async listForms(token, sessionId) {
|
|
1597
|
+
try {
|
|
1598
|
+
await this.admitForm(token, sessionId);
|
|
1599
|
+
if (!this.getConfig().forms.enabled)
|
|
1600
|
+
return { ok: true, value: [] };
|
|
1601
|
+
this.formGate.touch(sessionId);
|
|
1602
|
+
const service = this.forms();
|
|
1603
|
+
return {
|
|
1604
|
+
ok: true,
|
|
1605
|
+
value: service.store
|
|
1606
|
+
.list(sessionId)
|
|
1607
|
+
.map((r) => service.view(r, this.formGate.waiting(r.id))),
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
catch (error) {
|
|
1611
|
+
return formFailure(error);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
async getForm(token, sessionId, formId) {
|
|
1615
|
+
try {
|
|
1616
|
+
await this.admitForm(token, sessionId);
|
|
1617
|
+
const s = this.forms();
|
|
1618
|
+
return {
|
|
1619
|
+
ok: true,
|
|
1620
|
+
value: s.view(s.get(sessionId, formId), this.formGate.waiting(formId)),
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
catch (error) {
|
|
1624
|
+
return formFailure(error);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
async mutateForm(token, sessionId, command) {
|
|
1628
|
+
try {
|
|
1629
|
+
await this.admitForm(token, sessionId);
|
|
1630
|
+
const s = this.forms(), r = s.command(sessionId, command);
|
|
1631
|
+
this.logger.info("form.mutated", {
|
|
1632
|
+
sessionId,
|
|
1633
|
+
formId: r.id,
|
|
1634
|
+
action: command.action,
|
|
1635
|
+
revision: r.revision,
|
|
1636
|
+
status: r.status,
|
|
1637
|
+
});
|
|
1638
|
+
this.formGate.notify(r, command.action === "pause");
|
|
1639
|
+
return { ok: true, value: s.view(r, this.formGate.waiting(r.id)) };
|
|
1640
|
+
}
|
|
1641
|
+
catch (error) {
|
|
1642
|
+
return formFailure(error);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
async validateFormStep(token, sessionId, formId, stepId, revision) {
|
|
1646
|
+
try {
|
|
1647
|
+
await this.admitForm(token, sessionId);
|
|
1648
|
+
this.forms().step(sessionId, formId, stepId, revision);
|
|
1649
|
+
return { ok: true, value: null };
|
|
1650
|
+
}
|
|
1651
|
+
catch (error) {
|
|
1652
|
+
return formFailure(error);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
async formCapabilities() {
|
|
1656
|
+
return {
|
|
1657
|
+
enabled: this.getConfig().forms.enabled,
|
|
1658
|
+
schemaVersion: 1,
|
|
1659
|
+
upload: this.getConfig().accounts.enabled &&
|
|
1660
|
+
this.ctx.get("fileUploads") !== undefined &&
|
|
1661
|
+
this.formAttachments.available(),
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
async readFormAttachment(token, sessionId, formId, resourceId) {
|
|
1665
|
+
try {
|
|
1666
|
+
await this.admitForm(token, sessionId);
|
|
1667
|
+
const s = this.forms(), r = s.get(sessionId, formId);
|
|
1668
|
+
const file = Object.values(r.attachments)
|
|
1669
|
+
.flat()
|
|
1670
|
+
.find((f) => f.resource_id === resourceId);
|
|
1671
|
+
if (!file)
|
|
1672
|
+
return {
|
|
1673
|
+
ok: false,
|
|
1674
|
+
error: {
|
|
1675
|
+
code: "ACCESS_DENIED",
|
|
1676
|
+
message: "File access is unavailable.",
|
|
1677
|
+
},
|
|
1678
|
+
};
|
|
1679
|
+
const data = s.store.resource(formId, resourceId);
|
|
1680
|
+
this.requireChatOwner(token, sessionId);
|
|
1681
|
+
return {
|
|
1682
|
+
ok: true,
|
|
1683
|
+
value: {
|
|
1684
|
+
name: file.name,
|
|
1685
|
+
media_type: file.media_type,
|
|
1686
|
+
data: Buffer.from(data).toString("base64"),
|
|
1687
|
+
},
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
catch (error) {
|
|
1691
|
+
return formFailure(error);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1526
1694
|
/**
|
|
1527
1695
|
* Apply the operator's answers to one parked question request. Every question
|
|
1528
1696
|
* of the request must be present in `answers`; one the browser omits reads as
|
|
@@ -1901,6 +2069,28 @@ let QaSurface = (() => {
|
|
|
1901
2069
|
});
|
|
1902
2070
|
}
|
|
1903
2071
|
}
|
|
2072
|
+
refreshOidcRoute() {
|
|
2073
|
+
const config = this.getConfig();
|
|
2074
|
+
const key = config.enabled && config.accounts.enabled && config.accounts.oidc.enabled
|
|
2075
|
+
? JSON.stringify([config.accounts.oidc, config.route.path])
|
|
2076
|
+
: undefined;
|
|
2077
|
+
if (key === this.oidcRouteKey)
|
|
2078
|
+
return;
|
|
2079
|
+
this.disposeOidcRoute?.();
|
|
2080
|
+
this.disposeOidcRoute = undefined;
|
|
2081
|
+
this.oidcRouteKey = undefined;
|
|
2082
|
+
this.oidc.clear();
|
|
2083
|
+
if (!key || !this.webServer)
|
|
2084
|
+
return;
|
|
2085
|
+
try {
|
|
2086
|
+
this.disposeOidcRoute = registerQaOidcRoute(this.webServer, config, this.oidc);
|
|
2087
|
+
this.oidcRouteKey = key;
|
|
2088
|
+
this.logger.info("oidc.route-registered", {});
|
|
2089
|
+
}
|
|
2090
|
+
catch {
|
|
2091
|
+
this.logger.error("oidc.route-unavailable", {});
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
1904
2094
|
refreshRoute() {
|
|
1905
2095
|
const config = this.getConfig();
|
|
1906
2096
|
// Kiosk: the harness route policy owns the QA paths and serves the
|