@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.
- package/CHANGELOG.md +34 -0
- package/dist/add/add-ai-agent.d.ts +1 -1
- package/dist/add/add-ai-agent.js +1 -1
- package/dist/add/add-channel.js +14 -0
- package/dist/add/add-cli.d.ts +1 -1
- package/dist/add/add-cli.js +29 -8
- package/dist/add/add-file-extends-core-type.d.ts +1 -1
- package/dist/add/add-file-with-config.d.ts +1 -1
- package/dist/add/add-file-with-factory.d.ts +1 -1
- package/dist/add/add-file-with-factory.js +2 -2
- package/dist/add/add-functions.d.ts +1 -1
- package/dist/add/add-functions.js +6 -7
- package/dist/add/add-gateway.d.ts +2 -0
- package/dist/add/add-gateway.js +57 -0
- package/dist/add/add-http-route.d.ts +3 -2
- package/dist/add/add-http-route.js +5 -1
- package/dist/add/add-http-routes.d.ts +1 -1
- package/dist/add/add-http-routes.js +1 -0
- package/dist/add/add-keyed-wiring.d.ts +1 -1
- package/dist/add/add-mcp-prompt.d.ts +1 -1
- package/dist/add/add-mcp-resource.d.ts +1 -1
- package/dist/add/add-queue-worker.d.ts +1 -1
- package/dist/add/add-rpc-invocations.d.ts +3 -3
- package/dist/add/add-rpc-invocations.js +10 -10
- package/dist/add/add-schedule.d.ts +1 -1
- package/dist/add/add-secret.d.ts +1 -1
- package/dist/add/add-trigger.d.ts +1 -1
- package/dist/add/add-trigger.js +2 -2
- package/dist/add/add-wire-addon.d.ts +7 -0
- package/dist/add/add-wire-addon.js +70 -0
- package/dist/add/add-workflow.d.ts +1 -1
- package/dist/error-codes.d.ts +1 -0
- package/dist/error-codes.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/inspector.d.ts +1 -1
- package/dist/inspector.js +11 -4
- package/dist/types.d.ts +31 -20
- package/dist/utils/compute-required-schemas.js +1 -2
- package/dist/utils/contract-hashes.d.ts +20 -3
- package/dist/utils/contract-hashes.js +77 -10
- package/dist/utils/custom-types-generator.d.ts +1 -1
- package/dist/utils/detect-schema-vendor.d.ts +1 -1
- package/dist/utils/does-type-extend-core-type.d.ts +1 -1
- package/dist/utils/ensure-function-metadata.d.ts +1 -1
- package/dist/utils/extract-services.d.ts +1 -1
- package/dist/utils/filter-inspector-state.d.ts +1 -1
- package/dist/utils/filter-utils.d.ts +2 -2
- package/dist/utils/get-files-and-methods.d.ts +1 -1
- package/dist/utils/middleware.d.ts +2 -2
- package/dist/utils/permissions.d.ts +2 -2
- package/dist/utils/post-process.d.ts +4 -3
- package/dist/utils/post-process.js +24 -8
- package/dist/utils/resolve-addon-package.d.ts +16 -0
- package/dist/utils/{resolve-external-package.js → resolve-addon-package.js} +8 -8
- package/dist/utils/schema-generator.d.ts +2 -2
- package/dist/utils/serialize-inspector-state.d.ts +17 -3
- package/dist/utils/serialize-inspector-state.js +14 -2
- package/dist/utils/validate-auth-sessionless.d.ts +3 -0
- package/dist/utils/validate-auth-sessionless.js +14 -0
- package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +1 -1
- package/dist/visit.d.ts +1 -1
- package/dist/visit.js +4 -0
- package/package.json +3 -3
- package/src/add/add-ai-agent.ts +2 -2
- package/src/add/add-channel.ts +17 -0
- package/src/add/add-cli.ts +53 -15
- package/src/add/add-file-extends-core-type.ts +1 -1
- package/src/add/add-file-with-config.ts +1 -1
- package/src/add/add-file-with-factory.ts +3 -3
- package/src/add/add-functions.ts +21 -19
- package/src/add/add-gateway.ts +95 -0
- package/src/add/add-http-route.ts +19 -2
- package/src/add/add-http-routes.ts +2 -1
- package/src/add/add-keyed-wiring.ts +1 -1
- package/src/add/add-mcp-prompt.ts +1 -1
- package/src/add/add-mcp-resource.ts +1 -1
- package/src/add/add-queue-worker.ts +1 -1
- package/src/add/add-rpc-invocations.ts +11 -11
- package/src/add/add-schedule.ts +1 -1
- package/src/add/add-secret.ts +1 -1
- package/src/add/add-trigger.ts +4 -4
- package/src/add/add-wire-addon.ts +80 -0
- package/src/add/add-workflow.ts +2 -2
- package/src/error-codes.ts +1 -0
- package/src/index.ts +1 -0
- package/src/inspector.ts +17 -5
- package/src/types.ts +38 -20
- package/src/utils/compute-required-schemas.ts +1 -2
- package/src/utils/contract-hashes.test.ts +30 -5
- package/src/utils/contract-hashes.ts +110 -14
- package/src/utils/custom-types-generator.ts +1 -1
- package/src/utils/detect-schema-vendor.ts +1 -1
- package/src/utils/does-type-extend-core-type.ts +1 -1
- package/src/utils/ensure-function-metadata.ts +1 -1
- package/src/utils/extract-services.ts +1 -1
- package/src/utils/filter-inspector-state.test.ts +3 -5
- package/src/utils/filter-inspector-state.ts +7 -2
- package/src/utils/filter-utils.test.ts +1 -1
- package/src/utils/filter-utils.ts +2 -2
- package/src/utils/get-files-and-methods.ts +1 -1
- package/src/utils/middleware.ts +2 -2
- package/src/utils/permissions.ts +2 -2
- package/src/utils/post-process.ts +34 -12
- package/src/utils/{resolve-external-package.ts → resolve-addon-package.ts} +17 -10
- package/src/utils/resolve-versions.test.ts +1 -1
- package/src/utils/schema-generator.ts +4 -4
- package/src/utils/serialize-inspector-state.ts +35 -5
- package/src/utils/validate-auth-sessionless.ts +29 -0
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +2 -2
- package/src/visit.ts +9 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/resolve-external-package.d.ts +0 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
## 0.12.0
|
|
2
2
|
|
|
3
|
+
## 0.12.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3e04565: chore: update dependencies to latest minor/patch versions
|
|
8
|
+
- Updated dependencies [cc4c9e9]
|
|
9
|
+
- Updated dependencies [3e04565]
|
|
10
|
+
- @pikku/core@0.12.2
|
|
11
|
+
|
|
12
|
+
## 0.12.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 62a8725: Rename 'external' to 'addon' throughout the codebase. All types, functions, config keys, and CLI options previously named `external` or `External` are now named `addon` or `Addon` (e.g. `ExternalPackageConfig` → `AddonConfig`, `externalPackages` → `addons`, `function-external` → `function-addon`).
|
|
17
|
+
- 8eed717: Add `readonly` flag to function config and runtime enforcement. Functions can be marked `readonly: true` in their config. At runtime, if a session has `readonly: true`, only functions marked as readonly can be called — otherwise a `ReadonlySessionError` (403) is thrown.
|
|
18
|
+
- 62a8725: `pikku versions check` now prints rich, human-readable output for all contract version errors instead of raw error codes. Each error type (PKU861–PKU865) shows the function name, separate input/output schema hashes with a `prev → current` arrow, and clear next-step instructions.
|
|
19
|
+
|
|
20
|
+
The version manifest now stores separate `inputHash` and `outputHash` per version entry (backward-compatible — old string-hash manifests still load and validate correctly). `VersionValidateError` gains optional detail fields (`functionKey`, `version`, `previousInputHash`, `currentInputHash`, `previousOutputHash`, `currentOutputHash`, `nextVersion`, `latestVersion`, `expectedNextVersion`) for use by tooling.
|
|
21
|
+
|
|
22
|
+
- 62a8725: Replace config-based addon declarations with the new `wireAddon()` code-based API. Addons are now declared directly in wiring files using `wireAddon({ name, package, rpcEndpoint?, auth?, tags? })` instead of the `addons` field in `pikku.config.json`. The inspector reads these declarations from the TypeScript AST at build time.
|
|
23
|
+
- 62a8725: Add `secretOverrides` and `variableOverrides` support to `wireAddon()`. These optional maps allow an app to remap an addon's secret/variable keys to its own names (e.g. `secretOverrides: { SENDGRID_API_KEY: 'MY_EMAIL_API_KEY' }`). The inspector validates that all override keys exist in the app's own secrets/variables definitions.
|
|
24
|
+
- Updated dependencies [62a8725]
|
|
25
|
+
- Updated dependencies [a3bdb0d]
|
|
26
|
+
- Updated dependencies [e0349ff]
|
|
27
|
+
- Updated dependencies [62a8725]
|
|
28
|
+
- Updated dependencies [e04531f]
|
|
29
|
+
- Updated dependencies [62a8725]
|
|
30
|
+
- Updated dependencies [a83efb8]
|
|
31
|
+
- Updated dependencies [8eed717]
|
|
32
|
+
- Updated dependencies [62a8725]
|
|
33
|
+
- Updated dependencies [62a8725]
|
|
34
|
+
- Updated dependencies [62a8725]
|
|
35
|
+
- @pikku/core@0.12.1
|
|
36
|
+
|
|
3
37
|
### New Features
|
|
4
38
|
|
|
5
39
|
- AI agent metadata extraction
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddWiring } from '../types.js';
|
|
1
|
+
import type { AddWiring } from '../types.js';
|
|
2
2
|
export declare const addAIAgent: AddWiring;
|
package/dist/add/add-ai-agent.js
CHANGED
|
@@ -33,7 +33,7 @@ function resolveToolReferences(obj, checker, agentName, logger) {
|
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
if (calleeName === '
|
|
36
|
+
if (calleeName === 'addon') {
|
|
37
37
|
const [firstArg] = element.arguments;
|
|
38
38
|
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
39
39
|
resolved.push(firstArg.text);
|
package/dist/add/add-channel.js
CHANGED
|
@@ -7,6 +7,7 @@ import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
|
7
7
|
import { resolveMiddleware, resolveChannelMiddleware, } from '../utils/middleware.js';
|
|
8
8
|
import { extractWireNames } from '../utils/post-process.js';
|
|
9
9
|
import { resolveIdentifier } from '../utils/resolve-identifier.js';
|
|
10
|
+
import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js';
|
|
10
11
|
/**
|
|
11
12
|
* Safely get the "initializer" expression of a property-like AST node:
|
|
12
13
|
* - for `foo: expr`, returns `expr`
|
|
@@ -365,6 +366,7 @@ export const addChannel = (logger, node, checker, state, options) => {
|
|
|
365
366
|
if (disabled)
|
|
366
367
|
return;
|
|
367
368
|
const query = getPropertyValue(obj, 'query');
|
|
369
|
+
const binary = getPropertyValue(obj, 'binary');
|
|
368
370
|
const connect = getPropertyAssignmentInitializer(obj, 'onConnect', true, checker);
|
|
369
371
|
const disconnect = getPropertyAssignmentInitializer(obj, 'onDisconnect', true, checker);
|
|
370
372
|
// default onMessage handler
|
|
@@ -416,6 +418,17 @@ export const addChannel = (logger, node, checker, state, options) => {
|
|
|
416
418
|
}
|
|
417
419
|
}
|
|
418
420
|
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
421
|
+
// --- validate auth/sessionless ---
|
|
422
|
+
const handlersToValidate = [
|
|
423
|
+
connectFuncId,
|
|
424
|
+
disconnectFuncId,
|
|
425
|
+
message?.pikkuFuncId,
|
|
426
|
+
].filter(Boolean);
|
|
427
|
+
for (const funcId of handlersToValidate) {
|
|
428
|
+
if (!validateAuthSessionless(logger, obj, state, funcId, `Channel '${name}'`)) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
419
432
|
state.channels.files.add(node.getSourceFile().fileName);
|
|
420
433
|
state.channels.meta[name] = {
|
|
421
434
|
name,
|
|
@@ -427,6 +440,7 @@ export const addChannel = (logger, node, checker, state, options) => {
|
|
|
427
440
|
disconnect: disconnectFuncId ? { pikkuFuncId: disconnectFuncId } : null,
|
|
428
441
|
message,
|
|
429
442
|
messageWirings,
|
|
443
|
+
binary: binary === undefined ? undefined : binary,
|
|
430
444
|
summary,
|
|
431
445
|
description,
|
|
432
446
|
errors,
|
package/dist/add/add-cli.d.ts
CHANGED
package/dist/add/add-cli.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
-
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
2
|
+
import { extractFunctionName, makeContextBasedId, } from '../utils/extract-function-name.js';
|
|
3
3
|
import { resolveMiddleware } from '../utils/middleware.js';
|
|
4
4
|
import { extractWireNames } from '../utils/post-process.js';
|
|
5
5
|
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
6
6
|
import { resolveIdentifier } from '../utils/resolve-identifier.js';
|
|
7
|
+
import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js';
|
|
7
8
|
// Track if we've warned about missing Config type to avoid duplicate warnings
|
|
8
9
|
const configTypeWarningShown = new Set();
|
|
9
10
|
/**
|
|
@@ -94,10 +95,14 @@ function processCLIConfig(logger, node, sourceFile, typeChecker, inspectorState,
|
|
|
94
95
|
programMeta.options = processOptions(logger, prop.initializer, typeChecker, inspectorState, options);
|
|
95
96
|
}
|
|
96
97
|
break;
|
|
97
|
-
case 'render':
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
case 'render': {
|
|
99
|
+
let renderFuncId = extractFunctionName(prop.initializer, typeChecker, inspectorState.rootDir).pikkuFuncId;
|
|
100
|
+
if (renderFuncId.startsWith('__temp_')) {
|
|
101
|
+
renderFuncId = makeContextBasedId('cli-render', programName);
|
|
102
|
+
}
|
|
103
|
+
programMeta.defaultRenderName = renderFuncId;
|
|
100
104
|
break;
|
|
105
|
+
}
|
|
101
106
|
}
|
|
102
107
|
}
|
|
103
108
|
return { programName, programMeta };
|
|
@@ -155,8 +160,12 @@ function processCommand(logger, inspectorState, options, name, node, sourceFile,
|
|
|
155
160
|
if (ts.isIdentifier(node) ||
|
|
156
161
|
ts.isArrowFunction(node) ||
|
|
157
162
|
ts.isFunctionExpression(node)) {
|
|
163
|
+
let pikkuFuncId = extractFunctionName(node, typeChecker, inspectorState.rootDir).pikkuFuncId;
|
|
164
|
+
if (pikkuFuncId.startsWith('__temp_')) {
|
|
165
|
+
pikkuFuncId = makeContextBasedId('cli', programName, ...fullPath);
|
|
166
|
+
}
|
|
158
167
|
return {
|
|
159
|
-
pikkuFuncId
|
|
168
|
+
pikkuFuncId,
|
|
160
169
|
positionals: [],
|
|
161
170
|
options: {},
|
|
162
171
|
};
|
|
@@ -194,6 +203,9 @@ function processCommand(logger, inspectorState, options, name, node, sourceFile,
|
|
|
194
203
|
const propName = prop.name.text;
|
|
195
204
|
if (propName === 'func') {
|
|
196
205
|
pikkuFuncId = extractFunctionName(prop.initializer, typeChecker, inspectorState.rootDir).pikkuFuncId;
|
|
206
|
+
if (pikkuFuncId.startsWith('__temp_')) {
|
|
207
|
+
pikkuFuncId = makeContextBasedId('cli', programName, ...fullPath);
|
|
208
|
+
}
|
|
197
209
|
meta.pikkuFuncId = pikkuFuncId;
|
|
198
210
|
}
|
|
199
211
|
else if (propName === 'options' &&
|
|
@@ -237,9 +249,14 @@ function processCommand(logger, inspectorState, options, name, node, sourceFile,
|
|
|
237
249
|
case 'func':
|
|
238
250
|
// Already handled in first pass
|
|
239
251
|
break;
|
|
240
|
-
case 'render':
|
|
241
|
-
|
|
252
|
+
case 'render': {
|
|
253
|
+
let renderFuncId = extractFunctionName(prop.initializer, typeChecker, inspectorState.rootDir).pikkuFuncId;
|
|
254
|
+
if (renderFuncId.startsWith('__temp_')) {
|
|
255
|
+
renderFuncId = makeContextBasedId('cli-render', programName, ...fullPath);
|
|
256
|
+
}
|
|
257
|
+
meta.renderName = renderFuncId;
|
|
242
258
|
break;
|
|
259
|
+
}
|
|
243
260
|
case 'options':
|
|
244
261
|
// Process with pikkuFuncId from first pass
|
|
245
262
|
if (optionsNode) {
|
|
@@ -270,10 +287,14 @@ function processCommand(logger, inspectorState, options, name, node, sourceFile,
|
|
|
270
287
|
break;
|
|
271
288
|
}
|
|
272
289
|
}
|
|
290
|
+
// --- validate auth/sessionless ---
|
|
291
|
+
if (meta.pikkuFuncId &&
|
|
292
|
+
!validateAuthSessionless(logger, node, inspectorState, meta.pikkuFuncId, `CLI command '${name}'`)) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
273
295
|
// --- track used functions/middleware for service aggregation ---
|
|
274
296
|
inspectorState.serviceAggregation.usedFunctions.add(meta.pikkuFuncId);
|
|
275
297
|
extractWireNames(meta.middleware).forEach((name) => inspectorState.serviceAggregation.usedMiddleware.add(name));
|
|
276
|
-
// Note: subcommands are tracked recursively when they're processed
|
|
277
298
|
return meta;
|
|
278
299
|
}
|
|
279
300
|
/**
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { PathToNameAndType, InspectorState } from '../types.js';
|
|
2
|
+
import type { PathToNameAndType, InspectorState } from '../types.js';
|
|
3
3
|
export declare const addFileExtendsCoreType: (node: ts.Node, checker: ts.TypeChecker, methods: PathToNameAndType, expectedTypeName: string, state?: InspectorState) => void;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { PathToNameAndType, InspectorState } from '../types.js';
|
|
2
|
+
import type { PathToNameAndType, InspectorState } from '../types.js';
|
|
3
3
|
export declare const addFileWithFactory: (node: ts.Node, checker: ts.TypeChecker, methods: PathToNameAndType | undefined, expectedTypeName: string, state?: InspectorState) => void;
|
|
@@ -3,9 +3,9 @@ import { extractServicesFromFunction } from '../utils/extract-services.js';
|
|
|
3
3
|
// Mapping of wrapper function names to their corresponding types
|
|
4
4
|
const wrapperFunctionMap = {
|
|
5
5
|
pikkuConfig: 'CreateConfig',
|
|
6
|
-
|
|
6
|
+
pikkuAddonConfig: 'CreateConfig',
|
|
7
7
|
pikkuServices: 'CreateSingletonServices',
|
|
8
|
-
|
|
8
|
+
pikkuAddonServices: 'CreateSingletonServices',
|
|
9
9
|
pikkuWireServices: 'CreateWireServices',
|
|
10
10
|
};
|
|
11
11
|
export const addFileWithFactory = (node, checker, methods = new Map(), expectedTypeName, state) => {
|
|
@@ -154,9 +154,7 @@ const getNamesAndTypes = (checker, typesMap, direction, funcName, type) => {
|
|
|
154
154
|
const aliasType = rawNames.join(' | ');
|
|
155
155
|
const aliasName = funcIdToTypeName(funcName) + direction;
|
|
156
156
|
// record the alias in your TypesMap
|
|
157
|
-
const references = rawTypes
|
|
158
|
-
.map((t) => resolveTypeImports(t, typesMap, true, checker))
|
|
159
|
-
.flat();
|
|
157
|
+
const references = rawTypes.flatMap((t) => resolveTypeImports(t, typesMap, true, checker));
|
|
160
158
|
typesMap.addCustomType(aliasName, aliasType, references);
|
|
161
159
|
return {
|
|
162
160
|
names: [aliasName],
|
|
@@ -164,8 +162,7 @@ const getNamesAndTypes = (checker, typesMap, direction, funcName, type) => {
|
|
|
164
162
|
};
|
|
165
163
|
}
|
|
166
164
|
// 4) Single, valid name → inline it
|
|
167
|
-
const uniqueNames = rawNames
|
|
168
|
-
.map((name, i) => {
|
|
165
|
+
const uniqueNames = rawNames.flatMap((name, i) => {
|
|
169
166
|
const t = rawTypes[i];
|
|
170
167
|
if (!t) {
|
|
171
168
|
throw new Error(`Expected type for name "${name}" in ${funcName}`);
|
|
@@ -175,8 +172,7 @@ const getNamesAndTypes = (checker, typesMap, direction, funcName, type) => {
|
|
|
175
172
|
}
|
|
176
173
|
// non-primitive: import/alias it inline
|
|
177
174
|
return resolveTypeImports(t, typesMap, false, checker);
|
|
178
|
-
})
|
|
179
|
-
.flat();
|
|
175
|
+
});
|
|
180
176
|
return {
|
|
181
177
|
names: uniqueNames,
|
|
182
178
|
types: rawTypes,
|
|
@@ -248,6 +244,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
248
244
|
let expose;
|
|
249
245
|
let remote;
|
|
250
246
|
let mcp;
|
|
247
|
+
let readonly_;
|
|
251
248
|
let requiresApproval;
|
|
252
249
|
let version;
|
|
253
250
|
let objectNode;
|
|
@@ -313,6 +310,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
313
310
|
expose = getPropertyValue(firstArg, 'expose');
|
|
314
311
|
remote = getPropertyValue(firstArg, 'remote');
|
|
315
312
|
mcp = getPropertyValue(firstArg, 'mcp');
|
|
313
|
+
readonly_ = getPropertyValue(firstArg, 'readonly');
|
|
316
314
|
requiresApproval = getPropertyValue(firstArg, 'requiresApproval');
|
|
317
315
|
const versionRaw = getPropertyValue(firstArg, 'version');
|
|
318
316
|
if (versionRaw !== null && versionRaw !== undefined) {
|
|
@@ -566,6 +564,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
566
564
|
expose: expose || undefined,
|
|
567
565
|
remote: remote || undefined,
|
|
568
566
|
mcp: mcpEnabled || undefined,
|
|
567
|
+
readonly: readonly_ || undefined,
|
|
569
568
|
requiresApproval: requiresApproval || undefined,
|
|
570
569
|
version,
|
|
571
570
|
title,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
3
|
+
import { extractFunctionName, makeContextBasedId, } from '../utils/extract-function-name.js';
|
|
4
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
5
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
6
|
+
import { extractWireNames } from '../utils/post-process.js';
|
|
7
|
+
import { ErrorCode } from '../error-codes.js';
|
|
8
|
+
export const addGateway = (logger, node, checker, state, _options) => {
|
|
9
|
+
if (!ts.isCallExpression(node)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const args = node.arguments;
|
|
13
|
+
const firstArg = args[0];
|
|
14
|
+
const expression = node.expression;
|
|
15
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireGateway') {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (!firstArg || !ts.isObjectLiteralExpression(firstArg)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const obj = firstArg;
|
|
22
|
+
const nameValue = getPropertyValue(obj, 'name');
|
|
23
|
+
const typeValue = getPropertyValue(obj, 'type');
|
|
24
|
+
const routeValue = getPropertyValue(obj, 'route');
|
|
25
|
+
const { disabled, tags, summary, description, errors } = getCommonWireMetaData(obj, 'Gateway', nameValue, logger);
|
|
26
|
+
if (disabled)
|
|
27
|
+
return;
|
|
28
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
29
|
+
if (!funcInitializer) {
|
|
30
|
+
logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for gateway '${nameValue}'.`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const extracted = extractFunctionName(funcInitializer, checker, state.rootDir);
|
|
34
|
+
let pikkuFuncId = extracted.pikkuFuncId;
|
|
35
|
+
if (pikkuFuncId.startsWith('__temp_') && nameValue) {
|
|
36
|
+
pikkuFuncId = makeContextBasedId('gateway', nameValue);
|
|
37
|
+
}
|
|
38
|
+
if (!nameValue || !typeValue) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
42
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncId);
|
|
43
|
+
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
44
|
+
state.gateways.files.add(node.getSourceFile().fileName);
|
|
45
|
+
state.gateways.meta[nameValue] = {
|
|
46
|
+
pikkuFuncId,
|
|
47
|
+
name: nameValue,
|
|
48
|
+
type: typeValue,
|
|
49
|
+
route: routeValue,
|
|
50
|
+
gateway: true,
|
|
51
|
+
summary,
|
|
52
|
+
description,
|
|
53
|
+
errors,
|
|
54
|
+
tags,
|
|
55
|
+
middleware,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { AddWiring, InspectorState } from '../types.js';
|
|
2
|
+
import type { AddWiring, InspectorState } from '../types.js';
|
|
3
3
|
import type { InspectorLogger } from '../types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Parameters for registering an HTTP route
|
|
@@ -12,12 +12,13 @@ export interface RegisterHTTPRouteParams {
|
|
|
12
12
|
sourceFile: ts.SourceFile;
|
|
13
13
|
basePath?: string;
|
|
14
14
|
inheritedTags?: string[];
|
|
15
|
+
inheritedAuth?: boolean;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* Shared function to register an HTTP route in the inspector state.
|
|
18
19
|
* Used by both wireHTTP and wireHTTPRoutes.
|
|
19
20
|
*/
|
|
20
|
-
export declare function registerHTTPRoute({ obj, state, checker, logger, sourceFile, basePath, inheritedTags, }: RegisterHTTPRouteParams): void;
|
|
21
|
+
export declare function registerHTTPRoute({ obj, state, checker, logger, sourceFile, basePath, inheritedTags, inheritedAuth, }: RegisterHTTPRouteParams): void;
|
|
21
22
|
/**
|
|
22
23
|
* Process wireHTTP calls
|
|
23
24
|
*/
|
|
@@ -8,6 +8,7 @@ import { resolveHTTPPermissionsFromObject } from '../utils/permissions.js';
|
|
|
8
8
|
import { extractWireNames } from '../utils/post-process.js';
|
|
9
9
|
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
|
|
10
10
|
import { ErrorCode } from '../error-codes.js';
|
|
11
|
+
import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js';
|
|
11
12
|
import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js';
|
|
12
13
|
/**
|
|
13
14
|
* Extract header schema reference from headers property
|
|
@@ -76,7 +77,7 @@ const computeInputTypes = (metaTypes, methodType, inputType, queryValues, params
|
|
|
76
77
|
* Shared function to register an HTTP route in the inspector state.
|
|
77
78
|
* Used by both wireHTTP and wireHTTPRoutes.
|
|
78
79
|
*/
|
|
79
|
-
export function registerHTTPRoute({ obj, state, checker, logger, sourceFile, basePath = '', inheritedTags = [], }) {
|
|
80
|
+
export function registerHTTPRoute({ obj, state, checker, logger, sourceFile, basePath = '', inheritedTags = [], inheritedAuth, }) {
|
|
80
81
|
// Extract route path
|
|
81
82
|
const routePath = getPropertyValue(obj, 'route');
|
|
82
83
|
if (!routePath)
|
|
@@ -118,6 +119,9 @@ export function registerHTTPRoute({ obj, state, checker, logger, sourceFile, bas
|
|
|
118
119
|
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for '${funcName}'.`);
|
|
119
120
|
return;
|
|
120
121
|
}
|
|
122
|
+
if (!validateAuthSessionless(logger, obj, state, funcName, `Route '${fullRoute}'`, inheritedAuth)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
121
125
|
const input = fnMeta.inputs?.[0] || null;
|
|
122
126
|
// Validate that route params and query params exist in function input type
|
|
123
127
|
if (params.length > 0 || query.length > 0) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddWiring } from '../types.js';
|
|
1
|
+
import type { AddWiring } from '../types.js';
|
|
2
2
|
export declare const addMCPPrompt: AddWiring;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddWiring } from '../types.js';
|
|
1
|
+
import type { AddWiring } from '../types.js';
|
|
2
2
|
export declare const addMCPResource: AddWiring;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddWiring } from '../types.js';
|
|
1
|
+
import type { AddWiring } from '../types.js';
|
|
2
2
|
export declare const addQueueWorker: AddWiring;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { InspectorState, InspectorLogger } from '../types.js';
|
|
2
|
+
import type { InspectorState, InspectorLogger } from '../types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Scan for rpc.invoke() calls to track which functions are actually being invoked
|
|
5
|
-
* Also detects
|
|
5
|
+
* Also detects addon usage via:
|
|
6
6
|
* - Namespaced calls: rpc.invoke('namespace:function')
|
|
7
|
-
* -
|
|
7
|
+
* - Addon helper: addon('namespace:function')
|
|
8
8
|
*/
|
|
9
9
|
export declare function addRPCInvocations(node: ts.Node, state: InspectorState, logger: InspectorLogger): void;
|
|
@@ -11,25 +11,25 @@ function extractNamespace(functionRef) {
|
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Scan for rpc.invoke() calls to track which functions are actually being invoked
|
|
14
|
-
* Also detects
|
|
14
|
+
* Also detects addon usage via:
|
|
15
15
|
* - Namespaced calls: rpc.invoke('namespace:function')
|
|
16
|
-
* -
|
|
16
|
+
* - Addon helper: addon('namespace:function')
|
|
17
17
|
*/
|
|
18
18
|
export function addRPCInvocations(node, state, logger) {
|
|
19
|
-
// Look for call expressions:
|
|
19
|
+
// Look for call expressions: addon('ext:hello') or rpc.invoke('...')
|
|
20
20
|
if (ts.isCallExpression(node)) {
|
|
21
21
|
const { expression, arguments: args } = node;
|
|
22
|
-
// Check for
|
|
23
|
-
if (ts.isIdentifier(expression) && expression.text === '
|
|
22
|
+
// Check for addon('namespace:function') calls
|
|
23
|
+
if (ts.isIdentifier(expression) && expression.text === 'addon') {
|
|
24
24
|
const [firstArg] = args;
|
|
25
25
|
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
26
26
|
const functionRef = firstArg.text;
|
|
27
|
-
logger.debug(`• Found
|
|
27
|
+
logger.debug(`• Found addon() call: ${functionRef}`);
|
|
28
28
|
state.rpc.invokedFunctions.add(functionRef);
|
|
29
29
|
const namespace = extractNamespace(functionRef);
|
|
30
30
|
if (namespace) {
|
|
31
|
-
logger.debug(` →
|
|
32
|
-
state.rpc.
|
|
31
|
+
logger.debug(` → Addon detected: ${namespace}`);
|
|
32
|
+
state.rpc.usedAddons.add(namespace);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
}
|
|
@@ -60,8 +60,8 @@ export function addRPCInvocations(node, state, logger) {
|
|
|
60
60
|
state.rpc.invokedFunctions.add(functionRef);
|
|
61
61
|
const namespace = extractNamespace(functionRef);
|
|
62
62
|
if (namespace) {
|
|
63
|
-
logger.debug(` →
|
|
64
|
-
state.rpc.
|
|
63
|
+
logger.debug(` → Addon detected: ${namespace}`);
|
|
64
|
+
state.rpc.usedAddons.add(namespace);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
// Handle template literals like `function-${name}`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddWiring } from '../types.js';
|
|
1
|
+
import type { AddWiring } from '../types.js';
|
|
2
2
|
export declare const addSchedule: AddWiring;
|
package/dist/add/add-secret.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddWiring } from '../types.js';
|
|
1
|
+
import type { AddWiring } from '../types.js';
|
|
2
2
|
export declare const addTrigger: AddWiring;
|
package/dist/add/add-trigger.js
CHANGED
|
@@ -4,7 +4,7 @@ import { extractFunctionName, makeContextBasedId, } from '../utils/extract-funct
|
|
|
4
4
|
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
5
5
|
import { resolveMiddleware } from '../utils/middleware.js';
|
|
6
6
|
import { extractWireNames } from '../utils/post-process.js';
|
|
7
|
-
import {
|
|
7
|
+
import { resolveAddonName } from '../utils/resolve-addon-package.js';
|
|
8
8
|
import { ErrorCode } from '../error-codes.js';
|
|
9
9
|
export const addTrigger = (logger, node, checker, state, options) => {
|
|
10
10
|
if (!ts.isCallExpression(node)) {
|
|
@@ -76,7 +76,7 @@ const addWireTriggerSource = (logger, node, checker, state, options, firstArg) =
|
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
if (ts.isIdentifier(funcInitializer)) {
|
|
79
|
-
const packageName =
|
|
79
|
+
const packageName = resolveAddonName(funcInitializer, checker, state.rpc.wireAddonDeclarations);
|
|
80
80
|
state.triggers.sourceMeta[nameValue] = {
|
|
81
81
|
name: nameValue,
|
|
82
82
|
pikkuFuncId: funcInitializer.text,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import type { InspectorState, InspectorLogger } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detect wireAddon({ name: '...', package: '...' }) call expressions and
|
|
5
|
+
* populate state.rpc.wireAddonDeclarations and state.rpc.usedAddons.
|
|
6
|
+
*/
|
|
7
|
+
export declare function addWireAddon(node: ts.Node, state: InspectorState, logger: InspectorLogger): void;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
function parseStringRecord(obj) {
|
|
3
|
+
const result = {};
|
|
4
|
+
for (const prop of obj.properties) {
|
|
5
|
+
if (!ts.isPropertyAssignment(prop))
|
|
6
|
+
continue;
|
|
7
|
+
const keyNode = prop.name;
|
|
8
|
+
const key = ts.isIdentifier(keyNode)
|
|
9
|
+
? keyNode.text
|
|
10
|
+
: ts.isStringLiteral(keyNode)
|
|
11
|
+
? keyNode.text
|
|
12
|
+
: undefined;
|
|
13
|
+
if (key && ts.isStringLiteral(prop.initializer)) {
|
|
14
|
+
result[key] = prop.initializer.text;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Detect wireAddon({ name: '...', package: '...' }) call expressions and
|
|
21
|
+
* populate state.rpc.wireAddonDeclarations and state.rpc.usedAddons.
|
|
22
|
+
*/
|
|
23
|
+
export function addWireAddon(node, state, logger) {
|
|
24
|
+
if (!ts.isCallExpression(node))
|
|
25
|
+
return;
|
|
26
|
+
const { expression, arguments: args } = node;
|
|
27
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireAddon')
|
|
28
|
+
return;
|
|
29
|
+
const [firstArg] = args;
|
|
30
|
+
if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
|
|
31
|
+
return;
|
|
32
|
+
let name;
|
|
33
|
+
let pkg;
|
|
34
|
+
let rpcEndpoint;
|
|
35
|
+
let secretOverrides;
|
|
36
|
+
let variableOverrides;
|
|
37
|
+
for (const prop of firstArg.properties) {
|
|
38
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
|
|
39
|
+
continue;
|
|
40
|
+
const key = prop.name.text;
|
|
41
|
+
if (key === 'name' && ts.isStringLiteral(prop.initializer)) {
|
|
42
|
+
name = prop.initializer.text;
|
|
43
|
+
}
|
|
44
|
+
else if (key === 'package' && ts.isStringLiteral(prop.initializer)) {
|
|
45
|
+
pkg = prop.initializer.text;
|
|
46
|
+
}
|
|
47
|
+
else if (key === 'rpcEndpoint' && ts.isStringLiteral(prop.initializer)) {
|
|
48
|
+
rpcEndpoint = prop.initializer.text;
|
|
49
|
+
}
|
|
50
|
+
else if (key === 'secretOverrides' &&
|
|
51
|
+
ts.isObjectLiteralExpression(prop.initializer)) {
|
|
52
|
+
secretOverrides = parseStringRecord(prop.initializer);
|
|
53
|
+
}
|
|
54
|
+
else if (key === 'variableOverrides' &&
|
|
55
|
+
ts.isObjectLiteralExpression(prop.initializer)) {
|
|
56
|
+
variableOverrides = parseStringRecord(prop.initializer);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (!name || !pkg)
|
|
60
|
+
return;
|
|
61
|
+
logger.debug(`• Found wireAddon: ${name} → ${pkg}`);
|
|
62
|
+
state.rpc.wireAddonDeclarations.set(name, {
|
|
63
|
+
package: pkg,
|
|
64
|
+
rpcEndpoint,
|
|
65
|
+
secretOverrides,
|
|
66
|
+
variableOverrides,
|
|
67
|
+
});
|
|
68
|
+
state.rpc.usedAddons.add(name);
|
|
69
|
+
state.rpc.wireAddonFiles.add(node.getSourceFile().fileName);
|
|
70
|
+
}
|
package/dist/error-codes.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare enum ErrorCode {
|
|
|
31
31
|
HANDLER_NOT_RESOLVED = "PKU568",
|
|
32
32
|
ROUTE_PARAM_MISMATCH = "PKU571",
|
|
33
33
|
ROUTE_QUERY_MISMATCH = "PKU572",
|
|
34
|
+
AUTH_DISABLED_REQUIRES_SESSIONLESS = "PKU573",
|
|
34
35
|
MIDDLEWARE_HANDLER_INVALID = "PKU685",
|
|
35
36
|
MIDDLEWARE_TAG_INVALID = "PKU715",
|
|
36
37
|
MIDDLEWARE_EMPTY_ARRAY = "PKU736",
|
package/dist/error-codes.js
CHANGED
|
@@ -36,6 +36,7 @@ export var ErrorCode;
|
|
|
36
36
|
// HTTP Route errors
|
|
37
37
|
ErrorCode["ROUTE_PARAM_MISMATCH"] = "PKU571";
|
|
38
38
|
ErrorCode["ROUTE_QUERY_MISMATCH"] = "PKU572";
|
|
39
|
+
ErrorCode["AUTH_DISABLED_REQUIRES_SESSIONLESS"] = "PKU573";
|
|
39
40
|
// Middleware/Permission errors
|
|
40
41
|
ErrorCode["MIDDLEWARE_HANDLER_INVALID"] = "PKU685";
|
|
41
42
|
ErrorCode["MIDDLEWARE_TAG_INVALID"] = "PKU715";
|