@noodleseed/one 0.175.0 → 0.176.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/knowledge.d.ts.map +1 -1
- package/dist/commands/knowledge.js +4 -7
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/whatsapp-ops.d.ts.map +1 -1
- package/dist/commands/whatsapp-ops.js +12 -2
- package/dist/commands/whatsapp-ops.js.map +1 -1
- package/dist/commands/whatsapp-output.d.ts.map +1 -1
- package/dist/commands/whatsapp-output.js +1 -0
- package/dist/commands/whatsapp-output.js.map +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.d.ts +14 -8
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.js +11 -2
- package/node_modules/@noodle-borg/assistant-gateway/dist/channel-types.d.ts +14 -5
- package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -1
- package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-channels.js +5 -3
- package/node_modules/@noodle-borg/knowledge-operations/dist/executor.d.ts +3 -5
- package/node_modules/@noodle-borg/knowledge-operations/dist/executor.js +2 -7
- package/node_modules/@noodle-borg/knowledge-operations/dist/portable.d.ts +1 -1
- package/node_modules/@noodle-borg/knowledge-operations/dist/portable.js +1 -1
- package/node_modules/@noodle-borg/knowledge-operations/dist/publication.d.ts +0 -1
- package/node_modules/@noodle-borg/knowledge-operations/dist/publication.js +1 -10
- package/node_modules/@noodle-borg/knowledge-operations/dist/routes.d.ts +0 -4
- package/node_modules/@noodle-borg/knowledge-operations/dist/routes.js +1 -17
- package/node_modules/@noodle-borg/knowledge-operations/dist/search-port.d.ts +1 -2
- package/node_modules/@noodle-borg/knowledge-operations/dist/search-port.js +1 -3
- package/node_modules/@noodle-borg/knowledge-operations/dist/service-wiring.d.ts +4 -4
- package/node_modules/@noodle-borg/knowledge-operations/dist/service-wiring.js +3 -8
- package/node_modules/@noodle-borg/knowledge-operations/dist/status-routes.d.ts +1 -2
- package/node_modules/@noodle-borg/knowledge-operations/dist/status-routes.js +0 -14
- package/node_modules/@noodle-borg/protocol/dist/knowledge-tool.js +3 -5
- package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +2 -3
- package/node_modules/@noodle-borg/service/dist/assistant-composition.js +9 -0
- package/node_modules/@noodle-borg/service/dist/business-information/validation.js +1 -22
- package/node_modules/@noodle-borg/service/dist/channels/360dialog.js +41 -145
- package/node_modules/@noodle-borg/service/dist/channels/composition.js +1 -0
- package/node_modules/@noodle-borg/service/dist/channels/meta-cloud.js +102 -0
- package/node_modules/@noodle-borg/service/dist/channels/provider.js +151 -0
- package/node_modules/@noodle-borg/service/dist/channels/runtime.js +49 -21
- package/node_modules/@noodle-borg/service/dist/conversation-history/capture.js +99 -0
- package/node_modules/@noodle-borg/service/dist/conversation-history/contracts.js +17 -0
- package/node_modules/@noodle-borg/service/dist/payment-card.js +34 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-elevation.js +2 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-stream.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +15 -0
- package/node_modules/@noodle-borg/service/dist/routes/assistant-knowledge.js +1 -3
- package/node_modules/@noodle-borg/service/dist/routes/assistant.js +8 -6
- package/node_modules/@noodle-borg/service/dist/routes/whatsapp-meta.js +130 -0
- package/node_modules/@noodle-borg/service/dist/routes/whatsapp.js +18 -9
- package/node_modules/@noodle-borg/transport-http/dist/index.d.ts +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/index.js +1 -1
- package/node_modules/@noodle-borg/transport-http/dist/request-body.d.ts +9 -0
- package/node_modules/@noodle-borg/transport-http/dist/request-body.js +2 -1
- package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.d.ts +29 -7
- package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.js +27 -4
- package/node_modules/@noodleseed/assistant/package.json +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,9 @@ import { ChannelError, channelParticipantId, recordChannelDelivery, } from '@noo
|
|
|
2
2
|
import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
|
|
3
3
|
import * as wire from '@noodle-borg/wire-contracts';
|
|
4
4
|
import { parseWhatsAppWebhook, verifyWhatsAppWebhookSecret, WHATSAPP_CALLBACK_HEADER, } from '../channels/360dialog.js';
|
|
5
|
+
import { WHATSAPP_META_CALLBACK_PATH } from '../channels/meta-cloud.js';
|
|
5
6
|
import { authorizeTenantControl, developerGrantRouteAccess } from './control-plane.js';
|
|
7
|
+
import { metaWebhook } from './whatsapp-meta.js';
|
|
6
8
|
const participant = /^p_[a-f0-9]{64}$/;
|
|
7
9
|
const eventId = /^e_[0-9_]+$/;
|
|
8
10
|
function eventView(event) {
|
|
@@ -32,7 +34,8 @@ async function body(req, schema) {
|
|
|
32
34
|
export function dispatchWhatsAppRoutes(req, res, url, runtime, grants) {
|
|
33
35
|
const callback = /^\/v1\/channels\/whatsapp\/webhooks\/([a-z0-9-]+)$/.exec(url.pathname);
|
|
34
36
|
const operator = /^\/v1\/orgs\/([^/]+)\/apps\/([^/]+)\/envs\/([^/]+)\/channels\/whatsapp(?:\/(.*))?$/.exec(url.pathname);
|
|
35
|
-
|
|
37
|
+
const meta = url.pathname === WHATSAPP_META_CALLBACK_PATH;
|
|
38
|
+
if (!callback && !operator && !meta)
|
|
36
39
|
return false;
|
|
37
40
|
res.setHeader('Cache-Control', 'no-store');
|
|
38
41
|
if (!runtime) {
|
|
@@ -42,13 +45,15 @@ export function dispatchWhatsAppRoutes(req, res, url, runtime, grants) {
|
|
|
42
45
|
});
|
|
43
46
|
return true;
|
|
44
47
|
}
|
|
45
|
-
const run = Promise.resolve().then(() =>
|
|
46
|
-
?
|
|
47
|
-
:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
const run = Promise.resolve().then(() => meta
|
|
49
|
+
? metaWebhook(req, res, url, runtime)
|
|
50
|
+
: callback
|
|
51
|
+
? webhook(req, res, callback[1], runtime)
|
|
52
|
+
: operate(req, res, url, {
|
|
53
|
+
org: decodeURIComponent(operator[1]),
|
|
54
|
+
app: decodeURIComponent(operator[2]),
|
|
55
|
+
env: decodeURIComponent(operator[3]),
|
|
56
|
+
}, operator[4] ?? '', runtime, grants));
|
|
52
57
|
void run.catch((error) => {
|
|
53
58
|
const code = error instanceof ChannelError ? error.code : 'channel_unavailable';
|
|
54
59
|
const status = code === 'channel_not_found'
|
|
@@ -73,8 +78,12 @@ async function webhook(req, res, id, runtime) {
|
|
|
73
78
|
if (req.method !== 'POST')
|
|
74
79
|
return sendJson(res, 405, { error: 'method_not_allowed' });
|
|
75
80
|
const binding = await runtime.channels.internal(id);
|
|
81
|
+
// Meta numbers share the signed app callback; only 360dialog has a per-binding address.
|
|
82
|
+
if (binding.provider !== '360dialog')
|
|
83
|
+
return sendJson(res, 404, { error: 'not_found' });
|
|
76
84
|
const { webhookSecret } = await runtime.provider(binding);
|
|
77
|
-
if (!
|
|
85
|
+
if (!webhookSecret ||
|
|
86
|
+
!verifyWhatsAppWebhookSecret(req.headers[WHATSAPP_CALLBACK_HEADER], webhookSecret))
|
|
78
87
|
return sendJson(res, 401, { error: 'unauthorized' });
|
|
79
88
|
const input = await readJsonBody(req, 1 << 20);
|
|
80
89
|
if (!input.ok)
|
|
@@ -3,7 +3,7 @@ export { type AccessMode, type AdmissionCategory, type AdmissionContext, type Ad
|
|
|
3
3
|
export { bearerToken } from './identity-authorization.js';
|
|
4
4
|
export { createLogger, type LogFields, type Logger, type LoggerOptions, type LogLevel, type LogSink, noopLogger, stderrSink, stdoutSink, } from './logging.js';
|
|
5
5
|
export { resolveTrustedPublicOrg, resolveTrustedTenantMcpResource, type TrustedPublicOrg, type TrustedPublicRef, type TrustedPublicRouting, type TrustedTenantMcpResource, trustedPublicMcpRef, trustedPublicOrgWellKnownRef, } from './public-routing.js';
|
|
6
|
-
export { readBody, readDeployBody, readJsonBody } from './request-body.js';
|
|
6
|
+
export { readBody, readBodyBuffer, readDeployBody, readJsonBody } from './request-body.js';
|
|
7
7
|
export { sendJson } from './responses.js';
|
|
8
8
|
export { type RunningServer, type ServeOptions, serveHttp } from './serve.js';
|
|
9
9
|
export type { HostedToolAuthorizationObservation, HostedToolAuthorizationObserver, ServicePrincipalToolAuthorizationObservation, } from './service-principal-authorization.js';
|
|
@@ -3,7 +3,7 @@ export { createMcpHttpHandler, createMcpRouter, } from './handler.js';
|
|
|
3
3
|
export { bearerToken } from './identity-authorization.js';
|
|
4
4
|
export { createLogger, noopLogger, stderrSink, stdoutSink, } from './logging.js';
|
|
5
5
|
export { resolveTrustedPublicOrg, resolveTrustedTenantMcpResource, trustedPublicMcpRef, trustedPublicOrgWellKnownRef, } from './public-routing.js';
|
|
6
|
-
export { readBody, readDeployBody, readJsonBody } from './request-body.js';
|
|
6
|
+
export { readBody, readBodyBuffer, readDeployBody, readJsonBody } from './request-body.js';
|
|
7
7
|
export { sendJson } from './responses.js';
|
|
8
8
|
export { serveHttp } from './serve.js';
|
|
9
9
|
export { preflightServicePrincipalToolCall, sendServicePrincipalToolDenial, } from './service-principal-authorization.js';
|
|
@@ -7,6 +7,15 @@ export declare function readBody(req: IncomingMessage, max: number): Promise<{
|
|
|
7
7
|
receivedBytes: number;
|
|
8
8
|
maxBytes: number;
|
|
9
9
|
}>;
|
|
10
|
+
/** The exact request bytes, bounded; for callers that must verify a signature before parsing. */
|
|
11
|
+
export declare function readBodyBuffer(req: IncomingMessage, max: number): Promise<{
|
|
12
|
+
ok: true;
|
|
13
|
+
buffer: Buffer;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
receivedBytes: number;
|
|
17
|
+
maxBytes: number;
|
|
18
|
+
}>;
|
|
10
19
|
export declare function readDeployBody(req: IncomingMessage, max: number): Promise<{
|
|
11
20
|
ok: true;
|
|
12
21
|
text: string;
|
|
@@ -3,7 +3,8 @@ export async function readBody(req, max) {
|
|
|
3
3
|
const body = await readBodyBuffer(req, max);
|
|
4
4
|
return body.ok ? { ok: true, text: body.buffer.toString('utf8') } : body;
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
/** The exact request bytes, bounded; for callers that must verify a signature before parsing. */
|
|
7
|
+
export async function readBodyBuffer(req, max) {
|
|
7
8
|
const chunks = [];
|
|
8
9
|
let size = 0;
|
|
9
10
|
for await (const chunk of req) {
|
|
@@ -11,11 +11,21 @@ export declare const WhatsAppLimitsSchema: z.ZodObject<{
|
|
|
11
11
|
textCharacters: z.ZodNumber;
|
|
12
12
|
dailyMicroUsd: z.ZodNumber;
|
|
13
13
|
}, z.core.$strict>;
|
|
14
|
+
/** `360dialog` keeps a per-binding callback secret; `meta` names its WABA and uses the app signature. */
|
|
15
|
+
export declare const WhatsAppProviderSchema: z.ZodEnum<{
|
|
16
|
+
"360dialog": "360dialog";
|
|
17
|
+
meta: "meta";
|
|
18
|
+
}>;
|
|
14
19
|
export declare const WhatsAppConfigureRequestSchema: z.ZodObject<{
|
|
15
20
|
expectedRevision: z.ZodNumber;
|
|
21
|
+
provider: z.ZodDefault<z.ZodEnum<{
|
|
22
|
+
"360dialog": "360dialog";
|
|
23
|
+
meta: "meta";
|
|
24
|
+
}>>;
|
|
16
25
|
phoneNumberId: z.ZodString;
|
|
26
|
+
wabaId: z.ZodOptional<z.ZodString>;
|
|
17
27
|
apiKeySecret: z.ZodString;
|
|
18
|
-
webhookSecret: z.ZodString
|
|
28
|
+
webhookSecret: z.ZodOptional<z.ZodString>;
|
|
19
29
|
capabilities: z.ZodArray<z.ZodObject<{
|
|
20
30
|
kind: z.ZodEnum<{
|
|
21
31
|
tool: "tool";
|
|
@@ -86,10 +96,14 @@ export declare const WhatsAppBindingSchema: z.ZodObject<{
|
|
|
86
96
|
app: z.ZodString;
|
|
87
97
|
env: z.ZodString;
|
|
88
98
|
}, z.core.$strict>;
|
|
89
|
-
provider: z.
|
|
99
|
+
provider: z.ZodEnum<{
|
|
100
|
+
"360dialog": "360dialog";
|
|
101
|
+
meta: "meta";
|
|
102
|
+
}>;
|
|
90
103
|
phoneNumberId: z.ZodString;
|
|
104
|
+
wabaId: z.ZodOptional<z.ZodString>;
|
|
91
105
|
apiKeySecret: z.ZodString;
|
|
92
|
-
webhookSecret: z.ZodString
|
|
106
|
+
webhookSecret: z.ZodOptional<z.ZodString>;
|
|
93
107
|
deploymentId: z.ZodString;
|
|
94
108
|
capabilities: z.ZodArray<z.ZodObject<{
|
|
95
109
|
kind: z.ZodEnum<{
|
|
@@ -133,10 +147,14 @@ export declare const WhatsAppBindingResponseSchema: z.ZodObject<{
|
|
|
133
147
|
app: z.ZodString;
|
|
134
148
|
env: z.ZodString;
|
|
135
149
|
}, z.core.$strict>;
|
|
136
|
-
provider: z.
|
|
150
|
+
provider: z.ZodEnum<{
|
|
151
|
+
"360dialog": "360dialog";
|
|
152
|
+
meta: "meta";
|
|
153
|
+
}>;
|
|
137
154
|
phoneNumberId: z.ZodString;
|
|
155
|
+
wabaId: z.ZodOptional<z.ZodString>;
|
|
138
156
|
apiKeySecret: z.ZodString;
|
|
139
|
-
webhookSecret: z.ZodString
|
|
157
|
+
webhookSecret: z.ZodOptional<z.ZodString>;
|
|
140
158
|
deploymentId: z.ZodString;
|
|
141
159
|
capabilities: z.ZodArray<z.ZodObject<{
|
|
142
160
|
kind: z.ZodEnum<{
|
|
@@ -176,10 +194,14 @@ export declare const WhatsAppBindingClientResponseSchema: z.ZodObject<{
|
|
|
176
194
|
ok: z.ZodLiteral<true>;
|
|
177
195
|
data: z.ZodNullable<z.ZodObject<{
|
|
178
196
|
id: z.ZodString;
|
|
179
|
-
provider: z.
|
|
197
|
+
provider: z.ZodEnum<{
|
|
198
|
+
"360dialog": "360dialog";
|
|
199
|
+
meta: "meta";
|
|
200
|
+
}>;
|
|
180
201
|
phoneNumberId: z.ZodString;
|
|
202
|
+
wabaId: z.ZodOptional<z.ZodString>;
|
|
181
203
|
apiKeySecret: z.ZodString;
|
|
182
|
-
webhookSecret: z.ZodString
|
|
204
|
+
webhookSecret: z.ZodOptional<z.ZodString>;
|
|
183
205
|
deploymentId: z.ZodString;
|
|
184
206
|
supportEmail: z.ZodEmail;
|
|
185
207
|
revision: z.ZodNumber;
|
|
@@ -20,14 +20,36 @@ export const WhatsAppLimitsSchema = z.strictObject({
|
|
|
20
20
|
});
|
|
21
21
|
const capability = z.strictObject({ kind: z.enum(['tool', 'knowledge']), name: id });
|
|
22
22
|
const secretRef = z.string().regex(/^[A-Z][A-Z0-9_]{0,127}$/);
|
|
23
|
-
|
|
23
|
+
/** `360dialog` keeps a per-binding callback secret; `meta` names its WABA and uses the app signature. */
|
|
24
|
+
export const WhatsAppProviderSchema = z.enum(['360dialog', 'meta']);
|
|
25
|
+
export const WhatsAppConfigureRequestSchema = z
|
|
26
|
+
.strictObject({
|
|
24
27
|
expectedRevision: revision,
|
|
28
|
+
provider: WhatsAppProviderSchema.default('360dialog'),
|
|
25
29
|
phoneNumberId: id,
|
|
30
|
+
wabaId: id.optional(),
|
|
26
31
|
apiKeySecret: secretRef,
|
|
27
|
-
webhookSecret: secretRef,
|
|
32
|
+
webhookSecret: secretRef.optional(),
|
|
28
33
|
capabilities: z.array(capability).max(64),
|
|
29
34
|
supportEmail: z.email().max(254),
|
|
30
35
|
limits: WhatsAppLimitsSchema.partial().optional(),
|
|
36
|
+
})
|
|
37
|
+
.superRefine((value, context) => {
|
|
38
|
+
const meta = value.provider === 'meta';
|
|
39
|
+
if (meta ? !value.wabaId : !value.webhookSecret)
|
|
40
|
+
context.addIssue({
|
|
41
|
+
code: 'custom',
|
|
42
|
+
path: [meta ? 'wabaId' : 'webhookSecret'],
|
|
43
|
+
message: meta ? 'Meta requires wabaId' : '360dialog requires webhookSecret',
|
|
44
|
+
});
|
|
45
|
+
if (meta ? value.webhookSecret !== undefined : value.wabaId !== undefined)
|
|
46
|
+
context.addIssue({
|
|
47
|
+
code: 'custom',
|
|
48
|
+
path: [meta ? 'webhookSecret' : 'wabaId'],
|
|
49
|
+
message: meta
|
|
50
|
+
? 'Meta callbacks are authenticated by the app signature, not a webhook secret'
|
|
51
|
+
: 'wabaId applies only to the meta provider',
|
|
52
|
+
});
|
|
31
53
|
});
|
|
32
54
|
export const WhatsAppStateRequestSchema = z.strictObject({
|
|
33
55
|
expectedRevision: revision,
|
|
@@ -64,10 +86,11 @@ const tenant = z.strictObject({ org: id, app: id, env: id });
|
|
|
64
86
|
export const WhatsAppBindingSchema = z.strictObject({
|
|
65
87
|
id,
|
|
66
88
|
tenant,
|
|
67
|
-
provider:
|
|
89
|
+
provider: WhatsAppProviderSchema,
|
|
68
90
|
phoneNumberId: id,
|
|
91
|
+
wabaId: id.optional(),
|
|
69
92
|
apiKeySecret: secretRef,
|
|
70
|
-
webhookSecret: secretRef,
|
|
93
|
+
webhookSecret: secretRef.optional(),
|
|
71
94
|
deploymentId: id,
|
|
72
95
|
capabilities: z.array(capability),
|
|
73
96
|
supportEmail: z.email(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/assistant",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.1",
|
|
4
4
|
"description": "Embed the Noodle Seed customer-branded assistant in your web app with managed or framework-owned UI, a framework-neutral MCP App host, a DOM-free client, and a backend session helper. Authoring and deploying the server is @noodleseed/one.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/one",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.176.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
|
|
6
6
|
"license": "Apache-2.0",
|