@pikku/inspector 0.12.75 → 0.12.82

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 (223) hide show
  1. package/CHANGELOG.md +357 -0
  2. package/dist/add/add-analytics.d.ts +9 -0
  3. package/dist/add/add-analytics.js +178 -0
  4. package/dist/add/add-auth.js +0 -54
  5. package/dist/add/add-feature-flag.d.ts +2 -0
  6. package/dist/add/add-feature-flag.js +162 -0
  7. package/dist/add/add-middleware.js +66 -42
  8. package/dist/add/add-wire-addon.js +7 -4
  9. package/dist/add/add-wire-remote-addon.js +1 -0
  10. package/dist/error-codes.d.ts +1 -0
  11. package/dist/error-codes.js +1 -0
  12. package/dist/index.d.ts +3 -1
  13. package/dist/index.js +3 -1
  14. package/dist/inspector.js +5 -0
  15. package/dist/surface/collect-surface.d.ts +58 -0
  16. package/dist/surface/collect-surface.js +613 -0
  17. package/dist/types.d.ts +36 -12
  18. package/dist/utils/filter-inspector-state.js +14 -0
  19. package/dist/utils/load-addon-functions-meta.js +24 -11
  20. package/dist/utils/post-process.js +15 -0
  21. package/dist/utils/read-module-specifiers.d.ts +8 -0
  22. package/dist/utils/read-module-specifiers.js +23 -0
  23. package/dist/utils/read-tsconfig-out-dir.d.ts +5 -0
  24. package/dist/utils/read-tsconfig-out-dir.js +12 -0
  25. package/dist/utils/resolve-deploy-target.d.ts +7 -0
  26. package/dist/utils/resolve-deploy-target.js +15 -7
  27. package/dist/utils/serialize-inspector-state.d.ts +6 -0
  28. package/dist/utils/serialize-inspector-state.js +10 -0
  29. package/dist/visit.js +4 -0
  30. package/package.json +16 -6
  31. package/run-tests.sh +21 -6
  32. package/src/add/add-addon-bans.ts +0 -85
  33. package/src/add/add-agent-scorer.test.ts +0 -197
  34. package/src/add/add-agent-scorer.ts +0 -83
  35. package/src/add/add-agent.test.ts +0 -87
  36. package/src/add/add-agent.ts +0 -638
  37. package/src/add/add-approval-description.ts +0 -76
  38. package/src/add/add-auth.test.ts +0 -791
  39. package/src/add/add-auth.ts +0 -424
  40. package/src/add/add-channel.ts +0 -778
  41. package/src/add/add-cli-renderers.test.ts +0 -74
  42. package/src/add/add-cli.ts +0 -1006
  43. package/src/add/add-credential.ts +0 -186
  44. package/src/add/add-feature.test.ts +0 -306
  45. package/src/add/add-feature.ts +0 -253
  46. package/src/add/add-file-extends-core-type.ts +0 -66
  47. package/src/add/add-file-with-config.ts +0 -45
  48. package/src/add/add-file-with-factory.test.ts +0 -134
  49. package/src/add/add-file-with-factory.ts +0 -288
  50. package/src/add/add-functions.test.ts +0 -743
  51. package/src/add/add-functions.ts +0 -1548
  52. package/src/add/add-gateway.ts +0 -143
  53. package/src/add/add-http-route-ref.test.ts +0 -149
  54. package/src/add/add-http-route.ts +0 -530
  55. package/src/add/add-http-routes.ts +0 -471
  56. package/src/add/add-keyed-wiring.ts +0 -180
  57. package/src/add/add-mcp-prompt.ts +0 -157
  58. package/src/add/add-mcp-resource.ts +0 -175
  59. package/src/add/add-middleware.test.ts +0 -196
  60. package/src/add/add-middleware.ts +0 -879
  61. package/src/add/add-permission-auth.test.ts +0 -59
  62. package/src/add/add-permission.ts +0 -311
  63. package/src/add/add-personas.test.ts +0 -406
  64. package/src/add/add-personas.ts +0 -287
  65. package/src/add/add-queue-worker.ts +0 -117
  66. package/src/add/add-rpc-invocations.test.ts +0 -287
  67. package/src/add/add-rpc-invocations.ts +0 -221
  68. package/src/add/add-scenario-step.test.ts +0 -509
  69. package/src/add/add-schedule.ts +0 -120
  70. package/src/add/add-scope.test.ts +0 -419
  71. package/src/add/add-scope.ts +0 -221
  72. package/src/add/add-secret.ts +0 -10
  73. package/src/add/add-subject-scenario-steps.test.ts +0 -161
  74. package/src/add/add-system-role.test.ts +0 -297
  75. package/src/add/add-system-role.ts +0 -162
  76. package/src/add/add-trigger.ts +0 -165
  77. package/src/add/add-variable.ts +0 -10
  78. package/src/add/add-wire-addon.test.ts +0 -185
  79. package/src/add/add-wire-addon.ts +0 -146
  80. package/src/add/add-wire-remote-addon.ts +0 -80
  81. package/src/add/add-workflow-edge-cases.test.ts +0 -201
  82. package/src/add/add-workflow-fanout.test.ts +0 -166
  83. package/src/add/add-workflow-graph-foreach.test.ts +0 -174
  84. package/src/add/add-workflow-graph-input.test.ts +0 -94
  85. package/src/add/add-workflow-graph-notes.test.ts +0 -74
  86. package/src/add/add-workflow-graph.ts +0 -644
  87. package/src/add/add-workflow-on-error.test.ts +0 -118
  88. package/src/add/add-workflow-return-switch.test.ts +0 -121
  89. package/src/add/add-workflow-silent-drops.test.ts +0 -261
  90. package/src/add/add-workflow-sleep-expression.test.ts +0 -96
  91. package/src/add/add-workflow.test.ts +0 -155
  92. package/src/add/add-workflow.ts +0 -482
  93. package/src/add/addon-bans.test.ts +0 -121
  94. package/src/add/addon-contracts.test.ts +0 -221
  95. package/src/add/allow-escape-hatches.test.ts +0 -144
  96. package/src/add/audit-meta.test.ts +0 -75
  97. package/src/add/classified-sink-check.test.ts +0 -347
  98. package/src/add/config-value-metadata.test.ts +0 -263
  99. package/src/add/dynamic-import-check.test.ts +0 -119
  100. package/src/add/expect-eventually-scenario-only.test.ts +0 -108
  101. package/src/add/function-body-span.test.ts +0 -96
  102. package/src/add/inline-wiring-function.test.ts +0 -104
  103. package/src/add/pii-check.test.ts +0 -258
  104. package/src/add/rpc-type-cast.test.ts +0 -123
  105. package/src/add/scenario-instrumentation.test.ts +0 -89
  106. package/src/add/scenario-instrumentation.ts +0 -42
  107. package/src/add/scenario-marker.test.ts +0 -89
  108. package/src/add/scenario-not-extractable.test.ts +0 -159
  109. package/src/add/scenario-services.test.ts +0 -103
  110. package/src/add/scenario-skip.test.ts +0 -83
  111. package/src/add/validate-workflow-graph-addons.test.ts +0 -102
  112. package/src/add/wire-name-literal.test.ts +0 -117
  113. package/src/error-codes-emitted.test.ts +0 -76
  114. package/src/error-codes.ts +0 -145
  115. package/src/index.ts +0 -66
  116. package/src/inspector.ts +0 -575
  117. package/src/schema-generator.ts +0 -1
  118. package/src/source-file-cache.ts +0 -73
  119. package/src/tsconfig-paths.test.ts +0 -90
  120. package/src/types-map.ts +0 -141
  121. package/src/types.ts +0 -775
  122. package/src/utils/annotate-http-route-auth.test.ts +0 -161
  123. package/src/utils/annotate-http-route-auth.ts +0 -53
  124. package/src/utils/check-classified-sinks.ts +0 -215
  125. package/src/utils/check-pii-output.ts +0 -120
  126. package/src/utils/compute-diagnostics.test.ts +0 -106
  127. package/src/utils/compute-required-schemas.ts +0 -48
  128. package/src/utils/contract-hashes.test.ts +0 -553
  129. package/src/utils/contract-hashes.ts +0 -387
  130. package/src/utils/custom-types-generator.test.ts +0 -124
  131. package/src/utils/custom-types-generator.ts +0 -150
  132. package/src/utils/detect-schema-vendor.test.ts +0 -123
  133. package/src/utils/detect-schema-vendor.ts +0 -120
  134. package/src/utils/does-type-extend-core-type.ts +0 -53
  135. package/src/utils/ensure-function-metadata.ts +0 -385
  136. package/src/utils/extract-function-name.ts +0 -612
  137. package/src/utils/extract-function-node.ts +0 -70
  138. package/src/utils/extract-node-value.test.ts +0 -117
  139. package/src/utils/extract-node-value.ts +0 -172
  140. package/src/utils/extract-secret-usage.test.ts +0 -81
  141. package/src/utils/extract-secret-usage.ts +0 -73
  142. package/src/utils/extract-services.ts +0 -70
  143. package/src/utils/extract-surface-usage.test.ts +0 -147
  144. package/src/utils/extract-surface-usage.ts +0 -121
  145. package/src/utils/filter-inspector-state.test.ts +0 -2232
  146. package/src/utils/filter-inspector-state.ts +0 -1298
  147. package/src/utils/filter-utils.test.ts +0 -843
  148. package/src/utils/filter-utils.ts +0 -161
  149. package/src/utils/find-root-dir.ts +0 -68
  150. package/src/utils/find-zod-transform.test.ts +0 -70
  151. package/src/utils/find-zod-transform.ts +0 -103
  152. package/src/utils/get-exported-variable-name.ts +0 -48
  153. package/src/utils/get-files-and-methods.ts +0 -157
  154. package/src/utils/get-property-value.test.ts +0 -141
  155. package/src/utils/get-property-value.ts +0 -331
  156. package/src/utils/hash.ts +0 -26
  157. package/src/utils/literal-properties.ts +0 -97
  158. package/src/utils/load-addon-functions-meta.test.ts +0 -157
  159. package/src/utils/load-addon-functions-meta.ts +0 -508
  160. package/src/utils/load-addon-scopes.test.ts +0 -138
  161. package/src/utils/middleware.test.ts +0 -204
  162. package/src/utils/middleware.ts +0 -303
  163. package/src/utils/nested-project-filter.test.ts +0 -53
  164. package/src/utils/nested-project-filter.ts +0 -28
  165. package/src/utils/permissions-shorthand.test.ts +0 -79
  166. package/src/utils/permissions.test.ts +0 -125
  167. package/src/utils/permissions.ts +0 -129
  168. package/src/utils/post-process.test.ts +0 -1094
  169. package/src/utils/post-process.ts +0 -1604
  170. package/src/utils/resolve-addon-package.ts +0 -106
  171. package/src/utils/resolve-core-type.test.ts +0 -142
  172. package/src/utils/resolve-core-type.ts +0 -35
  173. package/src/utils/resolve-deploy-target.test.ts +0 -135
  174. package/src/utils/resolve-deploy-target.ts +0 -65
  175. package/src/utils/resolve-function-meta.ts +0 -25
  176. package/src/utils/resolve-function-types.ts +0 -42
  177. package/src/utils/resolve-identifier.ts +0 -46
  178. package/src/utils/resolve-ref-contract.ts +0 -71
  179. package/src/utils/resolve-versions.test.ts +0 -499
  180. package/src/utils/resolve-versions.ts +0 -228
  181. package/src/utils/schema-cache.test.ts +0 -124
  182. package/src/utils/schema-generator.test.ts +0 -272
  183. package/src/utils/schema-generator.ts +0 -780
  184. package/src/utils/secret-alias-services.test.ts +0 -146
  185. package/src/utils/secret-alias-services.ts +0 -58
  186. package/src/utils/serialize-inspector-state.ts +0 -742
  187. package/src/utils/serialize-mcp-json.ts +0 -150
  188. package/src/utils/serialize-middleware-groups-meta.ts +0 -36
  189. package/src/utils/serialize-openapi-json.ts +0 -277
  190. package/src/utils/serialize-permissions-groups-meta.ts +0 -7
  191. package/src/utils/single-declaration.ts +0 -57
  192. package/src/utils/type-utils.ts +0 -145
  193. package/src/utils/validate-auth-sessionless.ts +0 -30
  194. package/src/utils/validate-exposed-functions-gated.test.ts +0 -230
  195. package/src/utils/validate-exposed-functions-gated.ts +0 -103
  196. package/src/utils/validate-tags-resolve-to-middleware.test.ts +0 -108
  197. package/src/utils/validate-tags-resolve-to-middleware.ts +0 -48
  198. package/src/utils/workflow/derive-workflow-plan.test.ts +0 -178
  199. package/src/utils/workflow/derive-workflow-plan.ts +0 -117
  200. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +0 -1465
  201. package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +0 -71
  202. package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +0 -99
  203. package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +0 -161
  204. package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +0 -121
  205. package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +0 -116
  206. package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +0 -145
  207. package/src/utils/workflow/dsl/extract-approval-policy.test.ts +0 -71
  208. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +0 -2254
  209. package/src/utils/workflow/dsl/index.ts +0 -11
  210. package/src/utils/workflow/dsl/patterns.ts +0 -440
  211. package/src/utils/workflow/dsl/validation.ts +0 -203
  212. package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +0 -35
  213. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +0 -543
  214. package/src/utils/workflow/graph/fanout-node-identity.test.ts +0 -105
  215. package/src/utils/workflow/graph/finalize-workflow-wires.ts +0 -310
  216. package/src/utils/workflow/graph/finalize-workflows.test.ts +0 -50
  217. package/src/utils/workflow/graph/finalize-workflows.ts +0 -130
  218. package/src/utils/workflow/graph/index.ts +0 -28
  219. package/src/utils/workflow/graph/serialize-workflow-graph.ts +0 -240
  220. package/src/utils/workflow/graph/workflow-graph.types.ts +0 -281
  221. package/src/visit.ts +0 -181
  222. package/tsconfig.json +0 -19
  223. package/tsconfig.tsbuildinfo +0 -1
@@ -1,2232 +0,0 @@
1
- import { test, describe } from 'node:test'
2
- import { strict as assert } from 'node:assert'
3
- import { filterInspectorState } from './filter-inspector-state.js'
4
- import type { InspectorState, InspectorFilters } from '../types.js'
5
- import type { SerializableInspectorState } from './serialize-inspector-state.js'
6
- import {
7
- deserializeInspectorState,
8
- serializeInspectorState,
9
- } from './serialize-inspector-state.js'
10
- import { getInitialInspectorState } from '../inspector.js'
11
- import { readFileSync } from 'node:fs'
12
- import { fileURLToPath } from 'node:url'
13
- import { dirname, join } from 'node:path'
14
-
15
- const __filename = fileURLToPath(import.meta.url)
16
- const __dirname = dirname(__filename)
17
-
18
- // Load the real inspector state from templates/functions
19
- let realState: Omit<InspectorState, 'typesLookup'>
20
- try {
21
- const stateJson = readFileSync(
22
- join(__dirname, 'test-data/inspector-state.json'),
23
- 'utf-8'
24
- )
25
- const serialized = JSON.parse(stateJson) as SerializableInspectorState
26
- realState = deserializeInspectorState(serialized)
27
- } catch (e) {
28
- console.error('Failed to load real inspector state:', e)
29
- throw e
30
- }
31
-
32
- // Helper to create a minimal mock InspectorState for testing (kept for compatibility)
33
- function createMockInspectorState(): Omit<InspectorState, 'typesLookup'> {
34
- return {
35
- rootDir: '/test/project',
36
- singletonServicesTypeImportMap: new Map(),
37
- wireServicesTypeImportMap: new Map(),
38
- userSessionTypeImportMap: new Map(),
39
- configTypeImportMap: new Map(),
40
- singletonServicesFactories: new Map(),
41
- wireServicesFactories: new Map(),
42
- wireServicesMeta: new Map(),
43
- configFactories: new Map(),
44
- filesAndMethods: {},
45
- filesAndMethodsErrors: new Map(),
46
- http: {
47
- metaInputTypes: new Map(),
48
- meta: {
49
- get: {
50
- '/api/users': {
51
- pikkuFuncId: 'getUsers',
52
- route: '/api/users',
53
- method: 'GET',
54
- tags: ['api', 'public'],
55
- middleware: [],
56
- permissions: [],
57
- },
58
- '/admin/settings': {
59
- pikkuFuncId: 'getAdminSettings',
60
- route: '/admin/settings',
61
- method: 'GET',
62
- tags: ['admin'],
63
- middleware: [{ type: 'wire', name: 'authMiddleware' }],
64
- permissions: [{ type: 'wire', name: 'adminPermission' }],
65
- },
66
- },
67
- post: {
68
- '/api/users': {
69
- pikkuFuncId: 'createUser',
70
- route: '/api/users',
71
- method: 'POST',
72
- tags: ['api'],
73
- middleware: [],
74
- permissions: [],
75
- },
76
- },
77
- put: {},
78
- patch: {},
79
- delete: {},
80
- head: {},
81
- options: {},
82
- },
83
- files: new Set(['/test/project/src/api/users.ts']),
84
- routeMiddleware: new Map(),
85
- },
86
- functions: {
87
- typesMap: new Map(),
88
- meta: {
89
- getUsers: {
90
- services: [],
91
- optimized: false,
92
- },
93
- createUser: {
94
- services: [],
95
- optimized: false,
96
- },
97
- getAdminSettings: {
98
- services: [],
99
- optimized: false,
100
- },
101
- sendEmailWorker: {
102
- services: [],
103
- optimized: false,
104
- },
105
- dailyReport: {
106
- services: [],
107
- optimized: false,
108
- },
109
- mcpSearchTool: {
110
- services: [],
111
- optimized: false,
112
- },
113
- cliCommand: {
114
- services: [],
115
- optimized: false,
116
- },
117
- },
118
- files: new Map([
119
- [
120
- 'getUsers',
121
- { path: '/test/project/src/api/users.ts', exportedName: 'getUsers' },
122
- ],
123
- [
124
- 'createUser',
125
- {
126
- path: '/test/project/src/api/users.ts',
127
- exportedName: 'createUser',
128
- },
129
- ],
130
- [
131
- 'getAdminSettings',
132
- {
133
- path: '/test/project/src/admin/settings.ts',
134
- exportedName: 'getAdminSettings',
135
- },
136
- ],
137
- [
138
- 'sendEmailWorker',
139
- {
140
- path: '/test/project/src/workers/email.ts',
141
- exportedName: 'sendEmailWorker',
142
- },
143
- ],
144
- [
145
- 'dailyReport',
146
- {
147
- path: '/test/project/src/tasks/reports.ts',
148
- exportedName: 'dailyReport',
149
- },
150
- ],
151
- ]),
152
- },
153
- triggers: {
154
- meta: {},
155
- files: new Set(),
156
- },
157
- channels: {
158
- meta: {
159
- 'chat-channel': {
160
- pikkuFuncId: 'handleChatMessage',
161
- tags: ['realtime', 'public'],
162
- middleware: [],
163
- permissions: [],
164
- sourceFile: '/test/project/src/channels/chat.ts',
165
- } as any,
166
- 'admin-channel': {
167
- pikkuFuncId: 'handleAdminMessage',
168
- tags: ['realtime', 'admin'],
169
- middleware: [{ type: 'wire', name: 'authMiddleware' }],
170
- permissions: [],
171
- sourceFile: '/test/project/src/channels/admin.ts',
172
- } as any,
173
- },
174
- files: new Set([
175
- '/test/project/src/channels/chat.ts',
176
- '/test/project/src/channels/admin.ts',
177
- ]),
178
- },
179
- scheduledTasks: {
180
- meta: {
181
- 'daily-report': {
182
- pikkuFuncId: 'dailyReport',
183
- schedule: '0 0 * * *',
184
- tags: ['cron', 'reports'],
185
- middleware: [],
186
- sourceFile: '/test/project/src/tasks/reports.ts',
187
- } as any,
188
- 'hourly-cleanup': {
189
- pikkuFuncId: 'hourlyCleanup',
190
- schedule: '0 * * * *',
191
- tags: ['cron', 'maintenance'],
192
- middleware: [],
193
- sourceFile: '/test/project/src/tasks/cleanup.ts',
194
- } as any,
195
- },
196
- files: new Set([
197
- '/test/project/src/tasks/reports.ts',
198
- '/test/project/src/tasks/cleanup.ts',
199
- ]),
200
- },
201
- queueWorkers: {
202
- meta: {
203
- 'email-worker': {
204
- pikkuFuncId: 'sendEmailWorker',
205
- name: 'email-queue',
206
- tags: ['queue', 'email'],
207
- middleware: [],
208
- sourceFile: '/test/project/src/workers/email.ts',
209
- } as any,
210
- 'notification-worker': {
211
- pikkuFuncId: 'sendNotificationWorker',
212
- name: 'notification-queue',
213
- tags: ['queue', 'notifications'],
214
- middleware: [],
215
- sourceFile: '/test/project/src/workers/notification.ts',
216
- } as any,
217
- },
218
- files: new Set([
219
- '/test/project/src/workers/email.ts',
220
- '/test/project/src/workers/notification.ts',
221
- ]),
222
- },
223
- workflows: {
224
- meta: {},
225
- files: new Map(),
226
- graphMeta: {},
227
- graphFiles: new Map(),
228
- invokedWorkflows: new Set(),
229
- },
230
- rpc: {
231
- internalMeta: {},
232
- internalFiles: new Map(),
233
- exposedMeta: {},
234
- exposedFiles: new Map(),
235
- invokedFunctions: new Set(),
236
- invokedFunctionsByFile: new Map(),
237
- },
238
- mcpEndpoints: {
239
- toolsMeta: {
240
- 'search-tool': {
241
- name: 'search-tool',
242
- description: 'Search tool',
243
- pikkuFuncId: 'mcpSearchTool',
244
- tags: ['mcp', 'search'],
245
- middleware: [],
246
- permissions: [],
247
- sourceFile: '/test/project/src/mcp/search.ts',
248
- } as any,
249
- 'analyze-tool': {
250
- name: 'analyze-tool',
251
- description: 'Analyze tool',
252
- pikkuFuncId: 'mcpAnalyzeTool',
253
- tags: ['mcp', 'analytics'],
254
- middleware: [],
255
- permissions: [],
256
- sourceFile: '/test/project/src/mcp/analyze.ts',
257
- } as any,
258
- },
259
- resourcesMeta: {
260
- 'docs-resource': {
261
- title: 'Docs Resource',
262
- description: 'Documentation resource',
263
- uri: 'docs://resource',
264
- pikkuFuncId: 'mcpDocsResource',
265
- tags: ['mcp', 'docs'],
266
- middleware: [],
267
- permissions: [],
268
- sourceFile: '/test/project/src/mcp/docs.ts',
269
- } as any,
270
- },
271
- promptsMeta: {
272
- 'help-prompt': {
273
- name: 'help-prompt',
274
- description: 'Help prompt',
275
- pikkuFuncId: 'mcpHelpPrompt',
276
- tags: ['mcp', 'help'],
277
- middleware: [],
278
- permissions: [],
279
- sourceFile: '/test/project/src/mcp/help.ts',
280
- } as any,
281
- },
282
- files: new Set([
283
- '/test/project/src/mcp/search.ts',
284
- '/test/project/src/mcp/analyze.ts',
285
- '/test/project/src/mcp/docs.ts',
286
- '/test/project/src/mcp/help.ts',
287
- ]),
288
- },
289
- cli: {
290
- meta: {
291
- programs: {
292
- 'my-cli': {
293
- sourceFile: '/test/project/src/cli/program.ts',
294
- commands: {
295
- build: {
296
- pikkuFuncId: 'cliCommand',
297
- tags: ['cli', 'build'],
298
- middleware: [],
299
- positionals: [],
300
- options: {},
301
- sourceFile: '/test/project/src/cli/build.ts',
302
- } as any,
303
- test: {
304
- pikkuFuncId: 'cliTestCommand',
305
- tags: ['cli', 'test'],
306
- middleware: [],
307
- positionals: [],
308
- options: {},
309
- sourceFile: '/test/project/src/cli/test.ts',
310
- } as any,
311
- },
312
- } as any,
313
- },
314
- },
315
- files: new Set([
316
- '/test/project/src/cli/program.ts',
317
- '/test/project/src/cli/build.ts',
318
- '/test/project/src/cli/test.ts',
319
- ]),
320
- },
321
- middleware: {
322
- definitions: {},
323
- instances: {},
324
- tagMiddleware: new Map(),
325
- },
326
- channelMiddleware: {
327
- definitions: {},
328
- instances: {},
329
- tagMiddleware: new Map(),
330
- },
331
- permissions: {
332
- definitions: {},
333
- instances: {},
334
- },
335
- serviceAggregation: {
336
- requiredServices: new Set(),
337
- usedFunctions: new Set(),
338
- usedMiddleware: new Set(),
339
- usedPermissions: new Set(),
340
- },
341
- }
342
- }
343
-
344
- // Mock logger for testing
345
- const mockLogger = {
346
- info: () => {},
347
- error: () => {},
348
- warn: () => {},
349
- debug: () => {},
350
- diagnostic: () => {},
351
- critical: () => {},
352
- hasCriticalErrors: () => false,
353
- }
354
-
355
- describe('filterInspectorState', () => {
356
- describe('No filters - returns original state', () => {
357
- test('should return original state when no filters provided', () => {
358
- const state = createMockInspectorState()
359
- const filters: InspectorFilters = {}
360
-
361
- const result = filterInspectorState(state, filters, mockLogger)
362
-
363
- assert.equal(result, state) // Should be the same reference
364
- })
365
-
366
- test('should return original state when all filter arrays are empty', () => {
367
- const state = createMockInspectorState()
368
- const filters: InspectorFilters = {
369
- names: [],
370
- tags: [],
371
- wires: [],
372
- directories: [],
373
- httpRoutes: [],
374
- httpMethods: [],
375
- }
376
-
377
- const result = filterInspectorState(state, filters, mockLogger)
378
-
379
- assert.equal(result, state)
380
- })
381
- })
382
-
383
- describe('HTTP filtering', () => {
384
- test('should filter HTTP routes by type', () => {
385
- const state = createMockInspectorState()
386
- const filters: InspectorFilters = {
387
- wires: ['channel'], // Only channels, not HTTP
388
- }
389
-
390
- const result = filterInspectorState(state, filters, mockLogger)
391
-
392
- // HTTP routes should be empty
393
- assert.equal(Object.keys(result.http.meta.get).length, 0)
394
- assert.equal(Object.keys(result.http.meta.post).length, 0)
395
-
396
- // Channels should still exist
397
- assert.equal(Object.keys(result.channels.meta).length, 2)
398
- })
399
-
400
- test('should filter HTTP routes by tags', () => {
401
- const state = createMockInspectorState()
402
- const filters: InspectorFilters = {
403
- wires: ['http'],
404
- tags: ['admin'],
405
- }
406
-
407
- const result = filterInspectorState(state, filters, mockLogger)
408
-
409
- // Only admin route should remain
410
- assert.equal(Object.keys(result.http.meta.get).length, 1)
411
- assert.ok(result.http.meta.get['/admin/settings'])
412
- assert.equal(Object.keys(result.http.meta.post).length, 0)
413
- })
414
-
415
- test('should filter HTTP routes by httpMethod', () => {
416
- const state = createMockInspectorState()
417
- const filters: InspectorFilters = {
418
- httpMethods: ['GET'],
419
- }
420
-
421
- const result = filterInspectorState(state, filters, mockLogger)
422
-
423
- // Only GET routes should remain
424
- assert.equal(Object.keys(result.http.meta.get).length, 2)
425
- assert.equal(Object.keys(result.http.meta.post).length, 0)
426
- })
427
-
428
- test('should filter HTTP routes by httpRoute pattern', () => {
429
- const state = createMockInspectorState()
430
- const filters: InspectorFilters = {
431
- httpRoutes: ['/api/*'],
432
- }
433
-
434
- const result = filterInspectorState(state, filters, mockLogger)
435
-
436
- // Only /api/* routes should remain
437
- assert.ok(result.http.meta.get['/api/users'])
438
- assert.ok(result.http.meta.post['/api/users'])
439
- assert.ok(!result.http.meta.get['/admin/settings'])
440
- })
441
-
442
- test('should filter HTTP routes by directory', () => {
443
- const state = createMockInspectorState()
444
- const filters: InspectorFilters = {
445
- wires: ['http'],
446
- directories: ['src/admin'],
447
- }
448
-
449
- const result = filterInspectorState(state, filters, mockLogger)
450
-
451
- // Only admin routes should remain
452
- assert.equal(Object.keys(result.http.meta.get).length, 1)
453
- assert.ok(result.http.meta.get['/admin/settings'])
454
- })
455
-
456
- test('should filter HTTP routes by function name', () => {
457
- const state = createMockInspectorState()
458
- const filters: InspectorFilters = {
459
- wires: ['http'],
460
- names: ['getUsers'],
461
- }
462
-
463
- const result = filterInspectorState(state, filters, mockLogger)
464
-
465
- assert.equal(Object.keys(result.http.meta.get).length, 1)
466
- assert.ok(result.http.meta.get['/api/users'])
467
- assert.equal(result.http.meta.get['/api/users'].pikkuFuncId, 'getUsers')
468
- })
469
-
470
- test('should filter HTTP routes by name wildcard', () => {
471
- const state = createMockInspectorState()
472
- const filters: InspectorFilters = {
473
- wires: ['http'],
474
- names: ['get*'],
475
- }
476
-
477
- const result = filterInspectorState(state, filters, mockLogger)
478
-
479
- // Should match getUsers and getAdminSettings
480
- assert.equal(Object.keys(result.http.meta.get).length, 2)
481
- assert.equal(Object.keys(result.http.meta.post).length, 0)
482
- })
483
-
484
- test('should track middleware and permissions for filtered HTTP routes', () => {
485
- const state = createMockInspectorState()
486
- const filters: InspectorFilters = {
487
- wires: ['http'],
488
- tags: ['admin'],
489
- }
490
-
491
- const result = filterInspectorState(state, filters, mockLogger)
492
-
493
- // Check that service aggregation includes the middleware and permissions
494
- assert.ok(result.serviceAggregation.usedMiddleware.has('authMiddleware'))
495
- assert.ok(
496
- result.serviceAggregation.usedPermissions.has('adminPermission')
497
- )
498
- assert.ok(result.serviceAggregation.usedFunctions.has('getAdminSettings'))
499
- })
500
- })
501
-
502
- describe('Channel filtering', () => {
503
- test('should filter channels by type', () => {
504
- const state = createMockInspectorState()
505
- const filters: InspectorFilters = {
506
- wires: ['channel'],
507
- }
508
-
509
- const result = filterInspectorState(state, filters, mockLogger)
510
-
511
- // Channels should exist
512
- assert.equal(Object.keys(result.channels.meta).length, 2)
513
-
514
- // HTTP routes should be empty
515
- assert.equal(Object.keys(result.http.meta.get).length, 0)
516
- assert.equal(Object.keys(result.http.meta.post).length, 0)
517
- })
518
-
519
- test('should filter channels by tags', () => {
520
- const state = createMockInspectorState()
521
- const filters: InspectorFilters = {
522
- wires: ['channel'],
523
- tags: ['admin'],
524
- }
525
-
526
- const result = filterInspectorState(state, filters, mockLogger)
527
-
528
- assert.equal(Object.keys(result.channels.meta).length, 1)
529
- assert.ok(result.channels.meta['admin-channel'])
530
- })
531
-
532
- test('should filter channels by name', () => {
533
- const state = createMockInspectorState()
534
- const filters: InspectorFilters = {
535
- names: ['chat-channel'],
536
- }
537
-
538
- const result = filterInspectorState(state, filters, mockLogger)
539
-
540
- assert.equal(Object.keys(result.channels.meta).length, 1)
541
- assert.ok(result.channels.meta['chat-channel'])
542
- })
543
-
544
- test('should filter channels by name wildcard', () => {
545
- const state = createMockInspectorState()
546
- const filters: InspectorFilters = {
547
- names: ['*-channel'],
548
- }
549
-
550
- const result = filterInspectorState(state, filters, mockLogger)
551
-
552
- assert.equal(Object.keys(result.channels.meta).length, 2)
553
- })
554
-
555
- test('should repopulate channel files from surviving metadata', () => {
556
- const state = createMockInspectorState()
557
- const filters: InspectorFilters = {
558
- wires: ['channel'],
559
- tags: ['admin'],
560
- }
561
-
562
- const result = filterInspectorState(state, filters, mockLogger)
563
-
564
- assert.deepEqual(Array.from(result.channels.files).sort(), [
565
- '/test/project/src/channels/admin.ts',
566
- ])
567
- })
568
- })
569
-
570
- describe('Scheduled task filtering', () => {
571
- test('should filter scheduled tasks by type', () => {
572
- const state = createMockInspectorState()
573
- const filters: InspectorFilters = {
574
- wires: ['scheduler'],
575
- }
576
-
577
- const result = filterInspectorState(state, filters, mockLogger)
578
-
579
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 2)
580
-
581
- // Other types should be empty
582
- assert.equal(Object.keys(result.http.meta.get).length, 0)
583
- assert.equal(Object.keys(result.channels.meta).length, 0)
584
- })
585
-
586
- test('should filter scheduled tasks by tags', () => {
587
- const state = createMockInspectorState()
588
- const filters: InspectorFilters = {
589
- wires: ['scheduler'],
590
- tags: ['reports'],
591
- }
592
-
593
- const result = filterInspectorState(state, filters, mockLogger)
594
-
595
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 1)
596
- assert.ok(result.scheduledTasks.meta['daily-report'])
597
- })
598
-
599
- test('should filter scheduled tasks by name', () => {
600
- const state = createMockInspectorState()
601
- const filters: InspectorFilters = {
602
- names: ['daily-report'],
603
- }
604
-
605
- const result = filterInspectorState(state, filters, mockLogger)
606
-
607
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 1)
608
- assert.ok(result.scheduledTasks.meta['daily-report'])
609
- })
610
-
611
- test('should filter scheduled tasks by name wildcard', () => {
612
- const state = createMockInspectorState()
613
- const filters: InspectorFilters = {
614
- names: ['*-cleanup'],
615
- }
616
-
617
- const result = filterInspectorState(state, filters, mockLogger)
618
-
619
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 1)
620
- assert.ok(result.scheduledTasks.meta['hourly-cleanup'])
621
- })
622
-
623
- test('should repopulate scheduled task files from surviving metadata', () => {
624
- const state = createMockInspectorState()
625
- const filters: InspectorFilters = {
626
- wires: ['scheduler'],
627
- tags: ['reports'],
628
- }
629
-
630
- const result = filterInspectorState(state, filters, mockLogger)
631
-
632
- assert.deepEqual(Array.from(result.scheduledTasks.files).sort(), [
633
- '/test/project/src/tasks/reports.ts',
634
- ])
635
- })
636
- })
637
-
638
- describe('Queue worker filtering', () => {
639
- test('should filter queue workers by type', () => {
640
- const state = createMockInspectorState()
641
- const filters: InspectorFilters = {
642
- wires: ['queue'],
643
- }
644
-
645
- const result = filterInspectorState(state, filters, mockLogger)
646
-
647
- assert.equal(Object.keys(result.queueWorkers.meta).length, 2)
648
-
649
- // Other types should be empty
650
- assert.equal(Object.keys(result.http.meta.get).length, 0)
651
- assert.equal(Object.keys(result.channels.meta).length, 0)
652
- })
653
-
654
- test('should filter queue workers by tags', () => {
655
- const state = createMockInspectorState()
656
- const filters: InspectorFilters = {
657
- wires: ['queue'],
658
- tags: ['email'],
659
- }
660
-
661
- const result = filterInspectorState(state, filters, mockLogger)
662
-
663
- assert.equal(Object.keys(result.queueWorkers.meta).length, 1)
664
- assert.ok(result.queueWorkers.meta['email-worker'])
665
- })
666
-
667
- test('should filter queue workers by name', () => {
668
- const state = createMockInspectorState()
669
- const filters: InspectorFilters = {
670
- names: ['email-worker'],
671
- }
672
-
673
- const result = filterInspectorState(state, filters, mockLogger)
674
-
675
- assert.equal(Object.keys(result.queueWorkers.meta).length, 1)
676
- assert.ok(result.queueWorkers.meta['email-worker'])
677
- })
678
-
679
- test('should filter queue workers by name wildcard', () => {
680
- const state = createMockInspectorState()
681
- const filters: InspectorFilters = {
682
- names: ['*-worker'],
683
- }
684
-
685
- const result = filterInspectorState(state, filters, mockLogger)
686
-
687
- assert.equal(Object.keys(result.queueWorkers.meta).length, 2)
688
- })
689
-
690
- test('should repopulate queue worker files from surviving metadata', () => {
691
- const state = createMockInspectorState()
692
- const filters: InspectorFilters = {
693
- wires: ['queue'],
694
- tags: ['email'],
695
- }
696
-
697
- const result = filterInspectorState(state, filters, mockLogger)
698
-
699
- assert.deepEqual(Array.from(result.queueWorkers.files).sort(), [
700
- '/test/project/src/workers/email.ts',
701
- ])
702
- })
703
- })
704
-
705
- describe('MCP endpoint filtering', () => {
706
- test('should filter MCP tools by type', () => {
707
- const state = createMockInspectorState()
708
- const filters: InspectorFilters = {
709
- wires: ['mcp'],
710
- }
711
-
712
- const result = filterInspectorState(state, filters, mockLogger)
713
-
714
- assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 2)
715
- assert.equal(Object.keys(result.mcpEndpoints.resourcesMeta).length, 1)
716
- assert.equal(Object.keys(result.mcpEndpoints.promptsMeta).length, 1)
717
-
718
- // Other types should be empty
719
- assert.equal(Object.keys(result.http.meta.get).length, 0)
720
- })
721
-
722
- test('should filter MCP endpoints by tags', () => {
723
- const state = createMockInspectorState()
724
- const filters: InspectorFilters = {
725
- wires: ['mcp'],
726
- tags: ['search'],
727
- }
728
-
729
- const result = filterInspectorState(state, filters, mockLogger)
730
-
731
- assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 1)
732
- assert.ok(result.mcpEndpoints.toolsMeta['search-tool'])
733
- assert.equal(Object.keys(result.mcpEndpoints.resourcesMeta).length, 0)
734
- })
735
-
736
- test('should filter MCP endpoints by name', () => {
737
- const state = createMockInspectorState()
738
- const filters: InspectorFilters = {
739
- names: ['search-tool'],
740
- }
741
-
742
- const result = filterInspectorState(state, filters, mockLogger)
743
-
744
- assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 1)
745
- assert.ok(result.mcpEndpoints.toolsMeta['search-tool'])
746
- })
747
-
748
- test('should filter MCP endpoints by name wildcard', () => {
749
- const state = createMockInspectorState()
750
- const filters: InspectorFilters = {
751
- names: ['*-tool'],
752
- }
753
-
754
- const result = filterInspectorState(state, filters, mockLogger)
755
-
756
- assert.equal(Object.keys(result.mcpEndpoints.toolsMeta).length, 2)
757
- assert.equal(Object.keys(result.mcpEndpoints.resourcesMeta).length, 0)
758
- assert.equal(Object.keys(result.mcpEndpoints.promptsMeta).length, 0)
759
- })
760
-
761
- test('should repopulate MCP files from surviving metadata', () => {
762
- const state = createMockInspectorState()
763
- const filters: InspectorFilters = {
764
- wires: ['mcp'],
765
- tags: ['search'],
766
- }
767
-
768
- const result = filterInspectorState(state, filters, mockLogger)
769
-
770
- assert.deepEqual(Array.from(result.mcpEndpoints.files).sort(), [
771
- '/test/project/src/mcp/search.ts',
772
- ])
773
- })
774
- })
775
-
776
- describe('CLI filtering', () => {
777
- test('should filter CLI commands by type', () => {
778
- const state = createMockInspectorState()
779
- const filters: InspectorFilters = {
780
- wires: ['cli'],
781
- }
782
-
783
- const result = filterInspectorState(state, filters, mockLogger)
784
-
785
- assert.equal(
786
- Object.keys(result.cli.meta.programs['my-cli'].commands).length,
787
- 2
788
- )
789
-
790
- // Other types should be empty
791
- assert.equal(Object.keys(result.http.meta.get).length, 0)
792
- })
793
-
794
- test('should filter CLI commands by tags', () => {
795
- const state = createMockInspectorState()
796
- const filters: InspectorFilters = {
797
- wires: ['cli'],
798
- tags: ['build'],
799
- }
800
-
801
- const result = filterInspectorState(state, filters, mockLogger)
802
-
803
- assert.equal(
804
- Object.keys(result.cli.meta.programs['my-cli'].commands).length,
805
- 1
806
- )
807
- assert.ok(result.cli.meta.programs['my-cli'].commands['build'])
808
- })
809
-
810
- test('should filter CLI commands by name', () => {
811
- const state = createMockInspectorState()
812
- const filters: InspectorFilters = {
813
- names: ['build'],
814
- }
815
-
816
- const result = filterInspectorState(state, filters, mockLogger)
817
-
818
- assert.equal(
819
- Object.keys(result.cli.meta.programs['my-cli'].commands).length,
820
- 1
821
- )
822
- assert.ok(result.cli.meta.programs['my-cli'].commands['build'])
823
- })
824
-
825
- test('should remove program if all commands are filtered out', () => {
826
- const state = createMockInspectorState()
827
- const filters: InspectorFilters = {
828
- wires: ['cli'],
829
- tags: ['non-existent'],
830
- }
831
-
832
- const result = filterInspectorState(state, filters, mockLogger)
833
-
834
- // Program should be removed
835
- assert.equal(Object.keys(result.cli.meta.programs).length, 0)
836
- })
837
-
838
- test('should repopulate CLI files from surviving metadata', () => {
839
- const state = createMockInspectorState()
840
- const filters: InspectorFilters = {
841
- wires: ['cli'],
842
- tags: ['build'],
843
- }
844
-
845
- const result = filterInspectorState(state, filters, mockLogger)
846
-
847
- assert.deepEqual(Array.from(result.cli.files).sort(), [
848
- '/test/project/src/cli/build.ts',
849
- '/test/project/src/cli/program.ts',
850
- ])
851
- })
852
- })
853
-
854
- describe('Wire exclusion', () => {
855
- test('should exclude queue and scheduler wires while keeping http', () => {
856
- const state = createMockInspectorState()
857
- const filters: InspectorFilters = {
858
- excludeWires: ['queue', 'scheduler'],
859
- }
860
-
861
- const result = filterInspectorState(state, filters, mockLogger)
862
-
863
- assert.equal(Object.keys(result.queueWorkers.meta).length, 0)
864
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
865
- assert.ok(Object.keys(result.http.meta.get).length > 0)
866
- })
867
- })
868
-
869
- describe('Combined filtering', () => {
870
- test('should filter multiple types at once', () => {
871
- const state = createMockInspectorState()
872
- const filters: InspectorFilters = {
873
- wires: ['http', 'channel'],
874
- }
875
-
876
- const result = filterInspectorState(state, filters, mockLogger)
877
-
878
- // HTTP and channels should exist
879
- assert.equal(Object.keys(result.http.meta.get).length, 2)
880
- assert.equal(Object.keys(result.channels.meta).length, 2)
881
-
882
- // Other types should be empty
883
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
884
- assert.equal(Object.keys(result.queueWorkers.meta).length, 0)
885
- })
886
-
887
- test('should filter by tags across all types', () => {
888
- const state = createMockInspectorState()
889
- const filters: InspectorFilters = {
890
- tags: ['admin'],
891
- }
892
-
893
- const result = filterInspectorState(state, filters, mockLogger)
894
-
895
- // Only admin-tagged items should remain
896
- assert.equal(Object.keys(result.http.meta.get).length, 1)
897
- assert.ok(result.http.meta.get['/admin/settings'])
898
- assert.equal(Object.keys(result.channels.meta).length, 1)
899
- assert.ok(result.channels.meta['admin-channel'])
900
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
901
- })
902
-
903
- test('should handle complex combined filters', () => {
904
- const state = createMockInspectorState()
905
- const filters: InspectorFilters = {
906
- wires: ['http'],
907
- tags: ['api'],
908
- httpMethods: ['POST'],
909
- }
910
-
911
- const result = filterInspectorState(state, filters, mockLogger)
912
-
913
- // Only POST /api/users should remain
914
- assert.equal(Object.keys(result.http.meta.get).length, 0)
915
- assert.equal(Object.keys(result.http.meta.post).length, 1)
916
- assert.ok(result.http.meta.post['/api/users'])
917
- })
918
- })
919
-
920
- describe('Service aggregation', () => {
921
- test('should reset and recalculate service aggregation', () => {
922
- const state = createMockInspectorState()
923
-
924
- // Pre-populate with some old data
925
- state.serviceAggregation.usedFunctions.add('oldFunction')
926
- state.serviceAggregation.usedMiddleware.add('oldMiddleware')
927
-
928
- const filters: InspectorFilters = {
929
- wires: ['http'],
930
- tags: ['admin'],
931
- }
932
-
933
- const result = filterInspectorState(state, filters, mockLogger)
934
-
935
- // Old data should be gone, new data should be present
936
- assert.ok(!result.serviceAggregation.usedFunctions.has('oldFunction'))
937
- assert.ok(!result.serviceAggregation.usedMiddleware.has('oldMiddleware'))
938
- assert.ok(result.serviceAggregation.usedFunctions.has('getAdminSettings'))
939
- assert.ok(result.serviceAggregation.usedMiddleware.has('authMiddleware'))
940
- })
941
-
942
- test('should track all used functions across different wiring types', () => {
943
- const state = createMockInspectorState()
944
- const filters: InspectorFilters = {
945
- tags: ['admin'], // Filter for admin-tagged items across all types
946
- }
947
-
948
- const result = filterInspectorState(state, filters, mockLogger)
949
-
950
- // Should include functions from HTTP and channels
951
- assert.ok(result.serviceAggregation.usedFunctions.has('getAdminSettings'))
952
- assert.ok(
953
- result.serviceAggregation.usedFunctions.has('handleAdminMessage')
954
- )
955
- })
956
- })
957
-
958
- describe('State immutability', () => {
959
- test('should not mutate original state when filtering', () => {
960
- const state = createMockInspectorState()
961
- const originalHttpCount = Object.keys(state.http.meta.get).length
962
- const originalChannelCount = Object.keys(state.channels.meta).length
963
-
964
- const filters: InspectorFilters = {
965
- wires: ['http'],
966
- }
967
-
968
- filterInspectorState(state, filters, mockLogger)
969
-
970
- // Original state should not be modified
971
- assert.equal(Object.keys(state.http.meta.get).length, originalHttpCount)
972
- assert.equal(
973
- Object.keys(state.channels.meta).length,
974
- originalChannelCount
975
- )
976
- })
977
-
978
- test('should create deep copies of metadata', () => {
979
- const state = createMockInspectorState()
980
- const filters: InspectorFilters = {
981
- wires: ['http'],
982
- tags: ['api'],
983
- }
984
-
985
- const result = filterInspectorState(state, filters, mockLogger)
986
-
987
- // Modify filtered state
988
- delete result.http.meta.get['/api/users']
989
-
990
- // Original should still have the route
991
- assert.ok(state.http.meta.get['/api/users'])
992
- })
993
- })
994
-
995
- describe('Edge cases', () => {
996
- test('should handle empty state', () => {
997
- const state = createMockInspectorState()
998
- state.http.meta = {
999
- get: {},
1000
- post: {},
1001
- put: {},
1002
- patch: {},
1003
- delete: {},
1004
- head: {},
1005
- options: {},
1006
- }
1007
- state.channels.meta = {}
1008
- state.scheduledTasks.meta = {}
1009
- state.queueWorkers.meta = {}
1010
-
1011
- const filters: InspectorFilters = {
1012
- wires: ['http'],
1013
- }
1014
-
1015
- const result = filterInspectorState(state, filters, mockLogger)
1016
-
1017
- assert.equal(Object.keys(result.http.meta.get).length, 0)
1018
- })
1019
-
1020
- test('should handle filters that match nothing', () => {
1021
- const state = createMockInspectorState()
1022
- const filters: InspectorFilters = {
1023
- tags: ['non-existent-tag'],
1024
- }
1025
-
1026
- const result = filterInspectorState(state, filters, mockLogger)
1027
-
1028
- // Everything should be filtered out
1029
- assert.equal(Object.keys(result.http.meta.get).length, 0)
1030
- assert.equal(Object.keys(result.channels.meta).length, 0)
1031
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
1032
- assert.equal(Object.keys(result.queueWorkers.meta).length, 0)
1033
- })
1034
-
1035
- test('should handle missing optional metadata fields', () => {
1036
- const state = createMockInspectorState()
1037
- // Remove tags from one route
1038
- delete state.http.meta.get['/api/users'].tags
1039
-
1040
- const filters: InspectorFilters = {
1041
- tags: ['api'],
1042
- }
1043
-
1044
- const result = filterInspectorState(state, filters, mockLogger)
1045
-
1046
- // Route without tags should not match
1047
- assert.ok(!result.http.meta.get['/api/users'])
1048
- // Route with tags should match
1049
- assert.ok(result.http.meta.post['/api/users'])
1050
- })
1051
- })
1052
-
1053
- describe('Real data tests (from templates/functions)', () => {
1054
- test('should have loaded real state correctly', () => {
1055
- assert.ok(realState)
1056
- assert.ok(realState.http)
1057
- assert.ok(realState.functions)
1058
- assert.ok(realState.channels)
1059
- assert.ok(realState.scheduledTasks)
1060
- assert.ok(realState.queueWorkers)
1061
- assert.ok(realState.mcpEndpoints)
1062
- assert.ok(realState.cli)
1063
- })
1064
-
1065
- test('should filter HTTP routes by type in real data', () => {
1066
- // BEFORE: Check what we have in the real state
1067
- const beforeHttpCount = Object.values(
1068
- realState.http.meta as Record<string, any>
1069
- ).flatMap((m) => Object.keys(m)).length
1070
- const beforeChannelCount = Object.keys(realState.channels.meta).length
1071
- const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
1072
- const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
1073
-
1074
- assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
1075
- assert.ok(beforeChannelCount > 0, 'Real state should have channels')
1076
- assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
1077
- assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
1078
-
1079
- // FILTER: Apply HTTP type filter
1080
- const filters: InspectorFilters = {
1081
- wires: ['http'],
1082
- }
1083
- const result = filterInspectorState(realState, filters, mockLogger)
1084
-
1085
- // AFTER: Check filtered result
1086
- const afterHttpCount = Object.values(
1087
- result.http.meta as Record<string, any>
1088
- ).flatMap((m) => Object.keys(m)).length
1089
- const afterChannelCount = Object.keys(result.channels.meta).length
1090
- const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
1091
- const afterQueueCount = Object.keys(result.queueWorkers.meta).length
1092
-
1093
- // HTTP routes should remain
1094
- assert.equal(
1095
- afterHttpCount,
1096
- beforeHttpCount,
1097
- 'HTTP routes should be preserved'
1098
- )
1099
-
1100
- // Other types should be filtered out
1101
- assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
1102
- assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
1103
- assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
1104
- })
1105
-
1106
- test('should filter channels by type in real data', () => {
1107
- const filters: InspectorFilters = {
1108
- wires: ['channel'],
1109
- }
1110
-
1111
- const result = filterInspectorState(realState, filters, mockLogger)
1112
-
1113
- // Should have channels
1114
- assert.ok(
1115
- Object.keys(result.channels.meta).length > 0,
1116
- 'Should have channels'
1117
- )
1118
-
1119
- // Other types should be filtered out
1120
- const httpRouteCount = Object.values(result.http.meta).flatMap((m) =>
1121
- Object.keys(m)
1122
- ).length
1123
- assert.equal(httpRouteCount, 0)
1124
- assert.equal(Object.keys(result.scheduledTasks.meta).length, 0)
1125
- assert.equal(Object.keys(result.queueWorkers.meta).length, 0)
1126
- })
1127
-
1128
- test('should filter scheduler tasks by type in real data', () => {
1129
- // BEFORE: Check what we have in the real state
1130
- const beforeHttpCount = Object.values(
1131
- realState.http.meta as Record<string, any>
1132
- ).flatMap((m) => Object.keys(m)).length
1133
- const beforeChannelCount = Object.keys(realState.channels.meta).length
1134
- const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
1135
- const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
1136
-
1137
- assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
1138
- assert.ok(beforeChannelCount > 0, 'Real state should have channels')
1139
- assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
1140
- assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
1141
-
1142
- // FILTER: Apply scheduler type filter
1143
- const filters: InspectorFilters = {
1144
- wires: ['scheduler'],
1145
- }
1146
- const result = filterInspectorState(realState, filters, mockLogger)
1147
-
1148
- // AFTER: Check filtered result
1149
- const afterHttpCount = Object.values(
1150
- result.http.meta as Record<string, any>
1151
- ).flatMap((m) => Object.keys(m)).length
1152
- const afterChannelCount = Object.keys(result.channels.meta).length
1153
- const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
1154
- const afterQueueCount = Object.keys(result.queueWorkers.meta).length
1155
-
1156
- // Scheduled tasks should remain
1157
- assert.equal(
1158
- afterTaskCount,
1159
- beforeTaskCount,
1160
- 'Scheduled tasks should be preserved'
1161
- )
1162
-
1163
- // Other types should be filtered out
1164
- assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
1165
- assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
1166
- assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
1167
- })
1168
-
1169
- test('should filter queue workers by type in real data', () => {
1170
- // BEFORE: Check what we have in the real state
1171
- const beforeHttpCount = Object.values(
1172
- realState.http.meta as Record<string, any>
1173
- ).flatMap((m) => Object.keys(m)).length
1174
- const beforeChannelCount = Object.keys(realState.channels.meta).length
1175
- const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
1176
- const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
1177
-
1178
- assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
1179
- assert.ok(beforeChannelCount > 0, 'Real state should have channels')
1180
- assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
1181
- assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
1182
-
1183
- // FILTER: Apply queue type filter
1184
- const filters: InspectorFilters = {
1185
- wires: ['queue'],
1186
- }
1187
- const result = filterInspectorState(realState, filters, mockLogger)
1188
-
1189
- // AFTER: Check filtered result
1190
- const afterHttpCount = Object.values(
1191
- result.http.meta as Record<string, any>
1192
- ).flatMap((m) => Object.keys(m)).length
1193
- const afterChannelCount = Object.keys(result.channels.meta).length
1194
- const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
1195
- const afterQueueCount = Object.keys(result.queueWorkers.meta).length
1196
-
1197
- // Queue workers should remain
1198
- assert.equal(
1199
- afterQueueCount,
1200
- beforeQueueCount,
1201
- 'Queue workers should be preserved'
1202
- )
1203
-
1204
- // Other types should be filtered out
1205
- assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
1206
- assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
1207
- assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
1208
- })
1209
-
1210
- test('should filter MCP endpoints by type in real data', () => {
1211
- // BEFORE: Check what we have in the real state
1212
- const beforeHttpCount = Object.values(
1213
- realState.http.meta as Record<string, any>
1214
- ).flatMap((m) => Object.keys(m)).length
1215
- const beforeChannelCount = Object.keys(realState.channels.meta).length
1216
- const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
1217
- const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
1218
- const beforeMcpToolsCount = Object.keys(
1219
- realState.mcpEndpoints.toolsMeta
1220
- ).length
1221
- const beforeMcpResourcesCount = Object.keys(
1222
- realState.mcpEndpoints.resourcesMeta
1223
- ).length
1224
- const beforeMcpPromptsCount = Object.keys(
1225
- realState.mcpEndpoints.promptsMeta
1226
- ).length
1227
-
1228
- assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
1229
- assert.ok(beforeChannelCount > 0, 'Real state should have channels')
1230
- assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
1231
- assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
1232
- assert.ok(
1233
- beforeMcpToolsCount + beforeMcpResourcesCount + beforeMcpPromptsCount >
1234
- 0,
1235
- 'Real state should have MCP endpoints'
1236
- )
1237
-
1238
- // FILTER: Apply MCP type filter
1239
- const filters: InspectorFilters = {
1240
- wires: ['mcp'],
1241
- }
1242
- const result = filterInspectorState(realState, filters, mockLogger)
1243
-
1244
- // AFTER: Check filtered result
1245
- const afterHttpCount = Object.values(
1246
- result.http.meta as Record<string, any>
1247
- ).flatMap((m) => Object.keys(m)).length
1248
- const afterChannelCount = Object.keys(result.channels.meta).length
1249
- const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
1250
- const afterQueueCount = Object.keys(result.queueWorkers.meta).length
1251
- const afterMcpToolsCount = Object.keys(
1252
- result.mcpEndpoints.toolsMeta
1253
- ).length
1254
- const afterMcpResourcesCount = Object.keys(
1255
- result.mcpEndpoints.resourcesMeta
1256
- ).length
1257
- const afterMcpPromptsCount = Object.keys(
1258
- result.mcpEndpoints.promptsMeta
1259
- ).length
1260
-
1261
- // MCP endpoints should remain
1262
- assert.equal(
1263
- afterMcpToolsCount,
1264
- beforeMcpToolsCount,
1265
- 'MCP tools should be preserved'
1266
- )
1267
- assert.equal(
1268
- afterMcpResourcesCount,
1269
- beforeMcpResourcesCount,
1270
- 'MCP resources should be preserved'
1271
- )
1272
- assert.equal(
1273
- afterMcpPromptsCount,
1274
- beforeMcpPromptsCount,
1275
- 'MCP prompts should be preserved'
1276
- )
1277
-
1278
- // Other types should be filtered out
1279
- assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
1280
- assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
1281
- assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
1282
- assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
1283
- })
1284
-
1285
- test('should filter CLI programs by type in real data', () => {
1286
- // BEFORE: Check what we have in the real state
1287
- const beforeHttpCount = Object.values(
1288
- realState.http.meta as Record<string, any>
1289
- ).flatMap((m) => Object.keys(m)).length
1290
- const beforeChannelCount = Object.keys(realState.channels.meta).length
1291
- const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
1292
- const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
1293
- const beforeCliProgramCount = Object.keys(
1294
- realState.cli.meta.programs
1295
- ).length
1296
-
1297
- assert.ok(beforeHttpCount > 0, 'Real state should have HTTP routes')
1298
- assert.ok(beforeChannelCount > 0, 'Real state should have channels')
1299
- assert.ok(beforeTaskCount > 0, 'Real state should have scheduled tasks')
1300
- assert.ok(beforeQueueCount > 0, 'Real state should have queue workers')
1301
- assert.ok(
1302
- beforeCliProgramCount > 0,
1303
- 'Real state should have CLI programs'
1304
- )
1305
-
1306
- // FILTER: Apply CLI type filter
1307
- const filters: InspectorFilters = {
1308
- wires: ['cli'],
1309
- }
1310
- const result = filterInspectorState(realState, filters, mockLogger)
1311
-
1312
- // AFTER: Check filtered result
1313
- const afterHttpCount = Object.values(
1314
- result.http.meta as Record<string, any>
1315
- ).flatMap((m) => Object.keys(m)).length
1316
- const afterChannelCount = Object.keys(result.channels.meta).length
1317
- const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
1318
- const afterQueueCount = Object.keys(result.queueWorkers.meta).length
1319
- const afterCliProgramCount = Object.keys(result.cli.meta.programs).length
1320
-
1321
- // CLI programs should remain
1322
- assert.equal(
1323
- afterCliProgramCount,
1324
- beforeCliProgramCount,
1325
- 'CLI programs should be preserved'
1326
- )
1327
-
1328
- // Other types should be filtered out
1329
- assert.equal(afterHttpCount, 0, 'HTTP routes should be filtered out')
1330
- assert.equal(afterChannelCount, 0, 'Channels should be filtered out')
1331
- assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
1332
- assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
1333
- })
1334
-
1335
- test('should filter by HTTP method in real data', () => {
1336
- // BEFORE: Check what HTTP methods exist
1337
- const beforeGetCount = Object.keys(realState.http.meta.get || {}).length
1338
- const beforePostCount = Object.keys(realState.http.meta.post || {}).length
1339
- const beforePutCount = Object.keys(realState.http.meta.put || {}).length
1340
- const beforeDeleteCount = Object.keys(
1341
- realState.http.meta.delete || {}
1342
- ).length
1343
-
1344
- assert.ok(
1345
- beforeGetCount + beforePostCount + beforePutCount + beforeDeleteCount >
1346
- 0,
1347
- 'Real state should have HTTP routes'
1348
- )
1349
-
1350
- // FILTER: Apply GET method filter
1351
- const filters: InspectorFilters = {
1352
- wires: ['http'],
1353
- httpMethods: ['GET'],
1354
- }
1355
- const result = filterInspectorState(realState, filters, mockLogger)
1356
-
1357
- // AFTER: Check filtered result
1358
- const afterGetCount = Object.keys(result.http.meta.get || {}).length
1359
- const afterPostCount = Object.keys(result.http.meta.post || {}).length
1360
- const afterPutCount = Object.keys(result.http.meta.put || {}).length
1361
- const afterDeleteCount = Object.keys(result.http.meta.delete || {}).length
1362
-
1363
- // GET routes should remain
1364
- assert.equal(
1365
- afterGetCount,
1366
- beforeGetCount,
1367
- 'GET routes should be preserved'
1368
- )
1369
-
1370
- // Other methods should be filtered out
1371
- assert.equal(afterPostCount, 0, 'POST routes should be filtered out')
1372
- assert.equal(afterPutCount, 0, 'PUT routes should be filtered out')
1373
- assert.equal(afterDeleteCount, 0, 'DELETE routes should be filtered out')
1374
- })
1375
-
1376
- test('should filter by name pattern in real data', () => {
1377
- // BEFORE: Count all endpoints
1378
- const beforeHttpCount = Object.values(
1379
- realState.http.meta as Record<string, any>
1380
- ).flatMap((m) => Object.keys(m)).length
1381
- const beforeChannelCount = Object.keys(realState.channels.meta).length
1382
- const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
1383
- const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
1384
- const beforeTotal =
1385
- beforeHttpCount +
1386
- beforeChannelCount +
1387
- beforeTaskCount +
1388
- beforeQueueCount
1389
-
1390
- assert.ok(beforeTotal > 0, 'Real state should have endpoints')
1391
-
1392
- // FILTER: Apply name pattern filter for functions with "http" in their name
1393
- const filters: InspectorFilters = {
1394
- names: ['*http*'],
1395
- }
1396
- const result = filterInspectorState(realState, filters, mockLogger)
1397
-
1398
- // AFTER: Count all filtered endpoints
1399
- const afterHttpCount = Object.values(
1400
- result.http.meta as Record<string, any>
1401
- ).flatMap((m) => Object.keys(m)).length
1402
- const afterChannelCount = Object.keys(result.channels.meta).length
1403
- const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
1404
- const afterQueueCount = Object.keys(result.queueWorkers.meta).length
1405
- const afterTotal =
1406
- afterHttpCount + afterChannelCount + afterTaskCount + afterQueueCount
1407
-
1408
- // After filtering by name pattern, we should have fewer or equal items
1409
- assert.ok(
1410
- afterTotal <= beforeTotal,
1411
- 'Filtered count should be less than or equal to original'
1412
- )
1413
- })
1414
-
1415
- test('should not mutate real state when filtering', () => {
1416
- const originalHttpCount = Object.values(
1417
- realState.http.meta as Record<string, any>
1418
- ).flatMap((m) => Object.keys(m)).length
1419
- const originalChannelCount = Object.keys(realState.channels.meta).length
1420
-
1421
- const filters: InspectorFilters = {
1422
- wires: ['http'],
1423
- }
1424
-
1425
- filterInspectorState(realState, filters, mockLogger)
1426
-
1427
- // Original should not be modified
1428
- const afterHttpCount = Object.values(
1429
- realState.http.meta as Record<string, any>
1430
- ).flatMap((m) => Object.keys(m)).length
1431
- const afterChannelCount = Object.keys(realState.channels.meta).length
1432
-
1433
- assert.equal(afterHttpCount, originalHttpCount)
1434
- assert.equal(afterChannelCount, originalChannelCount)
1435
- })
1436
-
1437
- test('should aggregate services correctly with real data', () => {
1438
- const filters: InspectorFilters = {
1439
- wires: ['http'],
1440
- }
1441
-
1442
- const result = filterInspectorState(realState, filters, mockLogger)
1443
-
1444
- // Service aggregation should be recalculated
1445
- assert.ok(result.serviceAggregation)
1446
- assert.ok(result.serviceAggregation.usedFunctions instanceof Set)
1447
- assert.ok(result.serviceAggregation.usedMiddleware instanceof Set)
1448
- assert.ok(result.serviceAggregation.usedPermissions instanceof Set)
1449
- assert.ok(result.serviceAggregation.requiredServices instanceof Set)
1450
- })
1451
-
1452
- test('should handle combined filters with real data', () => {
1453
- // BEFORE: Check what we have
1454
- const beforeGetCount = Object.keys(realState.http.meta.get || {}).length
1455
- const beforePostCount = Object.keys(realState.http.meta.post || {}).length
1456
- const beforePutCount = Object.keys(realState.http.meta.put || {}).length
1457
- const beforeChannelCount = Object.keys(realState.channels.meta).length
1458
- const beforeTaskCount = Object.keys(realState.scheduledTasks.meta).length
1459
- const beforeQueueCount = Object.keys(realState.queueWorkers.meta).length
1460
-
1461
- assert.ok(
1462
- beforeGetCount + beforePostCount > 0,
1463
- 'Real state should have GET/POST routes'
1464
- )
1465
- assert.ok(beforeChannelCount > 0, 'Real state should have channels')
1466
-
1467
- // FILTER: Apply combined filters (HTTP and channels, GET/POST methods only)
1468
- const filters: InspectorFilters = {
1469
- wires: ['http', 'channel'],
1470
- httpMethods: ['GET', 'POST'],
1471
- }
1472
- const result = filterInspectorState(realState, filters, mockLogger)
1473
-
1474
- // AFTER: Check filtered result
1475
- const afterGetCount = Object.keys(result.http.meta.get || {}).length
1476
- const afterPostCount = Object.keys(result.http.meta.post || {}).length
1477
- const afterPutCount = Object.keys(result.http.meta.put || {}).length
1478
- const afterChannelCount = Object.keys(result.channels.meta).length
1479
- const afterTaskCount = Object.keys(result.scheduledTasks.meta).length
1480
- const afterQueueCount = Object.keys(result.queueWorkers.meta).length
1481
-
1482
- // GET and POST routes should be preserved
1483
- assert.equal(
1484
- afterGetCount,
1485
- beforeGetCount,
1486
- 'GET routes should be preserved'
1487
- )
1488
- assert.equal(
1489
- afterPostCount,
1490
- beforePostCount,
1491
- 'POST routes should be preserved'
1492
- )
1493
-
1494
- // Channels should be preserved (no HTTP method filter applies)
1495
- assert.equal(
1496
- afterChannelCount,
1497
- beforeChannelCount,
1498
- 'Channels should be preserved'
1499
- )
1500
-
1501
- // Other methods/types should be filtered out
1502
- assert.equal(afterPutCount, 0, 'PUT routes should be filtered out')
1503
- assert.equal(afterTaskCount, 0, 'Scheduled tasks should be filtered out')
1504
- assert.equal(afterQueueCount, 0, 'Queue workers should be filtered out')
1505
- })
1506
- })
1507
- })
1508
-
1509
- describe('filterInspectorState exclude filters', () => {
1510
- test('exclude tags removes matching entries after include', () => {
1511
- const state = createMockInspectorState()
1512
- const filters: InspectorFilters = {
1513
- tags: ['api', 'admin'],
1514
- excludeTags: ['admin'],
1515
- }
1516
-
1517
- const result = filterInspectorState(state, filters, mockLogger)
1518
-
1519
- assert.ok(result.http.meta.get['/api/users'])
1520
- assert.ok(result.http.meta.post['/api/users'])
1521
- assert.ok(!result.http.meta.get['/admin/settings'])
1522
- })
1523
-
1524
- test('exclude names wins over broad names include', () => {
1525
- const state = createMockInspectorState()
1526
- const filters: InspectorFilters = {
1527
- names: ['*'],
1528
- excludeNames: ['getAdminSettings'],
1529
- }
1530
-
1531
- const result = filterInspectorState(state, filters, mockLogger)
1532
-
1533
- assert.ok(result.http.meta.get['/api/users'])
1534
- assert.ok(result.http.meta.post['/api/users'])
1535
- assert.ok(!result.http.meta.get['/admin/settings'])
1536
- })
1537
-
1538
- test('exclude target prunes server target while keeping serverless', () => {
1539
- const state = createMockInspectorState()
1540
- ;(state.functions.meta as any).getAdminSettings.deploy = 'server'
1541
- ;(state.functions.meta as any).createUser.deploy = 'serverless'
1542
-
1543
- const filters: InspectorFilters = {
1544
- target: ['server', 'serverless'],
1545
- excludeTarget: ['server'],
1546
- }
1547
-
1548
- const result = filterInspectorState(state, filters, mockLogger)
1549
-
1550
- assert.ok(result.http.meta.post['/api/users'])
1551
- assert.ok(!result.http.meta.get['/admin/settings'])
1552
- })
1553
- })
1554
-
1555
- describe('addonServerlessIncompatible scoping', () => {
1556
- // Service names inside addons are scoped to that addon's namespace.
1557
- // 'FfmpegService' in addon A is unrelated to 'FfmpegService' in the app or
1558
- // another addon. The state.addonServerlessIncompatible map must NOT be
1559
- // merged into the global filter — it is intentionally kept separate.
1560
-
1561
- test('addon serverlessIncompatible does not bleed into app-level function resolution', () => {
1562
- const state = createMockInspectorState()
1563
-
1564
- // App function uses a service named 'FfmpegService' (e.g. its own service,
1565
- // unrelated to any addon's FfmpegService).
1566
- ;(state.functions.meta as any).getUsers.services = {
1567
- services: ['FfmpegService'],
1568
- }
1569
-
1570
- // An addon declares FfmpegService as serverless-incompatible for ITS namespace.
1571
- ;(state as any).addonServerlessIncompatible = new Map([
1572
- ['ffmpeg', ['FfmpegService']],
1573
- ])
1574
-
1575
- // Filter: only keep serverless functions. The filters object does NOT
1576
- // include serverlessIncompatible — that's app-level config only.
1577
- const filters: InspectorFilters = {
1578
- target: ['serverless'],
1579
- }
1580
-
1581
- const result = filterInspectorState(state, filters, mockLogger)
1582
-
1583
- // The app's getUsers function must survive — the addon's scoped
1584
- // serverlessIncompatible should have no effect on app-level resolution.
1585
- assert.ok(
1586
- result.http.meta.get['/api/users'],
1587
- 'app function using same-named service as addon should not be pruned by addon scoping'
1588
- )
1589
- })
1590
-
1591
- test('app-level serverlessIncompatible in filters still prunes matching app functions', () => {
1592
- const state = createMockInspectorState()
1593
-
1594
- ;(state.functions.meta as any).getUsers.services = {
1595
- services: ['HeavyService'],
1596
- }
1597
- ;(state as any).addonServerlessIncompatible = new Map([
1598
- ['some-addon', ['HeavyService']],
1599
- ])
1600
-
1601
- // The APP explicitly declares HeavyService incompatible via filters.
1602
- const filters: InspectorFilters = {
1603
- target: ['serverless'],
1604
- serverlessIncompatible: ['HeavyService'],
1605
- }
1606
-
1607
- const result = filterInspectorState(state, filters, mockLogger)
1608
-
1609
- // App explicitly opted in via filters.serverlessIncompatible → pruned.
1610
- assert.ok(
1611
- !result.http.meta.get['/api/users'],
1612
- 'app function should be pruned when app explicitly lists service in filters.serverlessIncompatible'
1613
- )
1614
- })
1615
- })
1616
-
1617
- describe("an addon's own deploy conflict is the consumer's only when used", () => {
1618
- // An addon publishes metadata for everything it exports. A function it marks
1619
- // `deploy: 'serverless'` while also naming one of its services
1620
- // serverless-incompatible is the addon author's contradiction — but the
1621
- // deploy scan walks every published function, so without care it fails the
1622
- // build of a consumer that never wires that function.
1623
- const withConflictingAddonFunction = (route?: string) => {
1624
- const state = createMockInspectorState()
1625
- ;(state as any).addonFunctions = {
1626
- ffmpeg: {
1627
- transcode: {
1628
- deploy: 'serverless',
1629
- services: { services: ['FfmpegService'] },
1630
- },
1631
- },
1632
- }
1633
- state.addonServerlessIncompatible = new Map([['ffmpeg', ['FfmpegService']]])
1634
- if (route) {
1635
- ;(state.http.meta.get as any)[route] = {
1636
- pikkuFuncId: 'ffmpeg:transcode',
1637
- route,
1638
- method: 'GET',
1639
- tags: [],
1640
- middleware: [],
1641
- permissions: [],
1642
- }
1643
- }
1644
- return state
1645
- }
1646
-
1647
- test('a conflicting addon function nothing wires does not fail the build', () => {
1648
- const state = withConflictingAddonFunction()
1649
-
1650
- assert.doesNotThrow(() =>
1651
- filterInspectorState(state, { target: ['serverless'] }, mockLogger)
1652
- )
1653
- })
1654
-
1655
- test('wiring that same function reports the conflict', () => {
1656
- const state = withConflictingAddonFunction('/transcode')
1657
-
1658
- assert.throws(
1659
- () => filterInspectorState(state, { target: ['serverless'] }, mockLogger),
1660
- /FfmpegService/
1661
- )
1662
- })
1663
- })
1664
-
1665
- describe('addonServerlessIncompatible serialization roundtrip', () => {
1666
- // Uses getInitialInspectorState to guarantee all Map fields are initialized —
1667
- // the lightweight mock in createMockInspectorState() omits fields like
1668
- // schemaLookup that serializeInspectorState needs.
1669
-
1670
- test('Map serializes to Array<[string, string[]]> and back', () => {
1671
- const state = getInitialInspectorState('/test')
1672
- state.addonServerlessIncompatible = new Map([
1673
- ['ffmpeg', ['FfmpegService', 'FfprobeService']],
1674
- ['humandesign', ['HumanDesignService']],
1675
- ])
1676
-
1677
- const serialized = serializeInspectorState(state)
1678
- assert.deepStrictEqual(serialized.addonServerlessIncompatible, [
1679
- ['ffmpeg', ['FfmpegService', 'FfprobeService']],
1680
- ['humandesign', ['HumanDesignService']],
1681
- ])
1682
-
1683
- const restored = deserializeInspectorState(serialized)
1684
- assert.ok(restored.addonServerlessIncompatible instanceof Map)
1685
- assert.deepStrictEqual(restored.addonServerlessIncompatible.get('ffmpeg'), [
1686
- 'FfmpegService',
1687
- 'FfprobeService',
1688
- ])
1689
- assert.deepStrictEqual(
1690
- restored.addonServerlessIncompatible.get('humandesign'),
1691
- ['HumanDesignService']
1692
- )
1693
- })
1694
-
1695
- test('empty Map serializes and restores correctly', () => {
1696
- const state = getInitialInspectorState('/test')
1697
- // addonServerlessIncompatible is already an empty Map from getInitialInspectorState
1698
-
1699
- const serialized = serializeInspectorState(state)
1700
- assert.deepStrictEqual(serialized.addonServerlessIncompatible, [])
1701
-
1702
- const restored = deserializeInspectorState(serialized)
1703
- assert.ok(restored.addonServerlessIncompatible instanceof Map)
1704
- assert.strictEqual(restored.addonServerlessIncompatible.size, 0)
1705
- })
1706
- })
1707
-
1708
- describe('addon bootstrap tree-shake', () => {
1709
- const withAddon = (
1710
- mutate?: (state: Omit<InspectorState, 'typesLookup'>) => void
1711
- ) => {
1712
- const state = createMockInspectorState()
1713
- state.rpc.wireAddonDeclarations = new Map([
1714
- ['console', { package: '@pikku/addon-console' }],
1715
- ])
1716
- state.rpc.usedAddons = new Set(['console'])
1717
- state.rpc.invokedFunctions = new Set(['console:streamWorkflowRun'])
1718
- mutate?.(state)
1719
- return state
1720
- }
1721
-
1722
- test('drops an addon nothing kept references', () => {
1723
- const state = withAddon()
1724
- const filtered = filterInspectorState(
1725
- state,
1726
- { names: ['getUsers'] },
1727
- mockLogger
1728
- )
1729
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 0)
1730
- assert.strictEqual(filtered.rpc.usedAddons.size, 0)
1731
- })
1732
-
1733
- test('keeps an addon when a kept wiring targets one of its functions', () => {
1734
- const state = withAddon((s) => {
1735
- s.http.meta.get['/console/stream'] = {
1736
- pikkuFuncId: 'console:streamWorkflowRun',
1737
- route: '/console/stream',
1738
- method: 'GET',
1739
- tags: [],
1740
- middleware: [],
1741
- permissions: [],
1742
- } as any
1743
- })
1744
- const filtered = filterInspectorState(
1745
- state,
1746
- { names: ['console:streamWorkflowRun'] },
1747
- mockLogger
1748
- )
1749
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1750
- assert.ok(filtered.rpc.wireAddonDeclarations.has('console'))
1751
- })
1752
-
1753
- test('keeps an addon when a kept route ref()-targets one of its functions', () => {
1754
- const state = withAddon((s) => {
1755
- s.http.meta.get['/workflow-run/stream'] = {
1756
- pikkuFuncId: 'console:streamWorkflowRun',
1757
- packageName: '@pikku/console',
1758
- route: '/workflow-run/stream',
1759
- method: 'GET',
1760
- tags: ['stream'],
1761
- middleware: [],
1762
- permissions: [],
1763
- } as any
1764
- })
1765
- const filtered = filterInspectorState(
1766
- state,
1767
- { tags: ['stream'] },
1768
- mockLogger
1769
- )
1770
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1771
- assert.ok(filtered.rpc.wireAddonDeclarations.has('console'))
1772
- assert.ok(
1773
- filtered.serviceAggregation.usedFunctions.has('console:streamWorkflowRun')
1774
- )
1775
- })
1776
-
1777
- test('keeps a ref()-wired route selected by its wiring id', () => {
1778
- const state = withAddon((s) => {
1779
- s.http.meta.get['/workflow-run/stream'] = {
1780
- pikkuFuncId: 'console:streamWorkflowRun',
1781
- packageName: '@pikku/console',
1782
- route: '/workflow-run/stream',
1783
- method: 'GET',
1784
- tags: [],
1785
- middleware: [],
1786
- permissions: [],
1787
- } as any
1788
- })
1789
- const filtered = filterInspectorState(
1790
- state,
1791
- { names: ['http:get:/workflow-run/stream'] },
1792
- mockLogger
1793
- )
1794
- assert.ok(filtered.http.meta.get['/workflow-run/stream'])
1795
- assert.ok(
1796
- filtered.serviceAggregation.usedFunctions.has('console:streamWorkflowRun')
1797
- )
1798
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1799
- assert.ok(filtered.rpc.wireAddonDeclarations.has('console'))
1800
- })
1801
-
1802
- test('drops the addon when the ref()-wired route is filtered out', () => {
1803
- const state = withAddon((s) => {
1804
- s.http.meta.get['/workflow-run/stream'] = {
1805
- pikkuFuncId: 'console:streamWorkflowRun',
1806
- packageName: '@pikku/console',
1807
- route: '/workflow-run/stream',
1808
- method: 'GET',
1809
- tags: [],
1810
- middleware: [],
1811
- permissions: [],
1812
- } as any
1813
- })
1814
- const filtered = filterInspectorState(
1815
- state,
1816
- { names: ['getUsers'] },
1817
- mockLogger
1818
- )
1819
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 0)
1820
- assert.ok(
1821
- !filtered.serviceAggregation.usedFunctions.has(
1822
- 'console:streamWorkflowRun'
1823
- )
1824
- )
1825
- })
1826
-
1827
- test('keeps an addon when a kept MCP tool targets one of its functions', () => {
1828
- const state = withAddon((s) => {
1829
- s.mcpEndpoints.toolsMeta['console:getSchema'] = {
1830
- name: 'console:getSchema',
1831
- description: 'addon tool',
1832
- pikkuFuncId: 'console:getSchema',
1833
- tags: [],
1834
- middleware: [],
1835
- permissions: [],
1836
- } as any
1837
- })
1838
- const filtered = filterInspectorState(
1839
- state,
1840
- { names: ['console:getSchema'] },
1841
- mockLogger
1842
- )
1843
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1844
- })
1845
-
1846
- test('keeps an addon when a kept agent lists one of its functions as a tool', () => {
1847
- const state = withAddon((s) => {
1848
- s.agents = s.agents ?? ({ agentsMeta: {} } as any)
1849
- s.agents.agentsMeta['support-agent'] = {
1850
- name: 'support-agent',
1851
- pikkuFuncId: 'supportAgent',
1852
- tools: ['console:getSchema'],
1853
- tags: [],
1854
- } as any
1855
- })
1856
- const filtered = filterInspectorState(
1857
- state,
1858
- { names: ['support-agent'] },
1859
- mockLogger
1860
- )
1861
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1862
- })
1863
-
1864
- test('keeps an addon when a kept function body-invokes it', () => {
1865
- const state = withAddon((s) => {
1866
- s.rpc.invokedFunctionsByFile = new Map([
1867
- ['/test/project/src/api/users.ts', new Set(['console:getSchema'])],
1868
- ])
1869
- })
1870
- const filtered = filterInspectorState(
1871
- state,
1872
- { names: ['getUsers'] },
1873
- mockLogger
1874
- )
1875
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1876
- })
1877
-
1878
- test('a kept-file body invoke joins the filtered usedFunctions', () => {
1879
- const state = withAddon((s) => {
1880
- s.rpc.invokedFunctionsByFile = new Map([
1881
- ['/test/project/src/api/users.ts', new Set(['console:getSchema'])],
1882
- ])
1883
- })
1884
- const filtered = filterInspectorState(
1885
- state,
1886
- { names: ['getUsers'] },
1887
- mockLogger
1888
- )
1889
- assert.ok(
1890
- filtered.serviceAggregation.usedFunctions.has('console:getSchema')
1891
- )
1892
- })
1893
-
1894
- test('drops an addon body-invoked only from filtered-out files', () => {
1895
- const state = withAddon((s) => {
1896
- s.rpc.invokedFunctionsByFile = new Map([
1897
- ['/test/project/src/admin/settings.ts', new Set(['console:getSchema'])],
1898
- ])
1899
- })
1900
- const filtered = filterInspectorState(
1901
- state,
1902
- { names: ['getUsers'] },
1903
- mockLogger
1904
- )
1905
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 0)
1906
- })
1907
-
1908
- test('unfiltered state keeps all addons', () => {
1909
- const state = withAddon()
1910
- const filtered = filterInspectorState(state, {}, mockLogger)
1911
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1912
- })
1913
-
1914
- const withRefWiredAddonRoute = (
1915
- addonFuncMeta: Record<string, unknown> = { services: [], optimized: false }
1916
- ) =>
1917
- withAddon((s) => {
1918
- s.http.meta.get['/workflow-run/stream'] = {
1919
- pikkuFuncId: 'console:streamWorkflowRun',
1920
- packageName: '@pikku/addon-console',
1921
- route: '/workflow-run/stream',
1922
- method: 'GET',
1923
- tags: [],
1924
- middleware: [],
1925
- permissions: [],
1926
- } as any
1927
- s.addonFunctions = {
1928
- console: { streamWorkflowRun: addonFuncMeta as any },
1929
- }
1930
- })
1931
-
1932
- test('the deploy filter keeps a ref()-wired route onto a serverless addon function', () => {
1933
- const filtered = filterInspectorState(
1934
- withRefWiredAddonRoute(),
1935
- { target: ['serverless'] },
1936
- mockLogger
1937
- )
1938
- assert.ok(filtered.http.meta.get['/workflow-run/stream'])
1939
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 1)
1940
- assert.ok(filtered.rpc.wireAddonDeclarations.has('console'))
1941
- })
1942
-
1943
- test('the deploy filter drops a ref()-wired route onto a server-only addon function', () => {
1944
- const filtered = filterInspectorState(
1945
- withRefWiredAddonRoute({
1946
- services: [],
1947
- optimized: false,
1948
- deploy: 'server',
1949
- }),
1950
- { target: ['serverless'] },
1951
- mockLogger
1952
- )
1953
- assert.ok(!filtered.http.meta.get['/workflow-run/stream'])
1954
- assert.strictEqual(filtered.rpc.wireAddonDeclarations.size, 0)
1955
- })
1956
-
1957
- test("the deploy filter honours the addon's own serverlessIncompatible services", () => {
1958
- const state = withRefWiredAddonRoute({
1959
- services: { services: ['FfmpegService'] },
1960
- optimized: false,
1961
- })
1962
- state.addonServerlessIncompatible = new Map([
1963
- ['console', ['FfmpegService']],
1964
- ])
1965
- const filtered = filterInspectorState(
1966
- state,
1967
- { target: ['serverless'] },
1968
- mockLogger
1969
- )
1970
- assert.ok(!filtered.http.meta.get['/workflow-run/stream'])
1971
- })
1972
- })
1973
-
1974
- describe('invokedFunctionsByFile serialization', () => {
1975
- test('round-trips through serialize/deserialize', () => {
1976
- const state = getInitialInspectorState('/test/project')
1977
- state.rpc.invokedFunctionsByFile = new Map([
1978
- ['/test/project/src/api/users.ts', new Set(['console:getSchema'])],
1979
- [
1980
- '/test/project/src/api/tasks.ts',
1981
- new Set(['listTasks', 'console:runAgent']),
1982
- ],
1983
- ])
1984
- const restored = deserializeInspectorState(
1985
- JSON.parse(JSON.stringify(serializeInspectorState(state as any)))
1986
- )
1987
- assert.ok(restored.rpc.invokedFunctionsByFile instanceof Map)
1988
- assert.strictEqual(restored.rpc.invokedFunctionsByFile.size, 2)
1989
- assert.deepStrictEqual(
1990
- [
1991
- ...restored.rpc.invokedFunctionsByFile.get(
1992
- '/test/project/src/api/tasks.ts'
1993
- )!,
1994
- ].sort(),
1995
- ['console:runAgent', 'listTasks']
1996
- )
1997
- })
1998
-
1999
- test('deserializing legacy state without the field yields an empty Map', () => {
2000
- const serialized = JSON.parse(
2001
- JSON.stringify(
2002
- serializeInspectorState(
2003
- getInitialInspectorState('/test/project') as any
2004
- )
2005
- )
2006
- )
2007
- delete serialized.rpc.invokedFunctionsByFile
2008
- const restored = deserializeInspectorState(serialized)
2009
- assert.ok(restored.rpc.invokedFunctionsByFile instanceof Map)
2010
- assert.strictEqual(restored.rpc.invokedFunctionsByFile.size, 0)
2011
- })
2012
- })
2013
-
2014
- describe('Workflow file pruning', () => {
2015
- const workflowState = () => {
2016
- const state = createMockInspectorState()
2017
- state.workflows.meta = {
2018
- moveOut: { pikkuFuncId: 'getUsers' } as any,
2019
- theMoveOutScenario: { pikkuFuncId: 'createUser' } as any,
2020
- }
2021
- state.workflows.graphMeta = {
2022
- moveOut: { pikkuFuncId: 'getUsers' } as any,
2023
- theMoveOutScenario: {
2024
- pikkuFuncId: 'createUser',
2025
- source: 'scenario',
2026
- } as any,
2027
- }
2028
- state.workflows.files = new Map([
2029
- [
2030
- 'moveOut',
2031
- {
2032
- path: '/test/project/src/wirings/move-out.workflow.ts',
2033
- exportedName: 'moveOut',
2034
- },
2035
- ],
2036
- [
2037
- 'theMoveOutScenario',
2038
- {
2039
- path: '/test/project/test/scenarios/the-move-out.scenario.ts',
2040
- exportedName: 'theMoveOutScenario',
2041
- },
2042
- ],
2043
- ])
2044
- return state
2045
- }
2046
-
2047
- test('drops the file entry of a pruned workflow', () => {
2048
- const result = filterInspectorState(
2049
- workflowState(),
2050
- { names: ['getUsers'] },
2051
- mockLogger
2052
- )
2053
-
2054
- assert.deepEqual(Object.keys(result.workflows.graphMeta), ['moveOut'])
2055
- assert.deepEqual([...result.workflows.files.keys()], ['moveOut'])
2056
- })
2057
-
2058
- test('leaves the original state untouched', () => {
2059
- const state = workflowState()
2060
- filterInspectorState(state, { names: ['getUsers'] }, mockLogger)
2061
-
2062
- assert.equal(state.workflows.files.size, 2)
2063
- assert.equal(Object.keys(state.workflows.graphMeta).length, 2)
2064
- })
2065
- })
2066
-
2067
- describe('invokedAgentsByFile', () => {
2068
- test('round-trips through serialize/deserialize', () => {
2069
- const state = getInitialInspectorState('/test/project')
2070
- state.agents.invokedAgentsByFile = new Map([
2071
- ['/test/project/src/api/users.ts', new Set(['houseAssistant'])],
2072
- [
2073
- '/test/project/src/api/tasks.ts',
2074
- new Set(['houseAssistant', 'gardenAssistant']),
2075
- ],
2076
- ])
2077
- const restored = deserializeInspectorState(
2078
- JSON.parse(JSON.stringify(serializeInspectorState(state as any)))
2079
- )
2080
- assert.ok(restored.agents.invokedAgentsByFile instanceof Map)
2081
- assert.strictEqual(restored.agents.invokedAgentsByFile.size, 2)
2082
- assert.deepStrictEqual(
2083
- [
2084
- ...restored.agents.invokedAgentsByFile.get(
2085
- '/test/project/src/api/tasks.ts'
2086
- )!,
2087
- ].sort(),
2088
- ['gardenAssistant', 'houseAssistant']
2089
- )
2090
- })
2091
-
2092
- test('deserializing legacy state without the field yields an empty Map', () => {
2093
- const serialized = JSON.parse(
2094
- JSON.stringify(
2095
- serializeInspectorState(
2096
- getInitialInspectorState('/test/project') as any
2097
- )
2098
- )
2099
- )
2100
- delete serialized.agents.invokedAgentsByFile
2101
- const restored = deserializeInspectorState(serialized)
2102
- assert.ok(restored.agents.invokedAgentsByFile instanceof Map)
2103
- assert.strictEqual(restored.agents.invokedAgentsByFile.size, 0)
2104
- })
2105
-
2106
- test('the filtered map is a clone, not the original', () => {
2107
- const state = createMockInspectorState()
2108
- state.agents = {
2109
- agentsMeta: {},
2110
- files: new Map(),
2111
- invokedAgentsByFile: new Map([
2112
- ['/test/project/src/api/users.ts', new Set(['houseAssistant'])],
2113
- ]),
2114
- }
2115
- const filtered = filterInspectorState(
2116
- state,
2117
- { names: ['getUsers'] },
2118
- mockLogger
2119
- )
2120
- filtered.agents.invokedAgentsByFile.clear()
2121
- assert.strictEqual(state.agents.invokedAgentsByFile.size, 1)
2122
- })
2123
-
2124
- test('keeps the entry of a kept function file and prunes the rest', () => {
2125
- const state = createMockInspectorState()
2126
- state.agents = {
2127
- agentsMeta: {},
2128
- files: new Map(),
2129
- invokedAgentsByFile: new Map([
2130
- ['/test/project/src/api/users.ts', new Set(['houseAssistant'])],
2131
- ['/test/project/src/admin/settings.ts', new Set(['adminAssistant'])],
2132
- ]),
2133
- }
2134
- const filtered = filterInspectorState(
2135
- state,
2136
- { names: ['getUsers'] },
2137
- mockLogger
2138
- )
2139
- assert.deepStrictEqual(
2140
- [...filtered.agents.invokedAgentsByFile.keys()],
2141
- ['/test/project/src/api/users.ts']
2142
- )
2143
- })
2144
-
2145
- describe('Wired addon retention', () => {
2146
- const withAddons = () => {
2147
- const state = createMockInspectorState()
2148
- state.rpc.wireAddonDeclarations = new Map([
2149
- ['admin', { package: '@pikku/addon-admin' } as any],
2150
- ['console', { package: '@pikku/addon-console' } as any],
2151
- ])
2152
- state.rpc.usedAddons = new Set(['admin', 'console'])
2153
- return state
2154
- }
2155
-
2156
- test('keeps only the addon whose function the unit is built for', () => {
2157
- const result = filterInspectorState(
2158
- withAddons(),
2159
- {
2160
- names: [
2161
- 'console:runSecurityAudit',
2162
- '/rpc/:rpcName',
2163
- 'http:post:/rpc/:rpcName',
2164
- 'rpcCaller',
2165
- ],
2166
- },
2167
- mockLogger
2168
- )
2169
- assert.deepStrictEqual(
2170
- [...result.rpc.wireAddonDeclarations.keys()],
2171
- ['console']
2172
- )
2173
- assert.deepStrictEqual([...result.rpc.usedAddons], ['console'])
2174
- })
2175
-
2176
- test('drops every wired addon for a unit serving the catch-all', () => {
2177
- const result = filterInspectorState(
2178
- withAddons(),
2179
- {
2180
- names: ['/rpc/:rpcName', 'http:post:/rpc/:rpcName', 'rpcCaller'],
2181
- },
2182
- mockLogger
2183
- )
2184
- assert.deepStrictEqual([...result.rpc.wireAddonDeclarations.keys()], [])
2185
- assert.deepStrictEqual([...result.rpc.usedAddons], [])
2186
- })
2187
-
2188
- test('drops wired addons for a unit given the scaffold names', () => {
2189
- const result = filterInspectorState(
2190
- withAddons(),
2191
- {
2192
- names: [
2193
- 'addRetreatPerson',
2194
- '/rpc/:rpcName',
2195
- 'http:post:/rpc/:rpcName',
2196
- 'rpcCaller',
2197
- ],
2198
- },
2199
- mockLogger
2200
- )
2201
- assert.deepStrictEqual([...result.rpc.wireAddonDeclarations.keys()], [])
2202
- assert.deepStrictEqual([...result.rpc.usedAddons], [])
2203
- })
2204
-
2205
- test('drops wired addons for a unit without the catch-all that references no namespace', () => {
2206
- const result = filterInspectorState(
2207
- withAddons(),
2208
- { names: ['getUsers'] },
2209
- mockLogger
2210
- )
2211
- assert.deepStrictEqual([...result.rpc.wireAddonDeclarations.keys()], [])
2212
- assert.deepStrictEqual([...result.rpc.usedAddons], [])
2213
- })
2214
-
2215
- test('still keeps an addon a surviving function statically references, without the catch-all', () => {
2216
- const state = withAddons()
2217
- state.serviceAggregation.usedFunctions.add('getUsers')
2218
- state.rpc.invokedFunctionsByFile = new Map([
2219
- ['/test/project/src/api/users.ts', new Set(['admin:createUser'])],
2220
- ])
2221
- const result = filterInspectorState(
2222
- state,
2223
- { names: ['getUsers'] },
2224
- mockLogger
2225
- )
2226
- assert.deepStrictEqual(
2227
- [...result.rpc.wireAddonDeclarations.keys()],
2228
- ['admin']
2229
- )
2230
- })
2231
- })
2232
- })