@pikku/inspector 0.12.41 → 0.12.43
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 +104 -0
- package/dist/add/add-addon-bans.js +1 -0
- package/dist/add/add-ai-agent.d.ts +3 -1
- package/dist/add/add-ai-agent.js +82 -0
- package/dist/add/add-credential.js +3 -1
- package/dist/add/add-functions.js +10 -9
- package/dist/add/add-gateway.js +3 -0
- package/dist/add/add-http-route.js +2 -2
- package/dist/add/add-mcp-prompt.js +0 -1
- package/dist/add/add-mcp-resource.js +0 -1
- package/dist/add/add-permission.d.ts +1 -1
- package/dist/add/add-permission.js +3 -177
- package/dist/add/add-queue-worker.js +3 -0
- package/dist/add/add-schedule.js +3 -0
- package/dist/add/add-scope.d.ts +2 -0
- package/dist/add/add-scope.js +146 -0
- package/dist/add/add-trigger.js +3 -0
- package/dist/add/add-wire-remote-addon.d.ts +10 -0
- package/dist/add/add-wire-remote-addon.js +66 -0
- package/dist/add/add-workflow-graph.js +32 -3
- package/dist/error-codes.d.ts +3 -0
- package/dist/error-codes.js +4 -0
- package/dist/inspector.js +19 -7
- package/dist/types.d.ts +19 -13
- package/dist/utils/custom-types-generator.js +2 -1
- package/dist/utils/ensure-function-metadata.d.ts +15 -0
- package/dist/utils/ensure-function-metadata.js +24 -0
- package/dist/utils/filter-inspector-state.js +9 -0
- package/dist/utils/get-property-value.d.ts +7 -2
- package/dist/utils/get-property-value.js +48 -1
- package/dist/utils/load-addon-functions-meta.js +81 -6
- package/dist/utils/nested-project-filter.d.ts +1 -0
- package/dist/utils/nested-project-filter.js +29 -0
- package/dist/utils/permissions.d.ts +1 -21
- package/dist/utils/permissions.js +17 -108
- package/dist/utils/post-process.d.ts +30 -1
- package/dist/utils/post-process.js +150 -72
- package/dist/utils/serialize-inspector-state.d.ts +13 -8
- package/dist/utils/serialize-inspector-state.js +12 -6
- package/dist/utils/serialize-permissions-groups-meta.d.ts +0 -2
- package/dist/utils/serialize-permissions-groups-meta.js +0 -26
- package/dist/utils/workflow/derive-workflow-plan.js +9 -3
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +56 -1
- package/dist/utils/workflow/dsl/patterns.d.ts +10 -0
- package/dist/utils/workflow/dsl/patterns.js +24 -8
- package/dist/utils/workflow/dsl/validation.js +3 -4
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +14 -0
- package/dist/utils/workflow/graph/finalize-workflows.d.ts +7 -0
- package/dist/utils/workflow/graph/finalize-workflows.js +11 -2
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +2 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +4 -0
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +6 -2
- package/dist/visit.js +4 -0
- package/package.json +3 -3
- package/src/add/add-addon-bans.ts +1 -0
- package/src/add/add-ai-agent.test.ts +87 -0
- package/src/add/add-ai-agent.ts +122 -0
- package/src/add/add-credential.ts +6 -0
- package/src/add/add-functions.ts +10 -12
- package/src/add/add-gateway.ts +11 -0
- package/src/add/add-http-route.ts +2 -8
- package/src/add/add-mcp-prompt.ts +0 -1
- package/src/add/add-mcp-resource.ts +0 -1
- package/src/add/add-permission.ts +4 -242
- package/src/add/add-queue-worker.ts +11 -0
- package/src/add/add-schedule.ts +11 -0
- package/src/add/add-scope.test.ts +346 -0
- package/src/add/add-scope.ts +225 -0
- package/src/add/add-trigger.ts +11 -0
- package/src/add/add-wire-remote-addon.ts +77 -0
- package/src/add/add-workflow-graph-input.test.ts +94 -0
- package/src/add/add-workflow-graph-notes.test.ts +74 -0
- package/src/add/add-workflow-graph.ts +35 -3
- package/src/add/inline-wiring-function.test.ts +104 -0
- package/src/add/validate-workflow-graph-addons.test.ts +102 -0
- package/src/error-codes.ts +5 -0
- package/src/inspector.ts +22 -6
- package/src/types.ts +16 -17
- package/src/utils/custom-types-generator.test.ts +26 -1
- package/src/utils/custom-types-generator.ts +2 -1
- package/src/utils/ensure-function-metadata.ts +42 -0
- package/src/utils/filter-inspector-state.test.ts +0 -2
- package/src/utils/filter-inspector-state.ts +9 -0
- package/src/utils/get-property-value.test.ts +141 -0
- package/src/utils/get-property-value.ts +62 -1
- package/src/utils/load-addon-functions-meta.test.ts +157 -0
- package/src/utils/load-addon-functions-meta.ts +94 -6
- package/src/utils/load-addon-scopes.test.ts +138 -0
- package/src/utils/nested-project-filter.test.ts +53 -0
- package/src/utils/nested-project-filter.ts +28 -0
- package/src/utils/permissions.test.ts +7 -232
- package/src/utils/permissions.ts +20 -160
- package/src/utils/post-process.test.ts +269 -4
- package/src/utils/post-process.ts +216 -95
- package/src/utils/serialize-inspector-state.ts +22 -25
- package/src/utils/serialize-permissions-groups-meta.ts +0 -28
- package/src/utils/workflow/derive-workflow-plan.test.ts +41 -3
- package/src/utils/workflow/derive-workflow-plan.ts +11 -4
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +66 -0
- package/src/utils/workflow/dsl/patterns.ts +34 -8
- package/src/utils/workflow/dsl/validation.ts +3 -4
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +15 -0
- package/src/utils/workflow/graph/finalize-workflows.test.ts +50 -0
- package/src/utils/workflow/graph/finalize-workflows.ts +13 -2
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +6 -0
- package/src/utils/workflow/graph/workflow-graph.types.ts +8 -0
- package/src/visit.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
|
+
import { ErrorCode } from '../error-codes.js';
|
|
4
|
+
const SEPARATOR = ':';
|
|
5
|
+
const WILDCARD = '*';
|
|
6
|
+
/**
|
|
7
|
+
* Validates a single scope segment, reporting rather than throwing so the
|
|
8
|
+
* inspector can surface every problem in one pass.
|
|
9
|
+
*
|
|
10
|
+
* @returns true when the segment is usable.
|
|
11
|
+
*/
|
|
12
|
+
const isValidSegment = (segment, scopeName, logger) => {
|
|
13
|
+
if (segment.length === 0) {
|
|
14
|
+
logger.critical(ErrorCode.INVALID_VALUE, `Scope '${scopeName}' contains an empty segment.`);
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (segment.includes(SEPARATOR)) {
|
|
18
|
+
logger.critical(ErrorCode.INVALID_VALUE, `Scope segment '${segment}' in '${scopeName}' contains the '${SEPARATOR}' separator. ` +
|
|
19
|
+
`Nest scopes with the 'scopes' property instead of embedding '${SEPARATOR}' in a name.`);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (segment === WILDCARD) {
|
|
23
|
+
logger.critical(ErrorCode.INVALID_VALUE, `Scope segment '${segment}' in '${scopeName}' is the wildcard. ` +
|
|
24
|
+
`'${WILDCARD}' is reserved for granting a scope and its descendants, and cannot be declared.`);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Recursively extracts a `scopes: { ... }` object literal into nested metadata.
|
|
31
|
+
*/
|
|
32
|
+
const extractScopeNodes = (obj, scopeName, logger) => {
|
|
33
|
+
const nodes = {};
|
|
34
|
+
for (const prop of obj.properties) {
|
|
35
|
+
if (!ts.isPropertyAssignment(prop)) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
let segment;
|
|
39
|
+
if (ts.isIdentifier(prop.name)) {
|
|
40
|
+
segment = prop.name.text;
|
|
41
|
+
}
|
|
42
|
+
else if (ts.isStringLiteral(prop.name)) {
|
|
43
|
+
segment = prop.name.text;
|
|
44
|
+
}
|
|
45
|
+
if (segment === undefined) {
|
|
46
|
+
logger.critical(ErrorCode.NON_LITERAL_WIRE_NAME, `Scope '${scopeName}' has a nested scope whose key is not a literal.`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (!isValidSegment(segment, scopeName, logger)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!ts.isObjectLiteralExpression(prop.initializer)) {
|
|
53
|
+
logger.critical(ErrorCode.INVALID_VALUE, `Nested scope '${segment}' in '${scopeName}' must be an object literal.`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const node = {};
|
|
57
|
+
const displayName = getPropertyValue(prop.initializer, 'displayName');
|
|
58
|
+
if (displayName) {
|
|
59
|
+
node.displayName = displayName;
|
|
60
|
+
}
|
|
61
|
+
const description = getPropertyValue(prop.initializer, 'description');
|
|
62
|
+
if (description) {
|
|
63
|
+
node.description = description;
|
|
64
|
+
}
|
|
65
|
+
const nestedProp = prop.initializer.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
66
|
+
ts.isIdentifier(p.name) &&
|
|
67
|
+
p.name.text === 'scopes');
|
|
68
|
+
if (nestedProp &&
|
|
69
|
+
ts.isPropertyAssignment(nestedProp) &&
|
|
70
|
+
ts.isObjectLiteralExpression(nestedProp.initializer)) {
|
|
71
|
+
const nested = extractScopeNodes(nestedProp.initializer, scopeName, logger);
|
|
72
|
+
if (nested) {
|
|
73
|
+
node.scopes = nested;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
nodes[segment] = node;
|
|
77
|
+
}
|
|
78
|
+
return Object.keys(nodes).length > 0 ? nodes : undefined;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Unwraps `x as const` / `x as any` so a cast declaration is still extracted
|
|
82
|
+
* rather than silently skipped.
|
|
83
|
+
*/
|
|
84
|
+
const unwrapAs = (node) => ts.isAsExpression(node) || ts.isSatisfiesExpression(node)
|
|
85
|
+
? unwrapAs(node.expression)
|
|
86
|
+
: node;
|
|
87
|
+
export const addScope = (logger, node, checker, state, _options) => {
|
|
88
|
+
if (!ts.isCallExpression(node)) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const expression = node.expression;
|
|
92
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireScope') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const firstArg = node.arguments[0];
|
|
96
|
+
if (!firstArg) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const unwrapped = unwrapAs(firstArg);
|
|
100
|
+
if (!ts.isObjectLiteralExpression(unwrapped)) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const sourceFile = node.getSourceFile().fileName;
|
|
104
|
+
// Roots are keyed exactly like the nodes beneath them, so each property of
|
|
105
|
+
// the call's single argument is one tree.
|
|
106
|
+
for (const prop of unwrapped.properties) {
|
|
107
|
+
if (!ts.isPropertyAssignment(prop)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
let name;
|
|
111
|
+
if (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name)) {
|
|
112
|
+
name = prop.name.text;
|
|
113
|
+
}
|
|
114
|
+
if (name === undefined) {
|
|
115
|
+
logger.critical(ErrorCode.NON_LITERAL_WIRE_NAME, 'A scope is declared with a key that is not a literal.');
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (!isValidSegment(name, name, logger)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (!ts.isObjectLiteralExpression(prop.initializer)) {
|
|
122
|
+
logger.critical(ErrorCode.INVALID_VALUE, `Scope '${name}' must be an object literal.`);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const root = prop.initializer;
|
|
126
|
+
const displayNameValue = getPropertyValue(root, 'displayName');
|
|
127
|
+
const descriptionValue = getPropertyValue(root, 'description');
|
|
128
|
+
let scopes;
|
|
129
|
+
const scopesProp = root.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
130
|
+
ts.isIdentifier(p.name) &&
|
|
131
|
+
p.name.text === 'scopes');
|
|
132
|
+
if (scopesProp &&
|
|
133
|
+
ts.isPropertyAssignment(scopesProp) &&
|
|
134
|
+
ts.isObjectLiteralExpression(scopesProp.initializer)) {
|
|
135
|
+
scopes = extractScopeNodes(scopesProp.initializer, name, logger);
|
|
136
|
+
}
|
|
137
|
+
state.scopes.files.add(sourceFile);
|
|
138
|
+
state.scopes.definitions.push({
|
|
139
|
+
name,
|
|
140
|
+
displayName: displayNameValue || undefined,
|
|
141
|
+
description: descriptionValue || undefined,
|
|
142
|
+
scopes,
|
|
143
|
+
sourceFile,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
};
|
package/dist/add/add-trigger.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as ts from 'typescript';
|
|
|
2
2
|
import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
3
3
|
import { extractFunctionName, makeContextBasedId, } from '../utils/extract-function-name.js';
|
|
4
4
|
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
5
|
+
import { ensureInlineWiringFunction } from '../utils/ensure-function-metadata.js';
|
|
5
6
|
import { resolveMiddleware } from '../utils/middleware.js';
|
|
6
7
|
import { extractWireNames } from '../utils/post-process.js';
|
|
7
8
|
import { resolveAddonName } from '../utils/resolve-addon-package.js';
|
|
@@ -45,6 +46,8 @@ const addWireTrigger = (logger, node, checker, state, firstArg) => {
|
|
|
45
46
|
if (!nameValue) {
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
49
|
+
// Register metadata for a func inlined into the wiring (see helper).
|
|
50
|
+
ensureInlineWiringFunction(state, pikkuFuncId, nameValue, funcInitializer, checker, extracted.isHelper);
|
|
48
51
|
// --- resolve middleware ---
|
|
49
52
|
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
50
53
|
// --- track used functions/middleware for service aggregation ---
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import type { InspectorState, InspectorLogger } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detect wireRemoteAddon({ name: '...', package: '...' }) call expressions and
|
|
5
|
+
* record the namespace as a **remote** addon declaration. Only name + package
|
|
6
|
+
* are needed for codegen (serverUrl/auth are runtime closures resolved by the
|
|
7
|
+
* RPC runner); the `remote` marker tells the consumer's RPC-map generator to
|
|
8
|
+
* import the addon's `.remote.gen` map instead of `.internal.gen`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function addWireRemoteAddon(node: ts.Node, state: InspectorState, logger: InspectorLogger): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Detect wireRemoteAddon({ name: '...', package: '...' }) call expressions and
|
|
4
|
+
* record the namespace as a **remote** addon declaration. Only name + package
|
|
5
|
+
* are needed for codegen (serverUrl/auth are runtime closures resolved by the
|
|
6
|
+
* RPC runner); the `remote` marker tells the consumer's RPC-map generator to
|
|
7
|
+
* import the addon's `.remote.gen` map instead of `.internal.gen`.
|
|
8
|
+
*/
|
|
9
|
+
export function addWireRemoteAddon(node, state, logger) {
|
|
10
|
+
if (!ts.isCallExpression(node))
|
|
11
|
+
return;
|
|
12
|
+
const { expression, arguments: args } = node;
|
|
13
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireRemoteAddon')
|
|
14
|
+
return;
|
|
15
|
+
const [firstArg] = args;
|
|
16
|
+
if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
|
|
17
|
+
return;
|
|
18
|
+
let name;
|
|
19
|
+
let pkg;
|
|
20
|
+
// The auth binding is a runtime closure; we only extract the statically
|
|
21
|
+
// knowable slot names so `pikku verify` can check they exist in the
|
|
22
|
+
// consumer's own wirings. `hasAuth` distinguishes "public" (omitted) from
|
|
23
|
+
// "bound via a custom resolve()" (present but no static id).
|
|
24
|
+
let hasAuth = false;
|
|
25
|
+
let authCredentialId;
|
|
26
|
+
let authSecretId;
|
|
27
|
+
for (const prop of firstArg.properties) {
|
|
28
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
|
|
29
|
+
continue;
|
|
30
|
+
const key = prop.name.text;
|
|
31
|
+
if (key === 'name' && ts.isStringLiteral(prop.initializer)) {
|
|
32
|
+
name = prop.initializer.text;
|
|
33
|
+
}
|
|
34
|
+
else if (key === 'package' && ts.isStringLiteral(prop.initializer)) {
|
|
35
|
+
pkg = prop.initializer.text;
|
|
36
|
+
}
|
|
37
|
+
else if (key === 'auth' &&
|
|
38
|
+
ts.isObjectLiteralExpression(prop.initializer)) {
|
|
39
|
+
hasAuth = true;
|
|
40
|
+
for (const authProp of prop.initializer.properties) {
|
|
41
|
+
if (!ts.isPropertyAssignment(authProp) || !ts.isIdentifier(authProp.name))
|
|
42
|
+
continue;
|
|
43
|
+
if (authProp.name.text === 'credentialId' &&
|
|
44
|
+
ts.isStringLiteral(authProp.initializer)) {
|
|
45
|
+
authCredentialId = authProp.initializer.text;
|
|
46
|
+
}
|
|
47
|
+
else if (authProp.name.text === 'secretId' &&
|
|
48
|
+
ts.isStringLiteral(authProp.initializer)) {
|
|
49
|
+
authSecretId = authProp.initializer.text;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!name || !pkg)
|
|
55
|
+
return;
|
|
56
|
+
logger.debug(`• Found wireRemoteAddon: ${name} → ${pkg} (remote)`);
|
|
57
|
+
state.rpc.wireAddonDeclarations.set(name, {
|
|
58
|
+
package: pkg,
|
|
59
|
+
remote: true,
|
|
60
|
+
hasAuth,
|
|
61
|
+
authCredentialId,
|
|
62
|
+
authSecretId,
|
|
63
|
+
});
|
|
64
|
+
state.rpc.usedAddons.add(name);
|
|
65
|
+
state.rpc.wireAddonFiles.add(node.getSourceFile().fileName);
|
|
66
|
+
}
|
|
@@ -2,6 +2,11 @@ import * as ts from 'typescript';
|
|
|
2
2
|
import { ErrorCode } from '../error-codes.js';
|
|
3
3
|
import { extractStringLiteral } from '../utils/extract-node-value.js';
|
|
4
4
|
function extractAstValue(expr, refParamName, templateParamName) {
|
|
5
|
+
// `'GET' as const` / parenthesised values wrap the real initializer — see
|
|
6
|
+
// through them or the whole property is silently dropped from the meta.
|
|
7
|
+
while (ts.isAsExpression(expr) || ts.isParenthesizedExpression(expr)) {
|
|
8
|
+
expr = expr.expression;
|
|
9
|
+
}
|
|
5
10
|
if (ts.isStringLiteral(expr)) {
|
|
6
11
|
return expr.text;
|
|
7
12
|
}
|
|
@@ -113,9 +118,13 @@ function extractInputMapping(node, _checker) {
|
|
|
113
118
|
const refParamName = node.parameters.length > 0 && ts.isIdentifier(node.parameters[0].name)
|
|
114
119
|
? node.parameters[0].name.text
|
|
115
120
|
: 'ref';
|
|
121
|
+
// The canonical form imports `template` from '@pikku/core/workflow' and calls
|
|
122
|
+
// it inside a single-param `(ref) => (...)` arrow; the older form passes it as
|
|
123
|
+
// a second arrow parameter. Support both — default to the imported name so a
|
|
124
|
+
// `template(...)` value is never dropped just because it isn't a 2nd param.
|
|
116
125
|
const templateParamName = node.parameters.length > 1 && ts.isIdentifier(node.parameters[1].name)
|
|
117
126
|
? node.parameters[1].name.text
|
|
118
|
-
:
|
|
127
|
+
: 'template';
|
|
119
128
|
const input = {};
|
|
120
129
|
for (const prop of bodyObj.properties) {
|
|
121
130
|
if (!ts.isPropertyAssignment(prop))
|
|
@@ -138,6 +147,12 @@ function extractInputMapping(node, _checker) {
|
|
|
138
147
|
* Extract next config (string, array, or record)
|
|
139
148
|
*/
|
|
140
149
|
function extractNextConfig(node, _checker) {
|
|
150
|
+
// Key-based branch `next` (`{ key: [targets] }`) is authored with an `as any`
|
|
151
|
+
// cast because the graph's NextConfig can't narrow record targets to node-id
|
|
152
|
+
// literals; see through that (and parens) so the routing survives into the meta.
|
|
153
|
+
while (ts.isAsExpression(node) || ts.isParenthesizedExpression(node)) {
|
|
154
|
+
node = node.expression;
|
|
155
|
+
}
|
|
141
156
|
if (ts.isStringLiteral(node)) {
|
|
142
157
|
return node.text;
|
|
143
158
|
}
|
|
@@ -207,6 +222,7 @@ function extractWorkflowGraphConfig(configArg, checker) {
|
|
|
207
222
|
let name;
|
|
208
223
|
let description;
|
|
209
224
|
let tags;
|
|
225
|
+
let notes;
|
|
210
226
|
let disabled;
|
|
211
227
|
let nodesNode;
|
|
212
228
|
let configNode;
|
|
@@ -231,6 +247,12 @@ function extractWorkflowGraphConfig(configArg, checker) {
|
|
|
231
247
|
.filter(ts.isStringLiteral)
|
|
232
248
|
.map((el) => el.text);
|
|
233
249
|
}
|
|
250
|
+
else if (propName === 'notes' &&
|
|
251
|
+
ts.isArrayLiteralExpression(prop.initializer)) {
|
|
252
|
+
notes = prop.initializer.elements
|
|
253
|
+
.filter(ts.isStringLiteral)
|
|
254
|
+
.map((el) => el.text);
|
|
255
|
+
}
|
|
234
256
|
else if (propName === 'nodes' &&
|
|
235
257
|
ts.isObjectLiteralExpression(prop.initializer)) {
|
|
236
258
|
nodesNode = prop.initializer;
|
|
@@ -240,7 +262,7 @@ function extractWorkflowGraphConfig(configArg, checker) {
|
|
|
240
262
|
configNode = prop.initializer;
|
|
241
263
|
}
|
|
242
264
|
}
|
|
243
|
-
return { name, description, tags, disabled, nodesNode, configNode };
|
|
265
|
+
return { name, description, tags, notes, disabled, nodesNode, configNode };
|
|
244
266
|
}
|
|
245
267
|
/**
|
|
246
268
|
* Extract graph nodes from the new pikkuWorkflowGraph format
|
|
@@ -283,6 +305,7 @@ function extractGraphFromNewFormat(nodesNode, configNode, checker, state) {
|
|
|
283
305
|
onError: undefined,
|
|
284
306
|
retries: undefined,
|
|
285
307
|
retryDelay: undefined,
|
|
308
|
+
notes: undefined,
|
|
286
309
|
};
|
|
287
310
|
}
|
|
288
311
|
// Extract config for each node from 'config' property
|
|
@@ -305,6 +328,7 @@ function extractGraphFromNewFormat(nodesNode, configNode, checker, state) {
|
|
|
305
328
|
nodes[nodeId].input = nodeConfig.input;
|
|
306
329
|
nodes[nodeId].retries = nodeConfig.retries;
|
|
307
330
|
nodes[nodeId].retryDelay = nodeConfig.retryDelay;
|
|
331
|
+
nodes[nodeId].notes = nodeConfig.notes;
|
|
308
332
|
}
|
|
309
333
|
}
|
|
310
334
|
}
|
|
@@ -320,6 +344,7 @@ function extractNodeConfigFromObject(obj, checker) {
|
|
|
320
344
|
let input = {};
|
|
321
345
|
let retries = undefined;
|
|
322
346
|
let retryDelay = undefined;
|
|
347
|
+
let notes = undefined;
|
|
323
348
|
for (const prop of obj.properties) {
|
|
324
349
|
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name))
|
|
325
350
|
continue;
|
|
@@ -346,8 +371,11 @@ function extractNodeConfigFromObject(obj, checker) {
|
|
|
346
371
|
retryDelay = prop.initializer.text;
|
|
347
372
|
}
|
|
348
373
|
}
|
|
374
|
+
else if (propName === 'notes') {
|
|
375
|
+
notes = extractStringLiteral(prop.initializer, checker);
|
|
376
|
+
}
|
|
349
377
|
}
|
|
350
|
-
return { next, onError, input, retries, retryDelay };
|
|
378
|
+
return { next, onError, input, retries, retryDelay, notes };
|
|
351
379
|
}
|
|
352
380
|
/**
|
|
353
381
|
* Inspector for pikkuWorkflowGraph() calls
|
|
@@ -402,6 +430,7 @@ export const addWorkflowGraph = (logger, node, checker, state) => {
|
|
|
402
430
|
source: 'graph',
|
|
403
431
|
description: graphConfig.description,
|
|
404
432
|
tags: graphConfig.tags,
|
|
433
|
+
notes: graphConfig.notes,
|
|
405
434
|
nodes: graphNodes,
|
|
406
435
|
entryNodeIds,
|
|
407
436
|
};
|
package/dist/error-codes.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ export declare enum ErrorCode {
|
|
|
22
22
|
EXPECT_EVENTUALLY_SCENARIO_ONLY = "PKU675",
|
|
23
23
|
WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED = "PKU600",
|
|
24
24
|
INVALID_DSL_WORKFLOW = "PKU641",
|
|
25
|
+
WORKFLOW_GRAPH_ADDON_NOT_WIRED = "PKU642",
|
|
26
|
+
REMOTE_ADDON_NOT_DEV_DEPENDENCY = "PKU338",
|
|
27
|
+
REMOTE_ADDON_AUTH_UNRESOLVED = "PKU339",
|
|
25
28
|
DB_COLUMN_NAME_TYPE_CONTRADICTION = "PKU480",
|
|
26
29
|
DB_JSON_COLUMN_UNTYPED = "PKU481",
|
|
27
30
|
DB_FORMAT_ON_NON_STRING = "PKU482",
|
package/dist/error-codes.js
CHANGED
|
@@ -24,6 +24,10 @@ export var ErrorCode;
|
|
|
24
24
|
ErrorCode["EXPECT_EVENTUALLY_SCENARIO_ONLY"] = "PKU675";
|
|
25
25
|
ErrorCode["WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED"] = "PKU600";
|
|
26
26
|
ErrorCode["INVALID_DSL_WORKFLOW"] = "PKU641";
|
|
27
|
+
ErrorCode["WORKFLOW_GRAPH_ADDON_NOT_WIRED"] = "PKU642";
|
|
28
|
+
// Remote addon (wireRemoteAddon) validation
|
|
29
|
+
ErrorCode["REMOTE_ADDON_NOT_DEV_DEPENDENCY"] = "PKU338";
|
|
30
|
+
ErrorCode["REMOTE_ADDON_AUTH_UNRESOLVED"] = "PKU339";
|
|
27
31
|
// Database schema codegen warnings
|
|
28
32
|
ErrorCode["DB_COLUMN_NAME_TYPE_CONTRADICTION"] = "PKU480";
|
|
29
33
|
ErrorCode["DB_JSON_COLUMN_UNTYPED"] = "PKU481";
|
package/dist/inspector.js
CHANGED
|
@@ -5,7 +5,8 @@ import { visitSetup, visitFunctions, visitRoutes } from './visit.js';
|
|
|
5
5
|
import { TypesMap } from './types-map.js';
|
|
6
6
|
import { getFilesAndMethods } from './utils/get-files-and-methods.js';
|
|
7
7
|
import { findCommonAncestor } from './utils/find-root-dir.js';
|
|
8
|
-
import {
|
|
8
|
+
import { createNestedProjectFilter } from './utils/nested-project-filter.js';
|
|
9
|
+
import { aggregateRequiredServices, stampAuthHandlerServices, validateAgentModels, validateSecretOverrides, validateVariableOverrides, validateCredentialOverrides, validateRemoteAddonDependencies, validateRemoteAddonAuth, validateScopeReferences, computeResolvedIOTypes, computeMiddlewareGroupsMeta, computePermissionsGroupsMeta, computeRequiredSchemas, computeDiagnostics, validateSchemaWiringSeparation, validateWorkflowGraphAddons, } from './utils/post-process.js';
|
|
9
10
|
import { generateOpenAPISpec } from './utils/serialize-openapi-json.js';
|
|
10
11
|
import { pikkuState } from '@pikku/core/internal';
|
|
11
12
|
import { resolveLatestVersions } from './utils/resolve-versions.js';
|
|
@@ -58,7 +59,6 @@ export function getInitialInspectorState(rootDir) {
|
|
|
58
59
|
},
|
|
59
60
|
files: new Set(),
|
|
60
61
|
routeMiddleware: new Map(),
|
|
61
|
-
routePermissions: new Map(),
|
|
62
62
|
},
|
|
63
63
|
channels: {
|
|
64
64
|
files: new Set(),
|
|
@@ -93,6 +93,8 @@ export function getInitialInspectorState(rootDir) {
|
|
|
93
93
|
internalFiles: new Map(),
|
|
94
94
|
exposedMeta: {},
|
|
95
95
|
exposedFiles: new Map(),
|
|
96
|
+
remoteMeta: {},
|
|
97
|
+
remoteFiles: new Map(),
|
|
96
98
|
invokedFunctions: new Set(),
|
|
97
99
|
invokedFunctionsByFile: new Map(),
|
|
98
100
|
usedAddons: new Set(),
|
|
@@ -134,6 +136,10 @@ export function getInitialInspectorState(rootDir) {
|
|
|
134
136
|
definitions: [],
|
|
135
137
|
files: new Set(),
|
|
136
138
|
},
|
|
139
|
+
scopes: {
|
|
140
|
+
definitions: [],
|
|
141
|
+
files: new Set(),
|
|
142
|
+
},
|
|
137
143
|
variables: {
|
|
138
144
|
definitions: [],
|
|
139
145
|
files: new Set(),
|
|
@@ -159,7 +165,6 @@ export function getInitialInspectorState(rootDir) {
|
|
|
159
165
|
permissions: {
|
|
160
166
|
definitions: {},
|
|
161
167
|
instances: {},
|
|
162
|
-
tagPermissions: new Map(),
|
|
163
168
|
},
|
|
164
169
|
serviceAggregation: {
|
|
165
170
|
requiredServices: new Set(),
|
|
@@ -183,8 +188,6 @@ export function getInitialInspectorState(rootDir) {
|
|
|
183
188
|
},
|
|
184
189
|
permissionsGroupsMeta: {
|
|
185
190
|
definitions: {},
|
|
186
|
-
httpGroups: {},
|
|
187
|
-
tagGroups: {},
|
|
188
191
|
},
|
|
189
192
|
requiredSchemas: new Set(),
|
|
190
193
|
openAPISpec: null,
|
|
@@ -225,17 +228,22 @@ export const inspect = async (logger, routeFiles, options = {}) => {
|
|
|
225
228
|
const startSourceFiles = performance.now();
|
|
226
229
|
// node_modules under rootDir (e.g. a locally-installed addon) is a
|
|
227
230
|
// dependency, not project source — scanning it double-counts the addon's
|
|
228
|
-
// own application types (CoreConfig/Services/SingletonServices).
|
|
231
|
+
// own application types (CoreConfig/Services/SingletonServices). Nested
|
|
232
|
+
// pikku projects (a workspace addon at packages/<addon>) are the same case:
|
|
233
|
+
// TS resolves the node_modules symlink to its realpath under rootDir, so
|
|
234
|
+
// the node_modules check alone misses them.
|
|
229
235
|
// Sort by file name so the sweeps populate state in a stable order. The
|
|
230
236
|
// program's own file order depends on glob + import-graph resolution, which
|
|
231
237
|
// varies run to run — leaving generated meta keys (and anything serialized
|
|
232
238
|
// in insertion order) non-reproducible across identical `pikku all` runs.
|
|
233
239
|
// Safe because function registration is a dedicated pass (visitFunctions)
|
|
234
240
|
// that completes before any order-sensitive wiring resolution in visitRoutes.
|
|
241
|
+
const isNestedProjectFile = createNestedProjectFilter(rootDir);
|
|
235
242
|
const sourceFiles = program
|
|
236
243
|
.getSourceFiles()
|
|
237
244
|
.filter((sf) => sf.fileName.startsWith(rootDir) &&
|
|
238
|
-
!sf.fileName.includes('/node_modules/')
|
|
245
|
+
!sf.fileName.includes('/node_modules/') &&
|
|
246
|
+
!isNestedProjectFile(sf.fileName))
|
|
239
247
|
.sort((a, b) => a.fileName < b.fileName ? -1 : a.fileName > b.fileName ? 1 : 0);
|
|
240
248
|
logger.debug(`Got source files in ${(performance.now() - startSourceFiles).toFixed(2)}ms`);
|
|
241
249
|
const state = getInitialInspectorState(rootDir);
|
|
@@ -301,6 +309,7 @@ export const inspect = async (logger, routeFiles, options = {}) => {
|
|
|
301
309
|
computePermissionsGroupsMeta(state);
|
|
302
310
|
computeDiagnostics(state);
|
|
303
311
|
validateSchemaWiringSeparation(logger, state);
|
|
312
|
+
validateWorkflowGraphAddons(logger, state);
|
|
304
313
|
if (options.openAPI) {
|
|
305
314
|
state.openAPISpec = await generateOpenAPISpec(logger, state.functions.meta, state.http.meta, state.schemas, options.openAPI.additionalInfo, pikkuState(null, 'misc', 'errors'));
|
|
306
315
|
}
|
|
@@ -308,6 +317,9 @@ export const inspect = async (logger, routeFiles, options = {}) => {
|
|
|
308
317
|
validateSecretOverrides(logger, state);
|
|
309
318
|
validateVariableOverrides(logger, state);
|
|
310
319
|
validateCredentialOverrides(logger, state);
|
|
320
|
+
validateRemoteAddonDependencies(logger, state);
|
|
321
|
+
validateRemoteAddonAuth(logger, state);
|
|
322
|
+
validateScopeReferences(logger, state);
|
|
311
323
|
}
|
|
312
324
|
state.program = program;
|
|
313
325
|
return state;
|
package/dist/types.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { CLICommandMeta } from '@pikku/core/cli';
|
|
|
13
13
|
import type { NodesMeta } from '@pikku/core/node';
|
|
14
14
|
import type { SecretDefinitions } from '@pikku/core/secret';
|
|
15
15
|
import type { CredentialDefinitions } from '@pikku/core/credential';
|
|
16
|
+
import type { ScopeDefinitions } from '@pikku/core/scope';
|
|
16
17
|
import type { VariableDefinitions } from '@pikku/core/variable';
|
|
17
18
|
import type { TypesMap } from './types-map.js';
|
|
18
19
|
import type { FunctionsMeta, FunctionServicesMeta, FunctionWiresMeta, JSONValue } from '@pikku/core';
|
|
@@ -39,21 +40,11 @@ export interface MiddlewareGroupMeta {
|
|
|
39
40
|
instanceIds: string[];
|
|
40
41
|
isFactory: boolean;
|
|
41
42
|
}
|
|
42
|
-
export interface PermissionGroupMeta {
|
|
43
|
-
exportName: string | null;
|
|
44
|
-
sourceFile: string;
|
|
45
|
-
position: number;
|
|
46
|
-
services: FunctionServicesMeta;
|
|
47
|
-
count: number;
|
|
48
|
-
instanceIds: string[];
|
|
49
|
-
isFactory: boolean;
|
|
50
|
-
}
|
|
51
43
|
export interface InspectorHTTPState {
|
|
52
44
|
metaInputTypes: MetaInputTypes;
|
|
53
45
|
meta: HTTPWiringsMeta;
|
|
54
46
|
files: Set<string>;
|
|
55
47
|
routeMiddleware: Map<string, MiddlewareGroupMeta>;
|
|
56
|
-
routePermissions: Map<string, PermissionGroupMeta>;
|
|
57
48
|
}
|
|
58
49
|
/**
|
|
59
50
|
* Schema vendor types for Standard Schema compliant validators
|
|
@@ -184,7 +175,6 @@ export interface InspectorPermissionInstance {
|
|
|
184
175
|
export interface InspectorPermissionState {
|
|
185
176
|
definitions: Record<string, InspectorPermissionDefinition>;
|
|
186
177
|
instances: Record<string, InspectorPermissionInstance>;
|
|
187
|
-
tagPermissions: Map<string, PermissionGroupMeta>;
|
|
188
178
|
}
|
|
189
179
|
export type InspectorFilters = {
|
|
190
180
|
names?: string[];
|
|
@@ -418,6 +408,12 @@ export interface InspectorState {
|
|
|
418
408
|
path: string;
|
|
419
409
|
exportedName: string;
|
|
420
410
|
}>;
|
|
411
|
+
/** Functions marked `remote: true` — the surface a wireRemoteAddon consumer imports */
|
|
412
|
+
remoteMeta: Record<string, string>;
|
|
413
|
+
remoteFiles: Map<string, {
|
|
414
|
+
path: string;
|
|
415
|
+
exportedName: string;
|
|
416
|
+
}>;
|
|
421
417
|
invokedFunctions: Set<string>;
|
|
422
418
|
invokedFunctionsByFile: Map<string, Set<string>>;
|
|
423
419
|
usedAddons: Set<string>;
|
|
@@ -425,6 +421,14 @@ export interface InspectorState {
|
|
|
425
421
|
package: string;
|
|
426
422
|
rpcEndpoint?: string;
|
|
427
423
|
mcp?: boolean;
|
|
424
|
+
/** True when declared via `wireRemoteAddon` — import the addon's `.remote.gen` map, not `.internal.gen` */
|
|
425
|
+
remote?: boolean;
|
|
426
|
+
/** wireRemoteAddon: whether an `auth` binding was supplied (vs a public surface) */
|
|
427
|
+
hasAuth?: boolean;
|
|
428
|
+
/** wireRemoteAddon: statically-known `auth.credentialId`, for verify */
|
|
429
|
+
authCredentialId?: string;
|
|
430
|
+
/** wireRemoteAddon: statically-known `auth.secretId`, for verify */
|
|
431
|
+
authSecretId?: string;
|
|
428
432
|
secretOverrides?: Record<string, string>;
|
|
429
433
|
variableOverrides?: Record<string, string>;
|
|
430
434
|
credentialOverrides?: Record<string, string>;
|
|
@@ -480,6 +484,10 @@ export interface InspectorState {
|
|
|
480
484
|
definitions: CredentialDefinitions;
|
|
481
485
|
files: Set<string>;
|
|
482
486
|
};
|
|
487
|
+
scopes: {
|
|
488
|
+
definitions: ScopeDefinitions;
|
|
489
|
+
files: Set<string>;
|
|
490
|
+
};
|
|
483
491
|
variables: {
|
|
484
492
|
definitions: VariableDefinitions;
|
|
485
493
|
files: Set<string>;
|
|
@@ -518,8 +526,6 @@ export interface InspectorState {
|
|
|
518
526
|
};
|
|
519
527
|
permissionsGroupsMeta: {
|
|
520
528
|
definitions: Record<string, InspectorPermissionDefinition>;
|
|
521
|
-
httpGroups: Record<string, PermissionGroupMeta>;
|
|
522
|
-
tagGroups: Record<string, PermissionGroupMeta>;
|
|
523
529
|
};
|
|
524
530
|
requiredSchemas: Set<string>;
|
|
525
531
|
openAPISpec: Record<string, any> | null;
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* ts-json-schema-generator can discover inline/custom types from typesMap.
|
|
6
6
|
*/
|
|
7
7
|
export function sanitizeTypeName(name) {
|
|
8
|
-
|
|
8
|
+
const sanitized = name.replace(/[^a-zA-Z0-9_$]/g, '_');
|
|
9
|
+
return /^[0-9]/.test(sanitized) ? `_${sanitized}` : sanitized;
|
|
9
10
|
}
|
|
10
11
|
const CLASSIFICATION_WRAPPERS = new Set(['Private', 'Pii', 'Secret']);
|
|
11
12
|
function findMatchingAngleBracket(type, startIndex) {
|
|
@@ -7,3 +7,18 @@ import type { InspectorState } from '../types.js';
|
|
|
7
7
|
* extracts tags/middleware/permissions from the pikkuFunc() config.
|
|
8
8
|
*/
|
|
9
9
|
export declare function ensureFunctionMetadata(state: InspectorState, pikkuFuncId: string, fallbackName?: string, funcInitializer?: ts.Node, checker?: ts.TypeChecker, isHelper?: boolean): void;
|
|
10
|
+
/**
|
|
11
|
+
* Register metadata for a `func:` inlined into a wiring (queue/scheduler/
|
|
12
|
+
* trigger/gateway/…).
|
|
13
|
+
*
|
|
14
|
+
* An inline function has no exported name, so `addFunctions` skips it (it bails
|
|
15
|
+
* on `__temp_` ids) and only the wiring's context-based id exists. Without this
|
|
16
|
+
* the wiring points at a function that was never registered and the worker
|
|
17
|
+
* resolves to nothing at runtime ("Missing generated metadata for ...").
|
|
18
|
+
*
|
|
19
|
+
* The stub also carries no session info, so the runtime would treat it as
|
|
20
|
+
* session-required and every invocation would fail with "Authentication
|
|
21
|
+
* required". Derive `sessionless` from the helper the function was built with —
|
|
22
|
+
* the same rule `addFunctions` applies to named ones (`!== 'pikkuFunc'`).
|
|
23
|
+
*/
|
|
24
|
+
export declare function ensureInlineWiringFunction(state: InspectorState, pikkuFuncId: string, fallbackName: string | undefined, funcInitializer: ts.Node, checker: ts.TypeChecker, isHelper?: boolean): void;
|
|
@@ -207,6 +207,30 @@ export function ensureFunctionMetadata(state, pikkuFuncId, fallbackName, funcIni
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Register metadata for a `func:` inlined into a wiring (queue/scheduler/
|
|
212
|
+
* trigger/gateway/…).
|
|
213
|
+
*
|
|
214
|
+
* An inline function has no exported name, so `addFunctions` skips it (it bails
|
|
215
|
+
* on `__temp_` ids) and only the wiring's context-based id exists. Without this
|
|
216
|
+
* the wiring points at a function that was never registered and the worker
|
|
217
|
+
* resolves to nothing at runtime ("Missing generated metadata for ...").
|
|
218
|
+
*
|
|
219
|
+
* The stub also carries no session info, so the runtime would treat it as
|
|
220
|
+
* session-required and every invocation would fail with "Authentication
|
|
221
|
+
* required". Derive `sessionless` from the helper the function was built with —
|
|
222
|
+
* the same rule `addFunctions` applies to named ones (`!== 'pikkuFunc'`).
|
|
223
|
+
*/
|
|
224
|
+
export function ensureInlineWiringFunction(state, pikkuFuncId, fallbackName, funcInitializer, checker, isHelper) {
|
|
225
|
+
ensureFunctionMetadata(state, pikkuFuncId, fallbackName, funcInitializer, checker, isHelper);
|
|
226
|
+
const meta = state.functions.meta[pikkuFuncId];
|
|
227
|
+
if (meta &&
|
|
228
|
+
meta.sessionless === undefined &&
|
|
229
|
+
ts.isCallExpression(funcInitializer) &&
|
|
230
|
+
ts.isIdentifier(funcInitializer.expression)) {
|
|
231
|
+
meta.sessionless = funcInitializer.expression.text !== 'pikkuFunc';
|
|
232
|
+
}
|
|
233
|
+
}
|
|
210
234
|
function populateTypesLookup(state, pikkuFuncId, funcInitializer, checker) {
|
|
211
235
|
const typeArgs = funcInitializer.typeArguments;
|
|
212
236
|
if (typeArgs && typeArgs.length >= 1) {
|
|
@@ -334,6 +334,8 @@ export function filterInspectorState(state, filters, logger) {
|
|
|
334
334
|
internalFiles: new Map(state.rpc.internalFiles),
|
|
335
335
|
exposedMeta: { ...state.rpc.exposedMeta },
|
|
336
336
|
exposedFiles: new Map(state.rpc.exposedFiles),
|
|
337
|
+
remoteMeta: { ...state.rpc.remoteMeta },
|
|
338
|
+
remoteFiles: new Map(state.rpc.remoteFiles),
|
|
337
339
|
invokedFunctions: new Set(state.rpc.invokedFunctions),
|
|
338
340
|
},
|
|
339
341
|
cli: {
|
|
@@ -746,6 +748,13 @@ export function filterInspectorState(state, filters, logger) {
|
|
|
746
748
|
filteredState.rpc.exposedFiles.delete(key);
|
|
747
749
|
}
|
|
748
750
|
}
|
|
751
|
+
for (const key of Object.keys(filteredState.rpc.remoteMeta)) {
|
|
752
|
+
const targetFuncId = filteredState.rpc.remoteMeta[key];
|
|
753
|
+
if (!survivingFuncIds.has(targetFuncId) && !survivingFuncIds.has(key)) {
|
|
754
|
+
delete filteredState.rpc.remoteMeta[key];
|
|
755
|
+
filteredState.rpc.remoteFiles.delete(key);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
749
758
|
// Prune invokedFunctions to match surviving functions
|
|
750
759
|
for (const funcId of filteredState.rpc.invokedFunctions) {
|
|
751
760
|
if (!survivingFuncIds.has(funcId)) {
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { ErrorCode } from '../error-codes.js';
|
|
3
|
+
export declare const getArrayPropertyValue: (obj: ts.ObjectLiteralExpression, propertyName: string) => string[] | null;
|
|
3
4
|
/**
|
|
4
|
-
* Extracts
|
|
5
|
+
* Extracts a string->string record from an object property.
|
|
6
|
+
*
|
|
7
|
+
* `getPropertyValue` falls through to `getText()` for an object literal, which
|
|
8
|
+
* returns the raw source text rather than the record — so callers that need the
|
|
9
|
+
* entries (e.g. oauth2 `additionalParams`) must use this instead.
|
|
5
10
|
*/
|
|
6
|
-
export declare const
|
|
11
|
+
export declare const getRecordPropertyValue: (obj: ts.ObjectLiteralExpression, propertyName: string) => Record<string, string> | null;
|
|
7
12
|
/**
|
|
8
13
|
* Wiring identity fields (`name`, `secretId`, `variableId`, …) are read
|
|
9
14
|
* STATICALLY from source — a const or variable reference is keyed by its
|