@apifuse/provider-sdk 2.2.0-beta.61 → 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.
- package/AUTHORING.md +268 -9
- package/CHANGELOG.md +8 -0
- package/README.md +1 -0
- package/bin/apifuse-check.ts +84 -2
- package/bin/apifuse-dev.ts +11 -31
- package/bin/apifuse-migrate-deployment.ts +200 -0
- package/bin/apifuse-pack-check.ts +11 -4
- package/bin/apifuse-pack-types.ts +191 -4
- package/bin/apifuse-record.ts +44 -32
- package/bin/apifuse-test.ts +3 -1
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +11 -0
- package/dist/cli/deployment-intent.d.ts +178 -0
- package/dist/cli/deployment-intent.js +277 -0
- package/dist/cli/migrate-deployment-intent.d.ts +132 -0
- package/dist/cli/migrate-deployment-intent.js +1552 -0
- package/dist/cli/migrate-provider-shape.d.ts +5 -1
- package/dist/cli/migrate-provider-shape.js +4 -2
- package/dist/cli/resolver-runtime.d.ts +21 -0
- package/dist/cli/resolver-runtime.js +31 -0
- package/dist/define.d.ts +3 -0
- package/dist/define.js +5 -0
- package/dist/dev.d.ts +3 -1
- package/dist/dev.js +6 -1
- package/dist/engine.d.ts +35 -1
- package/dist/engine.js +21 -2
- package/dist/error-resolution.d.ts +1 -0
- package/dist/error-resolution.js +54 -0
- package/dist/errors.d.ts +39 -1
- package/dist/errors.js +50 -0
- package/dist/handle-meta.d.ts +18 -2
- package/dist/handle-meta.js +30 -2
- package/dist/handle.d.ts +33 -12
- package/dist/handle.js +69 -24
- package/dist/i18n/error-messages.d.ts +86 -0
- package/dist/i18n/error-messages.js +192 -0
- package/dist/i18n/index.d.ts +1 -0
- package/dist/i18n/index.js +1 -0
- package/dist/i18n/keys.d.ts +12 -0
- package/dist/i18n/keys.js +76 -5
- package/dist/index.d.ts +10 -2
- package/dist/index.js +9 -1
- package/dist/lint.d.ts +10 -0
- package/dist/lint.js +440 -57
- package/dist/provider.d.ts +7 -5
- package/dist/provider.js +4 -2
- package/dist/runtime/browser-telemetry-binding.d.ts +5 -0
- package/dist/runtime/browser-telemetry-binding.js +83 -0
- package/dist/runtime/browser-telemetry.d.ts +76 -0
- package/dist/runtime/browser-telemetry.js +165 -0
- package/dist/runtime/browser.d.ts +3 -0
- package/dist/runtime/browser.js +208 -47
- package/dist/runtime/cache-telemetry.d.ts +71 -0
- package/dist/runtime/cache-telemetry.js +177 -0
- package/dist/runtime/cache.js +67 -7
- package/dist/runtime/capability-response.d.ts +3 -0
- package/dist/runtime/capability-response.js +56 -0
- package/dist/runtime/capability-telemetry.d.ts +46 -0
- package/dist/runtime/capability-telemetry.js +68 -0
- package/dist/runtime/diagnostic-env.d.ts +3 -0
- package/dist/runtime/diagnostic-env.js +10 -1
- package/dist/runtime/engine-mode.d.ts +74 -0
- package/dist/runtime/engine-mode.js +152 -0
- package/dist/runtime/handle.js +15 -10
- package/dist/runtime/http-telemetry-binding.d.ts +10 -0
- package/dist/runtime/http-telemetry-binding.js +152 -0
- package/dist/runtime/http-telemetry-guard.d.ts +16 -0
- package/dist/runtime/http-telemetry-guard.js +202 -0
- package/dist/runtime/http-telemetry.d.ts +104 -0
- package/dist/runtime/http-telemetry.js +190 -0
- package/dist/runtime/http.d.ts +31 -0
- package/dist/runtime/http.js +356 -174
- package/dist/runtime/instrumentation.js +92 -13
- package/dist/runtime/ocr-telemetry.d.ts +82 -0
- package/dist/runtime/ocr-telemetry.js +192 -0
- package/dist/runtime/ocr.js +30 -8
- package/dist/runtime/request-telemetry.d.ts +2 -0
- package/dist/runtime/request-telemetry.js +2 -1
- package/dist/runtime/resolver-runtime-options.d.ts +14 -0
- package/dist/runtime/resolver-runtime-options.js +33 -0
- package/dist/runtime/resolver-shared.d.ts +3 -2
- package/dist/runtime/resolver-shared.js +4 -4
- package/dist/runtime/resolver-telemetry.d.ts +1 -0
- package/dist/runtime/resolver-telemetry.js +1 -1
- package/dist/runtime/resolver-vendors/browser.d.ts +2 -0
- package/dist/runtime/resolver-vendors/browser.js +46 -0
- package/dist/runtime/resolver-vendors/hosts.d.ts +21 -0
- package/dist/runtime/resolver-vendors/hosts.js +35 -0
- package/dist/runtime/resolver-vendors/hypersolutions.js +2 -2
- package/dist/runtime/resolver-vendors/types.d.ts +5 -4
- package/dist/runtime/resolver.d.ts +4 -1
- package/dist/runtime/resolver.js +46 -13
- package/dist/runtime/state-telemetry.d.ts +79 -0
- package/dist/runtime/state-telemetry.js +194 -0
- package/dist/runtime/state.d.ts +3 -0
- package/dist/runtime/state.js +26 -7
- package/dist/runtime/stealth-cookies.d.ts +5 -1
- package/dist/runtime/stealth-cookies.js +21 -1
- package/dist/runtime/stealth-owned-headers.d.ts +26 -0
- package/dist/runtime/stealth-owned-headers.js +37 -0
- package/dist/runtime/stealth-telemetry.d.ts +92 -0
- package/dist/runtime/stealth-telemetry.js +179 -0
- package/dist/runtime/stealth.d.ts +4 -1
- package/dist/runtime/stealth.js +228 -85
- package/dist/runtime/stt-telemetry.d.ts +77 -0
- package/dist/runtime/stt-telemetry.js +176 -0
- package/dist/runtime/stt.js +15 -6
- package/dist/server/error-stack-frames.d.ts +35 -0
- package/dist/server/error-stack-frames.js +219 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.js +5 -0
- package/dist/server/sdk-version.d.ts +3 -0
- package/dist/server/sdk-version.js +19 -0
- package/dist/server/self-test.js +1 -18
- package/dist/server/sensitive-values.d.ts +1 -1
- package/dist/server/sensitive-values.js +9 -0
- package/dist/server/serve-implementation.d.ts +53 -2
- package/dist/server/serve-implementation.js +369 -123
- package/dist/server/types.d.ts +1 -0
- package/dist/server/types.js +7 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +22 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +3 -0
- package/dist/stateful/stateful-provider-runtime-context.js +1 -0
- package/dist/types.d.ts +94 -1
- package/package.json +6 -1
- package/src/cli/commands.ts +14 -0
- package/src/cli/deployment-intent.ts +364 -0
- package/src/cli/migrate-deployment-intent.ts +1908 -0
- package/src/cli/migrate-provider-shape.ts +10 -4
- package/src/cli/resolver-runtime.ts +72 -0
- package/src/define.ts +13 -0
- package/src/dev.ts +9 -2
- package/src/engine.ts +38 -2
- package/src/error-resolution.ts +58 -0
- package/src/errors.ts +77 -1
- package/src/handle-meta.ts +39 -4
- package/src/handle.ts +121 -38
- package/src/i18n/error-messages.ts +255 -0
- package/src/i18n/index.ts +1 -0
- package/src/i18n/keys.ts +80 -6
- package/src/index.ts +91 -0
- package/src/lint.ts +552 -57
- package/src/provider.ts +20 -0
- package/src/runtime/browser-telemetry-binding.ts +92 -0
- package/src/runtime/browser-telemetry.ts +289 -0
- package/src/runtime/browser.ts +249 -65
- package/src/runtime/cache-telemetry.ts +247 -0
- package/src/runtime/cache.ts +68 -17
- package/src/runtime/capability-response.ts +53 -0
- package/src/runtime/capability-telemetry.ts +101 -0
- package/src/runtime/diagnostic-env.ts +11 -1
- package/src/runtime/engine-mode.ts +233 -0
- package/src/runtime/handle.ts +20 -10
- package/src/runtime/http-telemetry-binding.ts +162 -0
- package/src/runtime/http-telemetry-guard.ts +208 -0
- package/src/runtime/http-telemetry.ts +292 -0
- package/src/runtime/http.ts +457 -204
- package/src/runtime/instrumentation.ts +105 -16
- package/src/runtime/ocr-telemetry.ts +308 -0
- package/src/runtime/ocr.ts +109 -74
- package/src/runtime/request-telemetry.ts +2 -1
- package/src/runtime/resolver-runtime-options.ts +50 -0
- package/src/runtime/resolver-shared.ts +9 -4
- package/src/runtime/resolver-telemetry.ts +1 -1
- package/src/runtime/resolver-vendors/browser.ts +65 -7
- package/src/runtime/resolver-vendors/hosts.ts +43 -0
- package/src/runtime/resolver-vendors/hypersolutions.ts +2 -2
- package/src/runtime/resolver-vendors/types.ts +5 -4
- package/src/runtime/resolver.ts +64 -21
- package/src/runtime/state-telemetry.ts +298 -0
- package/src/runtime/state.ts +46 -45
- package/src/runtime/stealth-cookies.ts +24 -1
- package/src/runtime/stealth-owned-headers.ts +41 -0
- package/src/runtime/stealth-telemetry.ts +304 -0
- package/src/runtime/stealth.ts +355 -150
- package/src/runtime/stt-telemetry.ts +282 -0
- package/src/runtime/stt.ts +93 -71
- package/src/server/error-stack-frames.ts +214 -0
- package/src/server/index.ts +66 -0
- package/src/server/sdk-version.ts +22 -0
- package/src/server/self-test.ts +1 -21
- package/src/server/sensitive-values.ts +14 -0
- package/src/server/serve-implementation.ts +601 -157
- package/src/server/types.ts +7 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +23 -0
- package/src/stateful/stateful-provider-runtime-context.ts +4 -0
- package/src/types.ts +99 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +0 -10
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +0 -2
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +0 -19
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +0 -8
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +0 -5
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +0 -4
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +0 -10
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-one.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-composed-two.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-mixed-index.ts.txt +0 -14
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-runtime-registry.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +0 -2
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +0 -8
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +0 -15
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +0 -9
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-kebab-operation-id.ts.txt +0 -17
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +0 -5
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +0 -24
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +0 -16
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-snake-operation-id.ts.txt +0 -21
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +0 -3
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +0 -18
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +0 -13
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +0 -31
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +0 -21
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +0 -14
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-en.json +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ja.json +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-canonical-ko.json +0 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/locale-existing-operation-namespace-en.json +0 -8
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +0 -6
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-binding-ambiguous.ts.txt +0 -12
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported-other.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-imported.ts.txt +0 -5
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-key-ambiguous.ts.txt +0 -19
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-shorthand.ts.txt +0 -9
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-typed.ts.txt +0 -11
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/registry-unrelated.ts.txt +0 -13
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +0 -7
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +0 -15
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +0 -4
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +0 -12
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `apifuse migrate-deployment [path] [--check] [--json] [--drop-codeowners-lock]`
|
|
5
|
+
*
|
|
6
|
+
* Retires a provider repository's standalone `deploy.ts`. Deployment intent
|
|
7
|
+
* has one home — the `deployment` key on `defineProvider({...})` — and only
|
|
8
|
+
* the fields that differ from the runtime profile are written there. The
|
|
9
|
+
* command:
|
|
10
|
+
*
|
|
11
|
+
* 1. reads `deploy.ts`, subtracts the profile defaults, and proves the
|
|
12
|
+
* resulting key resolves to exactly what the file declared;
|
|
13
|
+
* 2. writes the key into the declaration literal (after `runtime`), removes
|
|
14
|
+
* a `deployment` extra from a `{ ...provider, deployment }` default export
|
|
15
|
+
* and any `import ... from "./deploy"`;
|
|
16
|
+
* 3. deletes `deploy.ts` — after checking that no other repository source
|
|
17
|
+
* (tests included) imports the module. The `.github/CODEOWNERS`
|
|
18
|
+
* `/deploy.ts` lock stays unless `--drop-codeowners-lock` is passed: the
|
|
19
|
+
* platform still honors a re-added legacy file until its fallback is
|
|
20
|
+
* retired.
|
|
21
|
+
*
|
|
22
|
+
* Exit codes: 0 migrated or already migrated; 1 refused (the transform does
|
|
23
|
+
* not guess — a refusal names the manual step) or missing index.ts.
|
|
24
|
+
* `--check` reports without writing.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
28
|
+
import { join, relative, resolve } from "node:path";
|
|
29
|
+
|
|
30
|
+
import type * as MigrateModule from "../src/cli/migrate-deployment-intent.js";
|
|
31
|
+
|
|
32
|
+
/** Directories never scanned for deploy-module consumers. */
|
|
33
|
+
const SKIPPED_DIRECTORIES = new Set([
|
|
34
|
+
"node_modules",
|
|
35
|
+
".git",
|
|
36
|
+
"dist",
|
|
37
|
+
"build",
|
|
38
|
+
"coverage",
|
|
39
|
+
".turbo",
|
|
40
|
+
"__generated__",
|
|
41
|
+
]);
|
|
42
|
+
const SOURCE_FILE = /\.(?:[cm]?[jt]s|[jt]sx)$/u;
|
|
43
|
+
|
|
44
|
+
export const LEGACY_DEPLOY_FILE = "deploy.ts";
|
|
45
|
+
export const CODEOWNERS_FILE = ".github/CODEOWNERS";
|
|
46
|
+
|
|
47
|
+
export async function main(): Promise<void> {
|
|
48
|
+
// The transform needs the TypeScript compiler; load it here so a missing
|
|
49
|
+
// devDependency is a one-line report instead of an import stack trace.
|
|
50
|
+
let migrateDeploymentIntent: typeof MigrateModule.migrateDeploymentIntent;
|
|
51
|
+
let findDeployModuleConsumers: typeof MigrateModule.findDeployModuleConsumers;
|
|
52
|
+
try {
|
|
53
|
+
({ migrateDeploymentIntent, findDeployModuleConsumers } = await import(
|
|
54
|
+
"../src/cli/migrate-deployment-intent.js"
|
|
55
|
+
));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
const args = normalizeArgs(process.argv.slice(2));
|
|
61
|
+
const check = args.includes("--check");
|
|
62
|
+
const json = args.includes("--json");
|
|
63
|
+
const dropCodeownersLock = args.includes("--drop-codeowners-lock");
|
|
64
|
+
const positional = args.filter((argument) => !argument.startsWith("--"));
|
|
65
|
+
const providerRoot = resolve(positional[0] ?? ".");
|
|
66
|
+
const indexPath = resolve(providerRoot, "index.ts");
|
|
67
|
+
const deployPath = resolve(providerRoot, LEGACY_DEPLOY_FILE);
|
|
68
|
+
const codeownersPath = resolve(providerRoot, CODEOWNERS_FILE);
|
|
69
|
+
|
|
70
|
+
const report = (payload: Record<string, unknown>, humanText: string): void => {
|
|
71
|
+
if (json) {
|
|
72
|
+
console.log(JSON.stringify({ schemaVersion: 1, providerRoot, ...payload }));
|
|
73
|
+
} else {
|
|
74
|
+
console.log(humanText);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if (!existsSync(indexPath)) {
|
|
79
|
+
report(
|
|
80
|
+
{ status: "refused", reason: "index.ts not found" },
|
|
81
|
+
`migrate-deployment: ${indexPath} not found.`,
|
|
82
|
+
);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const deploySource = existsSync(deployPath) ? readFileSync(deployPath, "utf8") : undefined;
|
|
87
|
+
const codeownersSource = existsSync(codeownersPath)
|
|
88
|
+
? readFileSync(codeownersPath, "utf8")
|
|
89
|
+
: undefined;
|
|
90
|
+
const result = migrateDeploymentIntent({
|
|
91
|
+
indexSource: readFileSync(indexPath, "utf8"),
|
|
92
|
+
deploySource,
|
|
93
|
+
codeownersSource,
|
|
94
|
+
dropCodeownersLock,
|
|
95
|
+
indexFileName: indexPath,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (result.status === "refused") {
|
|
99
|
+
report(
|
|
100
|
+
{ status: "refused", reason: result.reason },
|
|
101
|
+
`migrate-deployment: refused — ${result.reason}\nThis provider needs a manual migration; do not delete deploy.ts without one.`,
|
|
102
|
+
);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (result.status === "unchanged") {
|
|
107
|
+
report(
|
|
108
|
+
{ status: "unchanged", notes: result.notes },
|
|
109
|
+
`migrate-deployment: already migrated; nothing to do.${formatNotes(result.notes)}`,
|
|
110
|
+
);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (result.removeDeployFile) {
|
|
115
|
+
// index.ts is accounted for by the transform; any other source that
|
|
116
|
+
// imports the module (a test, a helper) would break when it is deleted.
|
|
117
|
+
const consumers = findDeployModuleConsumers(
|
|
118
|
+
providerRoot,
|
|
119
|
+
collectOtherSources(providerRoot, [indexPath, deployPath]),
|
|
120
|
+
);
|
|
121
|
+
if (consumers.length > 0) {
|
|
122
|
+
const reason = `deploy.ts is still imported by ${consumers.join(", ")}; remove or rewrite those imports before migrating.`;
|
|
123
|
+
report(
|
|
124
|
+
{ status: "refused", reason },
|
|
125
|
+
`migrate-deployment: refused — ${reason}\nThis provider needs a manual migration; do not delete deploy.ts without one.`,
|
|
126
|
+
);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const touchedPaths: string[] = [];
|
|
132
|
+
if (result.indexChanged) touchedPaths.push("index.ts");
|
|
133
|
+
if (result.removeDeployFile) touchedPaths.push(LEGACY_DEPLOY_FILE);
|
|
134
|
+
if (result.codeownersChanged) touchedPaths.push(CODEOWNERS_FILE);
|
|
135
|
+
const payload = {
|
|
136
|
+
shape: result.shape,
|
|
137
|
+
legacy: result.legacy,
|
|
138
|
+
intent: result.intent,
|
|
139
|
+
resolved: result.resolved,
|
|
140
|
+
resolvedEqual: result.legacy === undefined ? undefined : true,
|
|
141
|
+
touchedPaths,
|
|
142
|
+
notes: result.notes,
|
|
143
|
+
};
|
|
144
|
+
const intentSummary =
|
|
145
|
+
Object.keys(result.intent).length === 0
|
|
146
|
+
? "profile defaults (no deployment key)"
|
|
147
|
+
: `deployment: ${JSON.stringify(result.intent)}`;
|
|
148
|
+
|
|
149
|
+
if (check) {
|
|
150
|
+
report(
|
|
151
|
+
{ status: "would-migrate", ...payload },
|
|
152
|
+
`migrate-deployment: would migrate (${intentSummary}; touches ${touchedPaths.join(", ")}). Run without --check to write.${formatNotes(result.notes)}`,
|
|
153
|
+
);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (result.indexChanged) writeFileSync(indexPath, result.indexSource, "utf8");
|
|
158
|
+
if (result.codeownersChanged && result.codeownersSource !== undefined) {
|
|
159
|
+
writeFileSync(codeownersPath, result.codeownersSource, "utf8");
|
|
160
|
+
}
|
|
161
|
+
if (result.removeDeployFile) rmSync(deployPath, { force: true });
|
|
162
|
+
report(
|
|
163
|
+
{ status: "migrated", ...payload },
|
|
164
|
+
`migrate-deployment: migrated (${intentSummary}; touched ${touchedPaths.join(", ")}). Review the diff, then run \`apifuse check\` and \`bun run type-check\`.${formatNotes(result.notes)}`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function normalizeArgs(argv: string[]): string[] {
|
|
169
|
+
return argv[0] === "migrate-deployment" ? argv.slice(1) : argv;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Every source file under `providerRoot` except `excluded`, with text. */
|
|
173
|
+
function collectOtherSources(
|
|
174
|
+
providerRoot: string,
|
|
175
|
+
excluded: readonly string[],
|
|
176
|
+
): { readonly path: string; readonly text: string }[] {
|
|
177
|
+
const skip = new Set(excluded.map((file) => resolve(file)));
|
|
178
|
+
const files: { readonly path: string; readonly text: string }[] = [];
|
|
179
|
+
const walk = (directory: string): void => {
|
|
180
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
181
|
+
const absolute = join(directory, entry.name);
|
|
182
|
+
if (entry.isDirectory()) {
|
|
183
|
+
if (!SKIPPED_DIRECTORIES.has(entry.name)) walk(absolute);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (!entry.isFile() || !SOURCE_FILE.test(entry.name) || skip.has(resolve(absolute))) continue;
|
|
187
|
+
files.push({ path: relative(providerRoot, absolute), text: readFileSync(absolute, "utf8") });
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
walk(providerRoot);
|
|
191
|
+
return files;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function formatNotes(notes: readonly string[]): string {
|
|
195
|
+
return notes.length === 0 ? "" : `\n${notes.map((note) => ` - ${note}`).join("\n")}`;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (import.meta.main) {
|
|
199
|
+
await main();
|
|
200
|
+
}
|
|
@@ -82,11 +82,18 @@ const requiredPaths = [
|
|
|
82
82
|
"dist/auth-turn/fixtures/invalid/unknown-top-level-field.json",
|
|
83
83
|
"src/auth-turn/auth-turn.v1.schema.json",
|
|
84
84
|
];
|
|
85
|
+
// Test material must never reach the published tarball: it carries no consumer
|
|
86
|
+
// value and the `.deploy.ts.txt` codemod fixtures describe internal provider
|
|
87
|
+
// deployment intent. The `files` negations in package.json do the excluding;
|
|
88
|
+
// these patterns are the ratchet that fails the build when a new test directory
|
|
89
|
+
// escapes them (top-level negations do not cover nested `__tests__`).
|
|
90
|
+
const isPackagedTestMaterial = (path: string): boolean =>
|
|
91
|
+
path.startsWith("__tests__/") ||
|
|
92
|
+
path.includes("/__tests__/") ||
|
|
93
|
+
path.endsWith(".test.ts") ||
|
|
94
|
+
path.endsWith(".spec.ts");
|
|
85
95
|
const forbiddenMatches = filePaths.filter(
|
|
86
|
-
(path) =>
|
|
87
|
-
path.startsWith("src/__tests__/") ||
|
|
88
|
-
path === "src/index.test.ts" ||
|
|
89
|
-
path === "bin/apifuse-init.ts",
|
|
96
|
+
(path) => isPackagedTestMaterial(path) || path === "bin/apifuse-init.ts",
|
|
90
97
|
);
|
|
91
98
|
const missingRequiredPaths = requiredPaths.filter(
|
|
92
99
|
(path) => !filePaths.includes(path),
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
// type errors, so this check cannot rot into a false-positive green.
|
|
23
23
|
|
|
24
24
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
25
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
26
26
|
import { tmpdir } from "node:os";
|
|
27
27
|
import { join, resolve } from "node:path";
|
|
28
28
|
import { z } from "zod";
|
|
@@ -293,14 +293,14 @@ const NEGATIVE_CONTROLS = [
|
|
|
293
293
|
].join("\n"),
|
|
294
294
|
},
|
|
295
295
|
{
|
|
296
|
-
filename: "negative-control-telemetry-
|
|
296
|
+
filename: "negative-control-proxy-telemetry-vendor.ts",
|
|
297
297
|
expectedCode: "TS2322",
|
|
298
|
-
description: "gateway telemetry
|
|
298
|
+
description: "proxy gateway telemetry rejects an unbranded vendor string",
|
|
299
299
|
source: [
|
|
300
300
|
'import type { TelemetryContributor } from "@apifuse/provider-sdk";',
|
|
301
301
|
"",
|
|
302
302
|
"const bad: TelemetryContributor<{}, { vendor: string }> = {",
|
|
303
|
-
'\tkey: "
|
|
303
|
+
'\tkey: "proxy",',
|
|
304
304
|
"\ttoLogPayload: () => ({}),",
|
|
305
305
|
'\ttoHeaderPayload: () => ({ vendor: "free-text" }),',
|
|
306
306
|
"};",
|
|
@@ -472,8 +472,195 @@ const NEGATIVE_CONTROLS = [
|
|
|
472
472
|
"export const ingestible: GatewayIngestible<NativeTelemetryHeaderPayload> = header;",
|
|
473
473
|
].join("\n"),
|
|
474
474
|
},
|
|
475
|
+
{
|
|
476
|
+
filename: "negative-control-http-telemetry-free-text.ts",
|
|
477
|
+
expectedCode: "TS2322",
|
|
478
|
+
description: "HTTP gateway telemetry rejects a free-string diagnostic field",
|
|
479
|
+
source: [
|
|
480
|
+
'import type { HttpTelemetryHeaderPayload, GatewayIngestible } from "@apifuse/provider-sdk";',
|
|
481
|
+
"type UnsafeHttpHeader = HttpTelemetryHeaderPayload & { message: string };",
|
|
482
|
+
"declare const header: HttpTelemetryHeaderPayload;",
|
|
483
|
+
'export const mustNotCompile: GatewayIngestible<UnsafeHttpHeader> = { ...header, message: "upstream free text" };',
|
|
484
|
+
"",
|
|
485
|
+
].join("\n"),
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
filename: "positive-control-http-telemetry-contributor.ts",
|
|
489
|
+
expectedCode: "",
|
|
490
|
+
description: "HTTP contributor satisfies the gateway and tenant projection contracts",
|
|
491
|
+
source: [
|
|
492
|
+
'import { HttpTelemetryCollector, type HttpTelemetryHeaderPayload, type HttpTelemetryLogPayload, type HttpTelemetryRetryPayload, type GatewayIngestible, type TenantNeutral, type TelemetryContributor } from "@apifuse/provider-sdk";',
|
|
493
|
+
'import { HttpTelemetryCollector as ServerHttpCollector } from "@apifuse/provider-sdk/server";',
|
|
494
|
+
"export const http: TelemetryContributor<HttpTelemetryLogPayload, HttpTelemetryHeaderPayload> = new HttpTelemetryCollector();",
|
|
495
|
+
"declare const header: HttpTelemetryHeaderPayload;",
|
|
496
|
+
"export const ingestible: GatewayIngestible<HttpTelemetryHeaderPayload> = header;",
|
|
497
|
+
"export const retry: TenantNeutral<HttpTelemetryRetryPayload> | undefined = new ServerHttpCollector().toTenantRetryPayload();",
|
|
498
|
+
"",
|
|
499
|
+
].join("\n"),
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
filename: "negative-control-stealth-telemetry-diagnostics.ts",
|
|
503
|
+
expectedCode: "TS2322",
|
|
504
|
+
description: "stealth gateway telemetry rejects a free-string header field",
|
|
505
|
+
source: [
|
|
506
|
+
'import { type GatewayIngestible, type StealthTelemetryHeaderPayload } from "@apifuse/provider-sdk";',
|
|
507
|
+
"type UnsafeHeader = StealthTelemetryHeaderPayload & { diagnostics: string };",
|
|
508
|
+
"declare const unsafeHeader: UnsafeHeader;",
|
|
509
|
+
"export const mustNotCompile: GatewayIngestible<UnsafeHeader> = unsafeHeader;",
|
|
510
|
+
"",
|
|
511
|
+
].join("\n"),
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
filename: "positive-control-stealth-telemetry-contributor.ts",
|
|
515
|
+
expectedCode: "",
|
|
516
|
+
description: "stealth telemetry contributor satisfies the gateway-ingestible contract",
|
|
517
|
+
source: [
|
|
518
|
+
'import { StealthTelemetryCollector, type GatewayIngestible, type StealthTelemetryHeaderPayload, type StealthTelemetryLogPayload, type TelemetryContributor } from "@apifuse/provider-sdk";',
|
|
519
|
+
"",
|
|
520
|
+
"export const stealth: TelemetryContributor<StealthTelemetryLogPayload, StealthTelemetryHeaderPayload> = new StealthTelemetryCollector();",
|
|
521
|
+
"declare const header: StealthTelemetryHeaderPayload;",
|
|
522
|
+
"export const ingestible: GatewayIngestible<StealthTelemetryHeaderPayload> = header;",
|
|
523
|
+
"",
|
|
524
|
+
].join("\n"),
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
filename: "negative-control-ocr-telemetry-free-text.ts",
|
|
528
|
+
expectedCode: "TS2322",
|
|
529
|
+
description: "ocr gateway telemetry rejects a free-string field",
|
|
530
|
+
source: [
|
|
531
|
+
'import type { GatewayIngestible, OcrTelemetryHeaderPayload } from "@apifuse/provider-sdk";',
|
|
532
|
+
"type Unsafe = OcrTelemetryHeaderPayload & { message: string };",
|
|
533
|
+
"declare const value: Unsafe;",
|
|
534
|
+
"export const bad: GatewayIngestible<Unsafe> = value;",
|
|
535
|
+
].join("\n"),
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
filename: "positive-control-ocr-telemetry-contributor.ts",
|
|
539
|
+
expectedCode: "",
|
|
540
|
+
description: "ocr telemetry contributor satisfies the gateway-ingestible contract",
|
|
541
|
+
source: [
|
|
542
|
+
'import { OcrTelemetryCollector, type TelemetryContributor, type OcrTelemetryLogPayload, type OcrTelemetryHeaderPayload } from "@apifuse/provider-sdk";',
|
|
543
|
+
"export const ocr: TelemetryContributor<OcrTelemetryLogPayload, OcrTelemetryHeaderPayload> = new OcrTelemetryCollector();",
|
|
544
|
+
].join("\n"),
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
filename: "negative-control-stt-telemetry-free-text.ts",
|
|
548
|
+
expectedCode: "TS2322",
|
|
549
|
+
description: "stt gateway telemetry rejects a free-string field",
|
|
550
|
+
source: [
|
|
551
|
+
'import type { GatewayIngestible, SttTelemetryHeaderPayload } from "@apifuse/provider-sdk";',
|
|
552
|
+
"type Unsafe = SttTelemetryHeaderPayload & { message: string };",
|
|
553
|
+
"declare const value: Unsafe;",
|
|
554
|
+
"export const bad: GatewayIngestible<Unsafe> = value;",
|
|
555
|
+
].join("\n"),
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
filename: "positive-control-stt-telemetry-contributor.ts",
|
|
559
|
+
expectedCode: "",
|
|
560
|
+
description: "stt telemetry contributor satisfies the gateway-ingestible contract",
|
|
561
|
+
source: [
|
|
562
|
+
'import { SttTelemetryCollector, type TelemetryContributor, type SttTelemetryLogPayload, type SttTelemetryHeaderPayload } from "@apifuse/provider-sdk";',
|
|
563
|
+
"export const stt: TelemetryContributor<SttTelemetryLogPayload, SttTelemetryHeaderPayload> = new SttTelemetryCollector();",
|
|
564
|
+
].join("\n"),
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
filename: "negative-control-browser-telemetry-free-text.ts",
|
|
568
|
+
expectedCode: "TS2322",
|
|
569
|
+
description: "browser gateway telemetry rejects a free-string field",
|
|
570
|
+
source: [
|
|
571
|
+
'import type { BrowserTelemetryHeaderPayload, GatewayIngestible } from "@apifuse/provider-sdk";',
|
|
572
|
+
"declare const header: BrowserTelemetryHeaderPayload;",
|
|
573
|
+
"type Unsafe = BrowserTelemetryHeaderPayload & { message: string };",
|
|
574
|
+
'export const bad: GatewayIngestible<Unsafe> = { ...header, message: "free text" };',
|
|
575
|
+
].join("\n"),
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
filename: "positive-control-browser-telemetry-contributor.ts",
|
|
579
|
+
expectedCode: "",
|
|
580
|
+
description: "browser telemetry contributor satisfies the gateway-ingestible contract",
|
|
581
|
+
source: [
|
|
582
|
+
'import { BrowserTelemetryCollector, type BrowserTelemetryHeaderPayload, type BrowserTelemetryLogPayload, type TelemetryContributor } from "@apifuse/provider-sdk";',
|
|
583
|
+
"export const browser: TelemetryContributor<BrowserTelemetryLogPayload, BrowserTelemetryHeaderPayload> = new BrowserTelemetryCollector();",
|
|
584
|
+
].join("\n"),
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
filename: "negative-control-cache-telemetry-free-text.ts",
|
|
588
|
+
expectedCode: "TS2322",
|
|
589
|
+
description: "cache gateway telemetry rejects raw cache-key samples",
|
|
590
|
+
source: [
|
|
591
|
+
'import type { TelemetryContributor } from "@apifuse/provider-sdk";',
|
|
592
|
+
"const bad: TelemetryContributor<{}, { key: string }> = {",
|
|
593
|
+
'\tkey: "cache",',
|
|
594
|
+
"\ttoLogPayload: () => ({}),",
|
|
595
|
+
'\ttoHeaderPayload: () => ({ key: "raw" }),',
|
|
596
|
+
"};",
|
|
597
|
+
].join("\n"),
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
filename: "positive-control-cache-telemetry-contributor.ts",
|
|
601
|
+
expectedCode: "",
|
|
602
|
+
description: "cache telemetry contributor satisfies the public contributor contract",
|
|
603
|
+
source: [
|
|
604
|
+
'import { CacheTelemetryCollector, type TelemetryContributor, type CacheTelemetryHeaderPayload, type CacheTelemetryLogPayload } from "@apifuse/provider-sdk";',
|
|
605
|
+
"export const cache: TelemetryContributor<CacheTelemetryLogPayload, CacheTelemetryHeaderPayload> = new CacheTelemetryCollector();",
|
|
606
|
+
].join("\n"),
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
filename: "negative-control-state-telemetry-free-text.ts",
|
|
610
|
+
expectedCode: "TS2322",
|
|
611
|
+
description: "state gateway telemetry rejects raw state-key samples",
|
|
612
|
+
source: [
|
|
613
|
+
'import type { TelemetryContributor } from "@apifuse/provider-sdk";',
|
|
614
|
+
"const bad: TelemetryContributor<{}, { key: string }> = {",
|
|
615
|
+
'\tkey: "state",',
|
|
616
|
+
"\ttoLogPayload: () => ({}),",
|
|
617
|
+
'\ttoHeaderPayload: () => ({ key: "raw" }),',
|
|
618
|
+
"};",
|
|
619
|
+
].join("\n"),
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
filename: "positive-control-state-telemetry-contributor.ts",
|
|
623
|
+
expectedCode: "",
|
|
624
|
+
description: "state telemetry contributor satisfies the public contributor contract",
|
|
625
|
+
source: [
|
|
626
|
+
'import { StateTelemetryCollector, type TelemetryContributor, type StateTelemetryHeaderPayload, type StateTelemetryLogPayload } from "@apifuse/provider-sdk";',
|
|
627
|
+
"export const state: TelemetryContributor<StateTelemetryLogPayload, StateTelemetryHeaderPayload> = new StateTelemetryCollector();",
|
|
628
|
+
].join("\n"),
|
|
629
|
+
},
|
|
475
630
|
] as const;
|
|
476
631
|
|
|
632
|
+
assertTelemetryContributorControls();
|
|
633
|
+
|
|
634
|
+
function assertTelemetryContributorControls(): void {
|
|
635
|
+
const requestTelemetry = readFileSync(join(sdkRoot, "src/runtime/request-telemetry.ts"), "utf8");
|
|
636
|
+
const priorityMatch = requestTelemetry.match(
|
|
637
|
+
/const HEADER_PRIORITY = \[([\s\S]*?)\] as const satisfies/,
|
|
638
|
+
);
|
|
639
|
+
if (!priorityMatch) throw new Error("Could not read request telemetry header priority list");
|
|
640
|
+
|
|
641
|
+
const priority = [...priorityMatch[1].matchAll(/"([a-z]+)"/g)].map((match) => match[1]);
|
|
642
|
+
const shipped = priority.filter((name) =>
|
|
643
|
+
existsSync(join(sdkRoot, "src/runtime", `${name}-telemetry.ts`)),
|
|
644
|
+
);
|
|
645
|
+
const missing: string[] = [];
|
|
646
|
+
for (const name of shipped) {
|
|
647
|
+
const hasPositive = NEGATIVE_CONTROLS.some(
|
|
648
|
+
({ filename }) => filename === `positive-control-${name}-telemetry-contributor.ts`,
|
|
649
|
+
);
|
|
650
|
+
const hasNegative = NEGATIVE_CONTROLS.some(({ filename }) =>
|
|
651
|
+
filename.startsWith(`negative-control-${name}-telemetry-`),
|
|
652
|
+
);
|
|
653
|
+
if (!hasNegative || !hasPositive) {
|
|
654
|
+
missing.push(
|
|
655
|
+
`${name} (${hasNegative ? "negative" : "missing negative"}, ${hasPositive ? "positive" : "missing positive"})`,
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (missing.length > 0) {
|
|
660
|
+
throw new Error(`Missing telemetry contributor pack controls: ${missing.join(", ")}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
477
664
|
const tempRoot = mkdtempSync(join(tmpdir(), "apifuse-provider-sdk-pack-types-"));
|
|
478
665
|
const packDir = join(tempRoot, "pack");
|
|
479
666
|
const consumerDir = join(tempRoot, "consumer");
|
package/bin/apifuse-record.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
createHandleContext,
|
|
15
15
|
createProviderEnvironment,
|
|
16
16
|
createSttClientFromEnv,
|
|
17
|
-
createUnsupportedResolverClient,
|
|
18
17
|
executeOperation,
|
|
19
18
|
type HttpClient,
|
|
20
19
|
type HttpResponse,
|
|
@@ -23,13 +22,13 @@ import {
|
|
|
23
22
|
type ProviderDefinition,
|
|
24
23
|
type ProviderEngineBindingCandidates,
|
|
25
24
|
ProviderError,
|
|
26
|
-
readEngineProxyCredentials,
|
|
27
|
-
type ProviderProxyPolicy,
|
|
28
25
|
type RequestOptions,
|
|
29
26
|
type StealthClient,
|
|
30
27
|
TransportError,
|
|
31
28
|
ValidationError,
|
|
32
29
|
} from "../src/index.js";
|
|
30
|
+
import { createCliResolverRuntime } from "../src/cli/resolver-runtime.js";
|
|
31
|
+
import { assertProcessEngineModeSupported } from "../src/runtime/engine-mode.js";
|
|
33
32
|
import type { JsonValue } from "../src/contract-json.js";
|
|
34
33
|
import {
|
|
35
34
|
isSensitiveFixtureKey,
|
|
@@ -37,7 +36,6 @@ import {
|
|
|
37
36
|
sanitizeDiagnosticText,
|
|
38
37
|
sanitizeFixtureString,
|
|
39
38
|
} from "../src/fixture-sanitization.js";
|
|
40
|
-
import { createResolverClientFromEnv } from "../src/runtime/resolver.js";
|
|
41
39
|
import {
|
|
42
40
|
isSensitiveKey,
|
|
43
41
|
normalizeSensitiveParams,
|
|
@@ -50,10 +48,10 @@ import {
|
|
|
50
48
|
requestOptionsFromHttpInvocation,
|
|
51
49
|
serializeRequestUrl,
|
|
52
50
|
} from "../src/runtime/request-options.js";
|
|
51
|
+
import type { ResolverTelemetryCollector } from "../src/runtime/resolver-telemetry.js";
|
|
53
52
|
import { createMemoryProviderRuntimeState } from "../src/runtime/state.js";
|
|
54
53
|
import { createStealthClient } from "../src/runtime/stealth.js";
|
|
55
54
|
import { parseSchema } from "../src/schema.js";
|
|
56
|
-
import { getStealthProfile } from "../src/stealth/profiles.js";
|
|
57
55
|
import {
|
|
58
56
|
captureStreamEvidence,
|
|
59
57
|
createStreamCaptureEnvelope,
|
|
@@ -107,6 +105,8 @@ export async function main() {
|
|
|
107
105
|
const args = parseArgs(normalizeArgs(process.argv.slice(2)));
|
|
108
106
|
const location = resolveProviderLocation(args.providerPath);
|
|
109
107
|
const provider = await loadProvider(location.rootDir);
|
|
108
|
+
// The capture context attaches in-process; refuse an explicit remote request instead of ignoring it.
|
|
109
|
+
assertProcessEngineModeSupported();
|
|
110
110
|
const operationName = resolveOperationName(provider, args.operation);
|
|
111
111
|
const operation = provider.operations[operationName];
|
|
112
112
|
const parsedParams = await parseParams(operation, args.params);
|
|
@@ -140,6 +140,12 @@ export async function main() {
|
|
|
140
140
|
);
|
|
141
141
|
}
|
|
142
142
|
throw operationError;
|
|
143
|
+
} finally {
|
|
144
|
+
const telemetryLine = formatResolverTelemetry(
|
|
145
|
+
capture.resolverTelemetry,
|
|
146
|
+
capture.getCapturedSensitiveParams().values,
|
|
147
|
+
);
|
|
148
|
+
if (telemetryLine) console.log(telemetryLine);
|
|
143
149
|
}
|
|
144
150
|
const captured = await capture.getCapturedRaw();
|
|
145
151
|
|
|
@@ -256,6 +262,25 @@ function parseArgs(argv: string[]): CliArgs {
|
|
|
256
262
|
return { append, providerPath, operation, params, sanitize };
|
|
257
263
|
}
|
|
258
264
|
|
|
265
|
+
/**
|
|
266
|
+
* The `resolver` sibling of the server request log, printed once per recorded invocation. The
|
|
267
|
+
* collector redacts at record time with the values registered so far; the mandatory query-secret
|
|
268
|
+
* pass over the final line also covers values captured after a solve and short low-entropy values
|
|
269
|
+
* the diagnostic redactor does not match, the same way handleCliError treats CLI errors.
|
|
270
|
+
*/
|
|
271
|
+
export function formatResolverTelemetry(
|
|
272
|
+
collector: ResolverTelemetryCollector,
|
|
273
|
+
sensitiveValues: readonly string[] = [],
|
|
274
|
+
): string | undefined {
|
|
275
|
+
const resolver = collector.toLogPayload();
|
|
276
|
+
return resolver
|
|
277
|
+
? `[apifuse record] Resolver telemetry ${redactSensitiveText(
|
|
278
|
+
JSON.stringify({ resolver }),
|
|
279
|
+
sensitiveValues,
|
|
280
|
+
)}`
|
|
281
|
+
: undefined;
|
|
282
|
+
}
|
|
283
|
+
|
|
259
284
|
function handleCliError(error: unknown, sensitiveValues: readonly string[] = []): never {
|
|
260
285
|
const message = redactSensitiveText(formatCliError(error), sensitiveValues);
|
|
261
286
|
console.error(`[apifuse record] ${message}`);
|
|
@@ -430,13 +455,6 @@ function resolveOperationBaseUrl(provider: ProviderRuntime, operationName: strin
|
|
|
430
455
|
return baseUrl;
|
|
431
456
|
}
|
|
432
457
|
|
|
433
|
-
function resolveNativeProxyPolicy(provider: ProviderDefinition): ProviderProxyPolicy | undefined {
|
|
434
|
-
if (typeof provider.proxy === "object") return provider.proxy;
|
|
435
|
-
if (provider.proxy === true) return { mode: "optional" };
|
|
436
|
-
if (provider.proxy === false) return { mode: "disabled" };
|
|
437
|
-
return undefined;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
458
|
export function createCaptureContext(
|
|
441
459
|
provider: ProviderRuntime,
|
|
442
460
|
baseUrl: string,
|
|
@@ -454,8 +472,19 @@ export function createCaptureContext(
|
|
|
454
472
|
let capturedSse: { order: number; method: string; path: string } | undefined;
|
|
455
473
|
const sensitiveParamNames = new Set<string>();
|
|
456
474
|
const sensitiveParamValues = new Set<string>();
|
|
475
|
+
const cache = createBypassProviderCache({ providerId: provider.id });
|
|
476
|
+
const { resolver, resolverTelemetry, registerSensitiveValues } = createCliResolverRuntime(
|
|
477
|
+
provider,
|
|
478
|
+
cache,
|
|
479
|
+
);
|
|
457
480
|
const captureSensitiveParams = (url: string, options?: SensitiveRequestOptions) => {
|
|
458
|
-
|
|
481
|
+
try {
|
|
482
|
+
captureSensitiveRequestValues(url, options, sensitiveParamNames, sensitiveParamValues);
|
|
483
|
+
} finally {
|
|
484
|
+
// Resolver telemetry redacts at record time, so the vendor diagnostics of a later solve
|
|
485
|
+
// must not echo a query secret captured here (same guarantee as handleCliError).
|
|
486
|
+
registerSensitiveValues([...sensitiveParamValues]);
|
|
487
|
+
}
|
|
459
488
|
};
|
|
460
489
|
const getCapturedSensitiveParams = (): CapturedSensitiveParams => ({
|
|
461
490
|
names: [...sensitiveParamNames],
|
|
@@ -521,7 +550,6 @@ export function createCaptureContext(
|
|
|
521
550
|
provider.secrets?.map((secret) => secret.name) ?? [],
|
|
522
551
|
);
|
|
523
552
|
const env = { get: (key: string) => readDiagnosticEnv(key, providerEnvironment) };
|
|
524
|
-
const engineCredentials = readEngineProxyCredentials();
|
|
525
553
|
const credential = {
|
|
526
554
|
mode: "none" as const,
|
|
527
555
|
get: () => undefined,
|
|
@@ -530,9 +558,6 @@ export function createCaptureContext(
|
|
|
530
558
|
getScopes: () => [],
|
|
531
559
|
};
|
|
532
560
|
const state = createMemoryProviderRuntimeState();
|
|
533
|
-
const cache = createBypassProviderCache({ providerId: provider.id });
|
|
534
|
-
const proxyPolicy = resolveNativeProxyPolicy(provider);
|
|
535
|
-
const stealthProfile = provider.stealth ? getStealthProfile(provider.stealth) : undefined;
|
|
536
561
|
const candidates: ProviderEngineBindingCandidates = {
|
|
537
562
|
env,
|
|
538
563
|
credential,
|
|
@@ -567,21 +592,7 @@ export function createCaptureContext(
|
|
|
567
592
|
},
|
|
568
593
|
ocr: createOcrClientFromEnv(provider.ocr),
|
|
569
594
|
stt: createSttClientFromEnv(provider.stt),
|
|
570
|
-
resolver
|
|
571
|
-
? createResolverClientFromEnv(provider.resolver, engineCredentials, {
|
|
572
|
-
allowedHosts: provider.allowedHosts,
|
|
573
|
-
cache,
|
|
574
|
-
...(proxyPolicy
|
|
575
|
-
? {
|
|
576
|
-
proxyIntent: {
|
|
577
|
-
mode: proxyPolicy.mode,
|
|
578
|
-
upstream: { proxy: provider.proxy },
|
|
579
|
-
...(stealthProfile ? { userAgent: stealthProfile.userAgent } : {}),
|
|
580
|
-
},
|
|
581
|
-
}
|
|
582
|
-
: {}),
|
|
583
|
-
})
|
|
584
|
-
: createUnsupportedResolverClient("Provider does not declare resolver capability"),
|
|
595
|
+
resolver,
|
|
585
596
|
handle: createHandleContext({
|
|
586
597
|
providerId: provider.id,
|
|
587
598
|
request: { headers: {}, connectionId: "local-record" },
|
|
@@ -595,6 +606,7 @@ export function createCaptureContext(
|
|
|
595
606
|
|
|
596
607
|
return {
|
|
597
608
|
ctx,
|
|
609
|
+
resolverTelemetry,
|
|
598
610
|
getCapturedRaw: async () => {
|
|
599
611
|
if (streamCaptures.length === 0) {
|
|
600
612
|
if (capturedSse) throw unsupportedSseCaptureError(capturedSse);
|
package/bin/apifuse-test.ts
CHANGED
package/dist/cli/commands.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ApifuseCommandName = "create" | "dev" | "check" | "sync-assets" | "migrate-shape" | "migrate-operation-declaration" | "submit-check" | "bounty-check" | "record" | "test" | "perf";
|
|
1
|
+
export type ApifuseCommandName = "create" | "dev" | "check" | "sync-assets" | "migrate-shape" | "migrate-operation-declaration" | "migrate-deployment" | "submit-check" | "bounty-check" | "record" | "test" | "perf";
|
|
2
2
|
export type ApifuseCommandManifest = {
|
|
3
3
|
name: ApifuseCommandName;
|
|
4
4
|
summary: string;
|
package/dist/cli/commands.js
CHANGED
|
@@ -47,6 +47,16 @@ export const COMMAND_MANIFEST = {
|
|
|
47
47
|
],
|
|
48
48
|
modulePath: "./apifuse-migrate-operation-declaration",
|
|
49
49
|
},
|
|
50
|
+
"migrate-deployment": {
|
|
51
|
+
name: "migrate-deployment",
|
|
52
|
+
summary: "Retire a legacy deploy.ts: hoist its non-default values into the defineProvider() deployment key and delete the file.",
|
|
53
|
+
usage: "apifuse migrate-deployment [path] [--check] [--json] [--drop-codeowners-lock]",
|
|
54
|
+
examples: [
|
|
55
|
+
"apifuse migrate-deployment .",
|
|
56
|
+
"apifuse migrate-deployment . --check --json",
|
|
57
|
+
],
|
|
58
|
+
modulePath: "./apifuse-migrate-deployment",
|
|
59
|
+
},
|
|
50
60
|
"submit-check": {
|
|
51
61
|
name: "submit-check",
|
|
52
62
|
summary: "Score provider bounty submission readiness and emit checklist evidence.",
|
|
@@ -100,6 +110,7 @@ export const COMMAND_ORDER = [
|
|
|
100
110
|
"sync-assets",
|
|
101
111
|
"migrate-shape",
|
|
102
112
|
"migrate-operation-declaration",
|
|
113
|
+
"migrate-deployment",
|
|
103
114
|
"submit-check",
|
|
104
115
|
"record",
|
|
105
116
|
"test",
|