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

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.
@@ -11,7 +11,7 @@ export { createProviderEnvironment, createInProcessProviderEngine, ENGINE_OWNED_
11
11
  export type { ProviderCapabilityKey, ProviderEngine, ProviderEngineAttachmentInput, ProviderEngineBindingCandidates, ProviderEngineCapabilitySurface, ProviderEngineMode, ProviderEngineRequest, ProviderEngineResidentSurface, ProviderEngineSession, ProviderEngineTransport, } from "./engine.js";
12
12
  export { getProviderLocalePath, type ProviderErrorMessageParams, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
13
13
  export * from "./handle.js";
14
- export { APIFUSE_HANDLE_META_KEY, HANDLE_KIND_NAME_PATTERN, handleFieldDescription, isHandleFieldMeta, } from "./handle-meta.js";
14
+ export { APIFUSE_HANDLE_META_KEY, HANDLE_KIND_NAME_PATTERN, handleFieldDescription, handleFieldNameFor, handleHasDirectionalFieldNames, isHandleFieldMeta, } from "./handle-meta.js";
15
15
  export { type CreateHandleContextOptions, type CreateTestHandleContextOptions, createHandleContext, createTestHandleContext, type HandleNormalizationClass, type NormalizedHandle, normalizeHandle, } from "./runtime/handle.js";
16
16
  export { createMemoryProviderRuntimeState, createUnsupportedProviderRuntimeState, } from "./runtime/state.js";
17
17
  export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, untrustedContent, z, } from "./schema.js";
package/dist/provider.js CHANGED
@@ -6,7 +6,7 @@ export { AuthError, HttpRedirectError, isProviderError, isSessionExpiredError, i
6
6
  export { createProviderEnvironment, createInProcessProviderEngine, ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RUNTIME_ENV_NAMES, ENGINE_OWNED_TELEMETRY_ENV_NAMES, isEngineOwnedEnvName, isEngineOwnedProxyCredentialName, isEngineOwnedResolverCredentialName, isEngineOwnedRuntimeEnvName, isEngineOwnedTelemetryEnvName, PROVIDER_CAPABILITY_KEYS, PROVIDER_ENGINE_MODE_ENV, PROVIDER_ENGINE_PROTOCOL_VERSION, readEngineProxyCredentials, } from "./engine.js";
7
7
  export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n/index.js";
8
8
  export * from "./handle.js";
9
- export { APIFUSE_HANDLE_META_KEY, HANDLE_KIND_NAME_PATTERN, handleFieldDescription, isHandleFieldMeta, } from "./handle-meta.js";
9
+ export { APIFUSE_HANDLE_META_KEY, HANDLE_KIND_NAME_PATTERN, handleFieldDescription, handleFieldNameFor, handleHasDirectionalFieldNames, isHandleFieldMeta, } from "./handle-meta.js";
10
10
  export { createHandleContext, createTestHandleContext, normalizeHandle, } from "./runtime/handle.js";
11
11
  export { createMemoryProviderRuntimeState, createUnsupportedProviderRuntimeState, } from "./runtime/state.js";
12
12
  export { APIFUSE_CONTENT_PROVENANCE_META_KEY, APIFUSE_CONTENT_TRUST_META_KEY, APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, publicField, redactPayload, sensitive, untrustedContent, z, } from "./schema.js";
@@ -11,7 +11,7 @@
11
11
  import { randomInt, randomUUID } from "node:crypto";
12
12
  import { isProviderError } from "../errors.js";
13
13
  import { HandleError, handleRecoverySentence, isDraftKind, } from "../handle.js";
14
- import { formatHandleIssuers } from "../handle-meta.js";
14
+ import { formatHandleIssuers, handleHasDirectionalFieldNames } from "../handle-meta.js";
15
15
  import { BOUND_HANDLE_WORD_COUNT, findHandleWordWithinDistance, HIGH_PUBLIC_HANDLE_WORD_COUNT, ISSUABLE_HANDLE_WORDS, PUBLIC_HANDLE_WORD_COUNT, } from "./handle-wordlist.js";
16
16
  import { createMemoryProviderRuntimeState } from "./state.js";
17
17
  const RECORD_VERSION = 1;
@@ -153,6 +153,14 @@ export function formatNormalizationClasses(classes) {
153
153
  // Errors (spec §5)
154
154
  // ---------------------------------------------------------------------------
155
155
  function publicCollapsedMessage(kind) {
156
+ // "a new one" is unambiguous only while the kind has one name. When it is
157
+ // issued under `next_cursor` and accepted under `cursor`, the caller has to
158
+ // be told which field to read, so use the full recovery sentence — it names
159
+ // both keys and is identical for invalid / expired / not-found, which is
160
+ // what keeps the public collapse indistinguishable.
161
+ if (handleHasDirectionalFieldNames(kind)) {
162
+ return `\`${kind.fieldName}\` is not valid or has expired. ${handleRecoverySentence(kind)}`;
163
+ }
156
164
  const issuers = formatHandleIssuers(kind.issuedBy);
157
165
  const again = issuers ? `Call ${issuers} again to get a new one.` : "Request a new one.";
158
166
  return `\`${kind.fieldName}\` is not valid or has expired. ${again}`;
@@ -42,6 +42,10 @@ function createErrorOcrClient(options) {
42
42
  });
43
43
  };
44
44
  return tagCapability({
45
+ // Own data property: `bindOcrTelemetry` re-spreads the context, so a
46
+ // getter or prototype member would silently vanish before reaching
47
+ // provider code.
48
+ available: false,
45
49
  async recognize() {
46
50
  return unavailable();
47
51
  },
@@ -274,6 +278,7 @@ function toOcrTransportError(error) {
274
278
  }
275
279
  function createOcrClient(model, recognize) {
276
280
  return {
281
+ available: true,
277
282
  recognize,
278
283
  async extractCaptchaText(image, options = {}) {
279
284
  const result = await recognize({ image, hint: "captcha" });
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Runtime boundary lint: provider runtime source must reach the outside world
3
+ * through the SDK context (`ctx.http`, `ctx.stealth`, `ctx.env`,
4
+ * `ctx.credential`, `ctx.browser`), not through ambient Node/Bun globals.
5
+ *
6
+ * Three rules, reported at `error` level: a finding fails `apifuse check` and
7
+ * `apifuse submit-check` (official and standalone mode alike). The first
8
+ * release reported them at `warn` as a migration window; the window closed once
9
+ * the fleet's request-path hits were fixed or acknowledged. A deliberate
10
+ * exception is acknowledged in code (see below), never through a hidden
11
+ * allowlist.
12
+ *
13
+ * - `process-env-direct-read`: `process.env.X`, `process.env["X"]`, a bare
14
+ * `process.env` object use, and the `Bun.env` equivalents. Runtime bootstrap
15
+ * keys (`APIFUSE__RUNTIME__*`) are exempt everywhere because `serve()`
16
+ * callers read the port and pod identity before a context exists.
17
+ * - `node-runtime-module-import`: value imports of `fs`, `fs/promises`, `net`,
18
+ * `tls`, `dgram`, `http`, `https`, `http2`, `child_process` (with or without
19
+ * the `node:` prefix) via import/export declarations, `require()`, or dynamic
20
+ * `import()`, plus the Bun equivalents `Bun.spawn`, `Bun.spawnSync`, `Bun.$`,
21
+ * `Bun.file`, `Bun.write`. Type-only imports are not runtime reach and are
22
+ * ignored.
23
+ * - `direct-fetch-call`: a call to the global `fetch` (bare identifier, or
24
+ * `globalThis`/`window`/`self`/`global` member). A bare `fetch` call whose
25
+ * enclosing scope declares a `fetch` binding (parameter, variable, import,
26
+ * function, catch clause) is calling that binding, not the global, and is
27
+ * left alone; the check is lexical, so a wrapper that takes `fetch` as a
28
+ * parameter does not hide a global `fetch()` elsewhere in the same file.
29
+ * `ctx.stealth.fetch()` is a member call and never matches.
30
+ *
31
+ * Files are parsed with the script kind their extension implies (`.ts` as
32
+ * TypeScript, `.tsx` as TSX, …). Parsing everything as TSX would make a
33
+ * generic arrow (`<T>(value: T) => value`) or an angle-bracket assertion in an
34
+ * ordinary `.ts` file read as JSX, and everything after it would silently drop
35
+ * out of the AST.
36
+ *
37
+ * Scope is the provider *runtime* source: JavaScript/TypeScript files under
38
+ * `providerSourceFiles` minus tests, recorded fixtures, the root bootstrap
39
+ * entrypoints (`dev.ts`, `start.ts`, `deploy.ts`) and the operator tooling
40
+ * directories (`scripts/`, `tools/`, `bin/`). Tooling legitimately reads the
41
+ * ambient environment and the filesystem when a human runs it; the rule is
42
+ * about code the pod executes on behalf of a request.
43
+ *
44
+ * A deliberate exception is acknowledged with the same escape hatch the submit
45
+ * check uses: `// @apifuse-allow <rule>: <reason>` on the finding line or the
46
+ * line directly above it. Acknowledged findings are reported as information so
47
+ * `apifuse check` still lists them.
48
+ */
49
+ import type { LintDiagnostic, ProviderLintInformation, ProviderLintResult } from "./lint.js";
50
+ import { type TypeScriptCompilerModuleLike, type TypeScriptModule } from "./typescript-module.js";
51
+ export declare const PROCESS_ENV_DIRECT_READ_RULE = "process-env-direct-read";
52
+ export declare const NODE_RUNTIME_MODULE_IMPORT_RULE = "node-runtime-module-import";
53
+ export declare const DIRECT_FETCH_CALL_RULE = "direct-fetch-call";
54
+ export declare const RUNTIME_BOUNDARY_RULES: readonly ["process-env-direct-read", "node-runtime-module-import", "direct-fetch-call"];
55
+ export type RuntimeBoundaryRule = (typeof RUNTIME_BOUNDARY_RULES)[number];
56
+ /**
57
+ * Environment names a provider may read from `process.env` directly. These
58
+ * are consumed before `serve()` builds a context (port, pod identity), so
59
+ * `ctx.env` cannot carry them. The whole `APIFUSE__RUNTIME__` family is the
60
+ * bootstrap contract; nothing else is exempt.
61
+ */
62
+ export declare const BOOTSTRAP_ENV_NAME_PREFIX = "APIFUSE__RUNTIME__";
63
+ export declare function isBootstrapEnvName(name: string): boolean;
64
+ export declare const TEST_SOURCE_FILE_PATTERN: RegExp;
65
+ type RuntimeBoundaryFinding = {
66
+ rule: RuntimeBoundaryRule;
67
+ /** 1-based line. */
68
+ line: number;
69
+ /** What was reached: the env name, module specifier, or call text. */
70
+ subject: string;
71
+ };
72
+ type RuntimeBoundaryFileReport = {
73
+ findings: RuntimeBoundaryFinding[];
74
+ acknowledged: Array<RuntimeBoundaryFinding & {
75
+ reason: string;
76
+ }>;
77
+ };
78
+ /** True for the files the runtime boundary rules look at. */
79
+ export declare function isRuntimeBoundarySourceFile(relativePath: string): boolean;
80
+ /**
81
+ * Script kind for a provider source file, from its extension. `.tsx`/`.jsx`
82
+ * enable JSX; everything else (`.ts`, `.mts`, `.cts`, `.js`, `.mjs`, `.cjs`,
83
+ * and the synthetic names used for in-memory sources) does not, so a generic
84
+ * arrow or `<T>value` assertion in a `.ts` file parses as TypeScript instead
85
+ * of swallowing the rest of the file as unterminated JSX.
86
+ */
87
+ export declare function scriptKindForSourceFile(ts: TypeScriptModule, fileName: string): import("typescript").ScriptKind;
88
+ export declare function analyzeRuntimeBoundary(ts: TypeScriptModule, fileName: string, source: string): RuntimeBoundaryFileReport;
89
+ export type RuntimeBoundaryLintInput = {
90
+ authFlowSource?: string;
91
+ providerSourceFiles?: Record<string, string>;
92
+ operations?: Record<string, {
93
+ handler?: unknown;
94
+ source?: string;
95
+ }>;
96
+ };
97
+ /**
98
+ * Lint the provider runtime boundary. Returns error-level diagnostics (one per
99
+ * file and rule, listing every line) and information entries for findings
100
+ * acknowledged with `@apifuse-allow`.
101
+ */
102
+ export declare function lintRuntimeBoundary(ts: TypeScriptModule, provider: RuntimeBoundaryLintInput, readOperationSource: (operation: {
103
+ handler?: unknown;
104
+ source?: string;
105
+ }) => string): {
106
+ diagnostics: LintDiagnostic[];
107
+ information: ProviderLintInformation[];
108
+ };
109
+ export type LintRuntimeBoundarySourcesOptions = {
110
+ /**
111
+ * A loaded TypeScript compiler API module to parse with (`typescript` 6.x
112
+ * or `@typescript/typescript6`). When omitted the SDK resolves one from its
113
+ * own install location, trying `typescript` first and falling back to
114
+ * `@typescript/typescript6` when `typescript` is the 7.x native shell
115
+ * without `createSourceFile`. A caller whose dependency tree pins its own
116
+ * compiler module (the APIFuse monorepo contract check) passes it here so
117
+ * the parse does not depend on what hoists next to the SDK.
118
+ */
119
+ typescript?: TypeScriptCompilerModuleLike;
120
+ };
121
+ /**
122
+ * Lint provider runtime source files for the runtime boundary rules without a
123
+ * provider definition: `files` maps provider-root-relative paths to source
124
+ * text (the same shape `apifuse check` collects as `providerSourceFiles`).
125
+ * Out-of-scope paths (tests, recorded fixtures, `.d.ts`, the root
126
+ * `dev.ts`/`start.ts`/`deploy.ts`, `scripts/`, `tools/`, `bin/`) are skipped
127
+ * with `isRuntimeBoundarySourceFile`. Diagnostics carry
128
+ * `field: "sourceFiles.<path>"`; `@apifuse-allow` acknowledgements come back
129
+ * as `information`.
130
+ *
131
+ * Parses with `options.typescript` when given, otherwise with the compiler
132
+ * module resolved from the installed SDK (see `getTypeScript`). This is the
133
+ * entry point the platform contract check uses to apply the rules with the
134
+ * monorepo's SDK pin instead of each provider's own pin.
135
+ */
136
+ export declare function lintRuntimeBoundarySources(files: Record<string, string>, options?: LintRuntimeBoundarySourcesOptions): ProviderLintResult;
137
+ export {};