@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/lint.ts
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import type { ZodType } from "zod";
|
|
2
2
|
|
|
3
|
-
import { lintPublicSchemaFieldNames } from "./public-schema-field-lint";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "./schema";
|
|
8
|
-
|
|
9
|
-
type AuthModeLike =
|
|
10
|
-
| "none"
|
|
11
|
-
| "platform-managed"
|
|
12
|
-
| "credentials"
|
|
13
|
-
| "oauth2"
|
|
14
|
-
| "api-key";
|
|
3
|
+
import { lintPublicSchemaFieldNames } from "./public-schema-field-lint.js";
|
|
4
|
+
import { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_SENSITIVE_META_KEY } from "./schema.js";
|
|
5
|
+
|
|
6
|
+
type AuthModeLike = "none" | "platform-managed" | "credentials" | "oauth2" | "api-key";
|
|
15
7
|
|
|
16
8
|
type ProviderAuthLike = {
|
|
17
9
|
mode?: AuthModeLike;
|
|
@@ -22,8 +14,12 @@ type ProviderAuthLike = {
|
|
|
22
14
|
abort?: unknown;
|
|
23
15
|
refresh?: unknown;
|
|
24
16
|
};
|
|
17
|
+
exchange?: unknown;
|
|
25
18
|
};
|
|
26
19
|
|
|
20
|
+
const AUTH_OPERATION_ID_PATTERN =
|
|
21
|
+
/^(?:auth[-_])?(?:login|exchange|continue|refresh|callback)(?:[-_]|$)/i;
|
|
22
|
+
|
|
27
23
|
type ProviderContractMetaLike = {
|
|
28
24
|
publicSchemaFieldNames?: "normalized";
|
|
29
25
|
};
|
|
@@ -127,34 +123,29 @@ function lintReviewed(
|
|
|
127
123
|
];
|
|
128
124
|
}
|
|
129
125
|
|
|
126
|
+
function isProviderAuthLike(value: unknown): value is ProviderAuthLike {
|
|
127
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
130
|
function hasReusableSecretKeys(keys: readonly string[] | undefined): boolean {
|
|
131
131
|
if (!keys) {
|
|
132
132
|
return false;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
return keys.some((key) =>
|
|
136
|
-
/(access_token|refresh_token|password|secret|cookie|session|token|api[_-]?key)/i.test(
|
|
137
|
-
key,
|
|
138
|
-
),
|
|
136
|
+
/(access_token|refresh_token|password|secret|cookie|session|token|api[_-]?key)/i.test(key),
|
|
139
137
|
);
|
|
140
138
|
}
|
|
141
139
|
|
|
142
|
-
function hasReusableReloginSecretKeys(
|
|
143
|
-
keys: readonly string[] | undefined,
|
|
144
|
-
): boolean {
|
|
140
|
+
function hasReusableReloginSecretKeys(keys: readonly string[] | undefined): boolean {
|
|
145
141
|
if (!keys) {
|
|
146
142
|
return false;
|
|
147
143
|
}
|
|
148
144
|
|
|
149
|
-
return keys.some((key) =>
|
|
150
|
-
/(password|passcode|secret|cookie|session)/i.test(key),
|
|
151
|
-
);
|
|
145
|
+
return keys.some((key) => /(password|passcode|secret|cookie|session)/i.test(key));
|
|
152
146
|
}
|
|
153
147
|
|
|
154
|
-
function getAuthFlowSource(provider: {
|
|
155
|
-
auth?: ProviderAuthLike;
|
|
156
|
-
authFlowSource?: string;
|
|
157
|
-
}): string {
|
|
148
|
+
function getAuthFlowSource(provider: { auth?: ProviderAuthLike; authFlowSource?: string }): string {
|
|
158
149
|
if (provider.authFlowSource) {
|
|
159
150
|
return provider.authFlowSource;
|
|
160
151
|
}
|
|
@@ -168,10 +159,7 @@ function getAuthFlowSource(provider: {
|
|
|
168
159
|
];
|
|
169
160
|
|
|
170
161
|
return parts
|
|
171
|
-
.filter(
|
|
172
|
-
(part): part is (...args: unknown[]) => unknown =>
|
|
173
|
-
typeof part === "function",
|
|
174
|
-
)
|
|
162
|
+
.filter((part): part is (...args: unknown[]) => unknown => typeof part === "function")
|
|
175
163
|
.map((part) => part.toString())
|
|
176
164
|
.join("\n");
|
|
177
165
|
}
|
|
@@ -215,6 +203,15 @@ function lintAuthModel(provider: {
|
|
|
215
203
|
});
|
|
216
204
|
}
|
|
217
205
|
|
|
206
|
+
if (isProviderAuthLike(provider.auth) && "exchange" in provider.auth) {
|
|
207
|
+
diagnostics.push({
|
|
208
|
+
rule: "auth-exchange-unsupported",
|
|
209
|
+
level: "error",
|
|
210
|
+
field: "auth.exchange",
|
|
211
|
+
message: `${providerLabel} must not define auth.exchange. The Provider SDK has one auth interface: auth.flow. Gateway only calls auth.flow.start/continue/poll/abort/refresh and persists complete turn data.credential as-is; put login/token/session exchange inside auth.flow.continue.`,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
218
215
|
if (authMode === "credentials" && credentialKeys.length === 0) {
|
|
219
216
|
diagnostics.push({
|
|
220
217
|
rule: "credential-keys-required-when-credentials-mode",
|
|
@@ -226,8 +223,7 @@ function lintAuthModel(provider: {
|
|
|
226
223
|
|
|
227
224
|
if (
|
|
228
225
|
hasReusableSecretKeys(credentialKeys) &&
|
|
229
|
-
(!provider.credential?.storesReusableSecret ||
|
|
230
|
-
!provider.credential.justification)
|
|
226
|
+
(!provider.credential?.storesReusableSecret || !provider.credential.justification)
|
|
231
227
|
) {
|
|
232
228
|
diagnostics.push({
|
|
233
229
|
rule: "credential-reusable-secret",
|
|
@@ -240,8 +236,7 @@ function lintAuthModel(provider: {
|
|
|
240
236
|
if (
|
|
241
237
|
typeof provider.auth?.flow?.refresh === "function" &&
|
|
242
238
|
hasReusableReloginSecretKeys(credentialKeys) &&
|
|
243
|
-
(!provider.credential?.storesReusableSecret ||
|
|
244
|
-
!provider.credential.justification)
|
|
239
|
+
(!provider.credential?.storesReusableSecret || !provider.credential.justification)
|
|
245
240
|
) {
|
|
246
241
|
diagnostics.push({
|
|
247
242
|
rule: "auth-refresh-reusable-secret",
|
|
@@ -261,10 +256,7 @@ function lintAuthModel(provider: {
|
|
|
261
256
|
}
|
|
262
257
|
|
|
263
258
|
const authFlowSource = getAuthFlowSource(provider);
|
|
264
|
-
if (
|
|
265
|
-
authFlowSource.includes("ctx.context") &&
|
|
266
|
-
(provider.context?.keys?.length ?? 0) === 0
|
|
267
|
-
) {
|
|
259
|
+
if (authFlowSource.includes("ctx.context") && (provider.context?.keys?.length ?? 0) === 0) {
|
|
268
260
|
diagnostics.push({
|
|
269
261
|
rule: "context-keys-required",
|
|
270
262
|
level: "warn",
|
|
@@ -306,8 +298,7 @@ function isSchemaRecord(value: unknown): value is Record<string, SchemaLike> {
|
|
|
306
298
|
}
|
|
307
299
|
|
|
308
300
|
function getObjectShape(schema: SchemaLike): Record<string, SchemaLike> {
|
|
309
|
-
const rawShape =
|
|
310
|
-
typeof schema.shape === "function" ? schema.shape() : schema.shape;
|
|
301
|
+
const rawShape = typeof schema.shape === "function" ? schema.shape() : schema.shape;
|
|
311
302
|
if (isSchemaRecord(rawShape)) {
|
|
312
303
|
return rawShape;
|
|
313
304
|
}
|
|
@@ -327,9 +318,7 @@ function getObjectShape(schema: SchemaLike): Record<string, SchemaLike> {
|
|
|
327
318
|
return {};
|
|
328
319
|
}
|
|
329
320
|
|
|
330
|
-
function getChildSchemas(
|
|
331
|
-
schema: SchemaLike,
|
|
332
|
-
): Array<{ key: string; schema: SchemaLike }> {
|
|
321
|
+
function getChildSchemas(schema: SchemaLike): Array<{ key: string; schema: SchemaLike }> {
|
|
333
322
|
const seen = new Map<string, SchemaLike>();
|
|
334
323
|
const def = getSchemaDef(schema);
|
|
335
324
|
|
|
@@ -433,10 +422,7 @@ function getSchemaMetadata(schema: SchemaLike): Record<string, unknown> {
|
|
|
433
422
|
}
|
|
434
423
|
|
|
435
424
|
function getSchemaDescriptionKey(schema: SchemaLike): string | undefined {
|
|
436
|
-
const value = Reflect.get(
|
|
437
|
-
getSchemaMetadata(schema),
|
|
438
|
-
APIFUSE_DESCRIPTION_KEY_META_KEY,
|
|
439
|
-
);
|
|
425
|
+
const value = Reflect.get(getSchemaMetadata(schema), APIFUSE_DESCRIPTION_KEY_META_KEY);
|
|
440
426
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
441
427
|
}
|
|
442
428
|
|
|
@@ -580,22 +566,14 @@ function collectSchemaDescriptionKeyDiagnostics(
|
|
|
580
566
|
? `${currentPath}[]`
|
|
581
567
|
: `${currentPath}.${child.key}`;
|
|
582
568
|
diagnostics.push(
|
|
583
|
-
...collectSchemaDescriptionKeyDiagnostics(
|
|
584
|
-
child.schema,
|
|
585
|
-
childPath,
|
|
586
|
-
seen,
|
|
587
|
-
!isStructuralNode,
|
|
588
|
-
),
|
|
569
|
+
...collectSchemaDescriptionKeyDiagnostics(child.schema, childPath, seen, !isStructuralNode),
|
|
589
570
|
);
|
|
590
571
|
}
|
|
591
572
|
|
|
592
573
|
return diagnostics;
|
|
593
574
|
}
|
|
594
575
|
|
|
595
|
-
function isComplexSchema(
|
|
596
|
-
schema: unknown,
|
|
597
|
-
seen = new Set<SchemaLike>(),
|
|
598
|
-
): boolean {
|
|
576
|
+
function isComplexSchema(schema: unknown, seen = new Set<SchemaLike>()): boolean {
|
|
599
577
|
if (!isSchema(schema) || seen.has(schema)) {
|
|
600
578
|
return false;
|
|
601
579
|
}
|
|
@@ -607,10 +585,7 @@ function isComplexSchema(
|
|
|
607
585
|
return childChildren.length > 0;
|
|
608
586
|
});
|
|
609
587
|
|
|
610
|
-
return (
|
|
611
|
-
hasNestedComposite ||
|
|
612
|
-
children.some(({ schema: child }) => isComplexSchema(child, seen))
|
|
613
|
-
);
|
|
588
|
+
return hasNestedComposite || children.some(({ schema: child }) => isComplexSchema(child, seen));
|
|
614
589
|
}
|
|
615
590
|
|
|
616
591
|
function hasBidirectionalFixtures(fixtures: unknown): boolean {
|
|
@@ -621,16 +596,11 @@ function hasBidirectionalFixtures(fixtures: unknown): boolean {
|
|
|
621
596
|
return "request" in fixtures && "response" in fixtures;
|
|
622
597
|
}
|
|
623
598
|
|
|
624
|
-
function getOperationSource(operation: {
|
|
625
|
-
handler?: unknown;
|
|
626
|
-
source?: string;
|
|
627
|
-
}): string {
|
|
599
|
+
function getOperationSource(operation: { handler?: unknown; source?: string }): string {
|
|
628
600
|
if (operation.source) {
|
|
629
601
|
return operation.source;
|
|
630
602
|
}
|
|
631
|
-
return typeof operation.handler === "function"
|
|
632
|
-
? operation.handler.toString()
|
|
633
|
-
: "";
|
|
603
|
+
return typeof operation.handler === "function" ? operation.handler.toString() : "";
|
|
634
604
|
}
|
|
635
605
|
|
|
636
606
|
function lintStealthTransportUsage(provider: {
|
|
@@ -643,22 +613,20 @@ function lintStealthTransportUsage(provider: {
|
|
|
643
613
|
}
|
|
644
614
|
|
|
645
615
|
const providerLabel = provider.id ? `Provider "${provider.id}"` : "Provider";
|
|
646
|
-
return Object.entries(provider.operations).flatMap(
|
|
647
|
-
(
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
},
|
|
661
|
-
);
|
|
616
|
+
return Object.entries(provider.operations).flatMap(([operationKey, operation]) => {
|
|
617
|
+
const source = getOperationSource(operation);
|
|
618
|
+
if (!/\bctx\.stealth\b/.test(source)) {
|
|
619
|
+
return [];
|
|
620
|
+
}
|
|
621
|
+
return [
|
|
622
|
+
{
|
|
623
|
+
rule: "stealth-config-required",
|
|
624
|
+
level: "error" as const,
|
|
625
|
+
field: `operations.${operationKey}`,
|
|
626
|
+
message: `${providerLabel} operation "${operationKey}" uses ctx.stealth but provider.stealth is not declared.`,
|
|
627
|
+
},
|
|
628
|
+
];
|
|
629
|
+
});
|
|
662
630
|
}
|
|
663
631
|
|
|
664
632
|
function lintCredentialWriteUsage(provider: {
|
|
@@ -668,24 +636,22 @@ function lintCredentialWriteUsage(provider: {
|
|
|
668
636
|
return [];
|
|
669
637
|
}
|
|
670
638
|
|
|
671
|
-
return Object.entries(provider.operations).flatMap(
|
|
672
|
-
(
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
639
|
+
return Object.entries(provider.operations).flatMap(([operationKey, operation]) => {
|
|
640
|
+
const source = getOperationSource(operation);
|
|
641
|
+
if (!/\bctx\.credential\.(?:set|setMany)\s*\(/.test(source)) {
|
|
642
|
+
return [];
|
|
643
|
+
}
|
|
677
644
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
);
|
|
645
|
+
return [
|
|
646
|
+
{
|
|
647
|
+
rule: "ctx-credential-write-forbidden-in-handler",
|
|
648
|
+
level: "error" as const,
|
|
649
|
+
field: `operations.${operationKey}.handler`,
|
|
650
|
+
message:
|
|
651
|
+
"Operation handlers must not mutate credentials; return refreshed credentials from auth.flow.refresh instead.",
|
|
652
|
+
},
|
|
653
|
+
];
|
|
654
|
+
});
|
|
689
655
|
}
|
|
690
656
|
|
|
691
657
|
function lintPlaywrightDirectImports(provider: {
|
|
@@ -707,9 +673,7 @@ function lintPlaywrightDirectImports(provider: {
|
|
|
707
673
|
});
|
|
708
674
|
}
|
|
709
675
|
|
|
710
|
-
for (const [filePath, source] of Object.entries(
|
|
711
|
-
provider.providerSourceFiles ?? {},
|
|
712
|
-
)) {
|
|
676
|
+
for (const [filePath, source] of Object.entries(provider.providerSourceFiles ?? {})) {
|
|
713
677
|
if (!importPattern.test(source)) {
|
|
714
678
|
continue;
|
|
715
679
|
}
|
|
@@ -797,15 +761,11 @@ function lintSelfHostedBrowserPatterns(
|
|
|
797
761
|
sources.push({ field: "auth.flow", source: provider.authFlowSource });
|
|
798
762
|
}
|
|
799
763
|
|
|
800
|
-
for (const [filePath, source] of Object.entries(
|
|
801
|
-
provider.providerSourceFiles ?? {},
|
|
802
|
-
)) {
|
|
764
|
+
for (const [filePath, source] of Object.entries(provider.providerSourceFiles ?? {})) {
|
|
803
765
|
sources.push({ field: `sourceFiles.${filePath}`, source });
|
|
804
766
|
}
|
|
805
767
|
|
|
806
|
-
for (const [operationKey, operation] of Object.entries(
|
|
807
|
-
provider.operations ?? {},
|
|
808
|
-
)) {
|
|
768
|
+
for (const [operationKey, operation] of Object.entries(provider.operations ?? {})) {
|
|
809
769
|
const source = getOperationSource(operation);
|
|
810
770
|
if (source) {
|
|
811
771
|
sources.push({
|
|
@@ -848,16 +808,14 @@ export function lintOperation(op: {
|
|
|
848
808
|
}): LintDiagnostic[] {
|
|
849
809
|
const diagnostics: LintDiagnostic[] = [];
|
|
850
810
|
const description = op.description ?? "";
|
|
851
|
-
const hasDescriptionKey =
|
|
852
|
-
typeof op.descriptionKey === "string" && op.descriptionKey.length > 0;
|
|
811
|
+
const hasDescriptionKey = typeof op.descriptionKey === "string" && op.descriptionKey.length > 0;
|
|
853
812
|
|
|
854
813
|
if (description.trim().length > 0 && !hasDescriptionKey) {
|
|
855
814
|
diagnostics.push({
|
|
856
815
|
rule: "operation-description-raw-prose",
|
|
857
816
|
level: "error",
|
|
858
817
|
field: "description",
|
|
859
|
-
message:
|
|
860
|
-
"Operation description must use descriptionKey instead of raw static prose.",
|
|
818
|
+
message: "Operation description must use descriptionKey instead of raw static prose.",
|
|
861
819
|
});
|
|
862
820
|
}
|
|
863
821
|
|
|
@@ -875,21 +833,16 @@ export function lintOperation(op: {
|
|
|
875
833
|
rule: "operation-when-to-use-raw-prose",
|
|
876
834
|
level: "error",
|
|
877
835
|
field: "whenToUse",
|
|
878
|
-
message:
|
|
879
|
-
"Operation whenToUse must use whenToUseKeys instead of raw static prose.",
|
|
836
|
+
message: "Operation whenToUse must use whenToUseKeys instead of raw static prose.",
|
|
880
837
|
});
|
|
881
838
|
}
|
|
882
839
|
|
|
883
|
-
if (
|
|
884
|
-
(op.whenNotToUse?.length ?? 0) > 0 &&
|
|
885
|
-
!(op.whenNotToUseKeys?.length ?? 0)
|
|
886
|
-
) {
|
|
840
|
+
if ((op.whenNotToUse?.length ?? 0) > 0 && !(op.whenNotToUseKeys?.length ?? 0)) {
|
|
887
841
|
diagnostics.push({
|
|
888
842
|
rule: "operation-when-not-to-use-raw-prose",
|
|
889
843
|
level: "error",
|
|
890
844
|
field: "whenNotToUse",
|
|
891
|
-
message:
|
|
892
|
-
"Operation whenNotToUse must use whenNotToUseKeys instead of raw static prose.",
|
|
845
|
+
message: "Operation whenNotToUse must use whenNotToUseKeys instead of raw static prose.",
|
|
893
846
|
});
|
|
894
847
|
}
|
|
895
848
|
|
|
@@ -925,14 +878,11 @@ export function lintOperation(op: {
|
|
|
925
878
|
rule: "complex-input-has-examples",
|
|
926
879
|
level: "warn",
|
|
927
880
|
field: "inputExamples",
|
|
928
|
-
message:
|
|
929
|
-
"Complex input schemas should provide at least 2 input examples.",
|
|
881
|
+
message: "Complex input schemas should provide at least 2 input examples.",
|
|
930
882
|
});
|
|
931
883
|
}
|
|
932
884
|
|
|
933
|
-
for (const field of uniqueFields(
|
|
934
|
-
collectUnmarkedSensitiveFields(op.input, "input"),
|
|
935
|
-
)) {
|
|
885
|
+
for (const field of uniqueFields(collectUnmarkedSensitiveFields(op.input, "input"))) {
|
|
936
886
|
diagnostics.push({
|
|
937
887
|
rule: "sensitive-field-unmarked",
|
|
938
888
|
level: "warn",
|
|
@@ -941,9 +891,7 @@ export function lintOperation(op: {
|
|
|
941
891
|
});
|
|
942
892
|
}
|
|
943
893
|
|
|
944
|
-
for (const field of uniqueFields(
|
|
945
|
-
collectUnmarkedSensitiveFields(op.output, "output"),
|
|
946
|
-
)) {
|
|
894
|
+
for (const field of uniqueFields(collectUnmarkedSensitiveFields(op.output, "output"))) {
|
|
947
895
|
diagnostics.push({
|
|
948
896
|
rule: "sensitive-field-unmarked",
|
|
949
897
|
level: "warn",
|
|
@@ -1006,41 +954,56 @@ export function lintProvider(
|
|
|
1006
954
|
...lintSelfHostedBrowserPatterns(provider, options),
|
|
1007
955
|
];
|
|
1008
956
|
|
|
957
|
+
if (provider.operations) {
|
|
958
|
+
const authMode = provider.auth?.mode;
|
|
959
|
+
if (authMode === "credentials" || authMode === "oauth2") {
|
|
960
|
+
for (const operationKey of Object.keys(provider.operations)) {
|
|
961
|
+
if (AUTH_OPERATION_ID_PATTERN.test(operationKey)) {
|
|
962
|
+
diagnostics.push({
|
|
963
|
+
rule: "auth-operation-unsupported",
|
|
964
|
+
level: "error",
|
|
965
|
+
field: `operations.${operationKey}`,
|
|
966
|
+
message: `Provider "${provider.id ?? "unknown"}" operation "${operationKey}" looks like a login/token/session exchange endpoint. Authenticated providers must expose login through the single auth.flow interface because Gateway persists only auth.flow complete turn data.credential as the connection credential. Move this logic into auth.flow.continue instead of a provider operation.`,
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
|
|
1009
973
|
if (!provider.operations) {
|
|
1010
974
|
return diagnostics;
|
|
1011
975
|
}
|
|
1012
976
|
|
|
1013
977
|
diagnostics.push(
|
|
1014
|
-
...Object.entries(provider.operations).flatMap(
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
})),
|
|
978
|
+
...Object.entries(provider.operations).flatMap(([operationKey, operation]) =>
|
|
979
|
+
[
|
|
980
|
+
...lintOperation({
|
|
981
|
+
description: operation.description ?? "",
|
|
982
|
+
descriptionKey: operation.descriptionKey,
|
|
983
|
+
whenToUse: operation.whenToUse,
|
|
984
|
+
whenToUseKeys: operation.whenToUseKeys,
|
|
985
|
+
whenNotToUse: operation.whenNotToUse,
|
|
986
|
+
whenNotToUseKeys: operation.whenNotToUseKeys,
|
|
987
|
+
input: operation.input,
|
|
988
|
+
output: operation.output,
|
|
989
|
+
fixtures: operation.fixtures,
|
|
990
|
+
inputExamples: operation.inputExamples,
|
|
991
|
+
derivations: operation.derivations,
|
|
992
|
+
}),
|
|
993
|
+
...lintPublicSchemaFieldNames(
|
|
994
|
+
provider.id,
|
|
995
|
+
operationKey,
|
|
996
|
+
operation.input,
|
|
997
|
+
operation.output,
|
|
998
|
+
provider.meta?.contract?.publicSchemaFieldNames === "normalized",
|
|
999
|
+
),
|
|
1000
|
+
].map((diagnostic) => ({
|
|
1001
|
+
...diagnostic,
|
|
1002
|
+
field: diagnostic.field
|
|
1003
|
+
? `operations.${operationKey}.${diagnostic.field}`
|
|
1004
|
+
: `operations.${operationKey}`,
|
|
1005
|
+
message: `[${operationKey}] ${diagnostic.message}`,
|
|
1006
|
+
})),
|
|
1044
1007
|
),
|
|
1045
1008
|
);
|
|
1046
1009
|
|
package/src/provider.ts
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
AuthAbortError,
|
|
3
|
+
credentialsAuthChallenge,
|
|
4
|
+
createAuthFlowHelpers,
|
|
5
|
+
defineCredentialsAuth,
|
|
6
|
+
} from "./auth.js";
|
|
7
|
+
export type {
|
|
8
|
+
CredentialsAuthChallengeDefinition,
|
|
9
|
+
CredentialsAuthChallengeRequest,
|
|
10
|
+
CredentialsAuthCompleteResult,
|
|
11
|
+
CredentialsAuthCredential,
|
|
12
|
+
CredentialsAuthField,
|
|
13
|
+
CredentialsAuthFields,
|
|
14
|
+
CredentialsAuthFieldType,
|
|
15
|
+
CredentialsAuthInput,
|
|
16
|
+
CredentialsAuthLoginResult,
|
|
17
|
+
DefineCredentialsAuthOptions,
|
|
18
|
+
DefinedCredentialsAuth,
|
|
19
|
+
} from "./auth.js";
|
|
20
|
+
export { createFormCeremony } from "./ceremonies/index.js";
|
|
2
21
|
export {
|
|
3
22
|
assertFreshProviderChoiceIssuedAt,
|
|
4
23
|
createProviderChoiceToken,
|
|
@@ -6,32 +25,37 @@ export {
|
|
|
6
25
|
type ProviderChoiceTokenErrorReason,
|
|
7
26
|
type ProviderChoiceTokenPayload,
|
|
8
27
|
parseProviderChoiceToken,
|
|
9
|
-
} from "./choice-token";
|
|
28
|
+
} from "./choice-token.js";
|
|
10
29
|
export {
|
|
30
|
+
centered,
|
|
31
|
+
delayed,
|
|
11
32
|
defineHealthJourney,
|
|
12
33
|
defineOperation,
|
|
13
34
|
defineProvider,
|
|
14
35
|
defineSmsOtpMatcher,
|
|
15
36
|
every,
|
|
16
|
-
} from "./define";
|
|
37
|
+
} from "./define.js";
|
|
17
38
|
export {
|
|
18
39
|
AuthError,
|
|
40
|
+
isProviderError,
|
|
41
|
+
isSessionExpiredError,
|
|
42
|
+
isTransportError,
|
|
19
43
|
ProviderError,
|
|
20
44
|
SessionExpiredError,
|
|
21
45
|
TransportError,
|
|
22
46
|
ValidationError,
|
|
23
|
-
} from "./errors";
|
|
47
|
+
} from "./errors.js";
|
|
24
48
|
export {
|
|
25
49
|
getProviderLocalePath,
|
|
26
50
|
providerLocaleKey,
|
|
27
51
|
qualifyProviderLocaleKey,
|
|
28
|
-
} from "./i18n";
|
|
52
|
+
} from "./i18n/index.js";
|
|
29
53
|
export {
|
|
30
54
|
type CreateProviderChoiceContextOptions,
|
|
31
55
|
createProviderChoiceContext,
|
|
32
56
|
createTestProviderChoiceContext,
|
|
33
57
|
PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV,
|
|
34
|
-
} from "./runtime/choice";
|
|
58
|
+
} from "./runtime/choice.js";
|
|
35
59
|
export {
|
|
36
60
|
APIFUSE_DESCRIPTION_KEY_META_KEY,
|
|
37
61
|
APIFUSE_REDACTION_MARKER,
|
|
@@ -48,9 +72,14 @@ export {
|
|
|
48
72
|
type SensitivePath,
|
|
49
73
|
sensitive,
|
|
50
74
|
z,
|
|
51
|
-
} from "./schema";
|
|
75
|
+
} from "./schema.js";
|
|
52
76
|
export type {
|
|
77
|
+
AuthAbortData,
|
|
78
|
+
AuthAbortRetry,
|
|
79
|
+
AuthFlowTerminalContext,
|
|
53
80
|
AuthMode,
|
|
81
|
+
AuthSafeData,
|
|
82
|
+
AuthSafeJson,
|
|
54
83
|
FlowContext,
|
|
55
84
|
HealthCheckAssertionContext,
|
|
56
85
|
HealthCheckCase,
|
|
@@ -61,6 +90,7 @@ export type {
|
|
|
61
90
|
HealthJourneyManualTriggerPolicy,
|
|
62
91
|
HealthJourneyRunContext,
|
|
63
92
|
HealthJourneyRunResult,
|
|
93
|
+
HealthScheduleRandomization,
|
|
64
94
|
HttpRetryOptions,
|
|
65
95
|
HttpRetrySummary,
|
|
66
96
|
InferSchemaOutput,
|
|
@@ -85,6 +115,7 @@ export type {
|
|
|
85
115
|
ProviderChoiceParseOptions,
|
|
86
116
|
ProviderContext,
|
|
87
117
|
ProviderDefinition,
|
|
118
|
+
ProviderDeploymentOverrides,
|
|
88
119
|
ProviderLocale,
|
|
89
120
|
ProviderLocaleKey,
|
|
90
121
|
ProviderLocaleKeyInput,
|
|
@@ -103,11 +134,11 @@ export type {
|
|
|
103
134
|
StateNamespaceOptions,
|
|
104
135
|
StateValue,
|
|
105
136
|
StateWriteOptions,
|
|
106
|
-
} from "./types";
|
|
137
|
+
} from "./types.js";
|
|
107
138
|
export {
|
|
108
139
|
HttpRetryAfterPolicy,
|
|
109
140
|
HttpRetryDelayStrategy,
|
|
110
141
|
HttpRetryJitter,
|
|
111
142
|
HttpRetryPreset,
|
|
112
143
|
HttpRetryUnsafeMethodPolicy,
|
|
113
|
-
} from "./types";
|
|
144
|
+
} from "./types.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ZodType } from "zod";
|
|
2
2
|
|
|
3
|
-
import type { LintDiagnostic } from "./lint";
|
|
3
|
+
import type { LintDiagnostic } from "./lint.js";
|
|
4
4
|
|
|
5
5
|
type SchemaLike = ZodType & {
|
|
6
6
|
def?: Record<string, unknown>;
|
|
@@ -55,8 +55,7 @@ function isSchemaRecord(value: unknown): value is Record<string, SchemaLike> {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
function getObjectShape(schema: SchemaLike): Record<string, SchemaLike> {
|
|
58
|
-
const rawShape =
|
|
59
|
-
typeof schema.shape === "function" ? schema.shape() : schema.shape;
|
|
58
|
+
const rawShape = typeof schema.shape === "function" ? schema.shape() : schema.shape;
|
|
60
59
|
if (isSchemaRecord(rawShape)) {
|
|
61
60
|
return rawShape;
|
|
62
61
|
}
|
|
@@ -69,10 +68,7 @@ function getObjectShape(schema: SchemaLike): Record<string, SchemaLike> {
|
|
|
69
68
|
return isSchemaRecord(defShape) ? defShape : {};
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
function appendSchemaChildren(
|
|
73
|
-
children: SchemaLike[],
|
|
74
|
-
value: unknown,
|
|
75
|
-
): SchemaLike[] {
|
|
71
|
+
function appendSchemaChildren(children: SchemaLike[], value: unknown): SchemaLike[] {
|
|
76
72
|
if (isSchema(value)) {
|
|
77
73
|
children.push(value);
|
|
78
74
|
return children;
|
|
@@ -183,26 +179,14 @@ function collectPublicSchemaFieldDiagnostics(
|
|
|
183
179
|
});
|
|
184
180
|
}
|
|
185
181
|
diagnostics.push(
|
|
186
|
-
...collectPublicSchemaFieldDiagnostics(
|
|
187
|
-
providerId,
|
|
188
|
-
operationId,
|
|
189
|
-
child,
|
|
190
|
-
fieldPath,
|
|
191
|
-
seen,
|
|
192
|
-
),
|
|
182
|
+
...collectPublicSchemaFieldDiagnostics(providerId, operationId, child, fieldPath, seen),
|
|
193
183
|
);
|
|
194
184
|
}
|
|
195
185
|
|
|
196
186
|
for (const child of getTransparentChildSchemas(schema)) {
|
|
197
187
|
const childPath = schema.element === child ? `${basePath}[]` : basePath;
|
|
198
188
|
diagnostics.push(
|
|
199
|
-
...collectPublicSchemaFieldDiagnostics(
|
|
200
|
-
providerId,
|
|
201
|
-
operationId,
|
|
202
|
-
child,
|
|
203
|
-
childPath,
|
|
204
|
-
seen,
|
|
205
|
-
),
|
|
189
|
+
...collectPublicSchemaFieldDiagnostics(providerId, operationId, child, childPath, seen),
|
|
206
190
|
);
|
|
207
191
|
}
|
|
208
192
|
|
|
@@ -221,17 +205,7 @@ export function lintPublicSchemaFieldNames(
|
|
|
221
205
|
}
|
|
222
206
|
|
|
223
207
|
return [
|
|
224
|
-
...collectPublicSchemaFieldDiagnostics(
|
|
225
|
-
|
|
226
|
-
operationId,
|
|
227
|
-
input,
|
|
228
|
-
"input",
|
|
229
|
-
),
|
|
230
|
-
...collectPublicSchemaFieldDiagnostics(
|
|
231
|
-
providerId,
|
|
232
|
-
operationId,
|
|
233
|
-
output,
|
|
234
|
-
"output",
|
|
235
|
-
),
|
|
208
|
+
...collectPublicSchemaFieldDiagnostics(providerId, operationId, input, "input"),
|
|
209
|
+
...collectPublicSchemaFieldDiagnostics(providerId, operationId, output, "output"),
|
|
236
210
|
];
|
|
237
211
|
}
|
package/src/recipes/gov-api.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { unwrapEnvelope } from "../utils/parse";
|
|
1
|
+
import { unwrapEnvelope } from "../utils/parse.js";
|
|
2
2
|
|
|
3
3
|
function getResultCode(raw: unknown): string | undefined {
|
|
4
4
|
if (!raw || typeof raw !== "object") {
|
|
@@ -33,10 +33,7 @@ export function checkResultCode(
|
|
|
33
33
|
* Replace placeholder values with null
|
|
34
34
|
* e.g., nullIfPlaceholder('해당없음', ['해당없음', '-', '']) → null
|
|
35
35
|
*/
|
|
36
|
-
export function nullIfPlaceholder(
|
|
37
|
-
v: unknown,
|
|
38
|
-
patterns: string[],
|
|
39
|
-
): unknown | null {
|
|
36
|
+
export function nullIfPlaceholder(v: unknown, patterns: string[]): unknown | null {
|
|
40
37
|
if (v === null || v === undefined) {
|
|
41
38
|
return null;
|
|
42
39
|
}
|