@contractspec/bundle.workspace 1.45.0 → 1.45.2

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 +1 @@
1
- {"version":3,"file":"sync.d.ts","names":[],"sources":["../../src/services/sync.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAqCY,UAxBK,gBAAA,CA2BZ;EAEO,OAAA,CAAA,EAAA,MAAA;EAEU,UAAA,CAAA,EAAS,CAAA,MAAA,GAAA,SAAA,CAAA,EAAA;EACb,QAAA,CAAA,EAAA,OAAA;EAAmB,YAAA,CAAA,EA5BpB,IA4BoB,CA5Bf,gBA4Be,EAAA,WAAA,CAAA;EAC3B,MAAA,CAAA,EAAA,OAAA;;AAGE,UA5BK,kBAAA,CA4BL;EACG,QAAA,EAAA,MAAA;EAEJ,SAAA,CAAA,EAAA,MAAA;EAAR,UAAA,CAAA,EA5BY,kBA4BZ;EAAO,KAAA,CAAA,EAAA,OAAA;;;;;;UApBO,eAAA;;QAET;;KAGI,sEAGP,QAAQ;KAED,cAAA,yBAAuC,QAAQ;iBAErC,SAAA;MACJ;UAAmB;WAC3B,2BACC;UAEC;aACG;IAEZ,QAAQ"}
1
+ {"version":3,"file":"sync.d.ts","names":[],"sources":["../../src/services/sync.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAqCY,UAxBK,gBAAA,CA2BJ;EAED,OAAA,CAAA,EAAA,MAAA;EAEU,UAAA,CAAA,EAAS,CAAA,MAAA,GAAA,SAAA,CAAA,EAAA;EACb,QAAA,CAAA,EAAA,OAAA;EAAmB,YAAA,CAAA,EA5BpB,IA4BoB,CA5Bf,gBA4Be,EAAA,WAAA,CAAA;EAC3B,MAAA,CAAA,EAAA,OAAA;;AAGE,UA5BK,kBAAA,CA4BL;EACG,QAAA,EAAA,MAAA;EAEJ,SAAA,CAAA,EAAA,MAAA;EAAR,UAAA,CAAA,EA5BY,kBA4BZ;EAAO,KAAA,CAAA,EAAA,OAAA;;;;;;UApBO,eAAA;;QAET;;KAGI,sEAGP,QAAQ;KAED,cAAA,yBAAuC,QAAQ;iBAErC,SAAA;MACJ;UAAmB;WAC3B,2BACC;UAEC;aACG;IAEZ,QAAQ"}
@@ -42,7 +42,7 @@ function extractBlueprintSpec(mod) {
42
42
  return candidates[0];
43
43
  }
44
44
  function isBlueprintSpec(value) {
45
- return typeof value === "object" && value !== null && "meta" in value && typeof value.meta?.key === "string" && typeof value.meta?.version === "number";
45
+ return typeof value === "object" && value !== null && "meta" in value && typeof value.meta?.key === "string" && typeof value.meta?.version === "string";
46
46
  }
47
47
 
48
48
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"blueprint-validator.js","names":["validateBlueprint","validateBlueprintSpec"],"sources":["../../../src/services/validate/blueprint-validator.ts"],"sourcesContent":["import { resolve } from 'path';\nimport { pathToFileURL } from 'url';\nimport {\n validateBlueprint as validateBlueprintSpec,\n type AppBlueprintSpec,\n} from '@contractspec/lib.contracts';\nimport type { FsAdapter } from '../../ports/fs';\n\n/**\n * Result of blueprint validation.\n */\nexport interface BlueprintValidationResult {\n spec?: AppBlueprintSpec;\n report?: ReturnType<typeof validateBlueprintSpec>;\n valid: boolean;\n errors: string[];\n}\n\n/**\n * Validate a blueprint spec file.\n */\nexport async function validateBlueprint(\n blueprintPath: string,\n adapters: { fs: FsAdapter }\n): Promise<BlueprintValidationResult> {\n const { fs } = adapters;\n const resolvedPath = resolve(process.cwd(), blueprintPath);\n\n if (!(await fs.exists(resolvedPath))) {\n return {\n valid: false,\n errors: [`Blueprint file not found: ${resolvedPath}`],\n };\n }\n\n try {\n const mod = await loadModule(resolvedPath);\n const spec = extractBlueprintSpec(mod);\n const report = validateBlueprintSpec(spec);\n\n return {\n spec,\n report,\n valid: report.valid,\n errors: report.errors.map((e) => `[${e.code}] ${e.path}: ${e.message}`),\n };\n } catch (error) {\n return {\n valid: false,\n errors: [error instanceof Error ? error.message : String(error)],\n };\n }\n}\n\nasync function loadModule(\n modulePath: string\n): Promise<Record<string, unknown>> {\n try {\n const url = pathToFileURL(modulePath).href;\n // Using native import which works with Bun and Node (if configured)\n const mod = await import(url);\n return mod;\n } catch (error) {\n throw new Error(`Failed to load module at ${modulePath}: ${error}`);\n }\n}\n\nfunction extractBlueprintSpec(mod: Record<string, unknown>): AppBlueprintSpec {\n const candidates = Object.values(mod).filter(isBlueprintSpec);\n if (candidates.length === 0) {\n throw new Error('Blueprint module does not export an AppBlueprintSpec.');\n }\n return candidates[0] as AppBlueprintSpec;\n}\n\nfunction isBlueprintSpec(value: unknown): value is AppBlueprintSpec {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as AppBlueprintSpec).meta?.key === 'string' &&\n typeof (value as AppBlueprintSpec).meta?.version === 'number'\n );\n}\n"],"mappings":";;;;;;;;AAqBA,eAAsBA,oBACpB,eACA,UACoC;CACpC,MAAM,EAAE,OAAO;CACf,MAAM,eAAe,QAAQ,QAAQ,KAAK,EAAE,cAAc;AAE1D,KAAI,CAAE,MAAM,GAAG,OAAO,aAAa,CACjC,QAAO;EACL,OAAO;EACP,QAAQ,CAAC,6BAA6B,eAAe;EACtD;AAGH,KAAI;EAEF,MAAM,OAAO,qBADD,MAAM,WAAW,aAAa,CACJ;EACtC,MAAM,SAASC,kBAAsB,KAAK;AAE1C,SAAO;GACL;GACA;GACA,OAAO,OAAO;GACd,QAAQ,OAAO,OAAO,KAAK,MAAM,IAAI,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE,UAAU;GACxE;UACM,OAAO;AACd,SAAO;GACL,OAAO;GACP,QAAQ,CAAC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC;GACjE;;;AAIL,eAAe,WACb,YACkC;AAClC,KAAI;AAIF,SADY,MAAM,OAFN,cAAc,WAAW,CAAC;UAI/B,OAAO;AACd,QAAM,IAAI,MAAM,4BAA4B,WAAW,IAAI,QAAQ;;;AAIvE,SAAS,qBAAqB,KAAgD;CAC5E,MAAM,aAAa,OAAO,OAAO,IAAI,CAAC,OAAO,gBAAgB;AAC7D,KAAI,WAAW,WAAW,EACxB,OAAM,IAAI,MAAM,wDAAwD;AAE1E,QAAO,WAAW;;AAGpB,SAAS,gBAAgB,OAA2C;AAClE,QACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAA2B,MAAM,QAAQ,YACjD,OAAQ,MAA2B,MAAM,YAAY"}
1
+ {"version":3,"file":"blueprint-validator.js","names":["validateBlueprint","validateBlueprintSpec"],"sources":["../../../src/services/validate/blueprint-validator.ts"],"sourcesContent":["import { resolve } from 'path';\nimport { pathToFileURL } from 'url';\nimport {\n validateBlueprint as validateBlueprintSpec,\n type AppBlueprintSpec,\n} from '@contractspec/lib.contracts';\nimport type { FsAdapter } from '../../ports/fs';\n\n/**\n * Result of blueprint validation.\n */\nexport interface BlueprintValidationResult {\n spec?: AppBlueprintSpec;\n report?: ReturnType<typeof validateBlueprintSpec>;\n valid: boolean;\n errors: string[];\n}\n\n/**\n * Validate a blueprint spec file.\n */\nexport async function validateBlueprint(\n blueprintPath: string,\n adapters: { fs: FsAdapter }\n): Promise<BlueprintValidationResult> {\n const { fs } = adapters;\n const resolvedPath = resolve(process.cwd(), blueprintPath);\n\n if (!(await fs.exists(resolvedPath))) {\n return {\n valid: false,\n errors: [`Blueprint file not found: ${resolvedPath}`],\n };\n }\n\n try {\n const mod = await loadModule(resolvedPath);\n const spec = extractBlueprintSpec(mod);\n const report = validateBlueprintSpec(spec);\n\n return {\n spec,\n report,\n valid: report.valid,\n errors: report.errors.map((e) => `[${e.code}] ${e.path}: ${e.message}`),\n };\n } catch (error) {\n return {\n valid: false,\n errors: [error instanceof Error ? error.message : String(error)],\n };\n }\n}\n\nasync function loadModule(\n modulePath: string\n): Promise<Record<string, unknown>> {\n try {\n const url = pathToFileURL(modulePath).href;\n // Using native import which works with Bun and Node (if configured)\n const mod = await import(url);\n return mod;\n } catch (error) {\n throw new Error(`Failed to load module at ${modulePath}: ${error}`);\n }\n}\n\nfunction extractBlueprintSpec(mod: Record<string, unknown>): AppBlueprintSpec {\n const candidates = Object.values(mod).filter(isBlueprintSpec);\n if (candidates.length === 0) {\n throw new Error('Blueprint module does not export an AppBlueprintSpec.');\n }\n return candidates[0] as AppBlueprintSpec;\n}\n\nfunction isBlueprintSpec(value: unknown): value is AppBlueprintSpec {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as AppBlueprintSpec).meta?.key === 'string' &&\n typeof (value as AppBlueprintSpec).meta?.version === 'string'\n );\n}\n"],"mappings":";;;;;;;;AAqBA,eAAsBA,oBACpB,eACA,UACoC;CACpC,MAAM,EAAE,OAAO;CACf,MAAM,eAAe,QAAQ,QAAQ,KAAK,EAAE,cAAc;AAE1D,KAAI,CAAE,MAAM,GAAG,OAAO,aAAa,CACjC,QAAO;EACL,OAAO;EACP,QAAQ,CAAC,6BAA6B,eAAe;EACtD;AAGH,KAAI;EAEF,MAAM,OAAO,qBADD,MAAM,WAAW,aAAa,CACJ;EACtC,MAAM,SAASC,kBAAsB,KAAK;AAE1C,SAAO;GACL;GACA;GACA,OAAO,OAAO;GACd,QAAQ,OAAO,OAAO,KAAK,MAAM,IAAI,EAAE,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE,UAAU;GACxE;UACM,OAAO;AACd,SAAO;GACL,OAAO;GACP,QAAQ,CAAC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC;GACjE;;;AAIL,eAAe,WACb,YACkC;AAClC,KAAI;AAIF,SADY,MAAM,OAFN,cAAc,WAAW,CAAC;UAI/B,OAAO;AACd,QAAM,IAAI,MAAM,4BAA4B,WAAW,IAAI,QAAQ;;;AAIvE,SAAS,qBAAqB,KAAgD;CAC5E,MAAM,aAAa,OAAO,OAAO,IAAI,CAAC,OAAO,gBAAgB;AAC7D,KAAI,WAAW,WAAW,EACxB,OAAM,IAAI,MAAM,wDAAwD;AAE1E,QAAO,WAAW;;AAGpB,SAAS,gBAAgB,OAA2C;AAClE,QACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAA2B,MAAM,QAAQ,YACjD,OAAQ,MAA2B,MAAM,YAAY"}
@@ -115,7 +115,7 @@ async function loadTranslationCatalog(path, fs) {
115
115
  return normaliseTranslationCatalog(catalogs[0]);
116
116
  }
117
117
  function isBlueprintTranslationCatalog(value) {
118
- return typeof value === "object" && value !== null && "meta" in value && typeof value.meta?.key === "string" && typeof value.meta?.version === "number" && Array.isArray(value.entries);
118
+ return typeof value === "object" && value !== null && "meta" in value && typeof value.meta?.key === "string" && typeof value.meta?.version === "string" && Array.isArray(value.entries);
119
119
  }
120
120
  function normaliseTranslationCatalog(catalog) {
121
121
  const supportedLocales = catalog.supportedLocales && catalog.supportedLocales.length > 0 ? catalog.supportedLocales : [catalog.defaultLocale];
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-validator.js","names":["context: Parameters<typeof validateTenantConfigSpecs>[2]","validateTenantConfigSpecs","results: IntegrationConnection[]"],"sources":["../../../src/services/validate/tenant-validator.ts"],"sourcesContent":["import { resolve } from 'path';\nimport { readFile } from 'fs/promises';\nimport { pathToFileURL } from 'url';\nimport {\n validateConfig as validateTenantConfigSpecs,\n type AppBlueprintSpec,\n type TenantAppConfig,\n type IntegrationSpecRegistry,\n type BlueprintTranslationCatalog,\n type IntegrationConnection,\n} from '@contractspec/lib.contracts';\nimport type { FsAdapter } from '../../ports/fs';\n\nexport interface TenantValidationResult {\n config?: TenantAppConfig;\n report?: ReturnType<typeof validateTenantConfigSpecs>;\n valid: boolean;\n errors: string[];\n}\n\nexport interface TenantValidationContext {\n connections?: string[] | string;\n integrationRegistrars?: string[] | string;\n translationCatalog?: string;\n}\n\nexport async function validateTenantConfig(\n blueprint: AppBlueprintSpec,\n tenantPath: string,\n contextOptions: TenantValidationContext,\n adapters: { fs: FsAdapter }\n): Promise<TenantValidationResult> {\n const { fs } = adapters;\n const resolvedPath = resolve(process.cwd(), tenantPath);\n\n if (!(await fs.exists(resolvedPath))) {\n return {\n valid: false,\n errors: [`Tenant config file not found: ${resolvedPath}`],\n };\n }\n\n try {\n const tenant = await loadTenantConfig(resolvedPath);\n const connections = await loadIntegrationConnections(\n contextOptions.connections,\n fs\n );\n const catalog = await loadTranslationCatalog(\n contextOptions.translationCatalog,\n fs\n );\n const integrationSpecs = await loadIntegrationRegistrars(\n contextOptions.integrationRegistrars\n );\n\n const context: Parameters<typeof validateTenantConfigSpecs>[2] = {};\n if (connections.length > 0) {\n context.tenantConnections = connections;\n }\n if (catalog) {\n context.translationCatalogs = {\n blueprint: [catalog],\n platform: [],\n };\n }\n if (integrationSpecs) {\n context.integrationSpecs = integrationSpecs;\n }\n\n const report = validateTenantConfigSpecs(blueprint, tenant, context);\n\n return {\n config: tenant,\n report,\n valid: report.valid,\n errors: report.errors.map((e) => `[${e.code}] ${e.path}: ${e.message}`),\n };\n } catch (error) {\n return {\n valid: false,\n errors: [error instanceof Error ? error.message : String(error)],\n };\n }\n}\n\n// Helpers\n\nasync function loadTenantConfig(tenantPath: string): Promise<TenantAppConfig> {\n if (tenantPath.endsWith('.json')) {\n const raw = await readFile(tenantPath, 'utf-8');\n const json = JSON.parse(raw);\n if (!isTenantConfig(json)) {\n throw new Error(\n 'Tenant config JSON does not match the expected structure (missing meta).'\n );\n }\n return json;\n }\n\n const mod = await loadModule(tenantPath);\n const candidates = Object.values(mod).filter(isTenantConfig);\n if (candidates.length === 0) {\n throw new Error('Tenant config module does not export a TenantAppConfig.');\n }\n return candidates[0] as TenantAppConfig;\n}\n\nfunction isTenantConfig(value: unknown): value is TenantAppConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as TenantAppConfig).meta?.tenantId === 'string'\n );\n}\n\n// Basic module loader\nasync function loadModule(\n modulePath: string\n): Promise<Record<string, unknown>> {\n try {\n const url = pathToFileURL(modulePath).href;\n const mod = await import(url);\n return mod;\n } catch (error) {\n throw new Error(`Failed to load module at ${modulePath}: ${error}`);\n }\n}\n\n// --- Connection Loaders ---\n\nfunction normalizePathOption(value?: string | string[]): string[] {\n if (!value) return [];\n const values = Array.isArray(value) ? value : value.split(',');\n return values.map((entry) => entry.trim()).filter(Boolean);\n}\n\nasync function loadIntegrationConnections(\n value: string | string[] | undefined,\n fs: FsAdapter\n): Promise<IntegrationConnection[]> {\n const paths = normalizePathOption(value);\n if (!paths.length) return [];\n\n const results: IntegrationConnection[] = [];\n for (const path of paths) {\n const resolved = resolve(process.cwd(), path);\n if (!(await fs.exists(resolved))) {\n console.warn(`Warning: Connection file not found: ${resolved}`);\n continue;\n }\n\n if (resolved.endsWith('.json')) {\n const raw = await readFile(resolved, 'utf-8');\n const parsed = JSON.parse(raw);\n results.push(...collectConnections(parsed));\n continue;\n }\n\n const mod = await loadModule(resolved);\n results.push(...collectConnections(mod));\n }\n return results;\n}\n\nfunction collectConnections(value: unknown): IntegrationConnection[] {\n if (Array.isArray(value)) {\n const connections = value.filter(isIntegrationConnection);\n if (connections.length) return connections;\n }\n if (isIntegrationConnection(value)) {\n return [value];\n }\n if (value && typeof value === 'object') {\n const entries = Object.values(value as Record<string, unknown>);\n const collected = entries.flatMap((entry) => collectConnections(entry));\n if (collected.length) return collected;\n }\n return [];\n}\n\nfunction isIntegrationConnection(\n value: unknown\n): value is IntegrationConnection {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as IntegrationConnection).meta?.id === 'string' &&\n typeof (value as IntegrationConnection).secretRef === 'string'\n );\n}\n\n// --- Translation Catalog Loaders ---\n\nasync function loadTranslationCatalog(\n path: string | undefined,\n fs: FsAdapter\n): Promise<BlueprintTranslationCatalog | undefined> {\n if (!path) return undefined;\n const resolved = resolve(process.cwd(), path);\n if (!(await fs.exists(resolved))) return undefined;\n\n if (resolved.endsWith('.json')) {\n const raw = await readFile(resolved, 'utf-8');\n const parsed = JSON.parse(raw);\n if (isBlueprintTranslationCatalog(parsed)) {\n return normaliseTranslationCatalog(parsed);\n }\n return undefined;\n }\n\n const mod = await loadModule(resolved);\n const catalogs = Object.values(mod).filter(isBlueprintTranslationCatalog);\n if (catalogs.length === 0) return undefined;\n return normaliseTranslationCatalog(\n catalogs[0] as BlueprintTranslationCatalog\n );\n}\n\nfunction isBlueprintTranslationCatalog(\n value: unknown\n): value is BlueprintTranslationCatalog {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as BlueprintTranslationCatalog).meta?.key === 'string' &&\n typeof (value as BlueprintTranslationCatalog).meta?.version === 'number' &&\n Array.isArray((value as BlueprintTranslationCatalog).entries)\n );\n}\n\nfunction normaliseTranslationCatalog(\n catalog: BlueprintTranslationCatalog\n): BlueprintTranslationCatalog {\n const supportedLocales =\n catalog.supportedLocales && catalog.supportedLocales.length > 0\n ? catalog.supportedLocales\n : [catalog.defaultLocale];\n return {\n ...catalog,\n supportedLocales,\n };\n}\n\n// --- Registrar Loaders ---\n// Important: This needs IntegrationSpecRegistry which is a Class.\n// We only import type in signature, but need constructor.\n// Imports fixed at top.\n\nasync function loadIntegrationRegistrars(\n value?: string | string[]\n): Promise<IntegrationSpecRegistry | undefined> {\n const entries = normalizePathOption(value);\n if (!entries.length) return undefined;\n\n // We need to import the Class dynamically or have it available.\n // It is imported from @contractspec/lib.contracts\n const { IntegrationSpecRegistry } =\n await import('@contractspec/lib.contracts');\n const registry = new IntegrationSpecRegistry();\n\n for (const entry of entries) {\n const { modulePath, exportName } = parseRegistrarEntry(entry);\n if (!modulePath) continue;\n const resolved = resolve(process.cwd(), modulePath);\n // Logic simplified for brevity, assume module exists or handled by catch in loadModule\n try {\n const mod = await loadModule(resolved);\n const registrar = pickRegistrar(mod, exportName);\n if (registrar) {\n await registrar(registry);\n }\n } catch (e) {\n console.warn(`Failed to load registrar from ${resolved}: ${e}`);\n }\n }\n return registry;\n}\n\nfunction parseRegistrarEntry(entry: string): {\n modulePath: string | null;\n exportName?: string;\n} {\n if (!entry) return { modulePath: null };\n const [modulePathRaw, exportNameRaw] = entry.split('#');\n const modulePath = modulePathRaw?.trim() ?? null;\n const exportName = exportNameRaw?.trim();\n return { modulePath, exportName };\n}\n\nfunction pickRegistrar(\n mod: Record<string, unknown>,\n exportName?: string\n): ((registry: IntegrationSpecRegistry) => void | Promise<void>) | undefined {\n if (exportName) {\n const candidate = mod[exportName];\n if (typeof candidate === 'function') {\n return candidate as (\n registry: IntegrationSpecRegistry\n ) => void | Promise<void>;\n }\n return undefined;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof (mod as any).default === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (mod as any).default;\n }\n for (const value of Object.values(mod)) {\n if (typeof value === 'function') {\n return value as (\n registry: IntegrationSpecRegistry\n ) => void | Promise<void>;\n }\n }\n return undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tenant-validator.js","names":["context: Parameters<typeof validateTenantConfigSpecs>[2]","validateTenantConfigSpecs","results: IntegrationConnection[]"],"sources":["../../../src/services/validate/tenant-validator.ts"],"sourcesContent":["import { resolve } from 'path';\nimport { readFile } from 'fs/promises';\nimport { pathToFileURL } from 'url';\nimport {\n validateConfig as validateTenantConfigSpecs,\n type AppBlueprintSpec,\n type TenantAppConfig,\n type IntegrationSpecRegistry,\n type BlueprintTranslationCatalog,\n type IntegrationConnection,\n} from '@contractspec/lib.contracts';\nimport type { FsAdapter } from '../../ports/fs';\n\nexport interface TenantValidationResult {\n config?: TenantAppConfig;\n report?: ReturnType<typeof validateTenantConfigSpecs>;\n valid: boolean;\n errors: string[];\n}\n\nexport interface TenantValidationContext {\n connections?: string[] | string;\n integrationRegistrars?: string[] | string;\n translationCatalog?: string;\n}\n\nexport async function validateTenantConfig(\n blueprint: AppBlueprintSpec,\n tenantPath: string,\n contextOptions: TenantValidationContext,\n adapters: { fs: FsAdapter }\n): Promise<TenantValidationResult> {\n const { fs } = adapters;\n const resolvedPath = resolve(process.cwd(), tenantPath);\n\n if (!(await fs.exists(resolvedPath))) {\n return {\n valid: false,\n errors: [`Tenant config file not found: ${resolvedPath}`],\n };\n }\n\n try {\n const tenant = await loadTenantConfig(resolvedPath);\n const connections = await loadIntegrationConnections(\n contextOptions.connections,\n fs\n );\n const catalog = await loadTranslationCatalog(\n contextOptions.translationCatalog,\n fs\n );\n const integrationSpecs = await loadIntegrationRegistrars(\n contextOptions.integrationRegistrars\n );\n\n const context: Parameters<typeof validateTenantConfigSpecs>[2] = {};\n if (connections.length > 0) {\n context.tenantConnections = connections;\n }\n if (catalog) {\n context.translationCatalogs = {\n blueprint: [catalog],\n platform: [],\n };\n }\n if (integrationSpecs) {\n context.integrationSpecs = integrationSpecs;\n }\n\n const report = validateTenantConfigSpecs(blueprint, tenant, context);\n\n return {\n config: tenant,\n report,\n valid: report.valid,\n errors: report.errors.map((e) => `[${e.code}] ${e.path}: ${e.message}`),\n };\n } catch (error) {\n return {\n valid: false,\n errors: [error instanceof Error ? error.message : String(error)],\n };\n }\n}\n\n// Helpers\n\nasync function loadTenantConfig(tenantPath: string): Promise<TenantAppConfig> {\n if (tenantPath.endsWith('.json')) {\n const raw = await readFile(tenantPath, 'utf-8');\n const json = JSON.parse(raw);\n if (!isTenantConfig(json)) {\n throw new Error(\n 'Tenant config JSON does not match the expected structure (missing meta).'\n );\n }\n return json;\n }\n\n const mod = await loadModule(tenantPath);\n const candidates = Object.values(mod).filter(isTenantConfig);\n if (candidates.length === 0) {\n throw new Error('Tenant config module does not export a TenantAppConfig.');\n }\n return candidates[0] as TenantAppConfig;\n}\n\nfunction isTenantConfig(value: unknown): value is TenantAppConfig {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as TenantAppConfig).meta?.tenantId === 'string'\n );\n}\n\n// Basic module loader\nasync function loadModule(\n modulePath: string\n): Promise<Record<string, unknown>> {\n try {\n const url = pathToFileURL(modulePath).href;\n const mod = await import(url);\n return mod;\n } catch (error) {\n throw new Error(`Failed to load module at ${modulePath}: ${error}`);\n }\n}\n\n// --- Connection Loaders ---\n\nfunction normalizePathOption(value?: string | string[]): string[] {\n if (!value) return [];\n const values = Array.isArray(value) ? value : value.split(',');\n return values.map((entry) => entry.trim()).filter(Boolean);\n}\n\nasync function loadIntegrationConnections(\n value: string | string[] | undefined,\n fs: FsAdapter\n): Promise<IntegrationConnection[]> {\n const paths = normalizePathOption(value);\n if (!paths.length) return [];\n\n const results: IntegrationConnection[] = [];\n for (const path of paths) {\n const resolved = resolve(process.cwd(), path);\n if (!(await fs.exists(resolved))) {\n console.warn(`Warning: Connection file not found: ${resolved}`);\n continue;\n }\n\n if (resolved.endsWith('.json')) {\n const raw = await readFile(resolved, 'utf-8');\n const parsed = JSON.parse(raw);\n results.push(...collectConnections(parsed));\n continue;\n }\n\n const mod = await loadModule(resolved);\n results.push(...collectConnections(mod));\n }\n return results;\n}\n\nfunction collectConnections(value: unknown): IntegrationConnection[] {\n if (Array.isArray(value)) {\n const connections = value.filter(isIntegrationConnection);\n if (connections.length) return connections;\n }\n if (isIntegrationConnection(value)) {\n return [value];\n }\n if (value && typeof value === 'object') {\n const entries = Object.values(value as Record<string, unknown>);\n const collected = entries.flatMap((entry) => collectConnections(entry));\n if (collected.length) return collected;\n }\n return [];\n}\n\nfunction isIntegrationConnection(\n value: unknown\n): value is IntegrationConnection {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as IntegrationConnection).meta?.id === 'string' &&\n typeof (value as IntegrationConnection).secretRef === 'string'\n );\n}\n\n// --- Translation Catalog Loaders ---\n\nasync function loadTranslationCatalog(\n path: string | undefined,\n fs: FsAdapter\n): Promise<BlueprintTranslationCatalog | undefined> {\n if (!path) return undefined;\n const resolved = resolve(process.cwd(), path);\n if (!(await fs.exists(resolved))) return undefined;\n\n if (resolved.endsWith('.json')) {\n const raw = await readFile(resolved, 'utf-8');\n const parsed = JSON.parse(raw);\n if (isBlueprintTranslationCatalog(parsed)) {\n return normaliseTranslationCatalog(parsed);\n }\n return undefined;\n }\n\n const mod = await loadModule(resolved);\n const catalogs = Object.values(mod).filter(isBlueprintTranslationCatalog);\n if (catalogs.length === 0) return undefined;\n return normaliseTranslationCatalog(\n catalogs[0] as BlueprintTranslationCatalog\n );\n}\n\nfunction isBlueprintTranslationCatalog(\n value: unknown\n): value is BlueprintTranslationCatalog {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'meta' in value &&\n typeof (value as BlueprintTranslationCatalog).meta?.key === 'string' &&\n typeof (value as BlueprintTranslationCatalog).meta?.version === 'string' &&\n Array.isArray((value as BlueprintTranslationCatalog).entries)\n );\n}\n\nfunction normaliseTranslationCatalog(\n catalog: BlueprintTranslationCatalog\n): BlueprintTranslationCatalog {\n const supportedLocales =\n catalog.supportedLocales && catalog.supportedLocales.length > 0\n ? catalog.supportedLocales\n : [catalog.defaultLocale];\n return {\n ...catalog,\n supportedLocales,\n };\n}\n\n// --- Registrar Loaders ---\n// Important: This needs IntegrationSpecRegistry which is a Class.\n// We only import type in signature, but need constructor.\n// Imports fixed at top.\n\nasync function loadIntegrationRegistrars(\n value?: string | string[]\n): Promise<IntegrationSpecRegistry | undefined> {\n const entries = normalizePathOption(value);\n if (!entries.length) return undefined;\n\n // We need to import the Class dynamically or have it available.\n // It is imported from @contractspec/lib.contracts\n const { IntegrationSpecRegistry } =\n await import('@contractspec/lib.contracts');\n const registry = new IntegrationSpecRegistry();\n\n for (const entry of entries) {\n const { modulePath, exportName } = parseRegistrarEntry(entry);\n if (!modulePath) continue;\n const resolved = resolve(process.cwd(), modulePath);\n // Logic simplified for brevity, assume module exists or handled by catch in loadModule\n try {\n const mod = await loadModule(resolved);\n const registrar = pickRegistrar(mod, exportName);\n if (registrar) {\n await registrar(registry);\n }\n } catch (e) {\n console.warn(`Failed to load registrar from ${resolved}: ${e}`);\n }\n }\n return registry;\n}\n\nfunction parseRegistrarEntry(entry: string): {\n modulePath: string | null;\n exportName?: string;\n} {\n if (!entry) return { modulePath: null };\n const [modulePathRaw, exportNameRaw] = entry.split('#');\n const modulePath = modulePathRaw?.trim() ?? null;\n const exportName = exportNameRaw?.trim();\n return { modulePath, exportName };\n}\n\nfunction pickRegistrar(\n mod: Record<string, unknown>,\n exportName?: string\n): ((registry: IntegrationSpecRegistry) => void | Promise<void>) | undefined {\n if (exportName) {\n const candidate = mod[exportName];\n if (typeof candidate === 'function') {\n return candidate as (\n registry: IntegrationSpecRegistry\n ) => void | Promise<void>;\n }\n return undefined;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof (mod as any).default === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (mod as any).default;\n }\n for (const value of Object.values(mod)) {\n if (typeof value === 'function') {\n return value as (\n registry: IntegrationSpecRegistry\n ) => void | Promise<void>;\n }\n }\n return undefined;\n}\n"],"mappings":"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"}
@@ -40,24 +40,24 @@ function buildMappingSection(prop, mappings) {
40
40
  if (mappings.length === 0) return "";
41
41
  return ` ${prop}: {\n${mappings.map((mapping) => ` ${mapping.slot}: {
42
42
  name: '${escapeString(mapping.name)}',
43
- ${typeof mapping.version === "number" ? `version: ${mapping.version},` : ""}
43
+ ${mapping.version !== void 0 ? `version: '${mapping.version}',` : ""}
44
44
  }`).join(",\n")}\n },\n`;
45
45
  }
46
46
  function buildPolicySection(data) {
47
47
  if (data.policyRefs.length === 0) return "";
48
48
  return ` policies: [\n${data.policyRefs.map((policy) => ` {
49
- name: '${escapeString(policy.name)}'${typeof policy.version === "number" ? `,\n version: ${policy.version}` : ""}
49
+ name: '${escapeString(policy.name)}'${policy.version !== void 0 ? `,\n version: '${policy.version}'` : ""}
50
50
  }`).join(",\n")}\n ],\n`;
51
51
  }
52
52
  function buildThemeSection(data) {
53
53
  if (!data.theme) return "";
54
- return ` theme: {\n${` primary: { name: '${escapeString(data.theme.name)}', version: ${data.theme.version} },\n`}${data.themeFallbacks.length > 0 ? ` fallbacks: [${data.themeFallbacks.map((theme) => `{ name: '${escapeString(theme.name)}', version: ${theme.version} }`).join(", ")}],\n` : ""} },\n`;
54
+ return ` theme: {\n${` primary: { name: '${escapeString(data.theme.name)}', version: '${data.theme.version}' },\n`}${data.themeFallbacks.length > 0 ? ` fallbacks: [${data.themeFallbacks.map((theme) => `{ name: '${escapeString(theme.name)}', version: '${theme.version}' }`).join(", ")}],\n` : ""} },\n`;
55
55
  }
56
56
  function buildTelemetrySection(data) {
57
57
  if (!data.telemetry) return "";
58
58
  return ` telemetry: {
59
59
  spec: {
60
- name: '${escapeString(data.telemetry.name)}'${typeof data.telemetry.version === "number" ? `,\n version: ${data.telemetry.version}` : ""}
60
+ name: '${escapeString(data.telemetry.name)}'${data.telemetry.version !== void 0 ? `\n version: '${data.telemetry.version}'` : ""}
61
61
  },
62
62
  },\n`;
63
63
  }
@@ -82,9 +82,9 @@ function buildRoutesSection(data) {
82
82
  route.label ? `label: '${escapeString(route.label)}'` : null,
83
83
  route.dataView ? `dataView: '${escapeString(route.dataView)}'` : null,
84
84
  route.workflow ? `workflow: '${escapeString(route.workflow)}'` : null,
85
- route.guardName ? `guard: { name: '${escapeString(route.guardName)}'${typeof route.guardVersion === "number" ? `, version: ${route.guardVersion}` : ""} }` : null,
85
+ route.guardName ? `guard: { name: '${escapeString(route.guardName)}'${route.guardVersion !== void 0 ? `, version: '${route.guardVersion}'` : ""} }` : null,
86
86
  route.featureFlag ? `featureFlag: '${escapeString(route.featureFlag)}'` : null,
87
- route.experimentName ? `experiment: { name: '${escapeString(route.experimentName)}'${typeof route.experimentVersion === "number" ? `, version: ${route.experimentVersion}` : ""} }` : null
87
+ route.experimentName ? `experiment: { name: '${escapeString(route.experimentName)}'${route.experimentVersion !== void 0 ? `, version: '${route.experimentVersion}'` : ""} }` : null
88
88
  ].filter(Boolean).join(", ")} }`;
89
89
  }).join(",\n")}\n ],\n`;
90
90
  }
@@ -92,7 +92,7 @@ function formatCapabilityRef(key) {
92
92
  return `{ key: '${escapeString(key)}' }`;
93
93
  }
94
94
  function formatExperimentRef(exp) {
95
- const version = typeof exp.version === "number" ? `, version: ${exp.version}` : "";
95
+ const version = exp.version !== void 0 ? `, version: '${exp.version}'` : "";
96
96
  return `{ name: '${escapeString(exp.name)}'${version} }`;
97
97
  }
98
98
  function toPascalCase(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"app-config.template.js","names":[],"sources":["../../src/templates/app-config.template.ts"],"sourcesContent":["import type { AppBlueprintSpecData } from '../types';\n\nexport function generateAppBlueprintSpec(data: AppBlueprintSpecData): string {\n const exportName =\n toPascalCase(data.name.split('.').pop() ?? 'App') + 'AppConfig';\n\n const capabilitiesSection = buildCapabilitiesSection(data);\n const featuresSection = buildFeaturesSection(data);\n const dataViewsSection = buildMappingSection('dataViews', data.dataViews);\n const workflowsSection = buildMappingSection('workflows', data.workflows);\n const policiesSection = buildPolicySection(data);\n const themeSection = buildThemeSection(data);\n const telemetrySection = buildTelemetrySection(data);\n const experimentsSection = buildExperimentsSection(data);\n const flagsSection = buildFeatureFlagsSection(data);\n const routesSection = buildRoutesSection(data);\n const notesSection = data.notes\n ? ` notes: '${escapeString(data.notes)}',\\n`\n : '';\n\n return `import type { AppBlueprintSpec } from '@contractspec/lib.contracts/app-config';\n\nexport const ${exportName}: AppBlueprintSpec = {\n meta: {\n key: '${escapeString(data.name)}',\n version: ${data.version},\n title: '${escapeString(data.title)}',\n description: '${escapeString(data.description)}',\n domain: '${escapeString(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],\n stability: '${data.stability}',\n appId: '${escapeString(data.appId)}',\n },\n${capabilitiesSection}${featuresSection}${dataViewsSection}${workflowsSection}${policiesSection}${themeSection}${telemetrySection}${experimentsSection}${flagsSection}${routesSection}${notesSection}};\\n`;\n}\n\nfunction buildCapabilitiesSection(data: AppBlueprintSpecData): string {\n if (\n data.capabilitiesEnabled.length === 0 &&\n data.capabilitiesDisabled.length === 0\n ) {\n return '';\n }\n const enabled =\n data.capabilitiesEnabled.length > 0\n ? ` enabled: [${data.capabilitiesEnabled\n .map((key) => formatCapabilityRef(key))\n .join(', ')}],\\n`\n : '';\n const disabled =\n data.capabilitiesDisabled.length > 0\n ? ` disabled: [${data.capabilitiesDisabled\n .map((key) => formatCapabilityRef(key))\n .join(', ')}],\\n`\n : '';\n return ` capabilities: {\\n${enabled}${disabled} },\\n`;\n}\n\nfunction buildFeaturesSection(data: AppBlueprintSpecData): string {\n if (data.featureIncludes.length === 0 && data.featureExcludes.length === 0) {\n return '';\n }\n const include =\n data.featureIncludes.length > 0\n ? ` include: [${data.featureIncludes\n .map((key) => `{ key: '${escapeString(key)}' }`)\n .join(', ')}],\\n`\n : '';\n const exclude =\n data.featureExcludes.length > 0\n ? ` exclude: [${data.featureExcludes\n .map((key) => `{ key: '${escapeString(key)}' }`)\n .join(', ')}],\\n`\n : '';\n return ` features: {\\n${include}${exclude} },\\n`;\n}\n\nfunction buildMappingSection(\n prop: 'dataViews' | 'workflows',\n mappings: AppBlueprintSpecData['dataViews']\n): string {\n if (mappings.length === 0) return '';\n const body = mappings\n .map(\n (mapping) => ` ${mapping.slot}: {\n name: '${escapeString(mapping.name)}',\n ${typeof mapping.version === 'number' ? `version: ${mapping.version},` : ''}\n }`\n )\n .join(',\\n');\n return ` ${prop}: {\\n${body}\\n },\\n`;\n}\n\nfunction buildPolicySection(data: AppBlueprintSpecData): string {\n if (data.policyRefs.length === 0) return '';\n const entries = data.policyRefs\n .map(\n (policy) => ` {\n name: '${escapeString(policy.name)}'${typeof policy.version === 'number' ? `,\\n version: ${policy.version}` : ''}\n }`\n )\n .join(',\\n');\n return ` policies: [\\n${entries}\\n ],\\n`;\n}\n\nfunction buildThemeSection(data: AppBlueprintSpecData): string {\n if (!data.theme) return '';\n const primary = ` primary: { name: '${escapeString(data.theme.name)}', version: ${data.theme.version} },\\n`;\n const fallbacks =\n data.themeFallbacks.length > 0\n ? ` fallbacks: [${data.themeFallbacks\n .map(\n (theme) =>\n `{ name: '${escapeString(theme.name)}', version: ${theme.version} }`\n )\n .join(', ')}],\\n`\n : '';\n return ` theme: {\\n${primary}${fallbacks} },\\n`;\n}\n\nfunction buildTelemetrySection(data: AppBlueprintSpecData): string {\n if (!data.telemetry) return '';\n return ` telemetry: {\n spec: {\n name: '${escapeString(data.telemetry.name)}'${\n typeof data.telemetry.version === 'number'\n ? `,\\n version: ${data.telemetry.version}`\n : ''\n }\n },\n },\\n`;\n}\n\nfunction buildExperimentsSection(data: AppBlueprintSpecData): string {\n if (\n data.activeExperiments.length === 0 &&\n data.pausedExperiments.length === 0\n ) {\n return '';\n }\n const active =\n data.activeExperiments.length > 0\n ? ` active: [${data.activeExperiments\n .map((exp) => formatExperimentRef(exp))\n .join(', ')}],\\n`\n : '';\n const paused =\n data.pausedExperiments.length > 0\n ? ` paused: [${data.pausedExperiments\n .map((exp) => formatExperimentRef(exp))\n .join(', ')}],\\n`\n : '';\n return ` experiments: {\\n${active}${paused} },\\n`;\n}\n\nfunction buildFeatureFlagsSection(data: AppBlueprintSpecData): string {\n if (data.featureFlags.length === 0) return '';\n const flags = data.featureFlags\n .map(\n (flag) => ` {\n key: '${escapeString(flag.key)}',\n enabled: ${flag.enabled},\n ${flag.variant ? `variant: '${escapeString(flag.variant)}',` : ''}\n ${flag.description ? `description: '${escapeString(flag.description)}',` : ''}\n }`\n )\n .join(',\\n');\n return ` featureFlags: [\\n${flags}\\n ],\\n`;\n}\n\nfunction buildRoutesSection(data: AppBlueprintSpecData): string {\n if (data.routes.length === 0) return '';\n const routes = data.routes\n .map((route) => {\n const entries = [\n `path: '${escapeString(route.path)}'`,\n route.label ? `label: '${escapeString(route.label)}'` : null,\n route.dataView ? `dataView: '${escapeString(route.dataView)}'` : null,\n route.workflow ? `workflow: '${escapeString(route.workflow)}'` : null,\n route.guardName\n ? `guard: { name: '${escapeString(route.guardName)}'${\n typeof route.guardVersion === 'number'\n ? `, version: ${route.guardVersion}`\n : ''\n } }`\n : null,\n route.featureFlag\n ? `featureFlag: '${escapeString(route.featureFlag)}'`\n : null,\n route.experimentName\n ? `experiment: { name: '${escapeString(route.experimentName)}'${\n typeof route.experimentVersion === 'number'\n ? `, version: ${route.experimentVersion}`\n : ''\n } }`\n : null,\n ].filter(Boolean);\n return ` { ${entries.join(', ')} }`;\n })\n .join(',\\n');\n return ` routes: [\\n${routes}\\n ],\\n`;\n}\n\nfunction formatCapabilityRef(key: string): string {\n return `{ key: '${escapeString(key)}' }`;\n}\n\nfunction formatExperimentRef(exp: { name: string; version?: number }): string {\n const version =\n typeof exp.version === 'number' ? `, version: ${exp.version}` : '';\n return `{ name: '${escapeString(exp.name)}'${version} }`;\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nfunction escapeString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-config.template.js","names":[],"sources":["../../src/templates/app-config.template.ts"],"sourcesContent":["import type { AppBlueprintSpecData } from '../types';\n\nexport function generateAppBlueprintSpec(data: AppBlueprintSpecData): string {\n const exportName =\n toPascalCase(data.name.split('.').pop() ?? 'App') + 'AppConfig';\n\n const capabilitiesSection = buildCapabilitiesSection(data);\n const featuresSection = buildFeaturesSection(data);\n const dataViewsSection = buildMappingSection('dataViews', data.dataViews);\n const workflowsSection = buildMappingSection('workflows', data.workflows);\n const policiesSection = buildPolicySection(data);\n const themeSection = buildThemeSection(data);\n const telemetrySection = buildTelemetrySection(data);\n const experimentsSection = buildExperimentsSection(data);\n const flagsSection = buildFeatureFlagsSection(data);\n const routesSection = buildRoutesSection(data);\n const notesSection = data.notes\n ? ` notes: '${escapeString(data.notes)}',\\n`\n : '';\n\n return `import type { AppBlueprintSpec } from '@contractspec/lib.contracts/app-config';\n\nexport const ${exportName}: AppBlueprintSpec = {\n meta: {\n key: '${escapeString(data.name)}',\n version: ${data.version},\n title: '${escapeString(data.title)}',\n description: '${escapeString(data.description)}',\n domain: '${escapeString(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],\n stability: '${data.stability}',\n appId: '${escapeString(data.appId)}',\n },\n${capabilitiesSection}${featuresSection}${dataViewsSection}${workflowsSection}${policiesSection}${themeSection}${telemetrySection}${experimentsSection}${flagsSection}${routesSection}${notesSection}};\\n`;\n}\n\nfunction buildCapabilitiesSection(data: AppBlueprintSpecData): string {\n if (\n data.capabilitiesEnabled.length === 0 &&\n data.capabilitiesDisabled.length === 0\n ) {\n return '';\n }\n const enabled =\n data.capabilitiesEnabled.length > 0\n ? ` enabled: [${data.capabilitiesEnabled\n .map((key) => formatCapabilityRef(key))\n .join(', ')}],\\n`\n : '';\n const disabled =\n data.capabilitiesDisabled.length > 0\n ? ` disabled: [${data.capabilitiesDisabled\n .map((key) => formatCapabilityRef(key))\n .join(', ')}],\\n`\n : '';\n return ` capabilities: {\\n${enabled}${disabled} },\\n`;\n}\n\nfunction buildFeaturesSection(data: AppBlueprintSpecData): string {\n if (data.featureIncludes.length === 0 && data.featureExcludes.length === 0) {\n return '';\n }\n const include =\n data.featureIncludes.length > 0\n ? ` include: [${data.featureIncludes\n .map((key) => `{ key: '${escapeString(key)}' }`)\n .join(', ')}],\\n`\n : '';\n const exclude =\n data.featureExcludes.length > 0\n ? ` exclude: [${data.featureExcludes\n .map((key) => `{ key: '${escapeString(key)}' }`)\n .join(', ')}],\\n`\n : '';\n return ` features: {\\n${include}${exclude} },\\n`;\n}\n\nfunction buildMappingSection(\n prop: 'dataViews' | 'workflows',\n mappings: AppBlueprintSpecData['dataViews']\n): string {\n if (mappings.length === 0) return '';\n const body = mappings\n .map(\n (mapping) => ` ${mapping.slot}: {\n name: '${escapeString(mapping.name)}',\n ${mapping.version !== undefined ? `version: '${mapping.version}',` : ''}\n }`\n )\n .join(',\\n');\n return ` ${prop}: {\\n${body}\\n },\\n`;\n}\n\nfunction buildPolicySection(data: AppBlueprintSpecData): string {\n if (data.policyRefs.length === 0) return '';\n const entries = data.policyRefs\n .map(\n (policy) => ` {\n name: '${escapeString(policy.name)}'${policy.version !== undefined ? `,\\n version: '${policy.version}'` : ''}\n }`\n )\n .join(',\\n');\n return ` policies: [\\n${entries}\\n ],\\n`;\n}\n\nfunction buildThemeSection(data: AppBlueprintSpecData): string {\n if (!data.theme) return '';\n const primary = ` primary: { name: '${escapeString(data.theme.name)}', version: '${data.theme.version}' },\\n`;\n const fallbacks =\n data.themeFallbacks.length > 0\n ? ` fallbacks: [${data.themeFallbacks\n .map(\n (theme) =>\n `{ name: '${escapeString(theme.name)}', version: '${theme.version}' }`\n )\n .join(', ')}],\\n`\n : '';\n return ` theme: {\\n${primary}${fallbacks} },\\n`;\n}\n\nfunction buildTelemetrySection(data: AppBlueprintSpecData): string {\n if (!data.telemetry) return '';\n return ` telemetry: {\n spec: {\n name: '${escapeString(data.telemetry.name)}'${\n data.telemetry.version !== undefined\n ? `\\n version: '${data.telemetry.version}'`\n : ''\n }\n },\n },\\n`;\n}\n\nfunction buildExperimentsSection(data: AppBlueprintSpecData): string {\n if (\n data.activeExperiments.length === 0 &&\n data.pausedExperiments.length === 0\n ) {\n return '';\n }\n const active =\n data.activeExperiments.length > 0\n ? ` active: [${data.activeExperiments\n .map((exp) => formatExperimentRef(exp))\n .join(', ')}],\\n`\n : '';\n const paused =\n data.pausedExperiments.length > 0\n ? ` paused: [${data.pausedExperiments\n .map((exp) => formatExperimentRef(exp))\n .join(', ')}],\\n`\n : '';\n return ` experiments: {\\n${active}${paused} },\\n`;\n}\n\nfunction buildFeatureFlagsSection(data: AppBlueprintSpecData): string {\n if (data.featureFlags.length === 0) return '';\n const flags = data.featureFlags\n .map(\n (flag) => ` {\n key: '${escapeString(flag.key)}',\n enabled: ${flag.enabled},\n ${flag.variant ? `variant: '${escapeString(flag.variant)}',` : ''}\n ${flag.description ? `description: '${escapeString(flag.description)}',` : ''}\n }`\n )\n .join(',\\n');\n return ` featureFlags: [\\n${flags}\\n ],\\n`;\n}\n\nfunction buildRoutesSection(data: AppBlueprintSpecData): string {\n if (data.routes.length === 0) return '';\n const routes = data.routes\n .map((route) => {\n const entries = [\n `path: '${escapeString(route.path)}'`,\n route.label ? `label: '${escapeString(route.label)}'` : null,\n route.dataView ? `dataView: '${escapeString(route.dataView)}'` : null,\n route.workflow ? `workflow: '${escapeString(route.workflow)}'` : null,\n route.guardName\n ? `guard: { name: '${escapeString(route.guardName)}'${\n route.guardVersion !== undefined\n ? `, version: '${route.guardVersion}'`\n : ''\n } }`\n : null,\n route.featureFlag\n ? `featureFlag: '${escapeString(route.featureFlag)}'`\n : null,\n route.experimentName\n ? `experiment: { name: '${escapeString(route.experimentName)}'${\n route.experimentVersion !== undefined\n ? `, version: '${route.experimentVersion}'`\n : ''\n } }`\n : null,\n ].filter(Boolean);\n return ` { ${entries.join(', ')} }`;\n })\n .join(',\\n');\n return ` routes: [\\n${routes}\\n ],\\n`;\n}\n\nfunction formatCapabilityRef(key: string): string {\n return `{ key: '${escapeString(key)}' }`;\n}\n\nfunction formatExperimentRef(exp: {\n name: string;\n version?: string | number;\n}): string {\n const version =\n exp.version !== undefined ? `, version: '${exp.version}'` : '';\n return `{ name: '${escapeString(exp.name)}'${version} }`;\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nfunction escapeString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":";AAEA,SAAgB,yBAAyB,MAAoC;CAC3E,MAAM,aACJ,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,MAAM,GAAG;CAEtD,MAAM,sBAAsB,yBAAyB,KAAK;CAC1D,MAAM,kBAAkB,qBAAqB,KAAK;CAClD,MAAM,mBAAmB,oBAAoB,aAAa,KAAK,UAAU;CACzE,MAAM,mBAAmB,oBAAoB,aAAa,KAAK,UAAU;CACzE,MAAM,kBAAkB,mBAAmB,KAAK;CAChD,MAAM,eAAe,kBAAkB,KAAK;CAC5C,MAAM,mBAAmB,sBAAsB,KAAK;CACpD,MAAM,qBAAqB,wBAAwB,KAAK;CACxD,MAAM,eAAe,yBAAyB,KAAK;CACnD,MAAM,gBAAgB,mBAAmB,KAAK;CAC9C,MAAM,eAAe,KAAK,QACtB,aAAa,aAAa,KAAK,MAAM,CAAC,QACtC;AAEJ,QAAO;;eAEM,WAAW;;YAEd,aAAa,KAAK,KAAK,CAAC;eACrB,KAAK,QAAQ;cACd,aAAa,KAAK,MAAM,CAAC;oBACnB,aAAa,KAAK,YAAY,CAAC;eACpC,aAAa,KAAK,OAAO,CAAC;eAC1B,KAAK,OAAO,KAAK,UAAU,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;aACpE,KAAK,KAAK,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;kBACvD,KAAK,UAAU;cACnB,aAAa,KAAK,MAAM,CAAC;;EAErC,sBAAsB,kBAAkB,mBAAmB,mBAAmB,kBAAkB,eAAe,mBAAmB,qBAAqB,eAAe,gBAAgB,aAAa;;AAGrM,SAAS,yBAAyB,MAAoC;AACpE,KACE,KAAK,oBAAoB,WAAW,KACpC,KAAK,qBAAqB,WAAW,EAErC,QAAO;AAcT,QAAO,sBAXL,KAAK,oBAAoB,SAAS,IAC9B,iBAAiB,KAAK,oBACnB,KAAK,QAAQ,oBAAoB,IAAI,CAAC,CACtC,KAAK,KAAK,CAAC,QACd,KAEJ,KAAK,qBAAqB,SAAS,IAC/B,kBAAkB,KAAK,qBACpB,KAAK,QAAQ,oBAAoB,IAAI,CAAC,CACtC,KAAK,KAAK,CAAC,QACd,GAC0C;;AAGlD,SAAS,qBAAqB,MAAoC;AAChE,KAAI,KAAK,gBAAgB,WAAW,KAAK,KAAK,gBAAgB,WAAW,EACvE,QAAO;AAcT,QAAO,kBAXL,KAAK,gBAAgB,SAAS,IAC1B,iBAAiB,KAAK,gBACnB,KAAK,QAAQ,WAAW,aAAa,IAAI,CAAC,KAAK,CAC/C,KAAK,KAAK,CAAC,QACd,KAEJ,KAAK,gBAAgB,SAAS,IAC1B,iBAAiB,KAAK,gBACnB,KAAK,QAAQ,WAAW,aAAa,IAAI,CAAC,KAAK,CAC/C,KAAK,KAAK,CAAC,QACd,GACqC;;AAG7C,SAAS,oBACP,MACA,UACQ;AACR,KAAI,SAAS,WAAW,EAAG,QAAO;AASlC,QAAO,KAAK,KAAK,OARJ,SACV,KACE,YAAY,OAAO,QAAQ,KAAK;eACxB,aAAa,QAAQ,KAAK,CAAC;QAClC,QAAQ,YAAY,SAAY,aAAa,QAAQ,QAAQ,MAAM,GAAG;OAEzE,CACA,KAAK,MAAM,CACe;;AAG/B,SAAS,mBAAmB,MAAoC;AAC9D,KAAI,KAAK,WAAW,WAAW,EAAG,QAAO;AAQzC,QAAO,kBAPS,KAAK,WAClB,KACE,WAAW;eACH,aAAa,OAAO,KAAK,CAAC,GAAG,OAAO,YAAY,SAAY,sBAAsB,OAAO,QAAQ,KAAK,GAAG;OAEnH,CACA,KAAK,MAAM,CACmB;;AAGnC,SAAS,kBAAkB,MAAoC;AAC7D,KAAI,CAAC,KAAK,MAAO,QAAO;AAWxB,QAAO,eAVS,yBAAyB,aAAa,KAAK,MAAM,KAAK,CAAC,eAAe,KAAK,MAAM,QAAQ,UAEvG,KAAK,eAAe,SAAS,IACzB,mBAAmB,KAAK,eACrB,KACE,UACC,YAAY,aAAa,MAAM,KAAK,CAAC,eAAe,MAAM,QAAQ,KACrE,CACA,KAAK,KAAK,CAAC,QACd,GACoC;;AAG5C,SAAS,sBAAsB,MAAoC;AACjE,KAAI,CAAC,KAAK,UAAW,QAAO;AAC5B,QAAO;;eAEM,aAAa,KAAK,UAAU,KAAK,CAAC,GACzC,KAAK,UAAU,YAAY,SACvB,qBAAqB,KAAK,UAAU,QAAQ,KAC5C,GACL;;;;AAKP,SAAS,wBAAwB,MAAoC;AACnE,KACE,KAAK,kBAAkB,WAAW,KAClC,KAAK,kBAAkB,WAAW,EAElC,QAAO;AAcT,QAAO,qBAXL,KAAK,kBAAkB,SAAS,IAC5B,gBAAgB,KAAK,kBAClB,KAAK,QAAQ,oBAAoB,IAAI,CAAC,CACtC,KAAK,KAAK,CAAC,QACd,KAEJ,KAAK,kBAAkB,SAAS,IAC5B,gBAAgB,KAAK,kBAClB,KAAK,QAAQ,oBAAoB,IAAI,CAAC,CACtC,KAAK,KAAK,CAAC,QACd,GACsC;;AAG9C,SAAS,yBAAyB,MAAoC;AACpE,KAAI,KAAK,aAAa,WAAW,EAAG,QAAO;AAW3C,QAAO,sBAVO,KAAK,aAChB,KACE,SAAS;cACF,aAAa,KAAK,IAAI,CAAC;iBACpB,KAAK,QAAQ;QACtB,KAAK,UAAU,aAAa,aAAa,KAAK,QAAQ,CAAC,MAAM,GAAG;QAChE,KAAK,cAAc,iBAAiB,aAAa,KAAK,YAAY,CAAC,MAAM,GAAG;OAE/E,CACA,KAAK,MAAM,CACqB;;AAGrC,SAAS,mBAAmB,MAAoC;AAC9D,KAAI,KAAK,OAAO,WAAW,EAAG,QAAO;AA6BrC,QAAO,gBA5BQ,KAAK,OACjB,KAAK,UAAU;AAwBd,SAAO,SAvBS;GACd,UAAU,aAAa,MAAM,KAAK,CAAC;GACnC,MAAM,QAAQ,WAAW,aAAa,MAAM,MAAM,CAAC,KAAK;GACxD,MAAM,WAAW,cAAc,aAAa,MAAM,SAAS,CAAC,KAAK;GACjE,MAAM,WAAW,cAAc,aAAa,MAAM,SAAS,CAAC,KAAK;GACjE,MAAM,YACF,mBAAmB,aAAa,MAAM,UAAU,CAAC,GAC/C,MAAM,iBAAiB,SACnB,eAAe,MAAM,aAAa,KAClC,GACL,MACD;GACJ,MAAM,cACF,iBAAiB,aAAa,MAAM,YAAY,CAAC,KACjD;GACJ,MAAM,iBACF,wBAAwB,aAAa,MAAM,eAAe,CAAC,GACzD,MAAM,sBAAsB,SACxB,eAAe,MAAM,kBAAkB,KACvC,GACL,MACD;GACL,CAAC,OAAO,QAAQ,CACO,KAAK,KAAK,CAAC;GACnC,CACD,KAAK,MAAM,CACgB;;AAGhC,SAAS,oBAAoB,KAAqB;AAChD,QAAO,WAAW,aAAa,IAAI,CAAC;;AAGtC,SAAS,oBAAoB,KAGlB;CACT,MAAM,UACJ,IAAI,YAAY,SAAY,eAAe,IAAI,QAAQ,KAAK;AAC9D,QAAO,YAAY,aAAa,IAAI,KAAK,CAAC,GAAG,QAAQ;;AAGvD,SAAS,aAAa,OAAuB;AAC3C,QAAO,MACJ,MAAM,QAAQ,CACd,OAAO,QAAQ,CACf,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;AAGb,SAAS,aAAa,OAAuB;AAC3C,QAAO,MAAM,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,MAAM"}
@@ -6,7 +6,7 @@ function generateExperimentSpec(data) {
6
6
  ${variant.overrides.map((override) => ` {
7
7
  type: '${override.type}',
8
8
  target: '${escapeString(override.target)}',
9
- ${typeof override.version === "number" ? `version: ${override.version},` : ""}
9
+ ${typeof override.version === "string" ? `version: ${override.version},` : ""}
10
10
  }`).join(",\n")}
11
11
  ],` : "";
12
12
  return ` {
@@ -21,7 +21,7 @@ ${overrides}
21
21
  const metrics = data.successMetrics?.length ? ` successMetrics: [
22
22
  ${data.successMetrics.map((metric) => ` {
23
23
  name: '${escapeString(metric.name)}',
24
- telemetryEvent: { name: '${escapeString(metric.eventName)}', version: ${metric.eventVersion} },
24
+ telemetryEvent: { name: '${escapeString(metric.eventName)}', version: ${typeof metric.eventVersion === "string" ? `'${metric.eventVersion}'` : metric.eventVersion} },
25
25
  aggregation: '${metric.aggregation}',
26
26
  ${typeof metric.target === "number" ? `target: ${metric.target},` : ""}
27
27
  }`).join(",\n")}
@@ -31,7 +31,7 @@ ${data.successMetrics.map((metric) => ` {
31
31
  export const ${specVar}: ExperimentSpec = {
32
32
  meta: {
33
33
  key: '${escapeString(data.name)}',
34
- version: ${data.version},
34
+ version: ${typeof data.version === "string" ? `'${data.version}'` : data.version},
35
35
  title: '${escapeString(data.name)} experiment',
36
36
  description: '${escapeString(data.description || "Describe the experiment goal.")}',
37
37
  domain: '${escapeString(data.domain)}',
@@ -65,7 +65,7 @@ function renderAllocation(allocation) {
65
65
  ${allocation.rules.map((rule) => ` {
66
66
  variantId: '${escapeString(rule.variantId)}',
67
67
  ${typeof rule.percentage === "number" ? `percentage: ${rule.percentage},` : ""}
68
- ${rule.policy ? `policy: { name: '${escapeString(rule.policy.name)}'${typeof rule.policy.version === "number" ? `, version: ${rule.policy.version}` : ""} },` : ""}
68
+ ${rule.policy ? `policy: { name: '${escapeString(rule.policy.name)}'${rule.policy.version !== void 0 ? `, version: ${typeof rule.policy.version === "string" ? `'${rule.policy.version}'` : rule.policy.version}` : ""} },` : ""}
69
69
  ${rule.expression ? `expression: '${escapeString(rule.expression)}',` : ""}
70
70
  }`).join(",\n")}
71
71
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"experiment.template.js","names":[],"sources":["../../src/templates/experiment.template.ts"],"sourcesContent":["import type { ExperimentSpecData } from '../types';\n\nexport function generateExperimentSpec(data: ExperimentSpecData): string {\n const specVar =\n toPascalCase(data.name.split('.').pop() ?? 'Experiment') + 'Experiment';\n\n const variants = data.variants\n .map((variant) => {\n const overrides = variant.overrides?.length\n ? ` overrides: [\n${variant.overrides\n .map(\n (override) => ` {\n type: '${override.type}',\n target: '${escapeString(override.target)}',\n ${typeof override.version === 'number' ? `version: ${override.version},` : ''}\n }`\n )\n .join(',\\n')}\n ],`\n : '';\n return ` {\n id: '${escapeString(variant.id)}',\n name: '${escapeString(variant.name)}',\n ${variant.description ? `description: '${escapeString(variant.description)}',` : ''}\n ${typeof variant.weight === 'number' ? `weight: ${variant.weight},` : ''}\n${overrides}\n }`;\n })\n .join(',\\n');\n\n const allocation = renderAllocation(data.allocation);\n\n const metrics = data.successMetrics?.length\n ? ` successMetrics: [\n${data.successMetrics\n .map(\n (metric) => ` {\n name: '${escapeString(metric.name)}',\n telemetryEvent: { name: '${escapeString(metric.eventName)}', version: ${metric.eventVersion} },\n aggregation: '${metric.aggregation}',\n ${typeof metric.target === 'number' ? `target: ${metric.target},` : ''}\n }`\n )\n .join(',\\n')}\n ],`\n : '';\n\n return `import type { ExperimentSpec } from '@contractspec/lib.contracts/experiments';\n\nexport const ${specVar}: ExperimentSpec = {\n meta: {\n key: '${escapeString(data.name)}',\n version: ${data.version},\n title: '${escapeString(data.name)} experiment',\n description: '${escapeString(\n data.description || 'Describe the experiment goal.'\n )}',\n domain: '${escapeString(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],\n stability: '${data.stability}',\n },\n controlVariant: '${escapeString(data.controlVariant)}',\n variants: [\n${variants}\n ],\n allocation: ${allocation},\n${metrics}\n};\n`;\n}\n\nfunction renderAllocation(\n allocation: ExperimentSpecData['allocation']\n): string {\n switch (allocation.type) {\n case 'random':\n return `{\n type: 'random',\n ${allocation.salt ? `salt: '${escapeString(allocation.salt)}',` : ''}\n }`;\n case 'sticky':\n return `{\n type: 'sticky',\n attribute: '${allocation.attribute}',\n ${allocation.salt ? `salt: '${escapeString(allocation.salt)}',` : ''}\n }`;\n case 'targeted':\n return `{\n type: 'targeted',\n rules: [\n${allocation.rules\n .map(\n (rule) => ` {\n variantId: '${escapeString(rule.variantId)}',\n ${typeof rule.percentage === 'number' ? `percentage: ${rule.percentage},` : ''}\n ${\n rule.policy\n ? `policy: { name: '${escapeString(rule.policy.name)}'${typeof rule.policy.version === 'number' ? `, version: ${rule.policy.version}` : ''} },`\n : ''\n }\n ${rule.expression ? `expression: '${escapeString(rule.expression)}',` : ''}\n }`\n )\n .join(',\\n')}\n ],\n fallback: '${allocation.fallback ?? 'control'}',\n }`;\n default:\n return renderUnsupportedAllocation(allocation);\n }\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nfunction escapeString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction renderUnsupportedAllocation(allocation: never): string {\n throw new Error(\n `Unsupported allocation type ${allocation as unknown as string}`\n );\n}\n"],"mappings":";AAEA,SAAgB,uBAAuB,MAAkC;CACvE,MAAM,UACJ,aAAa,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI,aAAa,GAAG;CAE7D,MAAM,WAAW,KAAK,SACnB,KAAK,YAAY;EAChB,MAAM,YAAY,QAAQ,WAAW,SACjC;EACR,QAAQ,UACP,KACE,aAAa;mBACC,SAAS,KAAK;qBACZ,aAAa,SAAS,OAAO,CAAC;YACvC,OAAO,SAAS,YAAY,WAAW,YAAY,SAAS,QAAQ,KAAK,GAAG;WAErF,CACA,KAAK,MAAM,CAAC;YAEL;AACJ,SAAO;aACA,aAAa,QAAQ,GAAG,CAAC;eACvB,aAAa,QAAQ,KAAK,CAAC;QAClC,QAAQ,cAAc,iBAAiB,aAAa,QAAQ,YAAY,CAAC,MAAM,GAAG;QAClF,OAAO,QAAQ,WAAW,WAAW,WAAW,QAAQ,OAAO,KAAK,GAAG;EAC7E,UAAU;;GAEN,CACD,KAAK,MAAM;CAEd,MAAM,aAAa,iBAAiB,KAAK,WAAW;CAEpD,MAAM,UAAU,KAAK,gBAAgB,SACjC;EACJ,KAAK,eACJ,KACE,WAAW;eACD,aAAa,OAAO,KAAK,CAAC;iCACR,aAAa,OAAO,UAAU,CAAC,cAAc,OAAO,aAAa;sBAC5E,OAAO,YAAY;QACjC,OAAO,OAAO,WAAW,WAAW,WAAW,OAAO,OAAO,KAAK,GAAG;OAE1E,CACA,KAAK,MAAM,CAAC;QAET;AAEJ,QAAO;;eAEM,QAAQ;;YAEX,aAAa,KAAK,KAAK,CAAC;eACrB,KAAK,QAAQ;cACd,aAAa,KAAK,KAAK,CAAC;oBAClB,aACd,KAAK,eAAe,gCACrB,CAAC;eACS,aAAa,KAAK,OAAO,CAAC;eAC1B,KAAK,OAAO,KAAK,UAAU,IAAI,aAAa,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;aACpE,KAAK,KAAK,KAAK,QAAQ,IAAI,aAAa,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC;kBACvD,KAAK,UAAU;;qBAEZ,aAAa,KAAK,eAAe,CAAC;;EAErD,SAAS;;gBAEK,WAAW;EACzB,QAAQ;;;;AAKV,SAAS,iBACP,YACQ;AACR,SAAQ,WAAW,MAAnB;EACE,KAAK,SACH,QAAO;;MAEP,WAAW,OAAO,UAAU,aAAa,WAAW,KAAK,CAAC,MAAM,GAAG;;EAErE,KAAK,SACH,QAAO;;kBAEK,WAAW,UAAU;MACjC,WAAW,OAAO,UAAU,aAAa,WAAW,KAAK,CAAC,MAAM,GAAG;;EAErE,KAAK,WACH,QAAO;;;EAGX,WAAW,MACV,KACE,SAAS;sBACQ,aAAa,KAAK,UAAU,CAAC;UACzC,OAAO,KAAK,eAAe,WAAW,eAAe,KAAK,WAAW,KAAK,GAAG;UAE7E,KAAK,SACD,oBAAoB,aAAa,KAAK,OAAO,KAAK,CAAC,GAAG,OAAO,KAAK,OAAO,YAAY,WAAW,cAAc,KAAK,OAAO,YAAY,GAAG,OACzI,GACL;UACC,KAAK,aAAa,gBAAgB,aAAa,KAAK,WAAW,CAAC,MAAM,GAAG;SAEhF,CACA,KAAK,MAAM,CAAC;;iBAEE,WAAW,YAAY,UAAU;;EAE9C,QACE,QAAO,4BAA4B,WAAW;;;AAIpD,SAAS,aAAa,OAAuB;AAC3C,QAAO,MACJ,MAAM,QAAQ,CACd,OAAO,QAAQ,CACf,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG;;AAGb,SAAS,aAAa,OAAuB;AAC3C,QAAO,MAAM,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,MAAM;;AAG1D,SAAS,4BAA4B,YAA2B;AAC9D,OAAM,IAAI,MACR,+BAA+B,aAChC"}
1
+ {"version":3,"file":"experiment.template.js","names":[],"sources":["../../src/templates/experiment.template.ts"],"sourcesContent":["import type { ExperimentSpecData } from '../types';\n\nexport function generateExperimentSpec(data: ExperimentSpecData): string {\n const specVar =\n toPascalCase(data.name.split('.').pop() ?? 'Experiment') + 'Experiment';\n\n const variants = data.variants\n .map((variant) => {\n const overrides = variant.overrides?.length\n ? ` overrides: [\n${variant.overrides\n .map(\n (override) => ` {\n type: '${override.type}',\n target: '${escapeString(override.target)}',\n ${typeof override.version === 'string' ? `version: ${override.version},` : ''}\n }`\n )\n .join(',\\n')}\n ],`\n : '';\n return ` {\n id: '${escapeString(variant.id)}',\n name: '${escapeString(variant.name)}',\n ${variant.description ? `description: '${escapeString(variant.description)}',` : ''}\n ${typeof variant.weight === 'number' ? `weight: ${variant.weight},` : ''}\n${overrides}\n }`;\n })\n .join(',\\n');\n\n const allocation = renderAllocation(data.allocation);\n\n const metrics = data.successMetrics?.length\n ? ` successMetrics: [\n${data.successMetrics\n .map(\n (metric) => ` {\n name: '${escapeString(metric.name)}',\n telemetryEvent: { name: '${escapeString(metric.eventName)}', version: ${typeof metric.eventVersion === 'string' ? `'${metric.eventVersion}'` : metric.eventVersion} },\n aggregation: '${metric.aggregation}',\n ${typeof metric.target === 'number' ? `target: ${metric.target},` : ''}\n }`\n )\n .join(',\\n')}\n ],`\n : '';\n\n return `import type { ExperimentSpec } from '@contractspec/lib.contracts/experiments';\n\nexport const ${specVar}: ExperimentSpec = {\n meta: {\n key: '${escapeString(data.name)}',\n version: ${typeof data.version === 'string' ? `'${data.version}'` : data.version},\n title: '${escapeString(data.name)} experiment',\n description: '${escapeString(\n data.description || 'Describe the experiment goal.'\n )}',\n domain: '${escapeString(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escapeString(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escapeString(tag)}'`).join(', ')}],\n stability: '${data.stability}',\n },\n controlVariant: '${escapeString(data.controlVariant)}',\n variants: [\n${variants}\n ],\n allocation: ${allocation},\n${metrics}\n};\n`;\n}\n\nfunction renderAllocation(\n allocation: ExperimentSpecData['allocation']\n): string {\n switch (allocation.type) {\n case 'random':\n return `{\n type: 'random',\n ${allocation.salt ? `salt: '${escapeString(allocation.salt)}',` : ''}\n }`;\n case 'sticky':\n return `{\n type: 'sticky',\n attribute: '${allocation.attribute}',\n ${allocation.salt ? `salt: '${escapeString(allocation.salt)}',` : ''}\n }`;\n case 'targeted':\n return `{\n type: 'targeted',\n rules: [\n${allocation.rules\n .map(\n (rule) => ` {\n variantId: '${escapeString(rule.variantId)}',\n ${typeof rule.percentage === 'number' ? `percentage: ${rule.percentage},` : ''}\n ${\n rule.policy\n ? `policy: { name: '${escapeString(rule.policy.name)}'${rule.policy.version !== undefined ? `, version: ${typeof rule.policy.version === 'string' ? `'${rule.policy.version}'` : rule.policy.version}` : ''} },`\n : ''\n }\n ${rule.expression ? `expression: '${escapeString(rule.expression)}',` : ''}\n }`\n )\n .join(',\\n')}\n ],\n fallback: '${allocation.fallback ?? 'control'}',\n }`;\n default:\n return renderUnsupportedAllocation(allocation);\n }\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nfunction escapeString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nfunction renderUnsupportedAllocation(allocation: never): string {\n throw new Error(\n `Unsupported allocation type ${allocation as unknown as string}`\n );\n}\n"],"mappings":"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"}
@@ -5,10 +5,10 @@ function generateIntegrationSpec(data) {
5
5
  const registerFn = `register${specName}Integration`;
6
6
  const supportedModes = data.supportedModes.length ? data.supportedModes : ["managed"];
7
7
  const supportedModesLine = supportedModes.map((mode) => `'${mode}'`).join(", ");
8
- const provides = data.capabilitiesProvided.map((cap) => ` { key: '${cap.key}', version: ${cap.version} }`).join(",\n");
8
+ const provides = data.capabilitiesProvided.map((cap) => ` { key: '${cap.key}', version: '${cap.version}' }`).join(",\n");
9
9
  const requires = data.capabilitiesRequired.length > 0 ? ` requires: [
10
10
  ${data.capabilitiesRequired.map((req) => {
11
- const version = typeof req.version === "number" ? `, version: ${req.version}` : "";
11
+ const version = req.version !== void 0 ? `, version: '${req.version}'` : "";
12
12
  const optional = req.optional ? ", optional: true" : "";
13
13
  const reason = req.reason ? `, reason: '${escape(req.reason)}'` : "";
14
14
  return ` { key: '${req.key}'${version}${optional}${reason} }`;
@@ -28,7 +28,7 @@ import type { IntegrationSpecRegistry } from '@contractspec/lib.contracts/integr
28
28
  export const ${varName}: IntegrationSpec = {
29
29
  meta: {
30
30
  key: '${data.name}',
31
- version: ${data.version},
31
+ version: ${typeof data.version === "string" ? `'${data.version}'` : data.version},
32
32
  category: '${data.category}',
33
33
  displayName: '${escape(data.displayName)}',
34
34
  title: '${escape(data.title)}',
@@ -1 +1 @@
1
- {"version":3,"file":"integration.template.js","names":["entries: string[]"],"sources":["../../src/templates/integration.template.ts"],"sourcesContent":["import type {\n IntegrationConfigFieldData,\n IntegrationSecretFieldData,\n IntegrationSpecData,\n Stability,\n} from '../types';\n\nexport function generateIntegrationSpec(data: IntegrationSpecData): string {\n const specName = toPascalCase(data.name.split('.').pop() ?? 'Integration');\n const varName = `${specName}IntegrationSpec`;\n const registerFn = `register${specName}Integration`;\n\n const supportedModes = data.supportedModes.length\n ? data.supportedModes\n : ['managed'];\n const supportedModesLine = supportedModes\n .map((mode) => `'${mode}'`)\n .join(', ');\n\n const provides = data.capabilitiesProvided\n .map((cap) => ` { key: '${cap.key}', version: ${cap.version} }`)\n .join(',\\n');\n\n const requires =\n data.capabilitiesRequired.length > 0\n ? ` requires: [\n${data.capabilitiesRequired\n .map((req) => {\n const version =\n typeof req.version === 'number' ? `, version: ${req.version}` : '';\n const optional = req.optional ? ', optional: true' : '';\n const reason = req.reason ? `, reason: '${escape(req.reason)}'` : '';\n return ` { key: '${req.key}'${version}${optional}${reason} }`;\n })\n .join(',\\n')}\n ],`\n : '';\n\n const configSchema = renderConfigSchema(data.configFields);\n const configExample = renderConfigExample(data.configFields);\n const secretSchema = renderSecretSchema(data.secretFields);\n const secretExample = renderSecretExample(data.secretFields);\n const docsUrl = data.docsUrl ? ` docsUrl: '${escape(data.docsUrl)}',\\n` : '';\n const constraints = renderConstraints(data.rateLimitRpm, data.rateLimitRph);\n const byokSetup = renderByokSetup(\n supportedModes,\n data.byokSetupInstructions,\n data.byokRequiredScopes\n );\n\n return `import { StabilityEnum } from '@contractspec/lib.contracts/ownership';\nimport type { IntegrationSpec } from '@contractspec/lib.contracts/integrations/spec';\nimport type { IntegrationSpecRegistry } from '@contractspec/lib.contracts/integrations/spec';\n\nexport const ${varName}: IntegrationSpec = {\n meta: {\n key: '${data.name}',\n version: ${data.version},\n category: '${data.category}',\n displayName: '${escape(data.displayName)}',\n title: '${escape(data.title)}',\n description: '${escape(data.description)}',\n domain: '${escape(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escape(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escape(tag)}'`).join(', ')}],\n stability: StabilityEnum.${stabilityToEnum(data.stability)},\n },\n supportedModes: [${supportedModesLine}],\n capabilities: {\n provides: [\n${provides}\n ],\n${requires.length > 0 ? `${requires}\\n` : ''} },\n configSchema: {\n${configSchema}\n example: ${configExample},\n },\n secretSchema: {\n${secretSchema}\n example: ${secretExample},\n },\n${docsUrl}${constraints}${byokSetup} healthCheck: {\n method: '${data.healthCheckMethod}',\n timeoutMs: ${data.healthCheckTimeoutMs},\n },\n};\n\nexport function ${registerFn}(\n registry: IntegrationSpecRegistry\n): IntegrationSpecRegistry {\n return registry.register(${varName});\n}\n`;\n}\n\nfunction renderConfigSchema(fields: IntegrationConfigFieldData[]): string {\n const requiredFields = fields.filter((field) => field.required);\n const requiredBlock =\n requiredFields.length > 0\n ? ` required: [${requiredFields\n .map((field) => `'${field.key}'`)\n .join(', ')}],\n`\n : '';\n\n const properties = fields.length\n ? fields\n .map((field) => {\n const description = field.description\n ? `, description: '${escape(field.description)}'`\n : '';\n return ` ${field.key}: { type: '${mapConfigType(\n field.type\n )}'${description} }`;\n })\n .join(',\\n')\n : '';\n\n return ` schema: {\n type: 'object',\n${requiredBlock} properties: {\n${properties || ' '}\n },\n },\\n`;\n}\n\nfunction renderSecretSchema(fields: IntegrationSecretFieldData[]): string {\n const requiredFields = fields.filter((field) => field.required);\n const requiredBlock =\n requiredFields.length > 0\n ? ` required: [${requiredFields\n .map((field) => `'${field.key}'`)\n .join(', ')}],\n`\n : '';\n\n const properties = fields.length\n ? fields\n .map((field) => {\n const description = field.description\n ? `, description: '${escape(field.description)}'`\n : '';\n return ` ${field.key}: { type: 'string'${description} }`;\n })\n .join(',\\n')\n : '';\n\n return ` schema: {\n type: 'object',\n${requiredBlock} properties: {\n${properties || ' '}\n },\n },\\n`;\n}\n\nfunction renderConfigExample(fields: IntegrationConfigFieldData[]): string {\n if (fields.length === 0) {\n return `{}`;\n }\n\n const exampleEntries = fields.map((field) => {\n switch (field.type) {\n case 'number':\n return ` ${field.key}: 0`;\n case 'boolean':\n return ` ${field.key}: true`;\n case 'string':\n default:\n return ` ${field.key}: '${field.key.toUpperCase()}_VALUE'`;\n }\n });\n\n return `{\n${exampleEntries.join(',\\n')}\n }`;\n}\n\nfunction renderSecretExample(fields: IntegrationSecretFieldData[]): string {\n if (fields.length === 0) {\n return `{}`;\n }\n\n const exampleEntries = fields.map(\n (field) => ` ${field.key}: '${field.key.toUpperCase()}_SECRET'`\n );\n\n return `{\n${exampleEntries.join(',\\n')}\n }`;\n}\n\nfunction renderConstraints(rpm?: number, rph?: number): string {\n if (rpm == null && rph == null) return '';\n const entries: string[] = [];\n if (rpm != null) entries.push(` rpm: ${rpm}`);\n if (rph != null) entries.push(` rph: ${rph}`);\n return ` constraints: {\n rateLimit: {\n${entries.join(',\\n')}\n },\n },\n`;\n}\n\nfunction renderByokSetup(\n modes: string[],\n instructions?: string,\n scopes?: string[]\n): string {\n if (!modes.includes('byok')) {\n return '';\n }\n\n const instructionsLine = instructions\n ? ` setupInstructions: '${escape(instructions)}',\\n`\n : '';\n const scopesLine =\n scopes && scopes.length\n ? ` requiredScopes: [${scopes\n .map((scope) => `'${escape(scope)}'`)\n .join(', ')}],\\n`\n : '';\n\n if (!instructionsLine && !scopesLine) {\n return '';\n }\n\n return ` byokSetup: {\n${instructionsLine}${scopesLine} },\n`;\n}\n\nfunction mapConfigType(type: IntegrationConfigFieldData['type']): string {\n switch (type) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'string':\n default:\n return 'string';\n }\n}\n\nfunction stabilityToEnum(stability: Stability): string {\n switch (stability) {\n case 'beta':\n return 'Beta';\n case 'stable':\n return 'Stable';\n case 'deprecated':\n return 'Deprecated';\n case 'experimental':\n default:\n return 'Experimental';\n }\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nfunction escape(value: string): string {\n return value.replace(/`/g, '\\\\`').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"integration.template.js","names":["entries: string[]"],"sources":["../../src/templates/integration.template.ts"],"sourcesContent":["import type {\n IntegrationConfigFieldData,\n IntegrationSecretFieldData,\n IntegrationSpecData,\n Stability,\n} from '../types';\n\nexport function generateIntegrationSpec(data: IntegrationSpecData): string {\n const specName = toPascalCase(data.name.split('.').pop() ?? 'Integration');\n const varName = `${specName}IntegrationSpec`;\n const registerFn = `register${specName}Integration`;\n\n const supportedModes = data.supportedModes.length\n ? data.supportedModes\n : ['managed'];\n const supportedModesLine = supportedModes\n .map((mode) => `'${mode}'`)\n .join(', ');\n\n const provides = data.capabilitiesProvided\n .map((cap) => ` { key: '${cap.key}', version: '${cap.version}' }`)\n .join(',\\n');\n\n const requires =\n data.capabilitiesRequired.length > 0\n ? ` requires: [\n${data.capabilitiesRequired\n .map((req) => {\n const version =\n req.version !== undefined ? `, version: '${req.version}'` : '';\n const optional = req.optional ? ', optional: true' : '';\n const reason = req.reason ? `, reason: '${escape(req.reason)}'` : '';\n return ` { key: '${req.key}'${version}${optional}${reason} }`;\n })\n .join(',\\n')}\n ],`\n : '';\n\n const configSchema = renderConfigSchema(data.configFields);\n const configExample = renderConfigExample(data.configFields);\n const secretSchema = renderSecretSchema(data.secretFields);\n const secretExample = renderSecretExample(data.secretFields);\n const docsUrl = data.docsUrl ? ` docsUrl: '${escape(data.docsUrl)}',\\n` : '';\n const constraints = renderConstraints(data.rateLimitRpm, data.rateLimitRph);\n const byokSetup = renderByokSetup(\n supportedModes,\n data.byokSetupInstructions,\n data.byokRequiredScopes\n );\n\n return `import { StabilityEnum } from '@contractspec/lib.contracts/ownership';\nimport type { IntegrationSpec } from '@contractspec/lib.contracts/integrations/spec';\nimport type { IntegrationSpecRegistry } from '@contractspec/lib.contracts/integrations/spec';\n\nexport const ${varName}: IntegrationSpec = {\n meta: {\n key: '${data.name}',\n version: ${typeof data.version === 'string' ? `'${data.version}'` : data.version},\n category: '${data.category}',\n displayName: '${escape(data.displayName)}',\n title: '${escape(data.title)}',\n description: '${escape(data.description)}',\n domain: '${escape(data.domain)}',\n owners: [${data.owners.map((owner) => `'${escape(owner)}'`).join(', ')}],\n tags: [${data.tags.map((tag) => `'${escape(tag)}'`).join(', ')}],\n stability: StabilityEnum.${stabilityToEnum(data.stability)},\n },\n supportedModes: [${supportedModesLine}],\n capabilities: {\n provides: [\n${provides}\n ],\n${requires.length > 0 ? `${requires}\\n` : ''} },\n configSchema: {\n${configSchema}\n example: ${configExample},\n },\n secretSchema: {\n${secretSchema}\n example: ${secretExample},\n },\n${docsUrl}${constraints}${byokSetup} healthCheck: {\n method: '${data.healthCheckMethod}',\n timeoutMs: ${data.healthCheckTimeoutMs},\n },\n};\n\nexport function ${registerFn}(\n registry: IntegrationSpecRegistry\n): IntegrationSpecRegistry {\n return registry.register(${varName});\n}\n`;\n}\n\nfunction renderConfigSchema(fields: IntegrationConfigFieldData[]): string {\n const requiredFields = fields.filter((field) => field.required);\n const requiredBlock =\n requiredFields.length > 0\n ? ` required: [${requiredFields\n .map((field) => `'${field.key}'`)\n .join(', ')}],\n`\n : '';\n\n const properties = fields.length\n ? fields\n .map((field) => {\n const description = field.description\n ? `, description: '${escape(field.description)}'`\n : '';\n return ` ${field.key}: { type: '${mapConfigType(\n field.type\n )}'${description} }`;\n })\n .join(',\\n')\n : '';\n\n return ` schema: {\n type: 'object',\n${requiredBlock} properties: {\n${properties || ' '}\n },\n },\\n`;\n}\n\nfunction renderSecretSchema(fields: IntegrationSecretFieldData[]): string {\n const requiredFields = fields.filter((field) => field.required);\n const requiredBlock =\n requiredFields.length > 0\n ? ` required: [${requiredFields\n .map((field) => `'${field.key}'`)\n .join(', ')}],\n`\n : '';\n\n const properties = fields.length\n ? fields\n .map((field) => {\n const description = field.description\n ? `, description: '${escape(field.description)}'`\n : '';\n return ` ${field.key}: { type: 'string'${description} }`;\n })\n .join(',\\n')\n : '';\n\n return ` schema: {\n type: 'object',\n${requiredBlock} properties: {\n${properties || ' '}\n },\n },\\n`;\n}\n\nfunction renderConfigExample(fields: IntegrationConfigFieldData[]): string {\n if (fields.length === 0) {\n return `{}`;\n }\n\n const exampleEntries = fields.map((field) => {\n switch (field.type) {\n case 'number':\n return ` ${field.key}: 0`;\n case 'boolean':\n return ` ${field.key}: true`;\n case 'string':\n default:\n return ` ${field.key}: '${field.key.toUpperCase()}_VALUE'`;\n }\n });\n\n return `{\n${exampleEntries.join(',\\n')}\n }`;\n}\n\nfunction renderSecretExample(fields: IntegrationSecretFieldData[]): string {\n if (fields.length === 0) {\n return `{}`;\n }\n\n const exampleEntries = fields.map(\n (field) => ` ${field.key}: '${field.key.toUpperCase()}_SECRET'`\n );\n\n return `{\n${exampleEntries.join(',\\n')}\n }`;\n}\n\nfunction renderConstraints(rpm?: number, rph?: number): string {\n if (rpm == null && rph == null) return '';\n const entries: string[] = [];\n if (rpm != null) entries.push(` rpm: ${rpm}`);\n if (rph != null) entries.push(` rph: ${rph}`);\n return ` constraints: {\n rateLimit: {\n${entries.join(',\\n')}\n },\n },\n`;\n}\n\nfunction renderByokSetup(\n modes: string[],\n instructions?: string,\n scopes?: string[]\n): string {\n if (!modes.includes('byok')) {\n return '';\n }\n\n const instructionsLine = instructions\n ? ` setupInstructions: '${escape(instructions)}',\\n`\n : '';\n const scopesLine =\n scopes && scopes.length\n ? ` requiredScopes: [${scopes\n .map((scope) => `'${escape(scope)}'`)\n .join(', ')}],\\n`\n : '';\n\n if (!instructionsLine && !scopesLine) {\n return '';\n }\n\n return ` byokSetup: {\n${instructionsLine}${scopesLine} },\n`;\n}\n\nfunction mapConfigType(type: IntegrationConfigFieldData['type']): string {\n switch (type) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'string':\n default:\n return 'string';\n }\n}\n\nfunction stabilityToEnum(stability: Stability): string {\n switch (stability) {\n case 'beta':\n return 'Beta';\n case 'stable':\n return 'Stable';\n case 'deprecated':\n return 'Deprecated';\n case 'experimental':\n default:\n return 'Experimental';\n }\n}\n\nfunction toPascalCase(value: string): string {\n return value\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n\nfunction escape(value: string): string {\n return value.replace(/`/g, '\\\\`').replace(/'/g, \"\\\\'\");\n}\n"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -34,11 +34,11 @@ interface WorkflowStepData {
34
34
  description?: string;
35
35
  operation?: {
36
36
  name: string;
37
- version: number;
37
+ version: string;
38
38
  };
39
39
  form?: {
40
40
  key: string;
41
- version: number;
41
+ version: string;
42
42
  };
43
43
  }
44
44
  interface WorkflowTransitionData {
@@ -70,11 +70,11 @@ interface DataViewSpecData extends BaseSpecData {
70
70
  kind: DataViewKind;
71
71
  primaryOperation: {
72
72
  name: string;
73
- version: number;
73
+ version: string;
74
74
  };
75
75
  itemOperation?: {
76
76
  name: string;
77
- version: number;
77
+ version: string;
78
78
  };
79
79
  fields: DataViewFieldData[];
80
80
  primaryField?: string;
@@ -96,7 +96,7 @@ interface TelemetryAnomalyRuleData {
96
96
  }
97
97
  interface TelemetryEventData {
98
98
  name: string;
99
- version: number;
99
+ version: string;
100
100
  what: string;
101
101
  who?: string;
102
102
  why?: string;
@@ -128,7 +128,7 @@ interface TelemetrySpecData extends BaseSpecData {
128
128
  interface ExperimentVariantOverrideData {
129
129
  type: 'dataView' | 'workflow' | 'theme' | 'policy' | 'presentation';
130
130
  target: string;
131
- version?: number;
131
+ version?: string;
132
132
  }
133
133
  interface ExperimentVariantData {
134
134
  id: string;
@@ -142,7 +142,7 @@ interface TargetingRuleData {
142
142
  percentage?: number;
143
143
  policy?: {
144
144
  name: string;
145
- version?: number;
145
+ version?: string;
146
146
  };
147
147
  expression?: string;
148
148
  }
@@ -164,7 +164,7 @@ type ExperimentAllocationData = RandomAllocationData | StickyAllocationData | Ta
164
164
  interface ExperimentMetricData {
165
165
  name: string;
166
166
  eventName: string;
167
- eventVersion: number;
167
+ eventVersion: string;
168
168
  aggregation: 'count' | 'avg' | 'p75' | 'p90' | 'p95' | 'p99';
169
169
  target?: number;
170
170
  }
@@ -178,7 +178,7 @@ interface ExperimentSpecData extends BaseSpecData {
178
178
  interface AppConfigMappingData {
179
179
  slot: string;
180
180
  name: string;
181
- version?: number;
181
+ version?: string;
182
182
  }
183
183
  interface AppConfigFeatureFlagData {
184
184
  key: string;
@@ -192,10 +192,10 @@ interface AppRouteConfigData {
192
192
  dataView?: string;
193
193
  workflow?: string;
194
194
  guardName?: string;
195
- guardVersion?: number;
195
+ guardVersion?: string;
196
196
  featureFlag?: string;
197
197
  experimentName?: string;
198
- experimentVersion?: number;
198
+ experimentVersion?: string;
199
199
  }
200
200
  interface AppBlueprintSpecData extends BaseSpecData {
201
201
  title: string;
@@ -209,27 +209,27 @@ interface AppBlueprintSpecData extends BaseSpecData {
209
209
  workflows: AppConfigMappingData[];
210
210
  policyRefs: {
211
211
  name: string;
212
- version?: number;
212
+ version?: string;
213
213
  }[];
214
214
  theme?: {
215
215
  name: string;
216
- version: number;
216
+ version: string;
217
217
  };
218
218
  themeFallbacks: {
219
219
  name: string;
220
- version: number;
220
+ version: string;
221
221
  }[];
222
222
  telemetry?: {
223
223
  name: string;
224
- version?: number;
224
+ version?: string;
225
225
  };
226
226
  activeExperiments: {
227
227
  name: string;
228
- version?: number;
228
+ version?: string;
229
229
  }[];
230
230
  pausedExperiments: {
231
231
  name: string;
232
- version?: number;
232
+ version?: string;
233
233
  }[];
234
234
  featureFlags: AppConfigFeatureFlagData[];
235
235
  routes: AppRouteConfigData[];
@@ -266,11 +266,11 @@ type IntegrationOwnershipModeData = 'managed' | 'byok';
266
266
  type IntegrationHealthCheckMethod = 'ping' | 'list' | 'custom';
267
267
  interface IntegrationCapabilityRefData {
268
268
  key: string;
269
- version: number;
269
+ version: string;
270
270
  }
271
271
  interface IntegrationCapabilityRequirementData {
272
272
  key: string;
273
- version?: number;
273
+ version?: string;
274
274
  optional?: boolean;
275
275
  reason?: string;
276
276
  }
@@ -312,7 +312,7 @@ interface KnowledgeSpaceSpecData extends BaseSpecData {
312
312
  category: KnowledgeCategoryData;
313
313
  retention: KnowledgeRetentionData;
314
314
  policyName?: string;
315
- policyVersion?: number;
315
+ policyVersion?: string;
316
316
  trustLevel: KnowledgeTrustLevel;
317
317
  automationWritable: boolean;
318
318
  embeddingModel?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/bundle.workspace",
3
- "version": "1.45.0",
3
+ "version": "1.45.2",
4
4
  "description": "Workspace utilities for monorepo development",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -32,24 +32,20 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@ai-sdk/anthropic": "3.0.1",
35
- "@ai-sdk/google": "3.0.1",
36
- "@ai-sdk/mistral": "3.0.1",
37
35
  "@ai-sdk/openai": "3.0.1",
38
36
  "ollama-ai-provider": "^1.2.0",
39
- "@contractspec/module.workspace": "1.45.0",
40
- "@contractspec/lib.contracts": "1.45.0",
41
- "@contractspec/lib.contracts-transformers": "1.45.0",
42
- "@contractspec/lib.ai-providers": "1.45.0",
43
- "@contractspec/lib.schema": "1.45.0",
44
- "@contractspec/lib.testing": "1.45.0",
37
+ "@contractspec/module.workspace": "1.45.2",
38
+ "@contractspec/lib.contracts": "1.45.2",
39
+ "@contractspec/lib.contracts-transformers": "1.45.2",
40
+ "@contractspec/lib.ai-providers": "1.45.2",
45
41
  "ai": "6.0.3",
46
42
  "zod": "^4.1.13",
47
43
  "glob": "^13.0.0",
48
44
  "chokidar": "^5.0.0"
49
45
  },
50
46
  "devDependencies": {
51
- "@contractspec/tool.tsdown": "1.45.0",
52
- "@contractspec/tool.typescript": "1.45.0",
47
+ "@contractspec/tool.tsdown": "1.45.2",
48
+ "@contractspec/tool.typescript": "1.45.2",
53
49
  "@types/node": "^22.10.2",
54
50
  "tsdown": "^0.18.3",
55
51
  "typescript": "^5.9.3"