@apifuse/provider-sdk 2.2.0-beta.2 → 2.2.0-beta.21
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 +487 -0
- package/CHANGELOG.md +90 -0
- package/README.md +49 -3
- package/SUBMISSION.md +1 -1
- package/bin/apifuse-check.ts +44 -59
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +27 -52
- package/bin/apifuse-pack-check.ts +14 -0
- package/bin/apifuse-pack-smoke.ts +36 -81
- package/bin/apifuse-pack-types.ts +305 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +659 -111
- package/bin/apifuse-submit-check.ts +546 -48
- package/bin/apifuse-sync-assets.ts +117 -0
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-delimited-text.ts +50 -0
- package/bin/submit-check-xml-semantics.ts +204 -0
- package/bin/submit-check-xml.ts +134 -0
- package/dist/auth-turn/index.d.ts +3 -3
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +9 -18
- package/dist/ceremonies/index.d.ts +9 -1
- package/dist/ceremonies/index.js +65 -18
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +8 -0
- package/dist/cli/create.d.ts +3 -0
- package/dist/cli/create.js +34 -35
- 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/config/loader.d.ts +176 -8
- package/dist/config/loader.js +424 -95
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +3 -6
- package/dist/contract-types.d.ts +2 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +4 -6
- package/dist/define.d.ts +9 -1
- package/dist/define.js +304 -119
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/error-resolution.d.ts +2 -0
- package/dist/error-resolution.js +90 -0
- package/dist/errors.d.ts +22 -1
- package/dist/errors.js +88 -0
- package/dist/fixture-sanitization.d.ts +26 -0
- package/dist/fixture-sanitization.js +216 -0
- package/dist/i18n/catalog.d.ts +2 -2
- package/dist/i18n/catalog.js +4 -10
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/keys.d.ts +2 -2
- package/dist/index.d.ts +46 -42
- package/dist/index.js +41 -37
- package/dist/lint.d.ts +1 -1
- package/dist/lint.js +8 -15
- 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 +12 -11
- package/dist/provider.js +10 -9
- package/dist/public-schema-field-lint.d.ts +1 -1
- package/dist/recipes/gov-api.js +1 -1
- package/dist/runtime/auth-flow.d.ts +2 -1
- package/dist/runtime/auth-flow.js +4 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +15 -29
- package/dist/runtime/cache.d.ts +1 -1
- package/dist/runtime/cache.js +4 -8
- package/dist/runtime/choice.d.ts +1 -1
- package/dist/runtime/choice.js +31 -35
- package/dist/runtime/credential.d.ts +1 -1
- package/dist/runtime/credential.js +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/runtime/executor.d.ts +1 -1
- package/dist/runtime/executor.js +31 -4
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +387 -47
- package/dist/runtime/insights.d.ts +1 -1
- package/dist/runtime/insights.js +6 -13
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +345 -22
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/native-network.d.ts +127 -0
- package/dist/runtime/native-network.js +1298 -0
- package/dist/runtime/otlp.d.ts +1 -1
- package/dist/runtime/perf.d.ts +1 -1
- package/dist/runtime/provider.d.ts +1 -1
- package/dist/runtime/provider.js +1 -2
- package/dist/runtime/proxy-errors.d.ts +1 -1
- package/dist/runtime/proxy-errors.js +9 -7
- package/dist/runtime/proxy-nodemaven.d.ts +56 -0
- package/dist/runtime/proxy-nodemaven.js +146 -0
- package/dist/runtime/proxy-retry-policy.d.ts +2 -2
- package/dist/runtime/proxy-retry-policy.js +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +2 -1
- package/dist/runtime/proxy-telemetry.js +55 -52
- 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 +2 -4
- package/dist/runtime/request-options.d.ts +68 -1
- package/dist/runtime/request-options.js +548 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +2 -2
- package/dist/runtime/state.js +238 -26
- package/dist/runtime/stealth.d.ts +5 -3
- package/dist/runtime/stealth.js +423 -143
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +11 -15
- package/dist/runtime/trace.d.ts +2 -2
- package/dist/runtime/trace.js +2 -4
- package/dist/runtime/waterfall.d.ts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +7 -15
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +6 -6
- 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-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +104 -3
- package/dist/server/self-test.js +673 -115
- package/dist/server/serve.d.ts +116 -4
- package/dist/server/serve.js +799 -128
- package/dist/server/types.d.ts +34 -9
- package/dist/server/types.js +8 -1
- package/dist/stateful/errors.d.ts +14 -0
- package/dist/stateful/errors.js +14 -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 +71 -0
- package/dist/stateful/stateful-provider-session-routing.js +353 -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 +1 -1
- package/dist/stealth/profiles.js +5 -14
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.d.ts +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +478 -28
- package/dist/types.d.ts +342 -14
- package/dist/types.js +1 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +16 -5
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +28 -86
- package/src/ceremonies/index.ts +103 -78
- package/src/cli/commands.ts +10 -0
- package/src/cli/create.ts +42 -35
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/src/config/loader.ts +652 -204
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +12 -28
- package/src/define.ts +499 -498
- package/src/dev.ts +4 -9
- package/src/error-resolution.ts +91 -0
- package/src/errors.ts +110 -5
- package/src/fixture-sanitization.ts +247 -0
- package/src/i18n/catalog.ts +10 -32
- package/src/i18n/index.ts +2 -2
- package/src/i18n/keys.ts +5 -11
- package/src/index.ts +112 -42
- package/src/lint.ts +88 -152
- 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 +66 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +7 -7
- package/src/runtime/browser.ts +64 -187
- package/src/runtime/cache.ts +20 -67
- package/src/runtime/choice.ts +79 -132
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +43 -20
- package/src/runtime/http.ts +494 -57
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +495 -66
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/native-network.ts +1686 -0
- package/src/runtime/otlp.ts +12 -23
- package/src/runtime/perf.ts +1 -1
- package/src/runtime/provider.ts +4 -9
- package/src/runtime/proxy-errors.ts +29 -42
- package/src/runtime/proxy-nodemaven.ts +221 -0
- package/src/runtime/proxy-retry-policy.ts +3 -3
- package/src/runtime/proxy-telemetry.ts +79 -77
- package/src/runtime/redirects.ts +66 -0
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +679 -9
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +353 -133
- package/src/runtime/stealth.ts +505 -154
- package/src/runtime/stt.ts +38 -94
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +1 -1
- package/src/server/index.ts +29 -7
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +857 -132
- package/src/server/serve.ts +1151 -328
- package/src/server/types.ts +12 -13
- package/src/stateful/README.md +146 -0
- package/src/stateful/errors.ts +23 -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 +555 -0
- package/src/stateful/stateful-provider-session-runtime.ts +403 -0
- package/src/stateful-signing.ts +46 -0
- package/src/stealth/profiles.ts +10 -26
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +10 -2
- package/src/testing/run.ts +653 -74
- package/src/types.ts +408 -28
- package/src/user-input.ts +118 -0
- 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
|
+
}
|
package/bin/apifuse.ts
CHANGED
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { XmlElement } from "@rgrove/parse-xml";
|
|
2
|
+
|
|
3
|
+
const FAILURE_TEXT_PATTERN =
|
|
4
|
+
/\b(?:access denied|denied|error|exception|failed|failure|fault|forbidden|invalid|maintenance|not authorized|temporarily unavailable|unauthorized|unavailable)\b/i;
|
|
5
|
+
const KOREAN_FAILURE_TEXT_PATTERN =
|
|
6
|
+
/(?:오류|에러|실패|장애|점검|서비스\s*(?:중단|불가)|(?:일시적(?:으로)?\s*)?(?:이용|사용)\s*(?:이|가)?\s*(?:불가|어렵|할\s*수\s*없))/u;
|
|
7
|
+
const SUCCESS_CODE_PATTERN = /^(?:0+|2\d\d|2xx|ok|success|successful|normalservice)$/;
|
|
8
|
+
const SUCCESS_VALUE_PATTERN = /^(?:1|true|y|yes|ok|success|successful)$/;
|
|
9
|
+
const SUCCESS_TEXT_PATTERN = /^(?:normalserviceresponse|successfulresponse)$/;
|
|
10
|
+
const LOCALIZED_SUCCESS_TEXT_PATTERN =
|
|
11
|
+
/^(?:成功|正常|処理完了|正常終了|処理が完了しました|성공|정상|처리완료|처리가완료되었습니다|处理完成|處理完成|操作成功)$/u;
|
|
12
|
+
const CODE_SHAPED_VALUE_PATTERN = /^(?:\d+|[1-5]xx)$/;
|
|
13
|
+
const CODE_CONTROL_FIELDS: ReadonlySet<string> = new Set([
|
|
14
|
+
"httpstatus",
|
|
15
|
+
"resultcode",
|
|
16
|
+
"returnreasoncode",
|
|
17
|
+
"statuscode",
|
|
18
|
+
]);
|
|
19
|
+
const TEXT_CONTROL_FIELDS: ReadonlySet<string> = new Set([
|
|
20
|
+
"message",
|
|
21
|
+
"msg",
|
|
22
|
+
"reason",
|
|
23
|
+
"resultmessage",
|
|
24
|
+
"resultmsg",
|
|
25
|
+
"state",
|
|
26
|
+
"status",
|
|
27
|
+
"statustext",
|
|
28
|
+
]);
|
|
29
|
+
const SUCCESS_CONTROL_FIELDS: ReadonlySet<string> = new Set([
|
|
30
|
+
"issuccess",
|
|
31
|
+
"ok",
|
|
32
|
+
"success",
|
|
33
|
+
"successful",
|
|
34
|
+
]);
|
|
35
|
+
const ERROR_CODE_FIELD_PATTERN = /^(?:(?:error|exception|fault)(?:code|status)s?|errcode)$/;
|
|
36
|
+
const ERROR_TEXT_FIELD_PATTERN =
|
|
37
|
+
/^(?:(?:error|exception|fault)(?:description|detail|details|info|message|reason|string|type)?s?|errmsg|returnauthmsg)$/;
|
|
38
|
+
const STRONG_CONTROL_CONTEXT_NAMES: ReadonlySet<string> = new Set([
|
|
39
|
+
"cmmmsgheader",
|
|
40
|
+
"control",
|
|
41
|
+
"error",
|
|
42
|
+
"exception",
|
|
43
|
+
"fault",
|
|
44
|
+
"header",
|
|
45
|
+
"meta",
|
|
46
|
+
"result",
|
|
47
|
+
"status",
|
|
48
|
+
]);
|
|
49
|
+
const ORDINARY_ENVELOPE_NAMES: ReadonlySet<string> = new Set(["body", "envelope", "response"]);
|
|
50
|
+
const ERROR_ROOT_NAMES: ReadonlySet<string> = new Set([
|
|
51
|
+
"error",
|
|
52
|
+
"errorresponse",
|
|
53
|
+
"exception",
|
|
54
|
+
"exceptionresponse",
|
|
55
|
+
"fault",
|
|
56
|
+
"faultresponse",
|
|
57
|
+
]);
|
|
58
|
+
const DOMAIN_BOUNDARY_NAMES: ReadonlySet<string> = new Set([
|
|
59
|
+
"entry",
|
|
60
|
+
"item",
|
|
61
|
+
"measurement",
|
|
62
|
+
"record",
|
|
63
|
+
"row",
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
export type XmlSemanticBranch = "control" | "domain" | "envelope" | "error" | "neutral";
|
|
67
|
+
|
|
68
|
+
// A control failure is only meaningful in a control/error/envelope context.
|
|
69
|
+
// Inside a domain boundary (item/record/row/…) the same field names are ordinary
|
|
70
|
+
// data — e.g. `faultCode` describing a charger's fault is not a service failure.
|
|
71
|
+
export function hasSemanticXmlFailure(element: XmlElement, branch: XmlSemanticBranch): boolean {
|
|
72
|
+
if (branch === "domain") return false;
|
|
73
|
+
const insideError = branch === "error";
|
|
74
|
+
const strongControl = insideError || branch === "control";
|
|
75
|
+
const insideControl = strongControl || branch === "envelope";
|
|
76
|
+
const fieldName = normalizedXmlName(element.name);
|
|
77
|
+
const value = element.text.trim();
|
|
78
|
+
if (
|
|
79
|
+
hasControlValueFailure({
|
|
80
|
+
fieldName,
|
|
81
|
+
value,
|
|
82
|
+
insideControl: insideControl || isSemanticControlField(fieldName),
|
|
83
|
+
strongControl,
|
|
84
|
+
})
|
|
85
|
+
) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
return Object.entries(element.attributes).some(([name, attributeValue]) =>
|
|
89
|
+
hasControlValueFailure({
|
|
90
|
+
fieldName: normalizedXmlName(name),
|
|
91
|
+
value: attributeValue.trim(),
|
|
92
|
+
insideControl: true,
|
|
93
|
+
strongControl: true,
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function rootXmlContext(name: string): XmlSemanticBranch {
|
|
99
|
+
if (DOMAIN_BOUNDARY_NAMES.has(name)) return "domain";
|
|
100
|
+
if (isXmlErrorWrapperName(name)) return "error";
|
|
101
|
+
if (isStrongControlContextName(name)) return "control";
|
|
102
|
+
return ORDINARY_ENVELOPE_NAMES.has(name) ? "envelope" : "neutral";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function childXmlContext(parent: XmlSemanticBranch, name: string): XmlSemanticBranch {
|
|
106
|
+
if (parent === "control" || parent === "domain" || parent === "error") return parent;
|
|
107
|
+
if (isXmlErrorWrapperName(name)) return "error";
|
|
108
|
+
if (isStrongControlContextName(name)) return "control";
|
|
109
|
+
if (DOMAIN_BOUNDARY_NAMES.has(name)) return "domain";
|
|
110
|
+
return parent === "envelope" || ORDINARY_ENVELOPE_NAMES.has(name) ? "envelope" : "neutral";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function isXmlErrorRootName(name: string): boolean {
|
|
114
|
+
return ERROR_ROOT_NAMES.has(name) || isXmlErrorWrapperName(name);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function normalizedXmlName(name: string): string {
|
|
118
|
+
const compatibleName = name.normalize("NFKC");
|
|
119
|
+
const localName = compatibleName.slice(compatibleName.lastIndexOf(":") + 1);
|
|
120
|
+
return localName.replace(/[^\p{L}\p{N}]/gu, "").toLowerCase();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function hasControlValueFailure(input: {
|
|
124
|
+
readonly fieldName: string;
|
|
125
|
+
readonly value: string;
|
|
126
|
+
readonly insideControl: boolean;
|
|
127
|
+
readonly strongControl: boolean;
|
|
128
|
+
}): boolean {
|
|
129
|
+
const { fieldName, value, insideControl, strongControl } = input;
|
|
130
|
+
const normalizedValue = normalizedXmlValue(value);
|
|
131
|
+
if (ERROR_CODE_FIELD_PATTERN.test(fieldName)) {
|
|
132
|
+
return !SUCCESS_CODE_PATTERN.test(normalizedValue);
|
|
133
|
+
}
|
|
134
|
+
if (ERROR_TEXT_FIELD_PATTERN.test(fieldName)) {
|
|
135
|
+
return normalizedValue.length > 0 && !SUCCESS_CODE_PATTERN.test(normalizedValue);
|
|
136
|
+
}
|
|
137
|
+
if (
|
|
138
|
+
strongControl &&
|
|
139
|
+
TEXT_CONTROL_FIELDS.has(fieldName) &&
|
|
140
|
+
normalizedValue.length > 0 &&
|
|
141
|
+
!isExplicitSuccess(normalizedValue)
|
|
142
|
+
) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
const isCodeControl =
|
|
146
|
+
CODE_CONTROL_FIELDS.has(fieldName) ||
|
|
147
|
+
(fieldName === "code" && insideControl) ||
|
|
148
|
+
(fieldName === "status" && insideControl && CODE_SHAPED_VALUE_PATTERN.test(normalizedValue));
|
|
149
|
+
if (isCodeControl && !SUCCESS_CODE_PATTERN.test(normalizedValue)) return true;
|
|
150
|
+
if (
|
|
151
|
+
insideControl &&
|
|
152
|
+
SUCCESS_CONTROL_FIELDS.has(fieldName) &&
|
|
153
|
+
!SUCCESS_VALUE_PATTERN.test(normalizedValue)
|
|
154
|
+
) {
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
return insideControl && TEXT_CONTROL_FIELDS.has(fieldName) && hasFailureText(value);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function isSemanticControlField(fieldName: string): boolean {
|
|
161
|
+
return (
|
|
162
|
+
CODE_CONTROL_FIELDS.has(fieldName) ||
|
|
163
|
+
TEXT_CONTROL_FIELDS.has(fieldName) ||
|
|
164
|
+
SUCCESS_CONTROL_FIELDS.has(fieldName) ||
|
|
165
|
+
ERROR_CODE_FIELD_PATTERN.test(fieldName) ||
|
|
166
|
+
ERROR_TEXT_FIELD_PATTERN.test(fieldName) ||
|
|
167
|
+
fieldName === "code"
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function isExplicitSuccess(value: string): boolean {
|
|
172
|
+
return (
|
|
173
|
+
SUCCESS_CODE_PATTERN.test(value) ||
|
|
174
|
+
SUCCESS_VALUE_PATTERN.test(value) ||
|
|
175
|
+
SUCCESS_TEXT_PATTERN.test(value) ||
|
|
176
|
+
LOCALIZED_SUCCESS_TEXT_PATTERN.test(value)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function isStrongControlContextName(name: string): boolean {
|
|
181
|
+
return STRONG_CONTROL_CONTEXT_NAMES.has(name) || name.endsWith("control");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function isXmlErrorWrapperName(name: string): boolean {
|
|
185
|
+
return /(?:error|exception|fault)(?:response)?$/.test(name);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function hasFailureText(value: string): boolean {
|
|
189
|
+
const normalized = value.normalize("NFKC");
|
|
190
|
+
return [normalized, normalized.replace(/\p{Cf}/gu, "")].some((candidate) => {
|
|
191
|
+
if (KOREAN_FAILURE_TEXT_PATTERN.test(candidate)) return true;
|
|
192
|
+
const tokenized = candidate
|
|
193
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
194
|
+
.replace(/[^A-Za-z0-9]+/g, " ");
|
|
195
|
+
return FAILURE_TEXT_PATTERN.test(tokenized);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function normalizedXmlValue(value: string): string {
|
|
200
|
+
return value
|
|
201
|
+
.normalize("NFKC")
|
|
202
|
+
.replace(/[^\p{L}\p{N}]/gu, "")
|
|
203
|
+
.toLowerCase();
|
|
204
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseXml,
|
|
3
|
+
XmlDocumentType,
|
|
4
|
+
XmlElement,
|
|
5
|
+
XmlError,
|
|
6
|
+
XmlProcessingInstruction,
|
|
7
|
+
} from "@rgrove/parse-xml";
|
|
8
|
+
import { Buffer } from "node:buffer";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
childXmlContext,
|
|
12
|
+
hasSemanticXmlFailure,
|
|
13
|
+
isXmlErrorRootName,
|
|
14
|
+
normalizedXmlName,
|
|
15
|
+
rootXmlContext,
|
|
16
|
+
type XmlSemanticBranch,
|
|
17
|
+
} from "./submit-check-xml-semantics.js";
|
|
18
|
+
|
|
19
|
+
const MIN_RECORDED_XML_LENGTH = 128;
|
|
20
|
+
// Recorded fixtures must remain reviewable; this pre-allocation cap also bounds the parser tree.
|
|
21
|
+
export const MAX_RECORDED_XML_BYTES = 4 * 1024 * 1024;
|
|
22
|
+
const MAX_RECORDED_XML_DEPTH = 64;
|
|
23
|
+
const MAX_RECORDED_XML_ELEMENTS = 50_000;
|
|
24
|
+
const XML_DOCTYPE_PATTERN = /<!DOCTYPE\b/i;
|
|
25
|
+
const REJECTED_RECORDED_XML_ROOT_NAMES: ReadonlySet<string> = new Set(["body", "html", "head"]);
|
|
26
|
+
|
|
27
|
+
// Recognizes a recorded operation value that is a substantive, well-formed XML
|
|
28
|
+
// success payload — the shape captured by `apifuse record` against upstreams
|
|
29
|
+
// that return XML (e.g. Korean public-data APIs). Fails closed on malformed XML,
|
|
30
|
+
// HTML, DTD/processing-instruction payloads, oversized/deep/wide trees, error
|
|
31
|
+
// roots, and failure/control-only envelopes. Uses a maintained parser rather
|
|
32
|
+
// than regex so entity/namespace/CDATA handling is correct.
|
|
33
|
+
export function hasSubstantiveXmlStructure(
|
|
34
|
+
value: string,
|
|
35
|
+
parser: typeof parseXml = parseXml,
|
|
36
|
+
): boolean {
|
|
37
|
+
if (Buffer.byteLength(value, "utf8") > MAX_RECORDED_XML_BYTES) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const xml = value.trim();
|
|
41
|
+
if (xml.length < MIN_RECORDED_XML_LENGTH || XML_DOCTYPE_PATTERN.test(xml)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let document: ReturnType<typeof parseXml>;
|
|
46
|
+
try {
|
|
47
|
+
document = parser(xml, { preserveDocumentType: true });
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error instanceof XmlError || error instanceof RangeError) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
if (
|
|
55
|
+
document.children.some(
|
|
56
|
+
(child) => child instanceof XmlDocumentType || child instanceof XmlProcessingInstruction,
|
|
57
|
+
)
|
|
58
|
+
) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const root = document.root;
|
|
63
|
+
if (root === null) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const rootName = normalizedXmlName(root.name);
|
|
67
|
+
if (REJECTED_RECORDED_XML_ROOT_NAMES.has(rootName) || isXmlErrorRootName(rootName)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const pending: Array<{
|
|
72
|
+
readonly branch: XmlSemanticBranch;
|
|
73
|
+
readonly element: XmlElement;
|
|
74
|
+
readonly depth: number;
|
|
75
|
+
}> = [
|
|
76
|
+
{
|
|
77
|
+
element: root,
|
|
78
|
+
depth: 1,
|
|
79
|
+
branch: rootXmlContext(rootName),
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
const leafNames = new Set<string>();
|
|
83
|
+
let leafTextLength = 0;
|
|
84
|
+
let elementCount = 0;
|
|
85
|
+
while (pending.length > 0) {
|
|
86
|
+
const current = pending.pop();
|
|
87
|
+
if (current === undefined) {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
elementCount += 1;
|
|
91
|
+
if (
|
|
92
|
+
elementCount > MAX_RECORDED_XML_ELEMENTS ||
|
|
93
|
+
current.depth > MAX_RECORDED_XML_DEPTH ||
|
|
94
|
+
hasSemanticXmlFailure(current.element, current.branch)
|
|
95
|
+
) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const childElements: XmlElement[] = [];
|
|
100
|
+
for (const child of current.element.children) {
|
|
101
|
+
if (child instanceof XmlProcessingInstruction) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (child instanceof XmlElement) {
|
|
105
|
+
childElements.push(child);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (childElements.length === 0) {
|
|
109
|
+
const leafText = current.element.text.trim();
|
|
110
|
+
// Only substantive *domain* leaves count as evidence. Control/error
|
|
111
|
+
// leaves (resultCode, resultMsg, header status, …) are not payload data,
|
|
112
|
+
// so a control-only success envelope with no real records is rejected.
|
|
113
|
+
if (
|
|
114
|
+
leafText.length > 0 &&
|
|
115
|
+
current.depth >= 3 &&
|
|
116
|
+
current.branch !== "control" &&
|
|
117
|
+
current.branch !== "error"
|
|
118
|
+
) {
|
|
119
|
+
leafNames.add(normalizedXmlName(current.element.name));
|
|
120
|
+
leafTextLength += leafText.length;
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
for (const child of childElements) {
|
|
125
|
+
const childName = normalizedXmlName(child.name);
|
|
126
|
+
pending.push({
|
|
127
|
+
element: child,
|
|
128
|
+
depth: current.depth + 1,
|
|
129
|
+
branch: childXmlContext(current.branch, childName),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return leafNames.size >= 2 && leafTextLength >= 16;
|
|
134
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthTurn } from "../types";
|
|
1
|
+
import type { AuthTurn } from "../types.js";
|
|
2
2
|
export type { AuthTurn };
|
|
3
3
|
/**
|
|
4
4
|
* Major version of the AuthTurn envelope contract.
|
|
@@ -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.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AuthError } from "./errors";
|
|
2
|
-
import type { AuthConfig, AuthFlowTerminalContext, AuthTurn, ContextDeclaration, CredentialDeclaration, FlowContext, ProviderLocaleKeyInput } from "./types";
|
|
1
|
+
import { AuthError } from "./errors.js";
|
|
2
|
+
import type { AuthConfig, AuthFlowTerminalContext, AuthTurn, ContextDeclaration, CredentialDeclaration, FlowContext, ProviderLocaleKeyInput } from "./types.js";
|
|
3
3
|
export type CredentialsAuthFieldType = "string" | "email" | "password" | "otp";
|
|
4
4
|
export interface CredentialsAuthField {
|
|
5
5
|
type?: CredentialsAuthFieldType;
|
package/dist/auth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthError, ProviderError } from "./errors";
|
|
1
|
+
import { AuthError, ProviderError } from "./errors.js";
|
|
2
2
|
const CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY = "__credentialsAuthChallenge";
|
|
3
3
|
const DEFAULT_COMPLETE_TURN_ID = "auth.complete";
|
|
4
4
|
const DEFAULT_ABORT_TURN_ID = "auth.abort";
|
|
@@ -97,7 +97,7 @@ export function createAuthFlowHelpers(options = {}) {
|
|
|
97
97
|
},
|
|
98
98
|
};
|
|
99
99
|
},
|
|
100
|
-
abort({ code, message, retry, actionHint, fieldErrors, data, turnId, expiresAt
|
|
100
|
+
abort({ code, message, retry, actionHint, fieldErrors, data, turnId, expiresAt }) {
|
|
101
101
|
return {
|
|
102
102
|
kind: "abort",
|
|
103
103
|
...authTurnBase({ turnId, defaultTurnId: DEFAULT_ABORT_TURN_ID, expiresAt }),
|
|
@@ -169,12 +169,8 @@ function expectedInputFromFields(fields) {
|
|
|
169
169
|
...(field.type === "password" ? { format: "password" } : {}),
|
|
170
170
|
...(field.type === "otp" ? { format: "otp" } : {}),
|
|
171
171
|
...(field.labelKey ? { nameKey: field.labelKey } : {}),
|
|
172
|
-
...(field.descriptionKey
|
|
173
|
-
|
|
174
|
-
: {}),
|
|
175
|
-
...(field.placeholderKey
|
|
176
|
-
? { placeholderKey: field.placeholderKey }
|
|
177
|
-
: {}),
|
|
172
|
+
...(field.descriptionKey ? { descriptionKey: field.descriptionKey } : {}),
|
|
173
|
+
...(field.placeholderKey ? { placeholderKey: field.placeholderKey } : {}),
|
|
178
174
|
...(field.sensitive || field.type === "password" || field.type === "otp"
|
|
179
175
|
? { sensitive: true }
|
|
180
176
|
: {}),
|
|
@@ -291,17 +287,15 @@ function completeTurn(credentialKeys, result, defaultTurnId) {
|
|
|
291
287
|
};
|
|
292
288
|
}
|
|
293
289
|
function challengeTurn(definition, request) {
|
|
294
|
-
const expectedInput = definition.fields
|
|
295
|
-
? expectedInputFromFields(definition.fields)
|
|
296
|
-
: undefined;
|
|
290
|
+
const expectedInput = definition.fields ? expectedInputFromFields(definition.fields) : undefined;
|
|
297
291
|
return {
|
|
298
292
|
kind: expectedInput ? "form" : "pending",
|
|
299
293
|
turnId: request.turnId ?? definition.turnId ?? `credentials.${request.challengeId}`,
|
|
300
294
|
...(request.expiresAt ? { expiresAt: request.expiresAt } : {}),
|
|
301
|
-
...(request.hintKey ?? definition.hintKey
|
|
295
|
+
...((request.hintKey ?? definition.hintKey)
|
|
302
296
|
? { hintKey: request.hintKey ?? definition.hintKey }
|
|
303
297
|
: {}),
|
|
304
|
-
...(request.timing ?? definition.timing
|
|
298
|
+
...((request.timing ?? definition.timing)
|
|
305
299
|
? { timing: request.timing ?? definition.timing }
|
|
306
300
|
: {}),
|
|
307
301
|
...(expectedInput ? { expectedInput } : {}),
|
|
@@ -378,7 +372,7 @@ async function pollPendingChallenge(ctx, credentialKeys, challenges, pending, co
|
|
|
378
372
|
export function defineCredentialsAuth(options) {
|
|
379
373
|
if (Object.keys(options.fields).length === 0) {
|
|
380
374
|
throw new ProviderError("defineCredentialsAuth requires at least one field", {
|
|
381
|
-
fix:
|
|
375
|
+
fix: 'Pass fields such as { email: { type: "email" }, password: { type: "password" } }.',
|
|
382
376
|
});
|
|
383
377
|
}
|
|
384
378
|
const expectedInput = expectedInputFromFields(options.fields);
|
|
@@ -427,10 +421,7 @@ export function defineCredentialsAuth(options) {
|
|
|
427
421
|
...(options.justification ? { justification: options.justification } : {}),
|
|
428
422
|
},
|
|
429
423
|
context: {
|
|
430
|
-
keys: Array.from(new Set([
|
|
431
|
-
CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY,
|
|
432
|
-
...(options.contextKeys ?? []),
|
|
433
|
-
])),
|
|
424
|
+
keys: Array.from(new Set([CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY, ...(options.contextKeys ?? [])])),
|
|
434
425
|
},
|
|
435
426
|
};
|
|
436
427
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type { AuthFlowDefinition, AuthTurn } from "../types";
|
|
1
|
+
import type { AuthFlowDefinition, AuthTurn } from "../types.js";
|
|
2
2
|
type JsonObject = Record<string, unknown>;
|
|
3
|
+
export declare const OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY = "APIFUSE__AUTH_PROXY__URL";
|
|
4
|
+
export declare const OAUTH2_PROXIED_PKCE_VERIFIER_KEY = "__oauth2_proxied_pkce_verifier";
|
|
3
5
|
export declare function validateCeremonyOutput(turn: unknown): AuthTurn;
|
|
4
6
|
export declare function createOAuth2Ceremony(options: {
|
|
5
7
|
authorizeUrl: string;
|
|
@@ -9,6 +11,12 @@ export declare function createOAuth2Ceremony(options: {
|
|
|
9
11
|
scopes: string[];
|
|
10
12
|
usePKCE?: boolean;
|
|
11
13
|
}): AuthFlowDefinition;
|
|
14
|
+
/**
|
|
15
|
+
* Builds the start handler for a custom-scheme OAuth provider. The shared
|
|
16
|
+
* auth-proxy owns state minting and callback capture, while the provider owns
|
|
17
|
+
* token exchange and any following authentication turns.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createOAuth2ProxiedStart(options: import("../types.js").ProxiedOAuthConfig): import("../types.js").AuthFlowStartHandler;
|
|
12
20
|
export declare function createDeviceFlowCeremony(options: {
|
|
13
21
|
deviceCodeUrl: string;
|
|
14
22
|
tokenUrl: string;
|