@pikku/inspector 0.12.42 → 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.
Files changed (102) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/dist/add/add-addon-bans.js +1 -0
  3. package/dist/add/add-ai-agent.d.ts +3 -1
  4. package/dist/add/add-ai-agent.js +82 -0
  5. package/dist/add/add-credential.js +3 -1
  6. package/dist/add/add-functions.js +10 -9
  7. package/dist/add/add-gateway.js +3 -0
  8. package/dist/add/add-http-route.js +2 -2
  9. package/dist/add/add-mcp-prompt.js +0 -1
  10. package/dist/add/add-mcp-resource.js +0 -1
  11. package/dist/add/add-permission.d.ts +1 -1
  12. package/dist/add/add-permission.js +3 -177
  13. package/dist/add/add-queue-worker.js +3 -0
  14. package/dist/add/add-schedule.js +3 -0
  15. package/dist/add/add-scope.d.ts +2 -0
  16. package/dist/add/add-scope.js +146 -0
  17. package/dist/add/add-trigger.js +3 -0
  18. package/dist/add/add-wire-remote-addon.d.ts +10 -0
  19. package/dist/add/add-wire-remote-addon.js +66 -0
  20. package/dist/add/add-workflow-graph.js +32 -3
  21. package/dist/error-codes.d.ts +3 -0
  22. package/dist/error-codes.js +4 -0
  23. package/dist/inspector.js +11 -5
  24. package/dist/types.d.ts +19 -13
  25. package/dist/utils/custom-types-generator.js +2 -1
  26. package/dist/utils/ensure-function-metadata.d.ts +15 -0
  27. package/dist/utils/ensure-function-metadata.js +24 -0
  28. package/dist/utils/filter-inspector-state.js +9 -0
  29. package/dist/utils/get-property-value.d.ts +7 -2
  30. package/dist/utils/get-property-value.js +48 -1
  31. package/dist/utils/load-addon-functions-meta.js +81 -6
  32. package/dist/utils/permissions.d.ts +1 -21
  33. package/dist/utils/permissions.js +17 -108
  34. package/dist/utils/post-process.d.ts +30 -1
  35. package/dist/utils/post-process.js +150 -72
  36. package/dist/utils/serialize-inspector-state.d.ts +13 -8
  37. package/dist/utils/serialize-inspector-state.js +12 -6
  38. package/dist/utils/serialize-permissions-groups-meta.d.ts +0 -2
  39. package/dist/utils/serialize-permissions-groups-meta.js +0 -26
  40. package/dist/utils/workflow/derive-workflow-plan.js +9 -3
  41. package/dist/utils/workflow/dsl/extract-dsl-workflow.js +56 -1
  42. package/dist/utils/workflow/dsl/patterns.d.ts +4 -0
  43. package/dist/utils/workflow/dsl/patterns.js +11 -0
  44. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +14 -0
  45. package/dist/utils/workflow/graph/finalize-workflows.d.ts +7 -0
  46. package/dist/utils/workflow/graph/finalize-workflows.js +11 -2
  47. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +2 -0
  48. package/dist/utils/workflow/graph/serialize-workflow-graph.js +4 -0
  49. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +6 -2
  50. package/dist/visit.js +4 -0
  51. package/package.json +3 -3
  52. package/src/add/add-addon-bans.ts +1 -0
  53. package/src/add/add-ai-agent.test.ts +87 -0
  54. package/src/add/add-ai-agent.ts +122 -0
  55. package/src/add/add-credential.ts +6 -0
  56. package/src/add/add-functions.ts +10 -12
  57. package/src/add/add-gateway.ts +11 -0
  58. package/src/add/add-http-route.ts +2 -8
  59. package/src/add/add-mcp-prompt.ts +0 -1
  60. package/src/add/add-mcp-resource.ts +0 -1
  61. package/src/add/add-permission.ts +4 -242
  62. package/src/add/add-queue-worker.ts +11 -0
  63. package/src/add/add-schedule.ts +11 -0
  64. package/src/add/add-scope.test.ts +346 -0
  65. package/src/add/add-scope.ts +225 -0
  66. package/src/add/add-trigger.ts +11 -0
  67. package/src/add/add-wire-remote-addon.ts +77 -0
  68. package/src/add/add-workflow-graph-input.test.ts +94 -0
  69. package/src/add/add-workflow-graph-notes.test.ts +74 -0
  70. package/src/add/add-workflow-graph.ts +35 -3
  71. package/src/add/inline-wiring-function.test.ts +104 -0
  72. package/src/add/validate-workflow-graph-addons.test.ts +102 -0
  73. package/src/error-codes.ts +5 -0
  74. package/src/inspector.ts +14 -4
  75. package/src/types.ts +16 -17
  76. package/src/utils/custom-types-generator.test.ts +26 -1
  77. package/src/utils/custom-types-generator.ts +2 -1
  78. package/src/utils/ensure-function-metadata.ts +42 -0
  79. package/src/utils/filter-inspector-state.test.ts +0 -2
  80. package/src/utils/filter-inspector-state.ts +9 -0
  81. package/src/utils/get-property-value.test.ts +141 -0
  82. package/src/utils/get-property-value.ts +62 -1
  83. package/src/utils/load-addon-functions-meta.test.ts +157 -0
  84. package/src/utils/load-addon-functions-meta.ts +94 -6
  85. package/src/utils/load-addon-scopes.test.ts +138 -0
  86. package/src/utils/permissions.test.ts +7 -232
  87. package/src/utils/permissions.ts +20 -160
  88. package/src/utils/post-process.test.ts +269 -4
  89. package/src/utils/post-process.ts +216 -95
  90. package/src/utils/serialize-inspector-state.ts +22 -25
  91. package/src/utils/serialize-permissions-groups-meta.ts +0 -28
  92. package/src/utils/workflow/derive-workflow-plan.test.ts +41 -3
  93. package/src/utils/workflow/derive-workflow-plan.ts +11 -4
  94. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +66 -0
  95. package/src/utils/workflow/dsl/patterns.ts +18 -0
  96. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +15 -0
  97. package/src/utils/workflow/graph/finalize-workflows.test.ts +50 -0
  98. package/src/utils/workflow/graph/finalize-workflows.ts +13 -2
  99. package/src/utils/workflow/graph/serialize-workflow-graph.ts +6 -0
  100. package/src/utils/workflow/graph/workflow-graph.types.ts +8 -0
  101. package/src/visit.ts +4 -0
  102. package/tsconfig.tsbuildinfo +1 -1
@@ -4,12 +4,21 @@ import { extractStringLiteral } from './extract-node-value.js';
4
4
  /**
5
5
  * Extracts an array of strings from an object property.
6
6
  */
7
+ /**
8
+ * Unwraps `x as const` / `x as any` / `x satisfies T` down to the underlying
9
+ * expression. Without this a cast makes the value invisible to the inspector,
10
+ * so it is silently dropped from meta rather than validated — and `as const` on
11
+ * an array is idiomatic enough that this is easy to hit by accident.
12
+ */
13
+ const unwrapAs = (node) => ts.isAsExpression(node) || ts.isSatisfiesExpression(node)
14
+ ? unwrapAs(node.expression)
15
+ : node;
7
16
  export const getArrayPropertyValue = (obj, propertyName) => {
8
17
  const property = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
9
18
  ts.isIdentifier(p.name) &&
10
19
  p.name.text === propertyName);
11
20
  if (property && ts.isPropertyAssignment(property)) {
12
- const initializer = property.initializer;
21
+ const initializer = unwrapAs(property.initializer);
13
22
  if (ts.isArrayLiteralExpression(initializer)) {
14
23
  return initializer.elements
15
24
  .filter(ts.isStringLiteral)
@@ -18,6 +27,44 @@ export const getArrayPropertyValue = (obj, propertyName) => {
18
27
  }
19
28
  return null;
20
29
  };
30
+ /**
31
+ * Extracts a string->string record from an object property.
32
+ *
33
+ * `getPropertyValue` falls through to `getText()` for an object literal, which
34
+ * returns the raw source text rather than the record — so callers that need the
35
+ * entries (e.g. oauth2 `additionalParams`) must use this instead.
36
+ */
37
+ export const getRecordPropertyValue = (obj, propertyName) => {
38
+ const property = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
39
+ ts.isIdentifier(p.name) &&
40
+ p.name.text === propertyName);
41
+ if (!property || !ts.isPropertyAssignment(property)) {
42
+ return null;
43
+ }
44
+ const initializer = property.initializer;
45
+ if (!ts.isObjectLiteralExpression(initializer)) {
46
+ return null;
47
+ }
48
+ const record = {};
49
+ for (const prop of initializer.properties) {
50
+ if (!ts.isPropertyAssignment(prop)) {
51
+ continue;
52
+ }
53
+ const key = ts.isIdentifier(prop.name)
54
+ ? prop.name.text
55
+ : ts.isStringLiteral(prop.name)
56
+ ? prop.name.text
57
+ : null;
58
+ if (key === null) {
59
+ continue;
60
+ }
61
+ if (ts.isStringLiteral(prop.initializer) ||
62
+ ts.isNoSubstitutionTemplateLiteral(prop.initializer)) {
63
+ record[key] = prop.initializer.text;
64
+ }
65
+ }
66
+ return Object.keys(record).length > 0 ? record : null;
67
+ };
21
68
  /**
22
69
  * Wiring identity fields (`name`, `secretId`, `variableId`, …) are read
23
70
  * STATICALLY from source — a const or variable reference is keyed by its
@@ -80,6 +80,11 @@ export async function loadAddonFunctionsMeta(logger, state) {
80
80
  return;
81
81
  const require = createRequire(join(state.rootDir, 'package.json'));
82
82
  for (const [namespace, decl] of wireAddonDeclarations) {
83
+ // Remote addons (wireRemoteAddon) ship as a devDependency: types only.
84
+ // Their functions, secrets, variables, schemas and services live on the
85
+ // HOST that runs them — never load or require any of that here.
86
+ if (decl.remote)
87
+ continue;
83
88
  try {
84
89
  const metaPath = require.resolve(`${decl.package}/.pikku/function/pikku-functions-meta.gen.json`);
85
90
  const raw = await readFile(metaPath, 'utf-8');
@@ -108,32 +113,99 @@ export async function loadAddonFunctionsMeta(logger, state) {
108
113
  const secretsRaw = await readFile(secretsMetaPath, 'utf-8');
109
114
  const secretsMeta = JSON.parse(secretsRaw);
110
115
  for (const [key, def] of Object.entries(secretsMeta)) {
111
- const existing = state.secrets.definitions.find((d) => d.name === key);
116
+ // secretOverrides key on the SECRET ID (the string the addon passes to
117
+ // getSecret — its typed map is keyed by secretId, e.g.
118
+ // `getSecret('MAILGUN_CREDENTIALS')`), NOT the logical meta key, so the
119
+ // runtime aliaser (which also keys on secretId) and this merge agree.
120
+ // The resolved id is the real project secret; the addon's secretId is
121
+ // the default when no override is given. Two instances with different
122
+ // overrides therefore surface two distinct project secrets. `key` is
123
+ // the fallback for older meta that predates the secretId field.
124
+ const secretId = def.secretId ?? key;
125
+ const resolvedSecretId = decl.secretOverrides?.[secretId] ?? secretId;
126
+ const existing = state.secrets.definitions.find((d) => (d.secretId ?? d.name) === resolvedSecretId);
112
127
  if (!existing) {
113
- state.secrets.definitions.push(def);
114
- logger.debug(`Loaded addon secret '${key}' from ${decl.package}`);
128
+ state.secrets.definitions.push({
129
+ ...def,
130
+ secretId: resolvedSecretId,
131
+ });
132
+ logger.debug(`Loaded addon secret '${resolvedSecretId}' from ${decl.package}`);
115
133
  }
116
134
  }
117
135
  }
118
136
  catch {
119
137
  // No secrets meta — that's fine
120
138
  }
139
+ // Load addon scopes meta. Without this an addon's own scopes never reach
140
+ // the host's ScopeId union or its declared set, so the pikku_scopes FK
141
+ // would refuse to grant one.
142
+ try {
143
+ const scopesMetaPath = require.resolve(`${decl.package}/.pikku/scopes/pikku-scopes-meta.gen.json`);
144
+ const scopesRaw = await readFile(scopesMetaPath, 'utf-8');
145
+ const scopesMeta = JSON.parse(scopesRaw);
146
+ for (const [key, def] of Object.entries(scopesMeta)) {
147
+ const existing = state.scopes.definitions.find((d) => d.name === key);
148
+ if (!existing) {
149
+ state.scopes.definitions.push(def);
150
+ logger.debug(`Loaded addon scope '${key}' from ${decl.package}`);
151
+ }
152
+ }
153
+ }
154
+ catch {
155
+ // No scopes meta — that's fine
156
+ }
121
157
  // Load addon variables meta
122
158
  try {
123
159
  const variablesMetaPath = require.resolve(`${decl.package}/.pikku/variables/pikku-variables-meta.gen.json`);
124
160
  const variablesRaw = await readFile(variablesMetaPath, 'utf-8');
125
161
  const variablesMeta = JSON.parse(variablesRaw);
126
162
  for (const [key, def] of Object.entries(variablesMeta)) {
127
- const existing = state.variables.definitions.find((d) => d.name === key);
163
+ // variableOverrides key on the VARIABLE ID (the string the addon reads
164
+ // via its typed map, keyed by variableId), same as secretOverrides key
165
+ // on secretId — so the runtime aliaser and this merge agree. `key` is
166
+ // the fallback for older meta without a variableId field.
167
+ const variableId = def.variableId ?? key;
168
+ const resolvedVariableId = decl.variableOverrides?.[variableId] ?? variableId;
169
+ const existing = state.variables.definitions.find((d) => (d.variableId ?? d.name) === resolvedVariableId);
128
170
  if (!existing) {
129
- state.variables.definitions.push(def);
130
- logger.debug(`Loaded addon variable '${key}' from ${decl.package}`);
171
+ state.variables.definitions.push({
172
+ ...def,
173
+ variableId: resolvedVariableId,
174
+ });
175
+ logger.debug(`Loaded addon variable '${resolvedVariableId}' from ${decl.package}`);
131
176
  }
132
177
  }
133
178
  }
134
179
  catch {
135
180
  // No variables meta — that's fine
136
181
  }
182
+ // Load addon credentials meta. Without this an addon's OAuth2/wire
183
+ // credentials never reach the consuming app's CREDENTIAL_OAUTH2_CONFIGS,
184
+ // so the credential-oauth provider and BetterAuthCredentialService can't
185
+ // resolve them — the addon's Connect flow and status silently no-op.
186
+ try {
187
+ const credentialsMetaPath = require.resolve(`${decl.package}/.pikku/credentials/pikku-credentials-meta.gen.json`);
188
+ const credentialsRaw = await readFile(credentialsMetaPath, 'utf-8');
189
+ const credentialsMeta = JSON.parse(credentialsRaw);
190
+ for (const [key, def] of Object.entries(credentialsMeta)) {
191
+ // Each instance's credentialOverrides remap the addon's logical
192
+ // credential name to a project credential — same mechanic as secrets
193
+ // and variables above. The credential name doubles as the better-auth
194
+ // providerId (accounts keyed by providerId+userId), so two instances
195
+ // with different overrides surface two distinct OAuth providers rather
196
+ // than sharing one account pool. The logical name is the default when
197
+ // no override is given.
198
+ const resolvedName = decl.credentialOverrides?.[key] ?? key;
199
+ const existing = state.credentials.definitions.find((d) => d.name === resolvedName);
200
+ if (!existing) {
201
+ state.credentials.definitions.push({ ...def, name: resolvedName });
202
+ logger.debug(`Loaded addon credential '${resolvedName}' from ${decl.package}`);
203
+ }
204
+ }
205
+ }
206
+ catch {
207
+ // No credentials meta — that's fine
208
+ }
137
209
  // Load addon serverlessIncompatible service names from pikku-addon-meta.gen.json
138
210
  let loadedParentServices = false;
139
211
  try {
@@ -215,6 +287,9 @@ export async function loadAddonSchemas(logger, state) {
215
287
  return;
216
288
  const require = createRequire(join(state.rootDir, 'package.json'));
217
289
  for (const [namespace, decl] of wireAddonDeclarations) {
290
+ // Remote addons carry no local schemas — their funcs run on the host.
291
+ if (decl.remote)
292
+ continue;
218
293
  try {
219
294
  const metaPath = require.resolve(`${decl.package}/.pikku/function/pikku-functions-meta.gen.json`);
220
295
  const schemasDir = join(dirname(metaPath), '..', 'schemas', 'schemas');
@@ -16,28 +16,8 @@ export declare function extractPermissionPikkuNames(node: ts.Expression, checker
16
16
  * Returns the initializer node for the 'permissions' property if it exists
17
17
  */
18
18
  export declare function getPermissionsNode(obj: ts.ObjectLiteralExpression): ts.Expression | undefined;
19
- /**
20
- * Check if a route matches a pattern with wildcards
21
- * Pattern can be exact match or use * as wildcard
22
- * e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
23
- */
24
- export declare function routeMatchesPattern(route: string, pattern: string): boolean;
25
- /**
26
- * Resolve permissions for an HTTP wiring based on:
27
- * 1. Global HTTP permissions (addHTTPPermission('*', [...]))
28
- * 2. Route-specific HTTP permissions (addHTTPPermission('/pattern', [...]))
29
- * 3. Tag-based permissions (addPermission('tag', [...]))
30
- * 4. Explicit wiring permissions (wireHTTP({ permissions: [...] }))
31
- * Returns undefined if no permissions are found, otherwise returns array with at least one item
32
- */
33
- export declare function resolveHTTPPermissions(state: InspectorState, route: string, tags: string[] | undefined, explicitPermissionsNode: ts.Expression | undefined, checker: ts.TypeChecker): PermissionMetadata[] | undefined;
34
19
  /**
35
20
  * Convenience wrapper: Extract permissions node from object and resolve
36
21
  * Use this in add-* files for cleaner code
37
22
  */
38
- export declare function resolvePermissions(state: InspectorState, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): PermissionMetadata[] | undefined;
39
- /**
40
- * Convenience wrapper for HTTP: Extract permissions and resolve with HTTP-specific logic
41
- * Use this in add-http-route.ts for cleaner code
42
- */
43
- export declare function resolveHTTPPermissionsFromObject(state: InspectorState, route: string, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): PermissionMetadata[] | undefined;
23
+ export declare function resolvePermissions(state: InspectorState, obj: ts.ObjectLiteralExpression, _tags: string[] | undefined, checker: ts.TypeChecker): PermissionMetadata[] | undefined;
@@ -57,122 +57,31 @@ export function getPermissionsNode(obj) {
57
57
  return permissionsProp?.initializer;
58
58
  }
59
59
  /**
60
- * Check if a route matches a pattern with wildcards
61
- * Pattern can be exact match or use * as wildcard
62
- * e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
60
+ * Resolve the explicit permission references declared on a function (or agent).
61
+ * Permissions are function-scoped only: a `permissions: { group: [fn] }` object
62
+ * is flattened to `{ type: 'wire', name }` references used at filter time.
63
+ * Returns undefined if none are declared, otherwise an array with ≥1 item.
63
64
  */
64
- export function routeMatchesPattern(route, pattern) {
65
- if (route === pattern)
66
- return true;
67
- // Convert pattern to regex: replace * with .*
68
- const regexPattern = pattern
69
- .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape regex special chars except *
70
- .replace(/\*/g, '.*'); // Replace * with .*
71
- const regex = new RegExp(`^${regexPattern}$`);
72
- return regex.test(route);
73
- }
74
- /**
75
- * Resolve permissions for an HTTP wiring based on:
76
- * 1. Global HTTP permissions (addHTTPPermission('*', [...]))
77
- * 2. Route-specific HTTP permissions (addHTTPPermission('/pattern', [...]))
78
- * 3. Tag-based permissions (addPermission('tag', [...]))
79
- * 4. Explicit wiring permissions (wireHTTP({ permissions: [...] }))
80
- * Returns undefined if no permissions are found, otherwise returns array with at least one item
81
- */
82
- export function resolveHTTPPermissions(state, route, tags, explicitPermissionsNode, checker) {
83
- const resolved = [];
84
- // 1. HTTP route permission groups (includes '*' for global)
85
- for (const [pattern, _groupMeta] of state.http.routePermissions.entries()) {
86
- if (routeMatchesPattern(route, pattern)) {
87
- // Just reference the group by route pattern
88
- resolved.push({
89
- type: 'http',
90
- route: pattern,
91
- });
92
- }
93
- }
94
- // 2. Tag-based permission groups
95
- if (tags && tags.length > 0) {
96
- for (const tag of tags) {
97
- if (state.permissions.tagPermissions.has(tag)) {
98
- // Just reference the group by tag
99
- resolved.push({
100
- type: 'tag',
101
- tag,
102
- });
103
- }
104
- }
105
- }
106
- // 3. Explicit wire permissions (inline is OK here)
107
- if (explicitPermissionsNode) {
108
- const permissionNames = extractPermissionPikkuNames(explicitPermissionsNode, checker, state.rootDir);
109
- for (const name of permissionNames) {
110
- const def = state.permissions.definitions[name];
111
- resolved.push({
112
- type: 'wire',
113
- name,
114
- inline: def?.exportedName === null,
115
- });
116
- }
65
+ function resolveExplicitPermissions(state, explicitPermissionsNode, checker) {
66
+ if (!explicitPermissionsNode) {
67
+ return undefined;
117
68
  }
118
- return resolved.length > 0 ? resolved : undefined;
119
- }
120
- /**
121
- * Resolve tag-based and explicit permissions (common logic for wires and functions)
122
- * 1. Tag-based permissions (addPermission('tag', [...]))
123
- * 2. Explicit permissions (wireHTTP/pikkuFunc({ permissions: [...] }))
124
- */
125
- function resolveTagAndExplicitPermissions(state, tags, explicitPermissionsNode, checker) {
126
69
  const resolved = [];
127
- // 1. Tag-based permission groups
128
- if (tags && tags.length > 0) {
129
- for (const tag of tags) {
130
- if (state.permissions.tagPermissions.has(tag)) {
131
- // Just reference the group by tag
132
- resolved.push({
133
- type: 'tag',
134
- tag,
135
- });
136
- }
137
- }
138
- }
139
- // 2. Explicit permissions (inline is OK here - used directly in wire/function)
140
- if (explicitPermissionsNode) {
141
- const permissionNames = extractPermissionPikkuNames(explicitPermissionsNode, checker, state.rootDir);
142
- for (const name of permissionNames) {
143
- const def = state.permissions.definitions[name];
144
- resolved.push({
145
- type: 'wire',
146
- name,
147
- inline: def?.exportedName === null,
148
- });
149
- }
70
+ const permissionNames = extractPermissionPikkuNames(explicitPermissionsNode, checker, state.rootDir);
71
+ for (const name of permissionNames) {
72
+ const def = state.permissions.definitions[name];
73
+ resolved.push({
74
+ type: 'wire',
75
+ name,
76
+ inline: def?.exportedName === null,
77
+ });
150
78
  }
151
- return resolved;
152
- }
153
- /**
154
- * Resolve permissions for a function based on:
155
- * 1. Tag-based permissions (addPermission('tag', [...]))
156
- * 2. Explicit function permissions (pikkuFunc({ permissions: [...] }))
157
- * Returns undefined if no permissions are found, otherwise returns array with at least one item
158
- */
159
- function resolveFunctionPermissionsInternal(state, tags, explicitPermissionsNode, checker) {
160
- const resolved = resolveTagAndExplicitPermissions(state, tags, explicitPermissionsNode, checker);
161
79
  return resolved.length > 0 ? resolved : undefined;
162
80
  }
163
81
  /**
164
82
  * Convenience wrapper: Extract permissions node from object and resolve
165
83
  * Use this in add-* files for cleaner code
166
84
  */
167
- export function resolvePermissions(state, obj, tags, checker) {
168
- const explicitPermissionsNode = getPermissionsNode(obj);
169
- return resolveFunctionPermissionsInternal(state, tags, explicitPermissionsNode, checker);
170
- }
171
- /**
172
- * Convenience wrapper for HTTP: Extract permissions and resolve with HTTP-specific logic
173
- * Use this in add-http-route.ts for cleaner code
174
- */
175
- export function resolveHTTPPermissionsFromObject(state, route, obj, tags, checker) {
176
- const explicitPermissionsNode = getPermissionsNode(obj);
177
- return resolveHTTPPermissions(state, route, tags, explicitPermissionsNode, checker);
85
+ export function resolvePermissions(state, obj, _tags, checker) {
86
+ return resolveExplicitPermissions(state, getPermissionsNode(obj), checker);
178
87
  }
@@ -19,7 +19,7 @@ export declare function stampAuthHandlerServices(state: InspectorState | Omit<In
19
19
  * Only extracts type:'wire' variants (individual middleware/permissions).
20
20
  * Skips type:'http' and type:'tag' (reference groups, not individuals).
21
21
  */
22
- export declare function extractWireNames(list?: MiddlewareMetadata[] | PermissionMetadata[]): string[];
22
+ export declare function extractWireNames(list?: Array<MiddlewareMetadata | PermissionMetadata>): string[];
23
23
  /**
24
24
  * Aggregates all required services from wired functions, middleware, and permissions.
25
25
  * Must be called after AST traversal completes.
@@ -31,11 +31,32 @@ export declare function aggregateRequiredServices(state: InspectorState | Omit<I
31
31
  export declare function validateSecretOverrides(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
32
32
  export declare function validateCredentialOverrides(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
33
33
  export declare function validateVariableOverrides(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
34
+ /**
35
+ * A `wireRemoteAddon` package ships types only — its handlers run on the host —
36
+ * so it MUST be a devDependency, not a production dependency (a prod dep would
37
+ * drag in the runtime deps remote consumption exists to avoid). This is the
38
+ * mirror image of `wireAddon`, which requires a production dependency.
39
+ */
40
+ export declare function validateRemoteAddonDependencies(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
41
+ /**
42
+ * The auth a `wireRemoteAddon` consumer binds must reference a slot the consumer
43
+ * actually declares: a `credentialId` must be a wired credential, a `secretId`
44
+ * a wired secret. A custom `resolve()` and a public (omitted) surface are not
45
+ * statically checkable and are left to runtime.
46
+ */
47
+ export declare function validateRemoteAddonAuth(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
34
48
  export declare function computeResolvedIOTypes(state: InspectorState): void;
35
49
  export declare function computeMiddlewareGroupsMeta(state: InspectorState): void;
36
50
  export declare function computePermissionsGroupsMeta(state: InspectorState): void;
37
51
  export declare function computeRequiredSchemas(state: InspectorState, options: InspectorOptions): void;
38
52
  export declare function validateAgentModels(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
53
+ /**
54
+ * A `pikkuWorkflowGraph` node that references the `graph:` namespace (e.g.
55
+ * `graph:editFields`) needs @pikku/addon-graph wired — otherwise the RPC never
56
+ * registers and codegen fails deep in type-checking with an opaque error. Fail
57
+ * early with an actionable message pointing at `scaffold: { graph: true }`.
58
+ */
59
+ export declare function validateWorkflowGraphAddons(logger: InspectorLogger, state: InspectorState): void;
39
60
  /**
40
61
  * Validates that Zod schemas and wiring side-effects (wireHTTPRoutes,
41
62
  * addPermission, addHTTPMiddleware, etc.) do not coexist in the same file.
@@ -46,3 +67,11 @@ export declare function validateAgentModels(logger: InspectorLogger, state: Insp
46
67
  */
47
68
  export declare function validateSchemaWiringSeparation(logger: InspectorLogger, state: InspectorState): void;
48
69
  export declare function computeDiagnostics(state: InspectorState): void;
70
+ /**
71
+ * Validates that every scope referenced by a function is declared via
72
+ * `wireScope`. Runs after all visitors, so declaration order does not matter.
73
+ *
74
+ * A `*` suffix is a wildcard requirement: `admin:*` requires the `admin` scope
75
+ * to be declared, and grants its whole subtree.
76
+ */
77
+ export declare function validateScopeReferences(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;