@pikku/inspector 0.10.1 → 0.10.2
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/CHANGELOG.md +46 -0
- package/dist/add/add-channel.js +68 -14
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/inspector.d.ts +6 -0
- package/dist/inspector.js +49 -15
- package/dist/types.d.ts +3 -0
- package/dist/utils/post-process.d.ts +1 -1
- package/dist/utils/post-process.js +30 -0
- package/dist/utils/serialize-inspector-state.d.ts +2 -0
- package/dist/utils/serialize-inspector-state.js +4 -0
- package/dist/utils/type-utils.js +5 -3
- package/package.json +2 -2
- package/src/add/add-channel.ts +94 -19
- package/src/index.ts +1 -1
- package/src/inspector.ts +73 -22
- package/src/types.ts +3 -0
- package/src/utils/post-process.ts +40 -2
- package/src/utils/serialize-inspector-state.ts +6 -0
- package/src/utils/type-utils.ts +5 -3
- package/src/visit.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @pikku/inspector
|
|
2
2
|
|
|
3
|
+
## 0.10.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1967172: Update code generation to support channel middleware enhancements
|
|
8
|
+
|
|
9
|
+
**Code Generation Updates:**
|
|
10
|
+
|
|
11
|
+
- Update channel type serialization to include middleware support
|
|
12
|
+
- Improve WebSocket wrapper generation for middleware handling
|
|
13
|
+
- Update CLI channel client generation with better type support
|
|
14
|
+
- Enhance services and schema generation for channel configurations
|
|
15
|
+
|
|
16
|
+
**Inspector Updates:**
|
|
17
|
+
|
|
18
|
+
- Improve channel metadata extraction for middleware
|
|
19
|
+
- Better type analysis for channel lifecycle functions
|
|
20
|
+
- Enhanced post-processing for channel configurations
|
|
21
|
+
|
|
22
|
+
- 753481a: Add bootstrap command, performance optimizations, and CLI improvements
|
|
23
|
+
|
|
24
|
+
**New Features:**
|
|
25
|
+
|
|
26
|
+
- Add `pikku bootstrap` command for type-only generation (~13.5% faster than `pikku all`)
|
|
27
|
+
- Add configurable `ignoreFiles` option to pikku.config.json with sensible defaults (_.gen.ts, _.test.ts, \*.spec.ts)
|
|
28
|
+
- Export pikkuCLIRender helper from serialize-cli-types.ts with JSDoc documentation
|
|
29
|
+
|
|
30
|
+
**Performance Improvements:**
|
|
31
|
+
|
|
32
|
+
- Add aggressive TypeScript compiler options (skipDefaultLibCheck, types: []) - ~37% faster TypeScript setup
|
|
33
|
+
- Add detailed performance timing to inspector phases (--logLevel=debug)
|
|
34
|
+
- Optimize file inspection with ignore patterns - ~10-20% faster overall
|
|
35
|
+
|
|
36
|
+
**Enhancements:**
|
|
37
|
+
|
|
38
|
+
- Fix --logLevel flag to properly apply log level to logger
|
|
39
|
+
- Update middleware logging to use structured log format
|
|
40
|
+
- Improve CLI renderers to consistently use destructured logger service
|
|
41
|
+
- Fix middleware file generation when middleware groups exist
|
|
42
|
+
|
|
43
|
+
- 44d71a8: fix: fixing inspector ensuring pikkuConfig is set
|
|
44
|
+
- Updated dependencies [ea652dc]
|
|
45
|
+
- Updated dependencies [4349ec5]
|
|
46
|
+
- Updated dependencies [44d71a8]
|
|
47
|
+
- @pikku/core@0.10.2
|
|
48
|
+
|
|
3
49
|
## 0.10.1
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
package/dist/add/add-channel.js
CHANGED
|
@@ -94,7 +94,15 @@ export function addMessagesRoutes(logger, obj, state, checker) {
|
|
|
94
94
|
const init = getInitializerOf(routeElem);
|
|
95
95
|
if (!init)
|
|
96
96
|
continue;
|
|
97
|
-
|
|
97
|
+
// Get the route key, stripping quotes if it's a string literal
|
|
98
|
+
const routeName = routeElem.name;
|
|
99
|
+
if (!routeName)
|
|
100
|
+
continue;
|
|
101
|
+
let routeKey = routeName.getText();
|
|
102
|
+
// For string literals like 'greet' or "greet", strip the quotes
|
|
103
|
+
if (ts.isStringLiteral(routeName)) {
|
|
104
|
+
routeKey = routeName.text;
|
|
105
|
+
}
|
|
98
106
|
// For shorthand properties, we need to resolve the identifier to its declaration
|
|
99
107
|
if (ts.isShorthandPropertyAssignment(routeElem)) {
|
|
100
108
|
// Get the symbol for the shorthand property
|
|
@@ -133,8 +141,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
|
|
|
133
141
|
// Look up in the registry
|
|
134
142
|
const fnMeta = state.functions.meta[handlerName];
|
|
135
143
|
if (fnMeta) {
|
|
144
|
+
// Resolve middleware for this route
|
|
145
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
146
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
147
|
+
: undefined;
|
|
148
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
149
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
150
|
+
: undefined;
|
|
136
151
|
result[channelKey][routeKey] = {
|
|
137
152
|
pikkuFuncName: handlerName,
|
|
153
|
+
middleware: routeMiddleware,
|
|
138
154
|
};
|
|
139
155
|
continue;
|
|
140
156
|
}
|
|
@@ -147,8 +163,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
|
|
|
147
163
|
// Look up in the registry
|
|
148
164
|
const fnMeta = state.functions.meta[handlerName];
|
|
149
165
|
if (fnMeta) {
|
|
166
|
+
// Resolve middleware for this route
|
|
167
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
168
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
169
|
+
: undefined;
|
|
170
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
171
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
172
|
+
: undefined;
|
|
150
173
|
result[channelKey][routeKey] = {
|
|
151
174
|
pikkuFuncName: handlerName,
|
|
175
|
+
middleware: routeMiddleware,
|
|
152
176
|
};
|
|
153
177
|
continue;
|
|
154
178
|
}
|
|
@@ -172,8 +196,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
|
|
|
172
196
|
const handlerName = pikkuFuncName;
|
|
173
197
|
const fnMeta = state.functions.meta[handlerName];
|
|
174
198
|
if (fnMeta) {
|
|
199
|
+
// Resolve middleware for this route
|
|
200
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
201
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
202
|
+
: undefined;
|
|
203
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
204
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
205
|
+
: undefined;
|
|
175
206
|
result[channelKey][routeKey] = {
|
|
176
207
|
pikkuFuncName: handlerName,
|
|
208
|
+
middleware: routeMiddleware,
|
|
177
209
|
};
|
|
178
210
|
continue;
|
|
179
211
|
}
|
|
@@ -183,8 +215,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
|
|
|
183
215
|
const handlerName = pikkuFuncName;
|
|
184
216
|
const fnMeta = state.functions.meta[handlerName];
|
|
185
217
|
if (fnMeta) {
|
|
218
|
+
// Resolve middleware for this route
|
|
219
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
220
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
221
|
+
: undefined;
|
|
222
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
223
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
224
|
+
: undefined;
|
|
186
225
|
result[channelKey][routeKey] = {
|
|
187
226
|
pikkuFuncName: handlerName,
|
|
227
|
+
middleware: routeMiddleware,
|
|
188
228
|
};
|
|
189
229
|
continue;
|
|
190
230
|
}
|
|
@@ -239,8 +279,16 @@ export function addMessagesRoutes(logger, obj, state, checker) {
|
|
|
239
279
|
// Now use this handlerName to look up in the registry
|
|
240
280
|
const fnMeta = state.functions.meta[handlerName];
|
|
241
281
|
if (fnMeta) {
|
|
282
|
+
// Resolve middleware for this route
|
|
283
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
284
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
285
|
+
: undefined;
|
|
286
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
287
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
288
|
+
: undefined;
|
|
242
289
|
result[channelKey][routeKey] = {
|
|
243
290
|
pikkuFuncName: handlerName,
|
|
291
|
+
middleware: routeMiddleware,
|
|
244
292
|
};
|
|
245
293
|
continue; // Skip the normal processing below
|
|
246
294
|
}
|
|
@@ -259,8 +307,17 @@ export function addMessagesRoutes(logger, obj, state, checker) {
|
|
|
259
307
|
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for handler '${handlerName}'`);
|
|
260
308
|
continue;
|
|
261
309
|
}
|
|
310
|
+
// Resolve middleware and permissions for this route
|
|
311
|
+
// Check if the route config is an object literal with middleware/permissions
|
|
312
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
313
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
314
|
+
: undefined;
|
|
315
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
316
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
317
|
+
: undefined;
|
|
262
318
|
result[channelKey][routeKey] = {
|
|
263
319
|
pikkuFuncName: handlerName,
|
|
320
|
+
middleware: routeMiddleware,
|
|
264
321
|
};
|
|
265
322
|
}
|
|
266
323
|
}
|
|
@@ -295,24 +352,21 @@ export const addChannel = (logger, node, checker, state, options) => {
|
|
|
295
352
|
const docs = getPropertyValue(obj, 'docs');
|
|
296
353
|
const tags = getPropertyTags(obj, 'Channel', route, logger);
|
|
297
354
|
const query = getPropertyValue(obj, 'query');
|
|
298
|
-
const connect = getPropertyAssignmentInitializer(obj, 'onConnect',
|
|
299
|
-
const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect',
|
|
355
|
+
const connect = getPropertyAssignmentInitializer(obj, 'onConnect', true, checker);
|
|
356
|
+
const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect', true, checker);
|
|
300
357
|
// default onMessage handler
|
|
301
358
|
let message = null;
|
|
302
|
-
const onMsgProp = getPropertyAssignmentInitializer(obj, 'onMessage',
|
|
359
|
+
const onMsgProp = getPropertyAssignmentInitializer(obj, 'onMessage', true, checker);
|
|
303
360
|
if (onMsgProp) {
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
const fnMeta = handlerName && state.functions.meta[handlerName];
|
|
361
|
+
const { pikkuFuncName } = extractFunctionName(onMsgProp, checker, state.rootDir);
|
|
362
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
307
363
|
if (!fnMeta) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
else {
|
|
312
|
-
message = {
|
|
313
|
-
pikkuFuncName: extractFunctionName(onMsgProp, checker, state.rootDir).pikkuFuncName,
|
|
314
|
-
};
|
|
364
|
+
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for onMessage handler '${pikkuFuncName}'`);
|
|
365
|
+
return;
|
|
315
366
|
}
|
|
367
|
+
message = {
|
|
368
|
+
pikkuFuncName,
|
|
369
|
+
};
|
|
316
370
|
}
|
|
317
371
|
// nested message-routes
|
|
318
372
|
const messageWirings = addMessagesRoutes(logger, obj, state, checker);
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { inspect } from './inspector.js';
|
|
1
|
+
export { inspect, getInitialInspectorState } from './inspector.js';
|
|
2
2
|
export { getFilesAndMethods } from './utils/get-files-and-methods.js';
|
|
3
3
|
export { ErrorCode } from './error-codes.js';
|
|
4
4
|
export { serializeInspectorState, deserializeInspectorState, } from './utils/serialize-inspector-state.js';
|
package/dist/inspector.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates an initial/empty inspector state with all required properties initialized
|
|
4
|
+
* @param rootDir - The root directory for the project
|
|
5
|
+
* @returns A fresh InspectorState with empty collections
|
|
6
|
+
*/
|
|
7
|
+
export declare function getInitialInspectorState(rootDir: string): InspectorState;
|
|
2
8
|
export declare const inspect: (logger: InspectorLogger, routeFiles: string[], options?: InspectorOptions) => InspectorState;
|
package/dist/inspector.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
+
import { performance } from 'perf_hooks';
|
|
2
3
|
import { visitSetup, visitRoutes } from './visit.js';
|
|
3
4
|
import { TypesMap } from './types-map.js';
|
|
4
5
|
import { getFilesAndMethods } from './utils/get-files-and-methods.js';
|
|
5
6
|
import { findCommonAncestor } from './utils/find-root-dir.js';
|
|
6
7
|
import { aggregateRequiredServices } from './utils/post-process.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// Infer root directory from source files
|
|
15
|
-
const rootDir = findCommonAncestor(routeFiles);
|
|
16
|
-
const state = {
|
|
8
|
+
/**
|
|
9
|
+
* Creates an initial/empty inspector state with all required properties initialized
|
|
10
|
+
* @param rootDir - The root directory for the project
|
|
11
|
+
* @returns A fresh InspectorState with empty collections
|
|
12
|
+
*/
|
|
13
|
+
export function getInitialInspectorState(rootDir) {
|
|
14
|
+
return {
|
|
17
15
|
rootDir,
|
|
18
16
|
singletonServicesTypeImportMap: new Map(),
|
|
19
17
|
sessionServicesTypeImportMap: new Map(),
|
|
@@ -91,21 +89,57 @@ export const inspect = (logger, routeFiles, options = {}) => {
|
|
|
91
89
|
usedFunctions: new Set(),
|
|
92
90
|
usedMiddleware: new Set(),
|
|
93
91
|
usedPermissions: new Set(),
|
|
92
|
+
allSingletonServices: [],
|
|
93
|
+
allSessionServices: [],
|
|
94
94
|
},
|
|
95
95
|
};
|
|
96
|
+
}
|
|
97
|
+
export const inspect = (logger, routeFiles, options = {}) => {
|
|
98
|
+
const startProgram = performance.now();
|
|
99
|
+
const program = ts.createProgram(routeFiles, {
|
|
100
|
+
target: ts.ScriptTarget.ESNext,
|
|
101
|
+
module: ts.ModuleKind.CommonJS,
|
|
102
|
+
skipLibCheck: true,
|
|
103
|
+
skipDefaultLibCheck: true,
|
|
104
|
+
moduleResolution: ts.ModuleResolutionKind.Node10,
|
|
105
|
+
types: [],
|
|
106
|
+
allowJs: false,
|
|
107
|
+
checkJs: false,
|
|
108
|
+
});
|
|
109
|
+
logger.debug(`Created program in ${(performance.now() - startProgram).toFixed(2)}ms`);
|
|
110
|
+
const startChecker = performance.now();
|
|
111
|
+
const checker = program.getTypeChecker();
|
|
112
|
+
logger.debug(`Got type checker in ${(performance.now() - startChecker).toFixed(2)}ms`);
|
|
113
|
+
const startSourceFiles = performance.now();
|
|
114
|
+
const sourceFiles = program.getSourceFiles();
|
|
115
|
+
logger.debug(`Got source files in ${(performance.now() - startSourceFiles).toFixed(2)}ms`);
|
|
116
|
+
// Infer root directory from source files
|
|
117
|
+
const rootDir = findCommonAncestor(routeFiles);
|
|
118
|
+
const state = getInitialInspectorState(rootDir);
|
|
96
119
|
// First sweep: add all functions
|
|
120
|
+
const startSetup = performance.now();
|
|
97
121
|
for (const sourceFile of sourceFiles) {
|
|
98
122
|
ts.forEachChild(sourceFile, (child) => visitSetup(logger, checker, child, state, options));
|
|
99
123
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
124
|
+
logger.debug(`Visit setup phase completed in ${(performance.now() - startSetup).toFixed(2)}ms`);
|
|
125
|
+
if (!options.setupOnly) {
|
|
126
|
+
// Second sweep: add all transports
|
|
127
|
+
const startRoutes = performance.now();
|
|
128
|
+
for (const sourceFile of sourceFiles) {
|
|
129
|
+
ts.forEachChild(sourceFile, (child) => visitRoutes(logger, checker, child, state, options));
|
|
130
|
+
}
|
|
131
|
+
logger.debug(`Visit routes phase completed in ${(performance.now() - startRoutes).toFixed(2)}ms`);
|
|
103
132
|
}
|
|
104
133
|
// Populate filesAndMethods
|
|
134
|
+
const startFilesAndMethods = performance.now();
|
|
105
135
|
const { result, errors } = getFilesAndMethods(state, options.types);
|
|
106
136
|
state.filesAndMethods = result;
|
|
107
137
|
state.filesAndMethodsErrors = errors;
|
|
108
|
-
|
|
109
|
-
|
|
138
|
+
logger.debug(`Get files and methods completed in ${(performance.now() - startFilesAndMethods).toFixed(2)}ms`);
|
|
139
|
+
if (!options.setupOnly) {
|
|
140
|
+
const startAggregate = performance.now();
|
|
141
|
+
aggregateRequiredServices(state);
|
|
142
|
+
logger.debug(`Aggregate required services completed in ${(performance.now() - startAggregate).toFixed(2)}ms`);
|
|
143
|
+
}
|
|
110
144
|
return state;
|
|
111
145
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -86,6 +86,7 @@ export type InspectorFilters = {
|
|
|
86
86
|
httpMethods?: string[];
|
|
87
87
|
};
|
|
88
88
|
export type InspectorOptions = Partial<{
|
|
89
|
+
setupOnly: boolean;
|
|
89
90
|
types: Partial<{
|
|
90
91
|
configFileType: string;
|
|
91
92
|
userSessionType: string;
|
|
@@ -200,5 +201,7 @@ export interface InspectorState {
|
|
|
200
201
|
usedFunctions: Set<string>;
|
|
201
202
|
usedMiddleware: Set<string>;
|
|
202
203
|
usedPermissions: Set<string>;
|
|
204
|
+
allSingletonServices: string[];
|
|
205
|
+
allSessionServices: string[];
|
|
203
206
|
};
|
|
204
207
|
}
|
|
@@ -13,4 +13,4 @@ export declare function extractWireNames(list?: MiddlewareMetadata[] | Permissio
|
|
|
13
13
|
* Note: usedFunctions, usedMiddleware, and usedPermissions are tracked directly
|
|
14
14
|
* in the add-* methods during AST traversal for efficiency.
|
|
15
15
|
*/
|
|
16
|
-
export declare function aggregateRequiredServices(state: InspectorState): void;
|
|
16
|
+
export declare function aggregateRequiredServices(state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { extractTypeKeys } from './type-utils.js';
|
|
1
2
|
/**
|
|
2
3
|
* Helper to extract wire-level middleware/permission names from metadata.
|
|
3
4
|
* Only extracts type:'wire' variants (individual middleware/permissions).
|
|
@@ -39,6 +40,33 @@ function expandAndAddGroupServices(list, state, addServices, isMiddleware) {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Extracts all service names from SingletonServices and Services types.
|
|
45
|
+
* This provides the complete list of available services for code generation.
|
|
46
|
+
* Only runs if typesLookup is available (omitted in deserialized states).
|
|
47
|
+
*/
|
|
48
|
+
function extractAllServices(state) {
|
|
49
|
+
// Skip if typesLookup is not available (e.g., deserialized state)
|
|
50
|
+
if (!('typesLookup' in state)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Extract all singleton services from the SingletonServices type
|
|
54
|
+
const singletonServicesTypes = state.typesLookup.get('SingletonServices');
|
|
55
|
+
if (singletonServicesTypes && singletonServicesTypes.length > 0) {
|
|
56
|
+
const singletonServiceNames = extractTypeKeys(singletonServicesTypes[0]);
|
|
57
|
+
state.serviceAggregation.allSingletonServices = singletonServiceNames.sort();
|
|
58
|
+
}
|
|
59
|
+
// Extract all services from the Services type
|
|
60
|
+
const servicesTypes = state.typesLookup.get('Services');
|
|
61
|
+
if (servicesTypes && servicesTypes.length > 0) {
|
|
62
|
+
const allServiceNames = extractTypeKeys(servicesTypes[0]);
|
|
63
|
+
// Session services are those in Services but not in SingletonServices
|
|
64
|
+
const singletonSet = new Set(state.serviceAggregation.allSingletonServices);
|
|
65
|
+
state.serviceAggregation.allSessionServices = allServiceNames
|
|
66
|
+
.filter((name) => !singletonSet.has(name))
|
|
67
|
+
.sort();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
42
70
|
/**
|
|
43
71
|
* Aggregates all required services from wired functions, middleware, and permissions.
|
|
44
72
|
* Must be called after AST traversal completes.
|
|
@@ -47,6 +75,8 @@ function expandAndAddGroupServices(list, state, addServices, isMiddleware) {
|
|
|
47
75
|
* in the add-* methods during AST traversal for efficiency.
|
|
48
76
|
*/
|
|
49
77
|
export function aggregateRequiredServices(state) {
|
|
78
|
+
// First, extract all available services from types
|
|
79
|
+
extractAllServices(state);
|
|
50
80
|
const { requiredServices, usedFunctions, usedMiddleware, usedPermissions } = state.serviceAggregation;
|
|
51
81
|
// Internal services (always excluded from tree-shaking)
|
|
52
82
|
const internalServices = new Set(['rpc', 'mcp', 'channel', 'userSession']);
|
|
@@ -80,6 +80,8 @@ export function serializeInspectorState(state) {
|
|
|
80
80
|
usedFunctions: Array.from(state.serviceAggregation.usedFunctions),
|
|
81
81
|
usedMiddleware: Array.from(state.serviceAggregation.usedMiddleware),
|
|
82
82
|
usedPermissions: Array.from(state.serviceAggregation.usedPermissions),
|
|
83
|
+
allSingletonServices: state.serviceAggregation.allSingletonServices,
|
|
84
|
+
allSessionServices: state.serviceAggregation.allSessionServices,
|
|
83
85
|
},
|
|
84
86
|
};
|
|
85
87
|
}
|
|
@@ -165,6 +167,8 @@ export function deserializeInspectorState(data) {
|
|
|
165
167
|
usedFunctions: new Set(data.serviceAggregation.usedFunctions),
|
|
166
168
|
usedMiddleware: new Set(data.serviceAggregation.usedMiddleware),
|
|
167
169
|
usedPermissions: new Set(data.serviceAggregation.usedPermissions),
|
|
170
|
+
allSingletonServices: data.serviceAggregation.allSingletonServices,
|
|
171
|
+
allSessionServices: data.serviceAggregation.allSessionServices,
|
|
168
172
|
},
|
|
169
173
|
};
|
|
170
174
|
}
|
package/dist/utils/type-utils.js
CHANGED
|
@@ -22,17 +22,19 @@ export function getPropertyAssignmentInitializer(obj, propName, followShorthand
|
|
|
22
22
|
prop.name.text === propName) {
|
|
23
23
|
if (!checker)
|
|
24
24
|
return prop.name; // best effort without a checker
|
|
25
|
-
|
|
25
|
+
// Use the proper TypeScript API for shorthand property resolution
|
|
26
|
+
let sym = checker.getShorthandAssignmentValueSymbol(prop);
|
|
26
27
|
if (sym && sym.flags & ts.SymbolFlags.Alias) {
|
|
27
28
|
sym = checker.getAliasedSymbol(sym);
|
|
28
29
|
}
|
|
29
30
|
const decl = sym?.declarations?.[0];
|
|
30
|
-
// const foo = () => {}
|
|
31
|
+
// const foo = () => {} or const foo = pikkuFunc(...)
|
|
31
32
|
if (decl &&
|
|
32
33
|
ts.isVariableDeclaration(decl) &&
|
|
33
34
|
decl.initializer &&
|
|
34
35
|
(ts.isArrowFunction(decl.initializer) ||
|
|
35
|
-
ts.isFunctionExpression(decl.initializer)
|
|
36
|
+
ts.isFunctionExpression(decl.initializer) ||
|
|
37
|
+
ts.isCallExpression(decl.initializer))) {
|
|
36
38
|
return decl.initializer;
|
|
37
39
|
}
|
|
38
40
|
// function foo() {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"test:coverage": "bash run-tests.sh --coverage"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@pikku/core": "^0.10.
|
|
19
|
+
"@pikku/core": "^0.10.2",
|
|
20
20
|
"path-to-regexp": "^8.3.0",
|
|
21
21
|
"typescript": "^5.9"
|
|
22
22
|
},
|
package/src/add/add-channel.ts
CHANGED
|
@@ -136,7 +136,15 @@ export function addMessagesRoutes(
|
|
|
136
136
|
const init = getInitializerOf(routeElem)
|
|
137
137
|
if (!init) continue
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
// Get the route key, stripping quotes if it's a string literal
|
|
140
|
+
const routeName = routeElem.name
|
|
141
|
+
if (!routeName) continue
|
|
142
|
+
|
|
143
|
+
let routeKey = routeName.getText()
|
|
144
|
+
// For string literals like 'greet' or "greet", strip the quotes
|
|
145
|
+
if (ts.isStringLiteral(routeName)) {
|
|
146
|
+
routeKey = routeName.text
|
|
147
|
+
}
|
|
140
148
|
|
|
141
149
|
// For shorthand properties, we need to resolve the identifier to its declaration
|
|
142
150
|
if (ts.isShorthandPropertyAssignment(routeElem)) {
|
|
@@ -196,8 +204,17 @@ export function addMessagesRoutes(
|
|
|
196
204
|
// Look up in the registry
|
|
197
205
|
const fnMeta = state.functions.meta[handlerName]
|
|
198
206
|
if (fnMeta) {
|
|
207
|
+
// Resolve middleware for this route
|
|
208
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
209
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
210
|
+
: undefined
|
|
211
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
212
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
213
|
+
: undefined
|
|
214
|
+
|
|
199
215
|
result[channelKey]![routeKey] = {
|
|
200
216
|
pikkuFuncName: handlerName,
|
|
217
|
+
middleware: routeMiddleware,
|
|
201
218
|
}
|
|
202
219
|
continue
|
|
203
220
|
}
|
|
@@ -214,8 +231,17 @@ export function addMessagesRoutes(
|
|
|
214
231
|
// Look up in the registry
|
|
215
232
|
const fnMeta = state.functions.meta[handlerName]
|
|
216
233
|
if (fnMeta) {
|
|
234
|
+
// Resolve middleware for this route
|
|
235
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
236
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
237
|
+
: undefined
|
|
238
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
239
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
240
|
+
: undefined
|
|
241
|
+
|
|
217
242
|
result[channelKey]![routeKey] = {
|
|
218
243
|
pikkuFuncName: handlerName,
|
|
244
|
+
middleware: routeMiddleware,
|
|
219
245
|
}
|
|
220
246
|
continue
|
|
221
247
|
}
|
|
@@ -249,8 +275,24 @@ export function addMessagesRoutes(
|
|
|
249
275
|
|
|
250
276
|
const fnMeta = state.functions.meta[handlerName]
|
|
251
277
|
if (fnMeta) {
|
|
278
|
+
// Resolve middleware for this route
|
|
279
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
280
|
+
? getPropertyTags(
|
|
281
|
+
init,
|
|
282
|
+
'channel',
|
|
283
|
+
channelKey,
|
|
284
|
+
logger
|
|
285
|
+
)
|
|
286
|
+
: undefined
|
|
287
|
+
const routeMiddleware = ts.isObjectLiteralExpression(
|
|
288
|
+
init
|
|
289
|
+
)
|
|
290
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
291
|
+
: undefined
|
|
292
|
+
|
|
252
293
|
result[channelKey]![routeKey] = {
|
|
253
294
|
pikkuFuncName: handlerName,
|
|
295
|
+
middleware: routeMiddleware,
|
|
254
296
|
}
|
|
255
297
|
continue
|
|
256
298
|
}
|
|
@@ -264,8 +306,24 @@ export function addMessagesRoutes(
|
|
|
264
306
|
|
|
265
307
|
const fnMeta = state.functions.meta[handlerName]
|
|
266
308
|
if (fnMeta) {
|
|
309
|
+
// Resolve middleware for this route
|
|
310
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
311
|
+
? getPropertyTags(
|
|
312
|
+
init,
|
|
313
|
+
'channel',
|
|
314
|
+
channelKey,
|
|
315
|
+
logger
|
|
316
|
+
)
|
|
317
|
+
: undefined
|
|
318
|
+
const routeMiddleware = ts.isObjectLiteralExpression(
|
|
319
|
+
init
|
|
320
|
+
)
|
|
321
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
322
|
+
: undefined
|
|
323
|
+
|
|
267
324
|
result[channelKey]![routeKey] = {
|
|
268
325
|
pikkuFuncName: handlerName,
|
|
326
|
+
middleware: routeMiddleware,
|
|
269
327
|
}
|
|
270
328
|
continue
|
|
271
329
|
}
|
|
@@ -336,8 +394,17 @@ export function addMessagesRoutes(
|
|
|
336
394
|
const fnMeta = state.functions.meta[handlerName]
|
|
337
395
|
|
|
338
396
|
if (fnMeta) {
|
|
397
|
+
// Resolve middleware for this route
|
|
398
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
399
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
400
|
+
: undefined
|
|
401
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
402
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
403
|
+
: undefined
|
|
404
|
+
|
|
339
405
|
result[channelKey]![routeKey] = {
|
|
340
406
|
pikkuFuncName: handlerName,
|
|
407
|
+
middleware: routeMiddleware,
|
|
341
408
|
}
|
|
342
409
|
continue // Skip the normal processing below
|
|
343
410
|
}
|
|
@@ -368,8 +435,18 @@ export function addMessagesRoutes(
|
|
|
368
435
|
continue
|
|
369
436
|
}
|
|
370
437
|
|
|
438
|
+
// Resolve middleware and permissions for this route
|
|
439
|
+
// Check if the route config is an object literal with middleware/permissions
|
|
440
|
+
const routeTags = ts.isObjectLiteralExpression(init)
|
|
441
|
+
? getPropertyTags(init, 'channel', channelKey, logger)
|
|
442
|
+
: undefined
|
|
443
|
+
const routeMiddleware = ts.isObjectLiteralExpression(init)
|
|
444
|
+
? resolveMiddleware(state, init, routeTags, checker)
|
|
445
|
+
: undefined
|
|
446
|
+
|
|
371
447
|
result[channelKey]![routeKey] = {
|
|
372
448
|
pikkuFuncName: handlerName,
|
|
449
|
+
middleware: routeMiddleware,
|
|
373
450
|
}
|
|
374
451
|
}
|
|
375
452
|
}
|
|
@@ -417,13 +494,13 @@ export const addChannel: AddWiring = (
|
|
|
417
494
|
const connect = getPropertyAssignmentInitializer(
|
|
418
495
|
obj,
|
|
419
496
|
'onConnect',
|
|
420
|
-
|
|
497
|
+
true,
|
|
421
498
|
checker
|
|
422
499
|
)
|
|
423
500
|
const disconnect = getPropertyAssignmentInitializer(
|
|
424
501
|
obj,
|
|
425
502
|
'onDisconnect',
|
|
426
|
-
|
|
503
|
+
true,
|
|
427
504
|
checker
|
|
428
505
|
)
|
|
429
506
|
|
|
@@ -432,28 +509,26 @@ export const addChannel: AddWiring = (
|
|
|
432
509
|
const onMsgProp = getPropertyAssignmentInitializer(
|
|
433
510
|
obj,
|
|
434
511
|
'onMessage',
|
|
435
|
-
|
|
512
|
+
true,
|
|
436
513
|
checker
|
|
437
514
|
)
|
|
438
515
|
|
|
439
516
|
if (onMsgProp) {
|
|
440
|
-
const
|
|
441
|
-
onMsgProp
|
|
442
|
-
|
|
443
|
-
|
|
517
|
+
const { pikkuFuncName } = extractFunctionName(
|
|
518
|
+
onMsgProp,
|
|
519
|
+
checker,
|
|
520
|
+
state.rootDir
|
|
521
|
+
)
|
|
522
|
+
const fnMeta = state.functions.meta[pikkuFuncName]
|
|
444
523
|
if (!fnMeta) {
|
|
445
|
-
|
|
446
|
-
|
|
524
|
+
logger.critical(
|
|
525
|
+
ErrorCode.FUNCTION_METADATA_NOT_FOUND,
|
|
526
|
+
`No function metadata found for onMessage handler '${pikkuFuncName}'`
|
|
447
527
|
)
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
onMsgProp as any,
|
|
453
|
-
checker,
|
|
454
|
-
state.rootDir
|
|
455
|
-
).pikkuFuncName,
|
|
456
|
-
}
|
|
528
|
+
return
|
|
529
|
+
}
|
|
530
|
+
message = {
|
|
531
|
+
pikkuFuncName,
|
|
457
532
|
}
|
|
458
533
|
}
|
|
459
534
|
|