Tooling shared by every action under actions/. Run from within
an action directory using a relative path (../../scripts/...), or from the
repo root via the root package.json scripts.
Two composable steps turn a vendor's OpenAPI spec into a typed zod schema module for an action. Any action that exposes data types from an OpenAPI spec (Stripe, Shopify, etc.) can reuse them — nothing is vendor-specific.
Reduces a large OpenAPI document to just the resources an action exposes plus everything they reference, so nested objects stay fully typed instead of collapsing to untyped passthrough objects.
node ../../scripts/openapi-filter.mjs <input-spec.(json|yaml)> <output.json> \
--roots <name,name,...> [--depth <n|infinity>] [--rename <old>=<new> ...]
--roots— comma-separated component schema names the action exposes.--depth— how many$refhops from a root to keep (defaultinfinity, i.e. the full transitive closure;$refsbeyond the horizon are stubbed as untyped objects). Lower it to trade completeness for a smaller output.--rename <old>=<new>(repeatable) — give an awkwardly-named component a stable identifier before roots are resolved (e.g. Twilio'sapi.v2010.account.message=TwilioMessage).- YAML specs (
.yaml/.yml) are accepted; the parser (yamlorjs-yaml) is loaded from the action'snode_modules, so add one as a devDependency. Output is always JSON.
Converts every schema under components.schemas into a zod schema.
node ../../scripts/openapi-to-zod.mjs <input-spec.json> <output.ts>
- Each schema becomes a
z.lazy(() => ...)named const; every$refbecomes a reference to that const. Lazy evaluation resolves circular references without inlining, so memory stays O(number of schemas). (This is why we do not useopenapi-zod-client, which OOMs expanding large circular specs like Stripe's.) - Handles the full OpenAPI 3.0/3.1 Schema Object:
$ref,type(incl.nulland type arrays),enum,const,allOf/anyOf/oneOf/not, object shapes (properties/required/additionalProperties/patternProperties) and array shapes (items/prefixItems). - Value constraints and annotations are recognized but not enforced (they never change the type). Any keyword that is neither handled nor ignored throws, so a new spec construct fails generation loudly instead of emitting a wrong schema.
Add a generate:*-schemas script to the action's package.json, e.g.:
"generate:stripe-schemas": "curl -fsSL --create-dirs -o schemas/stripe-openapi.json <spec-url> && node ../../scripts/openapi-filter.mjs schemas/stripe-openapi.json schemas/stripe-openapi.filtered.json --roots customer,payment_intent,refund,charge && node ../../scripts/openapi-to-zod.mjs schemas/stripe-openapi.filtered.json src/generated/stripe-schemas.ts"The generated file is committed, so this is a dev-time script — it is not run during Docker builds or CI.
Runs an npm script in every action that defines it (used by the root
typecheck / build / test scripts).
node scripts/for-each-action.mjs <script>