@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.
- package/dist/add/add-auth.d.ts +1 -9
- package/dist/add/add-auth.js +64 -17
- package/dist/add/add-cli.js +25 -11
- package/dist/add/add-functions.js +35 -39
- package/dist/add/add-keyed-wiring.js +22 -2
- package/dist/add/add-middleware.js +17 -16
- package/dist/add/add-permission.d.ts +0 -3
- package/dist/add/add-permission.js +213 -22
- package/dist/add/add-scope.d.ts +1 -7
- package/dist/add/add-scope.js +1 -21
- package/dist/add/add-virtual-users.d.ts +13 -0
- package/dist/add/{add-personas.js → add-virtual-users.js} +33 -33
- package/dist/add/add-workflow.js +14 -10
- package/dist/add/check-indirect-registrations.d.ts +9 -0
- package/dist/add/check-indirect-registrations.js +114 -0
- package/dist/error-codes.d.ts +5 -3
- package/dist/error-codes.js +5 -3
- package/dist/finalize.d.ts +10 -0
- package/dist/finalize.js +102 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +6 -5
- package/dist/initial-state.d.ts +7 -0
- package/dist/initial-state.js +216 -0
- package/dist/inspector.d.ts +6 -4
- package/dist/inspector.js +28 -300
- package/dist/lite.d.ts +26 -0
- package/dist/lite.js +25 -0
- package/dist/source-file-cache.d.ts +11 -0
- package/dist/source-file-cache.js +34 -10
- package/dist/types-map.js +2 -1
- package/dist/types.d.ts +35 -3
- package/dist/utils/apply-declared-scopes.d.ts +8 -0
- package/dist/utils/apply-declared-scopes.js +21 -0
- package/dist/utils/canonical-type-string.d.ts +14 -0
- package/dist/utils/canonical-type-string.js +162 -0
- package/dist/utils/context-based-id.d.ts +7 -0
- package/dist/utils/context-based-id.js +9 -0
- package/dist/utils/custom-types-generator.d.ts +15 -1
- package/dist/utils/custom-types-generator.js +17 -5
- package/dist/utils/ensure-function-metadata.d.ts +0 -14
- package/dist/utils/ensure-function-metadata.js +4 -1
- package/dist/utils/extract-function-name.d.ts +1 -1
- package/dist/utils/extract-function-name.js +2 -4
- package/dist/utils/filter-inspector-state.js +31 -1
- package/dist/utils/get-property-value.d.ts +5 -0
- package/dist/utils/get-property-value.js +15 -1
- package/dist/utils/inspector-constants.d.ts +16 -0
- package/dist/utils/inspector-constants.js +16 -0
- package/dist/utils/load-addon-functions-meta.js +1 -0
- package/dist/utils/post-process.d.ts +35 -36
- package/dist/utils/post-process.js +218 -193
- package/dist/utils/resolve-callee-name.d.ts +27 -0
- package/dist/utils/resolve-callee-name.js +147 -0
- package/dist/utils/resolve-service-types.d.ts +8 -0
- package/dist/utils/resolve-service-types.js +21 -0
- package/dist/utils/schema-generator.js +29 -2
- package/dist/utils/serialize-inspector-state.d.ts +9 -3
- package/dist/utils/serialize-inspector-state.js +22 -7
- package/dist/utils/single-declaration.d.ts +3 -3
- package/dist/utils/single-declaration.js +3 -3
- package/dist/utils/validate-single-step-workflows.d.ts +3 -0
- package/dist/utils/validate-single-step-workflows.js +32 -0
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +3 -3
- package/dist/utils/workflow/dsl/patterns.d.ts +4 -11
- package/dist/utils/workflow/dsl/patterns.js +5 -11
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +6 -6
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +5 -5
- package/dist/visit.js +4 -2
- package/package.json +25 -9
- package/CHANGELOG.md +0 -4318
- package/OPTIMIZATION-PLAN.md +0 -201
- package/dist/add/add-personas.d.ts +0 -13
- package/run-tests.sh +0 -68
- package/src/utils/test-data/inspector-state.json +0 -1687
package/OPTIMIZATION-PLAN.md
DELETED
|
@@ -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[@]}"
|