@apifuse/provider-sdk 2.2.0-beta.5 → 2.2.0-beta.51
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 +537 -33
- package/CHANGELOG.md +205 -1
- package/README.md +83 -22
- package/SUBMISSION.md +2 -2
- package/bin/apifuse-check.ts +165 -11
- package/bin/apifuse-dev.ts +57 -13
- package/bin/apifuse-migrate-operation-declaration.ts +55 -0
- package/bin/apifuse-migrate-shape.ts +202 -0
- package/bin/apifuse-pack-check.ts +22 -2
- package/bin/apifuse-pack-smoke.ts +57 -2
- package/bin/apifuse-pack-types.ts +357 -38
- package/bin/apifuse-perf.ts +14 -13
- package/bin/apifuse-record.ts +709 -72
- package/bin/apifuse-submit-check.ts +2344 -324
- package/bin/apifuse-sync-assets.ts +117 -0
- package/bin/submit-check-delimited-text.ts +50 -0
- package/dist/auth-turn/index.d.ts +3 -3
- package/dist/auth-turn/index.js +1 -1
- package/dist/auth.d.ts +14 -0
- package/dist/auth.js +67 -0
- package/dist/ceremonies/index.d.ts +16 -0
- package/dist/ceremonies/index.js +141 -36
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +27 -0
- package/dist/cli/create.d.ts +4 -1
- package/dist/cli/create.js +42 -37
- package/dist/cli/migrate-operation-declaration.d.ts +59 -0
- package/dist/cli/migrate-operation-declaration.js +1249 -0
- package/dist/cli/migrate-operation-shape.d.ts +44 -0
- package/dist/cli/migrate-operation-shape.js +113 -0
- package/dist/cli/migrate-provider-shape.d.ts +52 -0
- package/dist/cli/migrate-provider-shape.js +578 -0
- package/dist/cli/prompt-assets.d.ts +80 -0
- package/dist/cli/prompt-assets.js +743 -0
- package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/dist/cli/templates/provider/Dockerfile.tpl +1 -1
- package/dist/cli/templates/provider/README.md.tpl +5 -5
- package/dist/cli/templates/provider/index.ts.tpl +6 -3
- package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/dist/cli/templates/provider/provider.json.tpl +6 -0
- package/dist/config/loader.d.ts +179 -16
- package/dist/config/loader.js +435 -127
- package/dist/contract-serialization.js +4 -8
- package/dist/contract-types.d.ts +12 -5
- package/dist/contract.js +24 -10
- package/dist/declaration-validation.d.ts +33 -0
- package/dist/declaration-validation.js +266 -0
- package/dist/define.d.ts +66 -29
- package/dist/define.js +778 -69
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +1 -1
- package/dist/engine.d.ts +78 -0
- package/dist/engine.js +133 -0
- package/dist/error-observability.d.ts +7 -0
- package/dist/error-observability.js +61 -0
- package/dist/error-resolution.d.ts +4 -0
- package/dist/error-resolution.js +122 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.js +40 -0
- package/dist/fixture-sanitization.d.ts +28 -0
- package/dist/fixture-sanitization.js +227 -0
- package/dist/health-scenario.d.ts +1842 -0
- package/dist/health-scenario.js +624 -0
- package/dist/index.d.ts +21 -10
- package/dist/index.js +12 -7
- package/dist/lint.d.ts +23 -11
- package/dist/lint.js +572 -69
- package/dist/native-address.d.ts +43 -0
- package/dist/native-address.js +281 -0
- package/dist/native-egress-policy.d.ts +31 -0
- package/dist/native-egress-policy.js +288 -0
- package/dist/observability.d.ts +5 -2
- package/dist/observability.js +48 -1
- package/dist/provider.d.ts +10 -2
- package/dist/provider.js +4 -1
- package/dist/runtime/auth-flow.d.ts +5 -1
- package/dist/runtime/auth-flow.js +6 -0
- package/dist/runtime/browser.d.ts +1 -0
- package/dist/runtime/browser.js +492 -49
- package/dist/runtime/cache.d.ts +1 -0
- package/dist/runtime/cache.js +169 -15
- package/dist/runtime/choice-wordlist.d.ts +9 -0
- package/dist/runtime/choice-wordlist.js +138 -0
- package/dist/runtime/choice.d.ts +13 -1
- package/dist/runtime/choice.js +490 -102
- package/dist/runtime/chrome149-header-order.d.ts +58 -0
- package/dist/runtime/chrome149-header-order.js +289 -0
- package/dist/runtime/env.js +12 -0
- package/dist/runtime/executor.d.ts +3 -2
- package/dist/runtime/executor.js +26 -25
- package/dist/runtime/http.d.ts +1 -0
- package/dist/runtime/http.js +515 -53
- package/dist/runtime/insights.js +2 -2
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +366 -8
- package/dist/runtime/native-network-errors.d.ts +33 -0
- package/dist/runtime/native-network-errors.js +69 -0
- package/dist/runtime/native-network.d.ts +96 -0
- package/dist/runtime/native-network.js +1232 -0
- package/dist/runtime/ocr.d.ts +29 -0
- package/dist/runtime/ocr.js +440 -0
- package/dist/runtime/otlp.d.ts +71 -2
- package/dist/runtime/otlp.js +397 -16
- package/dist/runtime/proxy-errors.js +6 -2
- package/dist/runtime/proxy-nodemaven.d.ts +56 -0
- package/dist/runtime/proxy-nodemaven.js +146 -0
- package/dist/runtime/proxy-telemetry.d.ts +80 -1
- package/dist/runtime/proxy-telemetry.js +154 -47
- package/dist/runtime/redirects.d.ts +29 -0
- package/dist/runtime/redirects.js +36 -0
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +4 -2
- package/dist/runtime/request-options.d.ts +68 -1
- package/dist/runtime/request-options.js +548 -0
- package/dist/runtime/resolver-config.d.ts +6 -0
- package/dist/runtime/resolver-config.js +6 -0
- package/dist/runtime/resolver-public.d.ts +1 -0
- package/dist/runtime/resolver-public.js +1 -0
- package/dist/runtime/resolver-shared.d.ts +14 -0
- package/dist/runtime/resolver-shared.js +12 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +48 -0
- package/dist/runtime/resolver-vendors/bindings.js +40 -0
- package/dist/runtime/resolver-vendors/browser.d.ts +22 -0
- package/dist/runtime/resolver-vendors/browser.js +377 -0
- package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
- package/dist/runtime/resolver-vendors/capsolver.js +531 -0
- package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
- package/dist/runtime/resolver-vendors/hosts.js +33 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
- package/dist/runtime/resolver-vendors/twocaptcha.js +408 -0
- package/dist/runtime/resolver-vendors/types.d.ts +94 -0
- package/dist/runtime/resolver-vendors/types.js +96 -0
- package/dist/runtime/resolver.d.ts +72 -0
- package/dist/runtime/resolver.js +771 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +3 -0
- package/dist/runtime/state.js +277 -71
- package/dist/runtime/stealth-cookies.d.ts +20 -0
- package/dist/runtime/stealth-cookies.js +111 -0
- package/dist/runtime/stealth.d.ts +41 -5
- package/dist/runtime/stealth.js +997 -291
- package/dist/runtime/stt.js +1 -12
- package/dist/runtime/timeout.d.ts +5 -0
- package/dist/runtime/timeout.js +12 -0
- package/dist/runtime/trace-config.d.ts +12 -0
- package/dist/runtime/trace-config.js +62 -0
- package/dist/runtime/trace.d.ts +5 -0
- package/dist/runtime/trace.js +43 -10
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/error-observability.d.ts +1 -0
- package/dist/server/error-observability.js +1 -0
- package/dist/server/index.d.ts +5 -2
- package/dist/server/index.js +2 -2
- package/dist/server/self-test-input-tokens.d.ts +2 -1
- package/dist/server/self-test-input-tokens.js +18 -14
- package/dist/server/self-test.d.ts +14 -3
- package/dist/server/self-test.js +129 -58
- package/dist/server/serve-implementation.d.ts +230 -0
- package/dist/server/serve-implementation.js +2265 -0
- package/dist/server/serve.d.ts +1 -70
- package/dist/server/serve.js +1 -1131
- package/dist/server/trace-output.d.ts +6 -0
- package/dist/server/trace-output.js +79 -0
- package/dist/server/types.d.ts +30 -5
- package/dist/server/types.js +13 -1
- package/dist/stateful/errors.d.ts +19 -0
- package/dist/stateful/errors.js +24 -0
- package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
- package/dist/stateful/http-provider-event-emitter.js +237 -0
- package/dist/stateful/http-session-owner-registry.d.ts +44 -0
- package/dist/stateful/http-session-owner-registry.js +210 -0
- package/dist/stateful/index.d.ts +18 -0
- package/dist/stateful/index.js +18 -0
- package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
- package/dist/stateful/provider-event-delivery-failures.js +43 -0
- package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
- package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
- package/dist/stateful/provider-event-pipeline.d.ts +50 -0
- package/dist/stateful/provider-event-pipeline.js +1 -0
- package/dist/stateful/provider-events.d.ts +101 -0
- package/dist/stateful/provider-events.js +289 -0
- package/dist/stateful/session-key.d.ts +15 -0
- package/dist/stateful/session-key.js +86 -0
- package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
- package/dist/stateful/stateful-provider-adapter-context.js +42 -0
- package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
- package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
- package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
- package/dist/stateful/stateful-provider-adapter.js +287 -0
- package/dist/stateful/stateful-provider-observability.d.ts +62 -0
- package/dist/stateful/stateful-provider-observability.js +161 -0
- package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
- package/dist/stateful/stateful-provider-runtime-context.js +60 -0
- package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
- package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
- package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
- package/dist/stateful/stateful-provider-session-routing.js +345 -0
- package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
- package/dist/stateful/stateful-provider-session-runtime.js +245 -0
- package/dist/stateful-signing.d.ts +18 -0
- package/dist/stateful-signing.js +27 -0
- package/dist/stealth/profiles.d.ts +9 -4
- package/dist/stealth/profiles.js +160 -211
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.js +7 -1
- package/dist/testing/index.d.ts +2 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +489 -21
- package/dist/trace-sanitization.d.ts +5 -0
- package/dist/trace-sanitization.js +45 -0
- package/dist/types.d.ts +673 -131
- package/dist/types.js +1 -0
- package/package.json +45 -5
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +118 -0
- package/src/ceremonies/index.ts +189 -46
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +10 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +8 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-hoisted-array-spread.ts.txt +15 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-imported-array-spread.ts.txt +9 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +5 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-mixed-array-spread.ts.txt +24 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +16 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +31 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +21 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +14 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +15 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +4 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +12 -0
- package/src/cli/commands.ts +33 -0
- package/src/cli/create.ts +50 -37
- package/src/cli/migrate-operation-declaration.ts +1751 -0
- package/src/cli/migrate-operation-shape.ts +184 -0
- package/src/cli/migrate-provider-shape.ts +772 -0
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/src/cli/templates/provider/Dockerfile.tpl +1 -1
- package/src/cli/templates/provider/README.md.tpl +5 -5
- package/src/cli/templates/provider/index.ts.tpl +6 -3
- package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/src/cli/templates/provider/provider.json.tpl +6 -0
- package/src/config/loader.ts +690 -163
- package/src/contract-serialization.ts +5 -7
- package/src/contract-types.ts +12 -5
- package/src/contract.ts +24 -10
- package/src/declaration-validation.ts +330 -0
- package/src/define.ts +1048 -131
- package/src/dev.ts +4 -1
- package/src/engine.ts +279 -0
- package/src/error-observability.ts +64 -0
- package/src/error-resolution.ts +127 -0
- package/src/errors.ts +68 -0
- package/src/fixture-sanitization.ts +264 -0
- package/src/health-scenario.ts +875 -0
- package/src/index.ts +220 -13
- package/src/lint.ts +698 -90
- package/src/native-address.ts +340 -0
- package/src/native-egress-policy.ts +358 -0
- package/src/observability.ts +51 -1
- package/src/provider.ts +161 -3
- package/src/runtime/auth-flow.ts +12 -0
- package/src/runtime/browser.ts +661 -63
- package/src/runtime/cache.ts +189 -14
- package/src/runtime/choice-wordlist.ts +145 -0
- package/src/runtime/choice.ts +631 -120
- package/src/runtime/chrome149-header-order.ts +330 -0
- package/src/runtime/env.ts +13 -0
- package/src/runtime/executor.ts +43 -31
- package/src/runtime/http.ts +641 -61
- package/src/runtime/insights.ts +2 -2
- package/src/runtime/instrumentation.ts +520 -15
- package/src/runtime/native-network-errors.ts +99 -0
- package/src/runtime/native-network.ts +1605 -0
- package/src/runtime/ocr.ts +523 -0
- package/src/runtime/otlp.ts +467 -21
- package/src/runtime/proxy-errors.ts +12 -4
- package/src/runtime/proxy-nodemaven.ts +221 -0
- package/src/runtime/proxy-telemetry.ts +244 -75
- package/src/runtime/redirects.ts +66 -0
- package/src/runtime/redis.ts +7 -2
- package/src/runtime/request-options.ts +680 -1
- package/src/runtime/resolver-config.ts +6 -0
- package/src/runtime/resolver-public.ts +23 -0
- package/src/runtime/resolver-shared.ts +33 -0
- package/src/runtime/resolver-vendors/bindings.ts +56 -0
- package/src/runtime/resolver-vendors/browser.ts +533 -0
- package/src/runtime/resolver-vendors/capsolver.ts +707 -0
- package/src/runtime/resolver-vendors/hosts.ts +38 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +540 -0
- package/src/runtime/resolver-vendors/types.ts +212 -0
- package/src/runtime/resolver.ts +1157 -0
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +394 -77
- package/src/runtime/stealth-cookies.ts +132 -0
- package/src/runtime/stealth.ts +1280 -336
- package/src/runtime/stt.ts +1 -19
- package/src/runtime/timeout.ts +18 -0
- package/src/runtime/trace-config.ts +78 -0
- package/src/runtime/trace.ts +57 -17
- package/src/serve.ts +6 -1
- package/src/server/error-observability.ts +1 -0
- package/src/server/index.ts +34 -2
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/server/self-test.ts +191 -68
- package/src/server/serve-implementation.ts +3378 -0
- package/src/server/serve.ts +1 -1632
- package/src/server/trace-output.ts +129 -0
- package/src/server/types.ts +13 -1
- package/src/stateful/README.md +146 -0
- package/src/stateful/errors.ts +35 -0
- package/src/stateful/http-provider-event-emitter.ts +314 -0
- package/src/stateful/http-session-owner-registry.ts +306 -0
- package/src/stateful/index.ts +18 -0
- package/src/stateful/provider-event-delivery-failures.ts +80 -0
- package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
- package/src/stateful/provider-event-pipeline.ts +61 -0
- package/src/stateful/provider-events.ts +462 -0
- package/src/stateful/session-key.ts +111 -0
- package/src/stateful/stateful-provider-adapter-context.ts +59 -0
- package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
- package/src/stateful/stateful-provider-adapter.ts +562 -0
- package/src/stateful/stateful-provider-observability.ts +261 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
- package/src/stateful/stateful-provider-runtime-context.ts +92 -0
- package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
- package/src/stateful/stateful-provider-session-routing.ts +546 -0
- package/src/stateful/stateful-provider-session-runtime.ts +403 -0
- package/src/stateful-signing.ts +46 -0
- package/src/stealth/profiles.ts +202 -231
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +8 -1
- package/src/testing/index.ts +10 -1
- package/src/testing/run.ts +658 -15
- package/src/trace-sanitization.ts +63 -0
- package/src/types.ts +788 -174
- package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
- package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
- /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
formatPromptAssetIssues,
|
|
5
|
+
installedSdkVersion,
|
|
6
|
+
syncPromptAssets,
|
|
7
|
+
verifyPromptAssets,
|
|
8
|
+
} from "../src/cli/prompt-assets.js";
|
|
9
|
+
import { resolveProviderRoot } from "./apifuse-check.js";
|
|
10
|
+
|
|
11
|
+
const HELP_TEXT = `Usage: apifuse sync-assets [path] [--check]
|
|
12
|
+
Example: apifuse sync-assets .
|
|
13
|
+
Default: apifuse sync-assets .
|
|
14
|
+
|
|
15
|
+
Regenerates the SDK-managed agent prompt assets for the installed SDK version:
|
|
16
|
+
AGENTS.md, .agents/skills/**, the CLAUDE.md/.claude/.codex symlinks, and the
|
|
17
|
+
.apifuse/prompt-assets.json manifest. Legacy top-level skills/ layouts are
|
|
18
|
+
migrated. Idempotent.
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--check Verify only; exit 1 with a diff list when assets are stale/missing/modified
|
|
22
|
+
--help, -h Show this help`;
|
|
23
|
+
|
|
24
|
+
export async function main() {
|
|
25
|
+
const args = normalizeArgs(process.argv.slice(2));
|
|
26
|
+
|
|
27
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
28
|
+
console.log(HELP_TEXT);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let checkOnly = false;
|
|
33
|
+
let inputPath: string | undefined;
|
|
34
|
+
for (const arg of args) {
|
|
35
|
+
if (arg === "--check") {
|
|
36
|
+
checkOnly = true;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (arg.startsWith("-")) {
|
|
40
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
41
|
+
}
|
|
42
|
+
if (inputPath !== undefined) {
|
|
43
|
+
throw new Error(`Unexpected argument: ${arg}`);
|
|
44
|
+
}
|
|
45
|
+
inputPath = arg;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const providerRoot = resolveProviderRoot(inputPath ?? ".");
|
|
49
|
+
|
|
50
|
+
if (checkOnly) {
|
|
51
|
+
const verification = verifyPromptAssets(providerRoot);
|
|
52
|
+
if (verification.ok) {
|
|
53
|
+
console.log(
|
|
54
|
+
`Prompt assets are in sync with the installed SDK (${installedSdkVersion()}): ${providerRoot}`,
|
|
55
|
+
);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
console.error(`Prompt assets are out of sync in ${providerRoot}:`);
|
|
59
|
+
for (const issue of formatPromptAssetIssues(verification)) {
|
|
60
|
+
console.error(` - ${issue}`);
|
|
61
|
+
}
|
|
62
|
+
console.error("\nRun `bun run sync-assets` (or `bunx apifuse sync-assets .`) to regenerate.");
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const result = syncPromptAssets(providerRoot);
|
|
67
|
+
|
|
68
|
+
// Honesty gate: writes alone never imply success. sync-assets intentionally
|
|
69
|
+
// PRESERVES (does not delete) unauthorized skills and symlinks under
|
|
70
|
+
// .agents/skills, so it can return changed:false while verify still fails.
|
|
71
|
+
// Re-verify AFTER writing and let the true post-sync state drive the exit
|
|
72
|
+
// code — never claim success while the freshness gate would reject the tree.
|
|
73
|
+
const verification = verifyPromptAssets(providerRoot);
|
|
74
|
+
|
|
75
|
+
if (result.changed) {
|
|
76
|
+
for (const removed of result.removed) {
|
|
77
|
+
console.log(`removed ${removed}`);
|
|
78
|
+
}
|
|
79
|
+
for (const wrote of result.wroteFiles) {
|
|
80
|
+
console.log(`wrote ${wrote}`);
|
|
81
|
+
}
|
|
82
|
+
for (const link of result.createdSymlinks) {
|
|
83
|
+
console.log(`symlink ${link}`);
|
|
84
|
+
}
|
|
85
|
+
console.log(`manifest ${result.manifestPath} (sdkVersion ${installedSdkVersion()})`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!verification.ok) {
|
|
89
|
+
console.error(`\nPrompt assets are still out of sync in ${providerRoot}:`);
|
|
90
|
+
for (const issue of formatPromptAssetIssues(verification)) {
|
|
91
|
+
console.error(` - ${issue}`);
|
|
92
|
+
}
|
|
93
|
+
console.error(
|
|
94
|
+
"\nsync-assets never deletes unrecognized content: resolve these by hand — remove any unauthorized skill directory or symlink under .agents/skills/, migrate a real .claude/.codex directory into .agents/ — then re-run `apifuse sync-assets .`.",
|
|
95
|
+
);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!result.changed) {
|
|
100
|
+
console.log(
|
|
101
|
+
`Prompt assets already in sync with the installed SDK (${installedSdkVersion()}): ${providerRoot}`,
|
|
102
|
+
);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
console.log(`\nPrompt assets synced: ${providerRoot}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function normalizeArgs(argv: string[]): string[] {
|
|
109
|
+
return argv[0] === "sync-assets" ? argv.slice(1) : argv;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (import.meta.main) {
|
|
113
|
+
await main().catch((error: unknown) => {
|
|
114
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const MIN_RECORDED_DELIMITED_TEXT_LENGTH = 200;
|
|
2
|
+
const MIN_RECORDED_DELIMITED_TEXT_LINES = 3;
|
|
3
|
+
const MAX_SAMPLED_DELIMITED_TEXT_LINES = 10;
|
|
4
|
+
const DELIMITER_CANDIDATES = [",", "\t", ";"] as const;
|
|
5
|
+
|
|
6
|
+
// Recognizes a recorded operation value that is a substantive tabular text
|
|
7
|
+
// payload. The length floor and repeated, quote-aware field structure keep
|
|
8
|
+
// short strings and prose from being treated as fixture provenance.
|
|
9
|
+
export function hasSubstantiveDelimitedTextStructure(value: string): boolean {
|
|
10
|
+
if (value.length < MIN_RECORDED_DELIMITED_TEXT_LENGTH) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const lines = value
|
|
15
|
+
.replace(/^\uFEFF/, "")
|
|
16
|
+
.split(/\r\n?|\n/)
|
|
17
|
+
.filter((line) => line.trim().length > 0);
|
|
18
|
+
if (lines.length < MIN_RECORDED_DELIMITED_TEXT_LINES) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const sampledLines = lines.slice(0, MAX_SAMPLED_DELIMITED_TEXT_LINES);
|
|
23
|
+
return DELIMITER_CANDIDATES.some((delimiter) => {
|
|
24
|
+
const fieldCounts = sampledLines.map((line) => countDelimitedFields(line, delimiter));
|
|
25
|
+
const expectedFieldCount = fieldCounts[0];
|
|
26
|
+
return (
|
|
27
|
+
expectedFieldCount !== undefined &&
|
|
28
|
+
expectedFieldCount >= 2 &&
|
|
29
|
+
fieldCounts.every((fieldCount) => fieldCount === expectedFieldCount)
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function countDelimitedFields(line: string, delimiter: string): number | undefined {
|
|
35
|
+
let fieldCount = 1;
|
|
36
|
+
let insideQuotes = false;
|
|
37
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
38
|
+
const character = line[index];
|
|
39
|
+
if (character === '"') {
|
|
40
|
+
if (insideQuotes && line[index + 1] === '"') {
|
|
41
|
+
index += 1;
|
|
42
|
+
} else {
|
|
43
|
+
insideQuotes = !insideQuotes;
|
|
44
|
+
}
|
|
45
|
+
} else if (!insideQuotes && character === delimiter) {
|
|
46
|
+
fieldCount += 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return insideQuotes ? undefined : fieldCount;
|
|
50
|
+
}
|
|
@@ -20,7 +20,7 @@ export declare const AUTH_TURN_SCHEMA_ARTIFACT_PATH = "dist/auth-turn/auth-turn.
|
|
|
20
20
|
*
|
|
21
21
|
* This is the exact codification of the runtime validation the SDK applies to
|
|
22
22
|
* ceremony outputs (see `validateCeremonyOutput` in `src/ceremonies`), which
|
|
23
|
-
*
|
|
23
|
+
* evaluates this same document. `kind` is an OPEN string on the wire: the known
|
|
24
24
|
* kinds in {@link TURN_KINDS} are tooling metadata, never a wire constraint.
|
|
25
25
|
*
|
|
26
26
|
* The committed artifact at `src/auth-turn/auth-turn.v1.schema.json` (shipped
|
|
@@ -87,7 +87,7 @@ export declare const AUTH_TURN_SCHEMA: {
|
|
|
87
87
|
};
|
|
88
88
|
readonly $defs: {
|
|
89
89
|
readonly completeTurnData: {
|
|
90
|
-
readonly title:
|
|
90
|
+
readonly title: "Terminal payload for kind \"complete\"";
|
|
91
91
|
readonly description: "data payload of a complete turn. The gateway extracts data.credential for persistence; complete turns are never echoed to browsers.";
|
|
92
92
|
readonly type: "object";
|
|
93
93
|
readonly additionalProperties: true;
|
|
@@ -104,7 +104,7 @@ export declare const AUTH_TURN_SCHEMA: {
|
|
|
104
104
|
};
|
|
105
105
|
};
|
|
106
106
|
readonly abortTurnData: {
|
|
107
|
-
readonly title:
|
|
107
|
+
readonly title: "Terminal payload for kind \"abort\"";
|
|
108
108
|
readonly description: "data payload of an abort turn. code, when present, is the machine-readable abort reason.";
|
|
109
109
|
readonly type: "object";
|
|
110
110
|
readonly additionalProperties: true;
|
package/dist/auth-turn/index.js
CHANGED
|
@@ -18,7 +18,7 @@ export const AUTH_TURN_SCHEMA_ARTIFACT_PATH = "dist/auth-turn/auth-turn.v1.schem
|
|
|
18
18
|
*
|
|
19
19
|
* This is the exact codification of the runtime validation the SDK applies to
|
|
20
20
|
* ceremony outputs (see `validateCeremonyOutput` in `src/ceremonies`), which
|
|
21
|
-
*
|
|
21
|
+
* evaluates this same document. `kind` is an OPEN string on the wire: the known
|
|
22
22
|
* kinds in {@link TURN_KINDS} are tooling metadata, never a wire constraint.
|
|
23
23
|
*
|
|
24
24
|
* The committed artifact at `src/auth-turn/auth-turn.v1.schema.json` (shipped
|
package/dist/auth.d.ts
CHANGED
|
@@ -66,6 +66,20 @@ export interface DefineCredentialsAuthOptions<TFields extends CredentialsAuthFie
|
|
|
66
66
|
/** Extra auth-flow context keys used by custom login/challenge code. */
|
|
67
67
|
contextKeys?: readonly string[];
|
|
68
68
|
login(ctx: FlowContext, input: CredentialsAuthInput<TFields>): CredentialsAuthLoginResult<TCredentialKeys, keyof TChallenges & string> | Promise<CredentialsAuthLoginResult<TCredentialKeys, keyof TChallenges & string>>;
|
|
69
|
+
/**
|
|
70
|
+
* Optional re-mint of an expired session from the stored credential, wired
|
|
71
|
+
* to `auth.flow.refresh`.
|
|
72
|
+
*
|
|
73
|
+
* Credential-auth upstreams routinely invalidate a session well before the
|
|
74
|
+
* `expiresAt` the provider advertised, which leaves every operation failing
|
|
75
|
+
* with a reauth error until a human repeats the whole interactive login.
|
|
76
|
+
* Implement this to re-establish the session from what is already stored on
|
|
77
|
+
* the connection; the result is resolved exactly like `login`, so it may
|
|
78
|
+
* also raise a challenge when the upstream demands one. Omit it when the
|
|
79
|
+
* upstream has no non-interactive path and re-authentication genuinely
|
|
80
|
+
* requires the user.
|
|
81
|
+
*/
|
|
82
|
+
refresh?(ctx: FlowContext, input: Partial<CredentialsAuthInput<TFields>>): CredentialsAuthLoginResult<TCredentialKeys, keyof TChallenges & string> | Promise<CredentialsAuthLoginResult<TCredentialKeys, keyof TChallenges & string>>;
|
|
69
83
|
}
|
|
70
84
|
export interface DefinedCredentialsAuth {
|
|
71
85
|
auth: AuthConfig;
|
package/dist/auth.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AuthError, ProviderError } from "./errors.js";
|
|
2
|
+
import { declarationInvalidError, DECLARATION_RULE_IDS, } from "./declaration-validation.js";
|
|
2
3
|
const CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY = "__credentialsAuthChallenge";
|
|
3
4
|
const DEFAULT_COMPLETE_TURN_ID = "auth.complete";
|
|
4
5
|
const DEFAULT_ABORT_TURN_ID = "auth.abort";
|
|
@@ -198,6 +199,23 @@ function normalizeInput(fields, input) {
|
|
|
198
199
|
}
|
|
199
200
|
return result;
|
|
200
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Refresh variant of {@link normalizeInput}. `login` coerces every declared
|
|
204
|
+
* field to a string because the interactive turn has already enforced that they
|
|
205
|
+
* are present; refresh runs with no user present, so an absent field is omitted
|
|
206
|
+
* rather than turned into an empty string. That keeps "the user did not supply
|
|
207
|
+
* this" distinguishable from "the user supplied an empty value".
|
|
208
|
+
*/
|
|
209
|
+
function normalizePartialInput(fields, input) {
|
|
210
|
+
const result = {};
|
|
211
|
+
for (const name of Object.keys(fields)) {
|
|
212
|
+
const value = input?.[name];
|
|
213
|
+
if (typeof value === "string") {
|
|
214
|
+
result[name] = value;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
201
219
|
function assertCredentialKeys(credentialKeys, credential) {
|
|
202
220
|
const missing = credentialKeys.filter((key) => {
|
|
203
221
|
const value = credential[key];
|
|
@@ -379,6 +397,7 @@ export function defineCredentialsAuth(options) {
|
|
|
379
397
|
const retryTurnId = options.retryTurnId ?? "credentials.retry";
|
|
380
398
|
const completeTurnId = options.completeTurnId ?? "credentials.complete";
|
|
381
399
|
const challenges = (options.challenges ?? {});
|
|
400
|
+
validateCredentialsAuthChallenges(challenges);
|
|
382
401
|
return {
|
|
383
402
|
auth: {
|
|
384
403
|
mode: "credentials",
|
|
@@ -411,6 +430,27 @@ export function defineCredentialsAuth(options) {
|
|
|
411
430
|
}
|
|
412
431
|
return await pollPendingChallenge(ctx, options.credentialKeys, challenges, pending, completeTurnId);
|
|
413
432
|
},
|
|
433
|
+
// Only advertise refresh when the provider implements it: the
|
|
434
|
+
// protocol treats the hook's presence as "this connection can be
|
|
435
|
+
// re-established without the user", and exposing a stub that
|
|
436
|
+
// cannot actually re-mint would turn a recoverable expiry into a
|
|
437
|
+
// silent failure.
|
|
438
|
+
...(options.refresh
|
|
439
|
+
? {
|
|
440
|
+
refresh: async (ctx, rawInput) => {
|
|
441
|
+
// A pending challenge belongs to the interactive flow that
|
|
442
|
+
// raised it; finish it there rather than restarting.
|
|
443
|
+
const pending = getPendingChallenge(ctx);
|
|
444
|
+
if (pending) {
|
|
445
|
+
return await continuePendingChallenge(ctx, options.credentialKeys, challenges, pending, rawInput, completeTurnId);
|
|
446
|
+
}
|
|
447
|
+
// Refresh runs without user input, so fields are optional
|
|
448
|
+
// here — unlike `continue`, missing ones are not a retry.
|
|
449
|
+
const result = await options.refresh(ctx, normalizePartialInput(options.fields, rawInput));
|
|
450
|
+
return await resolveAuthResult(ctx, options.credentialKeys, challenges, result, completeTurnId);
|
|
451
|
+
},
|
|
452
|
+
}
|
|
453
|
+
: {}),
|
|
414
454
|
},
|
|
415
455
|
},
|
|
416
456
|
credential: {
|
|
@@ -425,3 +465,30 @@ export function defineCredentialsAuth(options) {
|
|
|
425
465
|
},
|
|
426
466
|
};
|
|
427
467
|
}
|
|
468
|
+
function validateCredentialsAuthChallenges(challenges) {
|
|
469
|
+
const violations = [];
|
|
470
|
+
for (const [challengeId, challenge] of Object.entries(challenges)) {
|
|
471
|
+
const fieldCount = challenge.fields && typeof challenge.fields === "object"
|
|
472
|
+
? Object.keys(challenge.fields).length
|
|
473
|
+
: 0;
|
|
474
|
+
const fieldsDeclared = challenge.fields !== undefined && challenge.fields !== null;
|
|
475
|
+
const hasFields = fieldCount > 0;
|
|
476
|
+
const hasVerify = typeof challenge.verify === "function";
|
|
477
|
+
const hasPoll = typeof challenge.poll === "function";
|
|
478
|
+
const isInteractive = hasFields && hasVerify && !hasPoll;
|
|
479
|
+
const isPolling = !fieldsDeclared && !hasVerify && hasPoll;
|
|
480
|
+
const isHybrid = hasFields && hasVerify && hasPoll;
|
|
481
|
+
const emptyFieldsDeclared = fieldsDeclared && !hasFields;
|
|
482
|
+
if (!emptyFieldsDeclared && (isInteractive || isPolling || isHybrid))
|
|
483
|
+
continue;
|
|
484
|
+
const path = `challenges.${challengeId}`;
|
|
485
|
+
violations.push({
|
|
486
|
+
ruleId: DECLARATION_RULE_IDS.challengeShape,
|
|
487
|
+
path,
|
|
488
|
+
message: "challenge must be interactive, polling, or an explicit hybrid.",
|
|
489
|
+
fix: `Give ${path} non-empty fields plus verify, poll alone, or all three for a hybrid.`,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
if (violations.length > 0)
|
|
493
|
+
throw declarationInvalidError(violations);
|
|
494
|
+
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import type { AuthStartNoInputGuard } from "../define.js";
|
|
1
2
|
import type { AuthFlowDefinition, AuthTurn } from "../types.js";
|
|
2
3
|
type JsonObject = Record<string, unknown>;
|
|
4
|
+
export declare const OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY = "APIFUSE__AUTH_PROXY__URL";
|
|
5
|
+
export declare const OAUTH2_PROXIED_PKCE_VERIFIER_KEY = "__oauth2_proxied_pkce_verifier";
|
|
3
6
|
export declare function validateCeremonyOutput(turn: unknown): AuthTurn;
|
|
7
|
+
/**
|
|
8
|
+
* Defines an auth flow while preserving its concrete type for downstream checks.
|
|
9
|
+
* The compile-time guard validates the inferred literal; annotating or widening
|
|
10
|
+
* a flow to `AuthFlowDefinition` before passing it defeats the check. Full
|
|
11
|
+
* enforcement requires branding, which is deferred to a future major.
|
|
12
|
+
*/
|
|
13
|
+
export declare function defineAuthFlow<const TFlow extends AuthFlowDefinition>(flow: TFlow & AuthStartNoInputGuard<TFlow>): TFlow;
|
|
4
14
|
export declare function createOAuth2Ceremony(options: {
|
|
5
15
|
authorizeUrl: string;
|
|
6
16
|
tokenUrl: string;
|
|
@@ -9,6 +19,12 @@ export declare function createOAuth2Ceremony(options: {
|
|
|
9
19
|
scopes: string[];
|
|
10
20
|
usePKCE?: boolean;
|
|
11
21
|
}): AuthFlowDefinition;
|
|
22
|
+
/**
|
|
23
|
+
* Builds the start handler for a custom-scheme OAuth provider. The shared
|
|
24
|
+
* auth-proxy owns state minting and callback capture, while the provider owns
|
|
25
|
+
* token exchange and any following authentication turns.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createOAuth2ProxiedStart(options: import("../types.js").ProxiedOAuthConfig): import("../types.js").AuthFlowStartHandler;
|
|
12
28
|
export declare function createDeviceFlowCeremony(options: {
|
|
13
29
|
deviceCodeUrl: string;
|
|
14
30
|
tokenUrl: string;
|
package/dist/ceremonies/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
|
-
import Ajv2020 from "ajv/dist/2020.js";
|
|
3
2
|
import { AUTH_TURN_SCHEMA } from "../auth-turn/index.js";
|
|
4
3
|
import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors.js";
|
|
5
|
-
const ajv = new Ajv2020({ allErrors: true, strict: true, strictSchema: true });
|
|
6
|
-
// Runtime ceremony-output validation derives from the exported versioned
|
|
7
|
-
// contract: it compiles the exact AUTH_TURN_SCHEMA document shipped at
|
|
8
|
-
// dist/auth-turn/auth-turn.v1.schema.json, so the two cannot drift.
|
|
9
|
-
const validateAuthTurn = ajv.compile(AUTH_TURN_SCHEMA);
|
|
10
4
|
const OAUTH2_STATE_KEY = "__oauth2_state";
|
|
11
5
|
const OAUTH2_PKCE_VERIFIER_KEY = "__oauth2_pkce_verifier";
|
|
6
|
+
export const OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY = "APIFUSE__AUTH_PROXY__URL";
|
|
7
|
+
export const OAUTH2_PROXIED_PKCE_VERIFIER_KEY = "__oauth2_proxied_pkce_verifier";
|
|
8
|
+
const OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS = new Set([
|
|
9
|
+
"client_id",
|
|
10
|
+
"response_type",
|
|
11
|
+
"state",
|
|
12
|
+
"code_challenge",
|
|
13
|
+
"code_challenge_method",
|
|
14
|
+
]);
|
|
12
15
|
const DEVICE_FLOW_KEY = "__device_flow";
|
|
13
16
|
const MAGIC_LINK_KEY = "__magic_link";
|
|
14
17
|
const COMBINED_STAGE_KEY = "__combined_stage";
|
|
@@ -17,6 +20,50 @@ const FORM_FIELD_ORDER_EXTENSION = "x-apifuse-field-order";
|
|
|
17
20
|
function isRecord(value) {
|
|
18
21
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
19
22
|
}
|
|
23
|
+
function validateSchemaNode(value, schema, path, errors) {
|
|
24
|
+
if (schema.type === "object") {
|
|
25
|
+
if (!isRecord(value)) {
|
|
26
|
+
errors.push(`${path} must be object`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const properties = schema.properties ?? {};
|
|
30
|
+
for (const required of schema.required ?? []) {
|
|
31
|
+
if (!Object.hasOwn(value, required) || value[required] === undefined) {
|
|
32
|
+
errors.push(`${path} must have required property '${required}'`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (schema.additionalProperties === false) {
|
|
36
|
+
for (const key of Object.keys(value)) {
|
|
37
|
+
if (!Object.hasOwn(properties, key)) {
|
|
38
|
+
errors.push(`${path} must NOT have additional property '${key}'`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const [key, childSchema] of Object.entries(properties)) {
|
|
43
|
+
if (Object.hasOwn(value, key) && value[key] !== undefined) {
|
|
44
|
+
validateSchemaNode(value[key], childSchema, `${path}/${key}`, errors);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (schema.type === "string") {
|
|
50
|
+
if (typeof value !== "string") {
|
|
51
|
+
errors.push(`${path} must be string`);
|
|
52
|
+
}
|
|
53
|
+
else if (schema.minLength !== undefined && value.length < schema.minLength) {
|
|
54
|
+
errors.push(`${path} must NOT have fewer than ${schema.minLength} characters`);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (schema.type === "number") {
|
|
59
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
60
|
+
errors.push(`${path} must be number`);
|
|
61
|
+
}
|
|
62
|
+
else if (schema.minimum !== undefined && value < schema.minimum) {
|
|
63
|
+
errors.push(`${path} must be >= ${schema.minimum}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
20
67
|
function ensureRecord(value) {
|
|
21
68
|
return isRecord(value) ? value : {};
|
|
22
69
|
}
|
|
@@ -105,16 +152,28 @@ function withDeclaredFormFieldOrder(expectedInput) {
|
|
|
105
152
|
};
|
|
106
153
|
}
|
|
107
154
|
export function validateCeremonyOutput(turn) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
155
|
+
// Evaluate the exact exported versioned schema without eagerly initializing
|
|
156
|
+
// a general-purpose JSON Schema compiler in every provider process. Contract
|
|
157
|
+
// parity tests compare this focused evaluator with AJV over all fixtures and
|
|
158
|
+
// edge probes, so the runtime and shipped document remain locked together.
|
|
159
|
+
const errors = [];
|
|
160
|
+
validateSchemaNode(turn, AUTH_TURN_SCHEMA, "", errors);
|
|
161
|
+
if (errors.length > 0) {
|
|
162
|
+
throw new TurnValidationError(errors.join("; "));
|
|
113
163
|
}
|
|
114
164
|
return turn;
|
|
115
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Defines an auth flow while preserving its concrete type for downstream checks.
|
|
168
|
+
* The compile-time guard validates the inferred literal; annotating or widening
|
|
169
|
+
* a flow to `AuthFlowDefinition` before passing it defeats the check. Full
|
|
170
|
+
* enforcement requires branding, which is deferred to a future major.
|
|
171
|
+
*/
|
|
172
|
+
export function defineAuthFlow(flow) {
|
|
173
|
+
return flow;
|
|
174
|
+
}
|
|
116
175
|
export function createOAuth2Ceremony(options) {
|
|
117
|
-
return {
|
|
176
|
+
return defineAuthFlow({
|
|
118
177
|
start: (ctx) => runCeremonyHandler(async () => {
|
|
119
178
|
const clientId = getRequiredEnv(ctx, options.clientIdEnvKey);
|
|
120
179
|
getRequiredEnv(ctx, options.clientSecretEnvKey);
|
|
@@ -171,10 +230,58 @@ export function createOAuth2Ceremony(options) {
|
|
|
171
230
|
});
|
|
172
231
|
}, "OAuth token exchange failed", ctx, input),
|
|
173
232
|
abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "OAuth flow aborted." })),
|
|
174
|
-
};
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Builds the start handler for a custom-scheme OAuth provider. The shared
|
|
237
|
+
* auth-proxy owns state minting and callback capture, while the provider owns
|
|
238
|
+
* token exchange and any following authentication turns.
|
|
239
|
+
*/
|
|
240
|
+
export function createOAuth2ProxiedStart(options) {
|
|
241
|
+
const pkce = options.pkce ?? "S256";
|
|
242
|
+
return (ctx) => runCeremonyHandler(async () => {
|
|
243
|
+
for (const key of Object.keys(options.authorizeParams ?? {})) {
|
|
244
|
+
if (OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS.has(key.toLowerCase())) {
|
|
245
|
+
throw new ValidationError(`OAuth2 proxied authorizeParams cannot override reserved parameter "${key}".`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const proxyOrigin = ctx.env.get(OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY);
|
|
249
|
+
if (!proxyOrigin) {
|
|
250
|
+
throw new ProviderSecretError(`Missing required platform environment: ${OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY}`);
|
|
251
|
+
}
|
|
252
|
+
const clientId = getRequiredEnv(ctx, options.clientIdEnvKey);
|
|
253
|
+
if (!ctx.flowId) {
|
|
254
|
+
throw new ValidationError("OAuth2 proxied start requires the gateway flow id.");
|
|
255
|
+
}
|
|
256
|
+
const authorizePath = new URL(options.authorizeUrl).pathname;
|
|
257
|
+
const url = new URL(`/p/${encodeURIComponent(ctx.providerId)}/f/${encodeURIComponent(ctx.flowId)}${authorizePath}`, proxyOrigin);
|
|
258
|
+
url.searchParams.set("client_id", clientId);
|
|
259
|
+
url.searchParams.set("response_type", "code");
|
|
260
|
+
if (pkce === "S256") {
|
|
261
|
+
const verifier = createCodeVerifier();
|
|
262
|
+
ctx.context.set(OAUTH2_PROXIED_PKCE_VERIFIER_KEY, verifier);
|
|
263
|
+
url.searchParams.set("code_challenge", createCodeChallenge(verifier));
|
|
264
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
265
|
+
}
|
|
266
|
+
for (const [key, value] of Object.entries(options.authorizeParams ?? {})) {
|
|
267
|
+
url.searchParams.set(key, value);
|
|
268
|
+
}
|
|
269
|
+
return createTurn("redirect", {
|
|
270
|
+
data: { url: url.toString() },
|
|
271
|
+
hint: "Open the provider authorization page to continue.",
|
|
272
|
+
expectedInput: {
|
|
273
|
+
type: "object",
|
|
274
|
+
required: ["code", "state"],
|
|
275
|
+
properties: {
|
|
276
|
+
code: { type: "string" },
|
|
277
|
+
state: { type: "string" },
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
}, "OAuth2 proxied start failed", ctx);
|
|
175
282
|
}
|
|
176
283
|
export function createDeviceFlowCeremony(options) {
|
|
177
|
-
return {
|
|
284
|
+
return defineAuthFlow({
|
|
178
285
|
start: (ctx) => runCeremonyHandler(async () => {
|
|
179
286
|
const response = await ctx.http.post(options.deviceCodeUrl, {
|
|
180
287
|
client_id: getRequiredEnv(ctx, options.clientIdEnvKey),
|
|
@@ -232,10 +339,10 @@ export function createDeviceFlowCeremony(options) {
|
|
|
232
339
|
});
|
|
233
340
|
}, "Device flow polling failed", ctx),
|
|
234
341
|
abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "Device flow aborted." })),
|
|
235
|
-
};
|
|
342
|
+
});
|
|
236
343
|
}
|
|
237
344
|
export function createWebAuthnCeremony(options) {
|
|
238
|
-
return {
|
|
345
|
+
return defineAuthFlow({
|
|
239
346
|
start: (ctx) => runCeremonyHandler(async () => {
|
|
240
347
|
const challenge = toBase64Url(randomBytes(32));
|
|
241
348
|
ctx.context.set("__webauthn_challenge", challenge);
|
|
@@ -277,21 +384,23 @@ export function createWebAuthnCeremony(options) {
|
|
|
277
384
|
});
|
|
278
385
|
}, "WebAuthn verification failed", ctx, input),
|
|
279
386
|
abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "WebAuthn ceremony aborted." })),
|
|
280
|
-
};
|
|
387
|
+
});
|
|
281
388
|
}
|
|
282
389
|
export function createMagicLinkCeremony(options) {
|
|
283
390
|
const emailField = options.emailField ?? "email";
|
|
284
|
-
|
|
285
|
-
|
|
391
|
+
const buildEmailForm = () => buildJsonSchemaForm({
|
|
392
|
+
type: "object",
|
|
393
|
+
required: [emailField],
|
|
394
|
+
properties: {
|
|
395
|
+
[emailField]: { type: "string", format: "email" },
|
|
396
|
+
},
|
|
397
|
+
}, "Provide the email address to receive a magic link.");
|
|
398
|
+
return defineAuthFlow({
|
|
399
|
+
start: (ctx) => runCeremonyHandler(async () => buildEmailForm(), "Magic link start failed", ctx),
|
|
400
|
+
continue: (ctx, input = {}) => runCeremonyHandler(async () => {
|
|
286
401
|
const email = getString(input, emailField);
|
|
287
402
|
if (!email) {
|
|
288
|
-
return
|
|
289
|
-
type: "object",
|
|
290
|
-
required: [emailField],
|
|
291
|
-
properties: {
|
|
292
|
-
[emailField]: { type: "string", format: "email" },
|
|
293
|
-
},
|
|
294
|
-
}, "Provide the email address to receive a magic link.");
|
|
403
|
+
return buildEmailForm();
|
|
295
404
|
}
|
|
296
405
|
await ctx.http.post(options.sendUrl, { email });
|
|
297
406
|
ctx.context.set(MAGIC_LINK_KEY, {
|
|
@@ -303,11 +412,7 @@ export function createMagicLinkCeremony(options) {
|
|
|
303
412
|
hint: "Check your email for the magic link, then poll for completion.",
|
|
304
413
|
timing: { suggestedPollIntervalMs: 5_000, maxWaitMs: 300_000 },
|
|
305
414
|
});
|
|
306
|
-
}, "Magic link
|
|
307
|
-
continue: async () => validateCeremonyOutput(createTurn("poll", {
|
|
308
|
-
hint: "Continue polling for magic link completion.",
|
|
309
|
-
timing: { suggestedPollIntervalMs: 5_000, maxWaitMs: 300_000 },
|
|
310
|
-
})),
|
|
415
|
+
}, "Magic link continuation failed", ctx, input),
|
|
311
416
|
poll: (ctx) => runCeremonyHandler(async () => {
|
|
312
417
|
const state = getNestedRecord(ctx, MAGIC_LINK_KEY);
|
|
313
418
|
const email = getString(state, "email");
|
|
@@ -333,10 +438,10 @@ export function createMagicLinkCeremony(options) {
|
|
|
333
438
|
});
|
|
334
439
|
}, "Magic link polling failed", ctx),
|
|
335
440
|
abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "Magic link flow aborted." })),
|
|
336
|
-
};
|
|
441
|
+
});
|
|
337
442
|
}
|
|
338
443
|
export function createFormCeremony(options) {
|
|
339
|
-
return {
|
|
444
|
+
return defineAuthFlow({
|
|
340
445
|
start: async () => validateCeremonyOutput(buildJsonSchemaForm(options.schema, options.hint ?? "Provide the required input to continue.")),
|
|
341
446
|
continue: (ctx, input = {}) => runCeremonyHandler(async () => {
|
|
342
447
|
const { prevalidate } = await import("../runtime/prevalidate.js");
|
|
@@ -354,7 +459,7 @@ export function createFormCeremony(options) {
|
|
|
354
459
|
});
|
|
355
460
|
}, "Form submission failed", ctx, input),
|
|
356
461
|
abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "Form ceremony aborted." })),
|
|
357
|
-
};
|
|
462
|
+
});
|
|
358
463
|
}
|
|
359
464
|
export function combineCeremonies(...ceremonies) {
|
|
360
465
|
function getStage(ctx) {
|
|
@@ -406,7 +511,7 @@ export function combineCeremonies(...ceremonies) {
|
|
|
406
511
|
}
|
|
407
512
|
export function createSwitchCeremony(options) {
|
|
408
513
|
const choiceKeys = Object.keys(options.choices);
|
|
409
|
-
return {
|
|
514
|
+
return defineAuthFlow({
|
|
410
515
|
start: async () => validateCeremonyOutput(createTurn("multi_choice", {
|
|
411
516
|
data: { choices: choiceKeys },
|
|
412
517
|
hint: options.prompt ?? "Choose an authentication method.",
|
|
@@ -452,5 +557,5 @@ export function createSwitchCeremony(options) {
|
|
|
452
557
|
}
|
|
453
558
|
return createTurn("abort", { hint: "Switch ceremony aborted." });
|
|
454
559
|
}, "Switch ceremony abort failed", ctx),
|
|
455
|
-
};
|
|
560
|
+
});
|
|
456
561
|
}
|
package/dist/cli/commands.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ApifuseCommandName = "create" | "dev" | "check" | "submit-check" | "bounty-check" | "record" | "test" | "perf";
|
|
1
|
+
export type ApifuseCommandName = "create" | "dev" | "check" | "sync-assets" | "migrate-shape" | "migrate-operation-declaration" | "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
|
@@ -23,6 +23,30 @@ export const COMMAND_MANIFEST = {
|
|
|
23
23
|
examples: ["apifuse check .", "apifuse check providers/korea-air-quality"],
|
|
24
24
|
modulePath: "./apifuse-check",
|
|
25
25
|
},
|
|
26
|
+
"sync-assets": {
|
|
27
|
+
name: "sync-assets",
|
|
28
|
+
summary: "Regenerate SDK-managed agent prompt assets (AGENTS.md, .agents/skills, symlinks, manifest) for the installed SDK version.",
|
|
29
|
+
usage: "apifuse sync-assets [path] [--check]",
|
|
30
|
+
examples: ["apifuse sync-assets .", "apifuse sync-assets . --check"],
|
|
31
|
+
modulePath: "./apifuse-sync-assets",
|
|
32
|
+
},
|
|
33
|
+
"migrate-shape": {
|
|
34
|
+
name: "migrate-shape",
|
|
35
|
+
summary: "Migrate a provider to the phase-separated SDK: two-phase defineProvider in index.ts and curried defineOperation across sources.",
|
|
36
|
+
usage: "apifuse migrate-shape [path] [--check] [--json]",
|
|
37
|
+
examples: ["apifuse migrate-shape .", "apifuse migrate-shape . --check"],
|
|
38
|
+
modulePath: "./apifuse-migrate-shape",
|
|
39
|
+
},
|
|
40
|
+
"migrate-operation-declaration": {
|
|
41
|
+
name: "migrate-operation-declaration",
|
|
42
|
+
summary: "Migrate legacy nested operation declarations to the ADR-0009 flat shape, refusing ambiguous safety or metadata.",
|
|
43
|
+
usage: "apifuse migrate-operation-declaration [path] [--check] [--json]",
|
|
44
|
+
examples: [
|
|
45
|
+
"apifuse migrate-operation-declaration .",
|
|
46
|
+
"apifuse migrate-operation-declaration . --check --json",
|
|
47
|
+
],
|
|
48
|
+
modulePath: "./apifuse-migrate-operation-declaration",
|
|
49
|
+
},
|
|
26
50
|
"submit-check": {
|
|
27
51
|
name: "submit-check",
|
|
28
52
|
summary: "Score provider bounty submission readiness and emit checklist evidence.",
|
|
@@ -73,6 +97,9 @@ export const COMMAND_ORDER = [
|
|
|
73
97
|
"create",
|
|
74
98
|
"dev",
|
|
75
99
|
"check",
|
|
100
|
+
"sync-assets",
|
|
101
|
+
"migrate-shape",
|
|
102
|
+
"migrate-operation-declaration",
|
|
76
103
|
"submit-check",
|
|
77
104
|
"record",
|
|
78
105
|
"test",
|