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

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 (243) hide show
  1. package/AUTHORING.md +268 -9
  2. package/CHANGELOG.md +4 -0
  3. package/README.md +1 -0
  4. package/bin/apifuse-check.ts +84 -2
  5. package/bin/apifuse-dev.ts +11 -31
  6. package/bin/apifuse-migrate-deployment.ts +200 -0
  7. package/bin/apifuse-pack-check.ts +11 -4
  8. package/bin/apifuse-pack-types.ts +187 -4
  9. package/bin/apifuse-record.ts +44 -32
  10. package/bin/apifuse-test.ts +3 -1
  11. package/dist/cli/commands.d.ts +1 -1
  12. package/dist/cli/commands.js +11 -0
  13. package/dist/cli/deployment-intent.d.ts +178 -0
  14. package/dist/cli/deployment-intent.js +277 -0
  15. package/dist/cli/migrate-deployment-intent.d.ts +132 -0
  16. package/dist/cli/migrate-deployment-intent.js +1552 -0
  17. package/dist/cli/migrate-provider-shape.d.ts +5 -1
  18. package/dist/cli/migrate-provider-shape.js +4 -2
  19. package/dist/cli/resolver-runtime.d.ts +21 -0
  20. package/dist/cli/resolver-runtime.js +31 -0
  21. package/dist/define.d.ts +3 -0
  22. package/dist/define.js +5 -0
  23. package/dist/dev.d.ts +3 -1
  24. package/dist/dev.js +6 -1
  25. package/dist/engine.d.ts +35 -1
  26. package/dist/engine.js +21 -2
  27. package/dist/error-resolution.d.ts +1 -0
  28. package/dist/error-resolution.js +54 -0
  29. package/dist/errors.d.ts +39 -1
  30. package/dist/errors.js +50 -0
  31. package/dist/i18n/error-messages.d.ts +86 -0
  32. package/dist/i18n/error-messages.js +192 -0
  33. package/dist/i18n/index.d.ts +1 -0
  34. package/dist/i18n/index.js +1 -0
  35. package/dist/i18n/keys.d.ts +12 -0
  36. package/dist/i18n/keys.js +76 -5
  37. package/dist/index.d.ts +7 -1
  38. package/dist/index.js +6 -0
  39. package/dist/lint.d.ts +10 -0
  40. package/dist/lint.js +412 -49
  41. package/dist/provider.d.ts +5 -5
  42. package/dist/provider.js +2 -2
  43. package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
  44. package/dist/runtime/browser-telemetry-binding.js +83 -0
  45. package/dist/runtime/browser-telemetry.d.ts +76 -0
  46. package/dist/runtime/browser-telemetry.js +165 -0
  47. package/dist/runtime/browser.d.ts +3 -0
  48. package/dist/runtime/browser.js +208 -47
  49. package/dist/runtime/cache-telemetry.d.ts +71 -0
  50. package/dist/runtime/cache-telemetry.js +177 -0
  51. package/dist/runtime/cache.js +67 -7
  52. package/dist/runtime/capability-response.d.ts +3 -0
  53. package/dist/runtime/capability-response.js +56 -0
  54. package/dist/runtime/capability-telemetry.d.ts +46 -0
  55. package/dist/runtime/capability-telemetry.js +68 -0
  56. package/dist/runtime/diagnostic-env.d.ts +3 -0
  57. package/dist/runtime/diagnostic-env.js +10 -1
  58. package/dist/runtime/engine-mode.d.ts +74 -0
  59. package/dist/runtime/engine-mode.js +152 -0
  60. package/dist/runtime/http-telemetry-guard.d.ts +10 -0
  61. package/dist/runtime/http-telemetry-guard.js +62 -10
  62. package/dist/runtime/http.js +141 -35
  63. package/dist/runtime/instrumentation.js +92 -13
  64. package/dist/runtime/ocr-telemetry.d.ts +82 -0
  65. package/dist/runtime/ocr-telemetry.js +192 -0
  66. package/dist/runtime/ocr.js +30 -8
  67. package/dist/runtime/request-telemetry.d.ts +2 -0
  68. package/dist/runtime/request-telemetry.js +2 -1
  69. package/dist/runtime/resolver-runtime-options.d.ts +14 -0
  70. package/dist/runtime/resolver-runtime-options.js +33 -0
  71. package/dist/runtime/resolver-shared.d.ts +3 -2
  72. package/dist/runtime/resolver-shared.js +4 -4
  73. package/dist/runtime/resolver-telemetry.d.ts +1 -0
  74. package/dist/runtime/resolver-telemetry.js +1 -1
  75. package/dist/runtime/resolver-vendors/browser.d.ts +2 -0
  76. package/dist/runtime/resolver-vendors/browser.js +46 -0
  77. package/dist/runtime/resolver-vendors/hosts.d.ts +21 -0
  78. package/dist/runtime/resolver-vendors/hosts.js +35 -0
  79. package/dist/runtime/resolver-vendors/hypersolutions.js +2 -2
  80. package/dist/runtime/resolver-vendors/types.d.ts +5 -4
  81. package/dist/runtime/resolver.d.ts +4 -1
  82. package/dist/runtime/resolver.js +46 -13
  83. package/dist/runtime/state-telemetry.d.ts +79 -0
  84. package/dist/runtime/state-telemetry.js +194 -0
  85. package/dist/runtime/state.d.ts +3 -0
  86. package/dist/runtime/state.js +26 -7
  87. package/dist/runtime/stealth-cookies.d.ts +5 -1
  88. package/dist/runtime/stealth-cookies.js +21 -1
  89. package/dist/runtime/stealth-owned-headers.d.ts +26 -0
  90. package/dist/runtime/stealth-owned-headers.js +37 -0
  91. package/dist/runtime/stealth-telemetry.d.ts +92 -0
  92. package/dist/runtime/stealth-telemetry.js +179 -0
  93. package/dist/runtime/stealth.d.ts +4 -1
  94. package/dist/runtime/stealth.js +228 -85
  95. package/dist/runtime/stt-telemetry.d.ts +77 -0
  96. package/dist/runtime/stt-telemetry.js +176 -0
  97. package/dist/runtime/stt.js +15 -6
  98. package/dist/server/error-stack-frames.d.ts +35 -0
  99. package/dist/server/error-stack-frames.js +219 -0
  100. package/dist/server/index.d.ts +7 -0
  101. package/dist/server/index.js +4 -0
  102. package/dist/server/sdk-version.d.ts +3 -0
  103. package/dist/server/sdk-version.js +19 -0
  104. package/dist/server/self-test.js +1 -18
  105. package/dist/server/sensitive-values.d.ts +1 -1
  106. package/dist/server/sensitive-values.js +9 -0
  107. package/dist/server/serve-implementation.d.ts +51 -2
  108. package/dist/server/serve-implementation.js +337 -90
  109. package/dist/server/types.d.ts +1 -0
  110. package/dist/server/types.js +7 -0
  111. package/dist/stateful/stateful-provider-owner-forwarder.js +22 -0
  112. package/dist/stateful/stateful-provider-runtime-context.d.ts +3 -0
  113. package/dist/stateful/stateful-provider-runtime-context.js +1 -0
  114. package/dist/types.d.ts +94 -1
  115. package/package.json +6 -1
  116. package/src/cli/commands.ts +14 -0
  117. package/src/cli/deployment-intent.ts +364 -0
  118. package/src/cli/migrate-deployment-intent.ts +1908 -0
  119. package/src/cli/migrate-provider-shape.ts +10 -4
  120. package/src/cli/resolver-runtime.ts +72 -0
  121. package/src/define.ts +13 -0
  122. package/src/dev.ts +9 -2
  123. package/src/engine.ts +38 -2
  124. package/src/error-resolution.ts +58 -0
  125. package/src/errors.ts +77 -1
  126. package/src/i18n/error-messages.ts +255 -0
  127. package/src/i18n/index.ts +1 -0
  128. package/src/i18n/keys.ts +80 -6
  129. package/src/index.ts +72 -0
  130. package/src/lint.ts +522 -50
  131. package/src/provider.ts +10 -0
  132. package/src/runtime/browser-telemetry-binding.ts +92 -0
  133. package/src/runtime/browser-telemetry.ts +289 -0
  134. package/src/runtime/browser.ts +249 -65
  135. package/src/runtime/cache-telemetry.ts +247 -0
  136. package/src/runtime/cache.ts +68 -17
  137. package/src/runtime/capability-response.ts +53 -0
  138. package/src/runtime/capability-telemetry.ts +101 -0
  139. package/src/runtime/diagnostic-env.ts +11 -1
  140. package/src/runtime/engine-mode.ts +233 -0
  141. package/src/runtime/http-telemetry-guard.ts +66 -13
  142. package/src/runtime/http.ts +168 -37
  143. package/src/runtime/instrumentation.ts +105 -16
  144. package/src/runtime/ocr-telemetry.ts +308 -0
  145. package/src/runtime/ocr.ts +109 -74
  146. package/src/runtime/request-telemetry.ts +2 -1
  147. package/src/runtime/resolver-runtime-options.ts +50 -0
  148. package/src/runtime/resolver-shared.ts +9 -4
  149. package/src/runtime/resolver-telemetry.ts +1 -1
  150. package/src/runtime/resolver-vendors/browser.ts +65 -7
  151. package/src/runtime/resolver-vendors/hosts.ts +43 -0
  152. package/src/runtime/resolver-vendors/hypersolutions.ts +2 -2
  153. package/src/runtime/resolver-vendors/types.ts +5 -4
  154. package/src/runtime/resolver.ts +64 -21
  155. package/src/runtime/state-telemetry.ts +298 -0
  156. package/src/runtime/state.ts +46 -45
  157. package/src/runtime/stealth-cookies.ts +24 -1
  158. package/src/runtime/stealth-owned-headers.ts +41 -0
  159. package/src/runtime/stealth-telemetry.ts +304 -0
  160. package/src/runtime/stealth.ts +355 -150
  161. package/src/runtime/stt-telemetry.ts +282 -0
  162. package/src/runtime/stt.ts +93 -71
  163. package/src/server/error-stack-frames.ts +214 -0
  164. package/src/server/index.ts +53 -0
  165. package/src/server/sdk-version.ts +22 -0
  166. package/src/server/self-test.ts +1 -21
  167. package/src/server/sensitive-values.ts +14 -0
  168. package/src/server/serve-implementation.ts +569 -108
  169. package/src/server/types.ts +7 -0
  170. package/src/stateful/stateful-provider-owner-forwarder.ts +23 -0
  171. package/src/stateful/stateful-provider-runtime-context.ts +4 -0
  172. package/src/types.ts +99 -1
  173. package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +0 -6
  174. package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +0 -3
  175. package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +0 -10
  176. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +0 -3
  177. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +0 -3
  178. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +0 -2
  179. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +0 -3
  180. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +0 -6
  181. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +0 -1
  182. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +0 -1
  183. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +0 -3
  184. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +0 -7
  185. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +0 -19
  186. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +0 -6
  187. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +0 -3
  188. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +0 -8
  189. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +0 -5
  190. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +0 -4
  191. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +0 -3
  192. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +0 -3
  193. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +0 -10
  194. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +0 -1
  195. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +0 -1
  196. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +0 -3
  197. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +0 -6
  198. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +0 -6
  199. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +0 -14
  200. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +0 -3
  201. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +0 -2
  202. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +0 -3
  203. package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +0 -3
  204. package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +0 -8
  205. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +0 -15
  206. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +0 -9
  207. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-kebab-operation-id.ts.txt +0 -17
  208. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +0 -5
  209. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +0 -24
  210. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +0 -16
  211. package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-snake-operation-id.ts.txt +0 -21
  212. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +0 -11
  213. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +0 -7
  214. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +0 -3
  215. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +0 -18
  216. package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +0 -13
  217. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +0 -31
  218. package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +0 -11
  219. package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +0 -11
  220. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +0 -11
  221. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +0 -21
  222. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +0 -11
  223. package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +0 -14
  224. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-en.json +0 -1
  225. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ja.json +0 -1
  226. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ko.json +0 -1
  227. package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-existing-operation-namespace-en.json +0 -8
  228. package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +0 -7
  229. package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +0 -6
  230. package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +0 -7
  231. package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +0 -6
  232. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-binding-ambiguous.ts.txt +0 -12
  233. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported-other.ts.txt +0 -7
  234. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported.ts.txt +0 -5
  235. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-key-ambiguous.ts.txt +0 -19
  236. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-shorthand.ts.txt +0 -9
  237. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-typed.ts.txt +0 -11
  238. package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-unrelated.ts.txt +0 -13
  239. package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +0 -7
  240. package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +0 -7
  241. package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +0 -15
  242. package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +0 -4
  243. package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +0 -12
@@ -0,0 +1,233 @@
1
+ import {
2
+ createInProcessProviderEngine,
3
+ PROVIDER_ENGINE_MODE_ENV,
4
+ type ProviderEngine,
5
+ type ProviderEngineMode,
6
+ } from "../engine.js";
7
+ import { ProviderError, ValidationError } from "../errors.js";
8
+
9
+ /**
10
+ * Engine attachment selection. Internal on purpose: ADR-0011 removes the
11
+ * in-process lane, so every symbol exported here would become a breaking removal
12
+ * later. The server surfaces the outcome on the `provider_engine_mode` boot
13
+ * event instead.
14
+ */
15
+
16
+ const KNOWN_PROVIDER_ENGINE_MODES = ["in-process", "remote"] as const;
17
+
18
+ /** Mode used when neither `engineMode` nor `APIFUSE__ENGINE__MODE` names one. */
19
+ export const DEFAULT_PROVIDER_ENGINE_MODE = "in-process" satisfies ProviderEngineMode;
20
+
21
+ /** Remote engine client endpoint; engine-owned, so never declarable as a provider secret. */
22
+ export const REMOTE_ENGINE_CLIENT_URL_ENV = "APIFUSE__ENGINE__URL";
23
+ /** Remote engine client credential; registered with the diagnostic redactor by sensitive-values. */
24
+ export const REMOTE_ENGINE_CLIENT_API_KEY_ENV = "APIFUSE__ENGINE__API_KEY";
25
+
26
+ /** Engine env names that only mean something in remote mode. */
27
+ const REMOTE_ONLY_ENGINE_ENV_NAMES = [
28
+ REMOTE_ENGINE_CLIENT_URL_ENV,
29
+ REMOTE_ENGINE_CLIENT_API_KEY_ENV,
30
+ ] as const;
31
+
32
+ /** Where the resolved mode came from, in precedence order. */
33
+ export type ProviderEngineModeSource = "engine" | "env" | "option" | "default";
34
+
35
+ /**
36
+ * Non-fatal conditions worth reporting at boot:
37
+ * - `invalid_env_value`: `APIFUSE__ENGINE__MODE` held an unrecognized value.
38
+ * - `env_overrode_option`: the manifest and the host code disagreed; the manifest won.
39
+ * - `engine_object_overrode_requested_mode`: an explicit engine object cannot honour the requested mode.
40
+ * - `engine_env_ignored`: remote-only engine env is projected but the mode is not
41
+ * remote (not reported for a host-supplied engine, which may consume it itself).
42
+ */
43
+ export type ProviderEngineModeWarning =
44
+ | "invalid_env_value"
45
+ | "env_overrode_option"
46
+ | "engine_object_overrode_requested_mode"
47
+ | "engine_env_ignored";
48
+
49
+ export interface ProviderEngineModeResolution {
50
+ readonly mode: ProviderEngineMode | "custom";
51
+ readonly source: ProviderEngineModeSource;
52
+ /** True for every non-remote attachment, whose removal is scheduled by ADR-0011. */
53
+ readonly deprecated: boolean;
54
+ readonly warnings: readonly ProviderEngineModeWarning[];
55
+ }
56
+
57
+ export interface ProviderEngineModeResolutionInput {
58
+ /** Explicit `engineMode` option passed by the host process. */
59
+ readonly option?: ProviderEngineMode;
60
+ /** Explicit engine object passed by the host; used as given when present. */
61
+ readonly engine?: Pick<ProviderEngine, "kind">;
62
+ /** Environment to read the engine env from; defaults to `process.env`. */
63
+ readonly environment?: Readonly<Record<string, string | undefined>>;
64
+ }
65
+
66
+ function isKnownMode(value: string): value is (typeof KNOWN_PROVIDER_ENGINE_MODES)[number] {
67
+ return (KNOWN_PROVIDER_ENGINE_MODES as readonly string[]).includes(value);
68
+ }
69
+
70
+ function normalize(value: unknown): string | undefined {
71
+ if (typeof value !== "string") return undefined;
72
+ const trimmed = value.trim().toLowerCase();
73
+ return trimmed === "" ? undefined : trimmed;
74
+ }
75
+
76
+ /**
77
+ * Resolve the engine attachment mode once at boot.
78
+ *
79
+ * Precedence: an explicit `engine` object, then `APIFUSE__ENGINE__MODE`, then the
80
+ * `engineMode` option, then the default. The manifest outranks the option so
81
+ * provider code cannot silently downgrade what the deployment asked for; every
82
+ * disagreement is reported in `warnings` with a truthful `source` rather than
83
+ * being dropped.
84
+ *
85
+ * Deployment-authored input is never fatal (an unrecognized env value is warned
86
+ * about and ignored). A malformed `engineMode` option is a fault in the calling
87
+ * code, which no manifest can reach, so it throws.
88
+ */
89
+ export function resolveProviderEngineMode(
90
+ input: ProviderEngineModeResolutionInput = {},
91
+ ): ProviderEngineModeResolution {
92
+ const environment = input.environment ?? process.env;
93
+ const warnings: ProviderEngineModeWarning[] = [];
94
+
95
+ // Read directly: this is a mode name, not a credential, so it must not be
96
+ // registered with the diagnostic redactor the way readDiagnosticEnv is.
97
+ const rawEnv = normalize(environment[PROVIDER_ENGINE_MODE_ENV]);
98
+ let envMode: ProviderEngineMode | undefined;
99
+ if (rawEnv !== undefined) {
100
+ if (isKnownMode(rawEnv)) envMode = rawEnv;
101
+ else warnings.push("invalid_env_value");
102
+ }
103
+
104
+ const optionMode = normalize(input.option);
105
+ if (input.option !== undefined && (optionMode === undefined || !isKnownMode(optionMode))) {
106
+ throw new ValidationError(
107
+ `Invalid engineMode option "${String(input.option)}"; expected ${KNOWN_PROVIDER_ENGINE_MODES.join(" or ")}`,
108
+ { fix: 'Pass engineMode: "in-process" | "remote", or omit it to use the default.' },
109
+ );
110
+ }
111
+ if (optionMode !== undefined && envMode !== undefined && optionMode !== envMode) {
112
+ warnings.push("env_overrode_option");
113
+ }
114
+
115
+ const requested = envMode ?? optionMode;
116
+ const requestedSource: ProviderEngineModeSource | undefined =
117
+ envMode !== undefined ? "env" : optionMode !== undefined ? "option" : undefined;
118
+
119
+ // Normalized like every other mode input: an un-normalized host `kind` would
120
+ // reach the boot event and /readyz verbatim and mis-score the fleet audit.
121
+ const engineKind =
122
+ input.engine === undefined ? undefined : (normalize(input.engine.kind) ?? "custom");
123
+ if (engineKind !== undefined) {
124
+ if (requested !== undefined && engineKind !== requested) {
125
+ warnings.push("engine_object_overrode_requested_mode");
126
+ }
127
+ return finalize(engineKind, "engine", environment, warnings);
128
+ }
129
+
130
+ return finalize(
131
+ requested ?? DEFAULT_PROVIDER_ENGINE_MODE,
132
+ requestedSource ?? "default",
133
+ environment,
134
+ warnings,
135
+ );
136
+ }
137
+
138
+ function finalize(
139
+ mode: ProviderEngineMode | "custom",
140
+ source: ProviderEngineModeSource,
141
+ environment: Readonly<Record<string, string | undefined>>,
142
+ warnings: ProviderEngineModeWarning[],
143
+ ): ProviderEngineModeResolution {
144
+ // Presence of the remote engine env never selects a mode (the manifest
145
+ // generator projects it fleet-wide before the SDK can use it), but staying
146
+ // silent about it would hide a half-applied cutover. Skipped for a host-supplied
147
+ // engine: that object may be a remote client that consumes the env itself, so
148
+ // claiming the env is unused would be a false report.
149
+ if (
150
+ mode !== "remote" &&
151
+ source !== "engine" &&
152
+ REMOTE_ONLY_ENGINE_ENV_NAMES.some((name) => normalize(environment[name]) !== undefined)
153
+ ) {
154
+ warnings.push("engine_env_ignored");
155
+ }
156
+ // Fail-closed for the ADR-0011 audit: everything that is not the remote lane
157
+ // still attaches capabilities inside the pod process and is scheduled for
158
+ // removal, including an opaque host engine that declares no kind.
159
+ return { mode, source, deprecated: mode !== "remote", warnings };
160
+ }
161
+
162
+ const UNAVAILABLE_ENGINES = new WeakSet<ProviderEngine>();
163
+
164
+ /** True when the engine cannot attach, so readiness must report the process as unready. */
165
+ export function isUnavailableProviderEngine(engine: ProviderEngine): boolean {
166
+ return UNAVAILABLE_ENGINES.has(engine);
167
+ }
168
+
169
+ /**
170
+ * Engine that refuses every attachment with `reason`.
171
+ *
172
+ * Requesting a mode this release cannot serve must not crash the process: the SDK
173
+ * answers a structured error per request and reports the process unready, the same
174
+ * trade-off `provider_secrets_missing` already makes at boot. Non-retryable, so a
175
+ * caller-side retry loop cannot turn a configuration fault into load.
176
+ */
177
+ export function createUnavailableProviderEngine(
178
+ kind: ProviderEngineMode,
179
+ reason: { message: string; code: string; fix: string },
180
+ ): ProviderEngine {
181
+ const engine: ProviderEngine = {
182
+ kind,
183
+ attach: () => {
184
+ throw new ProviderError(reason.message, {
185
+ code: reason.code,
186
+ retryable: false,
187
+ fix: reason.fix,
188
+ });
189
+ },
190
+ };
191
+ UNAVAILABLE_ENGINES.add(engine);
192
+ return engine;
193
+ }
194
+
195
+ /**
196
+ * Engine for a resolved mode. `remote` has no client in this release, so it
197
+ * resolves to an engine that fails every request instead of falling back to
198
+ * in-process (ADR-0011 Pitfall 2: in-process is never a fallback).
199
+ */
200
+ export function createEngineForMode(mode: ProviderEngineMode | "custom"): ProviderEngine {
201
+ // Default-deny on the mode name, not just on "remote": the mode union is open
202
+ // so a later lane can be named, and falling through to in-process for an
203
+ // unserved lane is the silent downgrade ADR-0011 Pitfall 2 forbids.
204
+ if (mode === DEFAULT_PROVIDER_ENGINE_MODE) return createInProcessProviderEngine();
205
+ return createUnavailableProviderEngine(mode, {
206
+ message: `Provider engine mode "${mode}" was requested but this @apifuse/provider-sdk release only serves the ${DEFAULT_PROVIDER_ENGINE_MODE} engine`,
207
+ code: "PROVIDER_ENGINE_MODE_UNSUPPORTED",
208
+ fix: `Unset ${PROVIDER_ENGINE_MODE_ENV} (or the engineMode option), or upgrade to a release that serves this mode.`,
209
+ });
210
+ }
211
+
212
+ /**
213
+ * Fail fast for the CLIs (`apifuse dev`, `apifuse record`). They are developer
214
+ * tools, not pods: an unusable mode should stop the command rather than start a
215
+ * server that refuses every request.
216
+ */
217
+ export function assertProcessEngineModeSupported(
218
+ environment: Readonly<Record<string, string | undefined>> = process.env,
219
+ ): ProviderEngineModeResolution {
220
+ const resolution = resolveProviderEngineMode({ environment });
221
+ if (resolution.mode !== DEFAULT_PROVIDER_ENGINE_MODE) {
222
+ throw new ProviderError(
223
+ `Provider engine mode "${resolution.mode}" was requested but this @apifuse/provider-sdk release only serves the ${DEFAULT_PROVIDER_ENGINE_MODE} engine`,
224
+ {
225
+ code: "PROVIDER_ENGINE_MODE_UNSUPPORTED",
226
+ retryable: false,
227
+ details: { mode: resolution.mode, source: resolution.source },
228
+ fix: `Unset ${PROVIDER_ENGINE_MODE_ENV}, or upgrade to a release that serves this mode.`,
229
+ },
230
+ );
231
+ }
232
+ return resolution;
233
+ }
@@ -1,3 +1,4 @@
1
+ import { isPromise } from "node:util/types";
1
2
  import type { HttpRetrySummary } from "../types.js";
2
3
  import {
3
4
  HttpTelemetryCollector,
@@ -46,7 +47,7 @@ function absorbObserverPromise(value: object): void {
46
47
  function isAsyncObserverReturn(value: unknown): boolean {
47
48
  if (!value || (typeof value !== "object" && typeof value !== "function")) return false;
48
49
  try {
49
- if (!("then" in value) || typeof value.then !== "function") return false;
50
+ if (!isPromise(value) && (!("then" in value) || typeof value.then !== "function")) return false;
50
51
  } catch {
51
52
  // A rejected Promise can itself have a throwing `then` getter. Still absorb it.
52
53
  }
@@ -54,11 +55,25 @@ function isAsyncObserverReturn(value: unknown): boolean {
54
55
  return true;
55
56
  }
56
57
 
57
- /** Keep all public observers, including property access, outside transport failures. */
58
- export function startHttpTelemetry(
59
- sink: HttpTelemetrySink | undefined,
60
- retryPreset: HttpRetrySummary["preset"],
61
- ): HttpTelemetryRequestSink & { observe(callback: () => void): void } {
58
+ /** Shared synchronous observer boundary for transport and capability contributors. */
59
+ export function observeTelemetry<T>(callback: () => T, fail: () => void): T | undefined {
60
+ try {
61
+ const result = callback();
62
+ if (isAsyncObserverReturn(result)) {
63
+ fail();
64
+ return undefined;
65
+ }
66
+ return result;
67
+ } catch {
68
+ fail();
69
+ return undefined;
70
+ }
71
+ }
72
+
73
+ /** Isolate synchronous void capability hooks using the same Promise defence. */
74
+ export function createTelemetryObserver(
75
+ sink: { markTelemetryFailed?(): void } | undefined,
76
+ ): (callback: () => unknown) => void {
62
77
  let failed = false;
63
78
  const fail = () => {
64
79
  if (failed) return;
@@ -66,23 +81,38 @@ export function startHttpTelemetry(
66
81
  try {
67
82
  isAsyncObserverReturn(sink?.markTelemetryFailed?.());
68
83
  } catch {
69
- // The failure reporter is itself an observer. Never recurse.
84
+ // The failure marker is also an observer.
70
85
  }
71
86
  };
72
- const observe = <T>(callback: () => T): T | undefined => {
87
+ return (callback) => {
73
88
  try {
74
89
  const result = callback();
75
- if (isAsyncObserverReturn(result)) {
76
- // The observer API is synchronous. Absorb invalid asynchronous returns too.
90
+ if (result !== undefined) {
91
+ isAsyncObserverReturn(result);
77
92
  fail();
78
- return undefined;
79
93
  }
80
- return result;
81
94
  } catch {
82
95
  fail();
83
- return undefined;
84
96
  }
85
97
  };
98
+ }
99
+
100
+ /** Keep all public observers, including property access, outside transport failures. */
101
+ export function startHttpTelemetry(
102
+ sink: HttpTelemetrySink | undefined,
103
+ retryPreset: HttpRetrySummary["preset"],
104
+ ): HttpTelemetryRequestSink & { observe(callback: () => void): void } {
105
+ let failed = false;
106
+ const fail = () => {
107
+ if (failed) return;
108
+ failed = true;
109
+ try {
110
+ isAsyncObserverReturn(sink?.markTelemetryFailed?.());
111
+ } catch {
112
+ // The failure reporter is itself an observer. Never recurse.
113
+ }
114
+ };
115
+ const observe = <T>(callback: () => T): T | undefined => observeTelemetry(callback, fail);
86
116
  const result = observe(() =>
87
117
  (sink ?? new HttpTelemetryCollector()).startRequest({ retryPreset }),
88
118
  );
@@ -153,3 +183,26 @@ export function startHttpTelemetry(
153
183
  },
154
184
  };
155
185
  }
186
+
187
+ /** Generic observer guard shared by capability hooks. Returned thenables are absorbed. */
188
+ export function observeTelemetryCallback(
189
+ sink: { markTelemetryFailed?: () => unknown } | undefined,
190
+ callback: () => unknown,
191
+ ): void {
192
+ let failed = false;
193
+ const fail = () => {
194
+ if (failed) return;
195
+ failed = true;
196
+ try {
197
+ isAsyncObserverReturn(sink?.markTelemetryFailed?.());
198
+ } catch {
199
+ // Observer failure is never transport failure.
200
+ }
201
+ };
202
+ try {
203
+ const result = callback();
204
+ if (isAsyncObserverReturn(result) || result !== undefined) fail();
205
+ } catch {
206
+ fail();
207
+ }
208
+ }