@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.31
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 +493 -5
- package/CHANGELOG.md +131 -1
- package/README.md +52 -6
- package/SUBMISSION.md +1 -1
- package/bin/apifuse-check.ts +106 -62
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +63 -55
- package/bin/apifuse-pack-check.ts +22 -2
- package/bin/apifuse-pack-smoke.ts +78 -82
- package/bin/apifuse-pack-types.ts +583 -0
- package/bin/apifuse-perf.ts +59 -140
- package/bin/apifuse-record.ts +698 -113
- package/bin/apifuse-submit-check.ts +517 -44
- 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.ts +1 -1
- package/dist/auth-turn/index.d.ts +4 -4
- package/dist/auth-turn/index.js +1 -1
- package/dist/auth.d.ts +16 -2
- package/dist/auth.js +76 -18
- package/dist/ceremonies/index.d.ts +9 -1
- package/dist/ceremonies/index.js +117 -29
- 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/cli/templates/provider/README.md.tpl +4 -4
- package/dist/config/loader.d.ts +176 -17
- package/dist/config/loader.js +434 -161
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +7 -14
- package/dist/contract-types.d.ts +3 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +6 -6
- package/dist/declaration-validation.d.ts +23 -0
- package/dist/declaration-validation.js +159 -0
- package/dist/define.d.ts +13 -1
- package/dist/define.js +391 -122
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/error-resolution.d.ts +4 -0
- package/dist/error-resolution.js +123 -0
- package/dist/errors.d.ts +19 -1
- package/dist/errors.js +41 -3
- 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 +50 -42
- package/dist/index.js +41 -37
- package/dist/lint.d.ts +6 -1
- package/dist/lint.js +370 -18
- 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 +13 -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 +3 -1
- package/dist/runtime/auth-flow.js +8 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +138 -40
- package/dist/runtime/cache.d.ts +2 -1
- package/dist/runtime/cache.js +173 -23
- package/dist/runtime/choice-wordlist.d.ts +9 -0
- package/dist/runtime/choice-wordlist.js +138 -0
- package/dist/runtime/choice.d.ts +14 -1
- package/dist/runtime/choice.js +566 -101
- 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 +25 -3
- package/dist/runtime/http.d.ts +3 -2
- package/dist/runtime/http.js +517 -55
- 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 +371 -23
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/native-network-errors.d.ts +33 -0
- package/dist/runtime/native-network-errors.js +69 -0
- package/dist/runtime/native-network.d.ts +96 -0
- package/dist/runtime/native-network.js +1232 -0
- package/dist/runtime/ocr.d.ts +29 -0
- package/dist/runtime/ocr.js +440 -0
- package/dist/runtime/otlp.d.ts +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 +58 -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 +5 -5
- package/dist/runtime/request-options.d.ts +68 -1
- package/dist/runtime/request-options.js +548 -0
- package/dist/runtime/resolver-config.d.ts +6 -0
- package/dist/runtime/resolver-config.js +6 -0
- package/dist/runtime/resolver-public.d.ts +1 -0
- package/dist/runtime/resolver-public.js +1 -0
- package/dist/runtime/resolver-shared.d.ts +3 -0
- package/dist/runtime/resolver-shared.js +12 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +48 -0
- package/dist/runtime/resolver-vendors/bindings.js +40 -0
- package/dist/runtime/resolver-vendors/browser.d.ts +20 -0
- package/dist/runtime/resolver-vendors/browser.js +282 -0
- package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
- package/dist/runtime/resolver-vendors/hosts.js +33 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
- package/dist/runtime/resolver-vendors/twocaptcha.js +368 -0
- package/dist/runtime/resolver-vendors/types.d.ts +83 -0
- package/dist/runtime/resolver-vendors/types.js +69 -0
- package/dist/runtime/resolver.d.ts +59 -0
- package/dist/runtime/resolver.js +705 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +5 -2
- package/dist/runtime/state.js +280 -74
- package/dist/runtime/stealth-cookies.d.ts +20 -0
- package/dist/runtime/stealth-cookies.js +111 -0
- package/dist/runtime/stealth.d.ts +30 -5
- package/dist/runtime/stealth.js +523 -259
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +12 -27
- package/dist/runtime/timeout.d.ts +5 -0
- package/dist/runtime/timeout.js +12 -0
- 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 +117 -3
- package/dist/server/self-test.js +787 -151
- package/dist/server/serve-implementation.d.ts +210 -0
- package/dist/server/serve-implementation.js +2078 -0
- package/dist/server/serve.d.ts +1 -70
- package/dist/server/serve.js +1 -1143
- package/dist/server/types.d.ts +34 -9
- package/dist/server/types.js +8 -1
- package/dist/stateful/errors.d.ts +19 -0
- package/dist/stateful/errors.js +24 -0
- package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
- package/dist/stateful/http-provider-event-emitter.js +237 -0
- package/dist/stateful/http-session-owner-registry.d.ts +44 -0
- package/dist/stateful/http-session-owner-registry.js +210 -0
- package/dist/stateful/index.d.ts +18 -0
- package/dist/stateful/index.js +18 -0
- package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
- package/dist/stateful/provider-event-delivery-failures.js +43 -0
- package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
- package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
- package/dist/stateful/provider-event-pipeline.d.ts +50 -0
- package/dist/stateful/provider-event-pipeline.js +1 -0
- package/dist/stateful/provider-events.d.ts +101 -0
- package/dist/stateful/provider-events.js +289 -0
- package/dist/stateful/session-key.d.ts +15 -0
- package/dist/stateful/session-key.js +86 -0
- package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
- package/dist/stateful/stateful-provider-adapter-context.js +42 -0
- package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
- package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
- package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
- package/dist/stateful/stateful-provider-adapter.js +287 -0
- package/dist/stateful/stateful-provider-observability.d.ts +62 -0
- package/dist/stateful/stateful-provider-observability.js +161 -0
- package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
- package/dist/stateful/stateful-provider-runtime-context.js +60 -0
- package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
- package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
- package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
- package/dist/stateful/stateful-provider-session-routing.js +345 -0
- package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
- package/dist/stateful/stateful-provider-session-runtime.js +245 -0
- package/dist/stateful-signing.d.ts +18 -0
- package/dist/stateful-signing.js +27 -0
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +21 -21
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.d.ts +1 -1
- package/dist/stream.js +7 -1
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.js +3 -2
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +488 -28
- package/dist/types.d.ts +566 -19
- package/dist/types.js +1 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +42 -7
- package/src/auth-turn/index.ts +2 -2
- package/src/auth.ts +146 -86
- package/src/ceremonies/index.ts +167 -92
- 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/cli/templates/provider/README.md.tpl +4 -4
- package/src/config/loader.ts +667 -289
- package/src/contract-serialization.ts +10 -18
- package/src/contract-types.ts +3 -2
- package/src/contract.ts +14 -28
- package/src/declaration-validation.ts +202 -0
- package/src/define.ts +631 -495
- package/src/dev.ts +4 -9
- package/src/error-resolution.ts +128 -0
- package/src/errors.ts +56 -11
- 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 +158 -44
- package/src/lint.ts +488 -154
- 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 +13 -7
- package/src/runtime/browser.ts +252 -207
- package/src/runtime/cache.ts +209 -81
- package/src/runtime/choice-wordlist.ts +145 -0
- package/src/runtime/choice.ts +758 -197
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +37 -19
- package/src/runtime/http.ts +645 -65
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +530 -67
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/native-network-errors.ts +99 -0
- package/src/runtime/native-network.ts +1605 -0
- package/src/runtime/ocr.ts +523 -0
- package/src/runtime/otlp.ts +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 +84 -77
- package/src/runtime/redirects.ts +66 -0
- package/src/runtime/redis.ts +10 -13
- package/src/runtime/request-options.ts +679 -9
- package/src/runtime/resolver-config.ts +6 -0
- package/src/runtime/resolver-public.ts +18 -0
- package/src/runtime/resolver-shared.ts +17 -0
- package/src/runtime/resolver-vendors/bindings.ts +56 -0
- package/src/runtime/resolver-vendors/browser.ts +408 -0
- package/src/runtime/resolver-vendors/hosts.ts +38 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +500 -0
- package/src/runtime/resolver-vendors/types.ts +173 -0
- package/src/runtime/resolver.ts +1060 -0
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +399 -161
- package/src/runtime/stealth-cookies.ts +132 -0
- package/src/runtime/stealth.ts +681 -295
- package/src/runtime/stt.ts +39 -113
- package/src/runtime/timeout.ts +18 -0
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +6 -1
- package/src/server/index.ts +30 -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 +1030 -180
- package/src/server/serve-implementation.ts +3062 -0
- package/src/server/serve.ts +1 -1781
- package/src/server/types.ts +12 -13
- package/src/stateful/README.md +146 -0
- package/src/stateful/errors.ts +35 -0
- package/src/stateful/http-provider-event-emitter.ts +314 -0
- package/src/stateful/http-session-owner-registry.ts +306 -0
- package/src/stateful/index.ts +18 -0
- package/src/stateful/provider-event-delivery-failures.ts +80 -0
- package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
- package/src/stateful/provider-event-pipeline.ts +61 -0
- package/src/stateful/provider-events.ts +462 -0
- package/src/stateful/session-key.ts +111 -0
- package/src/stateful/stateful-provider-adapter-context.ts +59 -0
- package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
- package/src/stateful/stateful-provider-adapter.ts +562 -0
- package/src/stateful/stateful-provider-observability.ts +261 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
- package/src/stateful/stateful-provider-runtime-context.ts +92 -0
- package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
- package/src/stateful/stateful-provider-session-routing.ts +546 -0
- package/src/stateful/stateful-provider-session-runtime.ts +403 -0
- package/src/stateful-signing.ts +46 -0
- package/src/stealth/profiles.ts +27 -33
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +16 -20
- package/src/testing/index.ts +11 -2
- package/src/testing/run.ts +668 -74
- package/src/types.ts +665 -35
- 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/src/ceremonies/index.ts
CHANGED
|
@@ -1,36 +1,39 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import { AUTH_TURN_SCHEMA, type KnownAuthTurnKind } from "../auth-turn";
|
|
3
|
+
import { AUTH_TURN_SCHEMA, type KnownAuthTurnKind } from "../auth-turn/index.js";
|
|
6
4
|
import {
|
|
7
5
|
FlowExpiredError,
|
|
8
6
|
ProviderSecretError,
|
|
9
7
|
TurnValidationError,
|
|
10
8
|
ValidationError,
|
|
11
|
-
} from "../errors";
|
|
12
|
-
import type {
|
|
13
|
-
AuthFlowDefinition,
|
|
14
|
-
AuthFlowInputHandler,
|
|
15
|
-
AuthTurn,
|
|
16
|
-
FlowContext,
|
|
17
|
-
} from "../types";
|
|
9
|
+
} from "../errors.js";
|
|
10
|
+
import type { AuthFlowDefinition, AuthFlowInputHandler, AuthTurn, FlowContext } from "../types.js";
|
|
18
11
|
|
|
19
12
|
type TurnKind = KnownAuthTurnKind;
|
|
20
13
|
|
|
21
14
|
type CeremonyHandler = AuthFlowInputHandler;
|
|
22
15
|
|
|
23
16
|
type JsonObject = Record<string, unknown>;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
type JsonSchemaNode = {
|
|
18
|
+
readonly additionalProperties?: boolean;
|
|
19
|
+
readonly minimum?: number;
|
|
20
|
+
readonly minLength?: number;
|
|
21
|
+
readonly properties?: Readonly<Record<string, JsonSchemaNode>>;
|
|
22
|
+
readonly required?: readonly string[];
|
|
23
|
+
readonly type?: "number" | "object" | "string";
|
|
24
|
+
};
|
|
31
25
|
|
|
32
26
|
const OAUTH2_STATE_KEY = "__oauth2_state";
|
|
33
27
|
const OAUTH2_PKCE_VERIFIER_KEY = "__oauth2_pkce_verifier";
|
|
28
|
+
export const OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY = "APIFUSE__AUTH_PROXY__URL";
|
|
29
|
+
export const OAUTH2_PROXIED_PKCE_VERIFIER_KEY = "__oauth2_proxied_pkce_verifier";
|
|
30
|
+
const OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS = new Set([
|
|
31
|
+
"client_id",
|
|
32
|
+
"response_type",
|
|
33
|
+
"state",
|
|
34
|
+
"code_challenge",
|
|
35
|
+
"code_challenge_method",
|
|
36
|
+
]);
|
|
34
37
|
const DEVICE_FLOW_KEY = "__device_flow";
|
|
35
38
|
const MAGIC_LINK_KEY = "__magic_link";
|
|
36
39
|
const COMBINED_STAGE_KEY = "__combined_stage";
|
|
@@ -41,14 +44,61 @@ function isRecord(value: unknown): value is JsonObject {
|
|
|
41
44
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
function validateSchemaNode(
|
|
48
|
+
value: unknown,
|
|
49
|
+
schema: JsonSchemaNode,
|
|
50
|
+
path: string,
|
|
51
|
+
errors: string[],
|
|
52
|
+
): void {
|
|
53
|
+
if (schema.type === "object") {
|
|
54
|
+
if (!isRecord(value)) {
|
|
55
|
+
errors.push(`${path} must be object`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const properties = schema.properties ?? {};
|
|
59
|
+
for (const required of schema.required ?? []) {
|
|
60
|
+
if (!Object.hasOwn(value, required) || value[required] === undefined) {
|
|
61
|
+
errors.push(`${path} must have required property '${required}'`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (schema.additionalProperties === false) {
|
|
65
|
+
for (const key of Object.keys(value)) {
|
|
66
|
+
if (!Object.hasOwn(properties, key)) {
|
|
67
|
+
errors.push(`${path} must NOT have additional property '${key}'`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const [key, childSchema] of Object.entries(properties)) {
|
|
72
|
+
if (Object.hasOwn(value, key) && value[key] !== undefined) {
|
|
73
|
+
validateSchemaNode(value[key], childSchema, `${path}/${key}`, errors);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (schema.type === "string") {
|
|
80
|
+
if (typeof value !== "string") {
|
|
81
|
+
errors.push(`${path} must be string`);
|
|
82
|
+
} else if (schema.minLength !== undefined && value.length < schema.minLength) {
|
|
83
|
+
errors.push(`${path} must NOT have fewer than ${schema.minLength} characters`);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (schema.type === "number") {
|
|
89
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
90
|
+
errors.push(`${path} must be number`);
|
|
91
|
+
} else if (schema.minimum !== undefined && value < schema.minimum) {
|
|
92
|
+
errors.push(`${path} must be >= ${schema.minimum}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
44
97
|
function ensureRecord(value: unknown): JsonObject {
|
|
45
98
|
return isRecord(value) ? value : {};
|
|
46
99
|
}
|
|
47
100
|
|
|
48
|
-
function createTurn(
|
|
49
|
-
kind: TurnKind,
|
|
50
|
-
options: Omit<AuthTurn, "kind" | "turnId"> = {},
|
|
51
|
-
): AuthTurn {
|
|
101
|
+
function createTurn(kind: TurnKind, options: Omit<AuthTurn, "kind" | "turnId"> = {}): AuthTurn {
|
|
52
102
|
return {
|
|
53
103
|
kind,
|
|
54
104
|
turnId: randomUUID(),
|
|
@@ -69,11 +119,7 @@ function getRequiredEnv(ctx: FlowContext, key: string): string {
|
|
|
69
119
|
}
|
|
70
120
|
|
|
71
121
|
function toBase64Url(input: Buffer): string {
|
|
72
|
-
return input
|
|
73
|
-
.toString("base64")
|
|
74
|
-
.replace(/\+/g, "-")
|
|
75
|
-
.replace(/\//g, "_")
|
|
76
|
-
.replace(/=+$/g, "");
|
|
122
|
+
return input.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
77
123
|
}
|
|
78
124
|
|
|
79
125
|
function createCodeVerifier(): string {
|
|
@@ -130,10 +176,7 @@ async function runCeremonyHandler(
|
|
|
130
176
|
}
|
|
131
177
|
}
|
|
132
178
|
|
|
133
|
-
function getString(
|
|
134
|
-
input: Record<string, unknown>,
|
|
135
|
-
key: string,
|
|
136
|
-
): string | undefined {
|
|
179
|
+
function getString(input: Record<string, unknown>, key: string): string | undefined {
|
|
137
180
|
const value = input[key];
|
|
138
181
|
return typeof value === "string" ? value : undefined;
|
|
139
182
|
}
|
|
@@ -142,10 +185,7 @@ function getNestedRecord(ctx: FlowContext, key: string): JsonObject {
|
|
|
142
185
|
return ensureRecord(ctx.context.get(key));
|
|
143
186
|
}
|
|
144
187
|
|
|
145
|
-
function buildJsonSchemaForm(
|
|
146
|
-
expectedInput: JsonObject,
|
|
147
|
-
hint: string,
|
|
148
|
-
): AuthTurn {
|
|
188
|
+
function buildJsonSchemaForm(expectedInput: JsonObject, hint: string): AuthTurn {
|
|
149
189
|
return createTurn("form", {
|
|
150
190
|
hint,
|
|
151
191
|
expectedInput: withDeclaredFormFieldOrder(expectedInput),
|
|
@@ -160,10 +200,7 @@ function withDeclaredFormFieldOrder(expectedInput: JsonObject): JsonObject {
|
|
|
160
200
|
}
|
|
161
201
|
|
|
162
202
|
const existingOrder = expectedInput[FORM_FIELD_ORDER_EXTENSION];
|
|
163
|
-
if (
|
|
164
|
-
Array.isArray(existingOrder) &&
|
|
165
|
-
existingOrder.every((value) => typeof value === "string")
|
|
166
|
-
) {
|
|
203
|
+
if (Array.isArray(existingOrder) && existingOrder.every((value) => typeof value === "string")) {
|
|
167
204
|
return expectedInput;
|
|
168
205
|
}
|
|
169
206
|
|
|
@@ -174,16 +211,17 @@ function withDeclaredFormFieldOrder(expectedInput: JsonObject): JsonObject {
|
|
|
174
211
|
}
|
|
175
212
|
|
|
176
213
|
export function validateCeremonyOutput(turn: unknown): AuthTurn {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
214
|
+
// Evaluate the exact exported versioned schema without eagerly initializing
|
|
215
|
+
// a general-purpose JSON Schema compiler in every provider process. Contract
|
|
216
|
+
// parity tests compare this focused evaluator with AJV over all fixtures and
|
|
217
|
+
// edge probes, so the runtime and shipped document remain locked together.
|
|
218
|
+
const errors: string[] = [];
|
|
219
|
+
validateSchemaNode(turn, AUTH_TURN_SCHEMA, "", errors);
|
|
220
|
+
if (errors.length > 0) {
|
|
221
|
+
throw new TurnValidationError(errors.join("; "));
|
|
184
222
|
}
|
|
185
223
|
|
|
186
|
-
return turn;
|
|
224
|
+
return turn as AuthTurn;
|
|
187
225
|
}
|
|
188
226
|
|
|
189
227
|
export function createOAuth2Ceremony(options: {
|
|
@@ -214,10 +252,7 @@ export function createOAuth2Ceremony(options: {
|
|
|
214
252
|
if (options.usePKCE) {
|
|
215
253
|
const verifier = createCodeVerifier();
|
|
216
254
|
ctx.context.set(OAUTH2_PKCE_VERIFIER_KEY, verifier);
|
|
217
|
-
authorizeUrl.searchParams.set(
|
|
218
|
-
"code_challenge",
|
|
219
|
-
createCodeChallenge(verifier),
|
|
220
|
-
);
|
|
255
|
+
authorizeUrl.searchParams.set("code_challenge", createCodeChallenge(verifier));
|
|
221
256
|
authorizeUrl.searchParams.set("code_challenge_method", "S256");
|
|
222
257
|
}
|
|
223
258
|
|
|
@@ -270,13 +305,78 @@ export function createOAuth2Ceremony(options: {
|
|
|
270
305
|
ctx,
|
|
271
306
|
input,
|
|
272
307
|
),
|
|
273
|
-
abort: async () =>
|
|
274
|
-
validateCeremonyOutput(
|
|
275
|
-
createTurn("abort", { hint: "OAuth flow aborted." }),
|
|
276
|
-
),
|
|
308
|
+
abort: async () => validateCeremonyOutput(createTurn("abort", { hint: "OAuth flow aborted." })),
|
|
277
309
|
};
|
|
278
310
|
}
|
|
279
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Builds the start handler for a custom-scheme OAuth provider. The shared
|
|
314
|
+
* auth-proxy owns state minting and callback capture, while the provider owns
|
|
315
|
+
* token exchange and any following authentication turns.
|
|
316
|
+
*/
|
|
317
|
+
export function createOAuth2ProxiedStart(
|
|
318
|
+
options: import("../types.js").ProxiedOAuthConfig,
|
|
319
|
+
): import("../types.js").AuthFlowStartHandler {
|
|
320
|
+
const pkce = options.pkce ?? "S256";
|
|
321
|
+
|
|
322
|
+
return (ctx) =>
|
|
323
|
+
runCeremonyHandler(
|
|
324
|
+
async () => {
|
|
325
|
+
for (const key of Object.keys(options.authorizeParams ?? {})) {
|
|
326
|
+
if (OAUTH2_PROXIED_RESERVED_AUTHORIZE_PARAMS.has(key.toLowerCase())) {
|
|
327
|
+
throw new ValidationError(
|
|
328
|
+
`OAuth2 proxied authorizeParams cannot override reserved parameter "${key}".`,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const proxyOrigin = ctx.env.get(OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY);
|
|
333
|
+
if (!proxyOrigin) {
|
|
334
|
+
throw new ProviderSecretError(
|
|
335
|
+
`Missing required platform environment: ${OAUTH2_PROXIED_AUTH_PROXY_ORIGIN_ENV_KEY}`,
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
const clientId = getRequiredEnv(ctx, options.clientIdEnvKey);
|
|
339
|
+
if (!ctx.flowId) {
|
|
340
|
+
throw new ValidationError("OAuth2 proxied start requires the gateway flow id.");
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const authorizePath = new URL(options.authorizeUrl).pathname;
|
|
344
|
+
const url = new URL(
|
|
345
|
+
`/p/${encodeURIComponent(ctx.providerId)}/f/${encodeURIComponent(ctx.flowId)}${authorizePath}`,
|
|
346
|
+
proxyOrigin,
|
|
347
|
+
);
|
|
348
|
+
url.searchParams.set("client_id", clientId);
|
|
349
|
+
url.searchParams.set("response_type", "code");
|
|
350
|
+
|
|
351
|
+
if (pkce === "S256") {
|
|
352
|
+
const verifier = createCodeVerifier();
|
|
353
|
+
ctx.context.set(OAUTH2_PROXIED_PKCE_VERIFIER_KEY, verifier);
|
|
354
|
+
url.searchParams.set("code_challenge", createCodeChallenge(verifier));
|
|
355
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
for (const [key, value] of Object.entries(options.authorizeParams ?? {})) {
|
|
359
|
+
url.searchParams.set(key, value);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return createTurn("redirect", {
|
|
363
|
+
data: { url: url.toString() },
|
|
364
|
+
hint: "Open the provider authorization page to continue.",
|
|
365
|
+
expectedInput: {
|
|
366
|
+
type: "object",
|
|
367
|
+
required: ["code", "state"],
|
|
368
|
+
properties: {
|
|
369
|
+
code: { type: "string" },
|
|
370
|
+
state: { type: "string" },
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
},
|
|
375
|
+
"OAuth2 proxied start failed",
|
|
376
|
+
ctx,
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
280
380
|
export function createDeviceFlowCeremony(options: {
|
|
281
381
|
deviceCodeUrl: string;
|
|
282
382
|
tokenUrl: string;
|
|
@@ -329,26 +429,19 @@ export function createDeviceFlowCeremony(options: {
|
|
|
329
429
|
client_id: getRequiredEnv(ctx, options.clientIdEnvKey),
|
|
330
430
|
...(options.clientSecretEnvKey
|
|
331
431
|
? {
|
|
332
|
-
client_secret: getRequiredEnv(
|
|
333
|
-
ctx,
|
|
334
|
-
options.clientSecretEnvKey,
|
|
335
|
-
),
|
|
432
|
+
client_secret: getRequiredEnv(ctx, options.clientSecretEnvKey),
|
|
336
433
|
}
|
|
337
434
|
: {}),
|
|
338
435
|
});
|
|
339
436
|
const data = ensureRecord(response.data);
|
|
340
437
|
const errorCode = getString(data, "error");
|
|
341
438
|
|
|
342
|
-
if (
|
|
343
|
-
errorCode === "authorization_pending" ||
|
|
344
|
-
errorCode === "slow_down"
|
|
345
|
-
) {
|
|
439
|
+
if (errorCode === "authorization_pending" || errorCode === "slow_down") {
|
|
346
440
|
return createTurn("poll", {
|
|
347
441
|
data,
|
|
348
442
|
hint: "Authorization pending.",
|
|
349
443
|
timing: {
|
|
350
|
-
suggestedPollIntervalMs:
|
|
351
|
-
errorCode === "slow_down" ? 10_000 : 5_000,
|
|
444
|
+
suggestedPollIntervalMs: errorCode === "slow_down" ? 10_000 : 5_000,
|
|
352
445
|
maxWaitMs: 120_000,
|
|
353
446
|
},
|
|
354
447
|
});
|
|
@@ -367,9 +460,7 @@ export function createDeviceFlowCeremony(options: {
|
|
|
367
460
|
ctx,
|
|
368
461
|
),
|
|
369
462
|
abort: async () =>
|
|
370
|
-
validateCeremonyOutput(
|
|
371
|
-
createTurn("abort", { hint: "Device flow aborted." }),
|
|
372
|
-
),
|
|
463
|
+
validateCeremonyOutput(createTurn("abort", { hint: "Device flow aborted." })),
|
|
373
464
|
};
|
|
374
465
|
}
|
|
375
466
|
|
|
@@ -437,9 +528,7 @@ export function createWebAuthnCeremony(options: {
|
|
|
437
528
|
input,
|
|
438
529
|
),
|
|
439
530
|
abort: async () =>
|
|
440
|
-
validateCeremonyOutput(
|
|
441
|
-
createTurn("abort", { hint: "WebAuthn ceremony aborted." }),
|
|
442
|
-
),
|
|
531
|
+
validateCeremonyOutput(createTurn("abort", { hint: "WebAuthn ceremony aborted." })),
|
|
443
532
|
};
|
|
444
533
|
}
|
|
445
534
|
|
|
@@ -526,9 +615,7 @@ export function createMagicLinkCeremony(options: {
|
|
|
526
615
|
ctx,
|
|
527
616
|
),
|
|
528
617
|
abort: async () =>
|
|
529
|
-
validateCeremonyOutput(
|
|
530
|
-
createTurn("abort", { hint: "Magic link flow aborted." }),
|
|
531
|
-
),
|
|
618
|
+
validateCeremonyOutput(createTurn("abort", { hint: "Magic link flow aborted." })),
|
|
532
619
|
};
|
|
533
620
|
}
|
|
534
621
|
|
|
@@ -548,7 +635,7 @@ export function createFormCeremony(options: {
|
|
|
548
635
|
continue: (ctx, input = {}) =>
|
|
549
636
|
runCeremonyHandler(
|
|
550
637
|
async () => {
|
|
551
|
-
const { prevalidate } = await import("../runtime/prevalidate");
|
|
638
|
+
const { prevalidate } = await import("../runtime/prevalidate.js");
|
|
552
639
|
const result = prevalidate(options.schema, input);
|
|
553
640
|
if (!result.valid) {
|
|
554
641
|
throw new ValidationError("Form input failed validation.", {
|
|
@@ -558,9 +645,7 @@ export function createFormCeremony(options: {
|
|
|
558
645
|
|
|
559
646
|
return createTurn("complete", {
|
|
560
647
|
data: {
|
|
561
|
-
credential: options.mapCredential
|
|
562
|
-
? options.mapCredential(input)
|
|
563
|
-
: input,
|
|
648
|
+
credential: options.mapCredential ? options.mapCredential(input) : input,
|
|
564
649
|
},
|
|
565
650
|
hint: "Form completed.",
|
|
566
651
|
});
|
|
@@ -570,15 +655,11 @@ export function createFormCeremony(options: {
|
|
|
570
655
|
input,
|
|
571
656
|
),
|
|
572
657
|
abort: async () =>
|
|
573
|
-
validateCeremonyOutput(
|
|
574
|
-
createTurn("abort", { hint: "Form ceremony aborted." }),
|
|
575
|
-
),
|
|
658
|
+
validateCeremonyOutput(createTurn("abort", { hint: "Form ceremony aborted." })),
|
|
576
659
|
};
|
|
577
660
|
}
|
|
578
661
|
|
|
579
|
-
export function combineCeremonies(
|
|
580
|
-
...ceremonies: AuthFlowDefinition[]
|
|
581
|
-
): AuthFlowDefinition {
|
|
662
|
+
export function combineCeremonies(...ceremonies: AuthFlowDefinition[]): AuthFlowDefinition {
|
|
582
663
|
function getStage(ctx: FlowContext): number {
|
|
583
664
|
const rawStage = ctx.context.get(COMBINED_STAGE_KEY);
|
|
584
665
|
return typeof rawStage === "number" ? rawStage : 0;
|
|
@@ -630,9 +711,7 @@ export function combineCeremonies(
|
|
|
630
711
|
async () => {
|
|
631
712
|
const current = ceremonies[getStage(ctx)];
|
|
632
713
|
if (!current?.poll) {
|
|
633
|
-
throw new ValidationError(
|
|
634
|
-
"Current ceremony does not support polling.",
|
|
635
|
-
);
|
|
714
|
+
throw new ValidationError("Current ceremony does not support polling.");
|
|
636
715
|
}
|
|
637
716
|
return await current.poll(ctx);
|
|
638
717
|
},
|
|
@@ -680,9 +759,7 @@ export function createSwitchCeremony(options: {
|
|
|
680
759
|
async () => {
|
|
681
760
|
const storedChoice = ctx.context.get(SWITCH_SELECTION_KEY);
|
|
682
761
|
const choice =
|
|
683
|
-
typeof storedChoice === "string"
|
|
684
|
-
? storedChoice
|
|
685
|
-
: getString(input, "choice");
|
|
762
|
+
typeof storedChoice === "string" ? storedChoice : getString(input, "choice");
|
|
686
763
|
|
|
687
764
|
if (!choice || !options.choices[choice]) {
|
|
688
765
|
throw new ValidationError("A valid choice is required.");
|
|
@@ -710,9 +787,7 @@ export function createSwitchCeremony(options: {
|
|
|
710
787
|
|
|
711
788
|
const ceremony = options.choices[choice];
|
|
712
789
|
if (!ceremony?.poll) {
|
|
713
|
-
throw new ValidationError(
|
|
714
|
-
"Selected ceremony does not support polling.",
|
|
715
|
-
);
|
|
790
|
+
throw new ValidationError("Selected ceremony does not support polling.");
|
|
716
791
|
}
|
|
717
792
|
|
|
718
793
|
return await ceremony.poll(ctx);
|
package/src/cli/commands.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type ApifuseCommandName =
|
|
|
2
2
|
| "create"
|
|
3
3
|
| "dev"
|
|
4
4
|
| "check"
|
|
5
|
+
| "sync-assets"
|
|
5
6
|
| "submit-check"
|
|
6
7
|
| "bounty-check"
|
|
7
8
|
| "record"
|
|
@@ -46,6 +47,14 @@ export const COMMAND_MANIFEST: Record<
|
|
|
46
47
|
examples: ["apifuse check .", "apifuse check providers/korea-air-quality"],
|
|
47
48
|
modulePath: "./apifuse-check",
|
|
48
49
|
},
|
|
50
|
+
"sync-assets": {
|
|
51
|
+
name: "sync-assets",
|
|
52
|
+
summary:
|
|
53
|
+
"Regenerate SDK-managed agent prompt assets (AGENTS.md, .agents/skills, symlinks, manifest) for the installed SDK version.",
|
|
54
|
+
usage: "apifuse sync-assets [path] [--check]",
|
|
55
|
+
examples: ["apifuse sync-assets .", "apifuse sync-assets . --check"],
|
|
56
|
+
modulePath: "./apifuse-sync-assets",
|
|
57
|
+
},
|
|
49
58
|
"submit-check": {
|
|
50
59
|
name: "submit-check",
|
|
51
60
|
summary:
|
|
@@ -103,6 +112,7 @@ export const COMMAND_ORDER: ApifuseCommandName[] = [
|
|
|
103
112
|
"create",
|
|
104
113
|
"dev",
|
|
105
114
|
"check",
|
|
115
|
+
"sync-assets",
|
|
106
116
|
"submit-check",
|
|
107
117
|
"record",
|
|
108
118
|
"test",
|
package/src/cli/create.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
|
@@ -8,6 +8,11 @@ import { cancel, intro, isCancel, note, outro, select, text } from "@clack/promp
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
import packageJson from "../../package.json";
|
|
11
|
+
import {
|
|
12
|
+
buildPromptAssetManifest,
|
|
13
|
+
buildPromptAssetPlanEntries,
|
|
14
|
+
PROMPT_ASSET_MANIFEST_PATH,
|
|
15
|
+
} from "./prompt-assets.js";
|
|
11
16
|
|
|
12
17
|
export const PROVIDER_NAME_REGEX = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
13
18
|
export const CATEGORY_OPTIONS = [
|
|
@@ -64,7 +69,10 @@ export type CreateResolvedOptions = {
|
|
|
64
69
|
|
|
65
70
|
export type ProviderPlanFile = {
|
|
66
71
|
path: string;
|
|
72
|
+
/** File content, or the symlink target (relative path) for kind "symlink". */
|
|
67
73
|
content: string;
|
|
74
|
+
/** Absent kind means "file" (backward compatible with older consumers). */
|
|
75
|
+
kind?: "file" | "symlink";
|
|
68
76
|
};
|
|
69
77
|
|
|
70
78
|
export type ProviderCreatePlan = {
|
|
@@ -410,11 +418,16 @@ export async function buildProviderCreatePlan(
|
|
|
410
418
|
);
|
|
411
419
|
}
|
|
412
420
|
|
|
421
|
+
// Exact pin, not a caret range: the prompt-asset freshness gate requires
|
|
422
|
+
// manifest.sdkVersion === installed SDK version, and the manifest records
|
|
423
|
+
// this CLI's own version. A caret range would let `bun install` resolve a
|
|
424
|
+
// newer SDK than the create binary, making a fresh scaffold fail its own
|
|
425
|
+
// gate. `sync-assets` after an explicit SDK upgrade re-records the version.
|
|
413
426
|
const sdkSpecifier =
|
|
414
427
|
options.sdkSpecifier ??
|
|
415
428
|
(options.preset === "monorepo" && resolvedWorkspaceRoot
|
|
416
429
|
? "workspace:*"
|
|
417
|
-
:
|
|
430
|
+
: packageJson.version);
|
|
418
431
|
const relativeProviderRoot = relative(cwd, providerRoot) || options.name;
|
|
419
432
|
const nextDevCommand = `cd ${relativeProviderRoot} && bun run dev`;
|
|
420
433
|
const packageName =
|
|
@@ -538,40 +551,23 @@ export async function buildProviderCreatePlan(
|
|
|
538
551
|
PROVIDER_ID: options.name,
|
|
539
552
|
}),
|
|
540
553
|
},
|
|
541
|
-
{
|
|
542
|
-
path: resolve(providerRoot, "AGENTS.md"),
|
|
543
|
-
content: await renderTemplate("AGENTS.md.tpl", {}),
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
path: resolve(providerRoot, "CLAUDE.md"),
|
|
547
|
-
content: await renderTemplate("CLAUDE.md.tpl", {}),
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
path: resolve(providerRoot, "skills", "normalization-standards", "SKILL.md"),
|
|
551
|
-
content: await renderTemplate("skills/normalization-standards/SKILL.md.tpl", {}),
|
|
552
|
-
},
|
|
553
|
-
{
|
|
554
|
-
path: resolve(providerRoot, "skills", "upstream-contract-verification", "SKILL.md"),
|
|
555
|
-
content: await renderTemplate("skills/upstream-contract-verification/SKILL.md.tpl", {}),
|
|
556
|
-
},
|
|
557
|
-
{
|
|
558
|
-
path: resolve(providerRoot, "skills", "fixtures-and-recording", "SKILL.md"),
|
|
559
|
-
content: await renderTemplate("skills/fixtures-and-recording/SKILL.md.tpl", {}),
|
|
560
|
-
},
|
|
561
|
-
{
|
|
562
|
-
path: resolve(providerRoot, "skills", "pagination-and-counts", "SKILL.md"),
|
|
563
|
-
content: await renderTemplate("skills/pagination-and-counts/SKILL.md.tpl", {}),
|
|
564
|
-
},
|
|
565
|
-
{
|
|
566
|
-
path: resolve(providerRoot, "skills", "health-checks-and-fail-closed", "SKILL.md"),
|
|
567
|
-
content: await renderTemplate("skills/health-checks-and-fail-closed/SKILL.md.tpl", {}),
|
|
568
|
-
},
|
|
569
|
-
{
|
|
570
|
-
path: resolve(providerRoot, "skills", "upstream-notes", "README.md"),
|
|
571
|
-
content: await renderTemplate("skills/upstream-notes/README.md.tpl", {}),
|
|
572
|
-
},
|
|
573
554
|
];
|
|
574
555
|
|
|
556
|
+
const promptAssetEntries = await buildPromptAssetPlanEntries(renderTemplate);
|
|
557
|
+
for (const entry of promptAssetEntries) {
|
|
558
|
+
files.push({
|
|
559
|
+
path: resolve(providerRoot, entry.path),
|
|
560
|
+
content: entry.content,
|
|
561
|
+
...(entry.kind === "symlink" ? { kind: "symlink" as const } : {}),
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
// Manifest last: writePlan writes in order, so a crash mid-scaffold never
|
|
565
|
+
// leaves a manifest that claims assets which were not written.
|
|
566
|
+
files.push({
|
|
567
|
+
path: resolve(providerRoot, PROMPT_ASSET_MANIFEST_PATH),
|
|
568
|
+
content: buildPromptAssetManifest(promptAssetEntries, packageJson.version),
|
|
569
|
+
});
|
|
570
|
+
|
|
575
571
|
return {
|
|
576
572
|
displayName: options.displayName,
|
|
577
573
|
files,
|
|
@@ -614,6 +610,7 @@ function renderPackageJson(input: { packageName: string; sdkSpecifier: string })
|
|
|
614
610
|
check: "apifuse check . && bun run type-check",
|
|
615
611
|
"type-check": "tsc --noEmit",
|
|
616
612
|
"submit-check": "apifuse submit-check . --markdown submission-report.md",
|
|
613
|
+
"sync-assets": "apifuse sync-assets .",
|
|
617
614
|
test: "apifuse test .",
|
|
618
615
|
record: "apifuse record .",
|
|
619
616
|
start: "bun start.ts",
|
|
@@ -869,6 +866,13 @@ function isApifuseInternalWorkspaceRoot(workspaceRoot: string): boolean {
|
|
|
869
866
|
async function writePlan(plan: ProviderCreatePlan): Promise<void> {
|
|
870
867
|
for (const file of plan.files) {
|
|
871
868
|
await mkdir(dirname(file.path), { recursive: true });
|
|
869
|
+
if (file.kind === "symlink") {
|
|
870
|
+
// rm operates on the link itself (lstat semantics) and tolerates
|
|
871
|
+
// directories, so whatever occupies the path is replaced by the link.
|
|
872
|
+
await rm(file.path, { recursive: true, force: true });
|
|
873
|
+
await symlink(file.content, file.path);
|
|
874
|
+
continue;
|
|
875
|
+
}
|
|
872
876
|
await writeFile(file.path, file.content);
|
|
873
877
|
}
|
|
874
878
|
}
|
|
@@ -940,7 +944,10 @@ function printResult(plan: ProviderCreatePlan, jsonMode: boolean, dryRun: boolea
|
|
|
940
944
|
},
|
|
941
945
|
validationCommands: plan.validationCommands,
|
|
942
946
|
nextDevCommand: plan.nextDevCommand,
|
|
943
|
-
files: plan.files.map((file) =>
|
|
947
|
+
files: plan.files.map((file) => {
|
|
948
|
+
const relativePath = relative(plan.providerRoot, file.path) || file.path;
|
|
949
|
+
return file.kind === "symlink" ? `${relativePath} -> ${file.content} (symlink)` : relativePath;
|
|
950
|
+
}),
|
|
944
951
|
};
|
|
945
952
|
|
|
946
953
|
if (jsonMode) {
|