@pikku/inspector 0.12.103 → 0.12.107

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 (74) hide show
  1. package/dist/add/add-auth.d.ts +1 -9
  2. package/dist/add/add-auth.js +64 -17
  3. package/dist/add/add-cli.js +25 -11
  4. package/dist/add/add-functions.js +35 -39
  5. package/dist/add/add-keyed-wiring.js +22 -2
  6. package/dist/add/add-middleware.js +17 -16
  7. package/dist/add/add-permission.d.ts +0 -3
  8. package/dist/add/add-permission.js +213 -22
  9. package/dist/add/add-scope.d.ts +1 -7
  10. package/dist/add/add-scope.js +1 -21
  11. package/dist/add/add-virtual-users.d.ts +13 -0
  12. package/dist/add/{add-personas.js → add-virtual-users.js} +33 -33
  13. package/dist/add/add-workflow.js +14 -10
  14. package/dist/add/check-indirect-registrations.d.ts +9 -0
  15. package/dist/add/check-indirect-registrations.js +114 -0
  16. package/dist/error-codes.d.ts +5 -3
  17. package/dist/error-codes.js +5 -3
  18. package/dist/finalize.d.ts +10 -0
  19. package/dist/finalize.js +102 -0
  20. package/dist/index.d.ts +8 -6
  21. package/dist/index.js +6 -5
  22. package/dist/initial-state.d.ts +7 -0
  23. package/dist/initial-state.js +216 -0
  24. package/dist/inspector.d.ts +6 -4
  25. package/dist/inspector.js +28 -300
  26. package/dist/lite.d.ts +26 -0
  27. package/dist/lite.js +25 -0
  28. package/dist/source-file-cache.d.ts +11 -0
  29. package/dist/source-file-cache.js +34 -10
  30. package/dist/types-map.js +2 -1
  31. package/dist/types.d.ts +35 -3
  32. package/dist/utils/apply-declared-scopes.d.ts +8 -0
  33. package/dist/utils/apply-declared-scopes.js +21 -0
  34. package/dist/utils/canonical-type-string.d.ts +14 -0
  35. package/dist/utils/canonical-type-string.js +162 -0
  36. package/dist/utils/context-based-id.d.ts +7 -0
  37. package/dist/utils/context-based-id.js +9 -0
  38. package/dist/utils/custom-types-generator.d.ts +15 -1
  39. package/dist/utils/custom-types-generator.js +17 -5
  40. package/dist/utils/ensure-function-metadata.d.ts +0 -14
  41. package/dist/utils/ensure-function-metadata.js +4 -1
  42. package/dist/utils/extract-function-name.d.ts +1 -1
  43. package/dist/utils/extract-function-name.js +2 -4
  44. package/dist/utils/filter-inspector-state.js +31 -1
  45. package/dist/utils/get-property-value.d.ts +5 -0
  46. package/dist/utils/get-property-value.js +15 -1
  47. package/dist/utils/inspector-constants.d.ts +16 -0
  48. package/dist/utils/inspector-constants.js +16 -0
  49. package/dist/utils/load-addon-functions-meta.js +1 -0
  50. package/dist/utils/post-process.d.ts +35 -36
  51. package/dist/utils/post-process.js +218 -193
  52. package/dist/utils/resolve-callee-name.d.ts +27 -0
  53. package/dist/utils/resolve-callee-name.js +147 -0
  54. package/dist/utils/resolve-service-types.d.ts +8 -0
  55. package/dist/utils/resolve-service-types.js +21 -0
  56. package/dist/utils/schema-generator.js +29 -2
  57. package/dist/utils/serialize-inspector-state.d.ts +9 -3
  58. package/dist/utils/serialize-inspector-state.js +22 -7
  59. package/dist/utils/single-declaration.d.ts +3 -3
  60. package/dist/utils/single-declaration.js +3 -3
  61. package/dist/utils/validate-single-step-workflows.d.ts +3 -0
  62. package/dist/utils/validate-single-step-workflows.js +32 -0
  63. package/dist/utils/workflow/dsl/extract-dsl-workflow.js +3 -3
  64. package/dist/utils/workflow/dsl/patterns.d.ts +4 -11
  65. package/dist/utils/workflow/dsl/patterns.js +5 -11
  66. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +6 -6
  67. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +5 -5
  68. package/dist/visit.js +4 -2
  69. package/package.json +25 -9
  70. package/CHANGELOG.md +0 -4318
  71. package/OPTIMIZATION-PLAN.md +0 -201
  72. package/dist/add/add-personas.d.ts +0 -13
  73. package/run-tests.sh +0 -68
  74. package/src/utils/test-data/inspector-state.json +0 -1687
@@ -1,201 +0,0 @@
1
- # Inspector Package Optimization Plan
2
-
3
- ## Context
4
-
5
- The inspector (`packages/inspector/src/`) is a static code analyzer built on TypeScript's compiler API. It extracts metadata from source files via a two-pass AST visitor pattern (setup + routes). Profiling reveals that for **every AST node**, all handlers are called sequentially (10 in setup, 16 in routes) even though only 1 ever matches. This creates millions of wasted function calls on large codebases.
6
-
7
- The inspector already has `performance.now()` instrumentation for 7 phases. We'll use this to measure each optimization independently.
8
-
9
- ---
10
-
11
- ## Step 0: Create Benchmark Harness
12
-
13
- **Goal:** Establish reproducible baseline measurements.
14
-
15
- **File:** `src/benchmark.ts`
16
-
17
- **What it does:**
18
-
19
- - Collects `.ts` files from a target directory (e.g., the external repo's packages)
20
- - Runs `inspect()` N iterations (default 10) with a warmup run
21
- - Parses existing `logger.debug` messages to capture per-phase timings
22
- - Reports median, mean, min, max for each phase + total
23
- - Outputs JSON for before/after diffing
24
- - Also benchmarks `filterInspectorState()` separately using the test fixture (`src/utils/test-data/inspector-state.json`)
25
- - Adds counters for: total AST nodes visited, CallExpression nodes, dispatch hits
26
-
27
- **Run with:**
28
-
29
- ```bash
30
- node --import tsx src/benchmark.ts <target-dir> <iterations>
31
- ```
32
-
33
- **How to verify:** Run 3x, confirm <5% variance between runs for each phase.
34
-
35
- ---
36
-
37
- ## Step 1: Identifier-Based Dispatch Map in `visit.ts`
38
-
39
- **File:** `src/visit.ts`
40
-
41
- **Problem:** Every AST node goes through ALL handlers. In `visitRoutes`, that's 16 function calls per node. Each handler independently checks `isCallExpression` -> `isIdentifier` -> `expression.text === 'xyz'`. For non-CallExpression nodes (the vast majority), all 16 calls are wasted.
42
-
43
- **Fix:** Check node kind once, extract identifier once, use `Map<string, handler>` for O(1) dispatch.
44
-
45
- **Dispatch map for `visitRoutes`** (all handlers expect CallExpression + Identifier):
46
-
47
- | Identifier | Handler |
48
- | ------------------- | ------------------ |
49
- | `wireHTTP` | `addHTTPRoute` |
50
- | `wireHTTPRoutes` | `addHTTPRoutes` |
51
- | `wireScheduler` | `addSchedule` |
52
- | `wireTrigger` | `addTrigger` |
53
- | `wireTriggerSource` | `addTrigger` |
54
- | `wireQueueWorker` | `addQueueWorker` |
55
- | `wireChannel` | `addChannel` |
56
- | `wireCLI` | `addCLI` |
57
- | `pikkuCLIRender` | `addCLIRenderers` |
58
- | `wireMCPResource` | `addMCPResource` |
59
- | `wireMCPTool` | `addMCPTool` |
60
- | `wireMCPPrompt` | `addMCPPrompt` |
61
- | `wireWorkflowGraph` | `addWorkflowGraph` |
62
- | `defineSecret` | `addSecret` |
63
- | `defineCredential` | `addCredential` |
64
- | `defineScope` | `addScope` |
65
- | `defineVariable` | `addVariable` |
66
-
67
- `addAuth` stays outside the map: it matches several identifiers
68
- (`betterAuthStatelessSession`, `betterAuthSession`) and gates them on
69
- surrounding context rather than on the identifier alone, so it keeps running on
70
- every CallExpression.
71
-
72
- Fallback for unmatched identifiers: check `/pikku.*func/i` regex -> `addFunctions`.
73
-
74
- **Dispatch for `visitSetup`** (mixed node kinds):
75
-
76
- - `SyntaxKind.CallExpression` + Identifier -> map with: `external`, `workflow`, `workflowStart`, `workflowRun`, `workflowStatus`, `graphStart` -> `addRPCInvocations`; `pikkuMiddleware`, `pikkuMiddlewareFactory`, `addMiddleware`, `addHTTPMiddleware` -> `addMiddleware`; `pikkuPermission`, `pikkuPermissionFactory`, `addPermission`, `addHTTPPermission` -> `addPermission`; `pikkuWorkflowFunc`, `pikkuWorkflowComplexFunc` -> `addWorkflow`
77
- - `SyntaxKind.CallExpression` + PropertyAccessExpression (`rpc.invoke`) -> `addRPCInvocations`
78
- - `SyntaxKind.ClassDeclaration` / `InterfaceDeclaration` -> `addFileExtendsCoreType` (4 core type names)
79
- - `SyntaxKind.VariableDeclaration` -> `addFileWithFactory` (3 factory type names)
80
- - All other node kinds -> skip directly to recursion
81
-
82
- **Measure:** Compare "Visit setup phase" and "Visit routes phase" benchmark timings.
83
-
84
- **Expected improvement:** 30-60% reduction in visit phase times.
85
-
86
- **Verify:** `bash run-tests.sh` + compare serialized inspector state output before/after.
87
-
88
- ---
89
-
90
- ## Step 2: Hoist Regex + Remove Redundant Checks in `add-functions.ts`
91
-
92
- **File:** `src/add/add-functions.ts`
93
-
94
- **Problem (lines 290-309):**
95
-
96
- ```ts
97
- // Line 301: regex re-created EVERY call (every AST node)
98
- const pikkuFuncPattern = /pikku.*func/i
99
- // Line 307: redundant - isIdentifier already checked at line 296,
100
- // startsWith('pikku') is a subset of the regex
101
- if (!ts.isIdentifier(expression) || !expression.text.startsWith('pikku'))
102
- ```
103
-
104
- **Fix:**
105
-
106
- 1. Move `const pikkuFuncPattern = /pikku.*func/i` to module scope
107
- 2. Remove the redundant check at line 307-309
108
-
109
- **Measure:** "Visit routes phase" timing.
110
-
111
- **Expected improvement:** 1-5% of visit routes phase.
112
-
113
- **Verify:** `bash run-tests.sh`
114
-
115
- ---
116
-
117
- ## Step 3: Replace `getText()` with `.text` Property Access
118
-
119
- **Files:** 3-5 files, ~8 safe replacements
120
-
121
- `node.getText()` reconstructs text by slicing the source string. For `Identifier` nodes, `.text` is a direct property -- zero overhead.
122
-
123
- **Safe replacements:**
124
-
125
- - `src/add/add-file-extends-core-type.ts` line 13: `node.name?.getText()` -> `node.name?.text`
126
- - `src/add/add-file-with-factory.ts` line 24: `node.name.getText()` -> guard with `ts.isIdentifier(node.name) ? node.name.text : node.name.getText()`
127
- - `src/add/add-channel.ts` line 360: `shorthandDecl.name.getText()` -> `.text` (ImportSpecifier name is always Identifier)
128
-
129
- **Skip** (not safe or rarely hit): error messages, template literals, TypeNode, QualifiedName.
130
-
131
- **Measure:** "Visit setup phase" + "Visit routes phase" timings.
132
-
133
- **Expected improvement:** 1-3% of visit phases.
134
-
135
- **Verify:** `bash run-tests.sh`
136
-
137
- ---
138
-
139
- ## Step 4: Replace `JSON.parse(JSON.stringify(...))` with `structuredClone()`
140
-
141
- **File:** `src/utils/filter-inspector-state.ts` (lines 198-233)
142
-
143
- **Problem:** 8 calls to `JSON.parse(JSON.stringify(...))` for deep cloning metadata objects. This serializes to string then parses back -- wasteful.
144
-
145
- **Fix:** Replace all 8 with `structuredClone()` (available Node 17+, package requires >=18).
146
-
147
- ```ts
148
- // Before
149
- meta: JSON.parse(JSON.stringify(state.http.meta))
150
- // After
151
- meta: structuredClone(state.http.meta)
152
- ```
153
-
154
- **Measure:** Separate `filterInspectorState` benchmark loop using the 45KB test fixture.
155
-
156
- **Expected improvement:** 10-30% of filter phase time (not the main inspect path, but important for CLI).
157
-
158
- **Verify:** `bash run-tests.sh` (filter-inspector-state.test.ts covers this extensively -- 1,440 lines of tests).
159
-
160
- ---
161
-
162
- ## Step 5: Cache `node.getSourceFile().fileName` in Hot Handlers
163
-
164
- **Files:** Primarily `src/add/add-functions.ts`
165
-
166
- **Problem:** `add-functions.ts` calls `node.getSourceFile().fileName` 4+ times within a single handler invocation for the same node (lines 666, 700, 721, 735). `getSourceFile()` walks the parent chain each time.
167
-
168
- **Fix:** Extract once at handler entry:
169
-
170
- ```ts
171
- const sourceFileName = node.getSourceFile().fileName
172
- ```
173
-
174
- Then reuse `sourceFileName` throughout.
175
-
176
- **Measure:** "Visit routes phase" timing.
177
-
178
- **Expected improvement:** 1-2%.
179
-
180
- **Verify:** `bash run-tests.sh`
181
-
182
- ---
183
-
184
- ## Summary
185
-
186
- | Step | Change | File(s) | Expected Impact | Metric |
187
- | ---- | ----------------- | --------------------------- | -------------------------- | -------------------- |
188
- | 0 | Benchmark harness | New `benchmark.ts` | Baseline | - |
189
- | 1 | Dispatch map | `visit.ts` | **30-60%** of visit phases | Visit setup + routes |
190
- | 2 | Hoist regex | `add-functions.ts` | 1-5% of visit routes | Visit routes |
191
- | 3 | getText -> .text | 3-5 files | 1-3% of visit phases | Visit setup + routes |
192
- | 4 | structuredClone | `filter-inspector-state.ts` | 10-30% of filter phase | Filter benchmark |
193
- | 5 | Cache sourceFile | `add-functions.ts` | 1-2% of visit routes | Visit routes |
194
-
195
- ## Verification
196
-
197
- After each step:
198
-
199
- 1. Run benchmark: `node --import tsx src/benchmark.ts <target> 10`
200
- 2. Run tests: `cd packages/inspector && bash run-tests.sh`
201
- 3. Compare serialized inspector state output (before vs after) to confirm identical results
@@ -1,13 +0,0 @@
1
- import type { AddWiring } from '../types.js';
2
- /**
3
- * Inspector for `definePersonas()` calls.
4
- *
5
- * A persona is entirely declaration — a person, their roles, what they want —
6
- * so there is no code body and nothing to resolve at runtime. What is read here
7
- * is the whole thing, and it is generated straight to `personas.gen.json` for
8
- * the CLI and the console to read without loading the app.
9
- *
10
- * `name` is the one field that cannot be defaulted. A persona without one is
11
- * not a person, and the console has nothing to show.
12
- */
13
- export declare const addPersonas: AddWiring;
package/run-tests.sh DELETED
@@ -1,68 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Enable nullglob to handle cases where no files match the pattern
4
- shopt -s nullglob
5
-
6
- # Initialize variables for options
7
- watch_mode=false
8
- coverage_mode=false
9
-
10
- # Parse command-line options
11
- while [[ $# -gt 0 ]]; do
12
- case $1 in
13
- --watch)
14
- watch_mode=true
15
- shift
16
- ;;
17
- --coverage)
18
- coverage_mode=true
19
- shift
20
- ;;
21
- *)
22
- echo "Unknown option: $1"
23
- exit 1
24
- ;;
25
- esac
26
- done
27
-
28
- # Define the pattern to match your test files
29
- pattern="src/*.test.ts"
30
-
31
- # Expand the pattern into an array of files
32
- files=($(find src -type f -name "*.test.ts"))
33
-
34
- # Check if any files matched the pattern
35
- if [ ${#files[@]} -eq 0 ]; then
36
- echo "No test files found matching pattern: $pattern"
37
- if [ "${STRICT_TEST_DISCOVERY}" = "1" ]; then
38
- exit 1
39
- fi
40
- exit 0
41
- fi
42
-
43
- # Construct the bun command
44
- #
45
- # --parallel gives every test file its own worker process, which is what node's
46
- # `--test` did. Several suites keep module-level caches (a TypeScript program, a
47
- # temp fixture directory) that a shared process would leak between files.
48
- #
49
- # --timeout because bun caps a test at 5s by default where node had no cap, and
50
- # the suites that build real TypeScript programs run well past that.
51
- bun_cmd=(bun test --parallel --timeout 120000)
52
-
53
- # Append options based on flags
54
- if [ "$watch_mode" = true ]; then
55
- # --watch reruns in one process; parallel workers have nothing to watch.
56
- bun_cmd=(bun test --watch --timeout 120000)
57
- fi
58
-
59
- if [ "$coverage_mode" = true ]; then
60
- # --coverage-dir=. keeps lcov.info at the package root: CI merges every
61
- # package's report by prefixing its SF paths with the file's own directory,
62
- # so a nested coverage/ directory would re-root them one level too deep.
63
- bun_cmd+=(--coverage --coverage-reporter=lcov --coverage-reporter=text --coverage-dir=.)
64
- export PIKKU_TEST_COVERAGE=1
65
- fi
66
-
67
- # Execute the bun command with the expanded list of files
68
- "${bun_cmd[@]}" "${files[@]}"