@slip-stream-kit/config 0.11.15 → 0.13.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.
@@ -1,6 +1,8 @@
1
1
  export { packageConfigSchema } from '../lib/package-config/package-config-schema';
2
+ export { DEV_SERVING_MARKER, E2E_MODE_ENV } from '../lib/playwright/playwright';
3
+ export { readRelease } from '../lib/release-slug/read-release';
2
4
  export { DEFAULT_RELEASE_SLUG, slugifyHostLabel, slugifyRelease } from '../lib/release-slug/release-slug';
3
5
  export { defineVendorConfig, VENDOR_CONFIG_FILE, vendorConfigSchema, vendorCopyItemSchema, } from '../lib/vendor/config-schema';
4
6
  export type { VendorConfig, VendorCopyItem } from '../lib/vendor/config-schema';
5
- export { describeProxyRoutes, DEV_CONTEXT_WIRE_VERSION, loadDev, readLocalContext, readLocalSet, } from '../lib/vite/vite';
6
- export type { LocalContext, LocalPackageInfo, ProxyRouteDescription } from '../lib/vite/vite';
7
+ export { describeProxyRoutes, DEV_CONTEXT_WIRE_VERSION, loadDev, loadPackageConfig, readCloudOrigin, readLocalContext, readLocalSet, } from '../lib/vite/vite';
8
+ export type { CloudOrigin, LocalContext, LocalPackageInfo, ProxyRouteDescription } from '../lib/vite/vite';
@@ -0,0 +1,2 @@
1
+ export { DEV_SERVING_MARKER, E2E_MODE_ENV, infraKitE2e } from '../lib/playwright/playwright';
2
+ export type { InfraKitE2eMode, InfraKitE2eOptions, InfraKitE2eSetup, InfraKitWebServer, } from '../lib/playwright/playwright';
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/lib/package-config/package-config.ts", "../src/lib/vendor/config-schema.ts"],
4
- "sourcesContent": ["/**\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 /** Local-dev configuration. Accepted-and-inert to the audit; consumed by the dev server. */\n dev?: InfraKitDev\n /** Where `infra-kit e2e` points this e2e package's Playwright run. Consumed by the CLI, inert to 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 /** URL templates. Placeholders like `<release>`/`<packageName>`/`<env>` are substituted at dev time. */\n templates: {\n local: string\n cloud: 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}\n\n/**\n * The e2e package's target. Local vs cloud is never configured: `infra-kit e2e` runs against this\n * worktree's dev server when one serves `target`, and against the deployed app at `INFRA_KIT_ENV` otherwise.\n *\n * @example\n * // apps/client/tests/infra-kit.config.ts\n * export default defineConfig(() => ({\n * e2e: { target: 'client/ui', baseUrlEnv: 'E2E_CLIENT_BASE_URL' },\n * }))\n */\nexport interface InfraKitE2e {\n /** The package under test, `<app>/ui` or `<app>/api`. */\n target: string\n /** The env var the Playwright config reads its base URL from; `infra-kit e2e` sets it for the run. */\n baseUrlEnv: string\n /**\n * The deployed URL, with an `<env>` placeholder. Separate from `dev.proxy.templates.cloud` because that\n * one names the BACKEND a UI proxies to, which is not always the host the UI itself is served from.\n * Absent \u2192 the value of `baseUrlEnv` that `infra-kit env-load` loaded, which is where Doppler already\n * keeps each env's deployed URL \u2014 the usual case, and the only one where prod is not `<env>`-shaped.\n */\n cloud?: string\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": ";AA6HO,IAAM,eAAe,CAAC,WAAmE;AAC9F,SAAO;AACT;;;AC/HA,SAAS,SAAS;AAyBlB,IAAM,cAAc,EAAE,OAAO,EAAE;AAAA,EAC7B,CAAC,MAAM;AACL,UAAM,aAAa,qBAAqB,KAAK,CAAC;AAC9C,UAAM,mBAAmB,EAAE,MAAM,OAAO,EAAE,SAAS,IAAI;AAEvD,WAAO,CAAC,cAAc,CAAC,oBAAoB,EAAE,KAAK,EAAE,SAAS;AAAA,EAC/D;AAAA,EACA,EAAE,SAAS,+DAA+D;AAC5E;AAOO,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,MAAM,EAAE,OAAO;AAAA,EACf,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM,EAAE,KAAK,CAAC,QAAQ,WAAW,CAAC;AAAA,EAClC,UAAU,EAAE,QAAQ,EAAE,SAAS;AACjC,CAAC;AAEM,IAAM,qBAAqB,EAC/B,OAAO;AAAA;AAAA,EAEN,MAAM,EAAE,MAAM,oBAAoB;AACpC,CAAC,EAIA,OAAO;AAmBH,IAAM,qBAAqB,CAAC,WAAuC;AACxE,SAAO;AACT;",
4
+ "sourcesContent": ["/**\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 /** Which app part this e2e package tests. Consumed by `infraKitE2e()` and the CLI, inert to 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.\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}\n\n/**\n * The e2e package's target. `infraKitE2e()` (`@slip-stream-kit/config/playwright`) reads it: a run is local\n * by default \u2014 `target` on this worktree, served by `infra-kit dev <app>` \u2014 and cloud only when asked\n * (`INFRA_KIT_E2E=cloud`, or CI), against the URL in the target package's `deployedUrlEnv`.\n *\n * @example\n * // apps/client/tests/infra-kit.config.ts\n * export default defineConfig(() => ({ e2e: { target: 'client/ui' } }))\n */\nexport interface InfraKitE2e {\n /** The package under test, `<app>/ui` or `<app>/api`. */\n target: string\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": ";AA4HO,IAAM,eAAe,CAAC,WAAmE;AAC9F,SAAO;AACT;;;AC9HA,SAAS,SAAS;AAyBlB,IAAM,cAAc,EAAE,OAAO,EAAE;AAAA,EAC7B,CAAC,MAAM;AACL,UAAM,aAAa,qBAAqB,KAAK,CAAC;AAC9C,UAAM,mBAAmB,EAAE,MAAM,OAAO,EAAE,SAAS,IAAI;AAEvD,WAAO,CAAC,cAAc,CAAC,oBAAoB,EAAE,KAAK,EAAE,SAAS;AAAA,EAC/D;AAAA,EACA,EAAE,SAAS,+DAA+D;AAC5E;AAOO,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,MAAM,EAAE,OAAO;AAAA,EACf,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM,EAAE,KAAK,CAAC,QAAQ,WAAW,CAAC;AAAA,EAClC,UAAU,EAAE,QAAQ,EAAE,SAAS;AACjC,CAAC;AAEM,IAAM,qBAAqB,EAC/B,OAAO;AAAA;AAAA,EAEN,MAAM,EAAE,MAAM,oBAAoB;AACpC,CAAC,EAIA,OAAO;AAmBH,IAAM,qBAAqB,CAAC,WAAuC;AACxE,SAAO;AACT;",
6
6
  "names": []
7
7
  }
package/dist/internal.js CHANGED
@@ -1,5 +1,9 @@
1
1
  // src/lib/package-config/package-config-schema.ts
2
2
  import { z } from "zod";
3
+ var ENV_VAR_NAME = /^[A-Z_][A-Z0-9_]*$/;
4
+ var retired = (replacement) => {
5
+ return z.never({ error: replacement }).optional();
6
+ };
3
7
  var packageConfigSchema = z.strictObject({
4
8
  requiredScripts: z.array(z.string().min(1)).optional(),
5
9
  requiredFiles: z.array(z.string().min(1)).optional(),
@@ -7,6 +11,9 @@ var packageConfigSchema = z.strictObject({
7
11
  // so a default on an optional key would make an EMPTY override layer parse to that default and
8
12
  // shallow-merge over a real setting from an earlier layer. Defaults belong at the read site.
9
13
  type: z.enum(["frontend", "backend", "lib", "e2e", "mobile"]).optional(),
14
+ // The deployed origin differs per environment (prod is not `<env>`-shaped), so the config names the
15
+ // variable and Doppler holds the value — the one source both the dev proxy and e2e read.
16
+ deployedUrlEnv: z.string().regex(ENV_VAR_NAME, "deployedUrlEnv must be an env var name (e.g. `CLIENT_URL`)").optional(),
10
17
  turbo: z.strictObject({
11
18
  requiredTasks: z.array(z.string().min(1)).optional()
12
19
  }).optional(),
@@ -18,7 +25,9 @@ var packageConfigSchema = z.strictObject({
18
25
  // warning emitted from `loadDev` in `../vite/vite.ts`). Make `https://` a hard schema
19
26
  // requirement next release, once both consumer repos have had a release to pick up the warning.
20
27
  local: z.string().min(1),
21
- cloud: z.string().min(1)
28
+ cloud: retired(
29
+ "`templates.cloud` was replaced by `deployedUrlEnv`: set `deployedUrlEnv: '<APP>_URL'` at the top of this config and keep the URL per environment in Doppler"
30
+ )
22
31
  }),
23
32
  routes: z.record(
24
33
  z.string().min(1),
@@ -46,10 +55,26 @@ var packageConfigSchema = z.strictObject({
46
55
  }).optional(),
47
56
  e2e: z.strictObject({
48
57
  target: z.string().regex(/^[^/\s]+\/(?:ui|api)$/, "target must be `<app>/ui` or `<app>/api` (e.g. `client/ui`)"),
49
- baseUrlEnv: z.string().regex(/^[A-Z_][A-Z0-9_]*$/, "baseUrlEnv must be an env var name"),
50
- cloud: z.string().min(1).optional()
58
+ baseUrlEnv: retired(
59
+ "`e2e.baseUrlEnv` was removed: the deployed URL is the target package's own `deployedUrlEnv`"
60
+ ),
61
+ cloud: retired("`e2e.cloud` was removed: the deployed URL is the target package's own `deployedUrlEnv`")
51
62
  }).optional()
52
- });
63
+ }).refine(
64
+ (config) => {
65
+ const routes = Object.values(config.dev?.proxy?.routes ?? {});
66
+ return config.deployedUrlEnv !== void 0 || !routes.some((route) => {
67
+ return route.from.includes("cloud");
68
+ });
69
+ },
70
+ {
71
+ message: "a `dev.proxy` route that can go to cloud needs `deployedUrlEnv` \u2014 the variable holding this app's deployed URL",
72
+ path: ["deployedUrlEnv"]
73
+ }
74
+ );
75
+
76
+ // src/lib/release-slug/read-release.ts
77
+ import { execFileSync } from "node:child_process";
53
78
 
54
79
  // src/lib/release-slug/release-slug.ts
55
80
  var slugifyHostLabel = (label) => {
@@ -61,30 +86,18 @@ var slugifyRelease = (branch) => {
61
86
  };
62
87
  var DEFAULT_RELEASE_SLUG = "local";
63
88
 
64
- // src/lib/vendor/config-schema.ts
65
- import { z as z2 } from "zod";
66
- var VENDOR_CONFIG_FILE = "vendor.config.ts";
67
- var safeRelPath = z2.string().refine(
68
- (p) => {
69
- const isAbsolute = /^(?:[/\\]|[a-z]:)/i.test(p);
70
- const hasDotDotSegment = p.split(/[\\/]/).includes("..");
71
- return !isAbsolute && !hasDotDotSegment && p.trim().length > 0;
72
- },
73
- { message: 'must be a non-empty repo-relative path without ".." segments' }
74
- );
75
- var vendorCopyItemSchema = z2.object({
76
- name: z2.string(),
77
- source: safeRelPath,
78
- target: safeRelPath,
79
- type: z2.enum(["file", "directory"]),
80
- vendored: z2.boolean().optional()
81
- });
82
- var vendorConfigSchema = z2.object({
83
- /** Files/dirs to copy. Items with `vendored: true` land under `vendor/`. */
84
- copy: z2.array(vendorCopyItemSchema)
85
- }).strict();
86
- var defineVendorConfig = (config) => {
87
- return config;
89
+ // src/lib/release-slug/read-release.ts
90
+ var readRelease = (cwd) => {
91
+ try {
92
+ const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
93
+ cwd,
94
+ encoding: "utf-8",
95
+ stdio: ["ignore", "pipe", "ignore"]
96
+ }).trim();
97
+ return slugifyRelease(branch) || DEFAULT_RELEASE_SLUG;
98
+ } catch {
99
+ return DEFAULT_RELEASE_SLUG;
100
+ }
88
101
  };
89
102
 
90
103
  // src/lib/vite/vite.ts
@@ -92,20 +105,20 @@ import fs from "node:fs";
92
105
  import path from "node:path";
93
106
  import process from "node:process";
94
107
  import { pathToFileURL } from "node:url";
95
- import { z as z3 } from "zod";
108
+ import { z as z2 } from "zod";
96
109
  var PACKAGE_CONFIG_FILE = "infra-kit.config.ts";
97
110
  var DEV_CONTEXT_DIR = path.join(".infra-kit", "dev-context");
98
111
  var DEV_CONTEXT_FILE = path.join(".infra-kit", "dev-context.json");
99
- var devContextFragmentSchema = z3.object({
100
- package: z3.string(),
101
- port: z3.number(),
102
- pid: z3.number().optional(),
103
- writtenAt: z3.number().optional(),
104
- release: z3.string().optional(),
105
- alias: z3.string().optional(),
106
- proxyPort: z3.number().optional(),
107
- origin: z3.string().optional(),
108
- v: z3.number().optional()
112
+ var devContextFragmentSchema = z2.object({
113
+ package: z2.string(),
114
+ port: z2.number(),
115
+ pid: z2.number().optional(),
116
+ writtenAt: z2.number().optional(),
117
+ release: z2.string().optional(),
118
+ alias: z2.string().optional(),
119
+ proxyPort: z2.number().optional(),
120
+ origin: z2.string().optional(),
121
+ v: z2.number().optional()
109
122
  });
110
123
  var DEV_CONTEXT_WIRE_VERSION = 2;
111
124
  var interpolate = (template, values) => {
@@ -163,6 +176,7 @@ var describeProxyRoutes = ({
163
176
  proxy,
164
177
  localContext,
165
178
  env,
179
+ cloud,
166
180
  getRelease
167
181
  }) => {
168
182
  const paths = Object.keys(proxy.routes).toSorted((a, b) => {
@@ -173,7 +187,7 @@ var describeProxyRoutes = ({
173
187
  const source = pickSource(route, localContext.packages);
174
188
  let target = null;
175
189
  if (source === "cloud") {
176
- target = env ? interpolate(proxy.templates.cloud, { release: "", packageName: route.packageName, env }) : null;
190
+ target = cloud.url ?? null;
177
191
  } else {
178
192
  try {
179
193
  target = resolveLocalTarget({
@@ -198,7 +212,10 @@ var warnIfNonHttpsLocalTemplate = (dev, configPath) => {
198
212
  );
199
213
  }
200
214
  };
201
- var loadDev = async (cwd) => {
215
+ var readCloudOrigin = (envVar, env = process.env) => {
216
+ return { envVar, url: envVar ? env[envVar] || void 0 : void 0 };
217
+ };
218
+ var loadPackageConfig = async (cwd) => {
202
219
  const configPath = path.join(cwd, PACKAGE_CONFIG_FILE);
203
220
  if (!fs.existsSync(configPath)) return void 0;
204
221
  const stat = fs.statSync(configPath);
@@ -210,11 +227,15 @@ var loadDev = async (cwd) => {
210
227
  const parsed = packageConfigSchema.safeParse(resolved);
211
228
  if (!parsed.success) {
212
229
  throw new Error(
213
- `@slip-stream-kit/config/vite: invalid ${PACKAGE_CONFIG_FILE} at ${configPath}: ${z3.prettifyError(parsed.error)}`
230
+ `@slip-stream-kit/config: invalid ${PACKAGE_CONFIG_FILE} at ${configPath}: ${z2.prettifyError(parsed.error)}`
214
231
  );
215
232
  }
216
- warnIfNonHttpsLocalTemplate(parsed.data.dev, configPath);
217
- return parsed.data.dev;
233
+ return parsed.data;
234
+ };
235
+ var loadDev = async (cwd) => {
236
+ const dev = (await loadPackageConfig(cwd))?.dev;
237
+ warnIfNonHttpsLocalTemplate(dev, path.join(cwd, PACKAGE_CONFIG_FILE));
238
+ return dev;
218
239
  };
219
240
  var extractPackages = (parsed) => {
220
241
  if (Array.isArray(parsed)) {
@@ -298,16 +319,51 @@ var readLocalContext = (cwd) => {
298
319
  var readLocalSet = (cwd) => {
299
320
  return readLocalContext(cwd).packages;
300
321
  };
322
+
323
+ // src/lib/playwright/playwright.ts
324
+ var DEV_SERVING_MARKER = "infra-kit dev: serving";
325
+ var E2E_MODE_ENV = "INFRA_KIT_E2E";
326
+
327
+ // src/lib/vendor/config-schema.ts
328
+ import { z as z3 } from "zod";
329
+ var VENDOR_CONFIG_FILE = "vendor.config.ts";
330
+ var safeRelPath = z3.string().refine(
331
+ (p) => {
332
+ const isAbsolute = /^(?:[/\\]|[a-z]:)/i.test(p);
333
+ const hasDotDotSegment = p.split(/[\\/]/).includes("..");
334
+ return !isAbsolute && !hasDotDotSegment && p.trim().length > 0;
335
+ },
336
+ { message: 'must be a non-empty repo-relative path without ".." segments' }
337
+ );
338
+ var vendorCopyItemSchema = z3.object({
339
+ name: z3.string(),
340
+ source: safeRelPath,
341
+ target: safeRelPath,
342
+ type: z3.enum(["file", "directory"]),
343
+ vendored: z3.boolean().optional()
344
+ });
345
+ var vendorConfigSchema = z3.object({
346
+ /** Files/dirs to copy. Items with `vendored: true` land under `vendor/`. */
347
+ copy: z3.array(vendorCopyItemSchema)
348
+ }).strict();
349
+ var defineVendorConfig = (config) => {
350
+ return config;
351
+ };
301
352
  export {
302
353
  DEFAULT_RELEASE_SLUG,
303
354
  DEV_CONTEXT_WIRE_VERSION,
355
+ DEV_SERVING_MARKER,
356
+ E2E_MODE_ENV,
304
357
  VENDOR_CONFIG_FILE,
305
358
  defineVendorConfig,
306
359
  describeProxyRoutes,
307
360
  loadDev,
361
+ loadPackageConfig,
308
362
  packageConfigSchema,
363
+ readCloudOrigin,
309
364
  readLocalContext,
310
365
  readLocalSet,
366
+ readRelease,
311
367
  slugifyHostLabel,
312
368
  slugifyRelease,
313
369
  vendorConfigSchema,