@pikku/core 0.12.63 → 0.12.64
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/CHANGELOG.md +147 -0
- package/dist/dev/hot-reload.js +13 -55
- package/dist/dev/module-runner.d.ts +14 -0
- package/dist/dev/module-runner.js +59 -0
- package/dist/dev/reload-meta.d.ts +13 -0
- package/dist/dev/reload-meta.js +22 -0
- package/dist/errors/errors.d.ts +12 -0
- package/dist/errors/errors.js +19 -0
- package/dist/function/function-runner.d.ts +5 -5
- package/dist/function/function-runner.js +39 -111
- package/dist/function/functions.types.d.ts +17 -7
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/middleware/auth-apikey.d.ts +1 -0
- package/dist/middleware/auth-bearer.d.ts +1 -0
- package/dist/middleware/auth-cookie.d.ts +1 -0
- package/dist/middleware/cors.d.ts +1 -0
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/remote-auth.d.ts +1 -0
- package/dist/middleware/telemetry.d.ts +2 -0
- package/dist/middleware/timeout.d.ts +1 -0
- package/dist/permissions.d.ts +32 -25
- package/dist/permissions.js +104 -185
- package/dist/pikku-state.js +0 -2
- package/dist/scopes.d.ts +17 -0
- package/dist/scopes.js +59 -0
- package/dist/services/ai-embedding-service.d.ts +31 -0
- package/dist/services/ai-embedding-service.js +1 -0
- package/dist/services/credential-wire-service.d.ts +3 -1
- package/dist/services/credential-wire-service.js +10 -4
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +2 -0
- package/dist/services/meta-service.d.ts +15 -2
- package/dist/services/meta-service.js +51 -1
- package/dist/services/queue-webhook-service.d.ts +55 -0
- package/dist/services/queue-webhook-service.js +136 -0
- package/dist/services/scope-service.d.ts +67 -0
- package/dist/services/scope-service.js +1 -0
- package/dist/services/typed-secret-service.d.ts +8 -0
- package/dist/services/typed-secret-service.js +39 -4
- package/dist/services/webhook-service.d.ts +140 -0
- package/dist/services/webhook-service.js +44 -0
- package/dist/services/workflow-service.d.ts +7 -0
- package/dist/types/core.types.d.ts +34 -6
- package/dist/types/state.types.d.ts +20 -2
- package/dist/utils/hmac.d.ts +16 -0
- package/dist/utils/hmac.js +26 -0
- package/dist/utils/safe-fetch.d.ts +51 -0
- package/dist/utils/safe-fetch.js +192 -0
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +84 -0
- package/dist/wirings/ai-agent/ai-agent-agui.js +305 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +41 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.js +146 -6
- package/dist/wirings/ai-agent/ai-agent-runner.js +6 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +61 -10
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +27 -1
- package/dist/wirings/ai-agent/index.d.ts +1 -0
- package/dist/wirings/ai-agent/index.js +1 -0
- package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
- package/dist/wirings/ai-agent/voice-input.js +2 -38
- package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
- package/dist/wirings/channel/channel-common.js +0 -1
- package/dist/wirings/channel/channel-handler.js +1 -4
- package/dist/wirings/channel/channel-middleware-runner.d.ts +12 -0
- package/dist/wirings/channel/channel-middleware-runner.js +34 -19
- package/dist/wirings/channel/channel.types.d.ts +2 -6
- package/dist/wirings/cli/cli-runner.js +0 -2
- package/dist/wirings/cli/cli.types.d.ts +1 -2
- package/dist/wirings/http/http-routes.js +0 -3
- package/dist/wirings/http/http-runner.d.ts +9 -29
- package/dist/wirings/http/http-runner.js +9 -34
- package/dist/wirings/http/http.types.d.ts +1 -9
- package/dist/wirings/mcp/mcp-runner.js +0 -2
- package/dist/wirings/mcp/mcp.types.d.ts +5 -11
- package/dist/wirings/oauth2/index.d.ts +0 -3
- package/dist/wirings/oauth2/index.js +1 -2
- package/dist/wirings/rpc/addon-runner.d.ts +28 -0
- package/dist/wirings/rpc/addon-runner.js +173 -0
- package/dist/wirings/rpc/index.d.ts +5 -1
- package/dist/wirings/rpc/index.js +3 -1
- package/dist/wirings/rpc/remote-addon-auth.d.ts +26 -0
- package/dist/wirings/rpc/remote-addon-auth.js +43 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +19 -0
- package/dist/wirings/rpc/rpc-runner.js +109 -3
- package/dist/wirings/rpc/rpc-types.d.ts +15 -1
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +47 -0
- package/dist/wirings/rpc/wire-remote-addon.js +19 -0
- package/dist/wirings/scope/index.d.ts +3 -0
- package/dist/wirings/scope/index.js +2 -0
- package/dist/wirings/scope/scope.types.d.ts +39 -0
- package/dist/wirings/scope/scope.types.js +1 -0
- package/dist/wirings/scope/validate-scope-definitions.d.ts +16 -0
- package/dist/wirings/scope/validate-scope-definitions.js +76 -0
- package/dist/wirings/scope/wire-scope.d.ts +33 -0
- package/dist/wirings/scope/wire-scope.js +32 -0
- package/dist/wirings/workflow/dsl/index.d.ts +1 -1
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +53 -1
- package/dist/wirings/workflow/graph/graph-node.d.ts +2 -0
- package/dist/wirings/workflow/graph/graph-runner.js +3 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +6 -0
- package/dist/wirings/workflow/graph/wire-workflow-graph.js +1 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +5 -0
- package/dist/wirings/workflow/index.d.ts +2 -2
- package/dist/wirings/workflow/index.js +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +51 -1
- package/dist/wirings/workflow/pikku-workflow-service.js +171 -0
- package/dist/wirings/workflow/workflow.types.d.ts +1 -1
- package/package.json +5 -1
- package/run-tests.sh +1 -0
- package/src/dev/hot-reload.ts +13 -68
- package/src/dev/module-runner.test.ts +169 -0
- package/src/dev/module-runner.ts +103 -0
- package/src/dev/reload-meta.test.ts +31 -2
- package/src/dev/reload-meta.ts +26 -0
- package/src/errors/errors.ts +24 -0
- package/src/function/function-runner.test.ts +276 -142
- package/src/function/function-runner.ts +52 -145
- package/src/function/functions.types.ts +28 -38
- package/src/index.ts +8 -6
- package/src/middleware/index.ts +1 -5
- package/src/permissions.test.ts +153 -372
- package/src/permissions.ts +139 -259
- package/src/pikku-state.ts +0 -2
- package/src/scopes.test.ts +167 -0
- package/src/scopes.ts +69 -0
- package/src/services/ai-embedding-service.ts +31 -0
- package/src/services/credential-wire-service.ts +10 -4
- package/src/services/index.ts +20 -0
- package/src/services/meta-service.ts +68 -3
- package/src/services/queue-webhook-service.test.ts +408 -0
- package/src/services/queue-webhook-service.ts +182 -0
- package/src/services/scope-service.ts +75 -0
- package/src/services/typed-secret-service.test.ts +35 -0
- package/src/services/typed-secret-service.ts +39 -4
- package/src/services/webhook-service.ts +180 -0
- package/src/services/workflow-service.ts +7 -0
- package/src/types/core.types.ts +42 -14
- package/src/types/state.types.ts +23 -3
- package/src/utils/hmac.ts +27 -0
- package/src/utils/safe-fetch.test.ts +373 -0
- package/src/utils/safe-fetch.ts +213 -0
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +1127 -0
- package/src/wirings/ai-agent/ai-agent-agui.ts +386 -0
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +308 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +192 -8
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +48 -1
- package/src/wirings/ai-agent/ai-agent-runner.ts +21 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +198 -10
- package/src/wirings/ai-agent/ai-agent-stream.ts +84 -10
- package/src/wirings/ai-agent/ai-agent.types.ts +28 -0
- package/src/wirings/ai-agent/index.ts +1 -0
- package/src/wirings/ai-agent/voice-input.ts +6 -35
- package/src/wirings/channel/channel-common.ts +0 -1
- package/src/wirings/channel/channel-handler.ts +1 -9
- package/src/wirings/channel/channel-middleware-runner.test.ts +28 -2
- package/src/wirings/channel/channel-middleware-runner.ts +39 -27
- package/src/wirings/channel/channel.types.ts +0 -6
- package/src/wirings/cli/cli-runner.ts +0 -2
- package/src/wirings/cli/cli.types.ts +0 -2
- package/src/wirings/http/http-routes.ts +0 -3
- package/src/wirings/http/http-runner.test.ts +1 -11
- package/src/wirings/http/http-runner.ts +16 -39
- package/src/wirings/http/http.types.ts +1 -10
- package/src/wirings/mcp/mcp-runner.ts +0 -2
- package/src/wirings/mcp/mcp.types.ts +3 -11
- package/src/wirings/oauth2/index.ts +0 -3
- package/src/wirings/rpc/addon-runner.ts +233 -0
- package/src/wirings/rpc/index.ts +17 -1
- package/src/wirings/rpc/remote-addon-auth.ts +69 -0
- package/src/wirings/rpc/rpc-runner.test.ts +319 -16
- package/src/wirings/rpc/rpc-runner.ts +155 -3
- package/src/wirings/rpc/rpc-types.ts +16 -5
- package/src/wirings/rpc/wire-addon.test.ts +6 -3
- package/src/wirings/rpc/wire-addon.ts +9 -0
- package/src/wirings/rpc/wire-remote-addon.ts +57 -0
- package/src/wirings/scope/index.ts +14 -0
- package/src/wirings/scope/scope.test.ts +135 -0
- package/src/wirings/scope/scope.types.ts +44 -0
- package/src/wirings/scope/validate-scope-definitions.ts +110 -0
- package/src/wirings/scope/wire-scope.ts +34 -0
- package/src/wirings/workflow/dsl/index.ts +4 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +61 -0
- package/src/wirings/workflow/graph/graph-node.ts +2 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +58 -0
- package/src/wirings/workflow/graph/graph-runner.ts +3 -0
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +5 -0
- package/src/wirings/workflow/index.ts +5 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +341 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +236 -0
- package/src/wirings/workflow/workflow-step-session.test.ts +21 -5
- package/src/wirings/workflow/workflow.types.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/wirings/oauth2/oauth2-client.test.ts +0 -930
- package/src/wirings/oauth2/oauth2-client.ts +0 -331
- package/src/wirings/oauth2/oauth2-routes.ts +0 -234
|
@@ -3,7 +3,7 @@ import { AIProviderNotConfiguredError } from '../../errors/errors.js';
|
|
|
3
3
|
import { randomUUID } from './ai-agent-utils.js';
|
|
4
4
|
import { combineChannelMiddleware, wrapChannelWithMiddleware, } from '../channel/channel-middleware-runner.js';
|
|
5
5
|
import { resolveMemoryServices, loadContextMessages, trimMessages, getWorkingMemoryMiddleware, } from './ai-agent-memory.js';
|
|
6
|
-
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, createScopedChannel, ToolApprovalRequired, ToolCredentialRequired, } from './ai-agent-prepare.js';
|
|
6
|
+
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, createScopedChannel, resolveOwnerResourceId, agentSessionScope, assertResourceOwner, ToolApprovalRequired, ToolCredentialRequired, APPROVAL_REQUIRED, } from './ai-agent-prepare.js';
|
|
7
7
|
import { resolveModelConfig } from './ai-agent-model-config.js';
|
|
8
8
|
function createPersistingChannel(parent, storage, threadId) {
|
|
9
9
|
let fullText = '';
|
|
@@ -213,14 +213,23 @@ export function checkForApprovals(stepResult, tools, runId) {
|
|
|
213
213
|
approvals.push(new ToolApprovalRequired(tc.toolCallId, tc.toolName, tc.args));
|
|
214
214
|
continue;
|
|
215
215
|
}
|
|
216
|
+
// The approval marker is only trusted from a framework tool declared with
|
|
217
|
+
// `forwardsApproval` (the sub-agent delegating tools) AND carrying the
|
|
218
|
+
// non-forgeable `APPROVAL_REQUIRED` Symbol brand. A plain tool's output — or
|
|
219
|
+
// a delegating tool's LLM-shaped `result.object`, which an attacker can
|
|
220
|
+
// influence — is plain JSON and can never carry the Symbol, so it can never
|
|
221
|
+
// forge an approval/suspension.
|
|
222
|
+
if (!toolDef?.forwardsApproval) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
216
225
|
const tr = stepResult.toolResults.find((r) => r.toolCallId === tc.toolCallId);
|
|
217
226
|
if (tr?.result &&
|
|
218
227
|
typeof tr.result === 'object' &&
|
|
219
|
-
|
|
228
|
+
APPROVAL_REQUIRED in tr.result) {
|
|
220
229
|
const r = tr.result;
|
|
221
230
|
if (r.subApprovals?.length) {
|
|
222
231
|
for (const sub of r.subApprovals) {
|
|
223
|
-
approvals.push(new ToolApprovalRequired(sub.toolCallId, r.toolName, r.args,
|
|
232
|
+
approvals.push(new ToolApprovalRequired(sub.toolCallId, r.toolName, r.args, sub.reason, sub.toolName, sub.args, r.agentRunId));
|
|
224
233
|
}
|
|
225
234
|
}
|
|
226
235
|
else {
|
|
@@ -341,16 +350,32 @@ function handleCredentialRequests(requests, runId, channel, aiRunState, persisti
|
|
|
341
350
|
suspendReason: 'credential',
|
|
342
351
|
pendingApprovals,
|
|
343
352
|
});
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
//
|
|
353
|
+
// The __credentialRequired tool result is suppressed from the stream, so
|
|
354
|
+
// credential-request events (with the runId needed for /resume) are the
|
|
355
|
+
// client's signal to show Connect/Ignore buttons — mirroring how
|
|
356
|
+
// approval-request suspensions work.
|
|
357
|
+
for (const req of requests) {
|
|
358
|
+
channel.send({
|
|
359
|
+
type: 'credential-request',
|
|
360
|
+
toolCallId: req.toolCallId,
|
|
361
|
+
toolName: req.toolName,
|
|
362
|
+
args: req.args,
|
|
363
|
+
credentialName: req.credentialName,
|
|
364
|
+
credentialType: req.credentialType,
|
|
365
|
+
connectUrl: req.connectUrl,
|
|
366
|
+
runId,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
347
369
|
channel.send({ type: 'done' });
|
|
348
370
|
channel.close();
|
|
349
371
|
})();
|
|
350
372
|
}
|
|
351
373
|
export async function streamAIAgent(agentName, input, channel, params, agentSessionMap, options) {
|
|
352
374
|
const sessionMap = agentSessionMap ?? new Map();
|
|
353
|
-
const normalizedInput =
|
|
375
|
+
const normalizedInput = {
|
|
376
|
+
...input,
|
|
377
|
+
resourceId: resolveOwnerResourceId(params, agentSessionScope(agentName), input.resourceId),
|
|
378
|
+
};
|
|
354
379
|
const streamContext = { channel, options };
|
|
355
380
|
// delegateState is attached after prepareAgentRun resolves the agent config
|
|
356
381
|
const { agent, packageName, resolvedName, agentRunner, storage, memoryConfig, threadId, userMessage, runnerParams, maxSteps, missingRpcs, workingMemorySchemaName, } = await prepareAgentRun(agentName, normalizedInput, params, sessionMap, streamContext);
|
|
@@ -408,6 +433,7 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
408
433
|
createdAt: new Date(),
|
|
409
434
|
updatedAt: new Date(),
|
|
410
435
|
});
|
|
436
|
+
options?.onRunCreated?.(runId);
|
|
411
437
|
if (storage) {
|
|
412
438
|
await storage.saveMessages(threadId, [userMessage]);
|
|
413
439
|
}
|
|
@@ -447,6 +473,22 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
447
473
|
const wrappedChannel = allChannelMiddleware.length > 0
|
|
448
474
|
? wrapChannelWithMiddleware({ channel: persistingChannel }, singletonServices, allChannelMiddleware).channel
|
|
449
475
|
: persistingChannel;
|
|
476
|
+
// Tool results carrying the __credentialRequired marker must never reach
|
|
477
|
+
// the client or persisted history: the run suspends with credential-request
|
|
478
|
+
// events instead (mirroring approvals), and leaving the tool call
|
|
479
|
+
// unresulted is what lets the client resume it after connecting.
|
|
480
|
+
const credentialFilteredChannel = {
|
|
481
|
+
...wrappedChannel,
|
|
482
|
+
send: (event) => {
|
|
483
|
+
if (event.type === 'tool-result' &&
|
|
484
|
+
event.result !== null &&
|
|
485
|
+
typeof event.result === 'object' &&
|
|
486
|
+
'__credentialRequired' in event.result) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
wrappedChannel.send(event);
|
|
490
|
+
},
|
|
491
|
+
};
|
|
450
492
|
// In delegate mode (default), suppress parent's text from reaching the client
|
|
451
493
|
// AFTER a sub-agent has been called. If the parent responds directly (no delegation),
|
|
452
494
|
// its text goes through normally. Sub-agent text bypasses this path entirely
|
|
@@ -458,16 +500,16 @@ export async function streamAIAgent(agentName, input, channel, params, agentSess
|
|
|
458
500
|
}
|
|
459
501
|
const outputChannel = isDelegateMode
|
|
460
502
|
? {
|
|
461
|
-
...
|
|
503
|
+
...credentialFilteredChannel,
|
|
462
504
|
send: (event) => {
|
|
463
505
|
if (delegateState.delegated &&
|
|
464
506
|
(event.type === 'text-delta' || event.type === 'reasoning-delta'))
|
|
465
507
|
return;
|
|
466
|
-
|
|
508
|
+
credentialFilteredChannel.send(event);
|
|
467
509
|
},
|
|
468
510
|
delegateState,
|
|
469
511
|
}
|
|
470
|
-
:
|
|
512
|
+
: credentialFilteredChannel;
|
|
471
513
|
try {
|
|
472
514
|
const loopResult = await runStreamStepLoop({
|
|
473
515
|
agent,
|
|
@@ -531,6 +573,7 @@ export async function resumeAIAgent(input, channel, params, options) {
|
|
|
531
573
|
if (!run) {
|
|
532
574
|
throw new Error(`No run found for runId ${input.runId}`);
|
|
533
575
|
}
|
|
576
|
+
assertResourceOwner(resolveOwnerResourceId(params, agentSessionScope(run.agentName), run.resourceId), run.resourceId, 'run');
|
|
534
577
|
const pending = run.pendingApprovals?.find((p) => p.toolCallId === input.toolCallId);
|
|
535
578
|
if (!pending) {
|
|
536
579
|
throw new Error(`No pending approval for toolCallId ${input.toolCallId} on run ${input.runId}`);
|
|
@@ -567,6 +610,14 @@ export async function resumeAIAgent(input, channel, params, options) {
|
|
|
567
610
|
},
|
|
568
611
|
]);
|
|
569
612
|
}
|
|
613
|
+
channel.send({
|
|
614
|
+
type: 'tool-result',
|
|
615
|
+
toolCallId: input.toolCallId,
|
|
616
|
+
toolName: pending.type === 'tool-call' || pending.type === 'credential-request'
|
|
617
|
+
? pending.toolName
|
|
618
|
+
: pending.agentName,
|
|
619
|
+
result: denialResult,
|
|
620
|
+
});
|
|
570
621
|
// Check remaining pending approvals
|
|
571
622
|
const updatedRun = await aiRunState.getRun(run.runId);
|
|
572
623
|
const remaining = updatedRun?.pendingApprovals ?? [];
|
|
@@ -100,6 +100,19 @@ export interface AIAgentOutput {
|
|
|
100
100
|
runId: string;
|
|
101
101
|
}>;
|
|
102
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* How an agent's threads/runs are owned and partitioned.
|
|
105
|
+
* - `'user'` (default): owner is the authenticated `session.userId`; the caller's
|
|
106
|
+
* `resourceId` becomes a sub-partition within that user (`userId:resourceId`).
|
|
107
|
+
* - `'org'`: owner is the authenticated `session.orgId` (`orgId:resourceId`), so
|
|
108
|
+
* threads are shared across everyone in the org. Requires a session with an org
|
|
109
|
+
* (e.g. Better Auth's `organization` plugin) — otherwise access is denied.
|
|
110
|
+
*
|
|
111
|
+
* The trusted principal is always the prefix, so a client-supplied `resourceId`
|
|
112
|
+
* can sub-divide within the caller's own boundary but can never widen access to
|
|
113
|
+
* another user's or org's threads.
|
|
114
|
+
*/
|
|
115
|
+
export type SessionScope = 'user' | 'org';
|
|
103
116
|
export interface AIAgentToolDef {
|
|
104
117
|
name: string;
|
|
105
118
|
description: string;
|
|
@@ -107,6 +120,14 @@ export interface AIAgentToolDef {
|
|
|
107
120
|
execute: (input: unknown) => Promise<unknown>;
|
|
108
121
|
needsApproval?: boolean;
|
|
109
122
|
approvalDescriptionFn?: (input: unknown) => Promise<string>;
|
|
123
|
+
/**
|
|
124
|
+
* Set only by the framework on sub-agent delegating tools. Such a tool may
|
|
125
|
+
* legitimately return an `__approvalRequired` marker to forward a nested
|
|
126
|
+
* sub-agent approval. The marker is honored ONLY from a tool with this flag —
|
|
127
|
+
* a plain tool's output (which an attacker may influence) can never forge an
|
|
128
|
+
* approval request. See `checkForApprovals`.
|
|
129
|
+
*/
|
|
130
|
+
forwardsApproval?: boolean;
|
|
110
131
|
}
|
|
111
132
|
export interface PikkuAIMiddlewareHooks<State extends Record<string, unknown> = Record<string, unknown>, Services = any> {
|
|
112
133
|
modifyInput?: (services: Services, ctx: {
|
|
@@ -200,8 +221,11 @@ export type CoreAIAgent<PikkuPermission = CorePikkuPermission<any, any>, PikkuMi
|
|
|
200
221
|
goal: string;
|
|
201
222
|
model: string;
|
|
202
223
|
temperature?: number;
|
|
224
|
+
/** Ownership/partitioning of this agent's threads and runs. Defaults to `'user'`. */
|
|
225
|
+
sessionScope?: SessionScope;
|
|
203
226
|
tools?: unknown[];
|
|
204
227
|
agents?: unknown[];
|
|
228
|
+
workflows?: unknown[];
|
|
205
229
|
agentMode?: 'delegate' | 'supervise';
|
|
206
230
|
memory?: AIAgentMemoryConfig;
|
|
207
231
|
maxSteps?: number;
|
|
@@ -267,6 +291,7 @@ export type AIStreamEvent = {
|
|
|
267
291
|
toolName: string;
|
|
268
292
|
args: unknown;
|
|
269
293
|
reason?: string;
|
|
294
|
+
runId?: string;
|
|
270
295
|
agent?: string;
|
|
271
296
|
session?: string;
|
|
272
297
|
} | {
|
|
@@ -397,9 +422,10 @@ export interface AgentRunService {
|
|
|
397
422
|
deleteThread(threadId: string): Promise<boolean>;
|
|
398
423
|
getDistinctAgentNames(): Promise<string[]>;
|
|
399
424
|
}
|
|
400
|
-
export type AIAgentMeta = Record<string, Omit<CoreAIAgent, 'input' | 'output' | 'tools' | 'agents' | 'middleware' | 'channelMiddleware' | 'aiMiddleware' | 'permissions'> & {
|
|
425
|
+
export type AIAgentMeta = Record<string, Omit<CoreAIAgent, 'input' | 'output' | 'tools' | 'agents' | 'workflows' | 'middleware' | 'channelMiddleware' | 'aiMiddleware' | 'permissions'> & {
|
|
401
426
|
tools?: string[];
|
|
402
427
|
agents?: string[];
|
|
428
|
+
workflows?: string[];
|
|
403
429
|
inputSchema: string | null;
|
|
404
430
|
outputSchema: string | null;
|
|
405
431
|
workingMemorySchema: string | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { agent, agentStream, agentResume, agentApprove, } from './ai-agent-helpers.js';
|
|
2
|
+
export { wrapChannelWithAGUI, type AGUIEvent } from './ai-agent-agui.js';
|
|
2
3
|
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js';
|
|
3
4
|
export { streamAIAgent, resumeAIAgent } from './ai-agent-stream.js';
|
|
4
5
|
export { voiceInput } from './voice-input.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { agent, agentStream, agentResume, agentApprove, } from './ai-agent-helpers.js';
|
|
2
|
+
export { wrapChannelWithAGUI } from './ai-agent-agui.js';
|
|
2
3
|
export { runAIAgent, resumeAIAgentSync } from './ai-agent-runner.js';
|
|
3
4
|
export { streamAIAgent, resumeAIAgent } from './ai-agent-stream.js';
|
|
4
5
|
export { voiceInput } from './voice-input.js';
|
|
@@ -6,5 +6,6 @@ export declare const voiceInput: (config?: {
|
|
|
6
6
|
logLevel?: import("../../services/logger.js").LogLevel;
|
|
7
7
|
secrets?: {};
|
|
8
8
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
9
|
+
webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
|
|
9
10
|
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
10
11
|
}>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { pikkuAIMiddleware } from '../../types/core.types.js';
|
|
2
|
+
import { safeFetch } from '../../utils/safe-fetch.js';
|
|
2
3
|
function base64ToUint8Array(base64) {
|
|
3
4
|
const binary = atob(base64);
|
|
4
5
|
const bytes = new Uint8Array(binary.length);
|
|
@@ -8,45 +9,8 @@ function base64ToUint8Array(base64) {
|
|
|
8
9
|
return bytes;
|
|
9
10
|
}
|
|
10
11
|
const MAX_AUDIO_SIZE = 50 * 1024 * 1024;
|
|
11
|
-
// Portable SSRF guard: @pikku/core runs in edge runtimes (CF Workers) with no
|
|
12
|
-
// Node `dns`, so we cannot resolve hostnames to check for private targets.
|
|
13
|
-
// Reject the obvious internal literals; callers wanting stricter control pass
|
|
14
|
-
// an explicit `allowedAudioHosts` allowlist. (Does not defend against a public
|
|
15
|
-
// hostname that resolves to a private IP / DNS rebinding — out of reach here.)
|
|
16
|
-
function isPrivateHost(hostname) {
|
|
17
|
-
const host = hostname.replace(/^\[|\]$/g, '').toLowerCase();
|
|
18
|
-
if (host === 'localhost' || host === '0.0.0.0' || host === '::1')
|
|
19
|
-
return true;
|
|
20
|
-
if (host.startsWith('fe80:') || host.startsWith('fc') || host.startsWith('fd'))
|
|
21
|
-
return true;
|
|
22
|
-
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.\d{1,3}$/);
|
|
23
|
-
if (v4) {
|
|
24
|
-
const [a, b] = [Number(v4[1]), Number(v4[2])];
|
|
25
|
-
if (a === 127 || a === 10 || a === 0)
|
|
26
|
-
return true;
|
|
27
|
-
if (a === 169 && b === 254)
|
|
28
|
-
return true; // link-local incl. cloud metadata
|
|
29
|
-
if (a === 172 && b >= 16 && b <= 31)
|
|
30
|
-
return true;
|
|
31
|
-
if (a === 192 && b === 168)
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
12
|
async function fetchAsUint8Array(url, allowedAudioHosts) {
|
|
37
|
-
const
|
|
38
|
-
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
39
|
-
throw new Error('Only HTTP(S) URLs are supported for audio');
|
|
40
|
-
}
|
|
41
|
-
if (allowedAudioHosts) {
|
|
42
|
-
if (!allowedAudioHosts.includes(parsed.hostname)) {
|
|
43
|
-
throw new Error(`Audio URL host is not allowed: ${parsed.hostname}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else if (isPrivateHost(parsed.hostname)) {
|
|
47
|
-
throw new Error(`Refusing to fetch audio from a private/internal host: ${parsed.hostname}`);
|
|
48
|
-
}
|
|
49
|
-
const response = await fetch(url);
|
|
13
|
+
const response = await safeFetch(url, {}, { allowedHosts: allowedAudioHosts });
|
|
50
14
|
const contentLength = response.headers.get('content-length');
|
|
51
15
|
if (contentLength && parseInt(contentLength, 10) > MAX_AUDIO_SIZE) {
|
|
52
16
|
throw new Error('Audio file exceeds maximum size');
|
|
@@ -12,6 +12,7 @@ export declare const voiceOutput: (config?: {
|
|
|
12
12
|
logLevel?: import("../../services/logger.js").LogLevel;
|
|
13
13
|
secrets?: {};
|
|
14
14
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
15
|
+
webhook?: import("../../services/webhook-service.js").WebhookServiceConfig;
|
|
15
16
|
postgres?: import("../../types/core.types.js").PostgresConfig;
|
|
16
17
|
}>>;
|
|
17
18
|
export {};
|
|
@@ -49,7 +49,7 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
|
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
const routeMeta = getRouteMeta(channelConfig.name, routingProperty, routerValue);
|
|
52
|
-
const { packageName, middleware: routeInheritedMiddleware
|
|
52
|
+
const { packageName, middleware: routeInheritedMiddleware } = routeMeta;
|
|
53
53
|
const pikkuFuncId = routeMeta.pikkuFuncId;
|
|
54
54
|
// Get wire middleware: channel-level middleware + message-specific middleware
|
|
55
55
|
const channelWireMiddleware = channelConfig.middleware || [];
|
|
@@ -68,7 +68,6 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
|
|
|
68
68
|
const wireMiddleware = [...channelWireMiddleware, ...messageWireMiddleware];
|
|
69
69
|
// Inherited middleware comes from metadata (tag groups, non-inline wire)
|
|
70
70
|
const inheritedMiddleware = routeInheritedMiddleware || [];
|
|
71
|
-
const wirePermissions = isWrapper ? onMessage.permissions : undefined;
|
|
72
71
|
// Create unique cache key that includes routing info to avoid cache collisions
|
|
73
72
|
// when multiple message handlers use the same function
|
|
74
73
|
const cacheKey = routingProperty
|
|
@@ -83,8 +82,6 @@ export const processMessageHandlers = (services, channelConfig, channelHandler,
|
|
|
83
82
|
wireMiddleware,
|
|
84
83
|
inheritedChannelMiddleware: channelMeta?.channelMiddleware,
|
|
85
84
|
wireChannelMiddleware: wireChannelMiddleware,
|
|
86
|
-
inheritedPermissions,
|
|
87
|
-
wirePermissions,
|
|
88
85
|
coerceDataFromSchema: true,
|
|
89
86
|
tags: channelConfig.tags,
|
|
90
87
|
sessionService: userSession,
|
|
@@ -2,6 +2,18 @@ import type { CoreSingletonServices, MiddlewareMetadata, PikkuRawWire } from '..
|
|
|
2
2
|
import type { CorePikkuChannelMiddleware } from './channel.types.js';
|
|
3
3
|
export declare const addChannelMiddleware: (tag: string, middleware: CorePikkuChannelMiddleware[], packageName?: string | null) => CorePikkuChannelMiddleware[];
|
|
4
4
|
export declare const clearChannelMiddlewareCache: () => void;
|
|
5
|
+
/**
|
|
6
|
+
* Combine the inherited (tag/named) channel middleware with any per-run
|
|
7
|
+
* middleware for a wiring.
|
|
8
|
+
*
|
|
9
|
+
* Only the statically-resolved inherited middleware is deterministic per `uid`
|
|
10
|
+
* and safe to cache. `wireChannelMiddleware` is a per-run set of closures (e.g.
|
|
11
|
+
* an AI agent's per-invocation stream middleware holding that run's
|
|
12
|
+
* thread/session state) and MUST NOT be cached — caching it lets a later run of
|
|
13
|
+
* the same `uid` reuse an earlier run's closures, leaking that run's state (and
|
|
14
|
+
* growing memory) across invocations. It is therefore appended fresh on every
|
|
15
|
+
* call after the cached inherited slice.
|
|
16
|
+
*/
|
|
5
17
|
export declare const combineChannelMiddleware: (wireType: string, uid: string, { wireInheritedChannelMiddleware, wireChannelMiddleware, packageName, }?: {
|
|
6
18
|
wireInheritedChannelMiddleware?: MiddlewareMetadata[];
|
|
7
19
|
wireChannelMiddleware?: CorePikkuChannelMiddleware[];
|
|
@@ -16,33 +16,48 @@ export const clearChannelMiddlewareCache = () => {
|
|
|
16
16
|
delete channelMiddlewareCache[key];
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Combine the inherited (tag/named) channel middleware with any per-run
|
|
21
|
+
* middleware for a wiring.
|
|
22
|
+
*
|
|
23
|
+
* Only the statically-resolved inherited middleware is deterministic per `uid`
|
|
24
|
+
* and safe to cache. `wireChannelMiddleware` is a per-run set of closures (e.g.
|
|
25
|
+
* an AI agent's per-invocation stream middleware holding that run's
|
|
26
|
+
* thread/session state) and MUST NOT be cached — caching it lets a later run of
|
|
27
|
+
* the same `uid` reuse an earlier run's closures, leaking that run's state (and
|
|
28
|
+
* growing memory) across invocations. It is therefore appended fresh on every
|
|
29
|
+
* call after the cached inherited slice.
|
|
30
|
+
*/
|
|
19
31
|
export const combineChannelMiddleware = (wireType, uid, { wireInheritedChannelMiddleware, wireChannelMiddleware, packageName = null, } = {}) => {
|
|
20
32
|
const cacheKey = `${wireType}:${uid}`;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
let inherited = channelMiddlewareCache[cacheKey];
|
|
34
|
+
if (!inherited) {
|
|
35
|
+
const resolved = [];
|
|
36
|
+
if (wireInheritedChannelMiddleware) {
|
|
37
|
+
for (const meta of wireInheritedChannelMiddleware) {
|
|
38
|
+
if (meta.type === 'tag') {
|
|
39
|
+
const groups = getTagGroups(pikkuState(packageName, 'channelMiddleware', 'tagGroup'), meta.tag);
|
|
40
|
+
for (const group of groups) {
|
|
41
|
+
resolved.push(...group);
|
|
42
|
+
}
|
|
31
43
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
else if (meta.type === 'wire') {
|
|
45
|
+
const middleware = getChannelMiddlewareByName(meta.name);
|
|
46
|
+
if (middleware) {
|
|
47
|
+
resolved.push(middleware);
|
|
48
|
+
}
|
|
37
49
|
}
|
|
38
50
|
}
|
|
39
51
|
}
|
|
52
|
+
inherited = channelMiddlewareCache[cacheKey] = freezeDedupe(resolved);
|
|
40
53
|
}
|
|
41
|
-
if (wireChannelMiddleware) {
|
|
42
|
-
|
|
54
|
+
if (!wireChannelMiddleware?.length) {
|
|
55
|
+
return inherited;
|
|
43
56
|
}
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
return freezeDedupe([
|
|
58
|
+
...inherited,
|
|
59
|
+
...wireChannelMiddleware,
|
|
60
|
+
]);
|
|
46
61
|
};
|
|
47
62
|
export function wrapChannelWithMiddleware(wire, services, middlewares) {
|
|
48
63
|
if (middlewares.length === 0 || !wire.channel)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { HTTPFunctionMetaInputTypes, PikkuHTTPRequest, PikkuHTTPResponse } from '../http/http.types.js';
|
|
2
|
-
import type { CorePikkuMiddleware, MiddlewareMetadata
|
|
2
|
+
import type { CorePikkuMiddleware, MiddlewareMetadata } from '../../types/core.types.js';
|
|
3
3
|
export type BinaryData = ArrayBuffer | Uint8Array;
|
|
4
4
|
export type CorePikkuChannelMiddleware<Services = any, Event = unknown> = (services: Services, event: Event, next: (event: Event | Event[] | null) => Promise<void> | void) => Promise<void> | void;
|
|
5
5
|
export type CorePikkuChannelMiddlewareFactory<In = any, Services = any, Event = unknown> = (input: In) => CorePikkuChannelMiddleware<Services, Event>;
|
|
6
|
-
import type {
|
|
6
|
+
import type { CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuFunctionSessionless, CorePikkuPermission } from '../../function/functions.types.js';
|
|
7
7
|
export type RunChannelOptions = Partial<{
|
|
8
8
|
skipUserSession: boolean;
|
|
9
9
|
respondWith404: boolean;
|
|
@@ -24,7 +24,6 @@ export interface ChannelMessageMeta {
|
|
|
24
24
|
errors?: string[];
|
|
25
25
|
tags?: string[];
|
|
26
26
|
middleware?: MiddlewareMetadata[];
|
|
27
|
-
permissions?: PermissionMetadata[];
|
|
28
27
|
}
|
|
29
28
|
export interface ChannelMeta {
|
|
30
29
|
name: string;
|
|
@@ -43,7 +42,6 @@ export interface ChannelMeta {
|
|
|
43
42
|
errors?: string[];
|
|
44
43
|
tags?: string[];
|
|
45
44
|
middleware?: MiddlewareMetadata[];
|
|
46
|
-
permissions?: PermissionMetadata[];
|
|
47
45
|
channelMiddleware?: MiddlewareMetadata[];
|
|
48
46
|
}
|
|
49
47
|
export type ChannelsMeta = Record<string, ChannelMeta>;
|
|
@@ -61,13 +59,11 @@ export type CoreChannel<ChannelData, Channel extends string, ChannelConnect = Co
|
|
|
61
59
|
onMessage?: ChannelFunctionMessage;
|
|
62
60
|
onMessageWiring?: Record<string, Record<string, ChannelFunctionMessage | {
|
|
63
61
|
func: ChannelFunctionMessage;
|
|
64
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
65
62
|
auth?: boolean;
|
|
66
63
|
middleware?: PikkuMiddleware[];
|
|
67
64
|
}>>;
|
|
68
65
|
middleware?: PikkuMiddleware[];
|
|
69
66
|
channelMiddleware?: Array<CorePikkuChannelMiddleware | CorePikkuChannelMiddlewareFactory>;
|
|
70
|
-
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
71
67
|
auth?: boolean;
|
|
72
68
|
binary?: boolean | null;
|
|
73
69
|
onBinaryMessage?: (services: any, data: BinaryData, channel: PikkuChannel<ChannelData, any>) => Promise<BinaryData | void> | BinaryData | void;
|
|
@@ -253,8 +253,6 @@ export async function runCLICommand({ program, commandPath, data, singletonServi
|
|
|
253
253
|
auth: false,
|
|
254
254
|
inheritedMiddleware: currentCommand.middleware,
|
|
255
255
|
wireMiddleware: allWireMiddleware,
|
|
256
|
-
inheritedPermissions: currentCommand.permissions,
|
|
257
|
-
wirePermissions: undefined,
|
|
258
256
|
coerceDataFromSchema: true,
|
|
259
257
|
tags: programData?.tags,
|
|
260
258
|
wire,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CorePikkuMiddleware, CoreSingletonServices, CoreUserSession, CoreServices, MiddlewareMetadata
|
|
1
|
+
import type { CorePikkuMiddleware, CoreSingletonServices, CoreUserSession, CoreServices, MiddlewareMetadata } from '../../types/core.types.js';
|
|
2
2
|
import type { CorePikkuFunctionConfig, CorePikkuPermission, CorePikkuFunction, CorePikkuFunctionSessionless } from '../../function/functions.types.js';
|
|
3
3
|
import type { PikkuChannel } from '../channel/channel.types.js';
|
|
4
4
|
/**
|
|
@@ -62,7 +62,6 @@ export interface CLICommandMeta {
|
|
|
62
62
|
tags?: string[];
|
|
63
63
|
subcommands?: Record<string, CLICommandMeta>;
|
|
64
64
|
middleware?: MiddlewareMetadata[];
|
|
65
|
-
permissions?: PermissionMetadata[];
|
|
66
65
|
isDefault?: boolean;
|
|
67
66
|
}
|
|
68
67
|
/**
|
|
@@ -83,7 +83,6 @@ function processRouteMap(map, parentConfig) {
|
|
|
83
83
|
* - tags: Merges (parent + child)
|
|
84
84
|
* - middleware: Merges (parent runs first)
|
|
85
85
|
* - auth: Inner overrides outer
|
|
86
|
-
* - permissions: Inner overrides outer
|
|
87
86
|
*/
|
|
88
87
|
function mergeGroupConfig(parent, child) {
|
|
89
88
|
return {
|
|
@@ -91,7 +90,6 @@ function mergeGroupConfig(parent, child) {
|
|
|
91
90
|
tags: [...(parent.tags || []), ...(child.tags || [])],
|
|
92
91
|
middleware: [...(parent.middleware || []), ...(child.middleware || [])],
|
|
93
92
|
auth: child.auth ?? parent.auth,
|
|
94
|
-
permissions: child.permissions ?? parent.permissions,
|
|
95
93
|
};
|
|
96
94
|
}
|
|
97
95
|
/**
|
|
@@ -109,7 +107,6 @@ function registerRoute(route, groupConfig) {
|
|
|
109
107
|
...(groupConfig.middleware || []),
|
|
110
108
|
...(route.middleware || []),
|
|
111
109
|
],
|
|
112
|
-
permissions: route.permissions ?? groupConfig.permissions,
|
|
113
110
|
contentType: route.contentType,
|
|
114
111
|
timeout: route.timeout,
|
|
115
112
|
headers: route.headers,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CoreHTTPFunctionWiring, RunHTTPWiringOptions, PikkuHTTP, PikkuHTTPRequest, PikkuHTTPResponse } from './http.types.js';
|
|
2
|
-
import type { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission
|
|
2
|
+
import type { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission } from '../../function/functions.types.js';
|
|
3
3
|
import type { CorePikkuMiddleware, CorePikkuMiddlewareGroup } from '../../types/core.types.js';
|
|
4
4
|
import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
|
|
5
5
|
/**
|
|
@@ -33,35 +33,15 @@ import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
|
|
|
33
33
|
*/
|
|
34
34
|
export declare const addHTTPMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(pattern: string, middleware: CorePikkuMiddlewareGroup, packageName?: string | null) => CorePikkuMiddlewareGroup;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @template PikkuPermission The permission type.
|
|
45
|
-
* @param {string} pattern - Route pattern (e.g., '*' for all routes, '/api/*' for specific routes).
|
|
46
|
-
* @param {CorePermissionGroup | CorePikkuPermission[]} permissions - Permissions for this route pattern.
|
|
47
|
-
*
|
|
48
|
-
* @returns {CorePermissionGroup | CorePikkuPermission[]} The permissions (for chaining/wrapping).
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```typescript
|
|
52
|
-
* // Recommended: tree-shakeable
|
|
53
|
-
* export const httpGlobalPermissions = () => addHTTPPermission('*', [
|
|
54
|
-
* authenticatedPermission,
|
|
55
|
-
* rateLimitPermission
|
|
56
|
-
* ])
|
|
57
|
-
*
|
|
58
|
-
* // Also works: no tree-shaking
|
|
59
|
-
* export const apiPermissions = addHTTPPermission('/api/*', [
|
|
60
|
-
* adminPermission
|
|
61
|
-
* ])
|
|
62
|
-
* ```
|
|
36
|
+
* @deprecated HTTP-route-level permissions were removed in #972 — permissions
|
|
37
|
+
* are now function-scoped only (declare them on the function via
|
|
38
|
+
* `pikkuFunc({ permissions })`). This throwing stub exists solely so the pinned
|
|
39
|
+
* bootstrap CLI (which still generates an `addHTTPPermission` wrapper) can
|
|
40
|
+
* resolve the import at build time; it is never called. Delete once
|
|
41
|
+
* `PIKKU_CLI_VERSION` in the CLI build is bumped past the release that removes
|
|
42
|
+
* HTTP-route permissions.
|
|
63
43
|
*/
|
|
64
|
-
export declare const addHTTPPermission:
|
|
44
|
+
export declare const addHTTPPermission: (_pattern: string, _permissions: Record<string, CorePikkuPermission | CorePikkuPermission[]> | CorePikkuPermission[]) => never;
|
|
65
45
|
/**
|
|
66
46
|
* Adds a new route to the global HTTP route registry.
|
|
67
47
|
*
|
|
@@ -64,38 +64,16 @@ export const addHTTPMiddleware = (pattern, middleware, packageName = null) => {
|
|
|
64
64
|
return middleware;
|
|
65
65
|
};
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* @template PikkuPermission The permission type.
|
|
76
|
-
* @param {string} pattern - Route pattern (e.g., '*' for all routes, '/api/*' for specific routes).
|
|
77
|
-
* @param {CorePermissionGroup | CorePikkuPermission[]} permissions - Permissions for this route pattern.
|
|
78
|
-
*
|
|
79
|
-
* @returns {CorePermissionGroup | CorePikkuPermission[]} The permissions (for chaining/wrapping).
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* ```typescript
|
|
83
|
-
* // Recommended: tree-shakeable
|
|
84
|
-
* export const httpGlobalPermissions = () => addHTTPPermission('*', [
|
|
85
|
-
* authenticatedPermission,
|
|
86
|
-
* rateLimitPermission
|
|
87
|
-
* ])
|
|
88
|
-
*
|
|
89
|
-
* // Also works: no tree-shaking
|
|
90
|
-
* export const apiPermissions = addHTTPPermission('/api/*', [
|
|
91
|
-
* adminPermission
|
|
92
|
-
* ])
|
|
93
|
-
* ```
|
|
67
|
+
* @deprecated HTTP-route-level permissions were removed in #972 — permissions
|
|
68
|
+
* are now function-scoped only (declare them on the function via
|
|
69
|
+
* `pikkuFunc({ permissions })`). This throwing stub exists solely so the pinned
|
|
70
|
+
* bootstrap CLI (which still generates an `addHTTPPermission` wrapper) can
|
|
71
|
+
* resolve the import at build time; it is never called. Delete once
|
|
72
|
+
* `PIKKU_CLI_VERSION` in the CLI build is bumped past the release that removes
|
|
73
|
+
* HTTP-route permissions.
|
|
94
74
|
*/
|
|
95
|
-
export const addHTTPPermission = (
|
|
96
|
-
|
|
97
|
-
httpGroups[pattern] = permissions;
|
|
98
|
-
return permissions;
|
|
75
|
+
export const addHTTPPermission = (_pattern, _permissions) => {
|
|
76
|
+
throw new Error('addHTTPPermission was removed in #972 — HTTP-route-level permissions no longer exist. Declare permissions on the function definition instead: pikkuFunc({ permissions }).');
|
|
99
77
|
};
|
|
100
78
|
/**
|
|
101
79
|
* Adds a new route to the global HTTP route registry.
|
|
@@ -156,7 +134,6 @@ const getMatchingRoute = (requestType, requestPath) => {
|
|
|
156
134
|
matchedPath,
|
|
157
135
|
params: matchedPath.params,
|
|
158
136
|
route,
|
|
159
|
-
permissions: route.permissions,
|
|
160
137
|
meta: meta,
|
|
161
138
|
};
|
|
162
139
|
}
|
|
@@ -307,8 +284,6 @@ const executeRoute = async (services, matchedRoute, http, options) => {
|
|
|
307
284
|
data,
|
|
308
285
|
inheritedMiddleware: meta.middleware,
|
|
309
286
|
wireMiddleware: route.middleware,
|
|
310
|
-
inheritedPermissions: meta.permissions,
|
|
311
|
-
wirePermissions: route.permissions,
|
|
312
287
|
coerceDataFromSchema: options.coerceDataFromSchema,
|
|
313
288
|
tags: route.tags,
|
|
314
289
|
wire,
|