@apifuse/provider-sdk 2.1.0-beta.0 → 2.1.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 +218 -21
- package/CHANGELOG.md +54 -0
- package/README.md +147 -10
- package/SUBMISSION.md +87 -0
- package/bin/apifuse-check.ts +86 -4
- package/bin/apifuse-dev.ts +87 -13
- package/bin/apifuse-pack-check.ts +120 -0
- package/bin/apifuse-pack-smoke.ts +423 -0
- package/bin/apifuse-perf.ts +142 -49
- package/bin/apifuse-record.ts +182 -104
- package/bin/apifuse-submit-check.ts +2538 -0
- package/bin/apifuse.ts +1 -1
- package/dist/ceremonies/index.d.ts +41 -0
- package/dist/ceremonies/index.js +490 -0
- package/dist/choice-token.d.ts +24 -0
- package/dist/choice-token.js +74 -0
- package/dist/cli/commands.d.ts +10 -0
- package/dist/cli/commands.js +80 -0
- package/dist/cli/create.d.ts +47 -0
- package/dist/cli/create.js +762 -0
- package/dist/cli/templates/provider/.dockerignore.tpl +22 -0
- package/dist/cli/templates/provider/.gitignore.tpl +22 -0
- package/dist/cli/templates/provider/Dockerfile.tpl +7 -0
- package/dist/cli/templates/provider/README.md.tpl +160 -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 +107 -0
- package/dist/config/loader.js +935 -0
- package/dist/contract-json.d.ts +9 -0
- package/dist/contract-json.js +51 -0
- package/dist/contract-serialization.d.ts +4 -0
- package/dist/contract-serialization.js +78 -0
- package/dist/contract-types.d.ts +49 -0
- package/dist/contract-types.js +1 -0
- package/dist/contract.d.ts +6 -0
- package/dist/contract.js +155 -0
- package/dist/define.d.ts +97 -0
- package/dist/define.js +1320 -0
- package/dist/dev.d.ts +9 -0
- package/dist/dev.js +15 -0
- package/dist/errors.d.ts +59 -0
- package/dist/errors.js +97 -0
- package/dist/i18n/catalog.d.ts +29 -0
- package/dist/i18n/catalog.js +159 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/keys.d.ts +10 -0
- package/dist/i18n/keys.js +34 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +37 -0
- package/dist/lint.d.ts +73 -0
- package/dist/lint.js +702 -0
- package/dist/observability.d.ts +5 -0
- package/dist/observability.js +39 -0
- package/dist/provider.d.ts +9 -0
- package/dist/provider.js +8 -0
- package/dist/public-schema-field-lint.d.ts +2 -0
- package/dist/public-schema-field-lint.js +158 -0
- package/dist/recipes/gov-api.d.ts +19 -0
- package/dist/recipes/gov-api.js +72 -0
- package/dist/recipes/rest-api.d.ts +21 -0
- package/dist/recipes/rest-api.js +115 -0
- package/dist/runtime/auth-flow.d.ts +14 -0
- package/dist/runtime/auth-flow.js +44 -0
- package/dist/runtime/browser.d.ts +25 -0
- package/dist/runtime/browser.js +1034 -0
- package/dist/runtime/cache.d.ts +10 -0
- package/dist/runtime/cache.js +372 -0
- package/dist/runtime/choice.d.ts +15 -0
- package/dist/runtime/choice.js +435 -0
- package/dist/runtime/credential.d.ts +8 -0
- package/dist/runtime/credential.js +61 -0
- package/dist/runtime/env.d.ts +2 -0
- package/dist/runtime/env.js +10 -0
- package/dist/runtime/executor.d.ts +16 -0
- package/dist/runtime/executor.js +51 -0
- package/dist/runtime/http.d.ts +8 -0
- package/dist/runtime/http.js +706 -0
- package/dist/runtime/insights.d.ts +9 -0
- package/dist/runtime/insights.js +324 -0
- package/dist/runtime/instrumentation.d.ts +8 -0
- package/dist/runtime/instrumentation.js +269 -0
- package/dist/runtime/key-derivation.d.ts +24 -0
- package/dist/runtime/key-derivation.js +73 -0
- package/dist/runtime/keyring.d.ts +25 -0
- package/dist/runtime/keyring.js +93 -0
- package/dist/runtime/namespace.d.ts +9 -0
- package/dist/runtime/namespace.js +19 -0
- package/dist/runtime/otlp.d.ts +39 -0
- package/dist/runtime/otlp.js +103 -0
- package/dist/runtime/perf.d.ts +12 -0
- package/dist/runtime/perf.js +52 -0
- package/dist/runtime/prevalidate.d.ts +12 -0
- package/dist/runtime/prevalidate.js +173 -0
- package/dist/runtime/provider.d.ts +2 -0
- package/dist/runtime/provider.js +11 -0
- package/dist/runtime/proxy-errors.d.ts +21 -0
- package/dist/runtime/proxy-errors.js +83 -0
- package/dist/runtime/proxy-telemetry.d.ts +8 -0
- package/dist/runtime/proxy-telemetry.js +174 -0
- package/dist/runtime/redis.d.ts +17 -0
- package/dist/runtime/redis.js +82 -0
- package/dist/runtime/request-options.d.ts +3 -0
- package/dist/runtime/request-options.js +42 -0
- package/dist/runtime/state.d.ts +17 -0
- package/dist/runtime/state.js +344 -0
- package/dist/runtime/stealth.d.ts +18 -0
- package/dist/runtime/stealth.js +834 -0
- package/dist/runtime/stt.d.ts +22 -0
- package/dist/runtime/stt.js +480 -0
- package/dist/runtime/trace.d.ts +26 -0
- package/dist/runtime/trace.js +142 -0
- package/dist/runtime/waterfall.d.ts +12 -0
- package/dist/runtime/waterfall.js +147 -0
- package/dist/schema.d.ts +74 -0
- package/dist/schema.js +243 -0
- package/dist/serve.d.ts +1 -0
- package/dist/serve.js +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +2 -0
- package/dist/server/serve.d.ts +64 -0
- package/dist/server/serve.js +1110 -0
- package/dist/server/types.d.ts +136 -0
- package/dist/server/types.js +86 -0
- package/dist/stealth/profiles.d.ts +4 -0
- package/dist/stealth/profiles.js +259 -0
- package/dist/stream.d.ts +44 -0
- package/dist/stream.js +151 -0
- package/dist/testing/helpers.d.ts +23 -0
- package/dist/testing/helpers.js +95 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/run.d.ts +34 -0
- package/dist/testing/run.js +303 -0
- package/dist/types.d.ts +1326 -0
- package/dist/types.js +61 -0
- package/dist/utils/date.d.ts +6 -0
- package/dist/utils/date.js +101 -0
- package/dist/utils/parse.d.ts +16 -0
- package/dist/utils/parse.js +51 -0
- package/dist/utils/text.d.ts +4 -0
- package/dist/utils/text.js +14 -0
- package/dist/utils/transform.d.ts +8 -0
- package/dist/utils/transform.js +48 -0
- package/package.json +57 -29
- package/src/ceremonies/index.ts +30 -3
- package/src/choice-token.ts +165 -0
- package/src/cli/commands.ts +34 -11
- package/src/cli/create.ts +214 -52
- package/src/cli/templates/provider/.dockerignore.tpl +22 -0
- package/src/cli/templates/provider/.gitignore.tpl +22 -0
- package/src/cli/templates/provider/README.md.tpl +134 -2
- package/src/cli/templates/provider/dev.ts.tpl +1 -1
- package/src/cli/templates/provider/domain/README.md.tpl +3 -0
- package/src/cli/templates/provider/index.ts.tpl +5 -44
- package/src/cli/templates/provider/mappers/README.md.tpl +3 -0
- package/src/cli/templates/provider/meta.ts.tpl +7 -0
- package/src/cli/templates/provider/operations/index.ts.tpl +5 -0
- package/src/cli/templates/provider/operations/ping.ts.tpl +24 -0
- package/src/cli/templates/provider/schemas/ping.ts.tpl +24 -0
- package/src/cli/templates/provider/start.ts.tpl +1 -1
- package/src/cli/templates/provider/upstream/README.md.tpl +3 -0
- package/src/config/loader.ts +1282 -7
- package/src/contract-json.ts +75 -0
- package/src/contract-serialization.ts +89 -0
- package/src/contract-types.ts +52 -0
- package/src/contract.ts +215 -0
- package/src/define.ts +1726 -48
- package/src/errors.ts +27 -0
- package/src/i18n/catalog.ts +277 -0
- package/src/i18n/index.ts +2 -0
- package/src/i18n/keys.ts +64 -0
- package/src/index.ts +174 -15
- package/src/lint.ts +547 -73
- package/src/observability.ts +41 -0
- package/src/provider.ts +104 -5
- package/src/public-schema-field-lint.ts +237 -0
- package/src/runtime/auth-flow.ts +7 -0
- package/src/runtime/browser.ts +762 -51
- package/src/runtime/cache.ts +528 -0
- package/src/runtime/choice.ts +760 -0
- package/src/runtime/executor.ts +32 -3
- package/src/runtime/http.ts +945 -185
- package/src/runtime/insights.ts +11 -11
- package/src/runtime/instrumentation.ts +12 -4
- package/src/runtime/key-derivation.ts +1 -1
- package/src/runtime/keyring.ts +4 -3
- package/src/runtime/proxy-errors.ts +132 -0
- package/src/runtime/proxy-telemetry.ts +253 -0
- package/src/runtime/redis.ts +116 -0
- package/src/runtime/request-options.ts +66 -0
- package/src/runtime/state.ts +563 -0
- package/src/runtime/stealth.ts +1159 -0
- package/src/runtime/stt.ts +629 -0
- package/src/runtime/trace.ts +1 -1
- package/src/schema.ts +363 -1
- package/src/server/serve.ts +1172 -76
- package/src/server/types.ts +37 -0
- package/src/stream.ts +210 -0
- package/src/testing/run.ts +31 -5
- package/src/types.ts +1118 -44
- package/src/composite.ts +0 -43
- package/src/runtime/tls.ts +0 -425
- package/src/types/playwright-stealth.d.ts +0 -9
package/bin/apifuse-check.ts
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import type { ProviderDefinition } from "../src";
|
|
10
|
+
import { lintProvider, type ProviderLintMode } from "../src/lint";
|
|
10
11
|
import { safeParseSchemaSync } from "../src/schema";
|
|
11
12
|
|
|
12
13
|
const HELP_TEXT = `Usage: apifuse check [path]
|
|
13
|
-
Example: apifuse check providers/
|
|
14
|
+
Example: apifuse check providers/korea-air-quality
|
|
14
15
|
Default: apifuse check .`;
|
|
15
16
|
|
|
16
|
-
type CheckResult = {
|
|
17
|
+
export type CheckResult = {
|
|
17
18
|
message: string;
|
|
18
19
|
passed: boolean;
|
|
19
20
|
details?: string[];
|
|
20
21
|
};
|
|
21
22
|
|
|
23
|
+
export type RunChecksOptions = {
|
|
24
|
+
lintMode?: ProviderLintMode;
|
|
25
|
+
};
|
|
26
|
+
|
|
22
27
|
type SafeParseResult =
|
|
23
28
|
| { success: true; data: unknown }
|
|
24
29
|
| { success: false; error: unknown };
|
|
@@ -103,7 +108,10 @@ function resolveFromParents(inputPath: string): string {
|
|
|
103
108
|
}
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
async function runChecks(
|
|
111
|
+
export async function runChecks(
|
|
112
|
+
providerRoot: string,
|
|
113
|
+
options: RunChecksOptions = {},
|
|
114
|
+
): Promise<CheckResult[]> {
|
|
107
115
|
const indexPath = resolve(providerRoot, "index.ts");
|
|
108
116
|
const dockerfilePath = resolve(providerRoot, "Dockerfile");
|
|
109
117
|
const packageJsonPath = resolve(providerRoot, "package.json");
|
|
@@ -112,18 +120,61 @@ async function runChecks(providerRoot: string): Promise<CheckResult[]> {
|
|
|
112
120
|
? await import(pathToFileURL(indexPath).href)
|
|
113
121
|
: undefined;
|
|
114
122
|
const provider = assertProviderDefinition(providerModule?.default);
|
|
123
|
+
const providerSourceFiles = collectProviderSourceFiles(providerRoot);
|
|
115
124
|
|
|
116
125
|
return [
|
|
117
126
|
checkIndex(indexPath, provider),
|
|
118
127
|
checkOperations(provider),
|
|
119
128
|
checkFixtures(provider),
|
|
120
129
|
checkSchemas(provider),
|
|
130
|
+
checkAuthoringLint(provider, providerSourceFiles, options.lintMode),
|
|
121
131
|
checkProviderMetadata(provider),
|
|
122
132
|
checkDockerfile(dockerfilePath),
|
|
123
133
|
checkPackageJson(packageJsonPath),
|
|
124
134
|
];
|
|
125
135
|
}
|
|
126
136
|
|
|
137
|
+
function isScannableProviderSourceFile(relativePath: string): boolean {
|
|
138
|
+
return (
|
|
139
|
+
/\.(?:ts|tsx|js|jsx|mjs|cjs|sh|bash)$/.test(relativePath) ||
|
|
140
|
+
/(?:^|\/)Dockerfile(?:\.|$)/.test(relativePath) ||
|
|
141
|
+
/(?:^|\/)entrypoint(?:\.|$)/.test(relativePath)
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function collectProviderSourceFiles(
|
|
146
|
+
providerRoot: string,
|
|
147
|
+
): Record<string, string> {
|
|
148
|
+
const sources: Record<string, string> = {};
|
|
149
|
+
const skipDirectories = new Set([
|
|
150
|
+
".git",
|
|
151
|
+
"node_modules",
|
|
152
|
+
"dist",
|
|
153
|
+
"build",
|
|
154
|
+
".next",
|
|
155
|
+
]);
|
|
156
|
+
const visit = (directory: string) => {
|
|
157
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
158
|
+
const path = resolve(directory, entry.name);
|
|
159
|
+
if (entry.isDirectory()) {
|
|
160
|
+
if (!skipDirectories.has(entry.name)) {
|
|
161
|
+
visit(path);
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (
|
|
166
|
+
!entry.isFile() ||
|
|
167
|
+
!isScannableProviderSourceFile(path.slice(providerRoot.length + 1))
|
|
168
|
+
) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
sources[path.slice(providerRoot.length + 1)] = readFileSync(path, "utf8");
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
visit(providerRoot);
|
|
175
|
+
return sources;
|
|
176
|
+
}
|
|
177
|
+
|
|
127
178
|
function checkIndex(
|
|
128
179
|
indexPath: string,
|
|
129
180
|
provider: ProviderDefinition | undefined,
|
|
@@ -254,6 +305,37 @@ function checkSchemas(provider: ProviderDefinition | undefined): CheckResult {
|
|
|
254
305
|
};
|
|
255
306
|
}
|
|
256
307
|
|
|
308
|
+
function checkAuthoringLint(
|
|
309
|
+
provider: ProviderDefinition | undefined,
|
|
310
|
+
providerSourceFiles: Record<string, string>,
|
|
311
|
+
lintMode: ProviderLintMode = "official",
|
|
312
|
+
): CheckResult {
|
|
313
|
+
if (!provider) {
|
|
314
|
+
return {
|
|
315
|
+
message: "Provider authoring lint has no error-level diagnostics",
|
|
316
|
+
passed: false,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const diagnostics = lintProvider(
|
|
321
|
+
{ ...provider, providerSourceFiles },
|
|
322
|
+
{ mode: lintMode },
|
|
323
|
+
);
|
|
324
|
+
const errors = diagnostics.filter(
|
|
325
|
+
(diagnostic) => diagnostic.level === "error",
|
|
326
|
+
);
|
|
327
|
+
const details = diagnostics.map((diagnostic) => {
|
|
328
|
+
const field = diagnostic.field ? `${diagnostic.field}: ` : "";
|
|
329
|
+
return `${diagnostic.level.toUpperCase()} ${diagnostic.rule} ${field}${diagnostic.message}`;
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
message: "Provider authoring lint has no error-level diagnostics",
|
|
334
|
+
passed: errors.length === 0,
|
|
335
|
+
details,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
257
339
|
function checkProviderMetadata(
|
|
258
340
|
provider: ProviderDefinition | undefined,
|
|
259
341
|
): CheckResult {
|
package/bin/apifuse-dev.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
-
import { dirname, resolve } from "node:path";
|
|
5
|
-
|
|
4
|
+
import { dirname, relative, resolve } from "node:path";
|
|
6
5
|
import type { ProviderDefinition } from "../src";
|
|
7
6
|
import {
|
|
8
7
|
createBrowserClient,
|
|
9
8
|
createCredentialContext,
|
|
10
9
|
createEnvContext,
|
|
11
10
|
createHttpClient,
|
|
12
|
-
|
|
11
|
+
createProviderCache,
|
|
12
|
+
createProviderChoiceContext,
|
|
13
|
+
createStealthClient,
|
|
14
|
+
createSttClientFromEnv,
|
|
15
|
+
PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
|
|
13
16
|
ProviderError,
|
|
14
17
|
} from "../src";
|
|
18
|
+
import { createMemoryProviderRuntimeState } from "../src/runtime/state";
|
|
15
19
|
import { createTraceContext } from "../src/runtime/trace";
|
|
16
20
|
import type { BrowserClient, ProviderContext } from "../src/types";
|
|
17
21
|
|
|
18
22
|
const HELP_TEXT = `Usage: apifuse dev [path]
|
|
19
|
-
Example: apifuse dev providers/
|
|
23
|
+
Example: apifuse dev providers/korea-air-quality
|
|
20
24
|
Default: apifuse dev .`;
|
|
21
25
|
|
|
22
26
|
export async function main() {
|
|
@@ -35,7 +39,7 @@ export async function main() {
|
|
|
35
39
|
);
|
|
36
40
|
|
|
37
41
|
const { startDevServer } = await import("../src/dev");
|
|
38
|
-
const port = Number(process.env.
|
|
42
|
+
const port = Number(process.env.APIFUSE__RUNTIME__PORT) || 3900;
|
|
39
43
|
|
|
40
44
|
startDevServer(provider, { port });
|
|
41
45
|
|
|
@@ -51,28 +55,58 @@ export async function main() {
|
|
|
51
55
|
console.log(` POST http://localhost:${port}/auth/poll`);
|
|
52
56
|
console.log(` POST http://localhost:${port}/auth/disconnect`);
|
|
53
57
|
|
|
58
|
+
const firstOperation = Object.keys(provider.operations)[0];
|
|
59
|
+
if (firstOperation) {
|
|
60
|
+
const sampleInput =
|
|
61
|
+
provider.operations[firstOperation]?.fixtures?.request ?? {};
|
|
62
|
+
const sampleBody = JSON.stringify({
|
|
63
|
+
requestId: `req_local_${firstOperation}`,
|
|
64
|
+
input: sampleInput,
|
|
65
|
+
headers: {},
|
|
66
|
+
});
|
|
67
|
+
console.log("\nSmoke:");
|
|
68
|
+
console.log(` curl -s http://localhost:${port}/health`);
|
|
69
|
+
console.log(
|
|
70
|
+
` curl -s -X POST http://localhost:${port}/v1/${firstOperation} -H 'Content-Type: application/json' -d ${shellSingleQuote(sampleBody)}`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
54
74
|
console.log("\nHot reload:");
|
|
55
|
-
console.log(
|
|
56
|
-
` bun --hot ${resolveImportPath("apifuse-dev.ts")} ${args[0] ?? "."}`,
|
|
57
|
-
);
|
|
75
|
+
console.log(` ${renderHotReloadCommand(providerPath, port)}`);
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
export function createProviderContext(provider: ProviderDefinition): {
|
|
61
79
|
ctx: ProviderContext;
|
|
62
80
|
} {
|
|
81
|
+
const env = createEnvContext([
|
|
82
|
+
...(provider.secrets?.map((secret) => secret.name) ?? []),
|
|
83
|
+
PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
|
|
84
|
+
]);
|
|
85
|
+
const credential = createCredentialContext();
|
|
86
|
+
const state = createMemoryProviderRuntimeState();
|
|
63
87
|
const ctx: ProviderContext = {
|
|
64
|
-
env
|
|
65
|
-
credential
|
|
88
|
+
env,
|
|
89
|
+
credential,
|
|
66
90
|
auth: createUnsupportedAuthStub(),
|
|
67
91
|
browser:
|
|
68
92
|
provider.runtime === "browser"
|
|
69
93
|
? createBrowserClient({
|
|
94
|
+
allowedHosts: provider.allowedHosts,
|
|
70
95
|
engine: provider.browser?.engine ?? "playwright-stealth",
|
|
71
96
|
})
|
|
72
97
|
: createUnsupportedBrowserStub(),
|
|
73
98
|
http: createHttpClient(),
|
|
99
|
+
cache: createProviderCache({ providerId: provider.id }),
|
|
100
|
+
state,
|
|
74
101
|
trace: createTraceContext(),
|
|
75
|
-
|
|
102
|
+
stealth: createStealthClient("http://localhost"),
|
|
103
|
+
stt: createSttClientFromEnv(provider.stt),
|
|
104
|
+
choice: createProviderChoiceContext({
|
|
105
|
+
providerId: provider.id,
|
|
106
|
+
env,
|
|
107
|
+
credential,
|
|
108
|
+
state,
|
|
109
|
+
}),
|
|
76
110
|
};
|
|
77
111
|
|
|
78
112
|
return { ctx };
|
|
@@ -111,13 +145,26 @@ function resolveFromParents(inputPath: string): string {
|
|
|
111
145
|
}
|
|
112
146
|
}
|
|
113
147
|
|
|
114
|
-
function
|
|
115
|
-
|
|
148
|
+
function renderHotReloadCommand(providerPath: string, port: number): string {
|
|
149
|
+
const devEntry = resolve(providerPath, "dev.ts");
|
|
150
|
+
if (existsSync(devEntry)) {
|
|
151
|
+
const relativeDevEntry = relative(process.cwd(), devEntry) || "dev.ts";
|
|
152
|
+
const portPrefix = process.env.APIFUSE__RUNTIME__PORT
|
|
153
|
+
? `APIFUSE__RUNTIME__PORT=${port} `
|
|
154
|
+
: "";
|
|
155
|
+
return `${portPrefix}bun --hot ${relativeDevEntry}`;
|
|
156
|
+
}
|
|
157
|
+
return "rerun `apifuse dev` after edits (no dev.ts entrypoint found)";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function shellSingleQuote(value: string): string {
|
|
161
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
116
162
|
}
|
|
117
163
|
|
|
118
164
|
function createUnsupportedBrowserStub(): BrowserClient {
|
|
119
165
|
return {
|
|
120
166
|
engine: "playwright-stealth",
|
|
167
|
+
async close() {},
|
|
121
168
|
async newPage() {
|
|
122
169
|
throw new ProviderError(
|
|
123
170
|
"Browser runtime is not enabled for this provider",
|
|
@@ -127,6 +174,33 @@ function createUnsupportedBrowserStub(): BrowserClient {
|
|
|
127
174
|
},
|
|
128
175
|
);
|
|
129
176
|
},
|
|
177
|
+
async rawPage() {
|
|
178
|
+
throw new ProviderError(
|
|
179
|
+
"Browser runtime is not enabled for this provider",
|
|
180
|
+
{
|
|
181
|
+
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
182
|
+
fix: 'Set provider runtime to "browser" and APIFUSE__CDP_POOL__URL to use ctx.browser.rawPage',
|
|
183
|
+
},
|
|
184
|
+
);
|
|
185
|
+
},
|
|
186
|
+
async withIsolatedContext() {
|
|
187
|
+
throw new ProviderError(
|
|
188
|
+
"Browser runtime is not enabled for this provider",
|
|
189
|
+
{
|
|
190
|
+
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
191
|
+
fix: 'Set provider runtime to "browser" to use ctx.browser.withIsolatedContext',
|
|
192
|
+
},
|
|
193
|
+
);
|
|
194
|
+
},
|
|
195
|
+
async solveChallenge() {
|
|
196
|
+
throw new ProviderError(
|
|
197
|
+
"Browser runtime is not enabled for this provider",
|
|
198
|
+
{
|
|
199
|
+
code: "BROWSER_RUNTIME_UNSUPPORTED",
|
|
200
|
+
fix: 'Set provider runtime to "browser" to use ctx.browser.solveChallenge',
|
|
201
|
+
},
|
|
202
|
+
);
|
|
203
|
+
},
|
|
130
204
|
};
|
|
131
205
|
}
|
|
132
206
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
|
|
6
7
|
const PACK_RESULT_SCHEMA = z.array(
|
|
@@ -28,12 +29,47 @@ if (!first) {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const filePaths = (first.files ?? []).map((file) => file.path);
|
|
32
|
+
const requiredPaths = [
|
|
33
|
+
"bin/apifuse.ts",
|
|
34
|
+
"bin/apifuse-create.ts",
|
|
35
|
+
"bin/apifuse-pack-smoke.ts",
|
|
36
|
+
"bin/apifuse-submit-check.ts",
|
|
37
|
+
"SUBMISSION.md",
|
|
38
|
+
"src/cli/create.ts",
|
|
39
|
+
"src/cli/templates/provider/.dockerignore.tpl",
|
|
40
|
+
"src/cli/templates/provider/.gitignore.tpl",
|
|
41
|
+
"src/cli/templates/provider/Dockerfile.tpl",
|
|
42
|
+
"src/cli/templates/provider/index.ts.tpl",
|
|
43
|
+
"src/cli/templates/provider/README.md.tpl",
|
|
44
|
+
"src/cli/templates/provider/meta.ts.tpl",
|
|
45
|
+
"src/cli/templates/provider/domain/README.md.tpl",
|
|
46
|
+
"src/cli/templates/provider/mappers/README.md.tpl",
|
|
47
|
+
"src/cli/templates/provider/operations/index.ts.tpl",
|
|
48
|
+
"src/cli/templates/provider/operations/ping.ts.tpl",
|
|
49
|
+
"src/cli/templates/provider/schemas/ping.ts.tpl",
|
|
50
|
+
"src/cli/templates/provider/upstream/README.md.tpl",
|
|
51
|
+
"dist/cli/templates/provider/.dockerignore.tpl",
|
|
52
|
+
"dist/cli/templates/provider/.gitignore.tpl",
|
|
53
|
+
"dist/cli/templates/provider/Dockerfile.tpl",
|
|
54
|
+
"dist/cli/templates/provider/index.ts.tpl",
|
|
55
|
+
"dist/cli/templates/provider/README.md.tpl",
|
|
56
|
+
"dist/cli/templates/provider/meta.ts.tpl",
|
|
57
|
+
"dist/cli/templates/provider/domain/README.md.tpl",
|
|
58
|
+
"dist/cli/templates/provider/mappers/README.md.tpl",
|
|
59
|
+
"dist/cli/templates/provider/operations/index.ts.tpl",
|
|
60
|
+
"dist/cli/templates/provider/operations/ping.ts.tpl",
|
|
61
|
+
"dist/cli/templates/provider/schemas/ping.ts.tpl",
|
|
62
|
+
"dist/cli/templates/provider/upstream/README.md.tpl",
|
|
63
|
+
];
|
|
31
64
|
const forbiddenMatches = filePaths.filter(
|
|
32
65
|
(path) =>
|
|
33
66
|
path.startsWith("src/__tests__/") ||
|
|
34
67
|
path === "src/index.test.ts" ||
|
|
35
68
|
path === "bin/apifuse-init.ts",
|
|
36
69
|
);
|
|
70
|
+
const missingRequiredPaths = requiredPaths.filter(
|
|
71
|
+
(path) => !filePaths.includes(path),
|
|
72
|
+
);
|
|
37
73
|
|
|
38
74
|
if (forbiddenMatches.length > 0) {
|
|
39
75
|
throw new Error(
|
|
@@ -41,7 +77,91 @@ if (forbiddenMatches.length > 0) {
|
|
|
41
77
|
);
|
|
42
78
|
}
|
|
43
79
|
|
|
80
|
+
if (missingRequiredPaths.length > 0) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Packed artifact is missing required public SDK files:\n${missingRequiredPaths.join("\n")}`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const packageJsonInput: unknown = JSON.parse(
|
|
87
|
+
readFileSync("package.json", "utf8"),
|
|
88
|
+
);
|
|
89
|
+
const packageJson = z
|
|
90
|
+
.object({
|
|
91
|
+
dependencies: z.record(z.string(), z.string()).optional(),
|
|
92
|
+
devDependencies: z.record(z.string(), z.string()).optional(),
|
|
93
|
+
})
|
|
94
|
+
.parse(packageJsonInput);
|
|
95
|
+
|
|
96
|
+
if (!packageJson.dependencies?.["@clack/prompts"]) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
"@clack/prompts is imported by the public create CLI and must be listed in dependencies.",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (packageJson.devDependencies?.["@clack/prompts"]) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"@clack/prompts must not be devDependency-only because the published create CLI imports it at runtime.",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
assertPublicSmokeDocs("README.md", readFileSync("README.md", "utf8"));
|
|
109
|
+
assertPublicSmokeDocs(
|
|
110
|
+
"src/cli/templates/provider/README.md.tpl",
|
|
111
|
+
readFileSync("src/cli/templates/provider/README.md.tpl", "utf8"),
|
|
112
|
+
);
|
|
113
|
+
|
|
44
114
|
console.log(`Packed artifact OK: ${first.filename}`);
|
|
45
115
|
for (const filePath of filePaths) {
|
|
46
116
|
console.log(` - ${filePath}`);
|
|
47
117
|
}
|
|
118
|
+
|
|
119
|
+
function assertPublicSmokeDocs(label: string, content: string): void {
|
|
120
|
+
if (!content.includes('"requestId":"req_local_ping"')) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`${label} must document the current provider server request envelope with requestId.`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (content.includes('"connection":null')) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`${label} must not tell public users to send connection:null; omit connection for no-auth operations.`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!content.includes("bunx playwright install chromium")) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`${label} must include browser runtime troubleshooting for public SDK-only debugging.`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!content.includes("impit")) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`${label} must include impit stealth runtime guidance for TLS/browser bounties.`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!content.includes("submit-check")) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`${label} must document the submit-check pre-submission workflow.`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (
|
|
151
|
+
!content.includes('browser.engine: "playwright-stealth"') ||
|
|
152
|
+
!content.includes("nodriver")
|
|
153
|
+
) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`${label} must clarify that TypeScript browser providers use playwright-stealth and nodriver is not the TypeScript happy path.`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (
|
|
160
|
+
label.includes("templates/provider/README.md.tpl") &&
|
|
161
|
+
!content.includes("bun run record -- --operation <operation>")
|
|
162
|
+
) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`${label} must document fixture recording through a generated package script, not a shell-global apifuse command.`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|