okengine 0.23.0 → 0.23.2
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/package.json +1 -1
- package/site/content/docs/ai/mcp.mdx +4 -4
- package/site/content/docs/elements/channel/index.mdx +4 -4
- package/site/content/docs/elements/channel/receipts.mdx +7 -5
- package/site/content/docs/elements/channel/sms.mdx +2 -1
- package/site/content/docs/elements/flow/index.mdx +22 -18
- package/site/content/docs/elements/signal/broadcast.mdx +4 -2
- package/site/content/docs/elements/signal/index.mdx +15 -14
- package/site/content/docs/plugins/otp.mdx +3 -3
- package/site/content/docs/reference/configuration.mdx +16 -0
- package/site/content/docs/reference/errors.mdx +31 -19
- package/site/content/docs/reference/fx.mdx +12 -4
- package/src/auth/tenants.ts +17 -0
- package/src/cli/doctor-diff.test.ts +29 -1
- package/src/cli/doctor-diff.ts +35 -0
- package/src/cli/manifest-pr-diff.ts +16 -0
- package/src/compiler/aot.test.ts +3 -2
- package/src/compiler/aot.ts +45 -1
- package/src/compiler/dynamic.ts +1 -1
- package/src/compiler/effects-fetch.test.ts +77 -0
- package/src/compiler/effects-infer.ts +87 -16
- package/src/compiler/effects-join.test.ts +48 -0
- package/src/compiler/extract.test.ts +28 -0
- package/src/compiler/extract.ts +11 -1
- package/src/compiler/fx-index.ts +58 -4
- package/src/compiler/http-parse.test.ts +101 -0
- package/src/compiler/http-parse.ts +188 -9
- package/src/compiler/interpret.ts +25 -2
- package/src/console/index.ts +1 -1
- package/src/console/ui-next/dist/assets/{access-page-DDKkhT9v.js → access-page-zBMhZnFm.js} +1 -1
- package/src/console/ui-next/dist/assets/{agent-disclosure-62Xts8Xi.js → agent-disclosure-CBj9f7Ju.js} +1 -1
- package/src/console/ui-next/dist/assets/{cache-glyph-DyeoKHKA.js → cache-glyph-D3MY49h3.js} +1 -1
- package/src/console/ui-next/dist/assets/{call-pii-button-DvfpLXsU.js → call-pii-button-L9JxdBhp.js} +1 -1
- package/src/console/ui-next/dist/assets/{collapsible-BY03SeCg.js → collapsible-BvFaX-Zt.js} +1 -1
- package/src/console/ui-next/dist/assets/{decisions-page-CgkKlA56.js → decisions-page-DgB76m-X.js} +1 -1
- package/src/console/ui-next/dist/assets/{duration-tone-Y6HLjyJ5.js → duration-tone-l1DSJ2Vz.js} +1 -1
- package/src/console/ui-next/dist/assets/{flows-page-DLPfNy-_.js → flows-page-Bb9t1lu6.js} +1 -1
- package/src/console/ui-next/dist/assets/{highlighted-json-D7nNzpgB.js → highlighted-json-DMvsi3Ti.js} +1 -1
- package/src/console/ui-next/dist/assets/{http-method-DdL19zzh.js → http-method-BwhJBTcQ.js} +1 -1
- package/src/console/ui-next/dist/assets/{index-C0lc_s9d.js → index-RhV2jT_7.js} +3 -3
- package/src/console/ui-next/dist/assets/{observability-page-CRlcyLCC.js → observability-page-BRfUILBq.js} +1 -1
- package/src/console/ui-next/dist/assets/{replica-lag-Bb3FWUu9.js → replica-lag-BsceAzIG.js} +1 -1
- package/src/console/ui-next/dist/assets/{request-meta-DYBMWhX8.js → request-meta-C6lTyCXp.js} +1 -1
- package/src/console/ui-next/dist/assets/{store-page-CcE-SXC8.js → store-page-YmE806bJ.js} +1 -1
- package/src/console/ui-next/dist/assets/{trace-detail-sheet-CKMSEQ4s.js → trace-detail-sheet-Di4irS49.js} +1 -1
- package/src/console/ui-next/dist/assets/{tree-expand-toggle-QOfk0M0H.js → tree-expand-toggle-DYeL6Rye.js} +1 -1
- package/src/console/ui-next/dist/assets/{units-page-DKC1CDDd.js → units-page-07agasRA.js} +1 -1
- package/src/console/ui-next/dist/assets/{vault-page-B54v4Yit.js → vault-page-CHBck4n_.js} +1 -1
- package/src/console/ui-next/dist/index.html +1 -1
- package/src/console/ui-next/seed-parked-approval.ts +5 -1
- package/src/drivers/journal-postgres.test.ts +106 -2
- package/src/drivers/journal-postgres.ts +475 -14
- package/src/drivers/postgres.test.ts +60 -0
- package/src/drivers/postgres.ts +79 -5
- package/src/drivers/signal-compete.test.ts +238 -0
- package/src/drivers/signal-postgres.test.ts +170 -0
- package/src/drivers/signal-postgres.ts +486 -213
- package/src/drivers/signal-redis.test.ts +224 -0
- package/src/drivers/signal-redis.ts +934 -93
- package/src/drivers/signal-types.ts +12 -0
- package/src/elements/ai/approval.test.ts +15 -3
- package/src/elements/ai/approval.ts +15 -9
- package/src/elements/ai/mcp-protocol.ts +5 -6
- package/src/elements/ai/runtime.ts +20 -19
- package/src/elements/channel/runtime.ts +42 -4
- package/src/elements/channel/sql-ledger.test.ts +404 -0
- package/src/elements/channel/sql-ledger.ts +395 -0
- package/src/elements/clock/chaos-child.ts +12 -2
- package/src/elements/clock/durable.ts +11 -0
- package/src/elements/signal/runtime.ts +9 -0
- package/src/elements/signal.test.ts +1 -0
- package/src/elements/store/cache-bus.test.ts +121 -0
- package/src/elements/store/cache-bus.ts +278 -0
- package/src/elements/store/cache.test.ts +179 -15
- package/src/elements/store/cache.ts +357 -51
- package/src/elements/store/prepare-row.test.ts +6 -2
- package/src/elements/store/runtime.ts +44 -2
- package/src/elements/store/sql-errors.test.ts +131 -0
- package/src/elements/store/sql-errors.ts +39 -16
- package/src/elements/store/sql-nested-tx.test.ts +344 -0
- package/src/elements/store/sql-session.test.ts +2 -0
- package/src/elements/store/sql-session.ts +275 -9
- package/src/elements/store.ts +1 -0
- package/src/kernel/app.ts +207 -43
- package/src/kernel/auto-cache.test.ts +228 -0
- package/src/kernel/auto-registry.test.ts +5 -1
- package/src/kernel/boot-bind/channel.ts +63 -2
- package/src/kernel/boot-bind/honor-config.test.ts +40 -10
- package/src/kernel/boot-bind/signal.ts +72 -25
- package/src/kernel/boot-bind/store.ts +16 -1
- package/src/kernel/boot.test.ts +2 -2
- package/src/kernel/boot.ts +54 -10
- package/src/kernel/boundary-contract.ts +7 -0
- package/src/kernel/builtin-errors.ts +2 -0
- package/src/kernel/call.test.ts +1 -0
- package/src/kernel/errors-compiler.ts +11 -0
- package/src/kernel/errors-text.ts +16 -0
- package/src/kernel/errors.ts +8 -0
- package/src/kernel/flow.ts +33 -3
- package/src/kernel/fx-call-types.test.ts +32 -0
- package/src/kernel/fx-decide.ts +11 -7
- package/src/kernel/fx-sql-handle.ts +52 -7
- package/src/kernel/fx.test.ts +1 -3
- package/src/kernel/fx.ts +27 -16
- package/src/kernel/horizontal-child.ts +54 -1
- package/src/kernel/horizontal.integration.test.ts +131 -7
- package/src/kernel/idempotency.test.ts +4 -4
- package/src/kernel/journal-boot.test.ts +83 -6
- package/src/kernel/journal.test.ts +158 -0
- package/src/kernel/journal.ts +515 -54
- package/src/kernel/pipeline-tenant.ts +5 -1
- package/src/kernel/pipeline.ts +5 -0
- package/src/kernel/signal-tx.ts +28 -0
- package/src/kernel/store-transaction.test.ts +95 -0
- package/src/mcp/authorization.ts +5 -11
- package/src/mcp/confirmation.ts +203 -38
- package/src/mcp/docs-server.ts +26 -4
- package/src/mcp/index.ts +4 -0
- package/src/mcp/mcp.test.ts +404 -33
- package/src/mcp/protocol.ts +8 -2
- package/src/mcp/server.ts +31 -5
- package/src/mcp/session.ts +7 -0
- package/src/mcp/tools.ts +68 -19
- package/src/mcp/versions.ts +60 -0
- package/src/plugins/index.ts +1 -0
- package/src/plugins/mena.ts +56 -0
- package/src/runtime/bun.ts +5 -0
- package/src/runtime/types.ts +5 -0
package/src/mcp/tools.ts
CHANGED
|
@@ -12,7 +12,9 @@ import { authorizeToolCall, MCP_TOOL_POLICIES, type McpToolPolicy } from "./auth
|
|
|
12
12
|
import {
|
|
13
13
|
createConfirmationGate,
|
|
14
14
|
MCP_CONFIRM_PHRASE,
|
|
15
|
+
type ConfirmationGate,
|
|
15
16
|
type ConfirmationGateOptions,
|
|
17
|
+
type ConfirmIssueResult,
|
|
16
18
|
} from "./confirmation.ts";
|
|
17
19
|
import { asData, freezeData, type McpDataEnvelope } from "./data.ts";
|
|
18
20
|
import type { McpRequester } from "./session.ts";
|
|
@@ -68,6 +70,9 @@ export type ToolCallResult =
|
|
|
68
70
|
/**
|
|
69
71
|
* Create the tool runtime bound to a context + confirmation gate.
|
|
70
72
|
*
|
|
73
|
+
* `listTools` receives the requester and omits tools their scopes cannot call.
|
|
74
|
+
* Confirmation is not required to appear in the list; `callTool` still enforces it.
|
|
75
|
+
*
|
|
71
76
|
* @param ctx - Manifest / runs / action adapters
|
|
72
77
|
* @param confirmOptions - Confirmation gate options
|
|
73
78
|
*/
|
|
@@ -75,7 +80,7 @@ export function createToolRuntime(
|
|
|
75
80
|
ctx: McpContext,
|
|
76
81
|
confirmOptions: ConfirmationGateOptions = {},
|
|
77
82
|
): {
|
|
78
|
-
readonly listTools: () => readonly McpToolPolicy[];
|
|
83
|
+
readonly listTools: (requester: McpRequester) => readonly McpToolPolicy[];
|
|
79
84
|
readonly callTool: (
|
|
80
85
|
requester: McpRequester,
|
|
81
86
|
name: string,
|
|
@@ -87,7 +92,14 @@ export function createToolRuntime(
|
|
|
87
92
|
const confirm = createConfirmationGate(confirmOptions);
|
|
88
93
|
|
|
89
94
|
return {
|
|
90
|
-
listTools
|
|
95
|
+
listTools(requester) {
|
|
96
|
+
// Same scope check as authorizeToolCall. Listing ignores confirmation;
|
|
97
|
+
// a later call to a write tool still requires a token.
|
|
98
|
+
return MCP_TOOL_POLICIES.filter((policy) => {
|
|
99
|
+
const decision = authorizeToolCall(policy.name, {}, requester.scopes, { confirmed: true });
|
|
100
|
+
return decision.ok;
|
|
101
|
+
});
|
|
102
|
+
},
|
|
91
103
|
confirmationSize: () => confirm.size(),
|
|
92
104
|
async callTool(requester, name, args) {
|
|
93
105
|
const policy = MCP_TOOL_POLICIES.find((p) => p.name === name);
|
|
@@ -113,15 +125,42 @@ export function createToolRuntime(
|
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
// Write path: consume a fresh per-call confirmation (no session cache).
|
|
128
|
+
// A call with no token is rejected and returns an opaque confirmationId
|
|
129
|
+
// bound to this requester — never the token.
|
|
116
130
|
if (policy?.mutability === "write") {
|
|
117
131
|
const token = typeof args.confirmToken === "string" ? args.confirmToken : "";
|
|
118
132
|
const phrase = typeof args.confirmation === "string" ? args.confirmation : "";
|
|
119
133
|
const reason = typeof args.reason === "string" ? args.reason : "";
|
|
120
134
|
const boundArgs = stripConfirmFields(args);
|
|
135
|
+
if (token.length === 0) {
|
|
136
|
+
const opened = confirm.open({
|
|
137
|
+
tool: name,
|
|
138
|
+
args: boundArgs,
|
|
139
|
+
target: {
|
|
140
|
+
principalId: requester.principalId,
|
|
141
|
+
sid: requester.sessionId,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
code: "forbidden",
|
|
147
|
+
message: "write tool requires fresh human confirmation (missing)",
|
|
148
|
+
data: asData(
|
|
149
|
+
{
|
|
150
|
+
tool: name,
|
|
151
|
+
confirmationId: opened.confirmationId,
|
|
152
|
+
requiredPhrase: MCP_CONFIRM_PHRASE,
|
|
153
|
+
confirmVia: "oke.action.confirm",
|
|
154
|
+
reason: "missing",
|
|
155
|
+
},
|
|
156
|
+
"error",
|
|
157
|
+
),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
121
160
|
const consumed = confirm.consume({
|
|
122
161
|
tool: name,
|
|
123
162
|
args: boundArgs,
|
|
124
|
-
|
|
163
|
+
consumerSid: requester.sessionId,
|
|
125
164
|
token,
|
|
126
165
|
phrase,
|
|
127
166
|
reason,
|
|
@@ -412,28 +451,23 @@ async function decisionsList(
|
|
|
412
451
|
}
|
|
413
452
|
|
|
414
453
|
function actionConfirm(
|
|
415
|
-
confirm:
|
|
454
|
+
confirm: ConfirmationGate,
|
|
416
455
|
requester: McpRequester,
|
|
417
456
|
args: Record<string, unknown>,
|
|
418
457
|
): ToolCallResult {
|
|
419
|
-
const
|
|
420
|
-
const reason =
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
? (args.args as Record<string, unknown>)
|
|
424
|
-
: {};
|
|
425
|
-
const issued = confirm.request({
|
|
426
|
-
tool,
|
|
427
|
-
args: toolArgs,
|
|
428
|
-
principalId: requester.principalId,
|
|
458
|
+
const confirmationId = typeof args.confirmationId === "string" ? args.confirmationId : "";
|
|
459
|
+
const reason = typeof args.reason === "string" ? args.reason : "";
|
|
460
|
+
const issued = confirm.issue({
|
|
461
|
+
confirmationId,
|
|
429
462
|
reason,
|
|
463
|
+
callerSid: requester.sessionId,
|
|
430
464
|
});
|
|
431
|
-
if (
|
|
465
|
+
if (!issued.ok) {
|
|
432
466
|
return {
|
|
433
467
|
ok: false,
|
|
434
|
-
code: "invalid",
|
|
435
|
-
message:
|
|
436
|
-
data: asData({ error: issued.
|
|
468
|
+
code: issued.reason === "reason-short" ? "invalid" : "forbidden",
|
|
469
|
+
message: confirmIssueMessage(issued.reason),
|
|
470
|
+
data: asData({ error: issued.reason }, "error"),
|
|
437
471
|
};
|
|
438
472
|
}
|
|
439
473
|
return okData(
|
|
@@ -443,12 +477,27 @@ function actionConfirm(
|
|
|
443
477
|
phrase: MCP_CONFIRM_PHRASE,
|
|
444
478
|
expiresAt: issued.expiresAt,
|
|
445
479
|
notice:
|
|
446
|
-
"Present confirmToken + confirmation phrase on the write call. Tokens are single-use;
|
|
480
|
+
"Present confirmToken + confirmation phrase on the write call from the session that requested it. Tokens are single-use; the issuer session cannot consume them.",
|
|
447
481
|
},
|
|
448
482
|
"action-result",
|
|
449
483
|
);
|
|
450
484
|
}
|
|
451
485
|
|
|
486
|
+
function confirmIssueMessage(reason: Extract<ConfirmIssueResult, { ok: false }>["reason"]): string {
|
|
487
|
+
switch (reason) {
|
|
488
|
+
case "reason-short":
|
|
489
|
+
return "reason must be at least 3 characters";
|
|
490
|
+
case "same-session":
|
|
491
|
+
return "confirmation must be issued by a different auth session";
|
|
492
|
+
case "unknown":
|
|
493
|
+
return "unknown confirmation";
|
|
494
|
+
case "expired":
|
|
495
|
+
return "confirmation expired";
|
|
496
|
+
case "already-issued":
|
|
497
|
+
return "confirmation already issued";
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
452
501
|
async function actionInvoke(
|
|
453
502
|
ctx: McpContext,
|
|
454
503
|
requester: McpRequester,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP protocol versions.
|
|
3
|
+
*
|
|
4
|
+
* The app and docs servers implement `initialize`, `ping`, `tools/list`, and
|
|
5
|
+
* `tools/call`. That is the 2024-11-05 tools surface, so they advertise
|
|
6
|
+
* {@link MCP_PROTOCOL_VERSION} and reject any other client version.
|
|
7
|
+
*
|
|
8
|
+
* The outbound client is separate. It probes external servers with
|
|
9
|
+
* {@link MCP_CLIENT_PROTOCOL_VERSION} (`_meta` on each request) and falls
|
|
10
|
+
* back to a 2024-11-05 `initialize`. That constant is not the server
|
|
11
|
+
* advertisement.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Versions the app and docs servers implement, newest last. */
|
|
15
|
+
export const MCP_SUPPORTED_PROTOCOL_VERSIONS = ["2024-11-05"] as const;
|
|
16
|
+
|
|
17
|
+
/** Highest protocol version the servers implement and advertise. */
|
|
18
|
+
export const MCP_PROTOCOL_VERSION: (typeof MCP_SUPPORTED_PROTOCOL_VERSIONS)[number] = "2024-11-05";
|
|
19
|
+
|
|
20
|
+
/** Version the outbound MCP client probes first. Not the server advertisement. */
|
|
21
|
+
export const MCP_CLIENT_PROTOCOL_VERSION = "2026-07-28";
|
|
22
|
+
|
|
23
|
+
/** `initialize` dialect the outbound client falls back to. */
|
|
24
|
+
export const MCP_LEGACY_PROTOCOL_VERSION = "2024-11-05";
|
|
25
|
+
|
|
26
|
+
const ACCEPTED: readonly string[] = MCP_SUPPORTED_PROTOCOL_VERSIONS;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether a client-offered protocol version is one this server implements.
|
|
30
|
+
*
|
|
31
|
+
* @param version - `initialize` or `tools/call` protocol version
|
|
32
|
+
*/
|
|
33
|
+
export function acceptsMcpProtocolVersion(version: string): boolean {
|
|
34
|
+
return ACCEPTED.includes(version);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Pick the protocol version for an `initialize` result.
|
|
39
|
+
*
|
|
40
|
+
* An omitted client version gets the highest version this server implements.
|
|
41
|
+
* A supported client version is echoed. Anything else has no overlap.
|
|
42
|
+
*
|
|
43
|
+
* @param requested - Client `protocolVersion`, when present
|
|
44
|
+
*/
|
|
45
|
+
export function negotiateMcpProtocolVersion(requested: string | undefined): string | undefined {
|
|
46
|
+
if (requested === undefined) return MCP_PROTOCOL_VERSION;
|
|
47
|
+
if (acceptsMcpProtocolVersion(requested)) return requested;
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Read `params.protocolVersion` when the client sent one.
|
|
53
|
+
*
|
|
54
|
+
* @param params - JSON-RPC params
|
|
55
|
+
*/
|
|
56
|
+
export function protocolVersionOf(params: unknown): string | undefined {
|
|
57
|
+
if (params === null || typeof params !== "object" || Array.isArray(params)) return undefined;
|
|
58
|
+
const version = (params as { protocolVersion?: unknown }).protocolVersion;
|
|
59
|
+
return typeof version === "string" && version.length > 0 ? version : undefined;
|
|
60
|
+
}
|
package/src/plugins/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ export {
|
|
|
24
24
|
type MagicLinkOptions,
|
|
25
25
|
} from "./magic-link.ts";
|
|
26
26
|
export { maintenanceMode, type MaintenanceModeOptions } from "./maintenance-mode.ts";
|
|
27
|
+
export { mena, menaChannels, type MenaChannelOptions } from "./mena.ts";
|
|
27
28
|
export {
|
|
28
29
|
createPhoneStore,
|
|
29
30
|
otp,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MENA channel plugin — Taqnyat, Unifonic, and Msegat behind one plugin.
|
|
3
|
+
*
|
|
4
|
+
* Drivers stay the protocol adapters. `fx.sendOtp`, `fx.verifyOtp`, and
|
|
5
|
+
* `fx.deliverOtp` remain supported Channel methods.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { openMsegatChannel } from "../drivers/channel-msegat.ts";
|
|
9
|
+
import { openTaqnyatChannel } from "../drivers/channel-taqnyat.ts";
|
|
10
|
+
import { openTaqnyatMailChannel } from "../drivers/channel-taqnyat-mail.ts";
|
|
11
|
+
import { openTaqnyatWhatsAppChannel } from "../drivers/channel-taqnyat-whatsapp.ts";
|
|
12
|
+
import { openUnifonicChannel } from "../drivers/channel-unifonic.ts";
|
|
13
|
+
import type { ChannelDriver, ChannelOpenOptions } from "../drivers/channel-types.ts";
|
|
14
|
+
import { plugin, type PluginDef } from "../kernel/plugin.ts";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
openMsegatChannel,
|
|
18
|
+
openTaqnyatChannel,
|
|
19
|
+
openTaqnyatMailChannel,
|
|
20
|
+
openTaqnyatWhatsAppChannel,
|
|
21
|
+
openUnifonicChannel,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Which MENA providers to open. Omitted providers are skipped. */
|
|
25
|
+
export interface MenaChannelOptions {
|
|
26
|
+
readonly sms?: ChannelOpenOptions;
|
|
27
|
+
readonly unifonic?: ChannelOpenOptions;
|
|
28
|
+
readonly msegat?: ChannelOpenOptions;
|
|
29
|
+
readonly mail?: ChannelOpenOptions;
|
|
30
|
+
readonly whatsapp?: ChannelOpenOptions;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Open the MENA drivers that have options.
|
|
35
|
+
*
|
|
36
|
+
* @param options - Per-provider credentials (`bearerToken` / `sender` / …)
|
|
37
|
+
*/
|
|
38
|
+
export function menaChannels(options: MenaChannelOptions = {}): ChannelDriver[] {
|
|
39
|
+
const drivers: ChannelDriver[] = [];
|
|
40
|
+
if (options.sms) drivers.push(openTaqnyatChannel(options.sms));
|
|
41
|
+
if (options.unifonic) drivers.push(openUnifonicChannel(options.unifonic));
|
|
42
|
+
if (options.msegat) drivers.push(openMsegatChannel(options.msegat));
|
|
43
|
+
if (options.mail) drivers.push(openTaqnyatMailChannel(options.mail));
|
|
44
|
+
if (options.whatsapp) drivers.push(openTaqnyatWhatsAppChannel(options.whatsapp));
|
|
45
|
+
return drivers;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Headline plugin. Attach with `.plug(mena())`. Drivers come from
|
|
50
|
+
* {@link menaChannels}; this registration is the product name.
|
|
51
|
+
*
|
|
52
|
+
* @param options - Unused today; reserved for plugin config
|
|
53
|
+
*/
|
|
54
|
+
export function mena(options: MenaChannelOptions = {}): PluginDef {
|
|
55
|
+
return plugin("mena", { version: "1", config: options });
|
|
56
|
+
}
|
package/src/runtime/bun.ts
CHANGED
|
@@ -149,6 +149,7 @@ export function serveBunHttp(options: {
|
|
|
149
149
|
readonly fetch: (request: Request) => Response | Promise<Response>;
|
|
150
150
|
readonly routes?: Record<string, MethodHandlers>;
|
|
151
151
|
readonly id?: string;
|
|
152
|
+
readonly maxRequestBodySize?: number;
|
|
152
153
|
}): ReturnType<typeof Bun.serve> {
|
|
153
154
|
const fetch = holdSseIdle(
|
|
154
155
|
typeof options.fetch === "function"
|
|
@@ -158,6 +159,7 @@ export function serveBunHttp(options: {
|
|
|
158
159
|
const base = {
|
|
159
160
|
port: options.port,
|
|
160
161
|
hostname: options.hostname,
|
|
162
|
+
maxRequestBodySize: options.maxRequestBodySize ?? 1_048_576,
|
|
161
163
|
fetch,
|
|
162
164
|
...(options.id !== undefined ? { id: options.id } : {}),
|
|
163
165
|
};
|
|
@@ -185,6 +187,9 @@ function listenBun(app: FetchApp, options?: ServeOptions): ServerHandle {
|
|
|
185
187
|
fetch: fetchHandler,
|
|
186
188
|
routes,
|
|
187
189
|
...(options?.id !== undefined ? { id: options.id } : {}),
|
|
190
|
+
...(options?.maxRequestBodySize !== undefined
|
|
191
|
+
? { maxRequestBodySize: options.maxRequestBodySize }
|
|
192
|
+
: {}),
|
|
188
193
|
});
|
|
189
194
|
|
|
190
195
|
const closeIdle = (
|
package/src/runtime/types.ts
CHANGED
|
@@ -72,6 +72,11 @@ export interface ServeOptions {
|
|
|
72
72
|
* never replaces the mandatory check.
|
|
73
73
|
*/
|
|
74
74
|
readonly allowedHosts?: readonly string[];
|
|
75
|
+
/**
|
|
76
|
+
* Bun.serve body backstop in bytes. Default 1 MiB. Raise it together with
|
|
77
|
+
* `maxRequestBodySize` when a route accepts a larger body.
|
|
78
|
+
*/
|
|
79
|
+
readonly maxRequestBodySize?: number;
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
/** Handle returned by {@link Runtime.serve}. */
|