@pikku/inspector 0.12.99 → 0.12.101

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 CHANGED
@@ -1,3 +1,20 @@
1
+ ## 0.12.101
2
+
3
+ ### Patch Changes
4
+
5
+ - 9112494: `pikku knowledge validate` reports code that no note describes as a warning rather than info, and raises one `PKU960` diagnostic for it, so `--fail-on-warn` can gate on it and the "consistent" line no longer prints while notes are missing. A plain run still exits 0: only errors fail it.
6
+
7
+ ## 0.12.100
8
+
9
+ ### Patch Changes
10
+
11
+ - 149faae: Webhook `receive` steps lose their boilerplate. `pikkuWebhookReceive` (from `#pikku/trigger` or `#pikku/addon/trigger`) declares one: it is public, typed to the raw request with a required `http`, and never registered as an RPC, and the inspector rejects a `receive` declared with any other wrapper. `parseJson` (in `@pikku/core/utils`, generated as `#pikku/utils` and `#pikku/addon/utils`) parses text or bytes and answers a body that is not JSON with a 400. A webhook source whose `method` includes `'head'` answers HEAD probes itself with a 200.
12
+
13
+ `receive` no longer returns `{ respond }`: a handshake returns nothing and writes its answer to `http.response`, like any other HTTP function. The webhook route no longer returns a fetch `Response` either. An HTTP function that returns nothing is now answered with whatever status its response has (200 unless it set another), no longer a forced 204. A webhook receive is also left out of contract versioning, since nothing but its own route calls it.
14
+
15
+ - Updated dependencies [149faae]
16
+ - @pikku/core@0.12.136
17
+
1
18
  ## 0.12.99
2
19
 
3
20
  ### Patch Changes
@@ -361,6 +361,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
361
361
  const pikkuFuncPattern = /pikku.*func/i;
362
362
  if (!pikkuFuncPattern.test(expression.text) &&
363
363
  expression.text !== 'pikkuScenario' &&
364
+ expression.text !== 'pikkuWebhookReceive' &&
364
365
  !SCENARIO_STEP_KINDS.has(expression.text)) {
365
366
  return;
366
367
  }
@@ -373,6 +374,10 @@ export const addFunctions = (logger, node, checker, state, options) => {
373
374
  // analyzer can tell it apart from an application workflow without having to
374
375
  // reach into the workflow graph.
375
376
  const isScenario = expression.text === 'pikkuScenario';
377
+ // A webhook source's `receive`. Only its source's route runs it, with the
378
+ // raw request, so like a scenario step it is bundled but never RPC-registered.
379
+ const isWebhookReceive = expression.text === 'pikkuWebhookReceive';
380
+ const notRpc = isScenarioStep || isWebhookReceive;
376
381
  // only handle calls like pikkuFunc(...)
377
382
  if (!ts.isIdentifier(expression) || !expression.text.startsWith('pikku')) {
378
383
  return;
@@ -817,6 +822,9 @@ export const addFunctions = (logger, node, checker, state, options) => {
817
822
  inputTypes = result.types;
818
823
  }
819
824
  }
825
+ // A receive's input is always the raw request, which no schema describes.
826
+ if (isWebhookReceive)
827
+ inputNames = [];
820
828
  // --- Output Extraction ---
821
829
  let outputNames = [];
822
830
  if (outputSchemaRef) {
@@ -1054,11 +1062,16 @@ export const addFunctions = (logger, node, checker, state, options) => {
1054
1062
  inputs: inputNames.filter((n) => n !== 'void') ?? null,
1055
1063
  outputs: outputNames.filter((n) => n !== 'void') ?? null,
1056
1064
  expose: expose || undefined,
1057
- auth: typeof auth === 'boolean' ? auth : undefined,
1065
+ auth: isWebhookReceive
1066
+ ? false
1067
+ : typeof auth === 'boolean'
1068
+ ? auth
1069
+ : undefined,
1058
1070
  permissionsInBody: permissionsInBody || undefined,
1059
1071
  audit,
1060
1072
  remote: remote || undefined,
1061
1073
  scenarioStep: isScenarioStep || undefined,
1074
+ webhookReceive: isWebhookReceive || undefined,
1062
1075
  scenario: isScenario || undefined,
1063
1076
  mcp: mcpEnabled || undefined,
1064
1077
  readonly: readonly_ || undefined,
@@ -1173,7 +1186,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
1173
1186
  logger.error(`• Function with explicit name '${name}' is not exported, this is not allowed.`);
1174
1187
  return;
1175
1188
  }
1176
- if (remote && !isScenarioStep) {
1189
+ if (remote && !notRpc) {
1177
1190
  state.rpc.invokedFunctions.add(pikkuFuncId);
1178
1191
  // The consumer-facing surface a wireRemoteAddon imports (mirrors exposedMeta)
1179
1192
  state.rpc.remoteMeta[name] = pikkuFuncId;
@@ -1182,7 +1195,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
1182
1195
  exportedName,
1183
1196
  });
1184
1197
  }
1185
- if (expose && !isScenarioStep) {
1198
+ if (expose && !notRpc) {
1186
1199
  state.rpc.exposedMeta[name] = pikkuFuncId;
1187
1200
  state.rpc.exposedFiles.set(name, {
1188
1201
  path: node.getSourceFile().fileName,
@@ -1191,7 +1204,7 @@ export const addFunctions = (logger, node, checker, state, options) => {
1191
1204
  // Track exposed RPC function for service aggregation
1192
1205
  state.serviceAggregation.usedFunctions.add(pikkuFuncId);
1193
1206
  }
1194
- if (!isScenarioStep) {
1207
+ if (!notRpc) {
1195
1208
  // We add it to internal meta to allow autocomplete for everything
1196
1209
  state.rpc.internalMeta[name] = pikkuFuncId;
1197
1210
  if (version !== undefined) {
@@ -184,6 +184,12 @@ const addWireTriggerWebhookSource = (logger, node, checker, state, firstArg) =>
184
184
  */
185
185
  export const validateWebhookSourceTriggers = (logger, state) => {
186
186
  const sources = state.triggers.webhookSourceMeta;
187
+ for (const source of Object.values(sources)) {
188
+ const meta = source.receive && state.functions.meta[source.receive];
189
+ if (meta && meta.funcWrapper && !meta.webhookReceive) {
190
+ logger.error(`Webhook source '${source.name}' receives with '${source.receive}', a ${meta.funcWrapper}. Declare it with pikkuWebhookReceive so it is never callable as an RPC.`);
191
+ }
192
+ }
187
193
  for (const trigger of Object.keys(state.triggers.meta)) {
188
194
  const colon = trigger.indexOf(':');
189
195
  if (colon === -1)
@@ -83,6 +83,7 @@ export declare enum ErrorCode {
83
83
  ADDON_WIRING_NOT_ALLOWED = "PKU920",
84
84
  ADDON_CONTRACT_HANDLERS_NOT_ALLOWED = "PKU921",
85
85
  RPC_INVOCATION_TYPE_CAST = "PKU940",
86
+ KNOWLEDGE_NOTE_MISSING = "PKU960",
86
87
  SECRET_SERVICE_ALIASED = "PKU950",
87
88
  SECRET_NOT_DECLARED = "PKU951",
88
89
  SECRET_KEY_NOT_STATIC = "PKU952",
@@ -108,6 +108,8 @@ export var ErrorCode;
108
108
  ErrorCode["ADDON_WIRING_NOT_ALLOWED"] = "PKU920";
109
109
  ErrorCode["ADDON_CONTRACT_HANDLERS_NOT_ALLOWED"] = "PKU921";
110
110
  ErrorCode["RPC_INVOCATION_TYPE_CAST"] = "PKU940";
111
+ // Knowledge base errors
112
+ ErrorCode["KNOWLEDGE_NOTE_MISSING"] = "PKU960";
111
113
  // Secret boundary errors
112
114
  ErrorCode["SECRET_SERVICE_ALIASED"] = "PKU950";
113
115
  ErrorCode["SECRET_NOT_DECLARED"] = "PKU951";
@@ -71,7 +71,9 @@ function resolveSchema(typeNames, allSchemas, typesMap) {
71
71
  export function buildCurrentContracts(functionsMeta, allSchemas, typesMap) {
72
72
  const result = new Map();
73
73
  for (const [funcId, meta] of Object.entries(functionsMeta)) {
74
- if (meta.remote === true) {
74
+ // A webhook receive has no callers but its own route, so there is no
75
+ // contract for a version to protect.
76
+ if (meta.remote === true || meta.webhookReceive) {
75
77
  continue;
76
78
  }
77
79
  const parsed = parseVersionedId(funcId);
@@ -251,7 +253,7 @@ export function updateManifest(existing, currentContracts) {
251
253
  export function extractContractsFromMeta(functionsMeta) {
252
254
  const result = new Map();
253
255
  for (const [funcId, meta] of Object.entries(functionsMeta)) {
254
- if (meta.remote === true || !meta.contractHash) {
256
+ if (meta.remote === true || meta.webhookReceive || !meta.contractHash) {
255
257
  continue;
256
258
  }
257
259
  const parsed = parseVersionedId(funcId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/inspector",
3
- "version": "0.12.99",
3
+ "version": "0.12.101",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",
@@ -54,10 +54,10 @@
54
54
  "zod": "^4.4.3"
55
55
  },
56
56
  "peerDependencies": {
57
- "@pikku/core": "^0.12.135"
57
+ "@pikku/core": "^0.12.136"
58
58
  },
59
59
  "devDependencies": {
60
- "@pikku/core": "^0.12.135",
60
+ "@pikku/core": "^0.12.136",
61
61
  "@types/node": "^24.13.3"
62
62
  },
63
63
  "engines": {