@slip-stream-kit/config 0.34.0 → 0.36.0
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/dist/index.js
CHANGED
|
@@ -22,8 +22,11 @@ var deployServiceSchema = z.strictObject({
|
|
|
22
22
|
* `devops/scripts/deploy-<service>.sh`.
|
|
23
23
|
*/
|
|
24
24
|
deploy: z.string().regex(/^(?!.*\.\.)[\w./-]+\.ts$/, "must be a repo-relative .ts path, e.g. apps/client/api/deploy.ts").optional(),
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* `false` leaves the service out of the deploy-all workflow; a list keeps it in deploy-all for those
|
|
27
|
+
* environments only, e.g. `['prod']`. Either way it stays selectable wherever it may deploy.
|
|
28
|
+
*/
|
|
29
|
+
deployAll: z.union([z.boolean(), z.array(kebabName).nonempty()]).optional()
|
|
27
30
|
});
|
|
28
31
|
var deployConfigSchema = z.strictObject({
|
|
29
32
|
/** The environments the generated workflows offer, in dispatch-menu order. */
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/lib/deploy/deploy-config-schema.ts", "../src/lib/package-config/package-config.ts", "../src/lib/vendor/config-schema.ts"],
|
|
4
|
-
"sourcesContent": ["import { z } from 'zod'\n\n/**\n * Pure (node-free) schema for a consumer repo's deploy manifest. `infra-kit deploy-sync` reads it and\n * generates the repo's deploy workflows from it, so CI runs plain YAML and never needs the CLI.\n *\n * A separate file rather than a `deploy` key in `infra-kit.json` / `infra-kit.config.ts`: both of those\n * are strict schemas parsed by every installed CLI and by the vite plugin, so a new key would break\n * every teammate and CI build still on an older release. Nothing but `deploy-sync` reads this file.\n */\nexport const DEPLOY_CONFIG_FILE = 'infra-kit.deploy.ts'\n\n/** Environment and service names end up in job ids, input keys and secret names. */\nconst kebabName = z.string().regex(/^[a-z][a-z0-9-]*$/, 'must be lower-case kebab-case, e.g. client-be')\n\n/** A reusable workflow in the consumer's own `.github/workflows/`, by file name. */\nconst localWorkflowFile = z\n .string()\n .regex(/^[\\w.-]+\\.ya?ml$/, 'must be a workflow file name in .github/workflows, e.g. _deploy-media-jobs.yml')\n\nconst secretName = z.string().regex(/^[A-Z_][A-Z0-9_]*$/, 'must be an upper-case secret name, e.g. MONITORING_IP')\n\n/** Service names become dispatch inputs, so they must not shadow the ones every workflow has. */\nconst RESERVED_SERVICE_NAMES = new Set(['environment'])\n\nexport const deployServiceSchema = z.strictObject({\n /** The only environments this service deploys to. Omitted = every environment. */\n envs: z.array(kebabName).nonempty().optional(),\n /** Environments this service never deploys to; every other one is allowed. Exclusive with `envs`. */\n skipEnvs: z.array(kebabName).nonempty().optional(),\n /** GitHub runner label. Omitted = the shared job's default (`ubuntu-24.04-arm`). */\n runner: z\n .string()\n .regex(/^[\\w.-]+$/, 'must be a runner label, e.g. macos-14')\n .optional(),\n /**\n * Deploy through this repo's own reusable workflow instead of `devops/scripts/deploy-<service>.sh`\n * in the shared job. It is called with `branch` and `environment` inputs and `secrets: inherit`.\n */\n workflow: localWorkflowFile.optional(),\n /**\n * The service's TypeScript deploy, run by `infra-kit deploy-run`, as a repo-relative path; put it in\n * the app it deploys (`apps/client/api/deploy.ts`) and it defaults to that app. Omitted =\n * `devops/scripts/deploy-<service>.sh`.\n */\n deploy: z\n .string()\n .regex(/^(?!.*\\.\\.)[\\w./-]+\\.ts$/, 'must be a repo-relative .ts path, e.g. apps/client/api/deploy.ts')\n .optional(),\n /** `false` leaves the service out of the deploy-all workflow; it stays selectable. */\n deployAll: z.boolean().optional(),\n})\n\nexport const deployConfigSchema = z\n .strictObject({\n /** The environments the generated workflows offer, in dispatch-menu order. */\n environments: z.array(kebabName).nonempty(),\n /** Preselected in the dispatch menu. Omitted = the first environment. */\n defaultEnvironment: kebabName.optional(),\n /** Every deployable service, keyed by its `devops/scripts/deploy-<name>.sh` suffix, in menu order. */\n services: z.record(kebabName, deployServiceSchema),\n /** Reusable workflows applied before any service deploys; skippable per run. */\n terraform: z.array(localWorkflowFile).optional(),\n /**\n * Reusable workflows run after terraform (applied or skipped) and before any service, e.g. publishing\n * a Lambda layer the services resolve at deploy time. Not skipped with terraform; a failure stops every service.\n */\n preDeploy: z.array(localWorkflowFile).optional(),\n /** Reusable workflow called once every deploy job finished without a failure. */\n notifySuccess: localWorkflowFile.optional(),\n /** Repo secrets exported, under the same name, to every deploy script. */\n extraEnv: z.array(secretName).optional(),\n /**\n * Minutes the deploy step of the shared job may run. Omitted = the shared job's default, 25. A\n * timed-out step fails and keeps its logs, where a job cancelled at GitHub's 360-minute cap loses them.\n */\n deployTimeoutMinutes: z.number().int().min(1).max(360).optional(),\n /**\n * Generate under the v1 names, `deploy-all.yml` and `deploy-selected-services.yml`, replacing the\n * hand-written files. Those are the files `infra-kit release deploy-*` dispatches, so the manifest\n * becomes what the CLI deploys and reads its service gates from. Omitted = the `-v2` pilot files,\n * which the CLI ignores. A repo that delivers prod needs `prod` in `environments` first: delivery\n * dispatches `deploy-all.yml` with it.\n */\n replaceV1: z.boolean().optional(),\n })\n .superRefine((config, ctx) => {\n if (Object.keys(config.services).length === 0) {\n ctx.addIssue({ code: 'custom', path: ['services'], message: 'declare at least one service' })\n }\n\n for (const [name, service] of Object.entries(config.services)) {\n if (RESERVED_SERVICE_NAMES.has(name)) {\n ctx.addIssue({ code: 'custom', path: ['services', name], message: 'is a dispatch input of its own' })\n }\n\n if (service.workflow !== undefined && service.deploy !== undefined) {\n ctx.addIssue({ code: 'custom', path: ['services', name], message: 'set workflow or deploy, not both' })\n }\n\n if (service.envs !== undefined && service.skipEnvs !== undefined) {\n ctx.addIssue({ code: 'custom', path: ['services', name], message: 'set envs or skipEnvs, not both' })\n }\n }\n\n for (const [index, file] of (config.preDeploy ?? []).entries()) {\n if (config.terraform?.includes(file)) {\n ctx.addIssue({ code: 'custom', path: ['preDeploy', index], message: 'already listed under terraform' })\n }\n }\n\n if (config.defaultEnvironment !== undefined && !config.environments.includes(config.defaultEnvironment)) {\n ctx.addIssue({\n code: 'custom',\n path: ['defaultEnvironment'],\n message: `must be one of environments (${config.environments.join(', ')})`,\n })\n }\n })\n\nexport type DeployService = z.infer<typeof deployServiceSchema>\nexport type DeployConfig = z.infer<typeof deployConfigSchema>\n\n/**\n * Identity helper for authoring a type-safe `infra-kit.deploy.ts`.\n *\n * A manifest can equally use `import type { DeployConfig }` with `satisfies DeployConfig`: the type\n * import is erased when the CLI loads the file, so it keeps working against an older installed\n * `@slip-stream-kit/config` that predates this helper.\n *\n * @example\n * export default defineDeployConfig({\n * environments: ['dev', 'stage'],\n * services: { 'client-be': {}, 'client-fe': { runner: 'macos-14' } },\n * })\n */\nexport const defineDeployConfig = (config: DeployConfig): DeployConfig => {\n return config\n}\n", "/**\n * Validation rules for a single workspace package, declared in its\n * `infra-kit.config.ts`. Every field is optional: a key left unset falls back to\n * the active baseline, and a key set replaces that default wholesale (per-key, no\n * array concatenation) so a package can opt out with an explicit empty array.\n *\n * The baselines themselves (`DEFAULT_RULES` / `ROOT_DEFAULT_RULES`) deliberately do\n * NOT live here \u2014 they are audit POLICY, and policy belongs to the `infra-kit` CLI\n * that enforces it, not to the package a consumer installs to author a config.\n *\n * Most packages need none of these \u2014 the standard rules live in the baseline, so\n * a typical config is just `defineConfig(() => ({}))`.\n *\n * @example\n * // infra-kit.config.ts\n * import { defineConfig } from '@slip-stream-kit/config'\n *\n * export default defineConfig(() => ({}))\n */\nexport interface InfraKitPackageConfig {\n /** Scripts that must be present in the package's package.json `scripts` map. */\n requiredScripts?: string[]\n /** Files (relative to the package root) that must exist on disk. */\n requiredFiles?: string[]\n /** Turborepo expectations \u2014 only meaningful where a turbo.json lives (the root). */\n turbo?: {\n /** Tasks that must be defined in turbo.json `tasks`. */\n requiredTasks?: string[]\n }\n /**\n * The env var holding this app part's deployed URL, e.g. `CLIENT_URL`. The value lives in Doppler, per\n * environment \u2014 prod's host is not `<env>`-shaped, so no template in code can name it. The dev proxy sends\n * a UI's cloud routes there, and e2e runs against it in cloud mode. Required on a UI whose `dev.proxy`\n * has a route that can go to cloud, and on any `e2e.target`.\n */\n deployedUrlEnv?: string\n /** Local-dev configuration. Accepted-and-inert to the audit; consumed by the dev server. */\n dev?: InfraKitDev\n /** Where this e2e package's suite runs. Consumed by `infraKitE2e()` and the CLI; `server: 'static'` also narrows the audit. */\n e2e?: InfraKitE2e\n /**\n * Explicit override for infra-kit's directory/dependency-based package-type detection (used to\n * pick the agent guidance rendered into this package's `CLAUDE.md`). Detection already covers\n * both consumer repos untouched, so this is an escape hatch for the cases it gets wrong \u2014 leaving\n * it unset is never an error.\n *\n * **Ordering precondition:** the CLI's own pinned `packageConfigSchema` \u2014 not this package's\n * version \u2014 governs what a consumer's `infra-kit.config.ts` may contain, and it is a\n * `z.strictObject`. Only write `type` here once the CLI in use is a version that carries this\n * key; an older CLI rejects the key outright and skips the rest of that package's audit checks.\n *\n * @example\n * // infra-kit.config.ts\n * export default defineConfig(() => ({ type: 'frontend' }))\n */\n type?: InfraKitPackageType\n}\n\n/** Package kinds infra-kit's agent guidance renders type-specific rules for. */\nexport type InfraKitPackageType = 'frontend' | 'backend' | 'lib' | 'e2e' | 'mobile'\n\n/** A proxy route's allowed backend source. */\nexport type InfraKitDevProxySource = 'local' | 'cloud'\n\nexport interface InfraKitDevProxyRoute {\n /** Backend package this route targets when resolved locally. */\n packageName: string\n /** Capabilities this route can resolve to. Must be non-empty. */\n from: InfraKitDevProxySource[]\n /**\n * Source used when a local backend for this package isn't active. Required when\n * `from` lists more than one source; redundant (and omitted) for a single-source\n * route. When set, must be one of `from`.\n */\n default?: InfraKitDevProxySource\n}\n\nexport interface InfraKitDevProxy {\n /**\n * The local backend's URL template \u2014 `<release>`/`<packageName>` are substituted at dev time. A cloud route\n * goes to the package's `deployedUrlEnv` instead. Consulted only for a fragment from a pre-v2 CLI: a\n * current one publishes the exact `origin` (`<release>.<packageName>.<repo>.localhost`) it registered.\n */\n templates: {\n local: string\n }\n /** Path-prefix (e.g. `/api`, `/api/v1`, `/media`) \u2192 route definition. */\n routes: Record<string, InfraKitDevProxyRoute>\n}\n\nexport interface InfraKitDev {\n proxy?: InfraKitDevProxy\n env?: InfraKitDevEnv\n}\n\n/**\n * Env overrides for this package's dev server only, applied over the loaded (Doppler) env when vite starts\n * it \u2014 never on `build`. For variables another build mode needs that break local dev, e.g. a mobile-only\n * absolute origin that sends requests around the dev proxy.\n *\n * @example\n * // apps/client/ui/infra-kit.config.ts\n * export default defineConfig(() => ({ dev: { env: { unset: ['VITE_ORIGIN_DOMAIN'] } } }))\n */\nexport interface InfraKitDevEnv {\n /** Variables removed from the dev server's env. */\n unset?: string[]\n /** Variables set (or overridden) in the dev server's env. A name cannot also be in `unset`. */\n set?: Record<string, string>\n}\n\n/**\n * Where an e2e package's suite runs. With `target`, `infraKitE2e()` (`@slip-stream-kit/config/playwright`)\n * reads it: a run is local by default \u2014 `target` on this worktree, served by `infra-kit dev <app>` \u2014 and\n * cloud only when asked (`INFRA_KIT_E2E=cloud`, or CI), against the URL in the target package's `deployedUrlEnv`.\n * With `server: 'static'`, see {@link InfraKitE2eStatic}.\n *\n * @example\n * // apps/client/tests/infra-kit.config.ts\n * export default defineConfig(() => ({ e2e: { target: 'client/ui' } }))\n */\nexport type InfraKitE2e = InfraKitE2eTarget | InfraKitE2eStatic\n\nexport interface InfraKitE2eTarget {\n /** The package under test, `<app>/ui` or `<app>/api`. */\n target: string\n server?: never\n}\n\n/**\n * A suite whose own `webServer` serves a static production build \u2014 e.g. one asserting the canonical and `og:`\n * URLs a build inlines, which a dev server never produces. `infraKitE2e()` refuses it, `infra-kit e2e` does\n * not list it, and the audit drops its `infraKitE2e` requirement; the other `playwright.config.ts` rules stay.\n *\n * @example\n * // apps/client/tests/infra-kit.config.ts\n * export default defineConfig(() => ({ e2e: { server: 'static' } }))\n */\nexport interface InfraKitE2eStatic {\n server: 'static'\n target?: never\n}\n\n/**\n * Accepted shapes for a package config's default export \u2014 mirrors Vite's\n * `defineConfig` input: a plain object, a sync factory, or an async factory.\n */\nexport type InfraKitPackageConfigInput =\n InfraKitPackageConfig | (() => InfraKitPackageConfig) | (() => Promise<InfraKitPackageConfig>)\n\n/**\n * Identity helper that gives `infra-kit.config.ts` authors full type inference\n * and editor autocomplete without changing the value \u2014 exactly like Vite's\n * `defineConfig`. Resolution of the factory form happens in the CLI's loader, not here.\n *\n * @example\n * export default defineConfig(() => ({}))\n * @example\n * export default defineConfig(() => ({ requiredScripts: [] }))\n */\nexport const defineConfig = (config: InfraKitPackageConfigInput): InfraKitPackageConfigInput => {\n return config\n}\n", "import { z } from 'zod'\n\n/**\n * Pure (node-free) vendor config schema + authoring helper. Kept separate from\n * `config.ts` (which imports node builtins for the runtime loader) so the public\n * lib entry can re-export `defineVendorConfig` without dragging node types into\n * the emitted `.d.ts`.\n */\n\n/**\n * Filename a source repo provides at its root to declare WHAT `vendor sync`\n * copies (`copy[]`). Lives ONLY on the write path \u2014 `vendor check` never loads it.\n * WHERE/WHICH to stamp (`workspaceDir` + `targets`) is machine-local and lives in\n * the user-global factory config (`~/.infra-kit/vendor.json`).\n */\nexport const VENDOR_CONFIG_FILE = 'vendor.config.ts'\n\n/**\n * A non-empty, repo-relative path with no `..` segments and no absolute prefix\n * (POSIX `/`, UNC/`\\`, or a Windows drive like `C:`). Containment guard for\n * vendor copy items so a malicious/typo config can't read or write outside the\n * source/target repo roots. Kept as a string/regex check (no `node:path`) to\n * respect this file's node-free constraint \u2014 `sync-ops.ts` does the resolved\n * runtime containment assert as defense in depth.\n */\nconst safeRelPath = z.string().refine(\n (p) => {\n const isAbsolute = /^(?:[/\\\\]|[a-z]:)/i.test(p)\n const hasDotDotSegment = p.split(/[\\\\/]/).includes('..')\n\n return !isAbsolute && !hasDotDotSegment && p.trim().length > 0\n },\n { message: 'must be a non-empty repo-relative path without \"..\" segments' },\n)\n\n/**\n * One item to sync from the source repo into each target. `vendored: true` marks\n * workspace packages that must land under `vendor/` (the single-source-of-truth\n * code); everything else is root-level tooling that stays at the repo root.\n */\nexport const vendorCopyItemSchema = z.object({\n name: z.string(),\n source: safeRelPath,\n target: safeRelPath,\n type: z.enum(['file', 'directory']),\n vendored: z.boolean().optional(),\n})\n\nexport const vendorConfigSchema = z\n .object({\n /** Files/dirs to copy. Items with `vendored: true` land under `vendor/`. */\n copy: z.array(vendorCopyItemSchema),\n })\n // Reject stray keys so a leftover `targets` (now machine-local, in\n // ~/.infra-kit/vendor.json) yields a clear \"unrecognized key\" error rather\n // than being silently ignored.\n .strict()\n\nexport type VendorCopyItem = z.infer<typeof vendorCopyItemSchema>\nexport type VendorConfig = z.infer<typeof vendorConfigSchema>\n\n/**\n * Identity helper for authoring a type-safe `vendor.config.ts` in a source repo.\n * Re-exported from the public lib entry so a source repo can\n * `import { defineVendorConfig } from 'infra-kit'`.\n *\n * NOTE: a `vendor.config.ts` must be type-strippable \u2014 Node's native type\n * stripping (Node >= 24) loads it without a build step, which forbids `enum`,\n * `namespace`, and parameter properties.\n *\n * @example\n * export default defineVendorConfig({\n * copy: [{ name: 'Configs', source: 'vendor/configs', target: 'vendor/configs', type: 'directory', vendored: true }],\n * })\n */\nexport const defineVendorConfig = (config: VendorConfig): VendorConfig => {\n return config\n}\n"],
|
|
5
|
-
"mappings": ";AAAA,SAAS,SAAS;AAalB,IAAM,YAAY,EAAE,OAAO,EAAE,MAAM,qBAAqB,+CAA+C;AAGvG,IAAM,oBAAoB,EACvB,OAAO,EACP,MAAM,oBAAoB,gFAAgF;AAE7G,IAAM,aAAa,EAAE,OAAO,EAAE,MAAM,sBAAsB,uDAAuD;AAGjH,IAAM,yBAAyB,oBAAI,IAAI,CAAC,aAAa,CAAC;AAE/C,IAAM,sBAAsB,EAAE,aAAa;AAAA;AAAA,EAEhD,MAAM,EAAE,MAAM,SAAS,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,EAE7C,UAAU,EAAE,MAAM,SAAS,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,EAEjD,QAAQ,EACL,OAAO,EACP,MAAM,aAAa,uCAAuC,EAC1D,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKZ,UAAU,kBAAkB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrC,QAAQ,EACL,OAAO,EACP,MAAM,4BAA4B,kEAAkE,EACpG,SAAS;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\n\n/**\n * Pure (node-free) schema for a consumer repo's deploy manifest. `infra-kit deploy-sync` reads it and\n * generates the repo's deploy workflows from it, so CI runs plain YAML and never needs the CLI.\n *\n * A separate file rather than a `deploy` key in `infra-kit.json` / `infra-kit.config.ts`: both of those\n * are strict schemas parsed by every installed CLI and by the vite plugin, so a new key would break\n * every teammate and CI build still on an older release. Nothing but `deploy-sync` reads this file.\n */\nexport const DEPLOY_CONFIG_FILE = 'infra-kit.deploy.ts'\n\n/** Environment and service names end up in job ids, input keys and secret names. */\nconst kebabName = z.string().regex(/^[a-z][a-z0-9-]*$/, 'must be lower-case kebab-case, e.g. client-be')\n\n/** A reusable workflow in the consumer's own `.github/workflows/`, by file name. */\nconst localWorkflowFile = z\n .string()\n .regex(/^[\\w.-]+\\.ya?ml$/, 'must be a workflow file name in .github/workflows, e.g. _deploy-media-jobs.yml')\n\nconst secretName = z.string().regex(/^[A-Z_][A-Z0-9_]*$/, 'must be an upper-case secret name, e.g. MONITORING_IP')\n\n/** Service names become dispatch inputs, so they must not shadow the ones every workflow has. */\nconst RESERVED_SERVICE_NAMES = new Set(['environment'])\n\nexport const deployServiceSchema = z.strictObject({\n /** The only environments this service deploys to. Omitted = every environment. */\n envs: z.array(kebabName).nonempty().optional(),\n /** Environments this service never deploys to; every other one is allowed. Exclusive with `envs`. */\n skipEnvs: z.array(kebabName).nonempty().optional(),\n /** GitHub runner label. Omitted = the shared job's default (`ubuntu-24.04-arm`). */\n runner: z\n .string()\n .regex(/^[\\w.-]+$/, 'must be a runner label, e.g. macos-14')\n .optional(),\n /**\n * Deploy through this repo's own reusable workflow instead of `devops/scripts/deploy-<service>.sh`\n * in the shared job. It is called with `branch` and `environment` inputs and `secrets: inherit`.\n */\n workflow: localWorkflowFile.optional(),\n /**\n * The service's TypeScript deploy, run by `infra-kit deploy-run`, as a repo-relative path; put it in\n * the app it deploys (`apps/client/api/deploy.ts`) and it defaults to that app. Omitted =\n * `devops/scripts/deploy-<service>.sh`.\n */\n deploy: z\n .string()\n .regex(/^(?!.*\\.\\.)[\\w./-]+\\.ts$/, 'must be a repo-relative .ts path, e.g. apps/client/api/deploy.ts')\n .optional(),\n /**\n * `false` leaves the service out of the deploy-all workflow; a list keeps it in deploy-all for those\n * environments only, e.g. `['prod']`. Either way it stays selectable wherever it may deploy.\n */\n deployAll: z.union([z.boolean(), z.array(kebabName).nonempty()]).optional(),\n})\n\nexport const deployConfigSchema = z\n .strictObject({\n /** The environments the generated workflows offer, in dispatch-menu order. */\n environments: z.array(kebabName).nonempty(),\n /** Preselected in the dispatch menu. Omitted = the first environment. */\n defaultEnvironment: kebabName.optional(),\n /** Every deployable service, keyed by its `devops/scripts/deploy-<name>.sh` suffix, in menu order. */\n services: z.record(kebabName, deployServiceSchema),\n /** Reusable workflows applied before any service deploys; skippable per run. */\n terraform: z.array(localWorkflowFile).optional(),\n /**\n * Reusable workflows run after terraform (applied or skipped) and before any service, e.g. publishing\n * a Lambda layer the services resolve at deploy time. Not skipped with terraform; a failure stops every service.\n */\n preDeploy: z.array(localWorkflowFile).optional(),\n /** Reusable workflow called once every deploy job finished without a failure. */\n notifySuccess: localWorkflowFile.optional(),\n /** Repo secrets exported, under the same name, to every deploy script. */\n extraEnv: z.array(secretName).optional(),\n /**\n * Minutes the deploy step of the shared job may run. Omitted = the shared job's default, 25. A\n * timed-out step fails and keeps its logs, where a job cancelled at GitHub's 360-minute cap loses them.\n */\n deployTimeoutMinutes: z.number().int().min(1).max(360).optional(),\n /**\n * Generate under the v1 names, `deploy-all.yml` and `deploy-selected-services.yml`, replacing the\n * hand-written files. Those are the files `infra-kit release deploy-*` dispatches, so the manifest\n * becomes what the CLI deploys and reads its service gates from. Omitted = the `-v2` pilot files,\n * which the CLI ignores. A repo that delivers prod needs `prod` in `environments` first: delivery\n * dispatches `deploy-all.yml` with it.\n */\n replaceV1: z.boolean().optional(),\n })\n .superRefine((config, ctx) => {\n if (Object.keys(config.services).length === 0) {\n ctx.addIssue({ code: 'custom', path: ['services'], message: 'declare at least one service' })\n }\n\n for (const [name, service] of Object.entries(config.services)) {\n if (RESERVED_SERVICE_NAMES.has(name)) {\n ctx.addIssue({ code: 'custom', path: ['services', name], message: 'is a dispatch input of its own' })\n }\n\n if (service.workflow !== undefined && service.deploy !== undefined) {\n ctx.addIssue({ code: 'custom', path: ['services', name], message: 'set workflow or deploy, not both' })\n }\n\n if (service.envs !== undefined && service.skipEnvs !== undefined) {\n ctx.addIssue({ code: 'custom', path: ['services', name], message: 'set envs or skipEnvs, not both' })\n }\n }\n\n for (const [index, file] of (config.preDeploy ?? []).entries()) {\n if (config.terraform?.includes(file)) {\n ctx.addIssue({ code: 'custom', path: ['preDeploy', index], message: 'already listed under terraform' })\n }\n }\n\n if (config.defaultEnvironment !== undefined && !config.environments.includes(config.defaultEnvironment)) {\n ctx.addIssue({\n code: 'custom',\n path: ['defaultEnvironment'],\n message: `must be one of environments (${config.environments.join(', ')})`,\n })\n }\n })\n\nexport type DeployService = z.infer<typeof deployServiceSchema>\nexport type DeployConfig = z.infer<typeof deployConfigSchema>\n\n/**\n * Identity helper for authoring a type-safe `infra-kit.deploy.ts`.\n *\n * A manifest can equally use `import type { DeployConfig }` with `satisfies DeployConfig`: the type\n * import is erased when the CLI loads the file, so it keeps working against an older installed\n * `@slip-stream-kit/config` that predates this helper.\n *\n * @example\n * export default defineDeployConfig({\n * environments: ['dev', 'stage'],\n * services: { 'client-be': {}, 'client-fe': { runner: 'macos-14' } },\n * })\n */\nexport const defineDeployConfig = (config: DeployConfig): DeployConfig => {\n return config\n}\n", "/**\n * Validation rules for a single workspace package, declared in its\n * `infra-kit.config.ts`. Every field is optional: a key left unset falls back to\n * the active baseline, and a key set replaces that default wholesale (per-key, no\n * array concatenation) so a package can opt out with an explicit empty array.\n *\n * The baselines themselves (`DEFAULT_RULES` / `ROOT_DEFAULT_RULES`) deliberately do\n * NOT live here \u2014 they are audit POLICY, and policy belongs to the `infra-kit` CLI\n * that enforces it, not to the package a consumer installs to author a config.\n *\n * Most packages need none of these \u2014 the standard rules live in the baseline, so\n * a typical config is just `defineConfig(() => ({}))`.\n *\n * @example\n * // infra-kit.config.ts\n * import { defineConfig } from '@slip-stream-kit/config'\n *\n * export default defineConfig(() => ({}))\n */\nexport interface InfraKitPackageConfig {\n /** Scripts that must be present in the package's package.json `scripts` map. */\n requiredScripts?: string[]\n /** Files (relative to the package root) that must exist on disk. */\n requiredFiles?: string[]\n /** Turborepo expectations \u2014 only meaningful where a turbo.json lives (the root). */\n turbo?: {\n /** Tasks that must be defined in turbo.json `tasks`. */\n requiredTasks?: string[]\n }\n /**\n * The env var holding this app part's deployed URL, e.g. `CLIENT_URL`. The value lives in Doppler, per\n * environment \u2014 prod's host is not `<env>`-shaped, so no template in code can name it. The dev proxy sends\n * a UI's cloud routes there, and e2e runs against it in cloud mode. Required on a UI whose `dev.proxy`\n * has a route that can go to cloud, and on any `e2e.target`.\n */\n deployedUrlEnv?: string\n /** Local-dev configuration. Accepted-and-inert to the audit; consumed by the dev server. */\n dev?: InfraKitDev\n /** Where this e2e package's suite runs. Consumed by `infraKitE2e()` and the CLI; `server: 'static'` also narrows the audit. */\n e2e?: InfraKitE2e\n /**\n * Explicit override for infra-kit's directory/dependency-based package-type detection (used to\n * pick the agent guidance rendered into this package's `CLAUDE.md`). Detection already covers\n * both consumer repos untouched, so this is an escape hatch for the cases it gets wrong \u2014 leaving\n * it unset is never an error.\n *\n * **Ordering precondition:** the CLI's own pinned `packageConfigSchema` \u2014 not this package's\n * version \u2014 governs what a consumer's `infra-kit.config.ts` may contain, and it is a\n * `z.strictObject`. Only write `type` here once the CLI in use is a version that carries this\n * key; an older CLI rejects the key outright and skips the rest of that package's audit checks.\n *\n * @example\n * // infra-kit.config.ts\n * export default defineConfig(() => ({ type: 'frontend' }))\n */\n type?: InfraKitPackageType\n}\n\n/** Package kinds infra-kit's agent guidance renders type-specific rules for. */\nexport type InfraKitPackageType = 'frontend' | 'backend' | 'lib' | 'e2e' | 'mobile'\n\n/** A proxy route's allowed backend source. */\nexport type InfraKitDevProxySource = 'local' | 'cloud'\n\nexport interface InfraKitDevProxyRoute {\n /** Backend package this route targets when resolved locally. */\n packageName: string\n /** Capabilities this route can resolve to. Must be non-empty. */\n from: InfraKitDevProxySource[]\n /**\n * Source used when a local backend for this package isn't active. Required when\n * `from` lists more than one source; redundant (and omitted) for a single-source\n * route. When set, must be one of `from`.\n */\n default?: InfraKitDevProxySource\n}\n\nexport interface InfraKitDevProxy {\n /**\n * The local backend's URL template \u2014 `<release>`/`<packageName>` are substituted at dev time. A cloud route\n * goes to the package's `deployedUrlEnv` instead. Consulted only for a fragment from a pre-v2 CLI: a\n * current one publishes the exact `origin` (`<release>.<packageName>.<repo>.localhost`) it registered.\n */\n templates: {\n local: string\n }\n /** Path-prefix (e.g. `/api`, `/api/v1`, `/media`) \u2192 route definition. */\n routes: Record<string, InfraKitDevProxyRoute>\n}\n\nexport interface InfraKitDev {\n proxy?: InfraKitDevProxy\n env?: InfraKitDevEnv\n}\n\n/**\n * Env overrides for this package's dev server only, applied over the loaded (Doppler) env when vite starts\n * it \u2014 never on `build`. For variables another build mode needs that break local dev, e.g. a mobile-only\n * absolute origin that sends requests around the dev proxy.\n *\n * @example\n * // apps/client/ui/infra-kit.config.ts\n * export default defineConfig(() => ({ dev: { env: { unset: ['VITE_ORIGIN_DOMAIN'] } } }))\n */\nexport interface InfraKitDevEnv {\n /** Variables removed from the dev server's env. */\n unset?: string[]\n /** Variables set (or overridden) in the dev server's env. A name cannot also be in `unset`. */\n set?: Record<string, string>\n}\n\n/**\n * Where an e2e package's suite runs. With `target`, `infraKitE2e()` (`@slip-stream-kit/config/playwright`)\n * reads it: a run is local by default \u2014 `target` on this worktree, served by `infra-kit dev <app>` \u2014 and\n * cloud only when asked (`INFRA_KIT_E2E=cloud`, or CI), against the URL in the target package's `deployedUrlEnv`.\n * With `server: 'static'`, see {@link InfraKitE2eStatic}.\n *\n * @example\n * // apps/client/tests/infra-kit.config.ts\n * export default defineConfig(() => ({ e2e: { target: 'client/ui' } }))\n */\nexport type InfraKitE2e = InfraKitE2eTarget | InfraKitE2eStatic\n\nexport interface InfraKitE2eTarget {\n /** The package under test, `<app>/ui` or `<app>/api`. */\n target: string\n server?: never\n}\n\n/**\n * A suite whose own `webServer` serves a static production build \u2014 e.g. one asserting the canonical and `og:`\n * URLs a build inlines, which a dev server never produces. `infraKitE2e()` refuses it, `infra-kit e2e` does\n * not list it, and the audit drops its `infraKitE2e` requirement; the other `playwright.config.ts` rules stay.\n *\n * @example\n * // apps/client/tests/infra-kit.config.ts\n * export default defineConfig(() => ({ e2e: { server: 'static' } }))\n */\nexport interface InfraKitE2eStatic {\n server: 'static'\n target?: never\n}\n\n/**\n * Accepted shapes for a package config's default export \u2014 mirrors Vite's\n * `defineConfig` input: a plain object, a sync factory, or an async factory.\n */\nexport type InfraKitPackageConfigInput =\n InfraKitPackageConfig | (() => InfraKitPackageConfig) | (() => Promise<InfraKitPackageConfig>)\n\n/**\n * Identity helper that gives `infra-kit.config.ts` authors full type inference\n * and editor autocomplete without changing the value \u2014 exactly like Vite's\n * `defineConfig`. Resolution of the factory form happens in the CLI's loader, not here.\n *\n * @example\n * export default defineConfig(() => ({}))\n * @example\n * export default defineConfig(() => ({ requiredScripts: [] }))\n */\nexport const defineConfig = (config: InfraKitPackageConfigInput): InfraKitPackageConfigInput => {\n return config\n}\n", "import { z } from 'zod'\n\n/**\n * Pure (node-free) vendor config schema + authoring helper. Kept separate from\n * `config.ts` (which imports node builtins for the runtime loader) so the public\n * lib entry can re-export `defineVendorConfig` without dragging node types into\n * the emitted `.d.ts`.\n */\n\n/**\n * Filename a source repo provides at its root to declare WHAT `vendor sync`\n * copies (`copy[]`). Lives ONLY on the write path \u2014 `vendor check` never loads it.\n * WHERE/WHICH to stamp (`workspaceDir` + `targets`) is machine-local and lives in\n * the user-global factory config (`~/.infra-kit/vendor.json`).\n */\nexport const VENDOR_CONFIG_FILE = 'vendor.config.ts'\n\n/**\n * A non-empty, repo-relative path with no `..` segments and no absolute prefix\n * (POSIX `/`, UNC/`\\`, or a Windows drive like `C:`). Containment guard for\n * vendor copy items so a malicious/typo config can't read or write outside the\n * source/target repo roots. Kept as a string/regex check (no `node:path`) to\n * respect this file's node-free constraint \u2014 `sync-ops.ts` does the resolved\n * runtime containment assert as defense in depth.\n */\nconst safeRelPath = z.string().refine(\n (p) => {\n const isAbsolute = /^(?:[/\\\\]|[a-z]:)/i.test(p)\n const hasDotDotSegment = p.split(/[\\\\/]/).includes('..')\n\n return !isAbsolute && !hasDotDotSegment && p.trim().length > 0\n },\n { message: 'must be a non-empty repo-relative path without \"..\" segments' },\n)\n\n/**\n * One item to sync from the source repo into each target. `vendored: true` marks\n * workspace packages that must land under `vendor/` (the single-source-of-truth\n * code); everything else is root-level tooling that stays at the repo root.\n */\nexport const vendorCopyItemSchema = z.object({\n name: z.string(),\n source: safeRelPath,\n target: safeRelPath,\n type: z.enum(['file', 'directory']),\n vendored: z.boolean().optional(),\n})\n\nexport const vendorConfigSchema = z\n .object({\n /** Files/dirs to copy. Items with `vendored: true` land under `vendor/`. */\n copy: z.array(vendorCopyItemSchema),\n })\n // Reject stray keys so a leftover `targets` (now machine-local, in\n // ~/.infra-kit/vendor.json) yields a clear \"unrecognized key\" error rather\n // than being silently ignored.\n .strict()\n\nexport type VendorCopyItem = z.infer<typeof vendorCopyItemSchema>\nexport type VendorConfig = z.infer<typeof vendorConfigSchema>\n\n/**\n * Identity helper for authoring a type-safe `vendor.config.ts` in a source repo.\n * Re-exported from the public lib entry so a source repo can\n * `import { defineVendorConfig } from 'infra-kit'`.\n *\n * NOTE: a `vendor.config.ts` must be type-strippable \u2014 Node's native type\n * stripping (Node >= 24) loads it without a build step, which forbids `enum`,\n * `namespace`, and parameter properties.\n *\n * @example\n * export default defineVendorConfig({\n * copy: [{ name: 'Configs', source: 'vendor/configs', target: 'vendor/configs', type: 'directory', vendored: true }],\n * })\n */\nexport const defineVendorConfig = (config: VendorConfig): VendorConfig => {\n return config\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["z", "z"]
|
|
7
7
|
}
|
package/dist/internal.js
CHANGED
|
@@ -23,8 +23,11 @@ var deployServiceSchema = z.strictObject({
|
|
|
23
23
|
* `devops/scripts/deploy-<service>.sh`.
|
|
24
24
|
*/
|
|
25
25
|
deploy: z.string().regex(/^(?!.*\.\.)[\w./-]+\.ts$/, "must be a repo-relative .ts path, e.g. apps/client/api/deploy.ts").optional(),
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* `false` leaves the service out of the deploy-all workflow; a list keeps it in deploy-all for those
|
|
28
|
+
* environments only, e.g. `['prod']`. Either way it stays selectable wherever it may deploy.
|
|
29
|
+
*/
|
|
30
|
+
deployAll: z.union([z.boolean(), z.array(kebabName).nonempty()]).optional()
|
|
28
31
|
});
|
|
29
32
|
var deployConfigSchema = z.strictObject({
|
|
30
33
|
/** The environments the generated workflows offer, in dispatch-menu order. */
|