@noodleseed/one 0.177.0 → 0.179.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/dist/commands/solutions-activity.d.ts.map +1 -1
- package/dist/commands/solutions-activity.js +9 -35
- package/dist/commands/solutions-activity.js.map +1 -1
- package/dist/commands/solutions-conversations.d.ts.map +1 -1
- package/dist/commands/solutions-conversations.js +65 -6
- package/dist/commands/solutions-conversations.js.map +1 -1
- package/dist/commands/solutions-history.d.ts +9 -0
- package/dist/commands/solutions-history.d.ts.map +1 -0
- package/dist/commands/solutions-history.js +166 -0
- package/dist/commands/solutions-history.js.map +1 -0
- package/dist/commands/solutions-ops.d.ts.map +1 -1
- package/dist/commands/solutions-ops.js +3 -0
- package/dist/commands/solutions-ops.js.map +1 -1
- package/dist/commands/whatsapp-ops.d.ts.map +1 -1
- package/dist/commands/whatsapp-ops.js +0 -7
- package/dist/commands/whatsapp-ops.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +14 -0
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/public-surface.d.ts +6 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/public-surface.js +5 -2
- package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -1
- package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts +18 -0
- package/node_modules/@noodle-borg/authoring/dist/assistant.js +14 -1
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-channels.js +0 -3
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-conversations.js +50 -5
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solution-history.js +82 -0
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-solutions.js +3 -42
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +8 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +7 -0
- package/node_modules/@noodle-borg/service/dist/application-activity.js +76 -21
- package/node_modules/@noodle-borg/service/dist/application-history-settings.js +108 -0
- package/node_modules/@noodle-borg/service/dist/assistant-composition.js +11 -2
- package/node_modules/@noodle-borg/service/dist/business-information/contracts.d.ts +3 -1
- package/node_modules/@noodle-borg/service/dist/business-information/workspace-permissions.js +1 -0
- package/node_modules/@noodle-borg/service/dist/channels/composition.js +10 -1
- package/node_modules/@noodle-borg/service/dist/channels/provider.js +13 -13
- package/node_modules/@noodle-borg/service/dist/channels/runtime.js +31 -5
- package/node_modules/@noodle-borg/service/dist/conversation-history/capture.js +63 -7
- package/node_modules/@noodle-borg/service/dist/conversation-history/contracts.js +13 -0
- package/node_modules/@noodle-borg/service/dist/conversation-history/customer.js +118 -0
- package/node_modules/@noodle-borg/service/dist/conversation-history/operator.js +147 -24
- package/node_modules/@noodle-borg/service/dist/conversation-history/preview.js +43 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-conversations.js +52 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-dispatch.js +6 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-elevation.js +3 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-stream.js +2 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +6 -11
- package/node_modules/@noodle-borg/service/dist/routes/assistant-public-session.js +6 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-route-http.js +16 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js +5 -17
- package/node_modules/@noodle-borg/service/dist/routes/business-information-activity.js +6 -5
- package/node_modules/@noodle-borg/service/dist/routes/business-information-conversations.js +67 -13
- package/node_modules/@noodle-borg/service/dist/routes/business-information-dispatch.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/business-information-paths.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/business-information.js +4 -0
- package/node_modules/@noodle-borg/service/dist/routes/whatsapp.js +0 -10
- package/node_modules/@noodle-borg/service/dist/service-history-projections.js +35 -4
- package/node_modules/@noodle-borg/service/dist/service-resource-cleanup.js +32 -0
- package/node_modules/@noodle-borg/service/dist/service.js +4 -3
- package/node_modules/@noodle-borg/service/package.json +1 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/application-activity.d.ts +0 -28
- package/node_modules/@noodle-borg/wire-contracts/dist/application-activity.js +0 -18
- package/node_modules/@noodle-borg/wire-contracts/dist/application-history-settings.d.ts +190 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/application-history-settings.js +92 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/assistant.d.ts +3 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/assistant.js +6 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/conversation-history.d.ts +182 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/conversation-history.js +78 -2
- package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/index.js +1 -0
- package/node_modules/@noodleseed/assistant/README.md +19 -0
- package/node_modules/@noodleseed/assistant/package.json +1 -1
- package/package.json +2 -2
|
@@ -1,25 +1,45 @@
|
|
|
1
1
|
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
2
|
+
import { ConversationReviewRequestSchema } from '@noodle-borg/wire-contracts';
|
|
3
|
+
import { businessGrantAllows } from '../business-information/model.js';
|
|
2
4
|
import { ConversationHistoryError, } from '../conversation-history/operator.js';
|
|
5
|
+
import { sendForbidden } from '../http-util.js';
|
|
3
6
|
import { requireIdentity, requireInstallationPermission, } from './business-information.js';
|
|
4
|
-
|
|
7
|
+
import { resolveBusinessStaffGrant } from './business-information-access.js';
|
|
8
|
+
/**
|
|
9
|
+
* ADR 0241 decision 10: readers see text; reviewing and noting need the record-handling permissions an
|
|
10
|
+
* Operator holds; only export and erasure need Owner/Administrator authority.
|
|
11
|
+
*/
|
|
5
12
|
const PERMISSIONS = {
|
|
6
13
|
list: 'records:read',
|
|
7
14
|
show: 'records:read',
|
|
8
15
|
export: 'records:export',
|
|
9
16
|
forget: 'records:delete',
|
|
10
17
|
};
|
|
18
|
+
const METHODS = { list: ['GET'], show: ['GET', 'PATCH'], export: ['GET'], forget: ['POST'] };
|
|
11
19
|
export async function handleApplicationConversations(req, res, url, ref, deps) {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
if (req.method
|
|
15
|
-
res.setHeader('allow',
|
|
20
|
+
const route = ref.conversationAction ?? 'list';
|
|
21
|
+
const methods = METHODS[route];
|
|
22
|
+
if (!methods.includes(req.method ?? '')) {
|
|
23
|
+
res.setHeader('allow', methods.join(', '));
|
|
16
24
|
return sendJson(res, 405, { error: 'method not allowed' });
|
|
17
25
|
}
|
|
26
|
+
const action = req.method === 'PATCH' ? 'review' : route;
|
|
18
27
|
const identity = await requireIdentity(req, res, deps);
|
|
19
28
|
if (identity === false)
|
|
20
29
|
return;
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
// A review's permissions follow its fields, so it is read-authorized before its body is parsed.
|
|
31
|
+
let permissions = [
|
|
32
|
+
action === 'list' || action === 'show'
|
|
33
|
+
? await readPermission(ref, identity, deps)
|
|
34
|
+
: PERMISSIONS[route],
|
|
35
|
+
];
|
|
36
|
+
const authorize = async () => {
|
|
37
|
+
const [last = PERMISSIONS[route], ...earlier] = [...permissions].reverse();
|
|
38
|
+
for (const permission of earlier)
|
|
39
|
+
if (!(await requireInstallationPermission(res, ref, identity, permission, deps)))
|
|
40
|
+
return false;
|
|
41
|
+
return requireInstallationPermission(res, ref, identity, last, deps);
|
|
42
|
+
};
|
|
23
43
|
const authorized = await authorize();
|
|
24
44
|
if (!authorized)
|
|
25
45
|
return;
|
|
@@ -28,29 +48,45 @@ export async function handleApplicationConversations(req, res, url, ref, deps) {
|
|
|
28
48
|
if (!deps.conversations)
|
|
29
49
|
throw new ConversationHistoryError('conversation_unavailable');
|
|
30
50
|
let body;
|
|
31
|
-
if (method
|
|
51
|
+
if (req.method !== 'GET') {
|
|
32
52
|
const parsed = await readJsonBody(req, deps.maxBody);
|
|
33
53
|
if (!parsed.ok)
|
|
34
54
|
return sendJson(res, parsed.status, { error: parsed.error });
|
|
35
55
|
body = parsed.value;
|
|
56
|
+
if (action === 'review') {
|
|
57
|
+
const review = ConversationReviewRequestSchema.safeParse(body);
|
|
58
|
+
if (!review.success)
|
|
59
|
+
throw new ConversationHistoryError('conversation_invalid');
|
|
60
|
+
permissions = [
|
|
61
|
+
...(review.data.reviewStatus === undefined ? [] : ['records:status']),
|
|
62
|
+
...(review.data.note === undefined ? [] : ['records:note']),
|
|
63
|
+
];
|
|
64
|
+
}
|
|
36
65
|
if (!(await authorize()))
|
|
37
66
|
return;
|
|
38
67
|
}
|
|
68
|
+
const fence = permissions.at(-1) ?? PERMISSIONS[route];
|
|
39
69
|
const result = await deps.conversations.project(authorized.scope, action, {
|
|
40
70
|
parameters: [...url.searchParams.entries()],
|
|
41
71
|
...(ref.conversationId === undefined ? {} : { conversationId: ref.conversationId }),
|
|
42
72
|
body,
|
|
43
|
-
|
|
44
|
-
|
|
73
|
+
actor: identity.subject,
|
|
74
|
+
...(deps.forgetWhatsApp ? { forgetWorkingMemory: deps.forgetWhatsApp } : {}),
|
|
75
|
+
}, (operation) => deps.store.staff.run(authorized.scope, identity.subject, fence, operation));
|
|
76
|
+
for (const event of result.audits)
|
|
45
77
|
await deps.audit?.emit({
|
|
46
|
-
...
|
|
78
|
+
...event,
|
|
47
79
|
org: ref.org,
|
|
48
80
|
app: authorized.scope.app,
|
|
49
81
|
env: authorized.scope.env,
|
|
50
82
|
actorSubject: identity.subject,
|
|
51
83
|
});
|
|
52
|
-
if (await authorize())
|
|
53
|
-
|
|
84
|
+
if (!(await authorize()))
|
|
85
|
+
return;
|
|
86
|
+
// A Preview read is answered only while the environment is still a Preview.
|
|
87
|
+
if (fence === 'drafts:preview' && !(await deps.conversations.isPreview(authorized.scope)))
|
|
88
|
+
return sendForbidden(res, 'business permission required: records:read');
|
|
89
|
+
sendJson(res, 200, result.response);
|
|
54
90
|
}
|
|
55
91
|
catch (error) {
|
|
56
92
|
if (!(error instanceof ConversationHistoryError))
|
|
@@ -62,4 +98,22 @@ export async function handleApplicationConversations(req, res, url, ref, deps) {
|
|
|
62
98
|
: 400, { code: error.code, error: error.message });
|
|
63
99
|
}
|
|
64
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* ADR 0241 decision 18: a Builder never holds `records:read`, but reads a Preview environment's
|
|
103
|
+
* conversations under `drafts:preview`. Every other caller keeps the ordinary read permission, so a
|
|
104
|
+
* production installation still denies Builders.
|
|
105
|
+
*/
|
|
106
|
+
async function readPermission(ref, identity, deps) {
|
|
107
|
+
if (ref.installationId === undefined || !deps.conversations)
|
|
108
|
+
return 'records:read';
|
|
109
|
+
const installation = await deps.store.getInstallationById(ref.org, ref.installationId);
|
|
110
|
+
if (installation === undefined)
|
|
111
|
+
return 'records:read';
|
|
112
|
+
const grant = await resolveBusinessStaffGrant(deps, installation.scope, identity.subject);
|
|
113
|
+
return !businessGrantAllows(grant, 'records:read') &&
|
|
114
|
+
businessGrantAllows(grant, 'drafts:preview') &&
|
|
115
|
+
(await deps.conversations.isPreview(installation.scope))
|
|
116
|
+
? 'drafts:preview'
|
|
117
|
+
: 'records:read';
|
|
118
|
+
}
|
|
65
119
|
//# sourceMappingURL=business-information-conversations.js.map
|
|
@@ -9,7 +9,7 @@ import { SourceCapacityError } from '../business-information/source-custody-budg
|
|
|
9
9
|
import { BusinessWorkspaceError } from '../business-workspaces/contracts.js';
|
|
10
10
|
import { respondRouteError } from '../http-util.js';
|
|
11
11
|
import { handleBusinessGrants, handleManagedRecords, handleSolutionCatalog, handleSolutionInstallations, } from './business-information.js';
|
|
12
|
-
import { handleApplicationActivity
|
|
12
|
+
import { handleApplicationActivity } from './business-information-activity.js';
|
|
13
13
|
import { handleBusinessChannels, } from './business-information-channels.js';
|
|
14
14
|
import { handleApplicationConnectionCallback, handleApplicationConnections, } from './business-information-connections.js';
|
|
15
15
|
import { handleApplicationConversations, } from './business-information-conversations.js';
|
|
@@ -79,7 +79,9 @@ export function dispatchBusinessInformationRoutes(req, res, url, deps) {
|
|
|
79
79
|
return run(req, res, deps, () => handleNativeRecordLifecycle(req, res, installationRef, deps));
|
|
80
80
|
if (installationRef.action === 'notice')
|
|
81
81
|
return run(req, res, deps, () => handleBusinessNotice(req, res, installationRef, deps));
|
|
82
|
-
if ((installationRef.action === 'activity' ||
|
|
82
|
+
if ((installationRef.action === 'activity' ||
|
|
83
|
+
installationRef.action === 'history' ||
|
|
84
|
+
installationRef.action === 'coordination') &&
|
|
83
85
|
installationRef.collection === undefined)
|
|
84
86
|
return run(req, res, deps, () => handleApplicationActivity(req, res, url, installationRef, deps));
|
|
85
87
|
if (installationRef.action === 'conversations')
|
|
@@ -43,7 +43,7 @@ export function parseSolutionInstallationPath(pathname) {
|
|
|
43
43
|
: { conversationAction: 'show', conversationId: segment }),
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
-
const application = /^\/v1\/orgs\/([^/]+)\/solution-installations\/([^/]+)\/(activate|settings|notice|record-lifecycle|channels|operations\/coordination(?:\/resolve)?|activity(?:\/(?:
|
|
46
|
+
const application = /^\/v1\/orgs\/([^/]+)\/solution-installations\/([^/]+)\/(activate|settings|notice|record-lifecycle|channels|operations\/coordination(?:\/resolve)?|history\/settings|activity(?:\/(?:export|preview))?)$/.exec(pathname);
|
|
47
47
|
if (application !== null) {
|
|
48
48
|
const org = decoded(application, 1);
|
|
49
49
|
const installationId = decoded(application, 2);
|
|
@@ -56,7 +56,9 @@ export function parseSolutionInstallationPath(pathname) {
|
|
|
56
56
|
? 'coordination'
|
|
57
57
|
: application[3]?.startsWith('activity')
|
|
58
58
|
? 'activity'
|
|
59
|
-
: application[3]
|
|
59
|
+
: application[3] === 'history/settings'
|
|
60
|
+
? 'history'
|
|
61
|
+
: application[3],
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
64
|
let match = /^\/v1\/orgs\/([^/]+)\/solution-installations$/.exec(pathname);
|
|
@@ -68,6 +68,10 @@ export async function handleSolutionInstallations(req, res, ref, deps) {
|
|
|
68
68
|
code: 'installation_conflict',
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
+
// Only a created installation opts in (ADR 0241 decision 8), before activation can read the setting.
|
|
72
|
+
// Without a verified allowance it stays not enabled: recording nothing is the safe failure.
|
|
73
|
+
if (result.disposition === 'created')
|
|
74
|
+
await deps.activity?.initializeHistory(result.installation.scope).catch(() => false);
|
|
71
75
|
const grant = await resolveBusinessStaffGrant(deps, result.installation.scope, identity.subject);
|
|
72
76
|
if (grant === undefined || grant.revokedAt !== undefined) {
|
|
73
77
|
return sendForbidden(res, 'business grant required');
|
|
@@ -209,16 +209,6 @@ async function operate(req, res, url, tenant, path, runtime, grants) {
|
|
|
209
209
|
}
|
|
210
210
|
return respond(res, wire.WhatsAppCooldownResponseSchema, await channels.cooldown(id, value));
|
|
211
211
|
}
|
|
212
|
-
if (kind === 'participants' &&
|
|
213
|
-
value &&
|
|
214
|
-
participant.test(value) &&
|
|
215
|
-
action === 'forget' &&
|
|
216
|
-
req.method === 'POST') {
|
|
217
|
-
await body(req, wire.WhatsAppEmptyRequestSchema);
|
|
218
|
-
await channels.forget(id, value, identity.subject, idempotency);
|
|
219
|
-
await audit('conversation_forgotten');
|
|
220
|
-
return sendJson(res, 200, { ok: true });
|
|
221
|
-
}
|
|
222
212
|
if (kind === 'events' &&
|
|
223
213
|
(!value || eventId.test(value)) &&
|
|
224
214
|
(read || (action === 'reconcile' && req.method === 'POST'))) {
|
|
@@ -1,24 +1,55 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { ApplicationActivity } from './application-activity.js';
|
|
2
|
+
import { ActivityPolicyError, ApplicationActivity } from './application-activity.js';
|
|
3
|
+
import { historyDisabledSurfaces } from './application-history-settings.js';
|
|
3
4
|
import { ApplicationConversations } from './conversation-history/operator.js';
|
|
5
|
+
import { previewEnvironments, withPreviewConversations } from './conversation-history/preview.js';
|
|
4
6
|
/** Installation history projections over the optional durable stores the service was given. */
|
|
5
|
-
export function createHistoryProjections(options, moduleHost) {
|
|
7
|
+
export function createHistoryProjections(options, moduleHost, installations, registry) {
|
|
8
|
+
const history = options.conversationHistory;
|
|
6
9
|
const activity = options.operationEvidence === undefined
|
|
7
10
|
? undefined
|
|
8
11
|
: new ApplicationActivity({
|
|
9
12
|
...options.operationEvidence,
|
|
10
13
|
allowance: async (org, request) => moduleHost.resolveActivityHistoryAllowance?.(org, request),
|
|
14
|
+
...(history === undefined ? {} : { conversationHistory: history.store }),
|
|
15
|
+
historyDisabledSurfaces: async (scope) => historyDisabledSurfaces((await registry.getActiveByTenant(scope))?.served.artifact.server.assistant),
|
|
11
16
|
});
|
|
12
|
-
const
|
|
17
|
+
const preview = previewEnvironments(registry);
|
|
18
|
+
const conversationPolicy = withPreviewConversations(history?.policy ?? settingsConversationPolicy(installations, activity), preview);
|
|
13
19
|
const conversations = history === undefined
|
|
14
20
|
? undefined
|
|
15
21
|
: new ApplicationConversations({
|
|
16
22
|
store: history.store,
|
|
23
|
+
policy: conversationPolicy,
|
|
24
|
+
preview,
|
|
17
25
|
identityKey: history.identityKey ?? randomBytes(32).toString('hex'),
|
|
18
26
|
...(options.clock === undefined
|
|
19
27
|
? {}
|
|
20
28
|
: { now: () => options.clock?.().getTime() ?? Date.now() }),
|
|
21
29
|
});
|
|
22
|
-
return { activity, conversations };
|
|
30
|
+
return { activity, conversations, conversationPolicy };
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Capture follows the installation history setting under the live plan allowance (ADR 0241). A tenant
|
|
34
|
+
* with no single installation, setting opt-in or verified allowance records nothing, and the read never
|
|
35
|
+
* creates a setting.
|
|
36
|
+
*/
|
|
37
|
+
function settingsConversationPolicy(installations, activity) {
|
|
38
|
+
return async (tenant) => {
|
|
39
|
+
if (!installations || !activity)
|
|
40
|
+
return undefined;
|
|
41
|
+
const matching = (await installations.listInstallations(tenant.org)).filter((item) => item.scope.app === tenant.app && item.scope.env === tenant.env);
|
|
42
|
+
const installation = matching.length === 1 ? matching[0] : undefined;
|
|
43
|
+
if (!installation)
|
|
44
|
+
return undefined;
|
|
45
|
+
try {
|
|
46
|
+
return await activity.conversationPolicy(installation.scope);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error instanceof ActivityPolicyError)
|
|
50
|
+
return undefined;
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
23
54
|
}
|
|
24
55
|
//# sourceMappingURL=service-history-projections.js.map
|
|
@@ -24,6 +24,38 @@ export async function closeServiceResources(input) {
|
|
|
24
24
|
if (errors.length > 0)
|
|
25
25
|
throw new AggregateError(errors, 'service resource cleanup failed');
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Clean up after a failed boot without letting a cleanup failure replace the error that aborted startup:
|
|
29
|
+
* operators must see the bind or boot cause, while the cleanup failure is still logged.
|
|
30
|
+
*/
|
|
31
|
+
export async function cleanupAfterStartupFailure(logger, phase, cleanup) {
|
|
32
|
+
try {
|
|
33
|
+
await cleanup();
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
const code = firstErrorCode(error);
|
|
37
|
+
logger.error('service.startup_cleanup_failed', {
|
|
38
|
+
phase,
|
|
39
|
+
name: error instanceof Error ? error.name : 'unknown',
|
|
40
|
+
...(code === undefined ? {} : { code }),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** The first scalar driver/system code, searching nested cleanup aggregates depth-first. */
|
|
45
|
+
function firstErrorCode(error, depth = 0) {
|
|
46
|
+
if (typeof error !== 'object' || error === null || depth > 4)
|
|
47
|
+
return undefined;
|
|
48
|
+
if ('code' in error && typeof error.code === 'string')
|
|
49
|
+
return error.code;
|
|
50
|
+
if (!(error instanceof AggregateError))
|
|
51
|
+
return undefined;
|
|
52
|
+
for (const nested of error.errors) {
|
|
53
|
+
const code = firstErrorCode(nested, depth + 1);
|
|
54
|
+
if (code !== undefined)
|
|
55
|
+
return code;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
27
59
|
export function listenHttpServer(http, port, host) {
|
|
28
60
|
return new Promise((resolve, reject) => {
|
|
29
61
|
const onError = (error) => {
|
|
@@ -14,7 +14,7 @@ import { assistantRouteDependencies } from './assistant-composition.js';
|
|
|
14
14
|
import { resolveBuildInfo } from './build-info.js';
|
|
15
15
|
import { createBusinessInformationRuntime, resolvePrivateInstallationDefinition, } from './business-information-runtime.js';
|
|
16
16
|
import { serviceCapabilityReport } from './capabilities.js';
|
|
17
|
-
import { createWhatsAppRuntime } from './channels/composition.js';
|
|
17
|
+
import { createWhatsAppRuntime, whatsappBusinessRoutes } from './channels/composition.js';
|
|
18
18
|
import { rejectIncompatibleCli } from './client-compatibility.js';
|
|
19
19
|
import { createDataPlaneMembershipAuthorizer } from './data-plane-membership.js';
|
|
20
20
|
import { DEVELOPER_MCP_PATH, handleDeveloperMcpRequest } from './developer-mcp/mount.js';
|
|
@@ -95,7 +95,7 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
95
95
|
activeAudit = audit;
|
|
96
96
|
const { publicTenantRouting } = mcp.mcpRoutingOptions(options, controlPlane);
|
|
97
97
|
const resolveEndpointOptions = (org) => mcp.endpointUrlOptionsForOrg(options, controlPlane, org);
|
|
98
|
-
const { activity, conversations } = createHistoryProjections(options, moduleHost);
|
|
98
|
+
const { activity, conversations, conversationPolicy } = createHistoryProjections(options, moduleHost, businessInformationStore, registry);
|
|
99
99
|
const withIntentMode = createIntentTargetResolver(intentSettings, intentPreviewOrgs);
|
|
100
100
|
const { activateInstallation, readInstallationActivation, resolveRuntimeTarget, businessOnboarding, } = createApplicationServingRuntime(registry, providerOptions, controlPlane, audit, activity);
|
|
101
101
|
const runtimeTarget = async (target) => target === undefined ? undefined : resolveRuntimeTarget(target);
|
|
@@ -192,6 +192,7 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
192
192
|
maxBody,
|
|
193
193
|
serviceBase: (request) => options.publicBaseUrl ?? baseFromRequest(request, tls),
|
|
194
194
|
logger,
|
|
195
|
+
conversationPolicy,
|
|
195
196
|
});
|
|
196
197
|
const whatsapp = createWhatsAppRuntime(options.whatsapp, assistantDeps, {
|
|
197
198
|
allowance: moduleHost.resolveActivityHistoryAllowance,
|
|
@@ -302,7 +303,7 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
302
303
|
dispatchBusinessInformationRoutes(req, res, url, {
|
|
303
304
|
pageOrigin: options.businessPageOrigin,
|
|
304
305
|
pageServiceUrl: options.publicBaseUrl,
|
|
305
|
-
...(whatsapp
|
|
306
|
+
...whatsappBusinessRoutes(whatsapp),
|
|
306
307
|
store: businessInformationStore,
|
|
307
308
|
...(options.businessAuthoring ? { workspaces: options.businessAuthoring.workspaces } : {}),
|
|
308
309
|
...(businessOnboarding ? { businessOnboarding } : {}),
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@noodle-borg/managed-capabilities": "0.0.0",
|
|
42
42
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
43
43
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
44
|
-
"@noodle-borg/agent-kit": "0.
|
|
44
|
+
"@noodle-borg/agent-kit": "0.108.0",
|
|
45
45
|
"@noodle-borg/app-package": "0.0.0",
|
|
46
46
|
"@noodle-borg/assistant-gateway": "0.0.0",
|
|
47
47
|
"@noodle-borg/auth": "0.0.0",
|
|
@@ -42,25 +42,6 @@ export declare const ApplicationActivityListResponseSchema: z.ZodObject<{
|
|
|
42
42
|
historyDays: z.ZodNumber;
|
|
43
43
|
}, z.core.$strict>;
|
|
44
44
|
}, z.core.$strict>;
|
|
45
|
-
export declare const ApplicationActivitySettingsSchema: z.ZodObject<{
|
|
46
|
-
revision: z.ZodString;
|
|
47
|
-
retentionDays: z.ZodNumber;
|
|
48
|
-
maximumDays: z.ZodNumber;
|
|
49
|
-
canEdit: z.ZodBoolean;
|
|
50
|
-
}, z.core.$strict>;
|
|
51
|
-
export declare const ApplicationActivitySettingsResponseSchema: z.ZodObject<{
|
|
52
|
-
ok: z.ZodLiteral<true>;
|
|
53
|
-
data: z.ZodObject<{
|
|
54
|
-
revision: z.ZodString;
|
|
55
|
-
retentionDays: z.ZodNumber;
|
|
56
|
-
maximumDays: z.ZodNumber;
|
|
57
|
-
canEdit: z.ZodBoolean;
|
|
58
|
-
}, z.core.$strict>;
|
|
59
|
-
}, z.core.$strict>;
|
|
60
|
-
export declare const ApplicationActivitySettingsSaveRequestSchema: z.ZodObject<{
|
|
61
|
-
expectedRevision: z.ZodString;
|
|
62
|
-
retentionDays: z.ZodNumber;
|
|
63
|
-
}, z.core.$strict>;
|
|
64
45
|
/** Clients tolerate additive response fields; writes and server output remain strict. */
|
|
65
46
|
export declare const ApplicationActivityListClientResponseSchema: z.ZodObject<{
|
|
66
47
|
ok: z.ZodLiteral<true>;
|
|
@@ -87,15 +68,6 @@ export declare const ApplicationActivityListClientResponseSchema: z.ZodObject<{
|
|
|
87
68
|
historyDays: z.ZodNumber;
|
|
88
69
|
}, z.core.$strip>;
|
|
89
70
|
}, z.core.$strip>;
|
|
90
|
-
export declare const ApplicationActivitySettingsClientResponseSchema: z.ZodObject<{
|
|
91
|
-
ok: z.ZodLiteral<true>;
|
|
92
|
-
data: z.ZodObject<{
|
|
93
|
-
revision: z.ZodString;
|
|
94
|
-
retentionDays: z.ZodNumber;
|
|
95
|
-
maximumDays: z.ZodNumber;
|
|
96
|
-
canEdit: z.ZodBoolean;
|
|
97
|
-
}, z.core.$strip>;
|
|
98
|
-
}, z.core.$strip>;
|
|
99
71
|
export declare const ApplicationActivityPreviewResponseSchema: z.ZodObject<{
|
|
100
72
|
ok: z.ZodLiteral<true>;
|
|
101
73
|
data: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -18,20 +18,6 @@ export const ApplicationActivityListResponseSchema = z.strictObject({
|
|
|
18
18
|
historyDays: z.number().int().min(1).max(365),
|
|
19
19
|
}),
|
|
20
20
|
});
|
|
21
|
-
export const ApplicationActivitySettingsSchema = z.strictObject({
|
|
22
|
-
revision: z.string().regex(/^[a-f0-9]{64}$/),
|
|
23
|
-
retentionDays: z.number().int().min(1).max(365),
|
|
24
|
-
maximumDays: z.number().int().min(1).max(365),
|
|
25
|
-
canEdit: z.boolean(),
|
|
26
|
-
});
|
|
27
|
-
export const ApplicationActivitySettingsResponseSchema = z.strictObject({
|
|
28
|
-
ok: z.literal(true),
|
|
29
|
-
data: ApplicationActivitySettingsSchema,
|
|
30
|
-
});
|
|
31
|
-
export const ApplicationActivitySettingsSaveRequestSchema = z.strictObject({
|
|
32
|
-
expectedRevision: z.string().regex(/^[a-f0-9]{64}$/),
|
|
33
|
-
retentionDays: z.number().int().min(1).max(365),
|
|
34
|
-
});
|
|
35
21
|
/** Clients tolerate additive response fields; writes and server output remain strict. */
|
|
36
22
|
export const ApplicationActivityListClientResponseSchema = z.object({
|
|
37
23
|
ok: z.literal(true),
|
|
@@ -45,10 +31,6 @@ export const ApplicationActivityListClientResponseSchema = z.object({
|
|
|
45
31
|
.max(100),
|
|
46
32
|
}),
|
|
47
33
|
});
|
|
48
|
-
export const ApplicationActivitySettingsClientResponseSchema = z.object({
|
|
49
|
-
ok: z.literal(true),
|
|
50
|
-
data: z.object(ApplicationActivitySettingsSchema.shape),
|
|
51
|
-
});
|
|
52
34
|
const ActivityPreviewScenarioSchema = z.strictObject({
|
|
53
35
|
id: z.string().min(1).max(128),
|
|
54
36
|
label: z.string().min(1).max(128),
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const HistorySourcesSchema: z.ZodObject<{
|
|
3
|
+
websiteVisitors: z.ZodBoolean;
|
|
4
|
+
signedInCustomers: z.ZodBoolean;
|
|
5
|
+
whatsapp: z.ZodBoolean;
|
|
6
|
+
}, z.core.$strict>;
|
|
7
|
+
/** A surface the application declared `history: false` on, named by its authoring constructor. */
|
|
8
|
+
export declare const ApplicationHistoryDisabledSurfaceSchema: z.ZodEnum<{
|
|
9
|
+
publicWebsite: "publicWebsite";
|
|
10
|
+
authenticatedWebsite: "authenticatedWebsite";
|
|
11
|
+
publicMessaging: "publicMessaging";
|
|
12
|
+
}>;
|
|
13
|
+
export declare const ApplicationHistorySettingsSchema: z.ZodObject<{
|
|
14
|
+
revision: z.ZodString;
|
|
15
|
+
canEdit: z.ZodBoolean;
|
|
16
|
+
activity: z.ZodObject<{
|
|
17
|
+
retentionDays: z.ZodNumber;
|
|
18
|
+
maximumDays: z.ZodNumber;
|
|
19
|
+
defaultDays: z.ZodNumber;
|
|
20
|
+
}, z.core.$strict>;
|
|
21
|
+
conversations: z.ZodObject<{
|
|
22
|
+
state: z.ZodEnum<{
|
|
23
|
+
not_enabled: "not_enabled";
|
|
24
|
+
off: "off";
|
|
25
|
+
on: "on";
|
|
26
|
+
}>;
|
|
27
|
+
retentionDays: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
sources: z.ZodObject<{
|
|
29
|
+
websiteVisitors: z.ZodBoolean;
|
|
30
|
+
signedInCustomers: z.ZodBoolean;
|
|
31
|
+
whatsapp: z.ZodBoolean;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
disabledByApplication: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
34
|
+
publicWebsite: "publicWebsite";
|
|
35
|
+
authenticatedWebsite: "authenticatedWebsite";
|
|
36
|
+
publicMessaging: "publicMessaging";
|
|
37
|
+
}>>>;
|
|
38
|
+
}, z.core.$strict>;
|
|
39
|
+
}, z.core.$strict>;
|
|
40
|
+
export declare const ApplicationHistorySettingsResponseSchema: z.ZodObject<{
|
|
41
|
+
ok: z.ZodLiteral<true>;
|
|
42
|
+
data: z.ZodObject<{
|
|
43
|
+
revision: z.ZodString;
|
|
44
|
+
canEdit: z.ZodBoolean;
|
|
45
|
+
activity: z.ZodObject<{
|
|
46
|
+
retentionDays: z.ZodNumber;
|
|
47
|
+
maximumDays: z.ZodNumber;
|
|
48
|
+
defaultDays: z.ZodNumber;
|
|
49
|
+
}, z.core.$strict>;
|
|
50
|
+
conversations: z.ZodObject<{
|
|
51
|
+
state: z.ZodEnum<{
|
|
52
|
+
not_enabled: "not_enabled";
|
|
53
|
+
off: "off";
|
|
54
|
+
on: "on";
|
|
55
|
+
}>;
|
|
56
|
+
retentionDays: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
sources: z.ZodObject<{
|
|
58
|
+
websiteVisitors: z.ZodBoolean;
|
|
59
|
+
signedInCustomers: z.ZodBoolean;
|
|
60
|
+
whatsapp: z.ZodBoolean;
|
|
61
|
+
}, z.core.$strict>;
|
|
62
|
+
disabledByApplication: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
63
|
+
publicWebsite: "publicWebsite";
|
|
64
|
+
authenticatedWebsite: "authenticatedWebsite";
|
|
65
|
+
publicMessaging: "publicMessaging";
|
|
66
|
+
}>>>;
|
|
67
|
+
}, z.core.$strict>;
|
|
68
|
+
}, z.core.$strict>;
|
|
69
|
+
}, z.core.$strict>;
|
|
70
|
+
/** Omitted fields keep their value; `dryRun` reports the effect without saving. */
|
|
71
|
+
export declare const ApplicationHistorySettingsSaveRequestSchema: z.ZodObject<{
|
|
72
|
+
expectedRevision: z.ZodString;
|
|
73
|
+
activityDays: z.ZodOptional<z.ZodNumber>;
|
|
74
|
+
conversations: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
75
|
+
retentionDays: z.ZodNumber;
|
|
76
|
+
}, z.core.$strict>, z.ZodLiteral<"off">]>>;
|
|
77
|
+
sources: z.ZodOptional<z.ZodObject<{
|
|
78
|
+
websiteVisitors: z.ZodOptional<z.ZodBoolean>;
|
|
79
|
+
signedInCustomers: z.ZodOptional<z.ZodBoolean>;
|
|
80
|
+
whatsapp: z.ZodOptional<z.ZodBoolean>;
|
|
81
|
+
}, z.core.$strict>>;
|
|
82
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
83
|
+
}, z.core.$strict>;
|
|
84
|
+
export declare const ApplicationHistorySettingsSaveResponseSchema: z.ZodObject<{
|
|
85
|
+
ok: z.ZodLiteral<true>;
|
|
86
|
+
data: z.ZodObject<{
|
|
87
|
+
dryRun: z.ZodBoolean;
|
|
88
|
+
shortensConversations: z.ZodBoolean;
|
|
89
|
+
impact: z.ZodObject<{
|
|
90
|
+
conversations: z.ZodNumber;
|
|
91
|
+
items: z.ZodNumber;
|
|
92
|
+
}, z.core.$strict>;
|
|
93
|
+
settings: z.ZodObject<{
|
|
94
|
+
revision: z.ZodString;
|
|
95
|
+
canEdit: z.ZodBoolean;
|
|
96
|
+
activity: z.ZodObject<{
|
|
97
|
+
retentionDays: z.ZodNumber;
|
|
98
|
+
maximumDays: z.ZodNumber;
|
|
99
|
+
defaultDays: z.ZodNumber;
|
|
100
|
+
}, z.core.$strict>;
|
|
101
|
+
conversations: z.ZodObject<{
|
|
102
|
+
state: z.ZodEnum<{
|
|
103
|
+
not_enabled: "not_enabled";
|
|
104
|
+
off: "off";
|
|
105
|
+
on: "on";
|
|
106
|
+
}>;
|
|
107
|
+
retentionDays: z.ZodOptional<z.ZodNumber>;
|
|
108
|
+
sources: z.ZodObject<{
|
|
109
|
+
websiteVisitors: z.ZodBoolean;
|
|
110
|
+
signedInCustomers: z.ZodBoolean;
|
|
111
|
+
whatsapp: z.ZodBoolean;
|
|
112
|
+
}, z.core.$strict>;
|
|
113
|
+
disabledByApplication: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
114
|
+
publicWebsite: "publicWebsite";
|
|
115
|
+
authenticatedWebsite: "authenticatedWebsite";
|
|
116
|
+
publicMessaging: "publicMessaging";
|
|
117
|
+
}>>>;
|
|
118
|
+
}, z.core.$strict>;
|
|
119
|
+
}, z.core.$strict>;
|
|
120
|
+
}, z.core.$strict>;
|
|
121
|
+
}, z.core.$strict>;
|
|
122
|
+
export declare const ApplicationHistorySettingsClientResponseSchema: z.ZodObject<{
|
|
123
|
+
ok: z.ZodLiteral<true>;
|
|
124
|
+
data: z.ZodObject<{
|
|
125
|
+
activity: z.ZodObject<{
|
|
126
|
+
retentionDays: z.ZodNumber;
|
|
127
|
+
maximumDays: z.ZodNumber;
|
|
128
|
+
defaultDays: z.ZodNumber;
|
|
129
|
+
}, z.core.$strip>;
|
|
130
|
+
conversations: z.ZodObject<{
|
|
131
|
+
sources: z.ZodObject<{
|
|
132
|
+
websiteVisitors: z.ZodBoolean;
|
|
133
|
+
signedInCustomers: z.ZodBoolean;
|
|
134
|
+
whatsapp: z.ZodBoolean;
|
|
135
|
+
}, z.core.$strip>;
|
|
136
|
+
state: z.ZodEnum<{
|
|
137
|
+
not_enabled: "not_enabled";
|
|
138
|
+
off: "off";
|
|
139
|
+
on: "on";
|
|
140
|
+
}>;
|
|
141
|
+
retentionDays: z.ZodOptional<z.ZodNumber>;
|
|
142
|
+
disabledByApplication: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
143
|
+
publicWebsite: "publicWebsite";
|
|
144
|
+
authenticatedWebsite: "authenticatedWebsite";
|
|
145
|
+
publicMessaging: "publicMessaging";
|
|
146
|
+
}>>>;
|
|
147
|
+
}, z.core.$strip>;
|
|
148
|
+
revision: z.ZodString;
|
|
149
|
+
canEdit: z.ZodBoolean;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
export declare const ApplicationHistorySettingsSaveClientResponseSchema: z.ZodObject<{
|
|
153
|
+
ok: z.ZodLiteral<true>;
|
|
154
|
+
data: z.ZodObject<{
|
|
155
|
+
impact: z.ZodObject<{
|
|
156
|
+
conversations: z.ZodNumber;
|
|
157
|
+
items: z.ZodNumber;
|
|
158
|
+
}, z.core.$strip>;
|
|
159
|
+
settings: z.ZodObject<{
|
|
160
|
+
activity: z.ZodObject<{
|
|
161
|
+
retentionDays: z.ZodNumber;
|
|
162
|
+
maximumDays: z.ZodNumber;
|
|
163
|
+
defaultDays: z.ZodNumber;
|
|
164
|
+
}, z.core.$strip>;
|
|
165
|
+
conversations: z.ZodObject<{
|
|
166
|
+
sources: z.ZodObject<{
|
|
167
|
+
websiteVisitors: z.ZodBoolean;
|
|
168
|
+
signedInCustomers: z.ZodBoolean;
|
|
169
|
+
whatsapp: z.ZodBoolean;
|
|
170
|
+
}, z.core.$strip>;
|
|
171
|
+
state: z.ZodEnum<{
|
|
172
|
+
not_enabled: "not_enabled";
|
|
173
|
+
off: "off";
|
|
174
|
+
on: "on";
|
|
175
|
+
}>;
|
|
176
|
+
retentionDays: z.ZodOptional<z.ZodNumber>;
|
|
177
|
+
disabledByApplication: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
178
|
+
publicWebsite: "publicWebsite";
|
|
179
|
+
authenticatedWebsite: "authenticatedWebsite";
|
|
180
|
+
publicMessaging: "publicMessaging";
|
|
181
|
+
}>>>;
|
|
182
|
+
}, z.core.$strip>;
|
|
183
|
+
revision: z.ZodString;
|
|
184
|
+
canEdit: z.ZodBoolean;
|
|
185
|
+
}, z.core.$strip>;
|
|
186
|
+
dryRun: z.ZodBoolean;
|
|
187
|
+
shortensConversations: z.ZodBoolean;
|
|
188
|
+
}, z.core.$strip>;
|
|
189
|
+
}, z.core.$strip>;
|
|
190
|
+
//# sourceMappingURL=application-history-settings.d.ts.map
|