@apifuse/provider-sdk 2.2.0-beta.4 → 2.2.0-beta.7
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 +92 -0
- package/CHANGELOG.md +12 -0
- package/README.md +5 -1
- package/SUBMISSION.md +1 -1
- package/bin/apifuse-check.ts +26 -1
- package/bin/apifuse-pack-check.ts +14 -0
- package/bin/apifuse-submit-check.ts +433 -15
- package/bin/apifuse-sync-assets.ts +117 -0
- 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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/runtime/executor.js +7 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/self-test.d.ts +101 -0
- package/dist/server/self-test.js +670 -112
- package/dist/server/serve.d.ts +5 -0
- package/dist/server/serve.js +41 -1
- package/package.json +1 -1
- 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/index.ts +5 -0
- package/src/runtime/executor.ts +8 -0
- package/src/runtime/secrets.ts +64 -0
- package/src/server/index.ts +5 -0
- package/src/server/self-test.ts +852 -127
- package/src/server/serve.ts +60 -1
- 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
|
@@ -4,8 +4,8 @@ You are building an APIFuse provider. APIFuse turns messy upstream APIs into
|
|
|
4
4
|
normalized, typed, evidence-backed public APIs. A provider that merely proxies
|
|
5
5
|
the upstream is a failed provider, even if every check passes.
|
|
6
6
|
|
|
7
|
-
This file is the core contract. Detailed procedures live in
|
|
8
|
-
the matching skill BEFORE working on that area (index at the bottom).
|
|
7
|
+
This file is the core contract. Detailed procedures live in `.agents/skills/` —
|
|
8
|
+
load the matching skill BEFORE working on that area (index at the bottom).
|
|
9
9
|
|
|
10
10
|
## Non-negotiable principles
|
|
11
11
|
|
|
@@ -75,13 +75,22 @@ bun run submit-check # structural score; a high score does NOT prove quality
|
|
|
75
75
|
`submit-check` is a structural gate. Every principle above can be violated
|
|
76
76
|
while scoring 95/100 — reviewers and CI audit for exactly these classes.
|
|
77
77
|
|
|
78
|
+
## Managed prompt assets
|
|
79
|
+
|
|
80
|
+
`AGENTS.md` and `.agents/skills/**` are generated by the SDK; `CLAUDE.md`,
|
|
81
|
+
`.claude`, and `.codex` are symlinks onto them so every agent CLI reads the
|
|
82
|
+
same contract. Do not hand-edit these files — regenerate them with
|
|
83
|
+
`bun run sync-assets` (or `bunx apifuse sync-assets .`). `apifuse check` and
|
|
84
|
+
`submit-check` enforce a freshness gate: stale or modified prompt assets
|
|
85
|
+
(tracked in `.apifuse/prompt-assets.json`) block submission until re-synced.
|
|
86
|
+
|
|
78
87
|
## Skill index — load before working on:
|
|
79
88
|
|
|
80
89
|
| Area | Load |
|
|
81
90
|
| --- | --- |
|
|
82
|
-
| Output schemas, mappers, field naming, timestamps, enums |
|
|
83
|
-
| Upstream request params, new endpoint wiring, field mapping |
|
|
84
|
-
| Recording fixtures, writing tests against fixtures |
|
|
85
|
-
| List operations, paging, totals, client-side filtering |
|
|
86
|
-
| healthCheck blocks, error classification, fail-closed guards |
|
|
87
|
-
| Upstream-specific known pitfalls for THIS bounty |
|
|
91
|
+
| Output schemas, mappers, field naming, timestamps, enums | `.agents/skills/normalization-standards/SKILL.md` |
|
|
92
|
+
| Upstream request params, new endpoint wiring, field mapping | `.agents/skills/upstream-contract-verification/SKILL.md` |
|
|
93
|
+
| Recording fixtures, writing tests against fixtures | `.agents/skills/fixtures-and-recording/SKILL.md` |
|
|
94
|
+
| List operations, paging, totals, client-side filtering | `.agents/skills/pagination-and-counts/SKILL.md` |
|
|
95
|
+
| healthCheck blocks, error classification, fail-closed guards | `.agents/skills/health-checks-and-fail-closed/SKILL.md` |
|
|
96
|
+
| Upstream-specific known pitfalls for THIS bounty | `.agents/skills/upstream-notes/` (read every file) |
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export { generateInsights } from "./runtime/insights.js";
|
|
|
27
27
|
export { type InstrumentationOptions, type InstrumentedProviderContext, wrapWithInstrumentation, } from "./runtime/instrumentation.js";
|
|
28
28
|
export { type PrevalidateResult, prevalidate } from "./runtime/prevalidate.js";
|
|
29
29
|
export { getProviderBaseUrl } from "./runtime/provider.js";
|
|
30
|
+
export { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "./runtime/secrets.js";
|
|
30
31
|
export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, } from "./runtime/state.js";
|
|
31
32
|
export { createStealthClient } from "./runtime/stealth.js";
|
|
32
33
|
export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ export { generateInsights } from "./runtime/insights.js";
|
|
|
24
24
|
export { wrapWithInstrumentation, } from "./runtime/instrumentation.js";
|
|
25
25
|
export { prevalidate } from "./runtime/prevalidate.js";
|
|
26
26
|
export { getProviderBaseUrl } from "./runtime/provider.js";
|
|
27
|
+
export { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "./runtime/secrets.js";
|
|
27
28
|
export { createUnsupportedProviderRuntimeState, UnsupportedProviderStateError, } from "./runtime/state.js";
|
|
28
29
|
export { createStealthClient } from "./runtime/stealth.js";
|
|
29
30
|
export { APIFUSE__STT__BACKEND_ENV, APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__STT__MODEL_ENV, createSttClientFromEnv, createUnsupportedSttClient, extractVerificationCode, resolveSttPrompt, } from "./runtime/stt.js";
|
package/dist/runtime/executor.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isSessionExpiredError, ProviderError, SessionExpiredError } from "../errors.js";
|
|
2
2
|
import { parseSchema } from "../schema.js";
|
|
3
|
+
import { assertRequiredSecretsPresent } from "./secrets.js";
|
|
3
4
|
export function isStreamingOperation(provider, operationId) {
|
|
4
5
|
const kind = provider.operations[operationId]?.transport?.kind ?? "json";
|
|
5
6
|
return kind !== "json";
|
|
@@ -23,6 +24,12 @@ export async function executeOperation(provider, operationId, ctx, input, _optio
|
|
|
23
24
|
fix: `Valid operations: ${Object.keys(provider.operations).join(", ")}`,
|
|
24
25
|
});
|
|
25
26
|
}
|
|
27
|
+
// SDK-owned secret presence gate (single source of truth): declared
|
|
28
|
+
// `required: true` secrets are validated here, before input parsing and the
|
|
29
|
+
// handler, so every invocation path (serve /v1, self-test probes, perf,
|
|
30
|
+
// record) fails with the same structured MISSING_SECRET error instead of a
|
|
31
|
+
// handler-specific crash. Providers must not re-check presence locally.
|
|
32
|
+
assertRequiredSecretsPresent(provider, ctx.env);
|
|
26
33
|
const validatedInput = await parseSchema(operation.input, input, `operations.${operationId}.input`);
|
|
27
34
|
const execute = () => ctx.trace.span(`handler:${operationId}`, () => Promise.resolve(operation.handler(ctx, validatedInput)));
|
|
28
35
|
let result;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EnvContext, ProviderDefinition } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical error code for a declared-but-unprovisioned provider secret.
|
|
4
|
+
*
|
|
5
|
+
* The SDK is the single source of truth for env/secret presence validation:
|
|
6
|
+
* providers declare secrets in `defineProvider({ secrets: [...] })` and the
|
|
7
|
+
* runtime enforces presence before any handler or auth-flow code runs.
|
|
8
|
+
* Provider-local presence guards (requireServiceKey/requireApiKey style) are a
|
|
9
|
+
* deprecated antipattern — see the `sdk-owned-secret-presence` submit-check
|
|
10
|
+
* rule.
|
|
11
|
+
*/
|
|
12
|
+
export declare const MISSING_SECRET_CODE = "MISSING_SECRET";
|
|
13
|
+
/**
|
|
14
|
+
* Names of declared `required: true` secrets whose env values are unset or
|
|
15
|
+
* whitespace-only. Whitespace-only values count as missing for parity with the
|
|
16
|
+
* `.trim()` guards well-built providers used before the SDK owned this check —
|
|
17
|
+
* a blank value provisioned by a broken secret pipeline must not pass the gate.
|
|
18
|
+
*/
|
|
19
|
+
export declare function listMissingRequiredSecrets(provider: ProviderDefinition, env: EnvContext): string[];
|
|
20
|
+
/**
|
|
21
|
+
* Throws the canonical structured missing-secret error when any declared
|
|
22
|
+
* `required: true` secret is absent. All missing names are reported in a
|
|
23
|
+
* single error so operators can provision the full set in one pass instead of
|
|
24
|
+
* discovering them one deploy at a time (the 2026-07-22 unprovisioned-secret
|
|
25
|
+
* incident failure mode).
|
|
26
|
+
*/
|
|
27
|
+
export declare function assertRequiredSecretsPresent(provider: ProviderDefinition, env: EnvContext): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ProviderSecretError } from "../errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical error code for a declared-but-unprovisioned provider secret.
|
|
4
|
+
*
|
|
5
|
+
* The SDK is the single source of truth for env/secret presence validation:
|
|
6
|
+
* providers declare secrets in `defineProvider({ secrets: [...] })` and the
|
|
7
|
+
* runtime enforces presence before any handler or auth-flow code runs.
|
|
8
|
+
* Provider-local presence guards (requireServiceKey/requireApiKey style) are a
|
|
9
|
+
* deprecated antipattern — see the `sdk-owned-secret-presence` submit-check
|
|
10
|
+
* rule.
|
|
11
|
+
*/
|
|
12
|
+
export const MISSING_SECRET_CODE = "MISSING_SECRET";
|
|
13
|
+
/**
|
|
14
|
+
* Names of declared `required: true` secrets whose env values are unset or
|
|
15
|
+
* whitespace-only. Whitespace-only values count as missing for parity with the
|
|
16
|
+
* `.trim()` guards well-built providers used before the SDK owned this check —
|
|
17
|
+
* a blank value provisioned by a broken secret pipeline must not pass the gate.
|
|
18
|
+
*/
|
|
19
|
+
export function listMissingRequiredSecrets(provider, env) {
|
|
20
|
+
const missing = [];
|
|
21
|
+
for (const secret of provider.secrets ?? []) {
|
|
22
|
+
if (secret.required !== true) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const value = env.get(secret.name);
|
|
26
|
+
if (value === undefined || value.trim() === "") {
|
|
27
|
+
missing.push(secret.name);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return missing;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Throws the canonical structured missing-secret error when any declared
|
|
34
|
+
* `required: true` secret is absent. All missing names are reported in a
|
|
35
|
+
* single error so operators can provision the full set in one pass instead of
|
|
36
|
+
* discovering them one deploy at a time (the 2026-07-22 unprovisioned-secret
|
|
37
|
+
* incident failure mode).
|
|
38
|
+
*/
|
|
39
|
+
export function assertRequiredSecretsPresent(provider, env) {
|
|
40
|
+
const missing = listMissingRequiredSecrets(provider, env);
|
|
41
|
+
if (missing.length === 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const names = missing.join(", ");
|
|
45
|
+
throw new ProviderSecretError(`Missing required provider secret${missing.length > 1 ? "s" : ""}: ${names}`, {
|
|
46
|
+
code: MISSING_SECRET_CODE,
|
|
47
|
+
category: "credential_unavailable",
|
|
48
|
+
retryable: false,
|
|
49
|
+
fix: `Provision ${names} in the provider environment (e.g. Doppler). Declared in defineProvider({ secrets: [...] }).`,
|
|
50
|
+
});
|
|
51
|
+
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createServerApp, type ServeOptions, serve } from "./serve.js";
|
|
2
|
-
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, type SelfTestAppOptions, type SelfTestCaseResult, type SelfTestCaseStatus, type SelfTestOperationInvoke, type SelfTestRequest, SelfTestRequestSchema, type SelfTestResponse, } from "./self-test.js";
|
|
2
|
+
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, type SelfTestAppOptions, type SelfTestAuthFlowInvoke, type SelfTestAuthFlowRoute, type SelfTestCaseResult, type SelfTestCaseStatus, type SelfTestOperationInvoke, type SelfTestRequest, SelfTestRequestSchema, type SelfTestResponse, } from "./self-test.js";
|
|
3
3
|
export { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens.js";
|
|
4
4
|
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
5
5
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, type SelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
package/dist/server/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createServerApp, serve } from "./serve.js";
|
|
2
|
-
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test.js";
|
|
2
|
+
export { computeSelfTestPlanDigest, createSelfTestApp, createSelfTestAuthFlowInvoke, createSelfTestInvoke, DEFAULT_SELF_TEST_REQUEST_BUDGET_MS, isSelfTestReadOnlyOperation, PROVIDER_RUNTIME_SELF_TEST_REQUEST_BUDGET_MS_ENV, resolveSelfTestPort, SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON, SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON, SELF_TEST_HEALTHZ_PATH, SELF_TEST_PATH, SELF_TEST_SCHEMA_VERSION, SelfTestRequestSchema, } from "./self-test.js";
|
|
3
3
|
export { resolveHealthCheckInputDateTokens } from "./self-test-input-tokens.js";
|
|
4
4
|
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
5
5
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
@@ -61,11 +61,53 @@ export type SelfTestOperationInvoke = (args: {
|
|
|
61
61
|
data: unknown;
|
|
62
62
|
meta?: Record<string, unknown>;
|
|
63
63
|
}>;
|
|
64
|
+
export type SelfTestAuthFlowRoute = "start" | "continue";
|
|
65
|
+
/**
|
|
66
|
+
* In-process driver for the tenant app's /auth pipeline. Self-test uses it to
|
|
67
|
+
* materialize `requiresConnection` credentials through the provider's declared
|
|
68
|
+
* auth flow — the exact path production connections take — instead of
|
|
69
|
+
* injecting raw credential inputs as connection secrets.
|
|
70
|
+
*/
|
|
71
|
+
export type SelfTestAuthFlowInvoke = (args: {
|
|
72
|
+
route: SelfTestAuthFlowRoute;
|
|
73
|
+
requestId: string;
|
|
74
|
+
flowId: string;
|
|
75
|
+
/** Stable per-credential connection id — keeps login on the probe's affinity. */
|
|
76
|
+
connectionId?: string;
|
|
77
|
+
/** The probe connection's externalRef — flows reading ctx.externalRef see the same identity. */
|
|
78
|
+
externalRef?: string;
|
|
79
|
+
input?: Record<string, unknown>;
|
|
80
|
+
context?: Record<string, unknown>;
|
|
81
|
+
}) => Promise<{
|
|
82
|
+
status: number;
|
|
83
|
+
body: unknown;
|
|
84
|
+
}>;
|
|
85
|
+
/**
|
|
86
|
+
* Skip reason reported when a declared auth flow does not complete in a single
|
|
87
|
+
* continue (OTP, retry loop). Cross-repo contract: the health-monitor maps
|
|
88
|
+
* this exact string to `self_test_incapable`; never vary it.
|
|
89
|
+
*/
|
|
90
|
+
export declare const SELF_TEST_AUTH_FLOW_MULTI_TURN_SKIP_REASON = "auth_flow_multi_turn";
|
|
91
|
+
/**
|
|
92
|
+
* A `retry` turn after credential submission: the flow REJECTED the
|
|
93
|
+
* configured inputs (bad password, exchange failure). Distinct from the
|
|
94
|
+
* multi-turn gap so monitoring surfaces it as a real credential outage, and
|
|
95
|
+
* memoized like multi-turn so the probe does not re-submit rejected
|
|
96
|
+
* credentials every cycle (lockout safety).
|
|
97
|
+
*/
|
|
98
|
+
export declare const SELF_TEST_AUTH_FLOW_REJECTED_SKIP_REASON = "auth_flow_rejected";
|
|
64
99
|
export interface SelfTestAppOptions {
|
|
65
100
|
/** Derived-token verification secrets; without them every self-test route 404s. */
|
|
66
101
|
secrets?: SelfTestMasterSecrets;
|
|
67
102
|
/** In-process invoke bound to the tenant-facing app's /v1 pipeline. */
|
|
68
103
|
invoke: SelfTestOperationInvoke;
|
|
104
|
+
/**
|
|
105
|
+
* In-process auth-flow driver bound to the tenant-facing app's /auth
|
|
106
|
+
* pipeline. Required for providers that declare `auth.mode: "credentials"`
|
|
107
|
+
* with a flow; without it their requiresConnection cases report a visible
|
|
108
|
+
* auth_flow_unavailable error instead of probing with raw inputs.
|
|
109
|
+
*/
|
|
110
|
+
authFlow?: SelfTestAuthFlowInvoke;
|
|
69
111
|
/** Overall request budget; defaults to env / 120s. */
|
|
70
112
|
requestBudgetMs?: number;
|
|
71
113
|
/** Env override for secret collection + budget resolution (tests). */
|
|
@@ -88,6 +130,65 @@ export declare function isSelfTestReadOnlyOperation(operation: OperationDefiniti
|
|
|
88
130
|
export declare function createSelfTestInvoke(app: {
|
|
89
131
|
request: (input: string, requestInit?: RequestInit) => Response | Promise<Response>;
|
|
90
132
|
}): SelfTestOperationInvoke;
|
|
133
|
+
/** Binds the self-test auth-flow driver to a tenant app's /auth pipeline in-process. */
|
|
134
|
+
export declare function createSelfTestAuthFlowInvoke(app: {
|
|
135
|
+
request: (input: string, requestInit?: RequestInit) => Response | Promise<Response>;
|
|
136
|
+
}): SelfTestAuthFlowInvoke;
|
|
137
|
+
/**
|
|
138
|
+
* How long a memoized multi-turn flow outcome suppresses re-driving the auth
|
|
139
|
+
* flow. Generous on purpose: a multi-turn ceremony (OTP, device approval) is a
|
|
140
|
+
* provider property that changes on the timescale of releases, not probe
|
|
141
|
+
* cycles, and every re-drive is a REAL upstream login submission. The cache is
|
|
142
|
+
* in-process, so a pod restart also clears the entry.
|
|
143
|
+
*/
|
|
144
|
+
export declare const SELF_TEST_MULTI_TURN_RETRY_AFTER_MS: number;
|
|
145
|
+
/**
|
|
146
|
+
* Age bound for POSITIVE cached credentials. Expiry modes that never produce
|
|
147
|
+
* a 401/403 (a 200 login page, an assertion failure) would otherwise replay
|
|
148
|
+
* the same stale session until pod restart — one re-login per day is the
|
|
149
|
+
* upstream-safe recovery for them.
|
|
150
|
+
*/
|
|
151
|
+
export declare const SELF_TEST_CREDENTIAL_MAX_AGE_MS: number;
|
|
152
|
+
export type SelfTestCredentialSessionEntry =
|
|
153
|
+
/** Flow-materialized credential reused across probe cycles. */
|
|
154
|
+
{
|
|
155
|
+
kind: "credential";
|
|
156
|
+
credential: Record<string, string>;
|
|
157
|
+
cachedAtMs: number;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Negative entry: the flow did not complete in a single continue turn
|
|
161
|
+
* (`auth_flow_multi_turn`). Memoized so subsequent cycles report the skip
|
|
162
|
+
* WITHOUT contacting the upstream again — the first attempt already
|
|
163
|
+
* submitted real credentials (and may have triggered an OTP send).
|
|
164
|
+
*/
|
|
165
|
+
| {
|
|
166
|
+
kind: "multi_turn";
|
|
167
|
+
cachedAtMs: number;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Negative entry: the flow REJECTED the submitted credential inputs
|
|
171
|
+
* (`retry` turn after continue — bad password, exchange failure).
|
|
172
|
+
* Memoized so the probe does not re-submit rejected credentials every
|
|
173
|
+
* cycle; a new entry is attempted when the inputs rotate (new hash),
|
|
174
|
+
* the TTL lapses, or the process restarts.
|
|
175
|
+
*/
|
|
176
|
+
| {
|
|
177
|
+
kind: "rejected";
|
|
178
|
+
cachedAtMs: number;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* In-process cache of per-(providerId + stable hash of credentialInputs) auth
|
|
182
|
+
* flow outcomes, so consecutive probe cycles reuse the session — or the
|
|
183
|
+
* memoized multi-turn skip — instead of logging in every cycle (upstream
|
|
184
|
+
* account safety, DR-7). Credential entries are invalidated on a probe auth
|
|
185
|
+
* failure, at most once; multi-turn entries expire after
|
|
186
|
+
* `SELF_TEST_MULTI_TURN_RETRY_AFTER_MS` or on process restart. Flow ERRORS
|
|
187
|
+
* (transport/protocol failures, thrown start/continue) are deliberately NEVER
|
|
188
|
+
* cached: they are typically transient, and retrying a failed request next
|
|
189
|
+
* cycle is not a repeated login submission.
|
|
190
|
+
*/
|
|
191
|
+
export type SelfTestCredentialSessionCache = Map<string, SelfTestCredentialSessionEntry>;
|
|
91
192
|
export declare function resolveSelfTestPort(env?: Readonly<Record<string, string | undefined>>): number;
|
|
92
193
|
/**
|
|
93
194
|
* Builds the internal self-test Hono app. This app is served on a SEPARATE
|