@pikku/inspector 0.12.4 → 0.12.5
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 +10 -0
- package/dist/add/add-credential.d.ts +2 -0
- package/dist/add/add-credential.js +118 -0
- package/dist/add/add-secret.d.ts +1 -3
- package/dist/add/add-secret.js +0 -74
- package/dist/inspector.js +4 -0
- package/dist/types.d.ts +5 -0
- package/dist/utils/serialize-inspector-state.d.ts +4 -0
- package/dist/utils/serialize-inspector-state.js +8 -0
- package/dist/visit.js +3 -2
- package/package.json +2 -2
- package/src/add/add-credential.ts +178 -0
- package/src/add/add-secret.ts +0 -131
- package/src/inspector.ts +4 -0
- package/src/types.ts +5 -0
- package/src/utils/serialize-inspector-state.ts +12 -0
- package/src/visit.ts +3 -2
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## 0.12.0
|
|
2
2
|
|
|
3
|
+
## 0.12.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 65eccc6: Cache Zod schema generation between re-inspection passes and batch imports by source file. Schemas are cached using a fingerprint of schemaLookup entries + file mtimes, so reinspections skip Zod generation entirely when schemas haven't changed. Source file imports are grouped so each file is imported once instead of per-schema. Reduces `pikku all` from ~5 minutes to ~13 seconds on projects with many Zod schemas.
|
|
8
|
+
- 0f59432: Add per-user credential system with CredentialService, OAuth2 route handlers, and KyselyCredentialService with envelope encryption
|
|
9
|
+
- Updated dependencies [0f59432]
|
|
10
|
+
- Updated dependencies [52b64d1]
|
|
11
|
+
- @pikku/core@0.12.10
|
|
12
|
+
|
|
3
13
|
## 0.12.4
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue, getArrayPropertyValue, } from '../utils/get-property-value.js';
|
|
3
|
+
import { ErrorCode } from '../error-codes.js';
|
|
4
|
+
import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js';
|
|
5
|
+
export const addCredential = (logger, node, checker, state, _options) => {
|
|
6
|
+
if (!ts.isCallExpression(node)) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const args = node.arguments;
|
|
10
|
+
const firstArg = args[0];
|
|
11
|
+
const expression = node.expression;
|
|
12
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireCredential') {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!firstArg) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
19
|
+
const obj = firstArg;
|
|
20
|
+
const nameValue = getPropertyValue(obj, 'name');
|
|
21
|
+
const displayNameValue = getPropertyValue(obj, 'displayName');
|
|
22
|
+
const descriptionValue = getPropertyValue(obj, 'description');
|
|
23
|
+
const typeValue = getPropertyValue(obj, 'type');
|
|
24
|
+
if (!nameValue) {
|
|
25
|
+
logger.critical(ErrorCode.MISSING_NAME, "Credential is missing the required 'name' property.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (!displayNameValue) {
|
|
29
|
+
logger.critical(ErrorCode.MISSING_NAME, `Credential '${nameValue}' is missing the required 'displayName' property.`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (!typeValue || (typeValue !== 'singleton' && typeValue !== 'wire')) {
|
|
33
|
+
logger.critical(ErrorCode.MISSING_NAME, `Credential '${nameValue}' is missing or has invalid 'type' property. Must be 'singleton' or 'wire'.`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
let schemaVariableName = null;
|
|
37
|
+
let schemaSourceFile = null;
|
|
38
|
+
let schemaIdentifier = null;
|
|
39
|
+
for (const prop of obj.properties) {
|
|
40
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
41
|
+
ts.isIdentifier(prop.name) &&
|
|
42
|
+
prop.name.text === 'schema') {
|
|
43
|
+
if (ts.isIdentifier(prop.initializer)) {
|
|
44
|
+
schemaVariableName = prop.initializer.text;
|
|
45
|
+
schemaIdentifier = prop.initializer;
|
|
46
|
+
const symbol = checker.getSymbolAtLocation(prop.initializer);
|
|
47
|
+
if (symbol) {
|
|
48
|
+
const decl = symbol.valueDeclaration || symbol.declarations?.[0];
|
|
49
|
+
if (decl) {
|
|
50
|
+
if (ts.isImportSpecifier(decl)) {
|
|
51
|
+
const aliasedSymbol = checker.getAliasedSymbol(symbol);
|
|
52
|
+
if (aliasedSymbol) {
|
|
53
|
+
const aliasedDecl = aliasedSymbol.valueDeclaration ||
|
|
54
|
+
aliasedSymbol.declarations?.[0];
|
|
55
|
+
if (aliasedDecl) {
|
|
56
|
+
schemaSourceFile = aliasedDecl.getSourceFile().fileName;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
schemaSourceFile = decl.getSourceFile().fileName;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let oauth2 = undefined;
|
|
70
|
+
const oauth2Prop = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
71
|
+
ts.isIdentifier(p.name) &&
|
|
72
|
+
p.name.text === 'oauth2');
|
|
73
|
+
if (oauth2Prop &&
|
|
74
|
+
ts.isPropertyAssignment(oauth2Prop) &&
|
|
75
|
+
ts.isObjectLiteralExpression(oauth2Prop.initializer)) {
|
|
76
|
+
const oauth2Obj = oauth2Prop.initializer;
|
|
77
|
+
const appCredentialSecretId = getPropertyValue(oauth2Obj, 'appCredentialSecretId');
|
|
78
|
+
const tokenSecretId = getPropertyValue(oauth2Obj, 'tokenSecretId');
|
|
79
|
+
const authorizationUrl = getPropertyValue(oauth2Obj, 'authorizationUrl');
|
|
80
|
+
const tokenUrl = getPropertyValue(oauth2Obj, 'tokenUrl');
|
|
81
|
+
const scopes = getArrayPropertyValue(oauth2Obj, 'scopes');
|
|
82
|
+
const pkce = getPropertyValue(oauth2Obj, 'pkce');
|
|
83
|
+
if (appCredentialSecretId && authorizationUrl && tokenUrl && scopes) {
|
|
84
|
+
oauth2 = {
|
|
85
|
+
appCredentialSecretId,
|
|
86
|
+
tokenSecretId: tokenSecretId || undefined,
|
|
87
|
+
authorizationUrl,
|
|
88
|
+
tokenUrl,
|
|
89
|
+
scopes,
|
|
90
|
+
pkce: pkce || undefined,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const sourceFile = node.getSourceFile().fileName;
|
|
95
|
+
state.credentials.files.add(sourceFile);
|
|
96
|
+
let schemaLookupName;
|
|
97
|
+
if (schemaVariableName && schemaSourceFile && schemaIdentifier) {
|
|
98
|
+
const vendor = detectSchemaVendorOrError(schemaIdentifier, checker, logger, `Credential '${nameValue}'`, schemaSourceFile);
|
|
99
|
+
if (vendor) {
|
|
100
|
+
schemaLookupName = `CredentialSchema_${nameValue}`;
|
|
101
|
+
state.schemaLookup.set(schemaLookupName, {
|
|
102
|
+
variableName: schemaVariableName,
|
|
103
|
+
sourceFile: schemaSourceFile,
|
|
104
|
+
vendor,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
state.credentials.definitions.push({
|
|
109
|
+
name: nameValue,
|
|
110
|
+
displayName: displayNameValue,
|
|
111
|
+
description: descriptionValue || undefined,
|
|
112
|
+
type: typeValue,
|
|
113
|
+
schema: schemaLookupName,
|
|
114
|
+
oauth2,
|
|
115
|
+
sourceFile,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
};
|
package/dist/add/add-secret.d.ts
CHANGED
package/dist/add/add-secret.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue, getArrayPropertyValue, } from '../utils/get-property-value.js';
|
|
3
|
-
import { ErrorCode } from '../error-codes.js';
|
|
4
1
|
import { createAddKeyedWiring } from './add-keyed-wiring.js';
|
|
5
2
|
export const addSecret = createAddKeyedWiring({
|
|
6
3
|
functionName: 'wireSecret',
|
|
@@ -9,74 +6,3 @@ export const addSecret = createAddKeyedWiring({
|
|
|
9
6
|
schemaPrefix: 'SecretSchema',
|
|
10
7
|
getState: (state) => state.secrets,
|
|
11
8
|
});
|
|
12
|
-
export const addOAuth2Credential = (logger, node, _checker, state, _options) => {
|
|
13
|
-
if (!ts.isCallExpression(node)) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const args = node.arguments;
|
|
17
|
-
const firstArg = args[0];
|
|
18
|
-
const expression = node.expression;
|
|
19
|
-
if (!ts.isIdentifier(expression) ||
|
|
20
|
-
expression.text !== 'wireOAuth2Credential') {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (!firstArg) {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
27
|
-
const obj = firstArg;
|
|
28
|
-
const nameValue = getPropertyValue(obj, 'name');
|
|
29
|
-
const displayNameValue = getPropertyValue(obj, 'displayName');
|
|
30
|
-
const descriptionValue = getPropertyValue(obj, 'description');
|
|
31
|
-
const secretIdValue = getPropertyValue(obj, 'secretId');
|
|
32
|
-
const tokenSecretIdValue = getPropertyValue(obj, 'tokenSecretId');
|
|
33
|
-
const authorizationUrlValue = getPropertyValue(obj, 'authorizationUrl');
|
|
34
|
-
const tokenUrlValue = getPropertyValue(obj, 'tokenUrl');
|
|
35
|
-
const scopesValue = getArrayPropertyValue(obj, 'scopes');
|
|
36
|
-
const pkceValue = getPropertyValue(obj, 'pkce');
|
|
37
|
-
if (!nameValue) {
|
|
38
|
-
logger.critical(ErrorCode.MISSING_NAME, "OAuth2 Credential is missing the required 'name' property.");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (!displayNameValue) {
|
|
42
|
-
logger.critical(ErrorCode.MISSING_NAME, `OAuth2 Credential '${nameValue}' is missing the required 'displayName' property.`);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (!secretIdValue) {
|
|
46
|
-
logger.critical(ErrorCode.MISSING_NAME, `OAuth2 Credential '${nameValue}' is missing the required 'secretId' property.`);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (!tokenSecretIdValue) {
|
|
50
|
-
logger.critical(ErrorCode.MISSING_NAME, `OAuth2 Credential '${nameValue}' is missing the required 'tokenSecretId' property.`);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
if (!authorizationUrlValue) {
|
|
54
|
-
logger.critical(ErrorCode.MISSING_NAME, `OAuth2 Credential '${nameValue}' is missing the required 'authorizationUrl' property.`);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (!tokenUrlValue) {
|
|
58
|
-
logger.critical(ErrorCode.MISSING_NAME, `OAuth2 Credential '${nameValue}' is missing the required 'tokenUrl' property.`);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (!scopesValue || scopesValue.length === 0) {
|
|
62
|
-
logger.critical(ErrorCode.MISSING_NAME, `OAuth2 Credential '${nameValue}' is missing the required 'scopes' property.`);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
const sourceFile = node.getSourceFile().fileName;
|
|
66
|
-
state.secrets.files.add(sourceFile);
|
|
67
|
-
state.secrets.definitions.push({
|
|
68
|
-
name: nameValue,
|
|
69
|
-
displayName: displayNameValue,
|
|
70
|
-
description: descriptionValue || undefined,
|
|
71
|
-
secretId: secretIdValue,
|
|
72
|
-
oauth2: {
|
|
73
|
-
tokenSecretId: tokenSecretIdValue,
|
|
74
|
-
authorizationUrl: authorizationUrlValue,
|
|
75
|
-
tokenUrl: tokenUrlValue,
|
|
76
|
-
scopes: scopesValue,
|
|
77
|
-
pkce: pkceValue || undefined,
|
|
78
|
-
},
|
|
79
|
-
sourceFile,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
};
|
package/dist/inspector.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { AIAgentMeta } from '@pikku/core/ai-agent';
|
|
|
11
11
|
import type { CLIMeta } from '@pikku/core/cli';
|
|
12
12
|
import type { NodesMeta } from '@pikku/core/node';
|
|
13
13
|
import type { SecretDefinitions } from '@pikku/core/secret';
|
|
14
|
+
import type { CredentialDefinitions } from '@pikku/core/credential';
|
|
14
15
|
import type { VariableDefinitions } from '@pikku/core/variable';
|
|
15
16
|
import type { TypesMap } from './types-map.js';
|
|
16
17
|
import type { FunctionsMeta, FunctionServicesMeta, FunctionWiresMeta, JSONValue } from '@pikku/core';
|
|
@@ -349,6 +350,10 @@ export interface InspectorState {
|
|
|
349
350
|
definitions: SecretDefinitions;
|
|
350
351
|
files: Set<string>;
|
|
351
352
|
};
|
|
353
|
+
credentials: {
|
|
354
|
+
definitions: CredentialDefinitions;
|
|
355
|
+
files: Set<string>;
|
|
356
|
+
};
|
|
352
357
|
variables: {
|
|
353
358
|
definitions: VariableDefinitions;
|
|
354
359
|
files: Set<string>;
|
|
@@ -205,6 +205,10 @@ export interface SerializableInspectorState {
|
|
|
205
205
|
definitions: InspectorState['secrets']['definitions'];
|
|
206
206
|
files: string[];
|
|
207
207
|
};
|
|
208
|
+
credentials: {
|
|
209
|
+
definitions: InspectorState['credentials']['definitions'];
|
|
210
|
+
files: string[];
|
|
211
|
+
};
|
|
208
212
|
variables: {
|
|
209
213
|
definitions: InspectorState['variables']['definitions'];
|
|
210
214
|
files: string[];
|
|
@@ -101,6 +101,10 @@ export function serializeInspectorState(state) {
|
|
|
101
101
|
definitions: state.secrets.definitions,
|
|
102
102
|
files: Array.from(state.secrets.files),
|
|
103
103
|
},
|
|
104
|
+
credentials: {
|
|
105
|
+
definitions: state.credentials.definitions,
|
|
106
|
+
files: Array.from(state.credentials.files),
|
|
107
|
+
},
|
|
104
108
|
variables: {
|
|
105
109
|
definitions: state.variables.definitions,
|
|
106
110
|
files: Array.from(state.variables.files),
|
|
@@ -244,6 +248,10 @@ export function deserializeInspectorState(data) {
|
|
|
244
248
|
definitions: data.secrets?.definitions || [],
|
|
245
249
|
files: new Set(data.secrets?.files || []),
|
|
246
250
|
},
|
|
251
|
+
credentials: {
|
|
252
|
+
definitions: data.credentials?.definitions || [],
|
|
253
|
+
files: new Set(data.credentials?.files || []),
|
|
254
|
+
},
|
|
247
255
|
variables: {
|
|
248
256
|
definitions: data.variables?.definitions || [],
|
|
249
257
|
files: new Set(data.variables?.files || []),
|
package/dist/visit.js
CHANGED
|
@@ -17,7 +17,8 @@ import { addWireAddon } from './add/add-wire-addon.js';
|
|
|
17
17
|
import { addMiddleware } from './add/add-middleware.js';
|
|
18
18
|
import { addPermission } from './add/add-permission.js';
|
|
19
19
|
import { addCLI, addCLIRenderers } from './add/add-cli.js';
|
|
20
|
-
import { addSecret
|
|
20
|
+
import { addSecret } from './add/add-secret.js';
|
|
21
|
+
import { addCredential } from './add/add-credential.js';
|
|
21
22
|
import { addVariable } from './add/add-variable.js';
|
|
22
23
|
import { addWorkflowGraph } from './add/add-workflow-graph.js';
|
|
23
24
|
import { addAIAgent } from './add/add-ai-agent.js';
|
|
@@ -41,7 +42,7 @@ export const visitSetup = (logger, checker, node, state, options) => {
|
|
|
41
42
|
export const visitRoutes = (logger, checker, node, state, options) => {
|
|
42
43
|
addFunctions(logger, node, checker, state, options);
|
|
43
44
|
addSecret(logger, node, checker, state, options);
|
|
44
|
-
|
|
45
|
+
addCredential(logger, node, checker, state, options);
|
|
45
46
|
addVariable(logger, node, checker, state, options);
|
|
46
47
|
addHTTPRoute(logger, node, checker, state, options);
|
|
47
48
|
addHTTPRoutes(logger, node, checker, state, options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.5",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@openapi-contrib/json-schema-to-openapi-schema": "^4.3.1",
|
|
38
|
-
"@pikku/core": "^0.12.
|
|
38
|
+
"@pikku/core": "^0.12.10",
|
|
39
39
|
"path-to-regexp": "^8.3.0",
|
|
40
40
|
"ts-json-schema-generator": "^2.5.0",
|
|
41
41
|
"tsx": "^4.21.0",
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import {
|
|
3
|
+
getPropertyValue,
|
|
4
|
+
getArrayPropertyValue,
|
|
5
|
+
} from '../utils/get-property-value.js'
|
|
6
|
+
import type { AddWiring } from '../types.js'
|
|
7
|
+
import { ErrorCode } from '../error-codes.js'
|
|
8
|
+
import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js'
|
|
9
|
+
|
|
10
|
+
export const addCredential: AddWiring = (
|
|
11
|
+
logger,
|
|
12
|
+
node,
|
|
13
|
+
checker,
|
|
14
|
+
state,
|
|
15
|
+
_options
|
|
16
|
+
) => {
|
|
17
|
+
if (!ts.isCallExpression(node)) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const args = node.arguments
|
|
22
|
+
const firstArg = args[0]
|
|
23
|
+
const expression = node.expression
|
|
24
|
+
|
|
25
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireCredential') {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!firstArg) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
34
|
+
const obj = firstArg
|
|
35
|
+
|
|
36
|
+
const nameValue = getPropertyValue(obj, 'name') as string | null
|
|
37
|
+
const displayNameValue = getPropertyValue(obj, 'displayName') as
|
|
38
|
+
| string
|
|
39
|
+
| null
|
|
40
|
+
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
41
|
+
| string
|
|
42
|
+
| null
|
|
43
|
+
const typeValue = getPropertyValue(obj, 'type') as string | null
|
|
44
|
+
|
|
45
|
+
if (!nameValue) {
|
|
46
|
+
logger.critical(
|
|
47
|
+
ErrorCode.MISSING_NAME,
|
|
48
|
+
"Credential is missing the required 'name' property."
|
|
49
|
+
)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!displayNameValue) {
|
|
54
|
+
logger.critical(
|
|
55
|
+
ErrorCode.MISSING_NAME,
|
|
56
|
+
`Credential '${nameValue}' is missing the required 'displayName' property.`
|
|
57
|
+
)
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!typeValue || (typeValue !== 'singleton' && typeValue !== 'wire')) {
|
|
62
|
+
logger.critical(
|
|
63
|
+
ErrorCode.MISSING_NAME,
|
|
64
|
+
`Credential '${nameValue}' is missing or has invalid 'type' property. Must be 'singleton' or 'wire'.`
|
|
65
|
+
)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let schemaVariableName: string | null = null
|
|
70
|
+
let schemaSourceFile: string | null = null
|
|
71
|
+
let schemaIdentifier: ts.Identifier | null = null
|
|
72
|
+
for (const prop of obj.properties) {
|
|
73
|
+
if (
|
|
74
|
+
ts.isPropertyAssignment(prop) &&
|
|
75
|
+
ts.isIdentifier(prop.name) &&
|
|
76
|
+
prop.name.text === 'schema'
|
|
77
|
+
) {
|
|
78
|
+
if (ts.isIdentifier(prop.initializer)) {
|
|
79
|
+
schemaVariableName = prop.initializer.text
|
|
80
|
+
schemaIdentifier = prop.initializer
|
|
81
|
+
|
|
82
|
+
const symbol = checker.getSymbolAtLocation(prop.initializer)
|
|
83
|
+
if (symbol) {
|
|
84
|
+
const decl = symbol.valueDeclaration || symbol.declarations?.[0]
|
|
85
|
+
if (decl) {
|
|
86
|
+
if (ts.isImportSpecifier(decl)) {
|
|
87
|
+
const aliasedSymbol = checker.getAliasedSymbol(symbol)
|
|
88
|
+
if (aliasedSymbol) {
|
|
89
|
+
const aliasedDecl =
|
|
90
|
+
aliasedSymbol.valueDeclaration ||
|
|
91
|
+
aliasedSymbol.declarations?.[0]
|
|
92
|
+
if (aliasedDecl) {
|
|
93
|
+
schemaSourceFile = aliasedDecl.getSourceFile().fileName
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
schemaSourceFile = decl.getSourceFile().fileName
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
break
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let oauth2: any = undefined
|
|
107
|
+
const oauth2Prop = obj.properties.find(
|
|
108
|
+
(p) =>
|
|
109
|
+
ts.isPropertyAssignment(p) &&
|
|
110
|
+
ts.isIdentifier(p.name) &&
|
|
111
|
+
p.name.text === 'oauth2'
|
|
112
|
+
)
|
|
113
|
+
if (
|
|
114
|
+
oauth2Prop &&
|
|
115
|
+
ts.isPropertyAssignment(oauth2Prop) &&
|
|
116
|
+
ts.isObjectLiteralExpression(oauth2Prop.initializer)
|
|
117
|
+
) {
|
|
118
|
+
const oauth2Obj = oauth2Prop.initializer
|
|
119
|
+
const appCredentialSecretId = getPropertyValue(
|
|
120
|
+
oauth2Obj,
|
|
121
|
+
'appCredentialSecretId'
|
|
122
|
+
) as string | null
|
|
123
|
+
const tokenSecretId = getPropertyValue(oauth2Obj, 'tokenSecretId') as
|
|
124
|
+
| string
|
|
125
|
+
| null
|
|
126
|
+
const authorizationUrl = getPropertyValue(
|
|
127
|
+
oauth2Obj,
|
|
128
|
+
'authorizationUrl'
|
|
129
|
+
) as string | null
|
|
130
|
+
const tokenUrl = getPropertyValue(oauth2Obj, 'tokenUrl') as string | null
|
|
131
|
+
const scopes = getArrayPropertyValue(oauth2Obj, 'scopes')
|
|
132
|
+
const pkce = getPropertyValue(oauth2Obj, 'pkce') as boolean | null
|
|
133
|
+
|
|
134
|
+
if (appCredentialSecretId && authorizationUrl && tokenUrl && scopes) {
|
|
135
|
+
oauth2 = {
|
|
136
|
+
appCredentialSecretId,
|
|
137
|
+
tokenSecretId: tokenSecretId || undefined,
|
|
138
|
+
authorizationUrl,
|
|
139
|
+
tokenUrl,
|
|
140
|
+
scopes,
|
|
141
|
+
pkce: pkce || undefined,
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const sourceFile = node.getSourceFile().fileName
|
|
147
|
+
state.credentials.files.add(sourceFile)
|
|
148
|
+
|
|
149
|
+
let schemaLookupName: string | undefined
|
|
150
|
+
if (schemaVariableName && schemaSourceFile && schemaIdentifier) {
|
|
151
|
+
const vendor = detectSchemaVendorOrError(
|
|
152
|
+
schemaIdentifier,
|
|
153
|
+
checker,
|
|
154
|
+
logger,
|
|
155
|
+
`Credential '${nameValue}'`,
|
|
156
|
+
schemaSourceFile
|
|
157
|
+
)
|
|
158
|
+
if (vendor) {
|
|
159
|
+
schemaLookupName = `CredentialSchema_${nameValue}`
|
|
160
|
+
state.schemaLookup.set(schemaLookupName, {
|
|
161
|
+
variableName: schemaVariableName,
|
|
162
|
+
sourceFile: schemaSourceFile,
|
|
163
|
+
vendor,
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
state.credentials.definitions.push({
|
|
169
|
+
name: nameValue,
|
|
170
|
+
displayName: displayNameValue,
|
|
171
|
+
description: descriptionValue || undefined,
|
|
172
|
+
type: typeValue as 'singleton' | 'wire',
|
|
173
|
+
schema: schemaLookupName,
|
|
174
|
+
oauth2,
|
|
175
|
+
sourceFile,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
}
|
package/src/add/add-secret.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import {
|
|
3
|
-
getPropertyValue,
|
|
4
|
-
getArrayPropertyValue,
|
|
5
|
-
} from '../utils/get-property-value.js'
|
|
6
|
-
import type { AddWiring } from '../types.js'
|
|
7
|
-
import { ErrorCode } from '../error-codes.js'
|
|
8
1
|
import { createAddKeyedWiring } from './add-keyed-wiring.js'
|
|
9
2
|
|
|
10
3
|
export const addSecret = createAddKeyedWiring({
|
|
@@ -14,127 +7,3 @@ export const addSecret = createAddKeyedWiring({
|
|
|
14
7
|
schemaPrefix: 'SecretSchema',
|
|
15
8
|
getState: (state) => state.secrets,
|
|
16
9
|
})
|
|
17
|
-
|
|
18
|
-
export const addOAuth2Credential: 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 (
|
|
34
|
-
!ts.isIdentifier(expression) ||
|
|
35
|
-
expression.text !== 'wireOAuth2Credential'
|
|
36
|
-
) {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (!firstArg) {
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
45
|
-
const obj = firstArg
|
|
46
|
-
|
|
47
|
-
const nameValue = getPropertyValue(obj, 'name') as string | null
|
|
48
|
-
const displayNameValue = getPropertyValue(obj, 'displayName') as
|
|
49
|
-
| string
|
|
50
|
-
| null
|
|
51
|
-
const descriptionValue = getPropertyValue(obj, 'description') as
|
|
52
|
-
| string
|
|
53
|
-
| null
|
|
54
|
-
const secretIdValue = getPropertyValue(obj, 'secretId') as string | null
|
|
55
|
-
const tokenSecretIdValue = getPropertyValue(obj, 'tokenSecretId') as
|
|
56
|
-
| string
|
|
57
|
-
| null
|
|
58
|
-
const authorizationUrlValue = getPropertyValue(obj, 'authorizationUrl') as
|
|
59
|
-
| string
|
|
60
|
-
| null
|
|
61
|
-
const tokenUrlValue = getPropertyValue(obj, 'tokenUrl') as string | null
|
|
62
|
-
const scopesValue = getArrayPropertyValue(obj, 'scopes')
|
|
63
|
-
const pkceValue = getPropertyValue(obj, 'pkce') as boolean | null
|
|
64
|
-
|
|
65
|
-
if (!nameValue) {
|
|
66
|
-
logger.critical(
|
|
67
|
-
ErrorCode.MISSING_NAME,
|
|
68
|
-
"OAuth2 Credential is missing the required 'name' property."
|
|
69
|
-
)
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!displayNameValue) {
|
|
74
|
-
logger.critical(
|
|
75
|
-
ErrorCode.MISSING_NAME,
|
|
76
|
-
`OAuth2 Credential '${nameValue}' is missing the required 'displayName' property.`
|
|
77
|
-
)
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!secretIdValue) {
|
|
82
|
-
logger.critical(
|
|
83
|
-
ErrorCode.MISSING_NAME,
|
|
84
|
-
`OAuth2 Credential '${nameValue}' is missing the required 'secretId' property.`
|
|
85
|
-
)
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!tokenSecretIdValue) {
|
|
90
|
-
logger.critical(
|
|
91
|
-
ErrorCode.MISSING_NAME,
|
|
92
|
-
`OAuth2 Credential '${nameValue}' is missing the required 'tokenSecretId' property.`
|
|
93
|
-
)
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (!authorizationUrlValue) {
|
|
98
|
-
logger.critical(
|
|
99
|
-
ErrorCode.MISSING_NAME,
|
|
100
|
-
`OAuth2 Credential '${nameValue}' is missing the required 'authorizationUrl' property.`
|
|
101
|
-
)
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (!tokenUrlValue) {
|
|
106
|
-
logger.critical(
|
|
107
|
-
ErrorCode.MISSING_NAME,
|
|
108
|
-
`OAuth2 Credential '${nameValue}' is missing the required 'tokenUrl' property.`
|
|
109
|
-
)
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (!scopesValue || scopesValue.length === 0) {
|
|
114
|
-
logger.critical(
|
|
115
|
-
ErrorCode.MISSING_NAME,
|
|
116
|
-
`OAuth2 Credential '${nameValue}' is missing the required 'scopes' property.`
|
|
117
|
-
)
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const sourceFile = node.getSourceFile().fileName
|
|
122
|
-
|
|
123
|
-
state.secrets.files.add(sourceFile)
|
|
124
|
-
|
|
125
|
-
state.secrets.definitions.push({
|
|
126
|
-
name: nameValue,
|
|
127
|
-
displayName: displayNameValue,
|
|
128
|
-
description: descriptionValue || undefined,
|
|
129
|
-
secretId: secretIdValue,
|
|
130
|
-
oauth2: {
|
|
131
|
-
tokenSecretId: tokenSecretIdValue,
|
|
132
|
-
authorizationUrl: authorizationUrlValue,
|
|
133
|
-
tokenUrl: tokenUrlValue,
|
|
134
|
-
scopes: scopesValue,
|
|
135
|
-
pkce: pkceValue || undefined,
|
|
136
|
-
},
|
|
137
|
-
sourceFile,
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
}
|
package/src/inspector.ts
CHANGED
|
@@ -148,6 +148,10 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
|
|
|
148
148
|
definitions: [],
|
|
149
149
|
files: new Set(),
|
|
150
150
|
},
|
|
151
|
+
credentials: {
|
|
152
|
+
definitions: [],
|
|
153
|
+
files: new Set(),
|
|
154
|
+
},
|
|
151
155
|
variables: {
|
|
152
156
|
definitions: [],
|
|
153
157
|
files: new Set(),
|
package/src/types.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type { AIAgentMeta } from '@pikku/core/ai-agent'
|
|
|
15
15
|
import type { CLIMeta } from '@pikku/core/cli'
|
|
16
16
|
import type { NodesMeta } from '@pikku/core/node'
|
|
17
17
|
import type { SecretDefinitions } from '@pikku/core/secret'
|
|
18
|
+
import type { CredentialDefinitions } from '@pikku/core/credential'
|
|
18
19
|
import type { VariableDefinitions } from '@pikku/core/variable'
|
|
19
20
|
import type { TypesMap } from './types-map.js'
|
|
20
21
|
import type {
|
|
@@ -379,6 +380,10 @@ export interface InspectorState {
|
|
|
379
380
|
definitions: SecretDefinitions
|
|
380
381
|
files: Set<string>
|
|
381
382
|
}
|
|
383
|
+
credentials: {
|
|
384
|
+
definitions: CredentialDefinitions
|
|
385
|
+
files: Set<string>
|
|
386
|
+
}
|
|
382
387
|
variables: {
|
|
383
388
|
definitions: VariableDefinitions
|
|
384
389
|
files: Set<string>
|