@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.
Files changed (198) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/dist/dev/hot-reload.js +13 -55
  3. package/dist/dev/module-runner.d.ts +14 -0
  4. package/dist/dev/module-runner.js +59 -0
  5. package/dist/dev/reload-meta.d.ts +13 -0
  6. package/dist/dev/reload-meta.js +22 -0
  7. package/dist/errors/errors.d.ts +12 -0
  8. package/dist/errors/errors.js +19 -0
  9. package/dist/function/function-runner.d.ts +5 -5
  10. package/dist/function/function-runner.js +39 -111
  11. package/dist/function/functions.types.d.ts +17 -7
  12. package/dist/index.d.ts +5 -1
  13. package/dist/index.js +3 -1
  14. package/dist/middleware/auth-apikey.d.ts +1 -0
  15. package/dist/middleware/auth-bearer.d.ts +1 -0
  16. package/dist/middleware/auth-cookie.d.ts +1 -0
  17. package/dist/middleware/cors.d.ts +1 -0
  18. package/dist/middleware/index.d.ts +1 -1
  19. package/dist/middleware/index.js +1 -1
  20. package/dist/middleware/remote-auth.d.ts +1 -0
  21. package/dist/middleware/telemetry.d.ts +2 -0
  22. package/dist/middleware/timeout.d.ts +1 -0
  23. package/dist/permissions.d.ts +32 -25
  24. package/dist/permissions.js +104 -185
  25. package/dist/pikku-state.js +0 -2
  26. package/dist/scopes.d.ts +17 -0
  27. package/dist/scopes.js +59 -0
  28. package/dist/services/ai-embedding-service.d.ts +31 -0
  29. package/dist/services/ai-embedding-service.js +1 -0
  30. package/dist/services/credential-wire-service.d.ts +3 -1
  31. package/dist/services/credential-wire-service.js +10 -4
  32. package/dist/services/index.d.ts +4 -0
  33. package/dist/services/index.js +2 -0
  34. package/dist/services/meta-service.d.ts +15 -2
  35. package/dist/services/meta-service.js +51 -1
  36. package/dist/services/queue-webhook-service.d.ts +55 -0
  37. package/dist/services/queue-webhook-service.js +136 -0
  38. package/dist/services/scope-service.d.ts +67 -0
  39. package/dist/services/scope-service.js +1 -0
  40. package/dist/services/typed-secret-service.d.ts +8 -0
  41. package/dist/services/typed-secret-service.js +39 -4
  42. package/dist/services/webhook-service.d.ts +140 -0
  43. package/dist/services/webhook-service.js +44 -0
  44. package/dist/services/workflow-service.d.ts +7 -0
  45. package/dist/types/core.types.d.ts +34 -6
  46. package/dist/types/state.types.d.ts +20 -2
  47. package/dist/utils/hmac.d.ts +16 -0
  48. package/dist/utils/hmac.js +26 -0
  49. package/dist/utils/safe-fetch.d.ts +51 -0
  50. package/dist/utils/safe-fetch.js +192 -0
  51. package/dist/wirings/ai-agent/ai-agent-agui.d.ts +84 -0
  52. package/dist/wirings/ai-agent/ai-agent-agui.js +305 -0
  53. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +41 -1
  54. package/dist/wirings/ai-agent/ai-agent-prepare.js +146 -6
  55. package/dist/wirings/ai-agent/ai-agent-runner.js +6 -1
  56. package/dist/wirings/ai-agent/ai-agent-stream.js +61 -10
  57. package/dist/wirings/ai-agent/ai-agent.types.d.ts +27 -1
  58. package/dist/wirings/ai-agent/index.d.ts +1 -0
  59. package/dist/wirings/ai-agent/index.js +1 -0
  60. package/dist/wirings/ai-agent/voice-input.d.ts +1 -0
  61. package/dist/wirings/ai-agent/voice-input.js +2 -38
  62. package/dist/wirings/ai-agent/voice-output.d.ts +1 -0
  63. package/dist/wirings/channel/channel-common.js +0 -1
  64. package/dist/wirings/channel/channel-handler.js +1 -4
  65. package/dist/wirings/channel/channel-middleware-runner.d.ts +12 -0
  66. package/dist/wirings/channel/channel-middleware-runner.js +34 -19
  67. package/dist/wirings/channel/channel.types.d.ts +2 -6
  68. package/dist/wirings/cli/cli-runner.js +0 -2
  69. package/dist/wirings/cli/cli.types.d.ts +1 -2
  70. package/dist/wirings/http/http-routes.js +0 -3
  71. package/dist/wirings/http/http-runner.d.ts +9 -29
  72. package/dist/wirings/http/http-runner.js +9 -34
  73. package/dist/wirings/http/http.types.d.ts +1 -9
  74. package/dist/wirings/mcp/mcp-runner.js +0 -2
  75. package/dist/wirings/mcp/mcp.types.d.ts +5 -11
  76. package/dist/wirings/oauth2/index.d.ts +0 -3
  77. package/dist/wirings/oauth2/index.js +1 -2
  78. package/dist/wirings/rpc/addon-runner.d.ts +28 -0
  79. package/dist/wirings/rpc/addon-runner.js +173 -0
  80. package/dist/wirings/rpc/index.d.ts +5 -1
  81. package/dist/wirings/rpc/index.js +3 -1
  82. package/dist/wirings/rpc/remote-addon-auth.d.ts +26 -0
  83. package/dist/wirings/rpc/remote-addon-auth.js +43 -0
  84. package/dist/wirings/rpc/rpc-runner.d.ts +19 -0
  85. package/dist/wirings/rpc/rpc-runner.js +109 -3
  86. package/dist/wirings/rpc/rpc-types.d.ts +15 -1
  87. package/dist/wirings/rpc/wire-addon.js +9 -0
  88. package/dist/wirings/rpc/wire-remote-addon.d.ts +47 -0
  89. package/dist/wirings/rpc/wire-remote-addon.js +19 -0
  90. package/dist/wirings/scope/index.d.ts +3 -0
  91. package/dist/wirings/scope/index.js +2 -0
  92. package/dist/wirings/scope/scope.types.d.ts +39 -0
  93. package/dist/wirings/scope/scope.types.js +1 -0
  94. package/dist/wirings/scope/validate-scope-definitions.d.ts +16 -0
  95. package/dist/wirings/scope/validate-scope-definitions.js +76 -0
  96. package/dist/wirings/scope/wire-scope.d.ts +33 -0
  97. package/dist/wirings/scope/wire-scope.js +32 -0
  98. package/dist/wirings/workflow/dsl/index.d.ts +1 -1
  99. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +53 -1
  100. package/dist/wirings/workflow/graph/graph-node.d.ts +2 -0
  101. package/dist/wirings/workflow/graph/graph-runner.js +3 -0
  102. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +6 -0
  103. package/dist/wirings/workflow/graph/wire-workflow-graph.js +1 -0
  104. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +5 -0
  105. package/dist/wirings/workflow/index.d.ts +2 -2
  106. package/dist/wirings/workflow/index.js +1 -1
  107. package/dist/wirings/workflow/pikku-workflow-service.d.ts +51 -1
  108. package/dist/wirings/workflow/pikku-workflow-service.js +171 -0
  109. package/dist/wirings/workflow/workflow.types.d.ts +1 -1
  110. package/package.json +5 -1
  111. package/run-tests.sh +1 -0
  112. package/src/dev/hot-reload.ts +13 -68
  113. package/src/dev/module-runner.test.ts +169 -0
  114. package/src/dev/module-runner.ts +103 -0
  115. package/src/dev/reload-meta.test.ts +31 -2
  116. package/src/dev/reload-meta.ts +26 -0
  117. package/src/errors/errors.ts +24 -0
  118. package/src/function/function-runner.test.ts +276 -142
  119. package/src/function/function-runner.ts +52 -145
  120. package/src/function/functions.types.ts +28 -38
  121. package/src/index.ts +8 -6
  122. package/src/middleware/index.ts +1 -5
  123. package/src/permissions.test.ts +153 -372
  124. package/src/permissions.ts +139 -259
  125. package/src/pikku-state.ts +0 -2
  126. package/src/scopes.test.ts +167 -0
  127. package/src/scopes.ts +69 -0
  128. package/src/services/ai-embedding-service.ts +31 -0
  129. package/src/services/credential-wire-service.ts +10 -4
  130. package/src/services/index.ts +20 -0
  131. package/src/services/meta-service.ts +68 -3
  132. package/src/services/queue-webhook-service.test.ts +408 -0
  133. package/src/services/queue-webhook-service.ts +182 -0
  134. package/src/services/scope-service.ts +75 -0
  135. package/src/services/typed-secret-service.test.ts +35 -0
  136. package/src/services/typed-secret-service.ts +39 -4
  137. package/src/services/webhook-service.ts +180 -0
  138. package/src/services/workflow-service.ts +7 -0
  139. package/src/types/core.types.ts +42 -14
  140. package/src/types/state.types.ts +23 -3
  141. package/src/utils/hmac.ts +27 -0
  142. package/src/utils/safe-fetch.test.ts +373 -0
  143. package/src/utils/safe-fetch.ts +213 -0
  144. package/src/wirings/ai-agent/ai-agent-agui.test.ts +1127 -0
  145. package/src/wirings/ai-agent/ai-agent-agui.ts +386 -0
  146. package/src/wirings/ai-agent/ai-agent-prepare.test.ts +308 -0
  147. package/src/wirings/ai-agent/ai-agent-prepare.ts +192 -8
  148. package/src/wirings/ai-agent/ai-agent-runner.test.ts +48 -1
  149. package/src/wirings/ai-agent/ai-agent-runner.ts +21 -0
  150. package/src/wirings/ai-agent/ai-agent-stream.test.ts +198 -10
  151. package/src/wirings/ai-agent/ai-agent-stream.ts +84 -10
  152. package/src/wirings/ai-agent/ai-agent.types.ts +28 -0
  153. package/src/wirings/ai-agent/index.ts +1 -0
  154. package/src/wirings/ai-agent/voice-input.ts +6 -35
  155. package/src/wirings/channel/channel-common.ts +0 -1
  156. package/src/wirings/channel/channel-handler.ts +1 -9
  157. package/src/wirings/channel/channel-middleware-runner.test.ts +28 -2
  158. package/src/wirings/channel/channel-middleware-runner.ts +39 -27
  159. package/src/wirings/channel/channel.types.ts +0 -6
  160. package/src/wirings/cli/cli-runner.ts +0 -2
  161. package/src/wirings/cli/cli.types.ts +0 -2
  162. package/src/wirings/http/http-routes.ts +0 -3
  163. package/src/wirings/http/http-runner.test.ts +1 -11
  164. package/src/wirings/http/http-runner.ts +16 -39
  165. package/src/wirings/http/http.types.ts +1 -10
  166. package/src/wirings/mcp/mcp-runner.ts +0 -2
  167. package/src/wirings/mcp/mcp.types.ts +3 -11
  168. package/src/wirings/oauth2/index.ts +0 -3
  169. package/src/wirings/rpc/addon-runner.ts +233 -0
  170. package/src/wirings/rpc/index.ts +17 -1
  171. package/src/wirings/rpc/remote-addon-auth.ts +69 -0
  172. package/src/wirings/rpc/rpc-runner.test.ts +319 -16
  173. package/src/wirings/rpc/rpc-runner.ts +155 -3
  174. package/src/wirings/rpc/rpc-types.ts +16 -5
  175. package/src/wirings/rpc/wire-addon.test.ts +6 -3
  176. package/src/wirings/rpc/wire-addon.ts +9 -0
  177. package/src/wirings/rpc/wire-remote-addon.ts +57 -0
  178. package/src/wirings/scope/index.ts +14 -0
  179. package/src/wirings/scope/scope.test.ts +135 -0
  180. package/src/wirings/scope/scope.types.ts +44 -0
  181. package/src/wirings/scope/validate-scope-definitions.ts +110 -0
  182. package/src/wirings/scope/wire-scope.ts +34 -0
  183. package/src/wirings/workflow/dsl/index.ts +4 -0
  184. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +61 -0
  185. package/src/wirings/workflow/graph/graph-node.ts +2 -0
  186. package/src/wirings/workflow/graph/graph-runner.test.ts +58 -0
  187. package/src/wirings/workflow/graph/graph-runner.ts +3 -0
  188. package/src/wirings/workflow/graph/wire-workflow-graph.ts +7 -0
  189. package/src/wirings/workflow/graph/workflow-graph.types.ts +5 -0
  190. package/src/wirings/workflow/index.ts +5 -0
  191. package/src/wirings/workflow/pikku-workflow-service.test.ts +341 -0
  192. package/src/wirings/workflow/pikku-workflow-service.ts +236 -0
  193. package/src/wirings/workflow/workflow-step-session.test.ts +21 -5
  194. package/src/wirings/workflow/workflow.types.ts +4 -0
  195. package/tsconfig.tsbuildinfo +1 -1
  196. package/src/wirings/oauth2/oauth2-client.test.ts +0 -930
  197. package/src/wirings/oauth2/oauth2-client.ts +0 -331
  198. package/src/wirings/oauth2/oauth2-routes.ts +0 -234
@@ -1,5 +1,6 @@
1
1
  import type { AIAgentRunnerService } from '../../services/ai-agent-runner-service.js'
2
2
  import { pikkuAIMiddleware } from '../../types/core.types.js'
3
+ import { safeFetch } from '../../utils/safe-fetch.js'
3
4
  import type { AIContentPart } from './ai-agent.types.js'
4
5
 
5
6
  function base64ToUint8Array(base64: string): Uint8Array {
@@ -13,45 +14,15 @@ function base64ToUint8Array(base64: string): Uint8Array {
13
14
 
14
15
  const MAX_AUDIO_SIZE = 50 * 1024 * 1024
15
16
 
16
- // Portable SSRF guard: @pikku/core runs in edge runtimes (CF Workers) with no
17
- // Node `dns`, so we cannot resolve hostnames to check for private targets.
18
- // Reject the obvious internal literals; callers wanting stricter control pass
19
- // an explicit `allowedAudioHosts` allowlist. (Does not defend against a public
20
- // hostname that resolves to a private IP / DNS rebinding — out of reach here.)
21
- function isPrivateHost(hostname: string): boolean {
22
- const host = hostname.replace(/^\[|\]$/g, '').toLowerCase()
23
- if (host === 'localhost' || host === '0.0.0.0' || host === '::1') return true
24
- if (host.startsWith('fe80:') || host.startsWith('fc') || host.startsWith('fd'))
25
- return true
26
- const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.\d{1,3}$/)
27
- if (v4) {
28
- const [a, b] = [Number(v4[1]), Number(v4[2])]
29
- if (a === 127 || a === 10 || a === 0) return true
30
- if (a === 169 && b === 254) return true // link-local incl. cloud metadata
31
- if (a === 172 && b >= 16 && b <= 31) return true
32
- if (a === 192 && b === 168) return true
33
- }
34
- return false
35
- }
36
-
37
17
  async function fetchAsUint8Array(
38
18
  url: string,
39
19
  allowedAudioHosts?: string[]
40
20
  ): Promise<Uint8Array> {
41
- const parsed = new URL(url)
42
- if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
43
- throw new Error('Only HTTP(S) URLs are supported for audio')
44
- }
45
- if (allowedAudioHosts) {
46
- if (!allowedAudioHosts.includes(parsed.hostname)) {
47
- throw new Error(`Audio URL host is not allowed: ${parsed.hostname}`)
48
- }
49
- } else if (isPrivateHost(parsed.hostname)) {
50
- throw new Error(
51
- `Refusing to fetch audio from a private/internal host: ${parsed.hostname}`
52
- )
53
- }
54
- const response = await fetch(url)
21
+ const response = await safeFetch(
22
+ url,
23
+ {},
24
+ { allowedHosts: allowedAudioHosts }
25
+ )
55
26
  const contentLength = response.headers.get('content-length')
56
27
  if (contentLength && parseInt(contentLength, 10) > MAX_AUDIO_SIZE) {
57
28
  throw new Error('Audio file exceeds maximum size')
@@ -85,7 +85,6 @@ export const runChannelLifecycleWithMiddleware = async ({
85
85
  data: () => data as any,
86
86
  wire,
87
87
  tags: meta.tags ?? [],
88
- inheritedPermissions: meta.permissions,
89
88
  packageName: meta.packageName ?? null,
90
89
  })
91
90
  }
@@ -102,11 +102,7 @@ export const processMessageHandlers = (
102
102
  routingProperty,
103
103
  routerValue
104
104
  )
105
- const {
106
- packageName,
107
- middleware: routeInheritedMiddleware,
108
- permissions: inheritedPermissions,
109
- } = routeMeta
105
+ const { packageName, middleware: routeInheritedMiddleware } = routeMeta
110
106
 
111
107
  const pikkuFuncId = routeMeta.pikkuFuncId
112
108
 
@@ -132,8 +128,6 @@ export const processMessageHandlers = (
132
128
  // Inherited middleware comes from metadata (tag groups, non-inline wire)
133
129
  const inheritedMiddleware = routeInheritedMiddleware || []
134
130
 
135
- const wirePermissions = isWrapper ? onMessage.permissions : undefined
136
-
137
131
  // Create unique cache key that includes routing info to avoid cache collisions
138
132
  // when multiple message handlers use the same function
139
133
  const cacheKey = routingProperty
@@ -150,8 +144,6 @@ export const processMessageHandlers = (
150
144
  wireMiddleware,
151
145
  inheritedChannelMiddleware: channelMeta?.channelMiddleware,
152
146
  wireChannelMiddleware: wireChannelMiddleware as any,
153
- inheritedPermissions,
154
- wirePermissions,
155
147
  coerceDataFromSchema: true,
156
148
  tags: channelConfig.tags,
157
149
  sessionService: userSession,
@@ -69,17 +69,17 @@ describe('combineChannelMiddleware', () => {
69
69
  void execution
70
70
  })
71
71
 
72
- test('deduplicates middleware and returns cached results until the cache is cleared', () => {
72
+ test('caches the statically-resolved inherited middleware until the cache is cleared', () => {
73
73
  const shared = async () => {}
74
74
  addChannelMiddleware('chat:outbound', [shared])
75
75
 
76
76
  const first = combineChannelMiddleware('channel', 'cached-1', {
77
77
  wireInheritedChannelMiddleware: [{ type: 'tag', tag: 'chat:outbound' }],
78
- wireChannelMiddleware: [shared],
79
78
  })
80
79
 
81
80
  assert.deepEqual(first, [shared])
82
81
 
82
+ // Re-registering after the first resolve does not change the cached result.
83
83
  addChannelMiddleware('chat:outbound', [async () => {}])
84
84
 
85
85
  const cached = combineChannelMiddleware('channel', 'cached-1', {
@@ -97,6 +97,32 @@ describe('combineChannelMiddleware', () => {
97
97
  assert.notStrictEqual(refreshed[0], shared)
98
98
  })
99
99
 
100
+ test('does not cache per-run wireChannelMiddleware across calls (C4 cross-run leak)', () => {
101
+ const shared = async () => {}
102
+ addChannelMiddleware('chat:outbound', [shared])
103
+
104
+ const runA = async () => {}
105
+ const first = combineChannelMiddleware('agent', 'stream:bot', {
106
+ wireInheritedChannelMiddleware: [{ type: 'tag', tag: 'chat:outbound' }],
107
+ wireChannelMiddleware: [runA],
108
+ })
109
+ assert.deepEqual(first, [shared, runA])
110
+
111
+ const runB = async () => {}
112
+ const second = combineChannelMiddleware('agent', 'stream:bot', {
113
+ wireInheritedChannelMiddleware: [{ type: 'tag', tag: 'chat:outbound' }],
114
+ wireChannelMiddleware: [runB],
115
+ })
116
+ assert.deepEqual(second, [shared, runB])
117
+ assert.strictEqual(second[1], runB)
118
+ assert.notStrictEqual(second[1], runA)
119
+
120
+ const third = combineChannelMiddleware('agent', 'stream:bot', {
121
+ wireInheritedChannelMiddleware: [{ type: 'tag', tag: 'chat:outbound' }],
122
+ })
123
+ assert.deepEqual(third, [shared])
124
+ })
125
+
100
126
  test('ignores missing named middleware references', () => {
101
127
  const combined = combineChannelMiddleware('channel', 'missing-wire', {
102
128
  wireInheritedChannelMiddleware: [{ type: 'wire', name: 'missing' }],
@@ -36,6 +36,18 @@ export const clearChannelMiddlewareCache = () => {
36
36
  }
37
37
  }
38
38
 
39
+ /**
40
+ * Combine the inherited (tag/named) channel middleware with any per-run
41
+ * middleware for a wiring.
42
+ *
43
+ * Only the statically-resolved inherited middleware is deterministic per `uid`
44
+ * and safe to cache. `wireChannelMiddleware` is a per-run set of closures (e.g.
45
+ * an AI agent's per-invocation stream middleware holding that run's
46
+ * thread/session state) and MUST NOT be cached — caching it lets a later run of
47
+ * the same `uid` reuse an earlier run's closures, leaking that run's state (and
48
+ * growing memory) across invocations. It is therefore appended fresh on every
49
+ * call after the cached inherited slice.
50
+ */
39
51
  export const combineChannelMiddleware = (
40
52
  wireType: string,
41
53
  uid: string,
@@ -50,40 +62,40 @@ export const combineChannelMiddleware = (
50
62
  } = {}
51
63
  ): readonly CorePikkuChannelMiddleware[] => {
52
64
  const cacheKey = `${wireType}:${uid}`
53
- if (channelMiddlewareCache[cacheKey]) {
54
- return channelMiddlewareCache[cacheKey]
55
- }
56
-
57
- const resolved: CorePikkuChannelMiddleware[] = []
58
-
59
- if (wireInheritedChannelMiddleware) {
60
- for (const meta of wireInheritedChannelMiddleware) {
61
- if (meta.type === 'tag') {
62
- const groups = getTagGroups(
63
- pikkuState(packageName, 'channelMiddleware', 'tagGroup'),
64
- meta.tag
65
- )
66
- for (const group of groups) {
67
- resolved.push(...group)
68
- }
69
- } else if (meta.type === 'wire') {
70
- const middleware = getChannelMiddlewareByName(meta.name)
71
- if (middleware) {
72
- resolved.push(middleware)
65
+ let inherited = channelMiddlewareCache[cacheKey]
66
+ if (!inherited) {
67
+ const resolved: CorePikkuChannelMiddleware[] = []
68
+ if (wireInheritedChannelMiddleware) {
69
+ for (const meta of wireInheritedChannelMiddleware) {
70
+ if (meta.type === 'tag') {
71
+ const groups = getTagGroups(
72
+ pikkuState(packageName, 'channelMiddleware', 'tagGroup'),
73
+ meta.tag
74
+ )
75
+ for (const group of groups) {
76
+ resolved.push(...group)
77
+ }
78
+ } else if (meta.type === 'wire') {
79
+ const middleware = getChannelMiddlewareByName(meta.name)
80
+ if (middleware) {
81
+ resolved.push(middleware)
82
+ }
73
83
  }
74
84
  }
75
85
  }
86
+ inherited = channelMiddlewareCache[cacheKey] = freezeDedupe(
87
+ resolved
88
+ ) as readonly CorePikkuChannelMiddleware[]
76
89
  }
77
90
 
78
- if (wireChannelMiddleware) {
79
- resolved.push(...wireChannelMiddleware)
91
+ if (!wireChannelMiddleware?.length) {
92
+ return inherited
80
93
  }
81
94
 
82
- channelMiddlewareCache[cacheKey] = freezeDedupe(
83
- resolved
84
- ) as readonly CorePikkuChannelMiddleware[]
85
-
86
- return channelMiddlewareCache[cacheKey]
95
+ return freezeDedupe([
96
+ ...inherited,
97
+ ...wireChannelMiddleware,
98
+ ]) as readonly CorePikkuChannelMiddleware[]
87
99
  }
88
100
 
89
101
  export function wrapChannelWithMiddleware<Out>(
@@ -6,7 +6,6 @@ import type {
6
6
  import type {
7
7
  CorePikkuMiddleware,
8
8
  MiddlewareMetadata,
9
- PermissionMetadata,
10
9
  } from '../../types/core.types.js'
11
10
 
12
11
  export type BinaryData = ArrayBuffer | Uint8Array
@@ -23,7 +22,6 @@ export type CorePikkuChannelMiddlewareFactory<
23
22
  Event = unknown,
24
23
  > = (input: In) => CorePikkuChannelMiddleware<Services, Event>
25
24
  import type {
26
- CorePermissionGroup,
27
25
  CorePikkuFunction,
28
26
  CorePikkuFunctionConfig,
29
27
  CorePikkuFunctionSessionless,
@@ -52,7 +50,6 @@ export interface ChannelMessageMeta {
52
50
  errors?: string[]
53
51
  tags?: string[]
54
52
  middleware?: MiddlewareMetadata[]
55
- permissions?: PermissionMetadata[]
56
53
  }
57
54
 
58
55
  export interface ChannelMeta {
@@ -72,7 +69,6 @@ export interface ChannelMeta {
72
69
  errors?: string[]
73
70
  tags?: string[]
74
71
  middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
75
- permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
76
72
  channelMiddleware?: MiddlewareMetadata[]
77
73
  }
78
74
 
@@ -123,7 +119,6 @@ export type CoreChannel<
123
119
  | ChannelFunctionMessage
124
120
  | {
125
121
  func: ChannelFunctionMessage
126
- permissions?: CorePermissionGroup<PikkuPermission>
127
122
  auth?: boolean
128
123
  middleware?: PikkuMiddleware[]
129
124
  }
@@ -133,7 +128,6 @@ export type CoreChannel<
133
128
  channelMiddleware?: Array<
134
129
  CorePikkuChannelMiddleware | CorePikkuChannelMiddlewareFactory
135
130
  >
136
- permissions?: CorePermissionGroup<PikkuPermission>
137
131
  auth?: boolean
138
132
  binary?: boolean | null
139
133
  onBinaryMessage?: (
@@ -374,8 +374,6 @@ export async function runCLICommand({
374
374
  auth: false,
375
375
  inheritedMiddleware: currentCommand.middleware,
376
376
  wireMiddleware: allWireMiddleware,
377
- inheritedPermissions: currentCommand.permissions,
378
- wirePermissions: undefined,
379
377
  coerceDataFromSchema: true,
380
378
  tags: programData?.tags,
381
379
  wire,
@@ -4,7 +4,6 @@ import type {
4
4
  CoreUserSession,
5
5
  CoreServices,
6
6
  MiddlewareMetadata,
7
- PermissionMetadata,
8
7
  } from '../../types/core.types.js'
9
8
  import type {
10
9
  CorePikkuFunctionConfig,
@@ -80,7 +79,6 @@ export interface CLICommandMeta {
80
79
  tags?: string[]
81
80
  subcommands?: Record<string, CLICommandMeta>
82
81
  middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
83
- permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
84
82
  isDefault?: boolean
85
83
  }
86
84
 
@@ -128,7 +128,6 @@ function processRouteMap(
128
128
  * - tags: Merges (parent + child)
129
129
  * - middleware: Merges (parent runs first)
130
130
  * - auth: Inner overrides outer
131
- * - permissions: Inner overrides outer
132
131
  */
133
132
  function mergeGroupConfig(
134
133
  parent: HTTPRoutesGroupConfig,
@@ -139,7 +138,6 @@ function mergeGroupConfig(
139
138
  tags: [...(parent.tags || []), ...(child.tags || [])],
140
139
  middleware: [...(parent.middleware || []), ...(child.middleware || [])],
141
140
  auth: child.auth ?? parent.auth,
142
- permissions: child.permissions ?? parent.permissions,
143
141
  }
144
142
  }
145
143
 
@@ -162,7 +160,6 @@ function registerRoute(
162
160
  ...(groupConfig.middleware || []),
163
161
  ...(route.middleware || []),
164
162
  ],
165
- permissions: route.permissions ?? groupConfig.permissions,
166
163
  contentType: route.contentType,
167
164
  timeout: route.timeout,
168
165
  headers: route.headers,
@@ -4,7 +4,6 @@ import { NotFoundError } from '../../errors/errors.js'
4
4
  import type { JSONValue, CorePikkuMiddleware } from '../../types/core.types.js'
5
5
  import {
6
6
  addHTTPMiddleware,
7
- addHTTPPermission,
8
7
  createHTTPWire,
9
8
  fetch,
10
9
  fetchData,
@@ -253,23 +252,14 @@ describe('http-runner helpers', () => {
253
252
  } as any)
254
253
  })
255
254
 
256
- test('addHTTPMiddleware and addHTTPPermission register route groups', () => {
255
+ test('addHTTPMiddleware registers a route middleware group', () => {
257
256
  const middleware = [sessionMiddleware]
258
- const permissions = [async () => true]
259
257
 
260
258
  assert.strictEqual(addHTTPMiddleware('/api/*', middleware), middleware)
261
- assert.strictEqual(
262
- addHTTPPermission('/api/*', permissions as any),
263
- permissions
264
- )
265
259
  assert.strictEqual(
266
260
  pikkuState(null, 'middleware', 'httpGroup')['/api/*'],
267
261
  middleware
268
262
  )
269
- assert.strictEqual(
270
- pikkuState(null, 'permissions', 'httpGroup')['/api/*'],
271
- permissions
272
- )
273
263
  })
274
264
 
275
265
  test('addHTTPMiddleware composes repeated registrations for the same pattern', () => {
@@ -11,7 +11,6 @@ import type {
11
11
  CorePikkuFunction,
12
12
  CorePikkuFunctionSessionless,
13
13
  CorePikkuPermission,
14
- CorePermissionGroup,
15
14
  } from '../../function/functions.types.js'
16
15
  import type {
17
16
  CoreUserSession,
@@ -106,42 +105,23 @@ export const addHTTPMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
106
105
  }
107
106
 
108
107
  /**
109
- * Registers HTTP permissions for a specific route pattern.
110
- *
111
- * This function registers permissions at runtime that will be applied to
112
- * HTTP routes matching the specified pattern.
113
- *
114
- * For tree-shaking benefits, wrap in a factory function:
115
- * `export const x = () => addHTTPPermission('pattern', [...])`
116
- *
117
- * @template PikkuPermission The permission type.
118
- * @param {string} pattern - Route pattern (e.g., '*' for all routes, '/api/*' for specific routes).
119
- * @param {CorePermissionGroup | CorePikkuPermission[]} permissions - Permissions for this route pattern.
120
- *
121
- * @returns {CorePermissionGroup | CorePikkuPermission[]} The permissions (for chaining/wrapping).
122
- *
123
- * @example
124
- * ```typescript
125
- * // Recommended: tree-shakeable
126
- * export const httpGlobalPermissions = () => addHTTPPermission('*', [
127
- * authenticatedPermission,
128
- * rateLimitPermission
129
- * ])
130
- *
131
- * // Also works: no tree-shaking
132
- * export const apiPermissions = addHTTPPermission('/api/*', [
133
- * adminPermission
134
- * ])
135
- * ```
108
+ * @deprecated HTTP-route-level permissions were removed in #972 — permissions
109
+ * are now function-scoped only (declare them on the function via
110
+ * `pikkuFunc({ permissions })`). This throwing stub exists solely so the pinned
111
+ * bootstrap CLI (which still generates an `addHTTPPermission` wrapper) can
112
+ * resolve the import at build time; it is never called. Delete once
113
+ * `PIKKU_CLI_VERSION` in the CLI build is bumped past the release that removes
114
+ * HTTP-route permissions.
136
115
  */
137
- export const addHTTPPermission = <PikkuPermission extends CorePikkuPermission>(
138
- pattern: string,
139
- permissions: CorePermissionGroup | CorePikkuPermission[],
140
- packageName: string | null = null
141
- ): CorePermissionGroup | CorePikkuPermission[] => {
142
- const httpGroups = pikkuState(packageName, 'permissions', 'httpGroup')
143
- httpGroups[pattern] = permissions
144
- return permissions
116
+ export const addHTTPPermission = (
117
+ _pattern: string,
118
+ _permissions:
119
+ | Record<string, CorePikkuPermission | CorePikkuPermission[]>
120
+ | CorePikkuPermission[]
121
+ ): never => {
122
+ throw new Error(
123
+ 'addHTTPPermission was removed in #972 — HTTP-route-level permissions no longer exist. Declare permissions on the function definition instead: pikkuFunc({ permissions }).'
124
+ )
145
125
  }
146
126
 
147
127
  /**
@@ -233,7 +213,6 @@ const getMatchingRoute = (requestType: string, requestPath: string) => {
233
213
  matchedPath,
234
214
  params: matchedPath.params,
235
215
  route,
236
- permissions: route.permissions,
237
216
  meta: meta!,
238
217
  }
239
218
  }
@@ -432,8 +411,6 @@ const executeRoute = async (
432
411
  data,
433
412
  inheritedMiddleware: meta.middleware,
434
413
  wireMiddleware: route.middleware,
435
- inheritedPermissions: meta.permissions,
436
- wirePermissions: route.permissions,
437
414
  coerceDataFromSchema: options.coerceDataFromSchema,
438
415
  tags: route.tags,
439
416
  wire,
@@ -8,7 +8,6 @@ import type {
8
8
  CorePikkuFunction,
9
9
  CorePikkuFunctionSessionless,
10
10
  CorePikkuPermission,
11
- CorePermissionGroup,
12
11
  CorePikkuFunctionConfig,
13
12
  } from '../../function/functions.types.js'
14
13
 
@@ -138,7 +137,6 @@ export type CoreHTTPFunctionWiring<
138
137
  PikkuPermission,
139
138
  PikkuMiddleware
140
139
  >
141
- permissions?: CorePermissionGroup<PikkuPermission>
142
140
  auth?: true
143
141
  middleware?: PikkuMiddleware[]
144
142
  sse?: undefined
@@ -151,7 +149,6 @@ export type CoreHTTPFunctionWiring<
151
149
  PikkuPermission,
152
150
  PikkuMiddleware
153
151
  >
154
- permissions?: undefined
155
152
  auth?: false
156
153
  middleware?: PikkuMiddleware[]
157
154
  sse?: undefined
@@ -164,7 +161,6 @@ export type CoreHTTPFunctionWiring<
164
161
  PikkuPermission,
165
162
  PikkuMiddleware
166
163
  >
167
- permissions?: CorePermissionGroup<PikkuPermission>
168
164
  auth?: true
169
165
  middleware?: PikkuMiddleware[]
170
166
  sse?: boolean
@@ -177,7 +173,6 @@ export type CoreHTTPFunctionWiring<
177
173
  PikkuPermission,
178
174
  PikkuMiddleware
179
175
  >
180
- permissions?: undefined
181
176
  auth?: false
182
177
  middleware?: PikkuMiddleware[]
183
178
  sse?: boolean
@@ -190,7 +185,6 @@ export type CoreHTTPFunctionWiring<
190
185
  PikkuPermission,
191
186
  PikkuMiddleware
192
187
  >
193
- permissions?: CorePermissionGroup<PikkuPermission>
194
188
  auth?: true
195
189
  middleware?: PikkuMiddleware[]
196
190
  query?: Array<keyof In>
@@ -204,7 +198,6 @@ export type CoreHTTPFunctionWiring<
204
198
  PikkuPermission,
205
199
  PikkuMiddleware
206
200
  >
207
- permissions?: undefined
208
201
  auth?: false
209
202
  middleware?: PikkuMiddleware[]
210
203
  query?: Array<keyof In>
@@ -305,9 +298,8 @@ export type HTTPRouteConfig<
305
298
  route: string
306
299
  func: CorePikkuFunctionConfig<PikkuFunction, PikkuPermission, PikkuMiddleware>
307
300
 
308
- // Auth & permissions
301
+ // Auth
309
302
  auth?: boolean
310
- permissions?: CorePermissionGroup<PikkuPermission>
311
303
 
312
304
  // Middleware
313
305
  middleware?: PikkuMiddleware[]
@@ -331,7 +323,6 @@ export type HTTPRoutesGroupConfig<
331
323
  tags?: string[]
332
324
  auth?: boolean
333
325
  middleware?: PikkuMiddleware[]
334
- permissions?: CorePermissionGroup<PikkuPermission>
335
326
  }
336
327
 
337
328
  /**
@@ -252,8 +252,6 @@ async function runMCPPikkuFunc(
252
252
  data: () => request.params,
253
253
  inheritedMiddleware: meta?.middleware,
254
254
  wireMiddleware: mcp?.middleware,
255
- inheritedPermissions: meta?.permissions,
256
- wirePermissions: mcp?.permissions,
257
255
  tags: mcp?.tags,
258
256
  wire,
259
257
  sessionService: mcpSessionService,
@@ -1,5 +1,4 @@
1
1
  import type {
2
- CorePermissionGroup,
3
2
  CorePikkuFunctionConfig,
4
3
  CorePikkuFunctionSessionless,
5
4
  CorePikkuPermission,
@@ -7,7 +6,6 @@ import type {
7
6
  import type {
8
7
  CorePikkuMiddleware,
9
8
  MiddlewareMetadata,
10
- PermissionMetadata,
11
9
  } from '../../types/core.types.js'
12
10
 
13
11
  /**
@@ -49,12 +47,11 @@ export type PikkuMCP<Tools extends string = any> = {
49
47
  */
50
48
  export type MCPResourceMeta = Record<
51
49
  string,
52
- Omit<CoreMCPResource, 'func' | 'middleware' | 'permissions'> & {
50
+ Omit<CoreMCPResource, 'func' | 'middleware'> & {
53
51
  pikkuFuncId: string
54
52
  inputSchema: string | null
55
53
  outputSchema: string | null
56
54
  middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
57
- permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
58
55
  }
59
56
  >
60
57
 
@@ -63,12 +60,11 @@ export type MCPResourceMeta = Record<
63
60
  */
64
61
  export type MCPToolMeta = Record<
65
62
  string,
66
- Omit<CoreMCPTool, 'func' | 'middleware' | 'permissions'> & {
63
+ Omit<CoreMCPTool, 'func' | 'middleware'> & {
67
64
  pikkuFuncId: string
68
65
  inputSchema: string | null
69
66
  outputSchema: string | null
70
67
  middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
71
- permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
72
68
  }
73
69
  >
74
70
 
@@ -77,7 +73,7 @@ export type MCPToolMeta = Record<
77
73
  */
78
74
  export type MCPPromptMeta = Record<
79
75
  string,
80
- Omit<CoreMCPPrompt, 'func' | 'middleware' | 'permissions'> & {
76
+ Omit<CoreMCPPrompt, 'func' | 'middleware'> & {
81
77
  pikkuFuncId: string
82
78
  inputSchema: string | null
83
79
  outputSchema: string | null
@@ -87,7 +83,6 @@ export type MCPPromptMeta = Record<
87
83
  required: boolean
88
84
  }>
89
85
  middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
90
- permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
91
86
  }
92
87
  >
93
88
 
@@ -112,7 +107,6 @@ export type CoreMCPResource<
112
107
  func: PikkuFunctionConfig
113
108
  tags?: string[]
114
109
  middleware?: PikkuMiddleware[]
115
- permissions?: CorePermissionGroup<PikkuPermission>
116
110
  }
117
111
 
118
112
  /**
@@ -134,7 +128,6 @@ export type CoreMCPTool<
134
128
  tags?: string[]
135
129
  streaming?: boolean
136
130
  middleware?: PikkuMiddleware[]
137
- permissions?: CorePermissionGroup<PikkuPermission>
138
131
  }
139
132
 
140
133
  /**
@@ -154,7 +147,6 @@ export type CoreMCPPrompt<
154
147
  func: PikkuFunctionConfig
155
148
  tags?: string[]
156
149
  middleware?: PikkuMiddleware[]
157
- permissions?: CorePermissionGroup<PikkuPermission>
158
150
  }
159
151
 
160
152
  export type JsonRpcRequest = {
@@ -1,4 +1 @@
1
- export { OAuth2Client } from './oauth2-client.js'
2
- export { createOAuth2Handler } from './oauth2-routes.js'
3
- export type { CreateOAuth2HandlerOptions } from './oauth2-routes.js'
4
1
  export type { OAuth2AppCredential, OAuth2Token } from './oauth2.types.js'