Split out of the #156 roadmap spike (Tier 2: extensibility groundwork). Blocks every candidate third adapter. Pairs with #181.
Problem
Two closed, flat, provider-specific shapes that every new provider has to widen.
1. ProviderOptions — flat credential fields
// src/lib/utils/providerHelper.ts
export interface ProviderOptions {
provider?: ProviderType
config?: ...
interactive?: boolean
// Vercel-specific
token?: string
projectId?: string
teamId?: string
// Cloudflare-specific
apiToken?: string
zoneId?: string
accountId?: string
}
These same fields are then threaded individually through WithCredentialsOptions, every command's options interface, and every command's yargs builder. AWS WAF alone would add accessKeyId, secretAccessKey, sessionToken, region, scope, webAclArn; GCP adds a service-account/OAuth2 shape that doesn't resemble a flat token at all. Continuing to flatten produces a ~20-field union where most fields are meaningless for any given provider.
2. ProvidersConfig — closed 2-key interface
// src/lib/types/common.ts
export interface ProvidersConfig {
vercel?: { projectId?: string; teamId?: string }
cloudflare?: { zoneId?: string; accountId?: string }
}
Mirrored by an equally closed zod schema in commonSchemas.ts. Also encodes the one-provider-one-target assumption called out separately in the multi-resource-targeting issue.
Proposed approach
- Introduce a per-provider credential descriptor owned by each adapter: which env vars it reads, which CLI flags it accepts, which are required, and how to prompt for them.
getProviderInstance resolves generically against the descriptor instead of branching per provider.
- Replace
ProviderOptions' flat fields with a credentials?: Record<string, string | undefined> bag plus the descriptor for validation/prompting. Keep the existing flags working as aliases so this isn't a breaking CLI change.
- Make
ProvidersConfig an index-signature type (Record<string, ProviderSettings>) with per-provider zod schemas contributed by each adapter, rather than one closed interface + one closed schema.
Constraints
- Not a breaking change for users.
--token/--projectId/--teamId/--apiToken/--zoneId/--accountId and their env vars must keep working exactly as they do today.
ProviderDetector currently keys off providers.vercel.projectId / providers.cloudflare.zoneId — its detection signals need to come from the same descriptors rather than hardcoded paths.
- The generated JSON schema (
schema/firewall-config.schema.json) must still validate real configs; check pnpm build:schema output.
Acceptance criteria
- A new provider declares its credentials once, in its own adapter directory
- No provider-specific credential field remains in
ProviderOptions / WithCredentialsOptions / command option interfaces
ProvidersConfig accepts an arbitrary provider key with a provider-supplied schema
- Existing configs and existing CLI flags/env vars work unchanged (full suite green + manual run against
demos/mock-server.mjs)
Split out of the #156 roadmap spike (Tier 2: extensibility groundwork). Blocks every candidate third adapter. Pairs with #181.
Problem
Two closed, flat, provider-specific shapes that every new provider has to widen.
1.
ProviderOptions— flat credential fieldsThese same fields are then threaded individually through
WithCredentialsOptions, every command's options interface, and every command's yargs builder. AWS WAF alone would addaccessKeyId,secretAccessKey,sessionToken,region,scope,webAclArn; GCP adds a service-account/OAuth2 shape that doesn't resemble a flat token at all. Continuing to flatten produces a ~20-field union where most fields are meaningless for any given provider.2.
ProvidersConfig— closed 2-key interfaceMirrored by an equally closed zod schema in
commonSchemas.ts. Also encodes the one-provider-one-target assumption called out separately in the multi-resource-targeting issue.Proposed approach
getProviderInstanceresolves generically against the descriptor instead of branching per provider.ProviderOptions' flat fields with acredentials?: Record<string, string | undefined>bag plus the descriptor for validation/prompting. Keep the existing flags working as aliases so this isn't a breaking CLI change.ProvidersConfigan index-signature type (Record<string, ProviderSettings>) with per-provider zod schemas contributed by each adapter, rather than one closed interface + one closed schema.Constraints
--token/--projectId/--teamId/--apiToken/--zoneId/--accountIdand their env vars must keep working exactly as they do today.ProviderDetectorcurrently keys offproviders.vercel.projectId/providers.cloudflare.zoneId— its detection signals need to come from the same descriptors rather than hardcoded paths.schema/firewall-config.schema.json) must still validate real configs; checkpnpm build:schemaoutput.Acceptance criteria
ProviderOptions/WithCredentialsOptions/ command option interfacesProvidersConfigaccepts an arbitrary provider key with a provider-supplied schemademos/mock-server.mjs)