@pikku/inspector 0.12.0 → 0.12.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.
Files changed (112) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/add/add-ai-agent.d.ts +1 -1
  3. package/dist/add/add-ai-agent.js +1 -1
  4. package/dist/add/add-channel.js +14 -0
  5. package/dist/add/add-cli.d.ts +1 -1
  6. package/dist/add/add-cli.js +29 -8
  7. package/dist/add/add-file-extends-core-type.d.ts +1 -1
  8. package/dist/add/add-file-with-config.d.ts +1 -1
  9. package/dist/add/add-file-with-factory.d.ts +1 -1
  10. package/dist/add/add-file-with-factory.js +2 -2
  11. package/dist/add/add-functions.d.ts +1 -1
  12. package/dist/add/add-functions.js +6 -7
  13. package/dist/add/add-gateway.d.ts +2 -0
  14. package/dist/add/add-gateway.js +57 -0
  15. package/dist/add/add-http-route.d.ts +3 -2
  16. package/dist/add/add-http-route.js +5 -1
  17. package/dist/add/add-http-routes.d.ts +1 -1
  18. package/dist/add/add-http-routes.js +1 -0
  19. package/dist/add/add-keyed-wiring.d.ts +1 -1
  20. package/dist/add/add-mcp-prompt.d.ts +1 -1
  21. package/dist/add/add-mcp-resource.d.ts +1 -1
  22. package/dist/add/add-queue-worker.d.ts +1 -1
  23. package/dist/add/add-rpc-invocations.d.ts +3 -3
  24. package/dist/add/add-rpc-invocations.js +10 -10
  25. package/dist/add/add-schedule.d.ts +1 -1
  26. package/dist/add/add-secret.d.ts +1 -1
  27. package/dist/add/add-trigger.d.ts +1 -1
  28. package/dist/add/add-trigger.js +2 -2
  29. package/dist/add/add-wire-addon.d.ts +7 -0
  30. package/dist/add/add-wire-addon.js +70 -0
  31. package/dist/add/add-workflow.d.ts +1 -1
  32. package/dist/error-codes.d.ts +1 -0
  33. package/dist/error-codes.js +1 -0
  34. package/dist/index.d.ts +1 -1
  35. package/dist/inspector.d.ts +1 -1
  36. package/dist/inspector.js +11 -4
  37. package/dist/types.d.ts +31 -20
  38. package/dist/utils/compute-required-schemas.js +1 -2
  39. package/dist/utils/contract-hashes.d.ts +20 -3
  40. package/dist/utils/contract-hashes.js +77 -10
  41. package/dist/utils/custom-types-generator.d.ts +1 -1
  42. package/dist/utils/detect-schema-vendor.d.ts +1 -1
  43. package/dist/utils/does-type-extend-core-type.d.ts +1 -1
  44. package/dist/utils/ensure-function-metadata.d.ts +1 -1
  45. package/dist/utils/extract-services.d.ts +1 -1
  46. package/dist/utils/filter-inspector-state.d.ts +1 -1
  47. package/dist/utils/filter-utils.d.ts +2 -2
  48. package/dist/utils/get-files-and-methods.d.ts +1 -1
  49. package/dist/utils/middleware.d.ts +2 -2
  50. package/dist/utils/permissions.d.ts +2 -2
  51. package/dist/utils/post-process.d.ts +4 -3
  52. package/dist/utils/post-process.js +24 -8
  53. package/dist/utils/resolve-addon-package.d.ts +16 -0
  54. package/dist/utils/{resolve-external-package.js → resolve-addon-package.js} +8 -8
  55. package/dist/utils/schema-generator.d.ts +2 -2
  56. package/dist/utils/serialize-inspector-state.d.ts +17 -3
  57. package/dist/utils/serialize-inspector-state.js +14 -2
  58. package/dist/utils/validate-auth-sessionless.d.ts +3 -0
  59. package/dist/utils/validate-auth-sessionless.js +14 -0
  60. package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +1 -1
  61. package/dist/visit.d.ts +1 -1
  62. package/dist/visit.js +4 -0
  63. package/package.json +3 -3
  64. package/src/add/add-ai-agent.ts +2 -2
  65. package/src/add/add-channel.ts +17 -0
  66. package/src/add/add-cli.ts +53 -15
  67. package/src/add/add-file-extends-core-type.ts +1 -1
  68. package/src/add/add-file-with-config.ts +1 -1
  69. package/src/add/add-file-with-factory.ts +3 -3
  70. package/src/add/add-functions.ts +21 -19
  71. package/src/add/add-gateway.ts +95 -0
  72. package/src/add/add-http-route.ts +19 -2
  73. package/src/add/add-http-routes.ts +2 -1
  74. package/src/add/add-keyed-wiring.ts +1 -1
  75. package/src/add/add-mcp-prompt.ts +1 -1
  76. package/src/add/add-mcp-resource.ts +1 -1
  77. package/src/add/add-queue-worker.ts +1 -1
  78. package/src/add/add-rpc-invocations.ts +11 -11
  79. package/src/add/add-schedule.ts +1 -1
  80. package/src/add/add-secret.ts +1 -1
  81. package/src/add/add-trigger.ts +4 -4
  82. package/src/add/add-wire-addon.ts +80 -0
  83. package/src/add/add-workflow.ts +2 -2
  84. package/src/error-codes.ts +1 -0
  85. package/src/index.ts +1 -0
  86. package/src/inspector.ts +17 -5
  87. package/src/types.ts +38 -20
  88. package/src/utils/compute-required-schemas.ts +1 -2
  89. package/src/utils/contract-hashes.test.ts +30 -5
  90. package/src/utils/contract-hashes.ts +110 -14
  91. package/src/utils/custom-types-generator.ts +1 -1
  92. package/src/utils/detect-schema-vendor.ts +1 -1
  93. package/src/utils/does-type-extend-core-type.ts +1 -1
  94. package/src/utils/ensure-function-metadata.ts +1 -1
  95. package/src/utils/extract-services.ts +1 -1
  96. package/src/utils/filter-inspector-state.test.ts +3 -5
  97. package/src/utils/filter-inspector-state.ts +7 -2
  98. package/src/utils/filter-utils.test.ts +1 -1
  99. package/src/utils/filter-utils.ts +2 -2
  100. package/src/utils/get-files-and-methods.ts +1 -1
  101. package/src/utils/middleware.ts +2 -2
  102. package/src/utils/permissions.ts +2 -2
  103. package/src/utils/post-process.ts +34 -12
  104. package/src/utils/{resolve-external-package.ts → resolve-addon-package.ts} +17 -10
  105. package/src/utils/resolve-versions.test.ts +1 -1
  106. package/src/utils/schema-generator.ts +4 -4
  107. package/src/utils/serialize-inspector-state.ts +35 -5
  108. package/src/utils/validate-auth-sessionless.ts +29 -0
  109. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +2 -2
  110. package/src/visit.ts +9 -1
  111. package/tsconfig.tsbuildinfo +1 -1
  112. package/dist/utils/resolve-external-package.d.ts +0 -12
@@ -44,6 +44,10 @@ export function serializeInspectorState(state) {
44
44
  files: Array.from(state.channels.files),
45
45
  meta: state.channels.meta,
46
46
  },
47
+ gateways: {
48
+ meta: state.gateways.meta,
49
+ files: Array.from(state.gateways.files),
50
+ },
47
51
  triggers: {
48
52
  meta: state.triggers.meta,
49
53
  sourceMeta: state.triggers.sourceMeta,
@@ -70,7 +74,9 @@ export function serializeInspectorState(state) {
70
74
  exposedMeta: state.rpc.exposedMeta,
71
75
  exposedFiles: Array.from(state.rpc.exposedFiles.entries()),
72
76
  invokedFunctions: Array.from(state.rpc.invokedFunctions),
73
- usedExternalPackages: Array.from(state.rpc.usedExternalPackages),
77
+ usedAddons: Array.from(state.rpc.usedAddons),
78
+ wireAddonDeclarations: Array.from(state.rpc.wireAddonDeclarations.entries()),
79
+ wireAddonFiles: Array.from(state.rpc.wireAddonFiles),
74
80
  },
75
81
  mcpEndpoints: {
76
82
  resourcesMeta: state.mcpEndpoints.resourcesMeta,
@@ -179,6 +185,10 @@ export function deserializeInspectorState(data) {
179
185
  files: new Set(data.channels.files),
180
186
  meta: data.channels.meta,
181
187
  },
188
+ gateways: {
189
+ meta: data.gateways?.meta ?? {},
190
+ files: new Set(data.gateways?.files ?? []),
191
+ },
182
192
  triggers: {
183
193
  meta: data.triggers?.meta ?? {},
184
194
  sourceMeta: data.triggers?.sourceMeta ?? {},
@@ -205,7 +215,9 @@ export function deserializeInspectorState(data) {
205
215
  exposedMeta: data.rpc.exposedMeta,
206
216
  exposedFiles: new Map(data.rpc.exposedFiles),
207
217
  invokedFunctions: new Set(data.rpc.invokedFunctions),
208
- usedExternalPackages: new Set(data.rpc.usedExternalPackages || []),
218
+ usedAddons: new Set(data.rpc.usedAddons || []),
219
+ wireAddonDeclarations: new Map(data.rpc.wireAddonDeclarations || []),
220
+ wireAddonFiles: new Set(data.rpc.wireAddonFiles || []),
209
221
  },
210
222
  mcpEndpoints: {
211
223
  resourcesMeta: data.mcpEndpoints.resourcesMeta,
@@ -0,0 +1,3 @@
1
+ import * as ts from 'typescript';
2
+ import type { InspectorLogger, InspectorState } from '../types.js';
3
+ export declare function validateAuthSessionless(logger: InspectorLogger, obj: ts.ObjectLiteralExpression, state: InspectorState, funcName: string, wireDescription: string, inheritedAuth?: boolean): boolean;
@@ -0,0 +1,14 @@
1
+ import { getPropertyValue } from './get-property-value.js';
2
+ import { ErrorCode } from '../error-codes.js';
3
+ export function validateAuthSessionless(logger, obj, state, funcName, wireDescription, inheritedAuth) {
4
+ const fnMeta = state.functions.meta[funcName];
5
+ if (!fnMeta)
6
+ return true;
7
+ const routeAuth = getPropertyValue(obj, 'auth');
8
+ const resolvedAuth = routeAuth === true || routeAuth === false ? routeAuth : inheritedAuth;
9
+ if (resolvedAuth === false && fnMeta.sessionless === false) {
10
+ logger.critical(ErrorCode.AUTH_DISABLED_REQUIRES_SESSIONLESS, `${wireDescription} has auth disabled but function '${funcName}' uses pikkuFunc (requires session). Use pikkuSessionlessFunc instead.`);
11
+ return false;
12
+ }
13
+ return true;
14
+ }
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript';
2
- import { WorkflowStepMeta, WorkflowContext } from '@pikku/core/workflow';
2
+ import type { WorkflowStepMeta, WorkflowContext } from '@pikku/core/workflow';
3
3
  /**
4
4
  * Result of simple workflow extraction
5
5
  */
package/dist/visit.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import * as ts from 'typescript';
2
- import { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
2
+ import type { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
3
3
  export declare const visitSetup: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
4
4
  export declare const visitRoutes: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
package/dist/visit.js CHANGED
@@ -11,7 +11,9 @@ import { addMCPResource } from './add/add-mcp-resource.js';
11
11
  import { addMCPPrompt } from './add/add-mcp-prompt.js';
12
12
  import { addFunctions } from './add/add-functions.js';
13
13
  import { addChannel } from './add/add-channel.js';
14
+ import { addGateway } from './add/add-gateway.js';
14
15
  import { addRPCInvocations } from './add/add-rpc-invocations.js';
16
+ import { addWireAddon } from './add/add-wire-addon.js';
15
17
  import { addMiddleware } from './add/add-middleware.js';
16
18
  import { addPermission } from './add/add-permission.js';
17
19
  import { addCLI, addCLIRenderers } from './add/add-cli.js';
@@ -28,6 +30,7 @@ export const visitSetup = (logger, checker, node, state, options) => {
28
30
  addFileWithFactory(node, checker, state.wireServicesFactories, 'CreateWireServices', state);
29
31
  addFileWithFactory(node, checker, state.configFactories, 'CreateConfig');
30
32
  addRPCInvocations(node, state, logger);
33
+ addWireAddon(node, state, logger);
31
34
  addMiddleware(logger, node, checker, state, options);
32
35
  addPermission(logger, node, checker, state, options);
33
36
  addWorkflow(logger, node, checker, state, options);
@@ -44,6 +47,7 @@ export const visitRoutes = (logger, checker, node, state, options) => {
44
47
  addTrigger(logger, node, checker, state, options);
45
48
  addQueueWorker(logger, node, checker, state, options);
46
49
  addChannel(logger, node, checker, state, options);
50
+ addGateway(logger, node, checker, state, options);
47
51
  addCLI(logger, node, checker, state, options);
48
52
  addCLIRenderers(logger, node, checker, state, options);
49
53
  addMCPResource(logger, node, checker, state, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/inspector",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "BUSL-1.1",
6
6
  "type": "module",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@openapi-contrib/json-schema-to-openapi-schema": "^4.3.1",
37
- "@pikku/core": "^0.12.0",
37
+ "@pikku/core": "^0.12.2",
38
38
  "path-to-regexp": "^8.3.0",
39
39
  "ts-json-schema-generator": "^2.5.0",
40
40
  "tsx": "^4.21.0",
@@ -43,7 +43,7 @@
43
43
  "zod-to-ts": "^2.0.0"
44
44
  },
45
45
  "devDependencies": {
46
- "@types/node": "^24.10.12"
46
+ "@types/node": "^24.11.0"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=18"
@@ -4,7 +4,7 @@ import {
4
4
  getCommonWireMetaData,
5
5
  } from '../utils/get-property-value.js'
6
6
  import { extractWireNames } from '../utils/post-process.js'
7
- import { AddWiring, InspectorLogger, SchemaRef } from '../types.js'
7
+ import type { AddWiring, InspectorLogger, SchemaRef } from '../types.js'
8
8
  import {
9
9
  extractFunctionName,
10
10
  funcIdToTypeName,
@@ -63,7 +63,7 @@ function resolveToolReferences(
63
63
  }
64
64
  }
65
65
 
66
- if (calleeName === 'external') {
66
+ if (calleeName === 'addon') {
67
67
  const [firstArg] = element.arguments
68
68
  if (firstArg && ts.isStringLiteral(firstArg)) {
69
69
  resolved.push(firstArg.text)
@@ -18,6 +18,7 @@ import {
18
18
  } from '../utils/middleware.js'
19
19
  import { extractWireNames } from '../utils/post-process.js'
20
20
  import { resolveIdentifier } from '../utils/resolve-identifier.js'
21
+ import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
21
22
 
22
23
  /**
23
24
  * Safely get the "initializer" expression of a property-like AST node:
@@ -526,6 +527,7 @@ export const addChannel: AddWiring = (
526
527
  if (disabled) return
527
528
 
528
529
  const query = getPropertyValue(obj, 'query') as string[] | []
530
+ const binary = getPropertyValue(obj, 'binary') as boolean | undefined
529
531
 
530
532
  const connect = getPropertyAssignmentInitializer(
531
533
  obj,
@@ -611,6 +613,20 @@ export const addChannel: AddWiring = (
611
613
  state.serviceAggregation.usedMiddleware.add(name)
612
614
  )
613
615
 
616
+ // --- validate auth/sessionless ---
617
+ const handlersToValidate = [
618
+ connectFuncId,
619
+ disconnectFuncId,
620
+ message?.pikkuFuncId,
621
+ ].filter(Boolean) as string[]
622
+ for (const funcId of handlersToValidate) {
623
+ if (
624
+ !validateAuthSessionless(logger, obj, state, funcId, `Channel '${name}'`)
625
+ ) {
626
+ return
627
+ }
628
+ }
629
+
614
630
  state.channels.files.add(node.getSourceFile().fileName)
615
631
  state.channels.meta[name] = {
616
632
  name,
@@ -622,6 +638,7 @@ export const addChannel: AddWiring = (
622
638
  disconnect: disconnectFuncId ? { pikkuFuncId: disconnectFuncId } : null,
623
639
  message,
624
640
  messageWirings,
641
+ binary: binary === undefined ? undefined : binary,
625
642
  summary,
626
643
  description,
627
644
  errors,
@@ -1,16 +1,21 @@
1
- import ts, { TypeChecker } from 'typescript'
2
- import {
1
+ import type { TypeChecker } from 'typescript'
2
+ import ts from 'typescript'
3
+ import type {
3
4
  AddWiring,
4
5
  InspectorLogger,
5
6
  InspectorOptions,
6
7
  InspectorState,
7
8
  } from '../types.js'
8
- import { CLIProgramMeta, CLICommandMeta } from '@pikku/core/cli'
9
- import { extractFunctionName } from '../utils/extract-function-name.js'
9
+ import type { CLIProgramMeta, CLICommandMeta } from '@pikku/core/cli'
10
+ import {
11
+ extractFunctionName,
12
+ makeContextBasedId,
13
+ } from '../utils/extract-function-name.js'
10
14
  import { resolveMiddleware } from '../utils/middleware.js'
11
15
  import { extractWireNames } from '../utils/post-process.js'
12
16
  import { getPropertyValue } from '../utils/get-property-value.js'
13
17
  import { resolveIdentifier } from '../utils/resolve-identifier.js'
18
+ import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
14
19
 
15
20
  // Track if we've warned about missing Config type to avoid duplicate warnings
16
21
  const configTypeWarningShown = new Set<string>()
@@ -151,14 +156,18 @@ function processCLIConfig(
151
156
  }
152
157
  break
153
158
 
154
- case 'render':
155
- // Extract the actual renderer function name
156
- programMeta.defaultRenderName = extractFunctionName(
159
+ case 'render': {
160
+ let renderFuncId = extractFunctionName(
157
161
  prop.initializer,
158
162
  typeChecker,
159
163
  inspectorState.rootDir
160
164
  ).pikkuFuncId
165
+ if (renderFuncId.startsWith('__temp_')) {
166
+ renderFuncId = makeContextBasedId('cli-render', programName)
167
+ }
168
+ programMeta.defaultRenderName = renderFuncId
161
169
  break
170
+ }
162
171
  }
163
172
  }
164
173
 
@@ -271,12 +280,16 @@ function processCommand(
271
280
  ts.isArrowFunction(node) ||
272
281
  ts.isFunctionExpression(node)
273
282
  ) {
283
+ let pikkuFuncId = extractFunctionName(
284
+ node,
285
+ typeChecker,
286
+ inspectorState.rootDir
287
+ ).pikkuFuncId
288
+ if (pikkuFuncId.startsWith('__temp_')) {
289
+ pikkuFuncId = makeContextBasedId('cli', programName, ...fullPath)
290
+ }
274
291
  return {
275
- pikkuFuncId: extractFunctionName(
276
- node,
277
- typeChecker,
278
- inspectorState.rootDir
279
- ).pikkuFuncId,
292
+ pikkuFuncId,
280
293
  positionals: [],
281
294
  options: {},
282
295
  }
@@ -336,6 +349,9 @@ function processCommand(
336
349
  typeChecker,
337
350
  inspectorState.rootDir
338
351
  ).pikkuFuncId
352
+ if (pikkuFuncId.startsWith('__temp_')) {
353
+ pikkuFuncId = makeContextBasedId('cli', programName, ...fullPath)
354
+ }
339
355
  meta.pikkuFuncId = pikkuFuncId
340
356
  } else if (
341
357
  propName === 'options' &&
@@ -391,13 +407,22 @@ function processCommand(
391
407
  // Already handled in first pass
392
408
  break
393
409
 
394
- case 'render':
395
- meta.renderName = extractFunctionName(
410
+ case 'render': {
411
+ let renderFuncId = extractFunctionName(
396
412
  prop.initializer,
397
413
  typeChecker,
398
414
  inspectorState.rootDir
399
415
  ).pikkuFuncId
416
+ if (renderFuncId.startsWith('__temp_')) {
417
+ renderFuncId = makeContextBasedId(
418
+ 'cli-render',
419
+ programName,
420
+ ...fullPath
421
+ )
422
+ }
423
+ meta.renderName = renderFuncId
400
424
  break
425
+ }
401
426
 
402
427
  case 'options':
403
428
  // Process with pikkuFuncId from first pass
@@ -453,12 +478,25 @@ function processCommand(
453
478
  }
454
479
  }
455
480
 
481
+ // --- validate auth/sessionless ---
482
+ if (
483
+ meta.pikkuFuncId &&
484
+ !validateAuthSessionless(
485
+ logger,
486
+ node,
487
+ inspectorState,
488
+ meta.pikkuFuncId,
489
+ `CLI command '${name}'`
490
+ )
491
+ ) {
492
+ return null
493
+ }
494
+
456
495
  // --- track used functions/middleware for service aggregation ---
457
496
  inspectorState.serviceAggregation.usedFunctions.add(meta.pikkuFuncId)
458
497
  extractWireNames(meta.middleware).forEach((name) =>
459
498
  inspectorState.serviceAggregation.usedMiddleware.add(name)
460
499
  )
461
- // Note: subcommands are tracked recursively when they're processed
462
500
 
463
501
  return meta
464
502
  }
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript'
2
- import { PathToNameAndType, InspectorState } from '../types.js'
2
+ import type { PathToNameAndType, InspectorState } from '../types.js'
3
3
 
4
4
  export const addFileExtendsCoreType = (
5
5
  node: ts.Node,
@@ -1,6 +1,6 @@
1
1
  import * as ts from 'typescript'
2
2
  import { doesTypeExtendsCore } from '../utils/does-type-extend-core-type.js'
3
- import { PathToNameAndType } from '../types.js'
3
+ import type { PathToNameAndType } from '../types.js'
4
4
 
5
5
  export const addFileWithConfig = (
6
6
  node: ts.Node,
@@ -1,13 +1,13 @@
1
1
  import * as ts from 'typescript'
2
- import { PathToNameAndType, InspectorState } from '../types.js'
2
+ import type { PathToNameAndType, InspectorState } from '../types.js'
3
3
  import { extractServicesFromFunction } from '../utils/extract-services.js'
4
4
 
5
5
  // Mapping of wrapper function names to their corresponding types
6
6
  const wrapperFunctionMap: Record<string, string> = {
7
7
  pikkuConfig: 'CreateConfig',
8
- pikkuExternalConfig: 'CreateConfig',
8
+ pikkuAddonConfig: 'CreateConfig',
9
9
  pikkuServices: 'CreateSingletonServices',
10
- pikkuExternalServices: 'CreateSingletonServices',
10
+ pikkuAddonServices: 'CreateSingletonServices',
11
11
  pikkuWireServices: 'CreateWireServices',
12
12
  }
13
13
 
@@ -1,14 +1,15 @@
1
1
  import * as ts from 'typescript'
2
- import { AddWiring, SchemaRef } from '../types.js'
2
+ import type { AddWiring, SchemaRef } from '../types.js'
3
3
  import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js'
4
- import { TypesMap } from '../types-map.js'
4
+ import type { TypesMap } from '../types-map.js'
5
5
  import {
6
6
  extractFunctionName,
7
7
  funcIdToTypeName,
8
8
  } from '../utils/extract-function-name.js'
9
9
  import { extractFunctionNode } from '../utils/extract-function-node.js'
10
10
  import { extractUsedWires } from '../utils/extract-services.js'
11
- import { FunctionServicesMeta, formatVersionedId } from '@pikku/core'
11
+ import type { FunctionServicesMeta } from '@pikku/core'
12
+ import { formatVersionedId } from '@pikku/core'
12
13
  import {
13
14
  getPropertyValue,
14
15
  getCommonWireMetaData,
@@ -216,9 +217,9 @@ const getNamesAndTypes = (
216
217
  const aliasName = funcIdToTypeName(funcName) + direction
217
218
 
218
219
  // record the alias in your TypesMap
219
- const references = rawTypes
220
- .map((t) => resolveTypeImports(t, typesMap, true, checker))
221
- .flat()
220
+ const references = rawTypes.flatMap((t) =>
221
+ resolveTypeImports(t, typesMap, true, checker)
222
+ )
222
223
 
223
224
  typesMap.addCustomType(aliasName, aliasType, references)
224
225
 
@@ -229,19 +230,17 @@ const getNamesAndTypes = (
229
230
  }
230
231
 
231
232
  // 4) Single, valid name → inline it
232
- const uniqueNames = rawNames
233
- .map((name, i) => {
234
- const t = rawTypes[i]
235
- if (!t) {
236
- throw new Error(`Expected type for name "${name}" in ${funcName}`)
237
- }
238
- if (isPrimitiveType(t)) {
239
- return name
240
- }
241
- // non-primitive: import/alias it inline
242
- return resolveTypeImports(t, typesMap, false, checker)
243
- })
244
- .flat()
233
+ const uniqueNames = rawNames.flatMap((name, i) => {
234
+ const t = rawTypes[i]
235
+ if (!t) {
236
+ throw new Error(`Expected type for name "${name}" in ${funcName}`)
237
+ }
238
+ if (isPrimitiveType(t)) {
239
+ return name
240
+ }
241
+ // non-primitive: import/alias it inline
242
+ return resolveTypeImports(t, typesMap, false, checker)
243
+ })
245
244
 
246
245
  return {
247
246
  names: uniqueNames,
@@ -339,6 +338,7 @@ export const addFunctions: AddWiring = (
339
338
  let expose: boolean | undefined
340
339
  let remote: boolean | undefined
341
340
  let mcp: boolean | undefined
341
+ let readonly_: boolean | undefined
342
342
  let requiresApproval: boolean | undefined
343
343
  let version: number | undefined
344
344
  let objectNode: ts.ObjectLiteralExpression | undefined
@@ -420,6 +420,7 @@ export const addFunctions: AddWiring = (
420
420
  expose = getPropertyValue(firstArg, 'expose') as boolean | undefined
421
421
  remote = getPropertyValue(firstArg, 'remote') as boolean | undefined
422
422
  mcp = getPropertyValue(firstArg, 'mcp') as boolean | undefined
423
+ readonly_ = getPropertyValue(firstArg, 'readonly') as boolean | undefined
423
424
  requiresApproval = getPropertyValue(firstArg, 'requiresApproval') as
424
425
  | boolean
425
426
  | undefined
@@ -757,6 +758,7 @@ export const addFunctions: AddWiring = (
757
758
  expose: expose || undefined,
758
759
  remote: remote || undefined,
759
760
  mcp: mcpEnabled || undefined,
761
+ readonly: readonly_ || undefined,
760
762
  requiresApproval: requiresApproval || undefined,
761
763
  version,
762
764
  title,
@@ -0,0 +1,95 @@
1
+ import * as ts from 'typescript'
2
+ import {
3
+ getPropertyValue,
4
+ getCommonWireMetaData,
5
+ } from '../utils/get-property-value.js'
6
+ import type { AddWiring } from '../types.js'
7
+ import {
8
+ extractFunctionName,
9
+ makeContextBasedId,
10
+ } from '../utils/extract-function-name.js'
11
+ import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
12
+ import { resolveMiddleware } from '../utils/middleware.js'
13
+ import { extractWireNames } from '../utils/post-process.js'
14
+ import type { GatewayTransportType } from '@pikku/core/gateway'
15
+
16
+ import { ErrorCode } from '../error-codes.js'
17
+
18
+ export const addGateway: AddWiring = (
19
+ logger,
20
+ node,
21
+ checker,
22
+ state,
23
+ _options
24
+ ) => {
25
+ if (!ts.isCallExpression(node)) {
26
+ return
27
+ }
28
+
29
+ const args = node.arguments
30
+ const firstArg = args[0]
31
+ const expression = node.expression
32
+
33
+ if (!ts.isIdentifier(expression) || expression.text !== 'wireGateway') {
34
+ return
35
+ }
36
+
37
+ if (!firstArg || !ts.isObjectLiteralExpression(firstArg)) {
38
+ return
39
+ }
40
+
41
+ const obj = firstArg
42
+
43
+ const nameValue = getPropertyValue(obj, 'name') as string | null
44
+ const typeValue = getPropertyValue(obj, 'type') as GatewayTransportType | null
45
+ const routeValue = getPropertyValue(obj, 'route') as string | undefined
46
+ const { disabled, tags, summary, description, errors } =
47
+ getCommonWireMetaData(obj, 'Gateway', nameValue, logger)
48
+
49
+ if (disabled) return
50
+
51
+ const funcInitializer = getPropertyAssignmentInitializer(
52
+ obj,
53
+ 'func',
54
+ true,
55
+ checker
56
+ )
57
+ if (!funcInitializer) {
58
+ logger.critical(
59
+ ErrorCode.MISSING_FUNC,
60
+ `No valid 'func' property for gateway '${nameValue}'.`
61
+ )
62
+ return
63
+ }
64
+
65
+ const extracted = extractFunctionName(funcInitializer, checker, state.rootDir)
66
+ let pikkuFuncId = extracted.pikkuFuncId
67
+ if (pikkuFuncId.startsWith('__temp_') && nameValue) {
68
+ pikkuFuncId = makeContextBasedId('gateway', nameValue)
69
+ }
70
+
71
+ if (!nameValue || !typeValue) {
72
+ return
73
+ }
74
+
75
+ const middleware = resolveMiddleware(state, obj, tags, checker)
76
+
77
+ state.serviceAggregation.usedFunctions.add(pikkuFuncId)
78
+ extractWireNames(middleware).forEach((name) =>
79
+ state.serviceAggregation.usedMiddleware.add(name)
80
+ )
81
+
82
+ state.gateways.files.add(node.getSourceFile().fileName)
83
+ state.gateways.meta[nameValue] = {
84
+ pikkuFuncId,
85
+ name: nameValue,
86
+ type: typeValue,
87
+ route: routeValue,
88
+ gateway: true,
89
+ summary,
90
+ description,
91
+ errors,
92
+ tags,
93
+ middleware,
94
+ }
95
+ }
@@ -4,7 +4,7 @@ import {
4
4
  getCommonWireMetaData,
5
5
  } from '../utils/get-property-value.js'
6
6
  import { pathToRegexp } from 'path-to-regexp'
7
- import { HTTPMethod } from '@pikku/core/http'
7
+ import type { HTTPMethod } from '@pikku/core/http'
8
8
  import {
9
9
  extractFunctionName,
10
10
  makeContextBasedId,
@@ -13,12 +13,13 @@ import {
13
13
  getPropertyAssignmentInitializer,
14
14
  extractTypeKeys,
15
15
  } from '../utils/type-utils.js'
16
- import { AddWiring, InspectorState } from '../types.js'
16
+ import type { AddWiring, InspectorState } from '../types.js'
17
17
  import { resolveHTTPMiddlewareFromObject } from '../utils/middleware.js'
18
18
  import { resolveHTTPPermissionsFromObject } from '../utils/permissions.js'
19
19
  import { extractWireNames } from '../utils/post-process.js'
20
20
  import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
21
21
  import { ErrorCode } from '../error-codes.js'
22
+ import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
22
23
  import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js'
23
24
 
24
25
  import type { InspectorLogger } from '../types.js'
@@ -34,6 +35,7 @@ export interface RegisterHTTPRouteParams {
34
35
  sourceFile: ts.SourceFile
35
36
  basePath?: string
36
37
  inheritedTags?: string[]
38
+ inheritedAuth?: boolean
37
39
  }
38
40
 
39
41
  /**
@@ -140,6 +142,7 @@ export function registerHTTPRoute({
140
142
  sourceFile,
141
143
  basePath = '',
142
144
  inheritedTags = [],
145
+ inheritedAuth,
143
146
  }: RegisterHTTPRouteParams): void {
144
147
  // Extract route path
145
148
  const routePath = getPropertyValue(obj, 'route') as string | null
@@ -218,6 +221,20 @@ export function registerHTTPRoute({
218
221
  )
219
222
  return
220
223
  }
224
+
225
+ if (
226
+ !validateAuthSessionless(
227
+ logger,
228
+ obj,
229
+ state,
230
+ funcName,
231
+ `Route '${fullRoute}'`,
232
+ inheritedAuth
233
+ )
234
+ ) {
235
+ return
236
+ }
237
+
221
238
  const input = fnMeta.inputs?.[0] || null
222
239
 
223
240
  // Validate that route params and query params exist in function input type
@@ -1,6 +1,6 @@
1
1
  import * as ts from 'typescript'
2
2
  import { getPropertyValue } from '../utils/get-property-value.js'
3
- import { AddWiring, InspectorState, InspectorLogger } from '../types.js'
3
+ import type { AddWiring, InspectorState, InspectorLogger } from '../types.js'
4
4
  import { registerHTTPRoute } from './add-http-route.js'
5
5
  import { resolveIdentifier } from '../utils/resolve-identifier.js'
6
6
 
@@ -224,5 +224,6 @@ function processRoute(
224
224
  sourceFile,
225
225
  basePath: groupConfig.basePath,
226
226
  inheritedTags: groupConfig.tags,
227
+ inheritedAuth: groupConfig.auth,
227
228
  })
228
229
  }
@@ -1,6 +1,6 @@
1
1
  import * as ts from 'typescript'
2
2
  import { getPropertyValue } from '../utils/get-property-value.js'
3
- import { AddWiring, InspectorState } from '../types.js'
3
+ import type { AddWiring, InspectorState } from '../types.js'
4
4
  import { ErrorCode } from '../error-codes.js'
5
5
  import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js'
6
6
 
@@ -5,7 +5,7 @@ import {
5
5
  } from '../utils/get-property-value.js'
6
6
  import { extractWireNames } from '../utils/post-process.js'
7
7
  import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
8
- import { AddWiring } from '../types.js'
8
+ import type { AddWiring } from '../types.js'
9
9
  import {
10
10
  extractFunctionName,
11
11
  makeContextBasedId,
@@ -5,7 +5,7 @@ import {
5
5
  } from '../utils/get-property-value.js'
6
6
  import { extractWireNames } from '../utils/post-process.js'
7
7
  import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
8
- import { AddWiring } from '../types.js'
8
+ import type { AddWiring } from '../types.js'
9
9
  import {
10
10
  extractFunctionName,
11
11
  makeContextBasedId,
@@ -3,7 +3,7 @@ import {
3
3
  getPropertyValue,
4
4
  getCommonWireMetaData,
5
5
  } from '../utils/get-property-value.js'
6
- import { AddWiring } from '../types.js'
6
+ import type { AddWiring } from '../types.js'
7
7
  import {
8
8
  extractFunctionName,
9
9
  makeContextBasedId,