@apifuse/provider-sdk 2.2.0-beta.62 → 2.2.0-beta.64

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 (261) hide show
  1. package/AUTHORING.md +367 -9
  2. package/CHANGELOG.md +8 -0
  3. package/LICENSE +21 -0
  4. package/README.md +1 -0
  5. package/bin/apifuse-check.ts +84 -2
  6. package/bin/apifuse-dev.ts +11 -31
  7. package/bin/apifuse-migrate-deployment.ts +200 -0
  8. package/bin/apifuse-pack-check.ts +11 -4
  9. package/bin/apifuse-pack-types.ts +187 -4
  10. package/bin/apifuse-record.ts +44 -32
  11. package/bin/apifuse-submit-check.ts +9 -5
  12. package/bin/apifuse-test.ts +3 -1
  13. package/dist/cli/commands.d.ts +1 -1
  14. package/dist/cli/commands.js +11 -0
  15. package/dist/cli/deployment-intent.d.ts +178 -0
  16. package/dist/cli/deployment-intent.js +277 -0
  17. package/dist/cli/migrate-deployment-intent.d.ts +132 -0
  18. package/dist/cli/migrate-deployment-intent.js +1552 -0
  19. package/dist/cli/migrate-provider-shape.d.ts +5 -1
  20. package/dist/cli/migrate-provider-shape.js +4 -2
  21. package/dist/cli/resolver-runtime.d.ts +21 -0
  22. package/dist/cli/resolver-runtime.js +31 -0
  23. package/dist/define.d.ts +3 -0
  24. package/dist/define.js +5 -0
  25. package/dist/dev.d.ts +3 -1
  26. package/dist/dev.js +6 -1
  27. package/dist/engine.d.ts +35 -1
  28. package/dist/engine.js +21 -2
  29. package/dist/error-resolution.d.ts +1 -0
  30. package/dist/error-resolution.js +54 -0
  31. package/dist/errors.d.ts +39 -1
  32. package/dist/errors.js +50 -0
  33. package/dist/handle-meta.d.ts +36 -1
  34. package/dist/handle-meta.js +16 -0
  35. package/dist/handle.d.ts +23 -5
  36. package/dist/handle.js +54 -8
  37. package/dist/health-scenario.d.ts +38 -0
  38. package/dist/i18n/error-messages.d.ts +86 -0
  39. package/dist/i18n/error-messages.js +192 -0
  40. package/dist/i18n/index.d.ts +1 -0
  41. package/dist/i18n/index.js +1 -0
  42. package/dist/i18n/keys.d.ts +12 -0
  43. package/dist/i18n/keys.js +76 -5
  44. package/dist/index.d.ts +11 -3
  45. package/dist/index.js +9 -1
  46. package/dist/lint.d.ts +15 -0
  47. package/dist/lint.js +469 -82
  48. package/dist/provider.d.ts +6 -6
  49. package/dist/provider.js +3 -3
  50. package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
  51. package/dist/runtime/browser-telemetry-binding.js +83 -0
  52. package/dist/runtime/browser-telemetry.d.ts +76 -0
  53. package/dist/runtime/browser-telemetry.js +165 -0
  54. package/dist/runtime/browser.d.ts +3 -0
  55. package/dist/runtime/browser.js +208 -47
  56. package/dist/runtime/cache-telemetry.d.ts +71 -0
  57. package/dist/runtime/cache-telemetry.js +177 -0
  58. package/dist/runtime/cache.js +67 -7
  59. package/dist/runtime/capability-response.d.ts +3 -0
  60. package/dist/runtime/capability-response.js +56 -0
  61. package/dist/runtime/capability-telemetry.d.ts +46 -0
  62. package/dist/runtime/capability-telemetry.js +68 -0
  63. package/dist/runtime/diagnostic-env.d.ts +3 -0
  64. package/dist/runtime/diagnostic-env.js +10 -1
  65. package/dist/runtime/engine-mode.d.ts +74 -0
  66. package/dist/runtime/engine-mode.js +152 -0
  67. package/dist/runtime/handle.js +9 -1
  68. package/dist/runtime/http-telemetry-guard.d.ts +10 -0
  69. package/dist/runtime/http-telemetry-guard.js +62 -10
  70. package/dist/runtime/http.js +141 -35
  71. package/dist/runtime/instrumentation.js +92 -13
  72. package/dist/runtime/ocr-telemetry.d.ts +82 -0
  73. package/dist/runtime/ocr-telemetry.js +192 -0
  74. package/dist/runtime/ocr.js +35 -8
  75. package/dist/runtime/request-telemetry.d.ts +2 -0
  76. package/dist/runtime/request-telemetry.js +2 -1
  77. package/dist/runtime/resolver-runtime-options.d.ts +14 -0
  78. package/dist/runtime/resolver-runtime-options.js +33 -0
  79. package/dist/runtime/resolver-shared.d.ts +3 -2
  80. package/dist/runtime/resolver-shared.js +4 -4
  81. package/dist/runtime/resolver-telemetry.d.ts +1 -0
  82. package/dist/runtime/resolver-telemetry.js +1 -1
  83. package/dist/runtime/resolver-vendors/browser.d.ts +2 -0
  84. package/dist/runtime/resolver-vendors/browser.js +46 -0
  85. package/dist/runtime/resolver-vendors/hosts.d.ts +21 -0
  86. package/dist/runtime/resolver-vendors/hosts.js +35 -0
  87. package/dist/runtime/resolver-vendors/hypersolutions.js +2 -2
  88. package/dist/runtime/resolver-vendors/types.d.ts +5 -4
  89. package/dist/runtime/resolver.d.ts +4 -1
  90. package/dist/runtime/resolver.js +46 -13
  91. package/dist/runtime/state-telemetry.d.ts +79 -0
  92. package/dist/runtime/state-telemetry.js +194 -0
  93. package/dist/runtime/state.d.ts +3 -0
  94. package/dist/runtime/state.js +26 -7
  95. package/dist/runtime/stealth-cookies.d.ts +5 -1
  96. package/dist/runtime/stealth-cookies.js +21 -1
  97. package/dist/runtime/stealth-owned-headers.d.ts +26 -0
  98. package/dist/runtime/stealth-owned-headers.js +37 -0
  99. package/dist/runtime/stealth-telemetry.d.ts +92 -0
  100. package/dist/runtime/stealth-telemetry.js +179 -0
  101. package/dist/runtime/stealth.d.ts +4 -1
  102. package/dist/runtime/stealth.js +228 -85
  103. package/dist/runtime/stt-telemetry.d.ts +77 -0
  104. package/dist/runtime/stt-telemetry.js +176 -0
  105. package/dist/runtime/stt.js +15 -6
  106. package/dist/runtime-boundary-lint.d.ts +132 -0
  107. package/dist/runtime-boundary-lint.js +586 -0
  108. package/dist/server/error-stack-frames.d.ts +35 -0
  109. package/dist/server/error-stack-frames.js +219 -0
  110. package/dist/server/index.d.ts +7 -0
  111. package/dist/server/index.js +4 -0
  112. package/dist/server/sdk-version.d.ts +3 -0
  113. package/dist/server/sdk-version.js +19 -0
  114. package/dist/server/self-test.js +1 -18
  115. package/dist/server/sensitive-values.d.ts +1 -1
  116. package/dist/server/sensitive-values.js +9 -0
  117. package/dist/server/serve-implementation.d.ts +51 -2
  118. package/dist/server/serve-implementation.js +337 -90
  119. package/dist/server/types.d.ts +1 -0
  120. package/dist/server/types.js +7 -0
  121. package/dist/stateful/stateful-provider-owner-forwarder.js +22 -0
  122. package/dist/stateful/stateful-provider-runtime-context.d.ts +3 -0
  123. package/dist/stateful/stateful-provider-runtime-context.js +1 -0
  124. package/dist/types.d.ts +123 -1
  125. package/dist/typescript-module.d.ts +39 -0
  126. package/dist/typescript-module.js +72 -0
  127. package/package.json +6 -1
  128. package/src/cli/commands.ts +14 -0
  129. package/src/cli/deployment-intent.ts +364 -0
  130. package/src/cli/migrate-deployment-intent.ts +1908 -0
  131. package/src/cli/migrate-provider-shape.ts +10 -4
  132. package/src/cli/resolver-runtime.ts +72 -0
  133. package/src/define.ts +13 -0
  134. package/src/dev.ts +9 -2
  135. package/src/engine.ts +38 -2
  136. package/src/error-resolution.ts +58 -0
  137. package/src/errors.ts +77 -1
  138. package/src/handle-meta.ts +51 -1
  139. package/src/handle.ts +92 -10
  140. package/src/health-scenario.ts +38 -0
  141. package/src/i18n/error-messages.ts +255 -0
  142. package/src/i18n/index.ts +1 -0
  143. package/src/i18n/keys.ts +80 -6
  144. package/src/index.ts +86 -0
  145. package/src/lint.ts +604 -91
  146. package/src/provider.ts +12 -0
  147. package/src/runtime/browser-telemetry-binding.ts +92 -0
  148. package/src/runtime/browser-telemetry.ts +289 -0
  149. package/src/runtime/browser.ts +249 -65
  150. package/src/runtime/cache-telemetry.ts +247 -0
  151. package/src/runtime/cache.ts +68 -17
  152. package/src/runtime/capability-response.ts +53 -0
  153. package/src/runtime/capability-telemetry.ts +101 -0
  154. package/src/runtime/diagnostic-env.ts +11 -1
  155. package/src/runtime/engine-mode.ts +233 -0
  156. package/src/runtime/handle.ts +9 -1
  157. package/src/runtime/http-telemetry-guard.ts +66 -13
  158. package/src/runtime/http.ts +168 -37
  159. package/src/runtime/instrumentation.ts +105 -16
  160. package/src/runtime/ocr-telemetry.ts +308 -0
  161. package/src/runtime/ocr.ts +114 -74
  162. package/src/runtime/request-telemetry.ts +2 -1
  163. package/src/runtime/resolver-runtime-options.ts +50 -0
  164. package/src/runtime/resolver-shared.ts +9 -4
  165. package/src/runtime/resolver-telemetry.ts +1 -1
  166. package/src/runtime/resolver-vendors/browser.ts +65 -7
  167. package/src/runtime/resolver-vendors/hosts.ts +43 -0
  168. package/src/runtime/resolver-vendors/hypersolutions.ts +2 -2
  169. package/src/runtime/resolver-vendors/types.ts +5 -4
  170. package/src/runtime/resolver.ts +64 -21
  171. package/src/runtime/state-telemetry.ts +298 -0
  172. package/src/runtime/state.ts +46 -45
  173. package/src/runtime/stealth-cookies.ts +24 -1
  174. package/src/runtime/stealth-owned-headers.ts +41 -0
  175. package/src/runtime/stealth-telemetry.ts +304 -0
  176. package/src/runtime/stealth.ts +355 -150
  177. package/src/runtime/stt-telemetry.ts +282 -0
  178. package/src/runtime/stt.ts +93 -71
  179. package/src/runtime-boundary-lint.ts +703 -0
  180. package/src/server/error-stack-frames.ts +214 -0
  181. package/src/server/index.ts +53 -0
  182. package/src/server/sdk-version.ts +22 -0
  183. package/src/server/self-test.ts +1 -21
  184. package/src/server/sensitive-values.ts +14 -0
  185. package/src/server/serve-implementation.ts +569 -108
  186. package/src/server/types.ts +7 -0
  187. package/src/stateful/stateful-provider-owner-forwarder.ts +23 -0
  188. package/src/stateful/stateful-provider-runtime-context.ts +4 -0
  189. package/src/types.ts +128 -1
  190. package/src/typescript-module.ts +100 -0
  191. package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +0 -6
  192. package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +0 -3
  193. package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +0 -10
  194. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +0 -3
  195. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +0 -3
  196. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +0 -2
  197. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +0 -3
  198. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +0 -6
  199. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +0 -1
  200. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +0 -1
  201. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +0 -3
  202. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +0 -7
  203. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +0 -19
  204. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +0 -6
  205. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +0 -3
  206. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +0 -8
  207. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +0 -5
  208. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +0 -4
  209. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +0 -3
  210. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +0 -3
  211. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +0 -10
  212. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +0 -1
  213. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +0 -1
  214. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +0 -3
  215. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +0 -6
  216. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +0 -6
  217. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +0 -14
  218. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +0 -3
  219. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +0 -2
  220. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +0 -3
  221. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +0 -3
  222. package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +0 -8
  223. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +0 -15
  224. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +0 -9
  225. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-kebab-operation-id.ts.txt +0 -17
  226. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +0 -5
  227. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +0 -24
  228. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +0 -16
  229. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-snake-operation-id.ts.txt +0 -21
  230. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +0 -11
  231. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +0 -7
  232. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +0 -3
  233. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +0 -18
  234. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +0 -13
  235. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +0 -31
  236. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +0 -11
  237. package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +0 -11
  238. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +0 -11
  239. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +0 -21
  240. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +0 -11
  241. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +0 -14
  242. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-en.json +0 -1
  243. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ja.json +0 -1
  244. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ko.json +0 -1
  245. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-existing-operation-namespace-en.json +0 -8
  246. package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +0 -7
  247. package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +0 -6
  248. package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +0 -7
  249. package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +0 -6
  250. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-binding-ambiguous.ts.txt +0 -12
  251. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported-other.ts.txt +0 -7
  252. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported.ts.txt +0 -5
  253. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-key-ambiguous.ts.txt +0 -19
  254. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-shorthand.ts.txt +0 -9
  255. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-typed.ts.txt +0 -11
  256. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-unrelated.ts.txt +0 -13
  257. package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +0 -7
  258. package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +0 -7
  259. package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +0 -15
  260. package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +0 -4
  261. package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +0 -12
@@ -25,6 +25,13 @@ export const OperationRequestSchema = z.object({
25
25
  input: z.record(z.string(), z.unknown()),
26
26
  connectionId: z.string().optional(),
27
27
  connection: OperationConnectionSchema.optional(),
28
+ /**
29
+ * Gateway-asserted principal scope: the organization id for customer
30
+ * subjects, the service-account id for platform service accounts. Absent
31
+ * on direct calls and self-test. Trusted exactly like `connectionId`; it is
32
+ * never derived from caller headers or `input`.
33
+ */
34
+ tenantId: z.string().optional(),
28
35
  headers: z.record(z.string(), z.string()).optional(),
29
36
  trace: z.record(z.string(), z.string()).optional(),
30
37
  });
@@ -205,6 +205,7 @@ function buildForwardingEnvelope(input: {
205
205
  requestId: input.request.requestId,
206
206
  input: input.request.input as Record<string, unknown>,
207
207
  connection: metadata.connection,
208
+ ...(metadata.tenantId ? { tenantId: metadata.tenantId } : {}),
208
209
  headers: sanitizeForwardedHeaders(metadata.headers),
209
210
  ...(metadata.trace ? { trace: metadata.trace } : {}),
210
211
  },
@@ -213,6 +214,7 @@ function buildForwardingEnvelope(input: {
213
214
 
214
215
  function forwardedMetadata(request: StatefulOperationRequest): {
215
216
  readonly connection: OperationConnection;
217
+ readonly tenantId?: string;
216
218
  readonly headers?: Record<string, string>;
217
219
  readonly trace?: Record<string, string>;
218
220
  } {
@@ -225,13 +227,34 @@ function forwardedMetadata(request: StatefulOperationRequest): {
225
227
  }
226
228
  const operationRequest = forwardingContext.operationRequest;
227
229
  const connection = OperationConnectionSchema.parse(operationRequest?.connection);
230
+ const tenantId = forwardedTenantId(operationRequest?.tenantId);
228
231
  return {
229
232
  connection,
233
+ ...(tenantId !== undefined ? { tenantId } : {}),
230
234
  ...(operationRequest?.headers ? { headers: operationRequest.headers } : {}),
231
235
  ...(operationRequest?.trace ? { trace: operationRequest.trace } : {}),
232
236
  };
233
237
  }
234
238
 
239
+ /**
240
+ * The runtime context is consumer-supplied and typed `unknown`, and only its
241
+ * `requestId` is guarded on read. A malformed principal scope must fail at the
242
+ * source with a forwarding error — the owner would otherwise reject the whole
243
+ * forwarded operation, and dropping it silently would downgrade a per-principal
244
+ * policy to the shared scope. `""` is not a principal (same rule as ids on the
245
+ * ingress envelope), so it is absent rather than invalid.
246
+ */
247
+ function forwardedTenantId(value: unknown): string | undefined {
248
+ if (value === undefined || value === "") return undefined;
249
+ if (typeof value !== "string") {
250
+ throw new StatefulOwnerForwardingError({
251
+ code: "STATEFUL_FORWARDING_CONTEXT_INVALID",
252
+ message: "Stateful operation forwarding requires a string tenantId when it is present.",
253
+ });
254
+ }
255
+ return value;
256
+ }
257
+
235
258
  function sanitizeForwardedHeaders(
236
259
  headers: Record<string, string> | undefined,
237
260
  ): Record<string, string> {
@@ -6,6 +6,8 @@ export interface StatefulForwardingRuntimeContext {
6
6
  readonly operationRequest?: {
7
7
  readonly requestId: string;
8
8
  readonly connection?: unknown;
9
+ /** Gateway-asserted principal scope; forwarded verbatim to the owner pod. */
10
+ readonly tenantId?: string;
9
11
  readonly headers?: Record<string, string>;
10
12
  readonly trace?: Record<string, string>;
11
13
  };
@@ -36,6 +38,7 @@ export function withStatefulLocalProviderContext(
36
38
  export function statefulForwardingContextFromProviderRequest(request: {
37
39
  readonly requestId: string;
38
40
  readonly connection?: unknown;
41
+ readonly tenantId?: string;
39
42
  readonly headers?: Record<string, string>;
40
43
  readonly trace?: Record<string, string>;
41
44
  }): StatefulForwardingRuntimeContext {
@@ -43,6 +46,7 @@ export function statefulForwardingContextFromProviderRequest(request: {
43
46
  operationRequest: {
44
47
  requestId: request.requestId,
45
48
  ...(request.connection !== undefined ? { connection: request.connection } : {}),
49
+ ...(request.tenantId ? { tenantId: request.tenantId } : {}),
46
50
  ...(request.headers ? { headers: request.headers } : {}),
47
51
  ...(request.trace ? { trace: request.trace } : {}),
48
52
  },
package/src/types.ts CHANGED
@@ -246,6 +246,25 @@ export interface OcrCaptchaResult {
246
246
  }
247
247
 
248
248
  export interface OcrContext {
249
+ /**
250
+ * Whether this context is backed by a configured OCR backend.
251
+ *
252
+ * The SDK owns this verdict: clients built by `createOcrClientFromEnv` for a
253
+ * configured backend report `true`; the unsupported/error clients handed to
254
+ * undeclared or misconfigured providers report `false`. Providers branch on
255
+ * this flag (for example, "require manual CAPTCHA input") instead of probing
256
+ * the engine-owned `APIFUSE__OCR__*` environment names themselves.
257
+ *
258
+ * `true` promises a configured backend, not a successful call: upstream
259
+ * failures still surface as errors from `recognize` / `extractCaptchaText`.
260
+ *
261
+ * Implementations must expose this as an own enumerable data property (not a
262
+ * getter or prototype member) so that wrappers which spread the context, such
263
+ * as `bindOcrTelemetry`, preserve it. Custom `OcrContext` overrides passed to
264
+ * `serve({ ocr })`, `createFlowContext({ ocr })`, or test contexts must set it
265
+ * explicitly.
266
+ */
267
+ readonly available: boolean;
249
268
  recognize(request: OcrRecognizeRequest): Promise<OcrResult>;
250
269
  extractCaptchaText(
251
270
  image: OcrImageInput,
@@ -796,6 +815,16 @@ export type HealthCheckCase<TInput = unknown, TOutput = unknown> = {
796
815
  *
797
816
  * MUST NOT access scheduler, recorder, or any runtime type — pure data
798
817
  * + lambda only.
818
+ *
819
+ * NOTE: a closure cannot cross the registry's serialization boundary, so
820
+ * the platform health monitor cannot execute this hook — it runs a case's
821
+ * serialized `scenario` and nothing else. A case that carries only
822
+ * `assertions` is still published as a probe, but its outcome is
823
+ * permanently `unknown` / `monitoring_unavailable`, so the operation
824
+ * reads as monitored while nothing is being checked. This hook runs only
825
+ * in the provider runtime's own self-test
826
+ * (`/internal/health/self-test`). Express anything that must be
827
+ * monitored in production as a `scenario`.
799
828
  */
800
829
  assertions: (
801
830
  ctx: HealthCheckAssertionContext<TOutput>,
@@ -924,8 +953,17 @@ export type ProviderErrorStatus = (typeof VALID_OPERATION_ERROR_STATUSES)[number
924
953
  export interface OperationErrorCode {
925
954
  code: string;
926
955
  status?: ProviderErrorStatus;
956
+ /** Developer-facing English prose for docs and MCP tool text. Never localized. */
927
957
  description: string;
928
958
  retryable?: boolean;
959
+ /**
960
+ * Locale catalog key for the client-facing `message` of every error thrown
961
+ * with this `code`. A throw site's own `messageKey` wins; when neither is
962
+ * present the SDK derives `errors.<code>.message`.
963
+ */
964
+ messageKey?: ProviderLocaleKeyInput;
965
+ /** Locale catalog key for the client-facing `fix`. Derived default: `errors.<code>.fix`. */
966
+ fixKey?: ProviderLocaleKeyInput;
929
967
  }
930
968
 
931
969
  export type StealthPlatform = "macos" | "windows" | "linux" | "android" | "ios";
@@ -1229,8 +1267,48 @@ export interface HttpRetrySummary {
1229
1267
  lastStatus?: number;
1230
1268
  }
1231
1269
 
1270
+ /** Per-attempt input for a `RequestOptions.headers` factory. */
1271
+ export interface HttpAttemptContext {
1272
+ /**
1273
+ * 1-based number of this request build: the first request is `1`, its first
1274
+ * retry `2`. Only attempts that reach header resolution count; a failed
1275
+ * proxy allocation or a skipped duplicate proxy offset builds no request
1276
+ * and is not numbered.
1277
+ */
1278
+ attempt: number;
1279
+ /**
1280
+ * Resolved request URL: `baseUrl` + path + `params` + `sensitiveParams`.
1281
+ * It is the exact URL the attempt is issued against, so bind signature
1282
+ * targets to it rather than to a URL the caller rebuilds. Strip the query
1283
+ * and fragment for fields that are defined without them — RFC 9449 §4.2
1284
+ * requires that of DPoP `htu`. It carries any sensitive query values, so
1285
+ * never log it and never copy it verbatim into a signed field that a
1286
+ * verifier logs.
1287
+ */
1288
+ url: string;
1289
+ /** Normalized upper-case HTTP method of the request. */
1290
+ method: Uppercase<HttpMethod>;
1291
+ }
1292
+
1293
+ /**
1294
+ * Builds the request headers for one issued attempt. Managed retry calls it
1295
+ * again for every retry, so request-bound single-use proofs (DPoP `jti`,
1296
+ * HTTP message signatures, HMAC nonces) can be re-minted instead of replayed.
1297
+ * A throw is raised as a non-retryable `TransportError` with code
1298
+ * `http_header_factory_failed`.
1299
+ */
1300
+ export type HttpHeadersFactory = (
1301
+ attempt: HttpAttemptContext,
1302
+ ) => Record<string, string> | Promise<Record<string, string>>;
1303
+
1232
1304
  export interface RequestOptions {
1233
- headers?: Record<string, string>;
1305
+ /**
1306
+ * Request headers, or a factory resolved once per issued attempt (see
1307
+ * `HttpHeadersFactory`). The factory runs after proxy resolution, before the
1308
+ * first redirect hop of that attempt; redirect hops reuse the attempt's
1309
+ * headers. `ctx.stealth` declares its own header option and is not affected.
1310
+ */
1311
+ headers?: Record<string, string> | HttpHeadersFactory;
1234
1312
  params?: RequestParams;
1235
1313
  /**
1236
1314
  * Query parameters whose values contain credentials or other secret material.
@@ -1238,7 +1316,23 @@ export interface RequestOptions {
1238
1316
  */
1239
1317
  sensitiveParams?: Record<string, string>;
1240
1318
  proxy?: string;
1319
+ /**
1320
+ * Per-attempt timeout for the response-header phase. It is disarmed once a
1321
+ * successful response's headers arrive, so it never bounds consumption of
1322
+ * that body — on the buffered path as well as on streams; use `signal` for
1323
+ * that. A non-2xx body the transport discards on the caller's behalf is
1324
+ * still drained under this deadline, so a wedged error body cannot hang the
1325
+ * attempt.
1326
+ */
1241
1327
  timeout?: number;
1328
+ /**
1329
+ * Cancels this request only — its retries, its backoff sleep and its
1330
+ * response-body consumption — leaving the client's other in-flight requests
1331
+ * untouched. Merged with the client-level `signal`, so a rejection reads as
1332
+ * `transport_cancelled` either way; inspect `signal.reason` to tell a
1333
+ * per-request abort from a fleet-wide one.
1334
+ */
1335
+ signal?: AbortSignal;
1242
1336
  /**
1243
1337
  * Defaults to true. Set to false when callers need to inspect upstream
1244
1338
  * non-2xx bodies themselves instead of converting them to TransportError.
@@ -1290,6 +1384,13 @@ export type HttpMethod =
1290
1384
  | "patch";
1291
1385
 
1292
1386
  export interface StealthFetchOptions extends Omit<RequestOptions, "redirectPolicy" | "headers"> {
1387
+ /**
1388
+ * Not supported by the stealth transport, which observes only the
1389
+ * client-level `signal` passed to `createStealthClient`. Typed as `never` so
1390
+ * a per-request signal fails to compile instead of being silently ignored;
1391
+ * threading one through the stealth session is a separate change.
1392
+ */
1393
+ signal?: never;
1293
1394
  /**
1294
1395
  * Defaults to true. Set to false when callers need to inspect upstream
1295
1396
  * non-2xx bodies themselves instead of converting them to TransportError.
@@ -1995,6 +2096,16 @@ export interface CredentialContext {
1995
2096
 
1996
2097
  export interface ProviderRequestContext {
1997
2098
  connectionId?: string;
2099
+ /**
2100
+ * Gateway-asserted principal scope of the operation request: the
2101
+ * organization id for customer subjects, the service-account id for
2102
+ * platform service accounts. `undefined` on direct calls and self-test
2103
+ * (unlike `FlowContext.tenantId`, which is coerced to `""`); an empty
2104
+ * string on the wire is normalised to `undefined` like `connectionId`.
2105
+ * Key per-principal policy (quota, fairness, correlation) for
2106
+ * connectionless operations on it. It does not scope `ctx.state`.
2107
+ */
2108
+ tenantId?: string;
1998
2109
  headers: Record<string, string>;
1999
2110
  }
2000
2111
 
@@ -2294,10 +2405,18 @@ export interface AuthConfig {
2294
2405
  flow?: AuthFlowDefinition;
2295
2406
  }
2296
2407
 
2408
+ /** Who provisions a declared secret: the platform (`apifuse`) or the provider author (`contributor`). */
2409
+ export type ProviderSecretIssuer = "apifuse" | "contributor";
2410
+
2297
2411
  export interface ProviderSecretDeclaration {
2298
2412
  name: string;
2299
2413
  description?: string;
2300
2414
  required?: boolean;
2415
+ /**
2416
+ * Optional today; ADR-0011 D3 makes it required once every deployed provider
2417
+ * declares it. Metadata only: it does not change which secrets are projected.
2418
+ */
2419
+ issuer?: ProviderSecretIssuer;
2301
2420
  }
2302
2421
 
2303
2422
  export interface CredentialDeclaration {
@@ -2398,6 +2517,14 @@ export interface OperationDefinition<
2398
2517
  * optional. Note that the deployment `runtime` axis
2399
2518
  * (`shared`/`dedicated`/`browser`) is distinct from the provider execution
2400
2519
  * `runtime` (`standard`/`shared`/`browser`).
2520
+ *
2521
+ * This key is the ONLY authored deployment surface. Declare it inside the
2522
+ * `defineProvider({...})` literal, not on a spread default export and not
2523
+ * in a standalone `deploy.ts` (legacy; `apifuse migrate-deployment` hoists
2524
+ * and deletes it). Write only what differs from the runtime profile —
2525
+ * shared `25m/128Mi`, browser `200m/256Mi`, `language: "typescript"`,
2526
+ * `replicas: 1`, HPA enabled 1-1 at 70% CPU — so most providers declare
2527
+ * nothing and `apifuse check` warns on restated defaults.
2401
2528
  */
2402
2529
  export interface ProviderDeploymentOverrides {
2403
2530
  runtime?: "shared" | "dedicated" | "browser";
@@ -0,0 +1,100 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ const requireModule = createRequire(import.meta.url);
4
+
5
+ /** The TypeScript compiler API surface the source-level lint rules parse with. */
6
+ export type TypeScriptModule = typeof import("typescript");
7
+
8
+ /**
9
+ * What a caller hands over as a compiler module. Typed structurally so the
10
+ * option does not depend on which `typescript` package the caller's own type
11
+ * resolution lands on: under a `typescript@7` pin `typeof import("typescript")`
12
+ * is the native shell's version module, not the compiler API. The members are
13
+ * optional for the same reason — the shell has none of them — and
14
+ * `isTypeScriptCompilerModule` decides at runtime whether the module can parse.
15
+ */
16
+ export type TypeScriptCompilerModuleLike = {
17
+ readonly createSourceFile?: (...parameters: never[]) => unknown;
18
+ readonly ScriptTarget?: object;
19
+ readonly version?: string;
20
+ };
21
+
22
+ /**
23
+ * Package specifiers that may carry the compiler API, in resolution order.
24
+ *
25
+ * `typescript@7` (the Go-native toolchain) resolves but its JavaScript entry
26
+ * exports only `version`/`getExePath` — no `createSourceFile`, so the lint
27
+ * rules cannot parse with it. The compiler API of that generation is published
28
+ * as `@typescript/typescript6`, which is what a `typescript@7` dependency tree
29
+ * (for example the APIFuse monorepo root) installs alongside the shell.
30
+ */
31
+ export const TYPESCRIPT_COMPILER_MODULE_SPECIFIERS = [
32
+ "typescript",
33
+ "@typescript/typescript6",
34
+ ] as const;
35
+
36
+ /**
37
+ * True when `candidate` is a loaded module that exposes the parser the lint
38
+ * rules need. Internal (narrows to the `typescript` module type, which is not
39
+ * part of the package surface); `lintRuntimeBoundarySources` applies it to the
40
+ * caller-supplied option.
41
+ */
42
+ export function isTypeScriptCompilerModule(candidate: unknown): candidate is TypeScriptModule {
43
+ return (
44
+ typeof candidate === "object" &&
45
+ candidate !== null &&
46
+ typeof (candidate as { createSourceFile?: unknown }).createSourceFile === "function" &&
47
+ typeof (candidate as { ScriptTarget?: unknown }).ScriptTarget === "object"
48
+ );
49
+ }
50
+
51
+ function describeCandidate(candidate: unknown): string {
52
+ if (typeof candidate === "object" && candidate !== null) {
53
+ const version = (candidate as { version?: unknown }).version;
54
+ if (typeof version === "string") return `resolved ${version} without a compiler API`;
55
+ }
56
+ return "resolved without a compiler API";
57
+ }
58
+
59
+ /**
60
+ * Resolve the compiler API through `load`, trying each specifier in order and
61
+ * accepting the first module that exposes `createSourceFile`. Exposed for the
62
+ * tests; production code uses `getTypeScript()`.
63
+ */
64
+ export function loadTypeScriptModule(
65
+ load: (specifier: string) => unknown,
66
+ specifiers: readonly string[] = TYPESCRIPT_COMPILER_MODULE_SPECIFIERS,
67
+ ): TypeScriptModule {
68
+ const attempts: string[] = [];
69
+ for (const specifier of specifiers) {
70
+ let candidate: unknown;
71
+ try {
72
+ candidate = load(specifier);
73
+ } catch {
74
+ attempts.push(`${specifier}: not resolvable`);
75
+ continue;
76
+ }
77
+ if (isTypeScriptCompilerModule(candidate)) return candidate;
78
+ attempts.push(`${specifier}: ${describeCandidate(candidate)}`);
79
+ }
80
+ throw new Error(
81
+ `The provider source lint needs the TypeScript compiler API (createSourceFile) and none of the resolvable packages provide it — ${attempts.join("; ")}. Install typescript 6.x as a devDependency, or @typescript/typescript6 next to a typescript 7 toolchain, in the dependency tree that installs @apifuse/provider-sdk.`,
82
+ );
83
+ }
84
+
85
+ /**
86
+ * Lazily loaded TypeScript compiler API shared by the source-level lint rules.
87
+ *
88
+ * `typeof import(...)` keeps the type without emitting a static import: the
89
+ * typescript package is a devDependency of the SDK and only the CLI and the
90
+ * lint rules need it at runtime, which the typescript-import-boundary test
91
+ * enforces for production sources. Resolution starts at the installed SDK, so
92
+ * the caller's dependency tree must provide one of
93
+ * `TYPESCRIPT_COMPILER_MODULE_SPECIFIERS`.
94
+ */
95
+ let typeScriptModule: TypeScriptModule | undefined;
96
+
97
+ export function getTypeScript(): TypeScriptModule {
98
+ typeScriptModule ??= loadTypeScriptModule(requireModule);
99
+ return typeScriptModule;
100
+ }
@@ -1,6 +0,0 @@
1
- const reserveOperation = defineOperation<ProviderContext>()({
2
- toolRouter: { riskClass: "write", approval: "always" },
3
- input: InputSchema,
4
- output: OutputSchema,
5
- handler,
6
- });
@@ -1,3 +0,0 @@
1
- const migrated = {
2
- riskClass: "read",;
3
- };
@@ -1,10 +0,0 @@
1
- const connectOperation = defineOperation<ProviderContext>()({
2
- annotations: { readOnly: true },
3
- toolRouter: {
4
- connectionMode: "optional",
5
- requiresConnection: true,
6
- },
7
- input: InputSchema,
8
- output: OutputSchema,
9
- handler,
10
- });
@@ -1,3 +0,0 @@
1
- export const registry = {
2
- first: { annotations: { readOnly: true }, input: InputSchema, output: OutputSchema, handler },
3
- };
@@ -1,3 +0,0 @@
1
- export const registry = {
2
- second: { annotations: { readOnly: true }, input: InputSchema, output: OutputSchema, handler },
3
- };
@@ -1,2 +0,0 @@
1
- export * from "./ambiguous-a";
2
- export * from "./ambiguous-b";
@@ -1,3 +0,0 @@
1
- import { registry } from "./ambiguous-barrel";
2
-
3
- export default buildProvider({ operations: registry });
@@ -1,6 +0,0 @@
1
- const operationId = "ping";
2
- const registry = {
3
- [operationId]: { annotations: { readOnly: true }, input: InputSchema, output: OutputSchema, handler },
4
- };
5
-
6
- export default buildProvider({ operations: registry });
@@ -1 +0,0 @@
1
- export { registry } from "./cycle-b";
@@ -1 +0,0 @@
1
- export { registry } from "./cycle-a";
@@ -1,3 +0,0 @@
1
- import { registry } from "./cycle-a";
2
-
3
- export default buildProvider({ operations: registry });
@@ -1,7 +0,0 @@
1
- import { catalogOperations } from "./catalog";
2
- import { storeOperations } from "./stores";
3
-
4
- export const daisoOperations = {
5
- ...catalogOperations,
6
- ...storeOperations,
7
- };
@@ -1,19 +0,0 @@
1
- import { OPERATION_DOCS } from "./docs";
2
-
3
- export const catalogOperations = {
4
- "browse-catalog": {
5
- docs: { ...OPERATION_DOCS.catalog },
6
- descriptionKey: "operations.browseCatalog.description",
7
- annotations: { readOnly: true },
8
- inputExamples: [{ scenario: "Browse the catalog", input: {} }],
9
- input: InputSchema,
10
- output: OutputSchema,
11
- handler,
12
- },
13
- "search-products": {
14
- annotations: { readOnly: true },
15
- input: InputSchema,
16
- output: OutputSchema,
17
- handler,
18
- },
19
- };
@@ -1,6 +0,0 @@
1
- export const OPERATION_DOCS = {
2
- catalog: {
3
- titleKey: "operations.groupedRead.title",
4
- descriptionKey: "operations.groupedRead.description",
5
- },
6
- };
@@ -1,3 +0,0 @@
1
- import { daisoOperations } from "./operations";
2
-
3
- export default buildProvider({ operations: daisoOperations });
@@ -1,8 +0,0 @@
1
- export const storeOperations = {
2
- "search-stores": {
3
- annotations: { readOnly: true },
4
- input: InputSchema,
5
- output: OutputSchema,
6
- handler,
7
- },
8
- };
@@ -1,5 +0,0 @@
1
- import { packageRegistry } from "provider-operation-package";
2
-
3
- const config = { operations: packageRegistry };
4
-
5
- export default buildProvider(config);
@@ -1,4 +0,0 @@
1
- const first = { ping: pingOperation };
2
- const second = { pong: pongOperation };
3
-
4
- export default buildProvider({ operations: enabled ? first : second });
@@ -1,3 +0,0 @@
1
- import { packageRegistry } from "provider-operation-package";
2
-
3
- export default buildProvider({ operations: packageRegistry });
@@ -1,3 +0,0 @@
1
- import { registry } from "./barrel-one.js";
2
-
3
- export default buildProvider({ operations: registry });
@@ -1,10 +0,0 @@
1
- const leafRegistry = {
2
- ping: {
3
- annotations: { readOnly: true },
4
- input: InputSchema,
5
- output: OutputSchema,
6
- handler,
7
- },
8
- };
9
-
10
- export const registry = leafRegistry;
@@ -1 +0,0 @@
1
- export { registry } from "./barrel-two.js";
@@ -1 +0,0 @@
1
- export { registry } from "./leaf";
@@ -1,3 +0,0 @@
1
- import { makeRegistry } from "./operations/registry";
2
-
3
- export default buildProvider({ operations: makeRegistry({ publicOnly: true }) });
@@ -1,6 +0,0 @@
1
- export const firstOperation = defineOperation<ProviderContext>()({
2
- annotations: { readOnly: true },
3
- input: FirstInputSchema,
4
- output: FirstOutputSchema,
5
- handler: firstHandler,
6
- });
@@ -1,6 +0,0 @@
1
- export const secondOperation = defineOperation<ProviderContext>()({
2
- annotations: { readOnly: true },
3
- input: SecondInputSchema,
4
- output: SecondOutputSchema,
5
- handler: secondHandler,
6
- });
@@ -1,14 +0,0 @@
1
- import { makeRegistry } from "./operations/registry";
2
-
3
- const literalOperation = defineOperation<ProviderContext>()({
4
- annotations: { readOnly: true },
5
- input: LiteralInputSchema,
6
- output: LiteralOutputSchema,
7
- handler: literalHandler,
8
- });
9
-
10
- export const literalProvider = buildProvider({
11
- operations: { literal: literalOperation },
12
- });
13
-
14
- export default buildProvider({ operations: makeRegistry({ publicOnly: true }) });
@@ -1,3 +0,0 @@
1
- export function makeRegistry(_options: { publicOnly: boolean }) {
2
- return {};
3
- }
@@ -1,2 +0,0 @@
1
- export * from "provider-operation-package";
2
- export * from "./star-leaf";
@@ -1,3 +0,0 @@
1
- import { registry } from "./star-barrel";
2
-
3
- export default buildProvider({ operations: registry });
@@ -1,3 +0,0 @@
1
- export const registry = {
2
- ping: { annotations: { readOnly: true }, input: InputSchema, output: OutputSchema, handler },
3
- };
@@ -1,8 +0,0 @@
1
- const searchOperation = defineOperation<ProviderContext>()({
2
- riskClass: "read",
3
- titleKey: "operations.search.title",
4
- docs: { titleKey: "operations.search.otherTitle" },
5
- input: InputSchema,
6
- output: OutputSchema,
7
- handler,
8
- });
@@ -1,15 +0,0 @@
1
- const LIST_INPUT_EXAMPLES = [
2
- {
3
- scenario: "List a full year",
4
- rationale: "Shows the common calendar query",
5
- input: { year: 2026 },
6
- },
7
- ] as const;
8
-
9
- const listOperation = defineOperation<ProviderContext>()({
10
- annotations: { readOnly: true },
11
- inputExamples: [...LIST_INPUT_EXAMPLES],
12
- input: InputSchema,
13
- output: OutputSchema,
14
- handler,
15
- });
@@ -1,9 +0,0 @@
1
- import { LIST_INPUT_EXAMPLES } from "./shared.js";
2
-
3
- const importedExamplesOperation = defineOperation<ProviderContext>()({
4
- annotations: { readOnly: true },
5
- inputExamples: [...LIST_INPUT_EXAMPLES],
6
- input: InputSchema,
7
- output: OutputSchema,
8
- handler,
9
- });