@pikku/inspector 0.12.41 → 0.12.43

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 (108) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/dist/add/add-addon-bans.js +1 -0
  3. package/dist/add/add-ai-agent.d.ts +3 -1
  4. package/dist/add/add-ai-agent.js +82 -0
  5. package/dist/add/add-credential.js +3 -1
  6. package/dist/add/add-functions.js +10 -9
  7. package/dist/add/add-gateway.js +3 -0
  8. package/dist/add/add-http-route.js +2 -2
  9. package/dist/add/add-mcp-prompt.js +0 -1
  10. package/dist/add/add-mcp-resource.js +0 -1
  11. package/dist/add/add-permission.d.ts +1 -1
  12. package/dist/add/add-permission.js +3 -177
  13. package/dist/add/add-queue-worker.js +3 -0
  14. package/dist/add/add-schedule.js +3 -0
  15. package/dist/add/add-scope.d.ts +2 -0
  16. package/dist/add/add-scope.js +146 -0
  17. package/dist/add/add-trigger.js +3 -0
  18. package/dist/add/add-wire-remote-addon.d.ts +10 -0
  19. package/dist/add/add-wire-remote-addon.js +66 -0
  20. package/dist/add/add-workflow-graph.js +32 -3
  21. package/dist/error-codes.d.ts +3 -0
  22. package/dist/error-codes.js +4 -0
  23. package/dist/inspector.js +19 -7
  24. package/dist/types.d.ts +19 -13
  25. package/dist/utils/custom-types-generator.js +2 -1
  26. package/dist/utils/ensure-function-metadata.d.ts +15 -0
  27. package/dist/utils/ensure-function-metadata.js +24 -0
  28. package/dist/utils/filter-inspector-state.js +9 -0
  29. package/dist/utils/get-property-value.d.ts +7 -2
  30. package/dist/utils/get-property-value.js +48 -1
  31. package/dist/utils/load-addon-functions-meta.js +81 -6
  32. package/dist/utils/nested-project-filter.d.ts +1 -0
  33. package/dist/utils/nested-project-filter.js +29 -0
  34. package/dist/utils/permissions.d.ts +1 -21
  35. package/dist/utils/permissions.js +17 -108
  36. package/dist/utils/post-process.d.ts +30 -1
  37. package/dist/utils/post-process.js +150 -72
  38. package/dist/utils/serialize-inspector-state.d.ts +13 -8
  39. package/dist/utils/serialize-inspector-state.js +12 -6
  40. package/dist/utils/serialize-permissions-groups-meta.d.ts +0 -2
  41. package/dist/utils/serialize-permissions-groups-meta.js +0 -26
  42. package/dist/utils/workflow/derive-workflow-plan.js +9 -3
  43. package/dist/utils/workflow/dsl/extract-dsl-workflow.js +56 -1
  44. package/dist/utils/workflow/dsl/patterns.d.ts +10 -0
  45. package/dist/utils/workflow/dsl/patterns.js +24 -8
  46. package/dist/utils/workflow/dsl/validation.js +3 -4
  47. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +14 -0
  48. package/dist/utils/workflow/graph/finalize-workflows.d.ts +7 -0
  49. package/dist/utils/workflow/graph/finalize-workflows.js +11 -2
  50. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +2 -0
  51. package/dist/utils/workflow/graph/serialize-workflow-graph.js +4 -0
  52. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +6 -2
  53. package/dist/visit.js +4 -0
  54. package/package.json +3 -3
  55. package/src/add/add-addon-bans.ts +1 -0
  56. package/src/add/add-ai-agent.test.ts +87 -0
  57. package/src/add/add-ai-agent.ts +122 -0
  58. package/src/add/add-credential.ts +6 -0
  59. package/src/add/add-functions.ts +10 -12
  60. package/src/add/add-gateway.ts +11 -0
  61. package/src/add/add-http-route.ts +2 -8
  62. package/src/add/add-mcp-prompt.ts +0 -1
  63. package/src/add/add-mcp-resource.ts +0 -1
  64. package/src/add/add-permission.ts +4 -242
  65. package/src/add/add-queue-worker.ts +11 -0
  66. package/src/add/add-schedule.ts +11 -0
  67. package/src/add/add-scope.test.ts +346 -0
  68. package/src/add/add-scope.ts +225 -0
  69. package/src/add/add-trigger.ts +11 -0
  70. package/src/add/add-wire-remote-addon.ts +77 -0
  71. package/src/add/add-workflow-graph-input.test.ts +94 -0
  72. package/src/add/add-workflow-graph-notes.test.ts +74 -0
  73. package/src/add/add-workflow-graph.ts +35 -3
  74. package/src/add/inline-wiring-function.test.ts +104 -0
  75. package/src/add/validate-workflow-graph-addons.test.ts +102 -0
  76. package/src/error-codes.ts +5 -0
  77. package/src/inspector.ts +22 -6
  78. package/src/types.ts +16 -17
  79. package/src/utils/custom-types-generator.test.ts +26 -1
  80. package/src/utils/custom-types-generator.ts +2 -1
  81. package/src/utils/ensure-function-metadata.ts +42 -0
  82. package/src/utils/filter-inspector-state.test.ts +0 -2
  83. package/src/utils/filter-inspector-state.ts +9 -0
  84. package/src/utils/get-property-value.test.ts +141 -0
  85. package/src/utils/get-property-value.ts +62 -1
  86. package/src/utils/load-addon-functions-meta.test.ts +157 -0
  87. package/src/utils/load-addon-functions-meta.ts +94 -6
  88. package/src/utils/load-addon-scopes.test.ts +138 -0
  89. package/src/utils/nested-project-filter.test.ts +53 -0
  90. package/src/utils/nested-project-filter.ts +28 -0
  91. package/src/utils/permissions.test.ts +7 -232
  92. package/src/utils/permissions.ts +20 -160
  93. package/src/utils/post-process.test.ts +269 -4
  94. package/src/utils/post-process.ts +216 -95
  95. package/src/utils/serialize-inspector-state.ts +22 -25
  96. package/src/utils/serialize-permissions-groups-meta.ts +0 -28
  97. package/src/utils/workflow/derive-workflow-plan.test.ts +41 -3
  98. package/src/utils/workflow/derive-workflow-plan.ts +11 -4
  99. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +66 -0
  100. package/src/utils/workflow/dsl/patterns.ts +34 -8
  101. package/src/utils/workflow/dsl/validation.ts +3 -4
  102. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +15 -0
  103. package/src/utils/workflow/graph/finalize-workflows.test.ts +50 -0
  104. package/src/utils/workflow/graph/finalize-workflows.ts +13 -2
  105. package/src/utils/workflow/graph/serialize-workflow-graph.ts +6 -0
  106. package/src/utils/workflow/graph/workflow-graph.types.ts +8 -0
  107. package/src/visit.ts +4 -0
  108. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,53 @@
1
+ import { test } from 'node:test'
2
+ import * as assert from 'node:assert'
3
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'fs'
4
+ import { tmpdir } from 'os'
5
+ import { join } from 'path'
6
+ import { createNestedProjectFilter } from './nested-project-filter.js'
7
+
8
+ test('createNestedProjectFilter', async (t) => {
9
+ const root = mkdtempSync(join(tmpdir(), 'pikku-nested-'))
10
+ t.after(() => rmSync(root, { recursive: true, force: true }))
11
+
12
+ writeFileSync(join(root, 'pikku.config.json'), '{}')
13
+ mkdirSync(join(root, 'packages/functions/src'), { recursive: true })
14
+ mkdirSync(join(root, 'packages/addon/src'), { recursive: true })
15
+ mkdirSync(join(root, 'packages/addon/types'), { recursive: true })
16
+ writeFileSync(join(root, 'packages/addon/pikku.config.json'), '{}')
17
+
18
+ const isNested = createNestedProjectFilter(root)
19
+
20
+ await t.test('keeps project source files', () => {
21
+ assert.strictEqual(
22
+ isNested(join(root, 'packages/functions/src/auth.ts')),
23
+ false
24
+ )
25
+ })
26
+
27
+ await t.test('keeps files directly under rootDir', () => {
28
+ assert.strictEqual(isNested(join(root, 'services.ts')), false)
29
+ })
30
+
31
+ await t.test('excludes files inside a nested pikku project', () => {
32
+ assert.strictEqual(
33
+ isNested(join(root, 'packages/addon/types/application-types.d.ts')),
34
+ true
35
+ )
36
+ assert.strictEqual(
37
+ isNested(join(root, 'packages/addon/src/index.ts')),
38
+ true
39
+ )
40
+ })
41
+
42
+ await t.test('keeps files outside rootDir untouched', () => {
43
+ assert.strictEqual(isNested('/somewhere/else/file.ts'), false)
44
+ })
45
+
46
+ await t.test('rootDir itself is not treated as nested', () => {
47
+ const addonScoped = createNestedProjectFilter(join(root, 'packages/addon'))
48
+ assert.strictEqual(
49
+ addonScoped(join(root, 'packages/addon/src/index.ts')),
50
+ false
51
+ )
52
+ })
53
+ })
@@ -0,0 +1,28 @@
1
+ import { existsSync } from 'fs'
2
+ import { dirname, join } from 'path'
3
+
4
+ export const createNestedProjectFilter = (rootDir: string) => {
5
+ const cache = new Map<string, boolean>()
6
+ return (fileName: string): boolean => {
7
+ const pending: string[] = []
8
+ let dir = dirname(fileName)
9
+ let nested = false
10
+ while (dir.startsWith(rootDir) && dir !== rootDir) {
11
+ const cached = cache.get(dir)
12
+ if (cached !== undefined) {
13
+ nested = cached
14
+ break
15
+ }
16
+ pending.push(dir)
17
+ if (existsSync(join(dir, 'pikku.config.json'))) {
18
+ nested = true
19
+ break
20
+ }
21
+ const parent = dirname(dir)
22
+ if (parent === dir) break
23
+ dir = parent
24
+ }
25
+ for (const d of pending) cache.set(d, nested)
26
+ return nested
27
+ }
28
+ }
@@ -1,193 +1,10 @@
1
1
  import { describe, test } from 'node:test'
2
2
  import assert from 'node:assert'
3
- import {
4
- routeMatchesPattern,
5
- resolveHTTPPermissions,
6
- resolvePermissions,
7
- } from './permissions.js'
8
- import type { InspectorState, PermissionGroupMeta } from '../types.js'
9
-
10
- describe('routeMatchesPattern', () => {
11
- test('should match exact routes', () => {
12
- assert.strictEqual(routeMatchesPattern('/api/users', '/api/users'), true)
13
- })
14
-
15
- test('should not match different routes', () => {
16
- assert.strictEqual(routeMatchesPattern('/api/users', '/api/posts'), false)
17
- })
18
-
19
- test('should match wildcard patterns', () => {
20
- assert.strictEqual(routeMatchesPattern('/api/users', '/api/*'), true)
21
- assert.strictEqual(routeMatchesPattern('/api/users/123', '/api/*'), true)
22
- assert.strictEqual(routeMatchesPattern('/api/posts', '/api/*'), true)
23
- })
24
-
25
- test('should match global wildcard', () => {
26
- assert.strictEqual(routeMatchesPattern('/api/users', '*'), true)
27
- assert.strictEqual(routeMatchesPattern('/any/path', '*'), true)
28
- })
29
-
30
- test('should not match if pattern is more specific', () => {
31
- assert.strictEqual(routeMatchesPattern('/users', '/api/*'), false)
32
- })
33
- })
34
-
35
- describe('resolveHTTPPermissions', () => {
36
- test('should return undefined when no permissions exist', () => {
37
- const state: InspectorState = createMockState()
38
-
39
- const result = resolveHTTPPermissions(
40
- state,
41
- '/api/test',
42
- undefined,
43
- undefined,
44
- {} as any
45
- )
46
-
47
- assert.strictEqual(result, undefined)
48
- })
49
-
50
- test('should resolve global HTTP permissions', () => {
51
- const state: InspectorState = createMockState()
52
- const globalPermission: PermissionGroupMeta = {
53
- exportName: 'globalPermissions',
54
- sourceFile: '/test.ts',
55
- position: 0,
56
- services: { services: [], singletons: [] },
57
- count: 1,
58
- instanceIds: [],
59
- isFactory: true,
60
- }
61
- state.http.routePermissions.set('*', globalPermission)
62
-
63
- const result = resolveHTTPPermissions(
64
- state,
65
- '/api/test',
66
- undefined,
67
- undefined,
68
- {} as any
69
- )
70
-
71
- assert.ok(result)
72
- assert.strictEqual(result.length, 1)
73
- assert.deepEqual(result[0], { type: 'http', route: '*' })
74
- })
75
-
76
- test('should resolve route pattern permissions', () => {
77
- const state: InspectorState = createMockState()
78
- const apiPermission: PermissionGroupMeta = {
79
- exportName: 'apiPermissions',
80
- sourceFile: '/test.ts',
81
- position: 0,
82
- services: { services: [], singletons: [] },
83
- count: 1,
84
- instanceIds: [],
85
- isFactory: true,
86
- }
87
- state.http.routePermissions.set('/api/*', apiPermission)
88
-
89
- const result = resolveHTTPPermissions(
90
- state,
91
- '/api/users',
92
- undefined,
93
- undefined,
94
- {} as any
95
- )
96
-
97
- assert.ok(result)
98
- assert.strictEqual(result.length, 1)
99
- assert.deepEqual(result[0], { type: 'http', route: '/api/*' })
100
- })
101
-
102
- test('should resolve tag-based permissions', () => {
103
- const state: InspectorState = createMockState()
104
- const adminPermission: PermissionGroupMeta = {
105
- exportName: 'adminPermissions',
106
- sourceFile: '/test.ts',
107
- position: 0,
108
- services: { services: [], singletons: [] },
109
- count: 1,
110
- instanceIds: [],
111
- isFactory: true,
112
- }
113
- state.permissions.tagPermissions.set('admin', adminPermission)
114
-
115
- const result = resolveHTTPPermissions(
116
- state,
117
- '/api/admin',
118
- ['admin'],
119
- undefined,
120
- {} as any
121
- )
122
-
123
- assert.ok(result)
124
- assert.strictEqual(result.length, 1)
125
- assert.deepEqual(result[0], { type: 'tag', tag: 'admin' })
126
- })
127
-
128
- test('should combine multiple permission sources in correct order', () => {
129
- const state: InspectorState = createMockState()
130
-
131
- // Setup global HTTP permission
132
- state.http.routePermissions.set('*', {
133
- exportName: 'global',
134
- sourceFile: '/test.ts',
135
- position: 0,
136
- services: { services: [], singletons: [] },
137
- count: 1,
138
- instanceIds: [],
139
- isFactory: true,
140
- })
141
-
142
- // Setup route pattern permission
143
- state.http.routePermissions.set('/api/*', {
144
- exportName: 'apiRoute',
145
- sourceFile: '/test.ts',
146
- position: 0,
147
- services: { services: [], singletons: [] },
148
- count: 1,
149
- instanceIds: [],
150
- isFactory: true,
151
- })
152
-
153
- // Setup tag permission
154
- state.permissions.tagPermissions.set('admin', {
155
- exportName: 'adminTag',
156
- sourceFile: '/test.ts',
157
- position: 0,
158
- services: { services: [], singletons: [] },
159
- count: 1,
160
- instanceIds: [],
161
- isFactory: true,
162
- })
163
-
164
- // Setup explicit permission
165
- state.permissions.definitions['testPermission'] = {
166
- services: { services: [], singletons: [] },
167
- sourceFile: '/test.ts',
168
- position: 0,
169
- exportedName: 'testPerm',
170
- }
171
-
172
- const result = resolveHTTPPermissions(
173
- state,
174
- '/api/admin',
175
- ['admin'],
176
- undefined, // We'd need a real TS node for this
177
- {} as any
178
- )
179
-
180
- assert.ok(result)
181
- // Should have: global HTTP, route pattern, tag
182
- assert.strictEqual(result.length, 3)
183
- assert.deepEqual(result[0], { type: 'http', route: '*' })
184
- assert.deepEqual(result[1], { type: 'http', route: '/api/*' })
185
- assert.deepEqual(result[2], { type: 'tag', tag: 'admin' })
186
- })
187
- })
3
+ import { resolvePermissions } from './permissions.js'
4
+ import type { InspectorState } from '../types.js'
188
5
 
189
6
  describe('resolvePermissions', () => {
190
- test('should return undefined when no permissions exist', () => {
7
+ test('should return undefined when the object declares no permissions', () => {
191
8
  const state: InspectorState = createMockState()
192
9
  const mockObj = createMockObjectLiteral()
193
10
 
@@ -196,47 +13,10 @@ describe('resolvePermissions', () => {
196
13
  assert.strictEqual(result, undefined)
197
14
  })
198
15
 
199
- test('should resolve tag-based permissions', () => {
200
- const state: InspectorState = createMockState()
201
- const mcpPermission: PermissionGroupMeta = {
202
- exportName: 'mcpPermissions',
203
- sourceFile: '/test.ts',
204
- position: 0,
205
- services: { services: [], singletons: [] },
206
- count: 1,
207
- instanceIds: [],
208
- isFactory: true,
209
- }
210
- state.permissions.tagPermissions.set('mcp', mcpPermission)
211
- const mockObj = createMockObjectLiteral()
212
-
213
- const result = resolvePermissions(state, mockObj, ['mcp'], {} as any)
214
-
215
- assert.ok(result)
216
- assert.strictEqual(result.length, 1)
217
- assert.deepEqual(result[0], { type: 'tag', tag: 'mcp' })
218
- })
219
-
220
- test('should handle multiple tags', () => {
16
+ test('tags no longer resolve to permissions', () => {
17
+ // Permissions are function-scoped only; tags are organizational and never
18
+ // contribute permission metadata.
221
19
  const state: InspectorState = createMockState()
222
- state.permissions.tagPermissions.set('mcp', {
223
- exportName: 'mcpPerms',
224
- sourceFile: '/test.ts',
225
- position: 0,
226
- services: { services: [], singletons: [] },
227
- count: 1,
228
- instanceIds: [],
229
- isFactory: true,
230
- })
231
- state.permissions.tagPermissions.set('admin', {
232
- exportName: 'adminPerms',
233
- sourceFile: '/test.ts',
234
- position: 0,
235
- services: { services: [], singletons: [] },
236
- count: 1,
237
- instanceIds: [],
238
- isFactory: true,
239
- })
240
20
  const mockObj = createMockObjectLiteral()
241
21
 
242
22
  const result = resolvePermissions(
@@ -246,10 +26,7 @@ describe('resolvePermissions', () => {
246
26
  {} as any
247
27
  )
248
28
 
249
- assert.ok(result)
250
- assert.strictEqual(result.length, 2)
251
- assert.deepEqual(result[0], { type: 'tag', tag: 'mcp' })
252
- assert.deepEqual(result[1], { type: 'tag', tag: 'admin' })
29
+ assert.strictEqual(result, undefined)
253
30
  })
254
31
  })
255
32
 
@@ -288,7 +65,6 @@ function createMockState(): InspectorState {
288
65
  },
289
66
  files: new Set(),
290
67
  routeMiddleware: new Map(),
291
- routePermissions: new Map(),
292
68
  },
293
69
  functions: {
294
70
  typesMap: {} as any,
@@ -344,7 +120,6 @@ function createMockState(): InspectorState {
344
120
  permissions: {
345
121
  definitions: {},
346
122
  instances: {},
347
- tagPermissions: new Map(),
348
123
  },
349
124
  }
350
125
  }
@@ -76,147 +76,34 @@ export function getPermissionsNode(
76
76
  }
77
77
 
78
78
  /**
79
- * Check if a route matches a pattern with wildcards
80
- * Pattern can be exact match or use * as wildcard
81
- * e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
79
+ * Resolve the explicit permission references declared on a function (or agent).
80
+ * Permissions are function-scoped only: a `permissions: { group: [fn] }` object
81
+ * is flattened to `{ type: 'wire', name }` references used at filter time.
82
+ * Returns undefined if none are declared, otherwise an array with ≥1 item.
82
83
  */
83
- export function routeMatchesPattern(route: string, pattern: string): boolean {
84
- if (route === pattern) return true
85
-
86
- // Convert pattern to regex: replace * with .*
87
- const regexPattern = pattern
88
- .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape regex special chars except *
89
- .replace(/\*/g, '.*') // Replace * with .*
90
-
91
- const regex = new RegExp(`^${regexPattern}$`)
92
- return regex.test(route)
93
- }
94
-
95
- /**
96
- * Resolve permissions for an HTTP wiring based on:
97
- * 1. Global HTTP permissions (addHTTPPermission('*', [...]))
98
- * 2. Route-specific HTTP permissions (addHTTPPermission('/pattern', [...]))
99
- * 3. Tag-based permissions (addPermission('tag', [...]))
100
- * 4. Explicit wiring permissions (wireHTTP({ permissions: [...] }))
101
- * Returns undefined if no permissions are found, otherwise returns array with at least one item
102
- */
103
- export function resolveHTTPPermissions(
84
+ function resolveExplicitPermissions(
104
85
  state: InspectorState,
105
- route: string,
106
- tags: string[] | undefined,
107
86
  explicitPermissionsNode: ts.Expression | undefined,
108
87
  checker: ts.TypeChecker
109
88
  ): PermissionMetadata[] | undefined {
110
- const resolved: PermissionMetadata[] = []
111
-
112
- // 1. HTTP route permission groups (includes '*' for global)
113
- for (const [pattern, _groupMeta] of state.http.routePermissions.entries()) {
114
- if (routeMatchesPattern(route, pattern)) {
115
- // Just reference the group by route pattern
116
- resolved.push({
117
- type: 'http',
118
- route: pattern,
119
- })
120
- }
89
+ if (!explicitPermissionsNode) {
90
+ return undefined
121
91
  }
122
92
 
123
- // 2. Tag-based permission groups
124
- if (tags && tags.length > 0) {
125
- for (const tag of tags) {
126
- if (state.permissions.tagPermissions.has(tag)) {
127
- // Just reference the group by tag
128
- resolved.push({
129
- type: 'tag',
130
- tag,
131
- })
132
- }
133
- }
134
- }
135
-
136
- // 3. Explicit wire permissions (inline is OK here)
137
- if (explicitPermissionsNode) {
138
- const permissionNames = extractPermissionPikkuNames(
139
- explicitPermissionsNode,
140
- checker,
141
- state.rootDir
142
- )
143
- for (const name of permissionNames) {
144
- const def = state.permissions.definitions[name]
145
- resolved.push({
146
- type: 'wire',
147
- name,
148
- inline: def?.exportedName === null,
149
- })
150
- }
151
- }
152
-
153
- return resolved.length > 0 ? resolved : undefined
154
- }
155
-
156
- /**
157
- * Resolve tag-based and explicit permissions (common logic for wires and functions)
158
- * 1. Tag-based permissions (addPermission('tag', [...]))
159
- * 2. Explicit permissions (wireHTTP/pikkuFunc({ permissions: [...] }))
160
- */
161
- function resolveTagAndExplicitPermissions(
162
- state: InspectorState,
163
- tags: string[] | undefined,
164
- explicitPermissionsNode: ts.Expression | undefined,
165
- checker: ts.TypeChecker
166
- ): PermissionMetadata[] {
167
93
  const resolved: PermissionMetadata[] = []
168
-
169
- // 1. Tag-based permission groups
170
- if (tags && tags.length > 0) {
171
- for (const tag of tags) {
172
- if (state.permissions.tagPermissions.has(tag)) {
173
- // Just reference the group by tag
174
- resolved.push({
175
- type: 'tag',
176
- tag,
177
- })
178
- }
179
- }
180
- }
181
-
182
- // 2. Explicit permissions (inline is OK here - used directly in wire/function)
183
- if (explicitPermissionsNode) {
184
- const permissionNames = extractPermissionPikkuNames(
185
- explicitPermissionsNode,
186
- checker,
187
- state.rootDir
188
- )
189
- for (const name of permissionNames) {
190
- const def = state.permissions.definitions[name]
191
- resolved.push({
192
- type: 'wire',
193
- name,
194
- inline: def?.exportedName === null,
195
- })
196
- }
197
- }
198
-
199
- return resolved
200
- }
201
-
202
- /**
203
- * Resolve permissions for a function based on:
204
- * 1. Tag-based permissions (addPermission('tag', [...]))
205
- * 2. Explicit function permissions (pikkuFunc({ permissions: [...] }))
206
- * Returns undefined if no permissions are found, otherwise returns array with at least one item
207
- */
208
- function resolveFunctionPermissionsInternal(
209
- state: InspectorState,
210
- tags: string[] | undefined,
211
- explicitPermissionsNode: ts.Expression | undefined,
212
- checker: ts.TypeChecker
213
- ): PermissionMetadata[] | undefined {
214
- const resolved = resolveTagAndExplicitPermissions(
215
- state,
216
- tags,
94
+ const permissionNames = extractPermissionPikkuNames(
217
95
  explicitPermissionsNode,
218
- checker
96
+ checker,
97
+ state.rootDir
219
98
  )
99
+ for (const name of permissionNames) {
100
+ const def = state.permissions.definitions[name]
101
+ resolved.push({
102
+ type: 'wire',
103
+ name,
104
+ inline: def?.exportedName === null,
105
+ })
106
+ }
220
107
 
221
108
  return resolved.length > 0 ? resolved : undefined
222
109
  }
@@ -228,35 +115,8 @@ function resolveFunctionPermissionsInternal(
228
115
  export function resolvePermissions(
229
116
  state: InspectorState,
230
117
  obj: ts.ObjectLiteralExpression,
231
- tags: string[] | undefined,
118
+ _tags: string[] | undefined,
232
119
  checker: ts.TypeChecker
233
120
  ): PermissionMetadata[] | undefined {
234
- const explicitPermissionsNode = getPermissionsNode(obj)
235
- return resolveFunctionPermissionsInternal(
236
- state,
237
- tags,
238
- explicitPermissionsNode,
239
- checker
240
- )
241
- }
242
-
243
- /**
244
- * Convenience wrapper for HTTP: Extract permissions and resolve with HTTP-specific logic
245
- * Use this in add-http-route.ts for cleaner code
246
- */
247
- export function resolveHTTPPermissionsFromObject(
248
- state: InspectorState,
249
- route: string,
250
- obj: ts.ObjectLiteralExpression,
251
- tags: string[] | undefined,
252
- checker: ts.TypeChecker
253
- ): PermissionMetadata[] | undefined {
254
- const explicitPermissionsNode = getPermissionsNode(obj)
255
- return resolveHTTPPermissions(
256
- state,
257
- route,
258
- tags,
259
- explicitPermissionsNode,
260
- checker
261
- )
121
+ return resolveExplicitPermissions(state, getPermissionsNode(obj), checker)
262
122
  }