@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
package/dist/ceremonies/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
2
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
3
|
-
import { AUTH_TURN_SCHEMA } from "../auth-turn";
|
|
4
|
-
import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors";
|
|
3
|
+
import { AUTH_TURN_SCHEMA } from "../auth-turn/index.js";
|
|
4
|
+
import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors.js";
|
|
5
5
|
const ajv = new Ajv2020({ allErrors: true, strict: true, strictSchema: true });
|
|
6
6
|
// Runtime ceremony-output validation derives from the exported versioned
|
|
7
7
|
// contract: it compiles the exact AUTH_TURN_SCHEMA document shipped at
|
|
@@ -9,6 +9,15 @@ const ajv = new Ajv2020({ allErrors: true, strict: true, strictSchema: true });
|
|
|
9
9
|
const validateAuthTurn = ajv.compile(AUTH_TURN_SCHEMA);
|
|
10
10
|
const OAUTH2_STATE_KEY = "__oauth2_state";
|
|
11
11
|
const OAUTH2_PKCE_VERIFIER_KEY = "__oauth2_pkce_verifier";
|
|
12
|
+
export const OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY = "APIFUSE__AUTH_PROXY__URL";
|
|
13
|
+
export const OAUTH2_PROXIED_PKCE_VERIFIER_KEY = "__oauth2_proxied_pkce_verifier";
|
|
14
|
+
const OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS = new Set([
|
|
15
|
+
"client_id",
|
|
16
|
+
"response_type",
|
|
17
|
+
"state",
|
|
18
|
+
"code_challenge",
|
|
19
|
+
"code_challenge_method",
|
|
20
|
+
]);
|
|
12
21
|
const DEVICE_FLOW_KEY = "__device_flow";
|
|
13
22
|
const MAGIC_LINK_KEY = "__magic_link";
|
|
14
23
|
const COMBINED_STAGE_KEY = "__combined_stage";
|
|
@@ -38,11 +47,7 @@ function getRequiredEnv(ctx, key) {
|
|
|
38
47
|
return value;
|
|
39
48
|
}
|
|
40
49
|
function toBase64Url(input) {
|
|
41
|
-
return input
|
|
42
|
-
.toString("base64")
|
|
43
|
-
.replace(/\+/g, "-")
|
|
44
|
-
.replace(/\//g, "_")
|
|
45
|
-
.replace(/=+$/g, "");
|
|
50
|
+
return input.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
46
51
|
}
|
|
47
52
|
function createCodeVerifier() {
|
|
48
53
|
return toBase64Url(randomBytes(32));
|
|
@@ -100,8 +105,7 @@ function withDeclaredFormFieldOrder(expectedInput) {
|
|
|
100
105
|
return expectedInput;
|
|
101
106
|
}
|
|
102
107
|
const existingOrder = expectedInput[FORM_FIELD_ORDER_EXTENSION];
|
|
103
|
-
if (Array.isArray(existingOrder) &&
|
|
104
|
-
existingOrder.every((value) => typeof value === "string")) {
|
|
108
|
+
if (Array.isArray(existingOrder) && existingOrder.every((value) => typeof value === "string")) {
|
|
105
109
|
return expectedInput;
|
|
106
110
|
}
|
|
107
111
|
return {
|
|
@@ -178,6 +182,54 @@ export function createOAuth2Ceremony(options) {
|
|
|
178
182
|
abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "OAuth flow aborted." })),
|
|
179
183
|
};
|
|
180
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Builds the start handler for a custom-scheme OAuth provider. The shared
|
|
187
|
+
* auth-proxy owns state minting and callback capture, while the provider owns
|
|
188
|
+
* token exchange and any following authentication turns.
|
|
189
|
+
*/
|
|
190
|
+
export function createOAuth2ProxiedStart(options) {
|
|
191
|
+
const pkce = options.pkce ?? "S256";
|
|
192
|
+
return (ctx) => runCeremonyHandler(async () => {
|
|
193
|
+
for (const key of Object.keys(options.authorizeParams ?? {})) {
|
|
194
|
+
if (OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS.has(key.toLowerCase())) {
|
|
195
|
+
throw new ValidationError(`OAuth2 proxied authorizeParams cannot override reserved parameter "${key}".`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const proxyOrigin = ctx.env.get(OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY);
|
|
199
|
+
if (!proxyOrigin) {
|
|
200
|
+
throw new ProviderSecretError(`Missing required platform environment: ${OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY}`);
|
|
201
|
+
}
|
|
202
|
+
const clientId = getRequiredEnv(ctx, options.clientIdEnvKey);
|
|
203
|
+
if (!ctx.flowId) {
|
|
204
|
+
throw new ValidationError("OAuth2 proxied start requires the gateway flow id.");
|
|
205
|
+
}
|
|
206
|
+
const authorizePath = new URL(options.authorizeUrl).pathname;
|
|
207
|
+
const url = new URL(`/p/${encodeURIComponent(ctx.providerId)}/f/${encodeURIComponent(ctx.flowId)}${authorizePath}`, proxyOrigin);
|
|
208
|
+
url.searchParams.set("client_id", clientId);
|
|
209
|
+
url.searchParams.set("response_type", "code");
|
|
210
|
+
if (pkce === "S256") {
|
|
211
|
+
const verifier = createCodeVerifier();
|
|
212
|
+
ctx.context.set(OAUTH2_PROXIED_PKCE_VERIFIER_KEY, verifier);
|
|
213
|
+
url.searchParams.set("code_challenge", createCodeChallenge(verifier));
|
|
214
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
215
|
+
}
|
|
216
|
+
for (const [key, value] of Object.entries(options.authorizeParams ?? {})) {
|
|
217
|
+
url.searchParams.set(key, value);
|
|
218
|
+
}
|
|
219
|
+
return createTurn("redirect", {
|
|
220
|
+
data: { url: url.toString() },
|
|
221
|
+
hint: "Open the provider authorization page to continue.",
|
|
222
|
+
expectedInput: {
|
|
223
|
+
type: "object",
|
|
224
|
+
required: ["code", "state"],
|
|
225
|
+
properties: {
|
|
226
|
+
code: { type: "string" },
|
|
227
|
+
state: { type: "string" },
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}, "OAuth2 proxied start failed", ctx);
|
|
232
|
+
}
|
|
181
233
|
export function createDeviceFlowCeremony(options) {
|
|
182
234
|
return {
|
|
183
235
|
start: (ctx) => runCeremonyHandler(async () => {
|
|
@@ -218,8 +270,7 @@ export function createDeviceFlowCeremony(options) {
|
|
|
218
270
|
});
|
|
219
271
|
const data = ensureRecord(response.data);
|
|
220
272
|
const errorCode = getString(data, "error");
|
|
221
|
-
if (errorCode === "authorization_pending" ||
|
|
222
|
-
errorCode === "slow_down") {
|
|
273
|
+
if (errorCode === "authorization_pending" || errorCode === "slow_down") {
|
|
223
274
|
return createTurn("poll", {
|
|
224
275
|
data,
|
|
225
276
|
hint: "Authorization pending.",
|
|
@@ -345,7 +396,7 @@ export function createFormCeremony(options) {
|
|
|
345
396
|
return {
|
|
346
397
|
start: async () => validateCeremonyOutput(buildJsonSchemaForm(options.schema, options.hint ?? "Provide the required input to continue.")),
|
|
347
398
|
continue: (ctx, input = {}) => runCeremonyHandler(async () => {
|
|
348
|
-
const { prevalidate } = await import("../runtime/prevalidate");
|
|
399
|
+
const { prevalidate } = await import("../runtime/prevalidate.js");
|
|
349
400
|
const result = prevalidate(options.schema, input);
|
|
350
401
|
if (!result.valid) {
|
|
351
402
|
throw new ValidationError("Form input failed validation.", {
|
|
@@ -354,9 +405,7 @@ export function createFormCeremony(options) {
|
|
|
354
405
|
}
|
|
355
406
|
return createTurn("complete", {
|
|
356
407
|
data: {
|
|
357
|
-
credential: options.mapCredential
|
|
358
|
-
? options.mapCredential(input)
|
|
359
|
-
: input,
|
|
408
|
+
credential: options.mapCredential ? options.mapCredential(input) : input,
|
|
360
409
|
},
|
|
361
410
|
hint: "Form completed.",
|
|
362
411
|
});
|
|
@@ -428,9 +477,7 @@ export function createSwitchCeremony(options) {
|
|
|
428
477
|
})),
|
|
429
478
|
continue: (ctx, input = {}) => runCeremonyHandler(async () => {
|
|
430
479
|
const storedChoice = ctx.context.get(SWITCH_SELECTION_KEY);
|
|
431
|
-
const choice = typeof storedChoice === "string"
|
|
432
|
-
? storedChoice
|
|
433
|
-
: getString(input, "choice");
|
|
480
|
+
const choice = typeof storedChoice === "string" ? storedChoice : getString(input, "choice");
|
|
434
481
|
if (!choice || !options.choices[choice]) {
|
|
435
482
|
throw new ValidationError("A valid choice is required.");
|
|
436
483
|
}
|
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" | "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,13 @@ 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
|
+
},
|
|
26
33
|
"submit-check": {
|
|
27
34
|
name: "submit-check",
|
|
28
35
|
summary: "Score provider bounty submission readiness and emit checklist evidence.",
|
|
@@ -73,6 +80,7 @@ export const COMMAND_ORDER = [
|
|
|
73
80
|
"create",
|
|
74
81
|
"dev",
|
|
75
82
|
"check",
|
|
83
|
+
"sync-assets",
|
|
76
84
|
"submit-check",
|
|
77
85
|
"record",
|
|
78
86
|
"test",
|
package/dist/cli/create.d.ts
CHANGED
|
@@ -26,7 +26,10 @@ export type CreateResolvedOptions = {
|
|
|
26
26
|
};
|
|
27
27
|
export type ProviderPlanFile = {
|
|
28
28
|
path: string;
|
|
29
|
+
/** File content, or the symlink target (relative path) for kind "symlink". */
|
|
29
30
|
content: string;
|
|
31
|
+
/** Absent kind means "file" (backward compatible with older consumers). */
|
|
32
|
+
kind?: "file" | "symlink";
|
|
30
33
|
};
|
|
31
34
|
export type ProviderCreatePlan = {
|
|
32
35
|
displayName: string;
|
package/dist/cli/create.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, relative, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { cancel, intro, isCancel, note, outro, select, text } from "@clack/prompts";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import packageJson from "../../package.json";
|
|
9
|
+
import { buildPromptAssetManifest, buildPromptAssetPlanEntries, PROMPT_ASSET_MANIFEST_PATH, } from "./prompt-assets.js";
|
|
9
10
|
export const PROVIDER_NAME_REGEX = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
10
11
|
export const CATEGORY_OPTIONS = [
|
|
11
12
|
"developer-tools",
|
|
@@ -283,10 +284,15 @@ export async function buildProviderCreatePlan(options, cwd) {
|
|
|
283
284
|
if (options.sdkSpecifier?.startsWith("workspace:") && !resolvedWorkspaceRoot) {
|
|
284
285
|
throw new Error("workspace:* is only valid inside the APIFuse monorepo because public Provider SDK scaffolds must install from npm or an explicit tarball/file specifier.");
|
|
285
286
|
}
|
|
287
|
+
// Exact pin, not a caret range: the prompt-asset freshness gate requires
|
|
288
|
+
// manifest.sdkVersion === installed SDK version, and the manifest records
|
|
289
|
+
// this CLI's own version. A caret range would let `bun install` resolve a
|
|
290
|
+
// newer SDK than the create binary, making a fresh scaffold fail its own
|
|
291
|
+
// gate. `sync-assets` after an explicit SDK upgrade re-records the version.
|
|
286
292
|
const sdkSpecifier = options.sdkSpecifier ??
|
|
287
293
|
(options.preset === "monorepo" && resolvedWorkspaceRoot
|
|
288
294
|
? "workspace:*"
|
|
289
|
-
:
|
|
295
|
+
: packageJson.version);
|
|
290
296
|
const relativeProviderRoot = relative(cwd, providerRoot) || options.name;
|
|
291
297
|
const nextDevCommand = `cd ${relativeProviderRoot} && bun run dev`;
|
|
292
298
|
const packageName = options.preset === "monorepo"
|
|
@@ -405,39 +411,21 @@ export async function buildProviderCreatePlan(options, cwd) {
|
|
|
405
411
|
PROVIDER_ID: options.name,
|
|
406
412
|
}),
|
|
407
413
|
},
|
|
408
|
-
{
|
|
409
|
-
path: resolve(providerRoot, "AGENTS.md"),
|
|
410
|
-
content: await renderTemplate("AGENTS.md.tpl", {}),
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
path: resolve(providerRoot, "CLAUDE.md"),
|
|
414
|
-
content: await renderTemplate("CLAUDE.md.tpl", {}),
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
path: resolve(providerRoot, "skills", "normalization-standards", "SKILL.md"),
|
|
418
|
-
content: await renderTemplate("skills/normalization-standards/SKILL.md.tpl", {}),
|
|
419
|
-
},
|
|
420
|
-
{
|
|
421
|
-
path: resolve(providerRoot, "skills", "upstream-contract-verification", "SKILL.md"),
|
|
422
|
-
content: await renderTemplate("skills/upstream-contract-verification/SKILL.md.tpl", {}),
|
|
423
|
-
},
|
|
424
|
-
{
|
|
425
|
-
path: resolve(providerRoot, "skills", "fixtures-and-recording", "SKILL.md"),
|
|
426
|
-
content: await renderTemplate("skills/fixtures-and-recording/SKILL.md.tpl", {}),
|
|
427
|
-
},
|
|
428
|
-
{
|
|
429
|
-
path: resolve(providerRoot, "skills", "pagination-and-counts", "SKILL.md"),
|
|
430
|
-
content: await renderTemplate("skills/pagination-and-counts/SKILL.md.tpl", {}),
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
path: resolve(providerRoot, "skills", "health-checks-and-fail-closed", "SKILL.md"),
|
|
434
|
-
content: await renderTemplate("skills/health-checks-and-fail-closed/SKILL.md.tpl", {}),
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
path: resolve(providerRoot, "skills", "upstream-notes", "README.md"),
|
|
438
|
-
content: await renderTemplate("skills/upstream-notes/README.md.tpl", {}),
|
|
439
|
-
},
|
|
440
414
|
];
|
|
415
|
+
const promptAssetEntries = await buildPromptAssetPlanEntries(renderTemplate);
|
|
416
|
+
for (const entry of promptAssetEntries) {
|
|
417
|
+
files.push({
|
|
418
|
+
path: resolve(providerRoot, entry.path),
|
|
419
|
+
content: entry.content,
|
|
420
|
+
...(entry.kind === "symlink" ? { kind: "symlink" } : {}),
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
// Manifest last: writePlan writes in order, so a crash mid-scaffold never
|
|
424
|
+
// leaves a manifest that claims assets which were not written.
|
|
425
|
+
files.push({
|
|
426
|
+
path: resolve(providerRoot, PROMPT_ASSET_MANIFEST_PATH),
|
|
427
|
+
content: buildPromptAssetManifest(promptAssetEntries, packageJson.version),
|
|
428
|
+
});
|
|
441
429
|
return {
|
|
442
430
|
displayName: options.displayName,
|
|
443
431
|
files,
|
|
@@ -477,6 +465,7 @@ function renderPackageJson(input) {
|
|
|
477
465
|
check: "apifuse check . && bun run type-check",
|
|
478
466
|
"type-check": "tsc --noEmit",
|
|
479
467
|
"submit-check": "apifuse submit-check . --markdown submission-report.md",
|
|
468
|
+
"sync-assets": "apifuse sync-assets .",
|
|
480
469
|
test: "apifuse test .",
|
|
481
470
|
record: "apifuse record .",
|
|
482
471
|
start: "bun start.ts",
|
|
@@ -696,6 +685,13 @@ function isApifuseInternalWorkspaceRoot(workspaceRoot) {
|
|
|
696
685
|
async function writePlan(plan) {
|
|
697
686
|
for (const file of plan.files) {
|
|
698
687
|
await mkdir(dirname(file.path), { recursive: true });
|
|
688
|
+
if (file.kind === "symlink") {
|
|
689
|
+
// rm operates on the link itself (lstat semantics) and tolerates
|
|
690
|
+
// directories, so whatever occupies the path is replaced by the link.
|
|
691
|
+
await rm(file.path, { recursive: true, force: true });
|
|
692
|
+
await symlink(file.content, file.path);
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
699
695
|
await writeFile(file.path, file.content);
|
|
700
696
|
}
|
|
701
697
|
}
|
|
@@ -754,7 +750,10 @@ function printResult(plan, jsonMode, dryRun) {
|
|
|
754
750
|
},
|
|
755
751
|
validationCommands: plan.validationCommands,
|
|
756
752
|
nextDevCommand: plan.nextDevCommand,
|
|
757
|
-
files: plan.files.map((file) =>
|
|
753
|
+
files: plan.files.map((file) => {
|
|
754
|
+
const relativePath = relative(plan.providerRoot, file.path) || file.path;
|
|
755
|
+
return file.kind === "symlink" ? `${relativePath} -> ${file.content} (symlink)` : relativePath;
|
|
756
|
+
}),
|
|
758
757
|
};
|
|
759
758
|
if (jsonMode) {
|
|
760
759
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK-managed agent prompt assets.
|
|
3
|
+
*
|
|
4
|
+
* `apifuse create` scaffolds these files, `apifuse sync-assets` regenerates
|
|
5
|
+
* them in an existing provider root, and `apifuse check` / `submit-check`
|
|
6
|
+
* enforce that they byte-match the installed SDK version (fail closed).
|
|
7
|
+
*
|
|
8
|
+
* Layout contract:
|
|
9
|
+
* - AGENTS.md — real file (agent guide)
|
|
10
|
+
* - CLAUDE.md — symlink -> AGENTS.md
|
|
11
|
+
* - .agents/skills/<skill>/SKILL.md — real files
|
|
12
|
+
* - .agents/skills/upstream-notes/README.md — real file
|
|
13
|
+
* - .claude / .codex — symlinks -> .agents
|
|
14
|
+
* - .apifuse/prompt-assets.json — manifest (schema v2), written last
|
|
15
|
+
*/
|
|
16
|
+
export declare const PROMPT_ASSET_MANIFEST_PATH = ".apifuse/prompt-assets.json";
|
|
17
|
+
export declare const PROMPT_ASSET_MANIFEST_SCHEMA_VERSION = 2;
|
|
18
|
+
export declare const PROMPT_ASSET_SYNC_REMEDIATION = "Run `bun run sync-assets` (or `bunx apifuse sync-assets .`) to regenerate the SDK-managed agent prompt assets.";
|
|
19
|
+
export declare const PROMPT_ASSET_SYMLINKS: Readonly<Record<string, string>>;
|
|
20
|
+
/** Relative asset paths whose content is rendered from `<path>.tpl`. */
|
|
21
|
+
export declare const PROMPT_ASSET_FILE_PATHS: readonly string[];
|
|
22
|
+
export type PromptAssetKind = "file" | "symlink";
|
|
23
|
+
export type PromptAssetEntry = {
|
|
24
|
+
/** Provider-root-relative path (POSIX separators). */
|
|
25
|
+
path: string;
|
|
26
|
+
/** File content, or the symlink target for kind "symlink". */
|
|
27
|
+
content: string;
|
|
28
|
+
kind: PromptAssetKind;
|
|
29
|
+
};
|
|
30
|
+
export type PromptAssetTemplateRenderer = (fileName: string, values: Record<string, string>) => string | Promise<string>;
|
|
31
|
+
export type PromptAssetVerification = {
|
|
32
|
+
ok: boolean;
|
|
33
|
+
/** Expected paths (or the manifest) absent on disk. */
|
|
34
|
+
missing: string[];
|
|
35
|
+
/** Manifest recorded for a different SDK version than the installed one. */
|
|
36
|
+
stale: string[];
|
|
37
|
+
/** Files/symlinks/manifest whose bytes or target differ from the regenerated set. */
|
|
38
|
+
modified: string[];
|
|
39
|
+
/** Legacy layout remnants (top-level skills/). */
|
|
40
|
+
legacy: string[];
|
|
41
|
+
/** Entries inside `.agents/` that are not part of the managed asset set. */
|
|
42
|
+
unexpected: string[];
|
|
43
|
+
};
|
|
44
|
+
export type PromptAssetSyncResult = {
|
|
45
|
+
changed: boolean;
|
|
46
|
+
removed: string[];
|
|
47
|
+
wroteFiles: string[];
|
|
48
|
+
createdSymlinks: string[];
|
|
49
|
+
manifestPath: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Build the full managed asset entry list (files first, symlinks after,
|
|
53
|
+
* manifest excluded). The renderer is injected so `apifuse create` can reuse
|
|
54
|
+
* its own template renderer; sync/verify use the SDK-internal renderer.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildPromptAssetPlanEntries(renderTemplate: PromptAssetTemplateRenderer): Promise<PromptAssetEntry[]>;
|
|
57
|
+
export declare function buildPromptAssetPlanEntriesSync(): PromptAssetEntry[];
|
|
58
|
+
/**
|
|
59
|
+
* Deterministic manifest serialization: schema v2, 2-space JSON, trailing
|
|
60
|
+
* newline, sorted paths (including symlink paths, excluding the manifest
|
|
61
|
+
* itself). `sdkVersion` + `paths` keep their v1 semantics so older parsers
|
|
62
|
+
* keep working; `schemaVersion` and `symlinks` are additive.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildPromptAssetManifest(entries: readonly PromptAssetEntry[], sdkVersion: string): string;
|
|
65
|
+
export declare function installedSdkVersion(): string;
|
|
66
|
+
/**
|
|
67
|
+
* Verify the on-disk prompt assets against the set regenerated from the
|
|
68
|
+
* installed SDK. Uses lstat/readlink for symlinks (never follows), byte
|
|
69
|
+
* comparison for files, and exact-version comparison for the manifest.
|
|
70
|
+
*/
|
|
71
|
+
export declare function verifyPromptAssets(providerRoot: string): PromptAssetVerification;
|
|
72
|
+
export declare function formatPromptAssetIssues(verification: PromptAssetVerification): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Regenerate the full managed asset set for the installed SDK version in an
|
|
75
|
+
* existing provider root. Deletes legacy managed paths first (top-level
|
|
76
|
+
* skills/**, plus manifest-listed paths that left the set — restricted to
|
|
77
|
+
* managed namespaces with no symlinked ancestors), writes files, replaces
|
|
78
|
+
* symlinks, and writes the manifest last. Idempotent.
|
|
79
|
+
*/
|
|
80
|
+
export declare function syncPromptAssets(providerRoot: string): PromptAssetSyncResult;
|