@apifuse/provider-sdk 2.1.0-beta.9 → 2.2.0-beta.10
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 +240 -0
- package/CHANGELOG.md +93 -0
- package/README.md +26 -10
- package/SUBMISSION.md +11 -12
- 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 +36 -0
- package/bin/apifuse-pack-smoke.ts +22 -81
- package/bin/apifuse-pack-types.ts +266 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +53 -70
- package/bin/apifuse-submit-check.ts +2177 -353
- 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/auth-turn.v1.schema.json +89 -0
- package/dist/auth-turn/fixtures/invalid/empty-kind.json +4 -0
- package/dist/auth-turn/fixtures/invalid/expires-at-not-string.json +5 -0
- package/dist/auth-turn/fixtures/invalid/missing-kind.json +3 -0
- package/dist/auth-turn/fixtures/invalid/missing-turn-id.json +3 -0
- package/dist/auth-turn/fixtures/invalid/timing-unknown-field.json +7 -0
- package/dist/auth-turn/fixtures/invalid/turn-id-snake-case.json +4 -0
- package/dist/auth-turn/fixtures/invalid/unknown-top-level-field.json +5 -0
- package/dist/auth-turn/fixtures/valid/abort.json +8 -0
- package/dist/auth-turn/fixtures/valid/challenge.json +17 -0
- package/dist/auth-turn/fixtures/valid/complete.json +13 -0
- package/dist/auth-turn/fixtures/valid/form.json +14 -0
- package/dist/auth-turn/fixtures/valid/message.json +13 -0
- package/dist/auth-turn/fixtures/valid/multi_choice.json +15 -0
- package/dist/auth-turn/fixtures/valid/pending.json +5 -0
- package/dist/auth-turn/fixtures/valid/poll.json +9 -0
- package/dist/auth-turn/fixtures/valid/redirect.json +16 -0
- package/dist/auth-turn/fixtures/valid/retry.json +8 -0
- package/dist/auth-turn/fixtures/valid/unknown-kind.json +7 -0
- package/dist/auth-turn/index.d.ts +195 -0
- package/dist/auth-turn/index.js +133 -0
- package/dist/auth.d.ts +76 -0
- package/dist/auth.js +427 -0
- package/dist/ceremonies/index.d.ts +1 -1
- package/dist/ceremonies/index.js +14 -48
- 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 +47 -33
- package/dist/cli/prompt-assets.d.ts +80 -0
- package/dist/cli/prompt-assets.js +743 -0
- package/dist/cli/templates/provider/.agents/skills/fixtures-and-recording/SKILL.md.tpl +58 -0
- package/dist/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +65 -0
- package/dist/cli/templates/provider/.agents/skills/normalization-standards/SKILL.md.tpl +57 -0
- package/dist/cli/templates/provider/.agents/skills/pagination-and-counts/SKILL.md.tpl +52 -0
- package/dist/cli/templates/provider/.agents/skills/upstream-contract-verification/SKILL.md.tpl +45 -0
- package/dist/cli/templates/provider/.agents/skills/upstream-notes/README.md.tpl +13 -0
- package/dist/cli/templates/provider/.dockerignore.tpl +22 -0
- package/dist/cli/templates/provider/.gitignore.tpl +22 -0
- package/dist/cli/templates/provider/AGENTS.md.tpl +96 -0
- package/dist/cli/templates/provider/Dockerfile.tpl +7 -0
- package/dist/cli/templates/provider/README.md.tpl +163 -0
- package/dist/cli/templates/provider/dev.ts.tpl +5 -0
- package/dist/cli/templates/provider/domain/README.md.tpl +3 -0
- package/dist/cli/templates/provider/index.test.ts.tpl +13 -0
- package/dist/cli/templates/provider/index.ts.tpl +15 -0
- package/dist/cli/templates/provider/mappers/README.md.tpl +3 -0
- package/dist/cli/templates/provider/meta.ts.tpl +7 -0
- package/dist/cli/templates/provider/operations/index.ts.tpl +5 -0
- package/dist/cli/templates/provider/operations/ping.ts.tpl +24 -0
- package/dist/cli/templates/provider/schemas/ping.ts.tpl +24 -0
- package/dist/cli/templates/provider/start.ts.tpl +5 -0
- package/dist/cli/templates/provider/upstream/README.md.tpl +3 -0
- package/dist/config/loader.d.ts +149 -8
- package/dist/config/loader.js +378 -89
- 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 +5 -6
- package/dist/define.d.ts +13 -1
- package/dist/define.js +245 -178
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/errors.d.ts +4 -1
- package/dist/errors.js +48 -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 +44 -41
- package/dist/index.js +39 -36
- package/dist/lint.d.ts +1 -0
- package/dist/lint.js +35 -15
- package/dist/provider.d.ts +11 -9
- package/dist/provider.js +9 -8
- 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 +1 -1
- package/dist/runtime/auth-flow.js +4 -2
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +214 -25
- 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 +15 -3
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +160 -344
- 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 +56 -19
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- 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 +35 -0
- package/dist/runtime/proxy-nodemaven.js +128 -0
- package/dist/runtime/proxy-retry-policy.d.ts +40 -0
- package/dist/runtime/proxy-retry-policy.js +326 -0
- package/dist/runtime/proxy-telemetry.d.ts +2 -1
- package/dist/runtime/proxy-telemetry.js +55 -52
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +2 -4
- package/dist/runtime/request-options.d.ts +1 -1
- 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 +15 -4
- package/dist/runtime/stealth.d.ts +7 -4
- package/dist/runtime/stealth.js +257 -215
- 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 -3
- package/dist/server/index.js +6 -2
- package/dist/server/self-test-input-tokens.d.ts +1 -0
- package/dist/server/self-test-input-tokens.js +37 -0
- package/dist/server/self-test-redaction.d.ts +20 -0
- package/dist/server/self-test-redaction.js +70 -0
- package/dist/server/self-test-token.d.ts +30 -0
- package/dist/server/self-test-token.js +50 -0
- package/dist/server/self-test.d.ts +199 -0
- package/dist/server/self-test.js +1113 -0
- package/dist/server/serve.d.ts +14 -3
- package/dist/server/serve.js +135 -64
- package/dist/server/types.d.ts +10 -9
- package/dist/server/types.js +3 -7
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +5 -14
- 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 +1 -1
- package/dist/testing/run.js +12 -15
- package/dist/types.d.ts +237 -1
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +16 -5
- package/src/auth-turn/auth-turn.v1.schema.json +89 -0
- package/src/auth-turn/fixtures/invalid/empty-kind.json +4 -0
- package/src/auth-turn/fixtures/invalid/expires-at-not-string.json +5 -0
- package/src/auth-turn/fixtures/invalid/missing-kind.json +3 -0
- package/src/auth-turn/fixtures/invalid/missing-turn-id.json +3 -0
- package/src/auth-turn/fixtures/invalid/timing-unknown-field.json +7 -0
- package/src/auth-turn/fixtures/invalid/turn-id-snake-case.json +4 -0
- package/src/auth-turn/fixtures/invalid/unknown-top-level-field.json +5 -0
- package/src/auth-turn/fixtures/valid/abort.json +8 -0
- package/src/auth-turn/fixtures/valid/challenge.json +17 -0
- package/src/auth-turn/fixtures/valid/complete.json +13 -0
- package/src/auth-turn/fixtures/valid/form.json +14 -0
- package/src/auth-turn/fixtures/valid/message.json +13 -0
- package/src/auth-turn/fixtures/valid/multi_choice.json +15 -0
- package/src/auth-turn/fixtures/valid/pending.json +5 -0
- package/src/auth-turn/fixtures/valid/poll.json +9 -0
- package/src/auth-turn/fixtures/valid/redirect.json +16 -0
- package/src/auth-turn/fixtures/valid/retry.json +8 -0
- package/src/auth-turn/fixtures/valid/unknown-kind.json +7 -0
- package/src/auth-turn/index.ts +177 -0
- package/src/auth.ts +728 -0
- package/src/ceremonies/index.ts +33 -121
- package/src/cli/commands.ts +10 -0
- package/src/cli/create.ts +69 -99
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/.agents/skills/fixtures-and-recording/SKILL.md.tpl +58 -0
- package/src/cli/templates/provider/.agents/skills/health-checks-and-fail-closed/SKILL.md.tpl +65 -0
- package/src/cli/templates/provider/.agents/skills/normalization-standards/SKILL.md.tpl +57 -0
- package/src/cli/templates/provider/.agents/skills/pagination-and-counts/SKILL.md.tpl +52 -0
- package/src/cli/templates/provider/.agents/skills/upstream-contract-verification/SKILL.md.tpl +45 -0
- package/src/cli/templates/provider/.agents/skills/upstream-notes/README.md.tpl +13 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +96 -0
- package/src/cli/templates/provider/README.md.tpl +7 -4
- package/src/config/loader.ts +543 -208
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +13 -28
- package/src/define.ts +397 -528
- package/src/dev.ts +4 -9
- package/src/errors.ts +58 -5
- 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 +64 -41
- package/src/lint.ts +122 -159
- package/src/provider.ts +40 -9
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +6 -6
- package/src/runtime/browser.ts +320 -151
- 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 +23 -20
- package/src/runtime/http.ts +216 -539
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +78 -65
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- 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 +178 -0
- package/src/runtime/proxy-retry-policy.ts +469 -0
- package/src/runtime/proxy-telemetry.ts +79 -77
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +4 -13
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +41 -110
- package/src/runtime/stealth.ts +331 -369
- 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 +44 -3
- package/src/server/self-test-input-tokens.ts +46 -0
- package/src/server/self-test-redaction.ts +97 -0
- package/src/server/self-test-token.ts +70 -0
- package/src/server/self-test.ts +1450 -0
- package/src/server/serve.ts +206 -216
- package/src/server/types.ts +7 -19
- package/src/stealth/profiles.ts +10 -26
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +2 -2
- package/src/testing/run.ts +24 -64
- package/src/types.ts +274 -1
- package/src/user-input.ts +118 -0
package/src/cli/create.ts
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
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
|
|
|
7
|
-
import {
|
|
8
|
-
cancel,
|
|
9
|
-
intro,
|
|
10
|
-
isCancel,
|
|
11
|
-
note,
|
|
12
|
-
outro,
|
|
13
|
-
select,
|
|
14
|
-
text,
|
|
15
|
-
} from "@clack/prompts";
|
|
7
|
+
import { cancel, intro, isCancel, note, outro, select, text } from "@clack/prompts";
|
|
16
8
|
import { z } from "zod";
|
|
17
9
|
|
|
18
10
|
import packageJson from "../../package.json";
|
|
11
|
+
import {
|
|
12
|
+
buildPromptAssetManifest,
|
|
13
|
+
buildPromptAssetPlanEntries,
|
|
14
|
+
PROMPT_ASSET_MANIFEST_PATH,
|
|
15
|
+
} from "./prompt-assets.js";
|
|
19
16
|
|
|
20
17
|
export const PROVIDER_NAME_REGEX = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
21
18
|
export const CATEGORY_OPTIONS = [
|
|
@@ -28,12 +25,7 @@ export const CATEGORY_OPTIONS = [
|
|
|
28
25
|
"communication",
|
|
29
26
|
"other",
|
|
30
27
|
] as const;
|
|
31
|
-
export const AUTH_MODE_OPTIONS = [
|
|
32
|
-
"none",
|
|
33
|
-
"platform-managed",
|
|
34
|
-
"credentials",
|
|
35
|
-
"oauth2",
|
|
36
|
-
] as const;
|
|
28
|
+
export const AUTH_MODE_OPTIONS = ["none", "platform-managed", "credentials", "oauth2"] as const;
|
|
37
29
|
export const RUNTIME_OPTIONS = ["standard", "browser"] as const;
|
|
38
30
|
export const PRESET_OPTIONS = ["standalone", "monorepo"] as const;
|
|
39
31
|
|
|
@@ -77,7 +69,10 @@ export type CreateResolvedOptions = {
|
|
|
77
69
|
|
|
78
70
|
export type ProviderPlanFile = {
|
|
79
71
|
path: string;
|
|
72
|
+
/** File content, or the symlink target (relative path) for kind "symlink". */
|
|
80
73
|
content: string;
|
|
74
|
+
/** Absent kind means "file" (backward compatible with older consumers). */
|
|
75
|
+
kind?: "file" | "symlink";
|
|
81
76
|
};
|
|
82
77
|
|
|
83
78
|
export type ProviderCreatePlan = {
|
|
@@ -95,9 +90,7 @@ export type ProviderCreatePlan = {
|
|
|
95
90
|
workspaceRoot?: string;
|
|
96
91
|
};
|
|
97
92
|
|
|
98
|
-
const TEMPLATE_DIR = fileURLToPath(
|
|
99
|
-
new URL("./templates/provider/", import.meta.url),
|
|
100
|
-
);
|
|
93
|
+
const TEMPLATE_DIR = fileURLToPath(new URL("./templates/provider/", import.meta.url));
|
|
101
94
|
const HELP_TEXT = `Usage: apifuse create <provider-name> [options]
|
|
102
95
|
Examples:
|
|
103
96
|
apifuse create my-provider
|
|
@@ -126,9 +119,7 @@ export async function main() {
|
|
|
126
119
|
}
|
|
127
120
|
|
|
128
121
|
const parsed = parseArgs(normalizedArgs);
|
|
129
|
-
const config = parsed.configPath
|
|
130
|
-
? await loadConfig(parsed.configPath)
|
|
131
|
-
: undefined;
|
|
122
|
+
const config = parsed.configPath ? await loadConfig(parsed.configPath) : undefined;
|
|
132
123
|
const resolved = await resolveCreateOptions(parsed, config, process.cwd());
|
|
133
124
|
const plan = await buildProviderCreatePlan(resolved, process.cwd());
|
|
134
125
|
|
|
@@ -195,18 +186,10 @@ function parseArgs(argv: string[]): ParsedArgs {
|
|
|
195
186
|
parsed.displayName = ensureValue(flag, consumeValue());
|
|
196
187
|
break;
|
|
197
188
|
case "--category":
|
|
198
|
-
parsed.category = parseEnum(
|
|
199
|
-
"category",
|
|
200
|
-
consumeValue(),
|
|
201
|
-
CATEGORY_OPTIONS,
|
|
202
|
-
);
|
|
189
|
+
parsed.category = parseEnum("category", consumeValue(), CATEGORY_OPTIONS);
|
|
203
190
|
break;
|
|
204
191
|
case "--auth-mode":
|
|
205
|
-
parsed.authMode = parseEnum(
|
|
206
|
-
"auth mode",
|
|
207
|
-
consumeValue(),
|
|
208
|
-
AUTH_MODE_OPTIONS,
|
|
209
|
-
);
|
|
192
|
+
parsed.authMode = parseEnum("auth mode", consumeValue(), AUTH_MODE_OPTIONS);
|
|
210
193
|
break;
|
|
211
194
|
case "--runtime":
|
|
212
195
|
parsed.runtime = parseEnum("runtime", consumeValue(), RUNTIME_OPTIONS);
|
|
@@ -253,9 +236,7 @@ function parseEnum<T extends readonly string[]>(
|
|
|
253
236
|
const resolvedValue = ensureValue(`--${label}`, value);
|
|
254
237
|
const matchedValue = options.find((option) => option === resolvedValue);
|
|
255
238
|
if (!matchedValue) {
|
|
256
|
-
throw new Error(
|
|
257
|
-
`Invalid ${label}: ${resolvedValue}. Expected one of: ${options.join(", ")}`,
|
|
258
|
-
);
|
|
239
|
+
throw new Error(`Invalid ${label}: ${resolvedValue}. Expected one of: ${options.join(", ")}`);
|
|
259
240
|
}
|
|
260
241
|
return matchedValue;
|
|
261
242
|
}
|
|
@@ -282,9 +263,7 @@ async function resolveCreateOptions(
|
|
|
282
263
|
authMode: parsed.authMode ?? config?.authMode,
|
|
283
264
|
runtime: parsed.runtime ?? config?.runtime,
|
|
284
265
|
sdkSpecifier:
|
|
285
|
-
parsed.sdkSpecifier ??
|
|
286
|
-
config?.sdkSpecifier ??
|
|
287
|
-
process.env.APIFUSE__SDK__SPECIFIER,
|
|
266
|
+
parsed.sdkSpecifier ?? config?.sdkSpecifier ?? process.env.APIFUSE__SDK__SPECIFIER,
|
|
288
267
|
dryRun: parsed.dryRun,
|
|
289
268
|
json: parsed.json,
|
|
290
269
|
yes: parsed.yes,
|
|
@@ -298,9 +277,7 @@ async function resolveCreateOptions(
|
|
|
298
277
|
|
|
299
278
|
if (partial.yes) {
|
|
300
279
|
if (!partial.name) {
|
|
301
|
-
throw new Error(
|
|
302
|
-
"--yes requires a provider name (positional or via config).",
|
|
303
|
-
);
|
|
280
|
+
throw new Error("--yes requires a provider name (positional or via config).");
|
|
304
281
|
}
|
|
305
282
|
|
|
306
283
|
return {
|
|
@@ -410,9 +387,7 @@ export async function buildProviderCreatePlan(
|
|
|
410
387
|
cwd: string,
|
|
411
388
|
): Promise<ProviderCreatePlan> {
|
|
412
389
|
const resolvedWorkspaceRoot =
|
|
413
|
-
options.preset === "monorepo"
|
|
414
|
-
? findApifuseInternalWorkspaceRoot(cwd)
|
|
415
|
-
: undefined;
|
|
390
|
+
options.preset === "monorepo" ? findApifuseInternalWorkspaceRoot(cwd) : undefined;
|
|
416
391
|
if (options.preset === "monorepo" && !resolvedWorkspaceRoot) {
|
|
417
392
|
throw new Error(
|
|
418
393
|
"Monorepo preset is internal to the APIFuse repository. External bounty workspaces are one-provider repositories; use the standalone default create flow.",
|
|
@@ -424,9 +399,7 @@ export async function buildProviderCreatePlan(
|
|
|
424
399
|
if (options.outputDir) {
|
|
425
400
|
providerRoot = resolve(cwd, options.outputDir);
|
|
426
401
|
installCwd =
|
|
427
|
-
options.preset === "monorepo" && resolvedWorkspaceRoot
|
|
428
|
-
? resolvedWorkspaceRoot
|
|
429
|
-
: providerRoot;
|
|
402
|
+
options.preset === "monorepo" && resolvedWorkspaceRoot ? resolvedWorkspaceRoot : providerRoot;
|
|
430
403
|
} else if (options.preset === "monorepo" && resolvedWorkspaceRoot) {
|
|
431
404
|
providerRoot = resolve(resolvedWorkspaceRoot, "providers", options.name);
|
|
432
405
|
installCwd = resolvedWorkspaceRoot;
|
|
@@ -439,20 +412,22 @@ export async function buildProviderCreatePlan(
|
|
|
439
412
|
throw new Error(`Target directory already exists: ${providerRoot}`);
|
|
440
413
|
}
|
|
441
414
|
|
|
442
|
-
if (
|
|
443
|
-
options.sdkSpecifier?.startsWith("workspace:") &&
|
|
444
|
-
!resolvedWorkspaceRoot
|
|
445
|
-
) {
|
|
415
|
+
if (options.sdkSpecifier?.startsWith("workspace:") && !resolvedWorkspaceRoot) {
|
|
446
416
|
throw new Error(
|
|
447
417
|
"workspace:* is only valid inside the APIFuse monorepo because public Provider SDK scaffolds must install from npm or an explicit tarball/file specifier.",
|
|
448
418
|
);
|
|
449
419
|
}
|
|
450
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.
|
|
451
426
|
const sdkSpecifier =
|
|
452
427
|
options.sdkSpecifier ??
|
|
453
428
|
(options.preset === "monorepo" && resolvedWorkspaceRoot
|
|
454
429
|
? "workspace:*"
|
|
455
|
-
:
|
|
430
|
+
: packageJson.version);
|
|
456
431
|
const relativeProviderRoot = relative(cwd, providerRoot) || options.name;
|
|
457
432
|
const nextDevCommand = `cd ${relativeProviderRoot} && bun run dev`;
|
|
458
433
|
const packageName =
|
|
@@ -578,6 +553,21 @@ export async function buildProviderCreatePlan(
|
|
|
578
553
|
},
|
|
579
554
|
];
|
|
580
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
|
+
|
|
581
571
|
return {
|
|
582
572
|
displayName: options.displayName,
|
|
583
573
|
files,
|
|
@@ -592,17 +582,14 @@ export async function buildProviderCreatePlan(
|
|
|
592
582
|
validationCommands: [
|
|
593
583
|
"bun run check",
|
|
594
584
|
"bun run type-check",
|
|
595
|
-
"bun run submit-check",
|
|
585
|
+
"bun run submit-check -- --smoke",
|
|
596
586
|
"bun run test",
|
|
597
587
|
],
|
|
598
588
|
workspaceRoot: resolvedWorkspaceRoot,
|
|
599
589
|
};
|
|
600
590
|
}
|
|
601
591
|
|
|
602
|
-
async function renderTemplate(
|
|
603
|
-
fileName: string,
|
|
604
|
-
values: Record<string, string>,
|
|
605
|
-
): Promise<string> {
|
|
592
|
+
async function renderTemplate(fileName: string, values: Record<string, string>): Promise<string> {
|
|
606
593
|
const templatePath = resolve(TEMPLATE_DIR, fileName);
|
|
607
594
|
const template = await readFile(templatePath, "utf8");
|
|
608
595
|
return template.replace(/\{\{([A-Z_]+)\}\}/g, (_match, key: string) => {
|
|
@@ -610,10 +597,7 @@ async function renderTemplate(
|
|
|
610
597
|
});
|
|
611
598
|
}
|
|
612
599
|
|
|
613
|
-
function renderPackageJson(input: {
|
|
614
|
-
packageName: string;
|
|
615
|
-
sdkSpecifier: string;
|
|
616
|
-
}): string {
|
|
600
|
+
function renderPackageJson(input: { packageName: string; sdkSpecifier: string }): string {
|
|
617
601
|
return `${JSON.stringify(
|
|
618
602
|
{
|
|
619
603
|
name: input.packageName,
|
|
@@ -625,11 +609,10 @@ function renderPackageJson(input: {
|
|
|
625
609
|
dev: "apifuse dev .",
|
|
626
610
|
check: "apifuse check . && bun run type-check",
|
|
627
611
|
"type-check": "tsc --noEmit",
|
|
628
|
-
"submit-check":
|
|
629
|
-
|
|
612
|
+
"submit-check": "apifuse submit-check . --markdown submission-report.md",
|
|
613
|
+
"sync-assets": "apifuse sync-assets .",
|
|
630
614
|
test: "apifuse test .",
|
|
631
615
|
record: "apifuse record .",
|
|
632
|
-
"perf:sample": "apifuse perf . --operation ping --runs 3",
|
|
633
616
|
start: "bun start.ts",
|
|
634
617
|
},
|
|
635
618
|
dependencies: {
|
|
@@ -666,10 +649,7 @@ function renderTsconfig(): string {
|
|
|
666
649
|
)}\n`;
|
|
667
650
|
}
|
|
668
651
|
|
|
669
|
-
function renderStarterLocaleCatalog(
|
|
670
|
-
displayName: string,
|
|
671
|
-
locale: "en" | "ko",
|
|
672
|
-
): string {
|
|
652
|
+
function renderStarterLocaleCatalog(displayName: string, locale: "en" | "ko"): string {
|
|
673
653
|
const catalog = {
|
|
674
654
|
meta: {
|
|
675
655
|
displayName,
|
|
@@ -734,8 +714,8 @@ function renderAuthBlock(authMode: CreateAuthMode): string {
|
|
|
734
714
|
return `{
|
|
735
715
|
mode: "credentials",
|
|
736
716
|
flow: {
|
|
737
|
-
start: async () => ({
|
|
738
|
-
kind: "
|
|
717
|
+
start: async (_ctx) => ({
|
|
718
|
+
kind: "form",
|
|
739
719
|
turnId: crypto.randomUUID(),
|
|
740
720
|
expectedInput: {
|
|
741
721
|
schema: {
|
|
@@ -778,7 +758,7 @@ function renderAuthBlock(authMode: CreateAuthMode): string {
|
|
|
778
758
|
return `{
|
|
779
759
|
mode: "oauth2",
|
|
780
760
|
flow: {
|
|
781
|
-
start: async () => ({
|
|
761
|
+
start: async (_ctx) => ({
|
|
782
762
|
kind: "redirect",
|
|
783
763
|
turnId: crypto.randomUUID(),
|
|
784
764
|
data: {
|
|
@@ -871,9 +851,7 @@ function isApifuseInternalWorkspaceRoot(workspaceRoot: string): boolean {
|
|
|
871
851
|
return false;
|
|
872
852
|
}
|
|
873
853
|
try {
|
|
874
|
-
const packageJson = JSON.parse(
|
|
875
|
-
readFileSync(providerSdkPackageJsonPath, "utf8"),
|
|
876
|
-
);
|
|
854
|
+
const packageJson = JSON.parse(readFileSync(providerSdkPackageJsonPath, "utf8"));
|
|
877
855
|
return (
|
|
878
856
|
typeof packageJson === "object" &&
|
|
879
857
|
packageJson !== null &&
|
|
@@ -888,31 +866,28 @@ function isApifuseInternalWorkspaceRoot(workspaceRoot: string): boolean {
|
|
|
888
866
|
async function writePlan(plan: ProviderCreatePlan): Promise<void> {
|
|
889
867
|
for (const file of plan.files) {
|
|
890
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
|
+
}
|
|
891
876
|
await writeFile(file.path, file.content);
|
|
892
877
|
}
|
|
893
878
|
}
|
|
894
879
|
|
|
895
|
-
async function installDependencies(
|
|
896
|
-
plan: ProviderCreatePlan,
|
|
897
|
-
jsonMode: boolean,
|
|
898
|
-
): Promise<void> {
|
|
880
|
+
async function installDependencies(plan: ProviderCreatePlan, jsonMode: boolean): Promise<void> {
|
|
899
881
|
await runCommand(plan.installCommand, plan.installCwd, jsonMode);
|
|
900
882
|
}
|
|
901
883
|
|
|
902
|
-
async function runBaselineValidation(
|
|
903
|
-
plan: ProviderCreatePlan,
|
|
904
|
-
jsonMode: boolean,
|
|
905
|
-
): Promise<void> {
|
|
884
|
+
async function runBaselineValidation(plan: ProviderCreatePlan, jsonMode: boolean): Promise<void> {
|
|
906
885
|
for (const command of plan.validationCommands) {
|
|
907
886
|
await runCommand(command, plan.providerRoot, jsonMode);
|
|
908
887
|
}
|
|
909
888
|
}
|
|
910
889
|
|
|
911
|
-
async function runCommand(
|
|
912
|
-
command: string,
|
|
913
|
-
cwd: string,
|
|
914
|
-
jsonMode: boolean,
|
|
915
|
-
): Promise<void> {
|
|
890
|
+
async function runCommand(command: string, cwd: string, jsonMode: boolean): Promise<void> {
|
|
916
891
|
const [binary, ...args] = command.split(" ");
|
|
917
892
|
if (!binary) {
|
|
918
893
|
throw new Error(`Cannot run empty command in ${cwd}`);
|
|
@@ -944,9 +919,7 @@ async function runCommand(
|
|
|
944
919
|
rejectPromise(
|
|
945
920
|
new Error(
|
|
946
921
|
`Command failed (${command}) in ${cwd}${
|
|
947
|
-
stdout || stderr
|
|
948
|
-
? `\n${[stdout, stderr].filter(Boolean).join("\n")}`
|
|
949
|
-
: ""
|
|
922
|
+
stdout || stderr ? `\n${[stdout, stderr].filter(Boolean).join("\n")}` : ""
|
|
950
923
|
}`,
|
|
951
924
|
),
|
|
952
925
|
);
|
|
@@ -954,11 +927,7 @@ async function runCommand(
|
|
|
954
927
|
});
|
|
955
928
|
}
|
|
956
929
|
|
|
957
|
-
function printResult(
|
|
958
|
-
plan: ProviderCreatePlan,
|
|
959
|
-
jsonMode: boolean,
|
|
960
|
-
dryRun: boolean,
|
|
961
|
-
) {
|
|
930
|
+
function printResult(plan: ProviderCreatePlan, jsonMode: boolean, dryRun: boolean) {
|
|
962
931
|
const payload = {
|
|
963
932
|
success: true,
|
|
964
933
|
dryRun,
|
|
@@ -975,9 +944,10 @@ function printResult(
|
|
|
975
944
|
},
|
|
976
945
|
validationCommands: plan.validationCommands,
|
|
977
946
|
nextDevCommand: plan.nextDevCommand,
|
|
978
|
-
files: plan.files.map(
|
|
979
|
-
|
|
980
|
-
|
|
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
|
+
}),
|
|
981
951
|
};
|
|
982
952
|
|
|
983
953
|
if (jsonMode) {
|
|
@@ -993,7 +963,7 @@ function printResult(
|
|
|
993
963
|
}
|
|
994
964
|
console.log(`Next local dev: ${plan.nextDevCommand}`);
|
|
995
965
|
console.log(
|
|
996
|
-
"Submission evidence: run `bun run submit-check
|
|
966
|
+
"Submission evidence: run `bun run submit-check -- --smoke` to archive measured `/health` and `POST /v1/{operation}` results.",
|
|
997
967
|
);
|
|
998
968
|
if (plan.files.some((file) => file.content.includes('runtime: "browser"'))) {
|
|
999
969
|
console.log(
|