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 with no tenant or environment data.
2. **TenantAppConfig**: tenant and environment overrides that Studio or control-plane workflows edit over time.
3. **ResolvedAppConfig**: the pure merged view consumed by runtime code.

- Types and registry: \`packages/libs/contracts-spec/src/app-config/spec.ts\`
- Resolution helpers: \`packages/libs/contracts-spec/src/app-config/runtime.ts\`
- Validation helpers: \`packages/libs/contracts-spec/src/app-config/validation.ts\`
- CLI wizard: \`contractspec create app-config\`

### 1. AppBlueprintSpec

\`\`\`ts
export interface AppBlueprintSpec {
  meta: AppBlueprintMeta;          // { key, version, appId, ownership }
  capabilities?: { enabled?: CapabilityRef[]; disabled?: CapabilityRef[] };
  features?: { include?: FeatureRef[]; exclude?: FeatureRef[] };
  integrationSlots?: AppIntegrationSlot[];
  branding?: BrandingDefaults;
  translationCatalog?: { key: string; version: string };
  dataViews?: Record<string, SpecPointer>;
  workflows?: Record<string, SpecPointer>;
  jobs?: Record<string, SpecPointer>;
  policies?: PolicyRef[];
  theme?: AppThemeBinding;         // { primary: ThemeRef; fallbacks?: ThemeRef[] }
  telemetry?: TelemetryBinding;    // { spec?: SpecPointer; disabledEvents?: string[] }
  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. Slots never include secrets.
- **Branding defaults** provide message-key-based names, placeholder assets, and token references that tenants can override later.

### 2. TenantAppConfig

\`\`\`ts
export interface TenantAppConfig {
  meta: TenantAppConfigMeta;  // { id, tenantId, appId, blueprintName, blueprintVersion, version, status }
  capabilities?: { enable?: CapabilityRef[]; disable?: CapabilityRef[] };
  features?: { include?: FeatureRef[]; exclude?: FeatureRef[] };
  dataViewOverrides?: TenantSpecOverride[];
  workflowOverrides?: TenantSpecOverride[];
  jobOverrides?: 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[];
  locales?: { defaultLocale: Locale; enabledLocales: Locale[] };
  translationOverrides?: { entries?: TranslationEntry[] };
  branding?: TenantBrandingConfig;
  notes?: string;
}
\`\`\`

- **AppIntegrationBinding** maps \`slotId\` to \`connectionId\` plus optional workflow scopes.
- **TenantBrandingConfig** allows per-tenant names, assets, and domains while keeping secrets and large files out of blueprints.

### 3. ResolvedAppConfig

Use \`resolveAppConfig(blueprint, tenant)\` to build the merged pointer view. Use \`composeAppConfig(...)\` to hydrate those pointers against registries and collect missing references.

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

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

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

### Static Validation

Use the validation helpers in \`@contractspec/lib.contracts-spec/app-config/validation\` before publish or promotion:

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

const blueprintReport = validateBlueprint(blueprint, context);
const tenantReport = validateTenantConfig(blueprint, tenant, context);
const publishReport = validateConfig(blueprint, tenant, context);
const resolvedReport = validateResolvedConfig(blueprint, resolved, context);

assertBlueprintValid(blueprint, context);
assertTenantConfigValid(blueprint, tenant, context);
assertResolvedConfigValid(blueprint, resolved, context);
\`\`\`

- \`ValidationResult\` exposes \`valid\`, plus structured \`errors\`, \`warnings\`, and \`info\`.
- Core rules cover capability references, integration slot bindings, knowledge bindings, branding constraints, and translation coverage.
- Run \`composeAppConfig(..., { strict: true })\` and the validators in CI to catch drift early.

### CLI

\`\`\`
contractspec create app-config
contractspec validate --blueprint packages/examples/integration-stripe/src/blueprint.ts
\`\`\`

### Lifecycle Types and Events

To model multi-step configuration changes, import the lifecycle helpers 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\` includes lifecycle metadata such as \`createdBy\`, \`publishedBy\`, \`publishedAt\`, and rollback lineage.
- Lifecycle contract specs under \`appConfig.lifecycle.*\` expose typed commands and queries for create -> preview -> publish -> rollback flows.
`}];export{f as tech_contracts_app_config_DocBlocks,c as makeAppBlueprintKey,k as defineAppConfig,G as AppBlueprintRegistry};
