@pikku/core 0.12.137 → 0.12.138

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/dev/hot-reload.js +5 -2
  3. package/dist/env.d.ts +18 -0
  4. package/dist/env.js +60 -1
  5. package/dist/function/abort-scope.d.ts +6 -5
  6. package/dist/function/abort-scope.js +6 -17
  7. package/dist/function/function-runner.js +2 -1
  8. package/dist/middleware/auth-apikey.js +1 -1
  9. package/dist/middleware/auth-bearer.js +1 -1
  10. package/dist/middleware/auth-cookie.js +1 -1
  11. package/dist/schema.js +3 -1
  12. package/dist/services/in-memory-queue-service.js +4 -2
  13. package/dist/services/in-memory-workflow-service.js +7 -6
  14. package/dist/services/index.d.ts +0 -1
  15. package/dist/services/index.js +0 -1
  16. package/dist/services/local-variables.d.ts +5 -0
  17. package/dist/services/local-variables.js +7 -2
  18. package/dist/services/queue-webhook-service.js +1 -1
  19. package/dist/services/webhook-service.d.ts +2 -2
  20. package/dist/services/webhook-service.js +6 -4
  21. package/dist/types/core.types.d.ts +10 -1
  22. package/dist/utils/hmac.d.ts +25 -10
  23. package/dist/utils/hmac.js +202 -24
  24. package/dist/wirings/agent/agent-agui.js +65 -62
  25. package/dist/wirings/agent/agent-interrupt.d.ts +4 -1
  26. package/dist/wirings/agent/agent-interrupt.js +3 -3
  27. package/dist/wirings/agent/agent-memory.js +5 -6
  28. package/dist/wirings/agent/agent-model-config.js +2 -1
  29. package/dist/wirings/agent/agent-prepare.js +21 -13
  30. package/dist/wirings/agent/agent-stream.js +38 -34
  31. package/dist/wirings/agent/agent.types.d.ts +8 -1
  32. package/dist/wirings/channel/channel-handler.js +1 -1
  33. package/dist/wirings/channel/local/local-channel-handler.js +5 -1
  34. package/dist/wirings/channel/local/local-channel-runner.js +6 -4
  35. package/dist/wirings/channel/local/local-eventhub-service.d.ts +1 -0
  36. package/dist/wirings/channel/local/local-eventhub-service.js +4 -1
  37. package/dist/wirings/cli/channel/cli-channel-runner.js +7 -2
  38. package/dist/wirings/cli/channel/cli-raw-client-runner.js +8 -4
  39. package/dist/wirings/cli/cli-runner.js +1 -1
  40. package/dist/wirings/gateway/gateway-runner.js +3 -3
  41. package/dist/wirings/http/http-runner.js +6 -6
  42. package/dist/wirings/scheduler/scheduler-runner.js +1 -1
  43. package/dist/wirings/scope/define-scope.d.ts +19 -0
  44. package/dist/wirings/scope/define-scope.js +19 -0
  45. package/dist/wirings/scope/index.d.ts +1 -1
  46. package/dist/wirings/scope/index.js +1 -1
  47. package/dist/wirings/trigger/trigger-runner.js +3 -1
  48. package/dist/wirings/trigger/webhook-source-runner.js +5 -2
  49. package/dist/wirings/virtual-user/virtual-user-scaffold.js +3 -2
  50. package/dist/wirings/workflow/workflow-invocation-id.js +85 -8
  51. package/package.json +3 -1
  52. package/src/public-surface.json +6 -3
@@ -43,7 +43,9 @@ export async function setupTrigger({ name, input, onTrigger, }) {
43
43
  trigger: {
44
44
  invoke: (data) => {
45
45
  singletonServices.logger.info(`Trigger fired: ${name}`);
46
- onTrigger(data);
46
+ // `invoke` is typed void for trigger sources, so a rejection from the
47
+ // trigger function is logged here rather than left unhandled.
48
+ Promise.resolve(onTrigger(data)).catch((e) => singletonServices.logger.error(`Trigger '${name}' handler failed: ${e?.message ?? e}`));
47
49
  },
48
50
  },
49
51
  };
@@ -63,6 +63,9 @@ const readRequest = async (http) => {
63
63
  };
64
64
  };
65
65
  const signedWith = async (verify, request, secret, services) => {
66
+ // Fail closed: an empty secret never verifies, whatever the scheme.
67
+ if (!secret)
68
+ return false;
66
69
  if (typeof verify === 'function') {
67
70
  return await verify(request, secret, services);
68
71
  }
@@ -72,14 +75,14 @@ const signedWith = async (verify, request, secret, services) => {
72
75
  };
73
76
  if ('hmac' in verify) {
74
77
  const { header: name, prefix, algorithm, encoding, secretEncoding, } = verify.hmac;
75
- return verifyHmacSignature(secret, header(name, prefix), algorithm, request.body, encoding, secretEncoding);
78
+ return await verifyHmacSignature(secret, header(name, prefix), algorithm, request.body, encoding, secretEncoding);
76
79
  }
77
80
  if ('token' in verify) {
78
81
  const token = header(verify.token.header, verify.token.prefix);
79
82
  return !!token && timingSafeStringEqual(token, secret);
80
83
  }
81
84
  const { header: name, ...options } = verify.publicKey;
82
- return verifyPublicKeySignature(secret, header(name), request.body, options);
85
+ return await verifyPublicKeySignature(secret, header(name), request.body, options);
83
86
  };
84
87
  /**
85
88
  * Whether the request was signed with the source's secret. A request with a
@@ -1,3 +1,4 @@
1
+ import { readEnvVariable } from '../../env.js';
1
2
  import { BadRequestError, ForbiddenError } from '../../errors/errors.js';
2
3
  import { prepareVirtualUserRun } from './prepare-virtual-user-run.js';
3
4
  import { runVirtualUser as runVirtualUserEngine } from './run-virtual-user.js';
@@ -122,7 +123,7 @@ const refuseInProduction = (personaId, disposition, config, environments, enviro
122
123
  * scheduled tick have in common. The dispatch that follows is typed off the
123
124
  * app's RPC map, so it stays in the generated wiring.
124
125
  */
125
- export const startVirtualUserRun = async ({ store, personas, config, environments, environment = process.env.PIKKU_ENV, persona: personaId, disposition: requested, seed: requestedSeed, goals, memory, startedBy, }) => {
126
+ export const startVirtualUserRun = async ({ store, personas, config, environments, environment = readEnvVariable('PIKKU_ENV'), persona: personaId, disposition: requested, seed: requestedSeed, goals, memory, startedBy, }) => {
126
127
  const runStore = requireVirtualUserRunStore(store);
127
128
  const persona = runnablePersona(personas, personaId);
128
129
  const disposition = (requested ??
@@ -251,7 +252,7 @@ export const serializeVirtualUserSchedule = (schedule, personas) => {
251
252
  * keeps what it had: enabling a row saved earlier as adversarial is refused
252
253
  * just as saving one would be.
253
254
  */
254
- export const writeVirtualUserSchedule = async ({ store, personas, persona, enabled, disposition, goals, budget, minIntervalMs, maxIntervalMs, nextRunAt, config, environments, environment = process.env.PIKKU_ENV, }) => {
255
+ export const writeVirtualUserSchedule = async ({ store, personas, persona, enabled, disposition, goals, budget, minIntervalMs, maxIntervalMs, nextRunAt, config, environments, environment = readEnvVariable('PIKKU_ENV'), }) => {
255
256
  const scheduleStore = requireVirtualUserScheduleStore(store);
256
257
  const declared = runnablePersona(personas, persona);
257
258
  const current = enabled === undefined || disposition === undefined
@@ -1,16 +1,93 @@
1
- import { createHash } from 'node:crypto';
2
1
  const PIKKU_WORKFLOW_NAMESPACE = '70696b6b-7500-5770-9f6c-6f77000a0001';
3
- const parseUuid = (uuid) => Buffer.from(uuid.replace(/-/g, ''), 'hex');
2
+ const encoder = new TextEncoder();
3
+ const parseUuid = (uuid) => {
4
+ const hex = uuid.replace(/-/g, '');
5
+ const bytes = new Uint8Array(hex.length / 2);
6
+ for (let i = 0; i < bytes.length; i++) {
7
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
8
+ }
9
+ return bytes;
10
+ };
4
11
  const formatUuid = (bytes) => {
5
- const hex = bytes.toString('hex');
12
+ let hex = '';
13
+ for (const b of bytes)
14
+ hex += b.toString(16).padStart(2, '0');
6
15
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
7
16
  };
17
+ /**
18
+ * SHA-1 (FIPS 180-4). Web Crypto only offers an async digest and `uuidv5` is
19
+ * called synchronously (and is a public export), so this is a small pure-JS
20
+ * one. It only derives dedupe IDs, never anything secret.
21
+ */
22
+ const sha1 = (message) => {
23
+ const padded = new Uint8Array(((message.length + 9 + 63) >> 6) << 6);
24
+ padded.set(message);
25
+ padded[message.length] = 0x80;
26
+ const view = new DataView(padded.buffer);
27
+ view.setUint32(padded.length - 8, Math.floor((message.length * 8) / 2 ** 32));
28
+ view.setUint32(padded.length - 4, (message.length * 8) >>> 0);
29
+ let h0 = 0x67452301;
30
+ let h1 = 0xefcdab89;
31
+ let h2 = 0x98badcfe;
32
+ let h3 = 0x10325476;
33
+ let h4 = 0xc3d2e1f0;
34
+ const w = new Uint32Array(80);
35
+ const rotl = (x, n) => (x << n) | (x >>> (32 - n));
36
+ for (let offset = 0; offset < padded.length; offset += 64) {
37
+ for (let i = 0; i < 16; i++)
38
+ w[i] = view.getUint32(offset + i * 4);
39
+ for (let i = 16; i < 80; i++) {
40
+ w[i] = rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
41
+ }
42
+ let a = h0;
43
+ let b = h1;
44
+ let c = h2;
45
+ let d = h3;
46
+ let e = h4;
47
+ for (let i = 0; i < 80; i++) {
48
+ let f;
49
+ let k;
50
+ if (i < 20) {
51
+ f = (b & c) | (~b & d);
52
+ k = 0x5a827999;
53
+ }
54
+ else if (i < 40) {
55
+ f = b ^ c ^ d;
56
+ k = 0x6ed9eba1;
57
+ }
58
+ else if (i < 60) {
59
+ f = (b & c) | (b & d) | (c & d);
60
+ k = 0x8f1bbcdc;
61
+ }
62
+ else {
63
+ f = b ^ c ^ d;
64
+ k = 0xca62c1d6;
65
+ }
66
+ const temp = (rotl(a, 5) + f + e + k + w[i]) >>> 0;
67
+ e = d;
68
+ d = c;
69
+ c = rotl(b, 30) >>> 0;
70
+ b = a;
71
+ a = temp;
72
+ }
73
+ h0 = (h0 + a) >>> 0;
74
+ h1 = (h1 + b) >>> 0;
75
+ h2 = (h2 + c) >>> 0;
76
+ h3 = (h3 + d) >>> 0;
77
+ h4 = (h4 + e) >>> 0;
78
+ }
79
+ const out = new Uint8Array(20);
80
+ const outView = new DataView(out.buffer);
81
+ [h0, h1, h2, h3, h4].forEach((h, i) => outView.setUint32(i * 4, h));
82
+ return out;
83
+ };
8
84
  export const uuidv5 = (name, namespace = PIKKU_WORKFLOW_NAMESPACE) => {
9
- const hash = createHash('sha1')
10
- .update(parseUuid(namespace))
11
- .update(name, 'utf8')
12
- .digest();
13
- const bytes = hash.subarray(0, 16);
85
+ const ns = parseUuid(namespace);
86
+ const nameBytes = encoder.encode(name);
87
+ const input = new Uint8Array(ns.length + nameBytes.length);
88
+ input.set(ns);
89
+ input.set(nameBytes, ns.length);
90
+ const bytes = sha1(input).subarray(0, 16);
14
91
  bytes[6] = (bytes[6] & 0x0f) | 0x50;
15
92
  bytes[8] = (bytes[8] & 0x3f) | 0x80;
16
93
  return formatUuid(bytes);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.12.137",
3
+ "version": "0.12.138",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",
@@ -81,6 +81,7 @@
81
81
  "./services/local-content": "./dist/services/local-content.js",
82
82
  "./services/local-content-request-handler": "./dist/services/local-content-request-handler.js",
83
83
  "./services/temporary-file-service": "./dist/services/temporary-file-service.js",
84
+ "./services/file-scenario-run-store": "./dist/services/file-scenario-run-store.js",
84
85
  "./crypto-utils": "./dist/crypto-utils.js",
85
86
  "./hmac": "./dist/utils/hmac.js",
86
87
  "./state": "./dist/pikku-state.js",
@@ -100,6 +101,7 @@
100
101
  },
101
102
  "devDependencies": {
102
103
  "@ag-ui/core": "0.0.57",
104
+ "@pikku/deploy": "^0.12.15",
103
105
  "@types/node": "^24.13.3",
104
106
  "esbuild": "~0.28.2",
105
107
  "tsx": "^4.23.12"
@@ -326,6 +326,7 @@
326
326
  "validateAndBuildCredentialDefinitionsMeta"
327
327
  ],
328
328
  "./scope": [
329
+ "declareScopes",
329
330
  "defineScope",
330
331
  "flattenScopeDefinitions",
331
332
  "hasScopes",
@@ -432,7 +433,6 @@
432
433
  "ACTOR_SECRET_NAME",
433
434
  "ConsoleLogger",
434
435
  "DEFAULT_WEBHOOK_RETRIES",
435
- "FileScenarioRunStore",
436
436
  "InMemoryAgentRunStateService",
437
437
  "InMemoryLeaseService",
438
438
  "InMemoryQueueService",
@@ -482,8 +482,6 @@
482
482
  "pikkuRemoteScheduledJobFunc",
483
483
  "pikkuWebhookWorkerFunc",
484
484
  "renderEmail",
485
- "scenarioArtifactContentType",
486
- "scenarioRunSummary",
487
485
  "spy",
488
486
  "stub",
489
487
  "verifyActorSecret",
@@ -510,6 +508,11 @@
510
508
  "createLocalContentRequestHandler",
511
509
  "verifySignedContentRequest"
512
510
  ],
511
+ "./services/file-scenario-run-store": [
512
+ "FileScenarioRunStore",
513
+ "scenarioArtifactContentType",
514
+ "scenarioRunSummary"
515
+ ],
513
516
  "./services/temporary-file-service": [
514
517
  "TemporaryFileInstance",
515
518
  "TemporaryFileService"