var{defineProperty:L,getOwnPropertyNames:Z,getOwnPropertyDescriptor:_}=Object,$=Object.prototype.hasOwnProperty;function b(h){return this[h]}var S=(h)=>{var j=(X??=new WeakMap).get(h),z;if(j)return j;if(j=L({},"__esModule",{value:!0}),h&&typeof h==="object"||typeof h==="function"){for(var D of Z(h))if(!$.call(j,D))L(j,D,{get:b.bind(h,D),enumerable:!(z=_(h,D))||z.enumerable})}return X.set(h,j),j},X;var A=(h)=>h;function H(h,j){this[h]=A.bind(null,j)}var K=(h,j)=>{for(var z in j)L(h,z,{get:j[z],enumerable:!0,configurable:!0,set:H.bind(j,z)})};var O=(h,j)=>()=>(h&&(j=h(h=0)),j);var q={};K(q,{groupByToArray:()=>R,groupByMultiple:()=>T,groupBy:()=>J,getUniqueTags:()=>P,getUniqueOwners:()=>U,getUniqueDomains:()=>V,filterBy:()=>N,GroupingStrategies:()=>M});function N(h,j){return h.filter((z)=>{if(j.tags?.length){if(!j.tags.some((E)=>z.meta.tags?.includes(E)))return!1}if(j.owners?.length){if(!j.owners.some((E)=>z.meta.owners?.includes(E)))return!1}if(j.stability?.length){if(!j.stability.includes(z.meta.stability??"stable"))return!1}if(j.domain){if(M.byDomain(z)!==j.domain)return!1}if(j.keyPattern){let D=z.meta.key??z.meta.key??"",E=j.keyPattern.replace(/\*/g,".*").replace(/\?/g,".");if(!new RegExp(`^${E}$`,"i").test(D))return!1}return!0})}function J(h,j){let z=new Map;for(let D of h){let E=j(D),I=z.get(E);if(I)I.push(D);else z.set(E,[D])}return z}function R(h,j){let z=J(h,j);return Array.from(z.entries()).map(([D,E])=>({key:D,items:E}))}function T(h,j){let z=new Map;for(let D of h){let E=j(D);for(let I of E){let W=z.get(I);if(W)W.push(D);else z.set(I,[D])}}return z}function P(h){let j=new Set;for(let z of h)for(let D of z.meta.tags??[])j.add(D);return Array.from(j).sort()}function U(h){let j=new Set;for(let z of h)for(let D of z.meta.owners??[])j.add(D);return Array.from(j).sort()}function V(h){let j=new Set;for(let z of h)j.add(M.byDomain(z));return Array.from(j).sort()}var M;var Y=O(()=>{M={byTag:(h)=>h.meta.tags?.[0]??"untagged",byAllTags:(h)=>h.meta.tags?.length?h.meta.tags:["untagged"],byOwner:(h)=>h.meta.owners?.[0]??"unowned",byDomain:(h)=>{return(h.meta.key??h.meta.key??"").split(".")[0]??"default"},byStability:(h)=>h.meta.stability??"stable",byUrlPath:(h)=>(j)=>{if(!j.path)return"root";return j.path.split("/").filter(Boolean).slice(0,h).join("/")||"root"}}});Y();import{compareVersions as B}from"compare-versions";var C=(h)=>`${h.meta.key}.v${h.meta.version}`;class Q{contractType;items=new Map;constructor(h,j){this.contractType=h;if(j)j.forEach((z)=>this.register(z))}register(h){let j=C(h);if(this.items.has(j))throw Error(`Duplicate contract \`${this.contractType}\` ${j}`);return this.items.set(j,h),this}count(){return this.items.size}list(){return[...this.items.values()]}get(h,j){if(j!=null)return this.items.get(`${h}.v${j}`);let z;for(let[D,E]of this.items.entries()){if(!D.startsWith(`${h}.v`))continue;if(!z||B(E.meta.version,z.meta.version)>0)z=E}return z}has(h,j){return!!this.get(h,j)}filter(h){return N(this.list(),h)}listByTag(h){return this.list().filter((j)=>j.meta.tags?.includes(h))}listByOwner(h){return this.list().filter((j)=>j.meta.owners?.includes(h))}groupBy(h){return J(this.list(),h)}getUniqueTags(){return P(this.list())}}var x=(h)=>`${h.key}.v${h.version}`;class G extends Q{constructor(h){super("app-config",h)}}function c(h){return x(h)}var k=(h)=>h,f=[{id:"docs.tech.contracts.app-config",title:"App Configuration Layers",summary:"App orchestration is split into three explicit layers:",kind:"reference",visibility:"public",route:"/docs/tech/contracts/app-config",tags:["tech","contracts","app-config"],body:`## App Configuration Layers

App orchestration is split into three explicit layers:

1. **AppBlueprintSpec** – global, versioned description of what an app can look like. Stored in Git, no tenant/environment data.
2. **TenantAppConfig** – tenant/environment overrides that the future Studio edits. Stored per tenant (DB/contract), mutable at runtime.
3. **ResolvedAppConfig** – pure, merged view consumed by the runtime. Derived in-memory from a blueprint + tenant config.

- Types & registry: \`packages/libs/contracts/src/app-config/spec.ts\`
- Resolution helpers: \`packages/libs/contracts/src/app-config/runtime.ts\`
- CLI wizard (blueprint scaffolding): \`contractspec create app-config\`

### 1. AppBlueprintSpec

\`\`\`ts
export interface AppBlueprintSpec {
  meta: AppBlueprintMeta;          // { name, version, appId, ownership }
  capabilities?: { enabled?: CapabilityRef[]; disabled?: CapabilityRef[] };
  features?: { include?: FeatureRef[]; exclude?: FeatureRef[] };
  integrationSlots?: AppIntegrationSlot[];
  branding?: BrandingDefaults;
  dataViews?: Record<string, SpecPointer>;
  workflows?: Record<string, SpecPointer>;
  policies?: PolicyRef[];
  theme?: AppThemeBinding;
  telemetry?: TelemetryBinding;
  experiments?: { active?: ExperimentRef[]; paused?: ExperimentRef[] };
  featureFlags?: FeatureFlagState[];
  routes?: AppRouteConfig[];
  notes?: string;
}
\`\`\`

Register blueprints with \`AppBlueprintRegistry\`. Blueprints only capture the default/global experience.

- **Integration slots** declare the categories and capability requirements an app expects (e.g. \`"primary-payments"\` must be a payments provider that supports managed or BYOK credentials). Slots never include secrets; tenants bind concrete connections later.
- **Branding defaults** provide message-key based names, placeholder assets, and theme token references that downstream tenants can override.

### 2. TenantAppConfig

\`\`\`ts
export interface TenantAppConfig {
  meta: TenantAppConfigMeta;  // { id, tenantId, appId, blueprintName/version, environment?, version, timestamps }
  capabilities?: { enable?: CapabilityRef[]; disable?: CapabilityRef[] };
  features?: { include?: FeatureRef[]; exclude?: FeatureRef[] };
  dataViewOverrides?: TenantSpecOverride[];
  workflowOverrides?: TenantSpecOverride[];
  additionalPolicies?: PolicyRef[];
  themeOverride?: { primary?: ThemeRef | null; fallbacks?: ThemeRef[] };
  telemetryOverride?: { spec?: SpecPointer | null; disabledEvents?: string[] };
  experiments?: { active?: ExperimentRef[]; paused?: ExperimentRef[] };
  featureFlags?: FeatureFlagState[];
  routeOverrides?: TenantRouteOverride[];
  integrations?: AppIntegrationBinding[];
  knowledge?: AppKnowledgeBinding[];
  branding?: TenantBrandingConfig;
  notes?: string;
}
\`\`\`

This object represents what a tenant edits via the Studio (stored in DB/contracts later).

- **AppIntegrationBinding** now maps \`slotId\` → \`connectionId\` (plus optional workflow scopes). It no longer carries capability lists; those are defined once in the slot.
- **TenantBrandingConfig** allows per-tenant names, assets, and domain overrides while keeping secrets and large files out of blueprints.

### 3. ResolvedAppConfig

\`\`\`ts
export interface ResolvedAppConfig {
  appId: string;
  tenantId: string;
  environment?: string;
  blueprintName: string;
  blueprintVersion: number;
  configVersion: number;
  capabilities: { enabled: CapabilityRef[]; disabled: CapabilityRef[] };
  features: { include: FeatureRef[]; exclude: FeatureRef[] };
  dataViews: Record<string, SpecPointer>;
  workflows: Record<string, SpecPointer>;
  policies: PolicyRef[];
  theme?: AppThemeBinding;
  telemetry?: TelemetryBinding;
  experiments: { catalog: ExperimentRef[]; active: ExperimentRef[]; paused: ExperimentRef[] };
  featureFlags: FeatureFlagState[];
  routes: AppRouteConfig[];
  integrations: ResolvedIntegration[];
  knowledge: ResolvedKnowledge[];
  branding: ResolvedBranding;
  notes?: string;
}
\`\`\`

Use \`resolveAppConfig(blueprint, tenant)\` to produce this merged view. No IO, no registry lookups—pure data merge.

- \`resolveAppConfig\` validates slot/category/mode constraints when \`integrationConnections\` and \`integrationSpecs\` are provided.
- \`branding\` merges blueprint defaults with tenant overrides, producing a runtime-friendly shape (resolved asset URLs, color values, and effective domain).

### Materializing specs

\`composeAppConfig(blueprint, tenant, registries, { strict })\`:

1. Calls \`resolveAppConfig\` to build the merged pointers.
2. Looks up referenced specs in the provided registries.
3. Returns:
   - \`resolved\` – the merged pointer view
   - \`capabilities\`, \`features\`, \`dataViews\`, \`workflows\`, \`policies\`, \`theme\`, \`telemetry\`, \`experiments\`
   - \`missing\` – unresolved references (strict mode throws).

\`\`\`ts
const blueprint = blueprintRegistry.get('core.app', 1)!;
const tenant = loadTenantConfigFromDB();

const composition = composeAppConfig(blueprint, tenant, {
  capabilities,
  features,
  dataViews,
  workflows,
  policies,
  themes,
  telemetry,
  experiments,
});

if (composition.missing.length) {
  console.warn('Unresolved references', composition.missing);
}
\`\`\`

### CLI workflow

\`\`\`
contractspec create app-config
\`\`\`

Generates an \`AppBlueprintSpec\`. A separate flow will later scaffold tenant configs.

### Best practices

1. Keep blueprint and tenant versions monotonic; bump when referenced spec versions change.
2. Favor stable slot keys (e.g. \`dataViews.dashboard\`) to align with Studio UX.
3. Reference telemetry and experiments declared in their respective specs to maintain observability.
4. Run \`resolveAppConfig\` in pure unit tests and \`composeAppConfig(..., { strict: true })\` in CI to catch drift early.
5. Pair resolved configs with \`TestSpec\` scenarios to guard tenant experiences end-to-end.

### Static validation

Use the validation helpers in \`@contractspec/lib.contracts-spec/app-config/validation\` to keep blueprints and tenant configs safe before publish time.

\`\`\`ts
import {
  validateConfig,
  validateBlueprint,
  validateTenantConfig,
  validateResolvedConfig,
} from '@contractspec/lib.contracts-spec/app-config/validation';

const context = {
  integrationSpecs,
  tenantConnections,
  knowledgeSpaces,
  knowledgeSources,
  translationCatalogs: {
    blueprint: blueprintCatalog,
    platform: platformCatalog,
  },
  existingConfigs,
};

const blueprintReport = validateBlueprint(blueprint, context);
const tenantReport = validateTenantConfig(blueprint, tenant, context);
const publishReport = validateConfig(blueprint, tenant, context);
\`\`\`

- \`ValidationResult\` exposes \`valid\`, plus structured \`errors\`, \`warnings\`, and \`info\`.
- Core rules cover capability references, integration slot bindings (category/ownership/capabilities), knowledge bindings, branding constraints (domains + assets), and translation coverage.
- Call \`validateBlueprint\` in CI when committing new specs, and \`validateConfig\` before promoting/publishing a tenant config.
- \`validateResolvedConfig\` can be used as a runtime pre-flight check when composing full configs for workflows.
- CLI usage example (blueprint + tenant):

\`\`\`
buncontractspec validate \\
  packages/examples/integration-stripe/blueprint.ts \\
  --blueprint packages/examples/integration-stripe/blueprint.ts \\
  --tenant-config packages/examples/integration-stripe/tenant.ts
\`\`\`
- Repository script:

\`\`\`
bun run validate:blueprints
\`\`\`

Runs the static validator for the sample blueprints/tenants and is wired into CI.


### Lifecycle types & events

To model multi-step configuration changes, use the lifecycle helpers exported from \`@contractspec/lib.contracts-spec/app-config\`:

\`\`\`ts
import type {
  ConfigStatus,
  TenantAppConfigVersion,
  ConfigTransition,
} from '@contractspec/lib.contracts-spec/app-config';
import {
  ConfigDraftCreatedEvent,
  ConfigPromotedToPreviewEvent,
  ConfigPublishedEvent,
  ConfigRolledBackEvent,
} from '@contractspec/lib.contracts-spec/app-config';
\`\`\`

- \`ConfigStatus\` enumerates the canonical states: \`draft\`, \`preview\`, \`published\`, \`archived\`, \`superseded\`.
- \`TenantAppConfigMeta\` now includes lifecycle metadata (\`status\`, \`createdBy\`, \`publishedBy\`, \`publishedAt\`, \`rolledBackFrom\`, \`rolledBackTo\`, \`changeSummary\`).
- \`TenantAppConfigVersion\` couples the lifecycle-aware metadata with the \`TenantAppConfig\` payload for history views.
- \`ConfigTransition\` captures state changes with actor, timestamp, and optional reason.
- Lifecycle events (\`app_config.draft_created\`, \`app_config.promoted_to_preview\`, \`app_config.published\`, \`app_config.rolled_back\`) standardize observability across services.
- Lifecycle contract specs (\`appConfig.lifecycle.*\`) expose typed commands/queries for create → preview → publish → rollback flows.

`}];export{f as tech_contracts_app_config_DocBlocks,c as makeAppBlueprintKey,k as defineAppConfig,G as AppBlueprintRegistry};
