@tbox.cn/app-toolkit 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/chunk-WUULQDOV.js +1 -0
  2. package/dist/contracts-resolver-PS2UH2G6.js +1 -0
  3. package/dist/index.d.ts +374 -150
  4. package/dist/index.js +9 -9
  5. package/package.json +2 -2
  6. package/src/assembly/provider-catalog.ts +1 -1
  7. package/src/assembly/resolve-key.ts +75 -0
  8. package/src/assembly/walk-manifests.ts +138 -85
  9. package/src/core/contracts-expected.ts +2 -2
  10. package/src/core/contracts-resolver.ts +12 -1
  11. package/src/core/module-schema.ts +90 -14
  12. package/src/dto.ts +80 -33
  13. package/src/factory.ts +78 -26
  14. package/src/index.ts +16 -7
  15. package/src/integrations/mock-bindings.ts +1 -1
  16. package/src/integrations/module-binding.ts +60 -0
  17. package/src/integrations/predicate-io.ts +26 -5
  18. package/src/integrations/predicate.ts +97 -57
  19. package/src/integrations/prune-bindings.ts +33 -14
  20. package/src/integrations/write.ts +47 -27
  21. package/src/views/app.ts +4 -4
  22. package/src/views/context.ts +15 -14
  23. package/src/views/integration-schemas.ts +76 -18
  24. package/src/views/modules.ts +93 -25
  25. package/src/views/providers.ts +5 -5
  26. package/src/views/service-detail.ts +1 -1
  27. package/src/views/service-resolutions.ts +14 -13
  28. package/tests/credentials-view.test.ts +2 -2
  29. package/tests/demo-app.ts +11 -6
  30. package/tests/dev-manifest-catalog.test.ts +14 -14
  31. package/tests/file-cache.test.ts +5 -5
  32. package/tests/module-resources.test.ts +148 -0
  33. package/tests/module-schema.test.ts +120 -20
  34. package/tests/resolve-key.test.ts +154 -0
  35. package/tests/vendor-schema-keywords.test.ts +74 -0
  36. package/tests/views.test.ts +585 -247
  37. package/tests/write-core.test.ts +117 -0
  38. package/dist/chunk-KPD3LUH4.js +0 -1
  39. package/dist/contracts-resolver-E4SECBOG.js +0 -1
  40. package/src/integrations/domain-binding.ts +0 -81
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import{a as ke,b as j,c as be}from"./chunk-KPD3LUH4.js";import{z as R}from"zod";var K=/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/,qn=R.object({cardType:R.string(),schemaVersion:R.number().optional()}),tn=R.object({route:R.string(),component:R.string()}),rn=R.object({route:R.string(),label:R.string().optional(),icon:R.string().optional(),order:R.number().optional()}),on=R.object({id:R.string(),range:R.string().optional(),required:R.boolean().default(!0)}),sn=R.object({service:R.string(),provider:R.string().regex(K,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:R.string(),credentialType:R.string(),local:R.boolean().optional(),configSchema:R.string().optional(),credentialSchema:R.string().optional()}),an=R.object({service:R.string(),optional:R.boolean().default(!0),defaults:R.array(R.object({provider:R.string().regex(K,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:R.string()})).default([]),title:R.string().optional(),description:R.string().optional()}),cn=R.object({id:R.string(),type:R.string()}),ln=R.object({schemaVersion:R.number().default(1),name:R.string(),title:R.string().optional(),description:R.string().optional(),version:R.string().default("0.0.0"),kind:R.enum(["platform","business","third-party"]).default("business"),risk:R.object({level:R.enum(["high","medium","low"]).default("low"),writeBoundary:R.enum(["sdk-enforced","source"]).default("source")}).default({}),distribution:R.object({defaultMode:R.enum(["hybrid","sdk","codegen","local"]).default("codegen")}).default({}),contributes:R.object({handlers:R.array(R.string()).default([]),tools:R.array(R.string()).default([]),cards:R.array(qn).default([]),routes:R.array(R.string()).default([]),pages:R.array(tn).default([]),tabs:R.array(rn).default([]),providers:R.object({slots:R.array(sn).default([])}).default({}),services:R.array(an).default([]),resources:R.array(cn).default([])}).default({}),dependencies:R.object({modules:R.array(on).default([])}).default({}),env:R.array(R.string()).default([])}).strict();function ee(e){let n=ln.safeParse(e);return n.success?{ok:!0,value:n.data}:{ok:!1,errors:n.error.issues.map(r=>`${r.path.join(".")||"(root)"}: ${r.message}`)}}var Gn=/\$\$?\{([A-Z][A-Z0-9_]*)(?::-([^}]*))?\}/g;function dn(e){return JSON.stringify(e).slice(1,-1)}function Ce(e,n=process.env){let r=[],t=e.replace(Gn,(o,i,s)=>{if(o.startsWith("$$"))return o.slice(1);let l=n[i];return l!==void 0?dn(l):s!==void 0?dn(s):(r.push(i),o)});return r.length>0?{missing:r}:{text:t,missing:[]}}import{mkdirSync as Qn,existsSync as un,readFileSync as Xn,writeFileSync as et}from"fs";import{dirname as nt,join as pn}from"path";function le(e){let n={};for(let[r,t]of Object.entries(e)){if(typeof t!="string"){n[r]=null;continue}n[r]=t.length<=4?"****":`${t.slice(0,2)}****`}return n}var A=class extends Error{code;httpStatus;fields;constructor(n,r,t,o){super(t),this.name="AppToolkitError",this.code=n,this.httpStatus=r,this.fields=o}};function Ae(e){return e.notes.length>0?e.notes[0]:e.version===null?"contracts 不可解析(未安装)——检查应用依赖安装后重试":e.strictValidation?"contracts workspace 源码态未构建——执行 pnpm --filter @tbox.cn/app-contracts build 后重试":`contracts ${e.version} 无严格校验面(需 ≥0.9.0)——升级应用 @tbox.cn/app-contracts 依赖后可用`}function de(e,n){if(n!==void 0&&(n.includes("/")||n.includes("\\")||n.includes("..")))throw new A("VALIDATION_FAILED",400,`凭据 stem 派生输入含路径敌对字符(${e})——拒绝派生`)}function Y(e){if(de("provider",e.provider),de("service",e.service),de("instanceId",e.instanceId),de("domain",e.domain),e.instanceId!==void 0){let n=e.domain??e.service??"global";return`${e.provider}-${e.instanceId}-${n}`}return e.service!==void 0?`${e.provider}-${e.service}`:`${e.provider}-global`}function tt(e){return`secret://${e}`}function F(e){return`config/credentials/${e}.json`}function ne(e,n){let r=pn(e,F(n));if(!un(r))return null;try{let t=JSON.parse(Xn(r,"utf8"));if(typeof t.type!="string")return null;let{type:o,...i}=t,s={};for(let[l,d]of Object.entries(i))typeof d=="string"&&(s[l]=d);return{type:o,values:s}}catch{return null}}function xe(e,n,r){let t=pn(e,F(n)),o=un(t);return Qn(nt(t),{recursive:!0}),et(t,`${JSON.stringify({type:r.type,...r.values},null,2)}
2
- `,"utf8"),o}import{mkdirSync as rt,renameSync as it,writeFileSync as ot}from"fs";import{dirname as st}from"path";function $(e,n){fn(st(e));let r=`${e}.tmp-${process.pid}-${Date.now()}`;ot(r,n,"utf8"),it(r,e)}function fn(e){rt(e,{recursive:!0})}function _(e){let n=e.indexOf(".");return n===-1?e:e.slice(0,n)}function L(e,n){let r=e?.domains?.[n]?.provider;if(typeof r=="string"&&r.length>0)return{provider:r,layer:"module"};let t=e?.provider;return typeof t=="string"&&t.length>0?{provider:t,layer:"app"}:{provider:null,layer:null}}function H(e,n){let r=[...new Set((n.descriptor.contributes.services??[]).map(i=>_(i.service)))].sort();if(r.length===0)return{writable:!1,reason:"zero-domain",domainKeys:[]};if(r.length>1)return{writable:!1,reason:"multi-domain",domainKeys:r};let t=r[0],o=new Set;for(let[i,s]of Object.entries(e.catalog.services))if(_(i)===t)for(let l of s.owners)o.add(l);return o.size>1?{writable:!1,reason:"shared-key",domainKeys:[t],domainKey:t,coOwners:[...o].sort()}:{writable:!0,domainKeys:[t],domainKey:t}}function gn(e,n){let r=e.find(t=>t.pkg===n||`@app/${t.id}`===n);return r?r.id:n.startsWith("@app/")?n.slice(5):n}function mn(e,n){return[...new Set(Object.values(e.providers[n]??{}).flatMap(r=>r.services))].sort()}function z(e){if(!e||typeof e!="object")return!1;let n=Object.keys(e),r=new Set(["provider","credentialType","configSchema"]);if(!n.every(o=>r.has(o)))return!1;let t=e;return typeof t.provider=="string"&&t.provider.length>0&&typeof t.credentialType=="string"&&t.credentialType.length>0&&(t.configSchema===void 0||typeof t.configSchema=="string")}function vn(e,n,r){return e==="*"||r.has(e)?null:{severity:"error",code:"INSTANCE_KEY_NOT_REGISTERED",instance:e,message:`integrations: ${n} 键 ${e} 不在 malls 白名单内(${[...r].join(", ")})`}}function Ee(e,n){let r=new Set(n),t=[],o=(i,s)=>{let l=vn(i,s,r);l&&t.push(l)};for(let i of Object.keys(e.configByInstance??{}))o(i,"configByInstance");for(let i of Object.keys(e.credentialRefByInstance??{}))o(i,"credentialRefByInstance");for(let[i,s]of Object.entries(e.services??{}))for(let l of Object.keys(s.instances??{}))o(l,`services.${i}.instances`);return t}function Z(e){let n=[],r=e.contracts,{integrations:t,suppliedProviders:o,demandedServices:i,supplies:s,malls:l,credentialSchemaMissing:d,vendorConfigKeys:f,vendorConfigSchemaMissing:S,credentialFileMissing:p,credentialFileType:w,realmSwitchHints:C,moduleResourceNeeds:g}=e,c=l?new Set(l):void 0;for(let a of C??[])n.push({severity:"warning",code:"REALM_SWITCH_HINT",message:a});let u=new Set(Object.keys(o).map(a=>a.slice(0,a.indexOf("\0"))).filter(a=>a.length>0)),m=(a,h,x,k)=>{if(typeof x?.provider=="string"&&typeof x.implementation=="string"&&x.provider&&x.implementation)return o[te(x.provider,x.implementation)]?.credentialType;if(typeof h.provider=="string"&&typeof h.implementation=="string")return o[te(h.provider,h.implementation)]?.credentialType;let E=h.provider?.credentialType;if(typeof E=="string")return E;if(!s)return;let M=k??Object.keys(h.instances??{})[0]??"",O=r.resolveEffectiveService(t,a,M,s);if(!(O.status!=="ok"||typeof O.effective.provider!="string"))return o[te(O.effective.provider,O.effective.implementation)]?.credentialType};if(p||w)for(let[a,h]of Object.entries(t.services))for(let[x,k]of Object.entries(h.instances??{})){if(k.enabled===!1)continue;let E=k.credentialRef??h.credentialRef??t.credentialRefByInstance?.[x]??t.credentialRef;if(typeof E!="string"||!E.startsWith("secret://"))continue;let M=E.slice(9);p?.[M]===!0&&n.push({severity:"error",code:"CREDENTIAL_FILE_MISSING",service:a,instance:x,message:`integrations: 凭据文件缺失 ${M}(${a}@${x} effective ref=${E};档内 config/credentials/ 无此文件)`});let O=w?.[M];if(O){let N=m(a,h,k,x);N&&O!==N&&n.push({severity:"error",code:"CREDENTIAL_TYPE_MISMATCH",service:a,instance:x,message:`integrations: 凭据文件 ${M}.json type=${O} 与绑定 credentialType ${N} 不一致(${a}@${x}——transport 创建期将按 type 选策略)`})}}let v=(a,h)=>{if(!c)return;let x=vn(a,h,c);x&&n.push(x)};for(let[a]of Object.entries(t.configByInstance??{}))v(a,"configByInstance");for(let[a]of Object.entries(t.credentialRefByInstance??{}))v(a,"credentialRefByInstance");let b=Object.entries(t.services).filter(([,a])=>a.instances==null||a.instances["*"]!=null).map(([a])=>a);if(b.length>0){let a=Object.entries(t.services).filter(([,h])=>h.instances!=null&&h.instances["*"]==null).map(([h])=>h);a.length>0&&n.push({severity:"warning",code:"WILDCARD_ALIGNMENT",message:`integrations: 激活形态不对称(通配:${b.join(", ")};显式键集:${a.join(", ")})——动态 mallId 将在显式键集槽上 INSTANCE_NOT_FOUND(provider 业务限制表达位),确认是否齐步`})}let y=r.normalizeInstances({instances:t.instances,defaultInstanceId:t.defaultInstanceId});y.instances.length>=2&&y.defaultInstanceId===null&&n.push({severity:"warning",code:"MULTI_INSTANCE_NO_DEFAULT",message:`integrations: ${y.instances.length} 个部署实例(${y.instances.map(a=>a.id).join(", ")})均无 defaultInstanceId——无 scope 参数访问将落全局会话(默认商圈不注入)`});for(let[a,h]of Object.entries(t.services)){if(i[a]||n.push({severity:"warning",code:"SLOT_NOT_DECLARED",service:a,message:`integrations: 服务槽 ${a} 无消费方声明(拼写错误或需求方未安装)——若为拆分前旧槽位词汇(member.main/parking.main/promotion.read/shopping-guide.main),参照 cookbook·app-config 槽位迁移配方展开为新槽`}),typeof h.provider=="string"?typeof h.implementation=="string"&&!o[te(h.provider,h.implementation)]&&n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:a,message:`integrations: provider ${h.provider}/${h.implementation} 未命中已装供给(${a} 槽级)——装对应 provider 包或改绑`}):h.provider!==void 0&&!z(h.provider)&&n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:a,message:`integrations: 内联 provider 超受控形状(${a} 槽级;允许键 provider/credentialType/configSchema)`}),d){let k=m(a,h);k&&d[k]===!0&&n.push({severity:"error",code:"SCHEMA_FILE_MISSING",service:a,message:`integrations: credentialType ${k} 的 schema 引用不存在(${a};manifest 声明指向缺失文件)`})}typeof h.provider=="object"&&typeof h.implementation!="string"&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:a,message:`integrations: 内联厂商声明必须同时提供 implementation(${a} 槽级)`});for(let[k,E]of Object.entries(h.instances??{})){v(k,`services.${a}.instances`);let M=E.provider!==void 0,O=E.implementation!==void 0;if(O&&!M&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:a,instance:k,message:`integrations: 实例级 implementation 需伴随 provider(${a}@${k}——impl-only 禁止,provider 是绑定组头)`}),M&&O){let N=E.provider,V=E.implementation;typeof N=="string"&&typeof V=="string"?o[te(N,V)]||n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:a,instance:k,message:`integrations: 实例级 provider 覆盖 ${N}/${V} 未命中已装供给(${a}@${k})`}):z(N)||n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:a,instance:k,message:`integrations: 实例级内联 provider 超受控形状(${a}@${k})`})}}}for(let[a,h]of[["root",t.provider],...Object.entries(t.domains??{}).map(([x,k])=>[`domains.${x}`,k?.provider])])typeof h!="string"||h.length===0||u.has(h)||n.push({severity:"error",code:"VENDOR_NOT_INSTALLED",module:a.startsWith("domains.")?a.slice(8):void 0,message:`integrations: ${a} provider ${h} 未命中已装供给——装对应 provider 包或 provider use 改绑`});if(s)for(let[a,h]of Object.entries(t.services)){let x=h.instances?Object.keys(h.instances):[""];for(let k of x){let E=r.resolveEffectiveService(t,a,k,s);E.status==="binding-unresolved"&&n.push({severity:"error",code:"BINDING_UNRESOLVED",service:a,instance:k||void 0,message:`integrations: ${E.message}`})}}for(let[a,h]of Object.entries(t.services))h.implementation!==void 0&&h.provider===void 0&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:a,message:`integrations: 槽级 implementation 需伴随 provider(${a}——impl-only 禁止,provider 是绑定组头)`});let I=new Set([...Object.keys(t.services).map(a=>r.moduleDomainOf(a)),...Object.keys(i).map(a=>r.moduleDomainOf(a))]);for(let a of Object.keys(t.domains??{}))I.has(a)||n.push({severity:"warning",code:"DOMAIN_KEY_UNMATCHED",module:a,message:`integrations: domains.${a} 无对应槽位或需求声明(域前缀拼写错误?——键 = 槽位 id 点分前缀)`});if(f){let a=new Set,h=!1,x=k=>{typeof k!="string"||k.length===0||(f[k]&&a.add(k),!f[k]&&!S?.[k]&&(h=!0),S?.[k]&&(h=!0))};x(t.provider);for(let k of Object.values(t.domains??{}))x(k?.provider);for(let k of Object.values(t.services)){let E=k.provider;x(typeof k.provider=="string"?k.provider:E?.provider)}if(a.size>0&&!h){let k=new Set;for(let M of a)for(let O of f[M]??[])k.add(O);let E=(M,O,N)=>{for(let[V]of Object.entries(M??{}))(N??k).has(V)||n.push({severity:"error",code:"DOMAIN_CONFIG_INVALID",message:`integrations: ${O} 键 ${V} 不在引用厂商(${[...a].join("/")})任何槽 schema properties 内(死配置)`})};E(t.config,"root.config");for(let[M,O]of Object.entries(t.configByInstance??{}))E(O,`root.configByInstance[${M}]`);for(let[M,O]of Object.entries(t.domains??{})){if(!O?.config)continue;let N=L(t,M).provider??void 0;if(N===void 0){E(O.config,`domains.${M}.config`);continue}let V=f[N];!V||S?.[N]||E(O.config,`domains.${M}.config`,new Set(V))}}}for(let[a,h]of Object.entries(i)){let x=t.services[a];if(!x){n.push({severity:"warning",code:"SLOT_NOT_CONFIGURED",service:a,message:`integrations: 服务槽 ${a}(需求方 ${h.owners.join(", ")})未配置${h.optional?"(可选槽)":"(必需槽——模块将走降级链)"}`});continue}let k=Object.entries(x.instances??{}).filter(([,E])=>E.enabled===!1).map(([E])=>E);k.length>0&&n.push({severity:"warning",code:"INSTANCE_DISABLED",service:a,instance:k.join(", "),message:`integrations: ${a} 实例禁用(${k.join(", ")})`})}for(let[a,h]of Object.entries(t.modules??{})){let x=g?.[a];g&&!(a in g)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:a,message:`integrations: modules.${a} 未命中已装模块(键 = install id——检查 .tbox/app.json entry.id / packages/ 目录名)`});for(let[k,E]of Object.entries(h?.resources??{})){let M=E?.type;(typeof M!="string"||!r.RESOURCE_TYPE_IDS.includes(M))&&n.push({severity:"error",code:"RESOURCE_TYPE_UNKNOWN",module:a,message:`integrations: modules.${a}.resources.${k} type 非法(${String(M)};词汇表 = ${r.RESOURCE_TYPE_IDS.join("/")})`}),x&&x.size>0&&!x.has(k)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:a,message:`integrations: modules.${a}.resources.${k} 未被模块 manifest contributes.resources 声明`})}}return n}function te(e,n){return`${e}\0${n}`}import{existsSync as Oe,readFileSync as at,readdirSync as ct}from"fs";import{join as ue}from"path";function Sn(e){return e.replaceAll("-","_").toUpperCase()}function yn(e){if(!Oe(e))return null;try{let n=JSON.parse(at(e,"utf8"));return n&&typeof n=="object"?n:null}catch{return null}}function lt(e){let n=new Set,r=e.properties;if(r&&typeof r=="object"&&!Array.isArray(r))for(let t of Object.keys(r))n.add(t);return n}function re(e,n,r,t=process.env){let o={};for(let[y,I]of Object.entries(n.catalog.providers))for(let[a,h]of Object.entries(I))o[`${y}\0${a}`]={services:[...h.services],owner:h.owner,credentialType:h.credentialType};let i={};for(let[y,I]of Object.entries(n.catalog.services))i[y]={optional:I.optional,owners:[...I.owners]};let s={},l={},d={},f={};for(let y of n.modules){f[y.id]=new Set((y.descriptor.contributes.resources??[]).map(I=>I.id));for(let I of y.descriptor.contributes.providers?.slots??[]){if(I.configSchema){let a=yn(ue(y.dir,I.configSchema));if(a){let h=s[I.provider]??=new Set;for(let x of lt(a))h.add(x)}else l[I.provider]=!0}I.credentialSchema&&!Oe(ue(y.dir,I.credentialSchema))&&(d[I.credentialType]=!0)}}let S={},p=new Set,w=ue(e,"config","credentials");if(Oe(w))for(let y of ct(w)){if(!y.endsWith(".json"))continue;let I=y.slice(0,-5);p.add(I);let a=yn(ue(w,y));a&&typeof a.type=="string"&&(S[I]=a.type)}let C=r,g=[],c=y=>{typeof y=="string"&&y.startsWith("secret://")&&g.push(y)};for(let y of Object.values(C.services??{}))if(y&&typeof y=="object"){c(y.credentialRef);for(let I of Object.values(y.instances??{}))I&&typeof I=="object"&&c(I.credentialRef)}for(let y of Object.values(C.credentialRefByInstance??{}))c(y);c(C.credentialRef);let u={};for(let y of g){let I=y.slice(9);t[Sn(I)]===void 0&&(p.has(I)||(u[I]=!0))}let m=[];for(let[y,I]of Object.entries(C.services??{})){let a=I&&typeof I=="object"&&typeof I.provider=="string"?I.provider:void 0;for(let[h,x]of Object.entries((I&&typeof I=="object"?I.instances:void 0)??{})){let k=x&&typeof x=="object"&&typeof x.provider=="string"?x.provider:void 0;a&&k&&k!==a&&m.push(`integrations: ${y}@${h} 实现覆盖跨厂商(${a} → ${k})——凭据域切换,确认该 mall 对应凭据在场`)}}let b=((Array.isArray(C.instances)?C.instances:void 0)??[]).map(y=>y&&typeof y=="object"&&typeof y.id=="string"?y.id:void 0).filter(y=>typeof y=="string");return{suppliedProviders:o,demandedServices:i,credentialFileMissing:u,credentialFileType:S,credentialSchemaMissing:d,vendorConfigKeys:s,vendorConfigSchemaMissing:l,realmSwitchHints:m,moduleResourceNeeds:f,...b.length>0?{malls:b}:{}}}import{existsSync as D,readdirSync as Me,readFileSync as q}from"fs";import{join as T}from"path";import{existsSync as dt,readFileSync as wn,mkdirSync as ut,writeFileSync as pt}from"fs";import hn from"path";function pe(e){return hn.join(e,".tbox","app.json")}function Rn(e){let n=pe(e);if(!dt(n))return null;try{let r=JSON.parse(wn(n,"utf8")),t=r?.templateVersion;return typeof t!="string"||t.trim().length===0?null:{templateVersion:t.trim(),npmModules:Array.isArray(r?.npmModules)?r.npmModules:[]}}catch{return null}}function ft(e,n){let r=pe(e);ut(hn.dirname(r),{recursive:!0}),pt(r,`${JSON.stringify(n,null,2)}
3
- `,"utf8")}function je(e){let n=Rn(e);if(n===null)return null;let r=pe(e);try{let t=JSON.parse(wn(r,"utf8"));return{...n,miniappContainers:Array.isArray(t?.miniappContainers)?t.miniappContainers:[]}}catch{return{...n,miniappContainers:[]}}}function gt(e,n){let r=e.npmModules.filter(t=>t.id!==n.id);return{...e,npmModules:[...r,n]}}function mt(e,n){return{...e,npmModules:e.npmModules.filter(r=>r.id!==n)}}function vt(e,n){let r=(e.miniappContainers??[]).filter(t=>t.id!==n.id);return{...e,miniappContainers:[...r,n]}}function yt(e,n,r){return{...e,npmModules:e.npmModules.map(t=>t.id===n?{...t,...r}:t)}}function In(e){return/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)&&!e.includes("..")}function St(e,n){if(!In(e))throw new Error(`非法模块 id "${e}"(来自 ${n}):仅允许小写字母/数字/中划线`)}function kn(e){try{let n=JSON.parse(e);if(!Array.isArray(n.slots))return null;let r=n.slots.filter(o=>typeof o=="string"),t={};if(n.meta&&typeof n.meta=="object"&&!Array.isArray(n.meta))for(let[o,i]of Object.entries(n.meta)){if(!i||typeof i!="object"||Array.isArray(i))continue;let{title:s,description:l}=i,d={};typeof s=="string"&&s.length>0&&(d.title=s),typeof l=="string"&&l.length>0&&(d.description=l),(d.title!==void 0||d.description!==void 0)&&(t[o]=d)}return{slots:r,meta:t}}catch{return null}}function fe(e,n){let r=t=>{try{let o=JSON.parse(t),i=ee(o);if(i.ok)return{kind:"strict",name:i.value.name,version:i.value.version,descriptor:i.value,contributes:i.value.contributes};if(o&&typeof o=="object"&&"contributes"in o){let s=o;return{kind:"loose",...typeof s.name=="string"?{name:s.name}:{},contributes:{providers:s.contributes?.providers,services:s.contributes?.services}}}return null}catch{return null}};if(n)return n.read(e,r)??null;if(!D(e))return null;try{return r(q(e,"utf8"))}catch{return null}}function wt(e){let n=T(e,".tbox","app.json");if(!D(n))return[];try{let r=JSON.parse(q(n,"utf8"));return Array.isArray(r.npmModules)?r.npmModules.filter(t=>!!t&&typeof t=="object"&&typeof t.id=="string"&&typeof t.package=="string"):[]}catch{return[]}}function ht(e){let n=T(e,".tbox-dev.local"),r=T(n,"dev-manifest.json");if(!D(r))return[];try{let t=JSON.parse(q(r,"utf8")),o=[];for(let[i,s]of Object.entries(t.redirects??{}))typeof s!="string"||!i.startsWith("@tbox.cn/app-")||o.push({pkg:i,dir:T(n,s)});return o}catch{return[]}}function Rt(e,n){let r=[],t=[e];for(let s of["apps","packages"]){let l=T(e,s);if(D(l))try{for(let d of Me(l,{withFileTypes:!0}))d.isDirectory()&&t.push(T(l,d.name))}catch{}}let o=new Set,i=(s,l)=>{let d=n?n.read(l,kn):kn(q(l,"utf8"));d!=null&&r.push({dir:s,slots:d.slots,meta:d.meta})};for(let s of t){let l=T(s,"node_modules","@tbox.cn");if(!D(l))continue;let d=[];try{d=Me(l)}catch{continue}for(let f of d){let S=T(l,f);if(o.has(S))continue;o.add(S);let p=T(S,"service-slots.json"),w=T(S,"src","service-slots.json");D(p)?i(S,p):D(w)&&i(S,w)}}for(let s of t)for(let l of[T(s,"service-slots.json"),T(s,"src","service-slots.json")])D(l)&&i(s,l);return r}function P(e,n){let r=[],t={providers:{},services:{},credentialTypes:{}},o={},i=[],s=new Set,l=new Map,d=(g,c,u,m)=>{for(let v of g){let b=t.providers[v.provider]??={},y=b[v.implementation];y?y.services.includes(v.service)||y.services.push(v.service):(b[v.implementation]={provider:v.provider,implementation:v.implementation,credentialType:v.credentialType,owner:c,...m?.title?{title:m.title}:{},...m?.description?{description:m.description}:{},...v.local?{local:!0}:{},...v.configSchema?{configSchema:v.configSchema}:{},...v.credentialSchema?{credentialSchema:v.credentialSchema}:{},services:[v.service]},t.credentialTypes[v.credentialType]??={owner:c,packageDir:u,...v.credentialSchema?{credentialSchema:v.credentialSchema}:{}});let I=`${v.provider}\0${v.service}`;o[I]||(o[I]={...v.configSchema?{configSchema:v.configSchema}:{},...v.credentialSchema?{credentialSchema:v.credentialSchema}:{},packageDir:u})}},f=g=>g.kind==="strict"?{title:g.descriptor.title,description:g.descriptor.description}:void 0,S=(g,c)=>{let u=g.optional!==!1,m=g.defaults??[],v=t.services[g.service];if(v){v.optional=v.optional&&u;let I=new Set(v.defaults.map(a=>`${a.provider}\0${a.implementation}`));for(let a of m){let h=`${a.provider}\0${a.implementation}`;I.has(h)||(v.defaults.push(a),I.add(h))}v.owners.includes(c)||v.owners.push(c);return}t.services[g.service]={optional:u,defaults:[...m],...g.title?{title:g.title}:{},...g.description?{description:g.description}:{},owners:[c]};let b=g.service.includes(".")?g.service.slice(0,g.service.indexOf(".")):g.service,y=l.get(b);y===void 0?l.set(b,c):y!==c&&i.push({severity:"warning",code:"DOMAIN_KEY_CONFLICT",module:c,message:`域键 ${b} 被多模块声明(${y} 与 ${c})——domains 换算歧义(P13)`})};for(let g of wt(e)){if(s.has(g.id))continue;let c=T(e,"packages",g.id),u=T(e,"node_modules",...g.package.split("/")),m=fe(T(c,"tbox.module.json"),n)??fe(T(u,"tbox.module.json"),n);if(!m)continue;s.add(g.id);let v=D(T(c,"tbox.module.json"))?c:u,b=m.contributes;m.kind==="strict"&&r.push({id:g.id,dir:v,pkg:g.mode==="sdk"?g.package:`@app/${g.id}`,descriptor:m.descriptor});let y=b.providers?.slots??[];y.length&&d(y,g.package,v,f(m));let I=b.services??[];if(I.length)for(let a of I)S(a,g.package)}for(let{pkg:g,dir:c}of ht(e)){let u=fe(T(c,"tbox.module.json"),n);if(!u?.name||s.has(u.name))continue;s.add(u.name);let m=u.contributes.providers?.slots??[];m.length&&d(m,g,c,f(u));let v=u.contributes.services??[];if(v.length)for(let b of v)S(b,g)}let p=T(e,"packages");if(D(p)){let g=[];try{g=Me(p,{withFileTypes:!0}).filter(c=>c.isDirectory()).map(c=>c.name)}catch{}for(let c of g){if(s.has(c))continue;let u=T(p,c),m=fe(T(u,"tbox.module.json"),n);if(!m)continue;let v=m.name??c;if(s.has(v))continue;s.add(v);let b=m.contributes;m.kind==="strict"&&r.push({id:v,dir:u,pkg:`@app/${v}`,descriptor:m.descriptor});let y=b.providers?.slots??[];y.length&&d(y,`@app/${v}`,u,f(m));let I=b.services??[];if(I.length)for(let a of I)S(a,`@app/${v}`)}}let w=new Set,C={};for(let g of Rt(e,n)){for(let c of g.slots)w.add(c);for(let[c,u]of Object.entries(g.meta))C[c]===void 0&&(C[c]=u)}return{modules:r,catalog:t,serviceSchemas:o,vocabulary:[...w].sort(),slotMeta:C,domainKeyIssues:i}}function bn(e,n,r){let t=T(e,"src",n,"index.ts");if(!D(t))return!1;try{let o=q(t,"utf8");return new RegExp(`export\\s+const\\s+${r}\\b`).test(o)}catch{return!1}}function It(e){let n=T(e,"src","server","index.ts");if(!D(n))return"";try{return q(n,"utf8")}catch{return""}}function Cn(e){return e.match(/declaration\s*:\s*\{[\s\S]*?moduleId\s*:\s*['"]([^'"]+)['"]/)?.[1]}function kt(e){let n=[],r=P(e),t=je(e),o=new Map;for(let i of t?.npmModules??[])o.set(i.id,i.mode);for(let i of r.modules){let s=o.get(i.id)??"local",l=bn(i.dir,"server","serverModule"),d=i.descriptor.contributes;n.push({id:i.id,pkg:s==="sdk"?i.pkg:`@app/${i.id}`,mode:s,hasServerEntry:l,hasClientEntry:bn(i.dir,"client","clientModule"),hasCards:(d.cards?.length??0)>0,...l?{moduleId:Cn(It(i.dir))}:{}})}return n.sort((i,s)=>i.id.localeCompare(s.id))}import{existsSync as Mr,readFileSync as Tr}from"fs";import{join as Nr,resolve as Vr}from"path";function Te(e){return P(e).catalog}function ge(e){let n=P(e).catalog,r={};for(let[i,s]of Object.entries(n.providers)){r[i]={};for(let[l,d]of Object.entries(s))r[i][l]={provider:d.provider,implementation:d.implementation,credentialType:d.credentialType,owner:d.owner,...d.local?{local:!0}:{},...d.configSchema?{configSchema:d.configSchema}:{},...d.credentialSchema?{credentialSchema:d.credentialSchema}:{},services:[...d.services]}}let t={};for(let[i,s]of Object.entries(n.services))t[i]={optional:s.optional,defaults:s.defaults.map(l=>({...l})),owners:[...s.owners]};let o={};for(let[i,s]of Object.entries(n.credentialTypes))o[i]={owner:s.owner,...s.credentialSchema?{credentialSchema:s.credentialSchema}:{}};return{providers:r,services:t,credentialTypes:o}}async function Pe(e,n,r,t=process.env){let o=r.module,i=P(e),s=o.buildSupplyLookup(ge(e)),l=re(e,i,n,t);return Z({contracts:o,integrations:n,supplies:s,...l})}import{existsSync as jt,rmSync as Mt}from"fs";import{join as Tt}from"path";import{existsSync as bt,readFileSync as Ct}from"fs";import{join as An}from"path";var At=An("config","integrations.json");function W(e,n){let r=An(e,At),t=o=>JSON.parse(o);if(n)return n.read(r,t)??null;if(!bt(r))return null;try{return t(Ct(r,"utf8"))}catch{return null}}async function xn(e,n){let r=await j(e),t=W(e,n);if(t===null)return{config:null,strict:!1,contracts:r};if(r.strictValidation&&r.module.parseIntegrationsConfig)try{return{config:r.module.parseIntegrationsConfig(t),strict:!0,contracts:r}}catch(o){if(o instanceof Error&&Array.isArray(o.issues)){let i=o.issues.filter(s=>Array.isArray(s.path)).map(s=>s.path.map(String).join(".")).filter(s=>s.length>0);throw new A("VALIDATION_FAILED",400,"integrations.json 校验失败",i.length>0?i:void 0)}throw new A("VALIDATION_FAILED",400,o instanceof Error?o.message:String(o))}return{config:t,strict:!1,contracts:r}}function ie(e,n,r){return e.includes(r)||n.includes(r)}import{readdirSync as xt,existsSync as me,readFileSync as Et}from"fs";import{join as ve}from"path";function En(e,n,r){let t=[];if(n){let o=Y({provider:e});t.push({stem:o,ref:`secret://${o}`,input:n})}for(let[o,i]of Object.entries(r??{})){let s=Y({provider:e,instanceId:o});t.push({instanceId:o,stem:s,ref:`secret://${s}`,input:i})}return t}function On(e,n,r,t,o){let i=[];if(t){let s=Y({provider:e,service:n});i.push({stem:s,ref:`secret://${s}`,input:t})}for(let[s,l]of Object.entries(o??{})){let d=Y({provider:e,instanceId:s,domain:r});i.push({instanceId:s,stem:d,ref:`secret://${d}`,input:l})}return i}function Ve(e,n,r){return n.map(t=>({stem:t.stem,ref:t.ref,overwrote:r?me(ve(e,F(t.stem))):xe(e,t.stem,t.input)}))}function Ot(e,n){return me(ve(e,F(n)))}function Ne(e,n){if(typeof e=="string"){e.startsWith("secret://")&&n.add(e.slice(9));return}if(Array.isArray(e)){for(let r of e)Ne(r,n);return}if(e&&typeof e=="object")for(let r of Object.values(e))Ne(r,n)}function oe(e){let n=ve(e,"config","credentials"),r=new Set,t=ve(e,"config","integrations.json");if(me(t))try{Ne(JSON.parse(Et(t,"utf8")),r)}catch{}let o=[];if(!me(n))return o;let i=[];try{i=xt(n).filter(s=>s.endsWith(".json")).map(s=>s.slice(0,-5))}catch{return o}for(let s of i.sort()){if(r.has(s))continue;let l=ne(e,s);o.push({severity:"warning",code:"ORPHANED_CREDENTIAL",message:`${F(s)} 不再被引用(凭据文件保留,可手动清理)`})}return o}function ye(e){if(typeof e=="string")return e.length>0?e:void 0;if(e&&typeof e=="object"&&z(e)){let n=e.provider;return n.length>0?n:void 0}}async function Pt(e){let n=Tt(e,"config","integrations.json"),r=W(e);if(r===null)return{removed:[],orphanCredentials:[],skipped:"not-configured"};let t=await j(e);if(!t.strictValidation)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};let o;try{let p=Ce(JSON.stringify(r),process.env);if(p.missing.length>0||p.text===void 0)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};o=JSON.parse(p.text)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let i;try{i=await Pe(e,o,t,process.env)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let s=new Set(Object.keys(P(e).catalog.providers)),l=structuredClone(r);l.services??={};let d=[];for(let p of i)if(p.severity==="error"){if(p.code==="VENDOR_NOT_INSTALLED")if(p.module){let w=l.domains?.[p.module];w?.provider&&(d.push(`domains.${p.module}.provider=${w.provider}`),delete w.provider,Object.keys(w).length===0&&delete l.domains[p.module])}else l.provider&&(d.push(`root.provider=${l.provider}`),delete l.provider);else if(p.code==="BINDING_UNRESOLVED"&&p.service){let w=l.services[p.service];if(!w||[p.instance?ye(w.instances?.[p.instance]?.provider):void 0,ye(w.provider),ye(l.domains?.[_(p.service)]?.provider),ye(l.provider)].filter(g=>typeof g=="string").some(g=>s.has(g)))continue;if(p.instance){let g=w.instances;if(!g||!(p.instance in g))continue;delete g[p.instance],d.push(`services.${p.service}.instances.${p.instance}`),Object.keys(g).length===0&&delete w.instances,Object.keys(w).length===0&&delete l.services[p.service]}else delete l.services[p.service],d.push(`services.${p.service}`)}}if(Object.keys(l.services).length===0&&delete l.services,d.length===0)return{removed:d,orphanCredentials:[]};let f=!l.provider&&Object.keys(l.domains??{}).length===0&&Object.keys(l.services??{}).length===0&&Object.keys(l.config??{}).length===0&&Object.keys(l.configByInstance??{}).length===0&&!l.credentialRef&&Object.keys(l.credentialRefByInstance??{}).length===0&&(l.instances??[]).length===0&&l.defaultInstanceId==null&&Object.keys(l.modules??{}).length===0;if(!f&&(l.services??={},typeof t.module.parseIntegrationsConfig=="function"))try{t.module.parseIntegrationsConfig(l)}catch{return{removed:[],orphanCredentials:[],skipped:"validation-failed"}}let S=[];return f?jt(n)&&Mt(n,{force:!0}):$(n,`${JSON.stringify(l,null,2)}
4
- `),S=oe(e).map(p=>p.message),{removed:d,orphanCredentials:S}}import{existsSync as Tn,readFileSync as Pn}from"fs";import{join as G,resolve as Nt}from"path";import Vt from"ajv";var se=["provider","config","configByInstance","credentialRef","credentialRefByInstance","instances","defaultInstanceId"];var U=G("config","integrations.json");function Q(e,n){if(e===n)return!0;if(Array.isArray(e)&&Array.isArray(n))return e.length!==n.length?!1:e.every((r,t)=>Q(r,n[t]));if(e&&n&&typeof e=="object"&&typeof n=="object"){let r=Object.keys(e),t=Object.keys(n);return r.length!==t.length?!1:r.every(o=>Q(e[o],n[o]))}return!1}function he(e,n){if(typeof e!="string"&&e&&typeof e=="object")for(let[r,t]of Object.entries(e)){if((r==="provider"||r==="instanceId")&&typeof t=="string"&&!K.test(t))throw new A("VALIDATION_FAILED",400,`${r} 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`${n}.${r}`]);he(t,`${n}.${r}`)}}function Se(e,n,r){if(!(!e||typeof e!="object"||Array.isArray(e))){for(let t of Object.keys(e))if(!(r&&(t==="*"||t==="**"))&&!K.test(t))throw new A("VALIDATION_FAILED",400,`${n} 键 ${t} 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)——进凭据 stem 派生,防路径逃逸`,[n])}}function jn(e,n,r){if(r==="root"){let t=e.instances;Array.isArray(t)&&t.forEach((o,i)=>{let s=o&&typeof o=="object"?o.id:void 0;if(typeof s=="string"&&!K.test(s))throw new A("VALIDATION_FAILED",400,`instances[${i}].id 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`root.instances[${i}].id`])}),Se(e.configByInstance,"root.configByInstance",!1),Se(e.credentialRefByInstance,"root.credentialRefByInstance",!1)}else Se(e.instances,"services.instances",!0);Se(n.credentialsByInstance,"credentialsByInstance",!1)}function we(e,n){let r=G(e,U),t=o=>JSON.parse(o);if(n)return n.read(r,t)??null;if(!Tn(r))return null;try{return t(Pn(r,"utf8"))}catch{return null}}function De(e){let n=(e.instances??[]).map(r=>r.id);return n.length===0?[]:Ee(e,n)}function Dt(e,n,r,t){let{catalog:o}=P(e,t),i=o.providers[n];if(!i)return;let s=new Set;for(let l of Object.values(i))(r===void 0||l.services.includes(r))&&s.add(l.credentialType);return s.size===1?[...s][0]:void 0}function Mn(e,n,r,t,o,i){if(typeof t.type!="string"||t.type.length===0)throw new A("VALIDATION_FAILED",400,"凭据 type 缺失或为空字符串",["credentials.type"]);let s=o??Dt(e,n,r,i);if(s!==void 0&&s!=="-"&&t.type!==s)throw new A("VALIDATION_FAILED",400,`凭据 type=${t.type} 与绑定 credentialType ${s} 不一致`,["credentials.type"]);if(r===void 0)return;let{serviceSchemas:l}=P(e,i),d=l[`${n}\0${r}`];if(!d?.credentialSchema)return;let f=Nt(d.packageDir,d.credentialSchema);if(Tn(f))try{let p=new Vt({allErrors:!0}).compile(JSON.parse(Pn(f,"utf8")));if(!p({type:t.type,...t.values})){let w=(p.errors??[]).map(C=>`credentials.values.${String(C.instancePath||C.params?.missingProperty||"").replace(/^\//,"")}`);throw new A("VALIDATION_FAILED",400,"凭据字段校验失败(ajv 字段级)",w)}}catch(S){if(S instanceof A)throw S}}function Fe(e,n={}){let{onApplied:r,cache:t}=n;function o(f,S,p,w){let C=f!==null,g=S.length>0,c=!w&&C,u=!w&&g;c&&($(G(e,U),`${JSON.stringify(f,null,2)}
5
- `),t?.invalidate([G(e,U)]));let m=c||u,v=m&&r!==void 0;v&&r?.();let b=[];return C&&b.push(U),g&&b.push(...S.map(y=>F(y.stem))),{written:m,restartScheduled:v,files:b,credentials:S,issues:p}}let i;async function s(){i=await j(e)}function l(f,S){return f.filter(p=>Array.isArray(p.path)).map(p=>{let w=p.path.map(String).join(".");return S!==""&&w.startsWith(S)&&w.length>S.length?w.slice(S.length):w}).filter(p=>p.length>0)}function d(f,S,p){let w=i;if(!w||!w.strictValidation||!w.module.parseIntegrationsConfig)throw new A("CONTRACTS_NOT_RESOLVED",503,"contracts 严格校验面不可用(需 ≥0.9)——写路径门控失败(工厂边缘断言应先行拦截)");try{w.module.parseIntegrationsConfig(f)}catch(C){throw C instanceof Error&&Array.isArray(C.issues)?new A("VALIDATION_FAILED",400,"节点 schema 校验失败",l(C.issues,p)):new A("VALIDATION_FAILED",400,C instanceof Error?C.message:String(C))}}return{warmup:s,applyApp(f,S={}){he(f,"root"),jn(f,S,"root");let p=[],w=we(e,t),C=w??{services:{}};w===null&&p.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let g={...C};for(let a of se)a in f||delete g[a];for(let[a,h]of Object.entries(f))g[a]=h;let c=typeof g.provider=="string"?g.provider:"app",u=En(c,S.credentials,S.credentialsByInstance);for(let a of u)Mn(e,c,void 0,a.input,void 0,t);let m=u.find(a=>a.instanceId===void 0);if(S.credentials&&m&&(g.credentialRef=m.ref),S.credentialsByInstance){let a={...g.credentialRefByInstance??{}};for(let h of u)h.instanceId!==void 0&&(a[h.instanceId]=h.ref);g.credentialRefByInstance=a}let v=S.credentials!==void 0||S.credentialsByInstance!==void 0,b=Q(w,g);if(b&&!v)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:p};d(g,p,"");let y=S.dryRun===!0,I=Ve(e,u,y);return p.push(...De(g)),o(b?null:g,I,p,S.dryRun)},applyModule(f,S,p={}){he(S,"root");let{modules:w,catalog:C}=P(e,t),g=w.find(a=>a.id===f);if(!g)throw new A("MODULE_NOT_FOUND",404,`模块 ${f} 非已装模块`);let c=H({modules:w,catalog:C},g);if(!c.writable)throw c.reason==="multi-domain"?new A("VALIDATION_FAILED",400,`模块 ${f} 跨 ${c.domainKeys.length} 个域(${c.domainKeys.join("、")})——模块级统一配置仅支持单域模块,请按服务级配置(编辑各服务行)`):c.reason==="zero-domain"?new A("VALIDATION_FAILED",400,`模块 ${f} 无服务需求声明,无域配置位`):new A("VALIDATION_FAILED",400,`域键 ${c.domainKey} ${c.coOwners.map(a=>gn(w,a)).join("、")} 共用——写通道拒绝歧义操作,请按服务级配置`);let u=c.domainKey,m=[],v=we(e,t);if(v===null&&Object.keys(S).length===0)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:m};v===null&&m.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let b=v??{services:{}},y={...b.domains??{}},I={...b,domains:y};return Object.keys(S).length===0?delete y[u]:y[u]={...S},Q(v,I)?{written:!1,restartScheduled:!1,files:[],credentials:[],issues:m}:(d(I,m,`domains.${u}.`),m.push(...De(I)),o(I,[],m,p.dryRun))},applyService(f,S,p={}){he(S,"root"),jn(S,p,"slot");let w=[],C=we(e,t);if(!ie(P(e,t).vocabulary,Object.keys(C?.services??{}),f))throw new A("SERVICE_NOT_FOUND",404,`服务 ${f} 不在服务词汇(已装契约包 ∪ 已配置)`);C===null&&w.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let g=C??{services:{}},c={...g.services??{}},u={...g,services:c};c[f]={...S};let m=S.provider,v=m!==null&&typeof m=="object"?m:void 0,b=typeof m=="string"?m:typeof v?.provider=="string"?v.provider:"app",y=f.includes(".")?f.slice(0,f.indexOf(".")):f,I=On(b,f,y,p.credentials,p.credentialsByInstance);for(let O of I)Mn(e,b,f,O.input,typeof v?.credentialType=="string"?v.credentialType:void 0,t);let a=c[f],h=I.find(O=>O.instanceId===void 0);if(p.credentials&&h&&(a.credentialRef=h.ref),p.credentialsByInstance){let O={...a.instances??{}};for(let N of I){if(N.instanceId===void 0)continue;let V={...O[N.instanceId]??{}};V.credentialRef=N.ref,O[N.instanceId]=V}a.instances=O}let x=p.credentials!==void 0||p.credentialsByInstance!==void 0,k=Q(C,u);if(k&&!x)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:w};d(u,w,`services.${f}.`);let E=p.dryRun===!0,M=Ve(e,I,E);return w.push(...De(u)),o(k?null:u,M,w,p.dryRun)},deleteService(f){let S=[],p=we(e,t);if(!ie(P(e,t).vocabulary,Object.keys(p?.services??{}),f))throw new A("SERVICE_NOT_FOUND",404,`服务 ${f} 不在服务词汇(已装契约包 ∪ 已配置)`);let w={...p?.services??{}};if(!(f in w))return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:S};delete w[f];let C={...p??{services:{}},services:w};$(G(e,U),`${JSON.stringify(C,null,2)}
6
- `),t?.invalidate([G(e,U)]),S.push(...oe(e));let g=r!==void 0;return g&&r?.(),{written:!0,restartScheduled:g,files:[U],credentials:[],issues:S}}}}import{existsSync as Ft}from"fs";import{join as $t}from"path";function $e(e){let n=$t(e,"config","integrations.json");if(Ft(n))return{generated:!1,reason:"in-place",services:[]};let r=[];for(let i of P(e).modules)for(let s of i.descriptor.contributes.providers?.slots??[])s.local===!0&&r.push({service:s.service,provider:s.provider,implementation:s.implementation});if(r.length===0)return{generated:!1,reason:"no-local-slots",services:[]};let t={},o=new Set(r.map(i=>i.provider));if(o.size===1){let[i]=o;for(let s of r)t[s.service]={};$(n,`${JSON.stringify({provider:i,services:t},null,2)}
7
- `)}else{for(let i of r)t[i.service]={provider:i.provider,implementation:i.implementation};$(n,`${JSON.stringify({services:t},null,2)}
8
- `)}return{generated:!0,reason:"generated",services:r.map(i=>i.service).sort()}}function Nn(e,n){let r=P(e.appDir,e.cache),t=W(e.appDir,e.cache);return{appDir:e.appDir,walk:r,catalog:r.catalog,integrations:t,contracts:n}}function Vn(e){let n=new Set;for(let r of e.modules){for(let t of r.descriptor.contributes.services??[])n.add(t.service);for(let t of r.descriptor.contributes.providers?.slots??[])n.add(t.service)}return n}function Re(e,n,r){let t=e.providers[n];return t?Object.values(t).some(o=>o.services.includes(r)):!1}function Dn(e,n){let r=[];for(let[t,o]of Object.entries(e.providers))Object.values(o).some(i=>i.services.includes(n))&&r.push(t);return r.sort()}function B(e,n){let r=e.slotMeta[n],t=e.catalog.services[n],o=r?.title??t?.title??n,i=r?.description??t?.description;return{title:o,...i!==void 0?{description:i}:{}}}function Fn(e){return e.replace(/^@tbox\.cn\/app-/,"").replace(/^@[^/]+\//,"")}function _t(e){return Fn(e.id).startsWith("provider-")||Fn(e.pkg).startsWith("provider-")}function _e(e){return{modules:e.walk.modules.filter(r=>!_t(r)).map(r=>({id:r.id,name:r.descriptor.name,title:r.descriptor.title??r.descriptor.name,description:r.descriptor.description??""})).sort((r,t)=>r.id.localeCompare(t.id))}}function Le(e,n){let r=e.walk.modules.find(d=>d.id===n);if(!r)throw new A("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块`);let t=(r.descriptor.contributes.services??[]).map(d=>{let f=B(e.walk,d.service);return{service:d.service,title:f.title,...f.description!==void 0?{description:f.description}:{},required:d.optional===!1}}),o=H(e.walk,r),i=e.integrations?.domains??{},s=o.writable?i[o.domainKey]??null:null,l=o.domainKeys.map(d=>{let f=L(e.integrations,d);return{domain:d,effective:f.provider,layer:f.layer}});return{title:r.descriptor.title??r.descriptor.name,description:r.descriptor.description??"",domainKeys:[...o.domainKeys],integration:s,providerBindings:l,configEditable:o.writable,services:t}}function We(e){let n=Vn(e.walk),r=e.walk.vocabulary.filter(i=>!n.has(i)).map(i=>{let s=B(e.walk,i);return{service:i,title:s.title,...s.description!==void 0?{description:s.description}:{},required:!1}}),t=e.integrations,o=null;if(t){let i={};for(let s of se)s in t&&(i[s]=t[s]);o=i}return{services:r,integration:o}}function Be(e,n){let r=e.integrations?.services??{},t=e.catalog.services[n];if(!ie(e.walk.vocabulary,Object.keys(r),n))throw new A("SERVICE_NOT_FOUND",404,`服务 ${n} 不在服务词汇(已装契约包 ∪ 已配置)`);let o=r[n]??null,i=B(e.walk,n);return{service:n,title:i.title,...i.description!==void 0?{description:i.description}:{},required:t?!t.optional:!1,defaults:t?t.defaults.map(s=>({...s})):[],integration:o,suppliedBy:Dn(e.catalog,n)}}import{existsSync as Ln,readFileSync as Wn,realpathSync as $n}from"fs";import{isAbsolute as Lt,join as Wt,relative as Bt,resolve as _n,sep as Kt}from"path";function Ke(e){let n=[];for(let[r,t]of Object.entries(e.catalog.providers)){let o=Object.values(t);o.length!==0&&n.push({provider:r,local:o.every(i=>i.local===!0),owner:o[0].owner,...o[0].title?{title:o[0].title}:{},...o[0].description?{description:o[0].description}:{}})}return{providers:n.sort((r,t)=>r.provider.localeCompare(t.provider))}}function ze(e,n,r){let t=e.catalog.providers[n];if(!t)throw new A("PROVIDER_NOT_FOUND",404,`厂商 ${n} 不 ∈ catalog(内联声明厂商无包级档案——身份与表单经组合端点暴露)`);let o={};for(let s of Object.values(t))for(let l of s.services)(o[l]??={implementations:[]}).implementations.push({implementation:s.implementation,credentialType:s.credentialType});for(let[s,l]of Object.entries(o)){let d=B(e.walk,s);l.title=d.title,d.description!==void 0&&(l.description=d.description)}if(r?.has("integrationSchemas"))for(let[s,l]of Object.entries(o))l.integrationSchemas={configSchema:J(e,n,s)};let i=Object.values(t);return{provider:n,local:i.every(s=>s.local===!0),owner:i[0].owner,...i[0].title?{title:i[0].title}:{},...i[0].description?{description:i[0].description}:{},services:o}}function Ue(e,n,r){let t=e.catalog.providers[n],o=e.integrations?.services??{},i=[];if(t)for(let f of Object.values(t))f.services.includes(r)&&i.push({implementation:f.implementation,credentialType:f.credentialType});let s=o[r]?.provider,l=s&&typeof s=="object"&&s.provider===n?s:void 0;if(i.length===0&&!l)throw t?new A("SUPPLY_NOT_FOUND",404,`厂商 ${n} 未供给服务 ${r}(AI 帮我实现流:PUT 显式绑定后实施)`):new A("PROVIDER_NOT_FOUND",404,`厂商 ${n} 完全未知(不 ∈ catalog 且无任何内联声明)`);i.length===0&&l&&i.push({implementation:o[r]?.implementation??`${n}-inline@1`,credentialType:l.credentialType});let d=J(e,n,r,l?s?.configSchema:void 0);return{provider:n,service:r,implementations:i,integrationSchemas:{configSchema:d}}}function J(e,n,r,t){let o=e.walk.serviceSchemas[`${n}\0${r}`];return o?Je(e.appDir,o.packageDir,o.configSchema):typeof t=="string"?zt(e.appDir,t):null}function Je(e,n,r){if(!r)return null;let t=Wt(n,r);if(!Ln(t))return null;try{return JSON.parse(Wn(t,"utf8"))}catch{return null}}function zt(e,n){let r=_n(e,"config","schemas"),t=_n(e,n),o=Bt(r,t);if(o===""||o.startsWith("..")||Lt(o))throw new A("VALIDATION_FAILED",400,"configSchema 引用必须落在 config/schemas/ 内(禁路径逃逸)",["provider.configSchema"]);if(!Ln(t))return null;let i,s;try{i=$n(r),s=$n(t)}catch{return null}if(s!==i&&!s.startsWith(i+Kt))throw new A("VALIDATION_FAILED",400,"configSchema 引用经 symlink 逃逸出 config/schemas/(realpath 复核拒绝)",["provider.configSchema"]);try{return JSON.parse(Wn(t,"utf8"))}catch{return null}}function Bn(e){return{version:e.version,evaluation:e.evaluation,strictValidation:e.strictValidation,notes:[...e.notes]}}function Kn(e,n,r){let t=e.integrations,o=_(n),i=t?.services?.[n],s=i?.instances?.[r]??i?.instances?.["*"];return s&&s.provider!==void 0?"instance":i?.provider!==void 0?"service":L(t,o).layer==="module"?"module":typeof t?.provider=="string"&&t.provider.length>0?"app":null}function zn(e,n,r,t,o){let i=n.resolveEffectiveService(e.integrations,r,t,o);if(i.status==="ok"&&i.effective){let s=i.effective.provider,l=typeof s=="string"?s:String(s?.provider??"");return{status:"ok",provider:l,implementation:i.effective.implementation,effective:{provider:l,implementation:i.effective.implementation,...i.effective.config!==void 0?{config:{...i.effective.config}}:{},...i.effective.credentialRef!==void 0?{credentialRef:i.effective.credentialRef}:{},layer:Kn(e,r,t)??"app"}}}return i.status==="binding-unresolved"?{status:"binding-unresolved",statusMessage:i.message}:{status:i.status}}function Ye(e){let n=e.contracts.module;if(!n.resolveEffectiveService||!n.normalizeInstances)throw new A("CONTRACTS_NOT_RESOLVED",503,"contracts 求值面缺席(契约包形态异常)——重新安装或升级应用 @tbox.cn/app-contracts 后重试");return n}function He(e,n){let r=Ye(n),{integrations:t,catalog:o}=n,i=r.buildSupplyLookup(o),s=t,d=r.normalizeInstances({instances:s?.instances,defaultInstanceId:s?.defaultInstanceId}).defaultInstanceId??"*",f=zn(n,r,e,d,i),S=Kn(n,e,d),p=n.integrations?.services?.[e]?.provider,w=f.provider??(typeof p=="string"?p:typeof p=="object"&&p?String(p.provider):void 0),C=new Set(Object.keys(n.catalog.providers)),g=w!==void 0&&C.has(w)?Ut(n.catalog,w,e):void 0,c=o.services[e],u=c!==void 0?!c.optional:void 0,m=c?.owners[0];return{status:f.status,...f.statusMessage?{statusMessage:f.statusMessage}:{},...w!==void 0?{provider:w}:{},...w!==void 0&&S!==null?{layer:S}:{},...g!==void 0?{supplied:g}:{},...m!==void 0?{module:m}:{},...u!==void 0?{required:u}:{}}}function Ut(e,n,r){return Re(e,n,r)}function ae(e,n,r){let t=new Set([...e.walk.vocabulary,...Object.keys(e.catalog.services)]),o=e.integrations?.services??{};for(let s of Object.keys(o))t.add(s);let i={};for(let s of[...t].sort())r&&!r.includes(s)||(i[s]=He(s,e));return{contracts:Bn(e.contracts),resolutions:i,issues:n}}function Ze(e,n,r){let t=Ye(n),o=t.buildSupplyLookup(n.catalog),i=n.integrations,l=t.normalizeInstances({instances:i?.instances,defaultInstanceId:i?.defaultInstanceId}).instances.map(c=>c.id),d=n.integrations?.services?.[e],f=d?.instances?Object.keys(d.instances):void 0,S;l.length>0?(S=[...l],f?.includes("*")&&S.push("*")):f!==void 0&&f.length>0?S=f.includes("*")?["*"]:f:S=[];let p=S.map(c=>{let u=zn(n,t,e,c,o);return{instanceId:c,status:u.status,...u.statusMessage?{statusMessage:u.statusMessage}:{},...u.effective?{effective:u.effective}:{}}}),w=Jt(n,e),g={...He(e,n),instances:p,inheritance:w};return{contracts:Bn(n.contracts),resolution:g,issues:r.filter(c=>c.service===e)}}function Jt(e,n){let r=e.integrations,t=_(n),o=r?.services?.[n],i=e.integrations,l=Ye(e).normalizeInstances({instances:i?.instances,defaultInstanceId:i?.defaultInstanceId}).defaultInstanceId??"*",d=o?.instances?.[l]??o?.instances?.["*"],f=L(r,t);return[{layer:"app",...r?.provider?{provider:r.provider}:{}},{layer:"module",...f.layer==="module"&&f.provider?{provider:f.provider}:{}},{layer:"service",...typeof o?.provider=="string"?{provider:o.provider}:{},...o?.implementation?{implementation:o.implementation}:{}},{layer:"instance",...d?.provider?{provider:d.provider}:{},...d?.implementation?{implementation:d.implementation}:{}}]}function qe(e,n,r){if(n===null)return null;let t={};for(let o of r)t[o]={configSchema:J(e,n,o)};return{provider:n,services:t}}function X(e){return e===null||typeof e!="object"?JSON.stringify(e??null):Array.isArray(e)?`[${e.map(X).join(",")}]`:`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${X(e[r])}`).join(",")}}`}var Yt="\0no-enum";function Ht(e){let n=e.enum;return Array.isArray(n)?`[${[...new Set(n.map(X))].sort().join(",")}]`:Yt}function Zt(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let n=e.type;return n===void 0?null:X(n)}function qt(e){let n=e.map(t=>Zt(t.subschema));if(n.some(t=>t===null)||new Set(n).size>1)return null;if(n[0]==='"object"'){let t=X(e[0].subschema);return e.every(o=>X(o.subschema)===t)?e[0].subschema:null}return new Set(e.map(t=>Ht(t.subschema))).size===1?e[0].subschema:null}function Un(e,n){let r=[],t=!0,o=new Map;for(let[s,l]of Object.entries(e.services)){let d=l.configSchema;if(d===null){r.push(s);continue}if(!d||typeof d!="object"||Array.isArray(d))continue;let f=d;f.additionalProperties===!1&&(t=!1);let S=f.properties;if(!S||typeof S!="object"||Array.isArray(S))continue;let p=Array.isArray(f.required)?f.required:[];for(let w of Object.keys(S)){let C=o.get(w)??[];C.push({service:s,subschema:S[w],required:p.includes(w)}),o.set(w,C)}}let i=[];for(let[s,l]of o)i.push({key:s,schema:qt(l),sources:l.map(({service:d,required:f})=>({service:d,required:f}))});return{provider:e.provider,schemaless:r,unsupplied:[...n?.unsupplied??[]],additionalPropertiesAllowed:t,fields:i}}function Jn(e,n,r,t){let o=typeof t=="string"&&t.length>0?t:void 0;if(e==="app"){if(o!==void 0)return o;let l=n.integrations?.provider;return typeof l=="string"&&l.length>0?l:null}let i=n.walk.modules.find(l=>l.id===r);if(!i)return null;let s=H(n.walk,i);return s.writable?o!==void 0?o:L(n.integrations,s.domainKey).provider:null}var Yn={integrationSchemas:null,integrationFieldRegistry:null};function Ge(e,n){let r=Jn("app",e,void 0,n);if(r===null)return Yn;let t=qe(e,r,mn(e.catalog,r));return{integrationSchemas:t,integrationFieldRegistry:Un(t)}}function Qe(e,n,r){let t=Jn("module",e,n,r),o=e.walk.modules.find(d=>d.id===n);if(t===null||!o)return Yn;let i=(o.descriptor.contributes.services??[]).map(d=>d.service),s=d=>Re(e.catalog,t,d),l=qe(e,t,i.filter(s));return{integrationSchemas:l,integrationFieldRegistry:Un(l,{unsupplied:[...new Set(i.filter(d=>!s(d)))]})}}function Gt(e){return Ge(e).integrationSchemas}function Qt(e,n){return Qe(e,n).integrationSchemas}function Xe(e,n){let r=e.integrations?.services?.[n]?.provider;if(r===void 0||r===""){let t=L(e.integrations,_(n));return t.provider===null?null:{provider:t.provider,configSchema:J(e,t.provider,n)}}if(typeof r=="string")return{provider:r,configSchema:J(e,r,n)};if(z(r)){let t=r;return{provider:t.provider,configSchema:J(e,t.provider,n,t.configSchema)}}return null}function ce(e,n){if(n===void 0||!n.startsWith("secret://"))return;let r=n.slice(9),t=ne(e,r);if(t)return{type:t.type,ref:n,file:F(r),masked:le(t.values)}}function en(e){let n=e.integrations,r={credential:ce(e.appDir,typeof n?.credentialRef=="string"?n.credentialRef:void 0)??null,byInstance:{}};for(let{id:o}of n?.instances??[]){let i=n?.credentialRefByInstance?.[o];i!==void 0&&(r.byInstance[o]=ce(e.appDir,i)??null)}let t={};for(let[o,i]of Object.entries(n?.services??{})){let s={credential:ce(e.appDir,i.credentialRef)??null,byInstance:{}};for(let[l,d]of Object.entries(i.instances??{}))s.byInstance[l]=ce(e.appDir,d.credentialRef)??null;t[o]=s}return{app:r,services:t}}function nn(e,n){return{types:(n===void 0?Object.keys(e.catalog.credentialTypes):[...new Set(Object.values(e.catalog.providers[n]??{}).map(t=>t.credentialType))]).sort().map(t=>{let o=e.catalog.credentialTypes[t];return{credentialType:t,owner:o?.owner??"",credentialSchema:o?Je(e.appDir,o.packageDir,o.credentialSchema):null}})}}import Xt from"path";var er={app:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],module:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],provider:["integrationSchemas"],service:["integrationSchemas"]};function Ie(e,n){if(!n||n.length===0)return new Set;let r=er[e],t=[...new Set(n)].filter(o=>!r.includes(o));if(t.length>0)throw new A("VALIDATION_FAILED",400,`include 含未知或不适用于本端点的键:${t.join("、")}(白名单:${r.join("、")})`,["include"]);return new Set(n)}var Hn=["integrationSchemas","integrationFieldRegistry"];function Zn(e,n,r){if(!(typeof n!="string"||n.length===0)&&!Hn.some(t=>r.has(t)))throw new A("VALIDATION_FAILED",400,`参数 ${e} 需与表单 include 键(${Hn.join("、")})同现——轴参仅重定向表单层双投影`,[e])}function nr(e,n={}){let r=ke(),t=Promise.resolve(),o={appDir:e,cache:r};function i(c){if(!c.strictValidation)throw new A("CONTRACTS_NOT_RESOLVED",503,Ae(c))}function s(c){return Nn(o,c)}async function l(){let c=await j(e),u=s(c),m=u.integrations;if(m===null)return[];let v={resolveEffectiveService:d(c.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:d(c.module.buildSupplyLookup,"buildSupplyLookup"),moduleDomainOf:d(c.module.moduleDomainOf,"moduleDomainOf"),normalizeInstances:d(c.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:c.module.RESOURCE_TYPE_IDS??[]},b=re(e,u.walk,m,process.env);return Z({contracts:v,integrations:m,supplies:v.buildSupplyLookup(u.catalog),...b})}function d(c,u){if(typeof c!="function")throw new A("CONTRACTS_NOT_RESOLVED",503,`contracts 求值面 ${u} 缺席(形态异常)`);return c}function f(c){let u=t.then(c,c);return t=u.catch(()=>{}),u}let S={async loadModules(){let c=await j(e);return _e(s(c))},async loadModule(c,u){let m=Ie("module",u?.include);Zn("moduleProvider",u?.moduleProvider,m);let v=await j(e),b=s(v),y=Le(b,c);if(m.has("serviceResolutions")&&(y.serviceResolutions=v.evaluation&&v.strictValidation?await l().then(I=>ae(b,I,y.services.map(a=>a.service))):null),m.has("integrationSchemas")||m.has("integrationFieldRegistry")){let I=Qe(b,c,u?.moduleProvider);m.has("integrationSchemas")&&(y.integrationSchemas=I.integrationSchemas),m.has("integrationFieldRegistry")&&(y.integrationFieldRegistry=I.integrationFieldRegistry)}return y},async loadApp(c){let u=Ie("app",c?.include);Zn("appProvider",c?.appProvider,u);let m=await j(e),v=s(m),b=We(v);if(u.has("serviceResolutions")&&(b.serviceResolutions=m.evaluation&&m.strictValidation?await l().then(y=>ae(v,y)):null),u.has("integrationSchemas")||u.has("integrationFieldRegistry")){let y=Ge(v,c?.appProvider);u.has("integrationSchemas")&&(b.integrationSchemas=y.integrationSchemas),u.has("integrationFieldRegistry")&&(b.integrationFieldRegistry=y.integrationFieldRegistry)}return b},async loadService(c,u){let m=Ie("service",u?.include),v=await j(e),b=s(v),y=Be(b,c);return m.has("integrationSchemas")&&(y.integrationSchemas=Xe(b,c)),y},async loadServiceResolutions(c){let u=await j(e);i(u);let m=await l();return ae(s(u),m,c)},async loadServiceResolution(c){let u=await j(e);i(u);let m=await l();return Ze(c,s(u),m)},async loadProviders(){let c=await j(e);return Ke(s(c))},async loadProvider(c,u){let m=Ie("provider",u?.include),v=await j(e);return ze(s(v),c,m)},async loadProviderService(c,u){let m=await j(e);return Ue(s(m),c,u)},async loadCredentials(){let c=await j(e);return en(s(c))},async loadCredentialTypes(c){let u=await j(e);return nn(s(u),c)}},p=Fe(e,{onApplied:n.onApplied,cache:r}),w={async writeAppIntegration(c,u){await p.warmup();let m=await j(e);return i(m),f(()=>p.applyApp(c,u))},async writeModuleIntegration(c,u,m){await p.warmup();let v=await j(e);return i(v),f(()=>p.applyModule(c,u,m))},async writeServiceIntegration(c,u,m){await p.warmup();let v=await j(e);return i(v),f(()=>p.applyService(c,u,m))},async deleteServiceIntegration(c){await p.warmup();let u=await j(e);return i(u),f(()=>p.deleteService(c))}},C={invalidate(){r.invalidate(),be(e)},async resolveContracts(){return j(e)},walkManifests(){return g(e)},parseModuleDescriptor(c){return ee(c)},loadProviderCatalogRaw(){return Te(e)},async readIntegrationsConfig(){return W(e,r)},async writeIntegrationsConfig(c){await p.warmup();let u=await j(e);return i(u),f(()=>tr(e,c,r))},async ensureMockBindings(){await p.warmup();let c=await j(e);return i(c),f(()=>$e(e))},async evaluateIntegrationServices(c){await p.warmup();let u=await j(e);i(u);let m={resolveEffectiveService:d(u.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:d(u.module.buildSupplyLookup,"buildSupplyLookup"),moduleDomainOf:d(u.module.moduleDomainOf,"moduleDomainOf"),normalizeInstances:d(u.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:u.module.RESOURCE_TYPE_IDS??[]};return Z({...c,contracts:m})}};function g(c){return P(c,r)}return{...S,...w,...C}}function tr(e,n,r){let t=Xt.join(e,"config","integrations.json");$(t,`${JSON.stringify(n,null,2)}
9
- `),r.invalidate([t])}export{se as APP_INTEGRATION_NODE_KEYS,A as AppToolkitError,K as SAFE_NAME_PATTERN,St as assertValidModuleId,re as buildPredicateAssembly,Ee as checkInstanceKeys,kt as collectDeclaredModules,Ae as contractsNotResolvedMessage,nr as createAppToolkit,ke as createFileCache,Fe as createWriteCore,Ot as credentialArtifactExists,Q as deepEqual,Y as deriveStem,ce as echoForRef,fn as ensureDir,$e as ensureMockBindings,Pe as evaluateAppIntegrationIssues,Z as evaluateIntegrationServices,Ce as expandEnvVars,Cn as extractModuleIdFromSource,be as invalidateContractsResolver,z as isControlledInlineProvider,In as isValidModuleId,Gt as loadAppIntegrationSchemas,We as loadAppView,nn as loadCredentialTypesView,en as loadCredentialsView,Le as loadModuleDetailView,Qt as loadModuleIntegrationSchemas,_e as loadModulesView,ge as loadProviderCatalog,Te as loadProviderCatalogRaw,ze as loadProviderDetailView,Ue as loadProviderServiceDetailView,Ke as loadProvidersView,Be as loadServiceDetailView,Xe as loadServiceIntegrationSchemas,Ze as loadServiceResolutionDetail,ae as loadServiceResolutionsView,pe as manifestPath,le as maskCredentialValues,on as moduleDependencySchema,ln as moduleDescriptorSchema,tn as pageContribSchema,ee as parseModuleDescriptor,sn as providerSlotContribSchema,Pt as pruneIntegrationBindings,Rn as readAppManifest,je as readAppManifestFull,ne as readCredentialFile,W as readIntegrationsConfig,xn as readIntegrationsStrict,oe as reconcileOrphanCredentials,Sn as refToEnvKey,mt as removeNpmModule,j as resolveContractsForApp,j as resolveContractsForAppExport,qe as resolveLayerIntegrationSchemas,He as resolveServiceSummary,cn as resourceNeedContribSchema,an as serviceNeedContribSchema,F as stemToFilePath,tt as stemToRef,rn as tabContribSchema,yt as updateNpmModule,vt as upsertMiniappContainer,gt as upsertNpmModule,P as walkManifests,ft as writeAppManifest,$ as writeAtomic,xe as writeCredentialFile};
1
+ import{a as je,b as T,c as Te}from"./chunk-WUULQDOV.js";import{z as I}from"zod";var K=/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/,ot=I.object({cardType:I.string(),schemaVersion:I.number().optional()}),gn=I.object({route:I.string(),component:I.string()}),mn=I.object({route:I.string(),label:I.string().optional(),icon:I.string().optional(),order:I.number().optional()}),vn=I.object({id:I.string(),range:I.string().optional(),required:I.boolean().default(!0)}),yn=I.object({service:I.string(),provider:I.string().regex(K,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:I.string(),credentialType:I.string(),local:I.boolean().optional(),configSchema:I.string().optional(),credentialSchema:I.string().optional()}),Sn=I.object({service:I.string(),optional:I.boolean().default(!0),defaults:I.array(I.object({provider:I.string().regex(K,"provider 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)"),implementation:I.string()})).default([]),name:I.string().optional(),description:I.string().optional()}),wn=I.object({service:I.string()}).strict(),hn=I.object({id:I.string(),type:I.string()}),Rn=I.object({schemaVersion:I.number().default(1),id:I.string(),name:I.string().optional(),description:I.string().optional(),hidden:I.boolean().optional(),version:I.string().default("0.0.0"),kind:I.enum(["platform","business","third-party"]).default("business"),risk:I.object({level:I.enum(["high","medium","low"]).default("low"),writeBoundary:I.enum(["sdk-enforced","source"]).default("source")}).default({}),distribution:I.object({defaultMode:I.enum(["hybrid","sdk","codegen","local"]).default("codegen")}).default({}),declare:I.object({handlers:I.array(I.string()).default([]),tools:I.array(I.string()).default([]),cards:I.array(ot).default([]),routes:I.array(I.string()).default([]),pages:I.array(gn).default([]),tabs:I.array(mn).default([]),providers:I.object({slots:I.array(yn).default([])}).default({}),owns:I.array(wn).default([]),consumes:I.array(Sn).default([]),resources:I.array(hn).default([])}).default({}),dependencies:I.object({modules:I.array(vn).default([])}).default({}),env:I.array(I.string()).default([])}).strict();function st(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let n=[],r=e;"contributes"in r&&n.push("(root): manifest 旧键 `contributes` 已更名 `declare`(v6 声明面)——codegen 副本经 `module update --source` 重新生成 / sdk 模式升级模块包 / 手改两键");let t=r.declare;t&&typeof t=="object"&&!Array.isArray(t)&&"services"in t&&n.push("declare: manifest 旧键 `declare.services` 已更名 `declare.consumes`(消费关系定向化)——同上三路径升级"),!("id"in r)&&"name"in r&&n.push("(root): manifest 标识键 `name` 已更名 `id`(v7 词汇统一)——codegen 副本经 `module update --source` 重新生成 / sdk 模式升级模块包 / 手改两键");let i=t&&typeof t=="object"&&!Array.isArray(t)?t:void 0,s=Array.isArray(i?.consumes)&&i.consumes.some(o=>o!==null&&typeof o=="object"&&"title"in o);return("title"in r||s)&&n.push("(root): manifest 展示名键 `title` 已更名 `name`(v7 词汇统一;declare.consumes[].title 同步改 name)——同上三路径升级"),n}function oe(e){let n=st(e);if(n.length>0)return{ok:!1,errors:n,legacy:!0};let r=Rn.safeParse(e);return r.success?{ok:!0,value:r.data}:{ok:!1,errors:r.error.issues.map(t=>`${t.path.join(".")||"(root)"}: ${t.message}`)}}var at=/\$\$?\{([A-Z][A-Z0-9_]*)(?::-([^}]*))?\}/g;function In(e){return JSON.stringify(e).slice(1,-1)}function Ne(e,n=process.env){let r=[],t=e.replace(at,(i,s,o)=>{if(i.startsWith("$$"))return i.slice(1);let d=n[s];return d!==void 0?In(d):o!==void 0?In(o):(r.push(s),i)});return r.length>0?{missing:r}:{text:t,missing:[]}}import{mkdirSync as ct,existsSync as kn,readFileSync as dt,writeFileSync as lt}from"fs";import{dirname as ut,join as bn}from"path";function ge(e){let n={};for(let[r,t]of Object.entries(e)){if(typeof t!="string"){n[r]=null;continue}n[r]=t.length<=4?"****":`${t.slice(0,2)}****`}return n}var M=class extends Error{code;httpStatus;fields;constructor(n,r,t,i){super(t),this.name="AppToolkitError",this.code=n,this.httpStatus=r,this.fields=i}};function Pe(e){return e.notes.length>0?e.notes[0]:e.version===null?"contracts 不可解析(未安装)——检查应用依赖安装后重试":e.strictValidation?"contracts workspace 源码态未构建——执行 pnpm --filter @tbox.cn/app-contracts build 后重试":`contracts ${e.version} 无严格校验面(需 ≥0.9.0)——升级应用 @tbox.cn/app-contracts 依赖后可用`}function me(e,n){if(n!==void 0&&(n.includes("/")||n.includes("\\")||n.includes("..")))throw new M("VALIDATION_FAILED",400,`凭据 stem 派生输入含路径敌对字符(${e})——拒绝派生`)}function Q(e){if(me("provider",e.provider),me("service",e.service),me("instanceId",e.instanceId),me("domain",e.domain),e.instanceId!==void 0){let n=e.domain??e.service??"global";return`${e.provider}-${e.instanceId}-${n}`}return e.service!==void 0?`${e.provider}-${e.service}`:`${e.provider}-global`}function pt(e){return`secret://${e}`}function _(e){return`config/credentials/${e}.json`}function se(e,n){let r=bn(e,_(n));if(!kn(r))return null;try{let t=JSON.parse(dt(r,"utf8"));if(typeof t.type!="string")return null;let{type:i,...s}=t,o={};for(let[d,p]of Object.entries(s))typeof p=="string"&&(o[d]=p);return{type:i,values:o}}catch{return null}}function Ve(e,n,r){let t=bn(e,_(n)),i=kn(t);return ct(ut(t),{recursive:!0}),lt(t,`${JSON.stringify({type:r.type,...r.values},null,2)}
2
+ `,"utf8"),i}import{mkdirSync as ft,renameSync as gt,writeFileSync as mt}from"fs";import{dirname as vt}from"path";function $(e,n){Cn(vt(e));let r=`${e}.tmp-${process.pid}-${Date.now()}`;mt(r,n,"utf8"),gt(r,e)}function Cn(e){ft(e,{recursive:!0})}import{existsSync as F,readdirSync as Fe,readFileSync as X}from"fs";import{join as P}from"path";import{existsSync as yt,readFileSync as An,mkdirSync as St,writeFileSync as wt}from"fs";import En from"path";function ve(e){return En.join(e,".tbox","app.json")}function On(e){let n=ve(e);if(!yt(n))return null;try{let r=JSON.parse(An(n,"utf8")),t=r?.templateVersion;return typeof t!="string"||t.trim().length===0?null:{templateVersion:t.trim(),npmModules:Array.isArray(r?.npmModules)?r.npmModules:[]}}catch{return null}}function ht(e,n){let r=ve(e);St(En.dirname(r),{recursive:!0}),wt(r,`${JSON.stringify(n,null,2)}
3
+ `,"utf8")}function De(e){let n=On(e);if(n===null)return null;let r=ve(e);try{let t=JSON.parse(An(r,"utf8"));return{...n,miniappContainers:Array.isArray(t?.miniappContainers)?t.miniappContainers:[]}}catch{return{...n,miniappContainers:[]}}}function Rt(e,n){let r=e.npmModules.filter(t=>t.id!==n.id);return{...e,npmModules:[...r,n]}}function It(e,n){return{...e,npmModules:e.npmModules.filter(r=>r.id!==n)}}function kt(e,n){let r=(e.miniappContainers??[]).filter(t=>t.id!==n.id);return{...e,miniappContainers:[...r,n]}}function bt(e,n,r){return{...e,npmModules:e.npmModules.map(t=>t.id===n?{...t,...r}:t)}}function Mn(e){return/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)&&!e.includes("..")}function Ct(e,n){if(!Mn(e))throw new Error(`非法模块 id "${e}"(来自 ${n}):仅允许小写字母/数字/中划线`)}function xn(e){try{let n=JSON.parse(e);if(!Array.isArray(n.slots))return null;let r=n.slots.filter(i=>typeof i=="string"),t={};if(n.meta&&typeof n.meta=="object"&&!Array.isArray(n.meta))for(let[i,s]of Object.entries(n.meta)){if(!s||typeof s!="object"||Array.isArray(s))continue;let{name:o,description:d}=s,p={};typeof o=="string"&&o.length>0&&(p.name=o),typeof d=="string"&&d.length>0&&(p.description=d),(p.name!==void 0||p.description!==void 0)&&(t[i]=p)}return{slots:r,meta:t}}catch{return null}}function ye(e,n){let r=t=>{try{let i=JSON.parse(t),s=oe(i);if(s.ok)return{kind:"strict",id:s.value.id,version:s.value.version,descriptor:s.value,declare:s.value.declare};if(s.legacy)return{kind:"legacy",detail:s.errors.join("; ")};if(i&&typeof i=="object"&&"declare"in i){let o=i;return{kind:"loose",...typeof o.id=="string"?{id:o.id}:{},declare:{providers:o.declare?.providers,consumes:o.declare?.consumes}}}return null}catch{return null}};if(n)return n.read(e,r)??null;if(!F(e))return null;try{return r(X(e,"utf8"))}catch{return null}}function At(e){let n=P(e,".tbox","app.json");if(!F(n))return[];try{let r=JSON.parse(X(n,"utf8"));return Array.isArray(r.npmModules)?r.npmModules.filter(t=>!!t&&typeof t=="object"&&typeof t.id=="string"&&typeof t.package=="string"):[]}catch{return[]}}function Et(e){let n=P(e,".tbox-dev.local"),r=P(n,"dev-manifest.json");if(!F(r))return[];try{let t=JSON.parse(X(r,"utf8")),i=[];for(let[s,o]of Object.entries(t.redirects??{}))typeof o!="string"||!s.startsWith("@tbox.cn/app-")||i.push({pkg:s,dir:P(n,o)});return i}catch{return[]}}function Ot(e,n){let r=[],t=[e];for(let o of["apps","packages"]){let d=P(e,o);if(F(d))try{for(let p of Fe(d,{withFileTypes:!0}))p.isDirectory()&&t.push(P(d,p.name))}catch{}}let i=new Set,s=(o,d)=>{let p=n?n.read(d,xn):xn(X(d,"utf8"));p!=null&&r.push({dir:o,slots:p.slots,meta:p.meta})};for(let o of t){let d=P(o,"node_modules","@tbox.cn");if(!F(d))continue;let p=[];try{p=Fe(d)}catch{continue}for(let c of p){let f=P(d,c);if(i.has(f))continue;i.add(f);let k=P(f,"service-slots.json"),w=P(f,"src","service-slots.json");F(k)?s(f,k):F(w)&&s(f,w)}}for(let o of t)for(let d of[P(o,"service-slots.json"),P(o,"src","service-slots.json")])F(d)&&s(o,d);return r}function V(e,n){let r=[],t={providers:{},services:{},credentialTypes:{}},i={},s=[],o={},d=new Set,p=(a,m,R,S)=>{for(let u of a){let v=t.providers[u.provider]??={},b=v[u.implementation];b?b.services.includes(u.service)||b.services.push(u.service):(v[u.implementation]={provider:u.provider,implementation:u.implementation,credentialType:u.credentialType,owner:m,...S?.name?{name:S.name}:{},...S?.description?{description:S.description}:{},...u.local?{local:!0}:{},...u.configSchema?{configSchema:u.configSchema}:{},...u.credentialSchema?{credentialSchema:u.credentialSchema}:{},services:[u.service]},t.credentialTypes[u.credentialType]??={owner:m,packageDir:R,...u.credentialSchema?{credentialSchema:u.credentialSchema}:{}});let l=`${u.provider}\0${u.service}`;i[l]||(i[l]={...u.configSchema?{configSchema:u.configSchema}:{},...u.credentialSchema?{credentialSchema:u.credentialSchema}:{},packageDir:R})}},c=a=>a.kind==="strict"?{name:a.descriptor.name,description:a.descriptor.description}:void 0,f=(a,m)=>{for(let R of a){let S=o[R];S===void 0?o[R]=m:S!==m&&s.push({severity:"error",code:"OWNERSHIP_CONFLICT",module:m,message:`服务 ${R} 归属冲突:${S} 与 ${m} 均声明 owns(先声明 ${S} 胜出)——修正 manifest declare.owns 互斥`})}},k=(a,m)=>{a.kind==="legacy"&&s.push({severity:"error",code:"OLD_MANIFEST_KEY",module:m,message:`${m}:${a.detail}`})},w=a=>a.kind==="strict"||a.kind==="loose"?a.declare:null,y=(a,m)=>{let R=a.optional!==!1,S=a.defaults??[],u=t.services[a.service];if(u){u.optional=u.optional&&R;let v=new Set(u.defaults.map(b=>`${b.provider}\0${b.implementation}`));for(let b of S){let l=`${b.provider}\0${b.implementation}`;v.has(l)||(u.defaults.push(b),v.add(l))}u.owners.includes(m)||u.owners.push(m);return}t.services[a.service]={optional:R,defaults:[...S],...a.name?{name:a.name}:{},...a.description?{description:a.description}:{},owners:[m]}};for(let a of At(e)){if(d.has(a.id))continue;let m=P(e,"packages",a.id),R=P(e,"node_modules",...a.package.split("/")),S=ye(P(m,"tbox.module.json"),n)??ye(P(R,"tbox.module.json"),n);if(S?.kind==="legacy"){k(S,a.id),d.add(a.id);continue}if(!S)continue;d.add(a.id);let u=F(P(m,"tbox.module.json"))?m:R,v=w(S);S.kind==="strict"&&r.push({id:a.id,dir:u,pkg:a.mode==="sdk"?a.package:`@app/${a.id}`,descriptor:S.descriptor});let b=v?.providers?.slots??[];b.length&&p(b,a.package,u,c(S));let l=v?.consumes??[];for(let E of l)y(E,a.package);let h=S.kind==="strict"?S.descriptor.declare.owns:[];h.length&&f(h.map(E=>E.service),a.id)}for(let{pkg:a,dir:m}of Et(e)){let R=ye(P(m,"tbox.module.json"),n);if(R?.kind==="legacy"){k(R,a);continue}if(!R?.id||d.has(R.id))continue;d.add(R.id);let S=w(R),u=S?.providers?.slots??[];u.length&&p(u,a,m,c(R));let v=S?.consumes??[];for(let l of v)y(l,a);let b=R.kind==="strict"?R.descriptor.declare.owns:[];b.length&&f(b.map(l=>l.service),R.id)}let A=P(e,"packages");if(F(A)){let a=[];try{a=Fe(A,{withFileTypes:!0}).filter(m=>m.isDirectory()).map(m=>m.name)}catch{}for(let m of a){if(d.has(m))continue;let R=P(A,m),S=ye(P(R,"tbox.module.json"),n);if(S?.kind==="legacy"){k(S,m),d.add(m);continue}if(!S)continue;let u=S.id??m;if(d.has(u))continue;d.add(u);let v=w(S);S.kind==="strict"&&r.push({id:u,dir:R,pkg:`@app/${u}`,descriptor:S.descriptor});let b=v?.providers?.slots??[];b.length&&p(b,`@app/${u}`,R,c(S));let l=v?.consumes??[];for(let E of l)y(E,`@app/${u}`);let h=S.kind==="strict"?S.descriptor.declare.owns:[];h.length&&f(h.map(E=>E.service),u)}}let O=new Set,g={};for(let a of Ot(e,n)){for(let m of a.slots)O.add(m);for(let[m,R]of Object.entries(a.meta))g[m]===void 0&&(g[m]=R)}return{modules:r,catalog:t,serviceSchemas:i,vocabulary:[...O].sort(),slotMeta:g,ownership:o,declarationIssues:s}}function jn(e,n,r){let t=P(e,"src",n,"index.ts");if(!F(t))return!1;try{let i=X(t,"utf8");return new RegExp(`export\\s+const\\s+${r}\\b`).test(i)}catch{return!1}}function Mt(e){let n=P(e,"src","server","index.ts");if(!F(n))return"";try{return X(n,"utf8")}catch{return""}}function Tn(e){return e.match(/declaration\s*:\s*\{[\s\S]*?moduleId\s*:\s*['"]([^'"]+)['"]/)?.[1]}function xt(e){let n=[],r=V(e),t=De(e),i=new Map;for(let s of t?.npmModules??[])i.set(s.id,s.mode);for(let s of r.modules){let o=i.get(s.id)??"local",d=jn(s.dir,"server","serverModule"),p=s.descriptor.declare;n.push({id:s.id,pkg:o==="sdk"?s.pkg:`@app/${s.id}`,mode:o,hasServerEntry:d,hasClientEntry:jn(s.dir,"client","clientModule"),hasCards:(p.cards?.length??0)>0,...d?{moduleId:Tn(Mt(s.dir))}:{}})}return n.sort((s,o)=>s.id.localeCompare(o.id))}function jt(e){return V(e).ownership}function L(e,n){let r=e?.modules?.[n]?.provider;if(typeof r=="string"&&r.length>0)return{provider:r,layer:"module"};let t=e?.provider;return typeof t=="string"&&t.length>0?{provider:t,layer:"app"}:{provider:null,layer:null}}function J(e,n){let r=(n.descriptor.declare.owns??[]).map(t=>t.service).sort();return r.length===0?{writable:!1,reason:"zero-ownership",ownedServices:[]}:{writable:!0,ownedServices:r}}function _e(e,n){return[...new Set(Object.values(e.providers[n]??{}).flatMap(r=>r.services))].sort()}function G(e){if(!e||typeof e!="object")return!1;let n=Object.keys(e),r=new Set(["provider","credentialType","configSchema"]);if(!n.every(i=>r.has(i)))return!1;let t=e;return typeof t.provider=="string"&&t.provider.length>0&&typeof t.credentialType=="string"&&t.credentialType.length>0&&(t.configSchema===void 0||typeof t.configSchema=="string")}function Nn(e,n,r){return e==="*"||r.has(e)?null:{severity:"error",code:"INSTANCE_KEY_NOT_REGISTERED",instance:e,message:`integrations: ${n} 键 ${e} 不在 malls 白名单内(${[...r].join(", ")})`}}function $e(e,n){let r=new Set(n),t=[],i=(s,o)=>{let d=Nn(s,o,r);d&&t.push(d)};for(let s of Object.keys(e.configByInstance??{}))i(s,"configByInstance");for(let s of Object.keys(e.credentialRefByInstance??{}))i(s,"credentialRefByInstance");for(let[s,o]of Object.entries(e.services??{}))for(let d of Object.keys(o.instances??{}))i(d,`services.${s}.instances`);return t}function ee(e){let n=[],r=e.contracts,{integrations:t,suppliedProviders:i,demandedServices:s,supplies:o,malls:d,credentialSchemaMissing:p,vendorConfigKeys:c,vendorGlobalConfigKeys:f,vendorConfigSchemaMissing:k,credentialFileMissing:w,credentialFileType:y,realmSwitchHints:A,moduleResourceNeeds:O,ownership:g,installedModuleIds:a}=e,m=d?new Set(d):void 0;for(let l of A??[])n.push({severity:"warning",code:"REALM_SWITCH_HINT",message:l});let R=new Set(Object.keys(i).map(l=>l.slice(0,l.indexOf("\0"))).filter(l=>l.length>0)),S=(l,h,E,C)=>{if(typeof E?.provider=="string"&&typeof E.implementation=="string"&&E.provider&&E.implementation)return i[ae(E.provider,E.implementation)]?.credentialType;if(typeof h.provider=="string"&&typeof h.implementation=="string")return i[ae(h.provider,h.implementation)]?.credentialType;let x=h.provider?.credentialType;if(typeof x=="string")return x;if(!o)return;let N=C??Object.keys(h.instances??{})[0]??"",j=r.resolveEffectiveService(t,l,N,o,g);if(!(j.status!=="ok"||typeof j.effective.provider!="string"))return i[ae(j.effective.provider,j.effective.implementation)]?.credentialType};if(w||y)for(let[l,h]of Object.entries(t.services))for(let[E,C]of Object.entries(h.instances??{})){if(C.enabled===!1)continue;let x=C.credentialRef??h.credentialRef??t.credentialRefByInstance?.[E]??t.credentialRef;if(typeof x!="string"||!x.startsWith("secret://"))continue;let N=x.slice(9);w?.[N]===!0&&n.push({severity:"error",code:"CREDENTIAL_FILE_MISSING",service:l,instance:E,message:`integrations: 凭据文件缺失 ${N}(${l}@${E} effective ref=${x};档内 config/credentials/ 无此文件)`});let j=y?.[N];if(j){let D=S(l,h,C,E);D&&j!==D&&n.push({severity:"error",code:"CREDENTIAL_TYPE_MISMATCH",service:l,instance:E,message:`integrations: 凭据文件 ${N}.json type=${j} 与绑定 credentialType ${D} 不一致(${l}@${E}——transport 创建期将按 type 选策略)`})}}let u=(l,h)=>{if(!m)return;let E=Nn(l,h,m);E&&n.push(E)};for(let[l]of Object.entries(t.configByInstance??{}))u(l,"configByInstance");for(let[l]of Object.entries(t.credentialRefByInstance??{}))u(l,"credentialRefByInstance");let v=Object.entries(t.services).filter(([,l])=>l.instances==null||l.instances["*"]!=null).map(([l])=>l);if(v.length>0){let l=Object.entries(t.services).filter(([,h])=>h.instances!=null&&h.instances["*"]==null).map(([h])=>h);l.length>0&&n.push({severity:"warning",code:"WILDCARD_ALIGNMENT",message:`integrations: 激活形态不对称(通配:${v.join(", ")};显式键集:${l.join(", ")})——动态 mallId 将在显式键集槽上 INSTANCE_NOT_FOUND(provider 业务限制表达位),确认是否齐步`})}let b=r.normalizeInstances({instances:t.instances,defaultInstanceId:t.defaultInstanceId});b.instances.length>=2&&b.defaultInstanceId===null&&n.push({severity:"warning",code:"MULTI_INSTANCE_NO_DEFAULT",message:`integrations: ${b.instances.length} 个部署实例(${b.instances.map(l=>l.id).join(", ")})均无 defaultInstanceId——无 scope 参数访问将落全局会话(默认商圈不注入)`});for(let[l,h]of Object.entries(t.services)){if(s[l]||n.push({severity:"warning",code:"SLOT_NOT_DECLARED",service:l,message:`integrations: 服务槽 ${l} 无消费方声明(拼写错误或需求方未安装)——若为拆分前旧槽位词汇(member.main/parking.main/promotion.read/shopping-guide.main),参照 cookbook·app-config 槽位迁移配方展开为新槽`}),typeof h.provider=="string"?typeof h.implementation=="string"&&!i[ae(h.provider,h.implementation)]&&n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:l,message:`integrations: provider ${h.provider}/${h.implementation} 未命中已装供给(${l} 槽级)——装对应 provider 包或改绑`}):h.provider!==void 0&&!G(h.provider)&&n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:l,message:`integrations: 内联 provider 超受控形状(${l} 槽级;允许键 provider/credentialType/configSchema)`}),p){let C=S(l,h);C&&p[C]===!0&&n.push({severity:"error",code:"SCHEMA_FILE_MISSING",service:l,message:`integrations: credentialType ${C} 的 schema 引用不存在(${l};manifest 声明指向缺失文件)`})}typeof h.provider=="object"&&typeof h.implementation!="string"&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:l,message:`integrations: 内联厂商声明必须同时提供 implementation(${l} 槽级)`});for(let[C,x]of Object.entries(h.instances??{})){u(C,`services.${l}.instances`);let N=x.provider!==void 0,j=x.implementation!==void 0;if(j&&!N&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:l,instance:C,message:`integrations: 实例级 implementation 需伴随 provider(${l}@${C}——impl-only 禁止,provider 是绑定组头)`}),N&&j){let D=x.provider,W=x.implementation;typeof D=="string"&&typeof W=="string"?i[ae(D,W)]||n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:l,instance:C,message:`integrations: 实例级 provider 覆盖 ${D}/${W} 未命中已装供给(${l}@${C})`}):G(D)||n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:l,instance:C,message:`integrations: 实例级内联 provider 超受控形状(${l}@${C})`})}}}for(let[l,h]of[["root",t.provider],...Object.entries(t.modules??{}).map(([E,C])=>[`modules.${E}`,C?.provider])])typeof h!="string"||h.length===0||R.has(h)||n.push({severity:"error",code:"VENDOR_NOT_INSTALLED",module:l.startsWith("modules.")?l.slice(8):void 0,message:`integrations: ${l} provider ${h} 未命中已装供给——装对应 provider 包或 provider use 改绑`});if(o)for(let[l,h]of Object.entries(t.services)){let E=h.instances?Object.keys(h.instances):[""];for(let C of E){let x=r.resolveEffectiveService(t,l,C,o,g);x.status==="binding-unresolved"&&n.push({severity:"error",code:"BINDING_UNRESOLVED",service:l,instance:C||void 0,message:`integrations: ${x.message}`})}}for(let[l,h]of Object.entries(t.services))h.implementation!==void 0&&h.provider===void 0&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:l,message:`integrations: 槽级 implementation 需伴随 provider(${l}——impl-only 禁止,provider 是绑定组头)`});for(let[l,h]of Object.entries(t.modules??{})){if(!(h?.provider!==void 0||h?.config!==void 0))continue;let C=a?!a.has(l):!1,x=0;if(g)for(let j of Object.values(g))j===l&&(x+=1);if(C||!(g===void 0)&&x===0){let j=C?"未安装(键 = install id)":"未声明任何 owns(无模块级配置位)";n.push({severity:"error",code:"MODULE_CONFIG_DEAD",module:l,message:`integrations: modules.${l} 携带 provider/config 但模块${j}(MODULE_CONFIG_DEAD——模块级集成位作用于 declare.owns 服务,改 declare.owns 或删除该节点)`})}}if(c){let l=new Set,h=!1,E=C=>{typeof C!="string"||C.length===0||(c[C]&&l.add(C),!c[C]&&!k?.[C]&&(h=!0),k?.[C]&&(h=!0))};E(t.provider);for(let C of Object.values(t.modules??{}))E(C?.provider);for(let C of Object.values(t.services)){let x=C.provider;E(typeof C.provider=="string"?C.provider:x?.provider)}if(l.size>0&&!h){let C=new Set;for(let j of l)for(let D of c[j]??[])C.add(D);let x=new Set;for(let j of l)for(let D of f?.[j]??[])x.add(D);let N=(j,D,W,Z)=>{for(let[q]of Object.entries(j??{}))(W??C).has(q)?Z&&Z.size>0&&!Z.has(q)&&n.push({severity:"warning",code:"GLOBAL_FIELD_UNDECLARED",message:`integrations: ${D} 键 ${q} 过 schema 校验但未声明 x-tbox-global(不进应用/模块全局表单;已配置值照常生效——如需全局编辑请在 provider schema 标记)`}):n.push({severity:"error",code:"DOMAIN_CONFIG_INVALID",message:`integrations: ${D} 键 ${q} 不在引用厂商(${[...l].join("/")})任何槽 schema properties 内(死配置)`})};N(t.config,"root.config",void 0,x);for(let[j,D]of Object.entries(t.configByInstance??{}))N(D,`root.configByInstance[${j}]`,void 0,x);for(let[j,D]of Object.entries(t.modules??{})){if(!D?.config)continue;let W=L(t,j).provider??void 0;if(W===void 0){N(D.config,`modules.${j}.config`,void 0,x);continue}let Z=c[W];if(!Z||k?.[W])continue;let q=f?.[W];N(D.config,`modules.${j}.config`,new Set(Z),q)}}}for(let[l,h]of Object.entries(s)){let E=t.services[l];if(!E){n.push({severity:"warning",code:"SLOT_NOT_CONFIGURED",service:l,message:`integrations: 服务槽 ${l}(需求方 ${h.owners.join(", ")})未配置${h.optional?"(可选槽)":"(必需槽——模块将走降级链)"}`});continue}let C=Object.entries(E.instances??{}).filter(([,x])=>x.enabled===!1).map(([x])=>x);C.length>0&&n.push({severity:"warning",code:"INSTANCE_DISABLED",service:l,instance:C.join(", "),message:`integrations: ${l} 实例禁用(${C.join(", ")})`})}for(let[l,h]of Object.entries(t.modules??{})){let E=O?.[l];O&&!(l in O)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:l,message:`integrations: modules.${l} 未命中已装模块(键 = install id——检查 .tbox/app.json entry.id / packages/ 目录名)`});for(let[C,x]of Object.entries(h?.resources??{})){let N=x?.type;(typeof N!="string"||!r.RESOURCE_TYPE_IDS.includes(N))&&n.push({severity:"error",code:"RESOURCE_TYPE_UNKNOWN",module:l,message:`integrations: modules.${l}.resources.${C} type 非法(${String(N)};词汇表 = ${r.RESOURCE_TYPE_IDS.join("/")})`}),E&&E.size>0&&!E.has(C)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:l,message:`integrations: modules.${l}.resources.${C} 未被模块 manifest declare.resources 声明`})}}return n}function ae(e,n){return`${e}\0${n}`}import{existsSync as Le,readFileSync as Tt,readdirSync as Nt}from"fs";import{join as Se}from"path";function Vn(e){return e.replaceAll("-","_").toUpperCase()}function Pn(e){if(!Le(e))return null;try{let n=JSON.parse(Tt(e,"utf8"));return n&&typeof n=="object"?n:null}catch{return null}}function Pt(e){let n=new Set,r=e.properties;if(r&&typeof r=="object"&&!Array.isArray(r))for(let t of Object.keys(r))n.add(t);return n}function ce(e,n,r,t=process.env){let i={};for(let[u,v]of Object.entries(n.catalog.providers))for(let[b,l]of Object.entries(v))i[`${u}\0${b}`]={services:[...l.services],owner:l.owner,credentialType:l.credentialType};let s={};for(let[u,v]of Object.entries(n.catalog.services))s[u]={optional:v.optional,owners:[...v.owners]};let o={},d={},p={},c={},f={};for(let u of n.modules){f[u.id]=new Set((u.descriptor.declare.resources??[]).map(v=>v.id));for(let v of u.descriptor.declare.providers?.slots??[]){if(v.configSchema){let b=Pn(Se(u.dir,v.configSchema));if(b){let l=o[v.provider]??=new Set,h=d[v.provider]??=new Set;for(let C of Pt(b))l.add(C);let E=b.properties;if(E&&typeof E=="object"&&!Array.isArray(E))for(let[C,x]of Object.entries(E))x&&typeof x=="object"&&x["x-tbox-global"]===!0&&h.add(C)}else p[v.provider]=!0}v.credentialSchema&&!Le(Se(u.dir,v.credentialSchema))&&(c[v.credentialType]=!0)}}let k={},w=new Set,y=Se(e,"config","credentials");if(Le(y))for(let u of Nt(y)){if(!u.endsWith(".json"))continue;let v=u.slice(0,-5);w.add(v);let b=Pn(Se(y,u));b&&typeof b.type=="string"&&(k[v]=b.type)}let A=r,O=[],g=u=>{typeof u=="string"&&u.startsWith("secret://")&&O.push(u)};for(let u of Object.values(A.services??{}))if(u&&typeof u=="object"){g(u.credentialRef);for(let v of Object.values(u.instances??{}))v&&typeof v=="object"&&g(v.credentialRef)}for(let u of Object.values(A.credentialRefByInstance??{}))g(u);g(A.credentialRef);let a={};for(let u of O){let v=u.slice(9);t[Vn(v)]===void 0&&(w.has(v)||(a[v]=!0))}let m=[];for(let[u,v]of Object.entries(A.services??{})){let b=v&&typeof v=="object"&&typeof v.provider=="string"?v.provider:void 0;for(let[l,h]of Object.entries((v&&typeof v=="object"?v.instances:void 0)??{})){let E=h&&typeof h=="object"&&typeof h.provider=="string"?h.provider:void 0;b&&E&&E!==b&&m.push(`integrations: ${u}@${l} 实现覆盖跨厂商(${b} → ${E})——凭据域切换,确认该 mall 对应凭据在场`)}}let S=((Array.isArray(A.instances)?A.instances:void 0)??[]).map(u=>u&&typeof u=="object"&&typeof u.id=="string"?u.id:void 0).filter(u=>typeof u=="string");return{suppliedProviders:i,demandedServices:s,credentialFileMissing:a,credentialFileType:k,credentialSchemaMissing:c,vendorConfigKeys:o,vendorGlobalConfigKeys:d,vendorConfigSchemaMissing:p,realmSwitchHints:m,moduleResourceNeeds:f,...S.length>0?{malls:S}:{},ownership:n.ownership,installedModuleIds:new Set([...n.modules.map(u=>u.id),...new Set(Object.values(n.ownership))])}}import{existsSync as Hr,readFileSync as Yr}from"fs";import{join as qr,resolve as Qr}from"path";function We(e){return V(e).catalog}function we(e){let n=V(e).catalog,r={};for(let[s,o]of Object.entries(n.providers)){r[s]={};for(let[d,p]of Object.entries(o))r[s][d]={provider:p.provider,implementation:p.implementation,credentialType:p.credentialType,owner:p.owner,...p.local?{local:!0}:{},...p.configSchema?{configSchema:p.configSchema}:{},...p.credentialSchema?{credentialSchema:p.credentialSchema}:{},services:[...p.services]}}let t={};for(let[s,o]of Object.entries(n.services))t[s]={optional:o.optional,defaults:o.defaults.map(d=>({...d})),owners:[...o.owners]};let i={};for(let[s,o]of Object.entries(n.credentialTypes))i[s]={owner:o.owner,...o.credentialSchema?{credentialSchema:o.credentialSchema}:{}};return{providers:r,services:t,credentialTypes:i}}async function Be(e,n,r,t=process.env){let i=r.module,s=V(e),o=i.buildSupplyLookup(we(e)),d=ce(e,s,n,t);return ee({contracts:i,integrations:n,supplies:o,...d})}import{existsSync as Wt,rmSync as Bt}from"fs";import{join as Ut}from"path";import{existsSync as Vt,readFileSync as Dt}from"fs";import{join as Dn}from"path";var Ft=Dn("config","integrations.json");function B(e,n){let r=Dn(e,Ft),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!Vt(r))return null;try{return t(Dt(r,"utf8"))}catch{return null}}async function Fn(e,n){let r=await T(e),t=B(e,n);if(t===null)return{config:null,strict:!1,contracts:r};if(r.strictValidation&&r.module.parseIntegrationsConfig)try{return{config:r.module.parseIntegrationsConfig(t),strict:!0,contracts:r}}catch(i){if(i instanceof Error&&Array.isArray(i.issues)){let s=i.issues.filter(o=>Array.isArray(o.path)).map(o=>o.path.map(String).join(".")).filter(o=>o.length>0);throw new M("VALIDATION_FAILED",400,"integrations.json 校验失败",s.length>0?s:void 0)}throw new M("VALIDATION_FAILED",400,i instanceof Error?i.message:String(i))}return{config:t,strict:!1,contracts:r}}function de(e,n,r){return e.includes(r)||n.includes(r)}import{readdirSync as _t,existsSync as he,readFileSync as $t}from"fs";import{join as Re}from"path";function _n(e,n,r){let t=[];if(n){let i=Q({provider:e});t.push({stem:i,ref:`secret://${i}`,input:n})}for(let[i,s]of Object.entries(r??{})){let o=Q({provider:e,instanceId:i});t.push({instanceId:i,stem:o,ref:`secret://${o}`,input:s})}return t}function $n(e,n,r,t,i){let s=[];if(t){let o=Q({provider:e,service:n});s.push({stem:o,ref:`secret://${o}`,input:t})}for(let[o,d]of Object.entries(i??{})){let p=Q({provider:e,instanceId:o,domain:r});s.push({instanceId:o,stem:p,ref:`secret://${p}`,input:d})}return s}function ze(e,n,r){return n.map(t=>({stem:t.stem,ref:t.ref,overwrote:r?he(Re(e,_(t.stem))):Ve(e,t.stem,t.input)}))}function Lt(e,n){return he(Re(e,_(n)))}function Ue(e,n){if(typeof e=="string"){e.startsWith("secret://")&&n.add(e.slice(9));return}if(Array.isArray(e)){for(let r of e)Ue(r,n);return}if(e&&typeof e=="object")for(let r of Object.values(e))Ue(r,n)}function ne(e){let n=Re(e,"config","credentials"),r=new Set,t=Re(e,"config","integrations.json");if(he(t))try{Ue(JSON.parse($t(t,"utf8")),r)}catch{}let i=[];if(!he(n))return i;let s=[];try{s=_t(n).filter(o=>o.endsWith(".json")).map(o=>o.slice(0,-5))}catch{return i}for(let o of s.sort()){if(r.has(o))continue;let d=se(e,o);i.push({severity:"warning",code:"ORPHANED_CREDENTIAL",message:`${_(o)} 不再被引用(凭据文件保留,可手动清理)`})}return i}function Ie(e){if(typeof e=="string")return e.length>0?e:void 0;if(e&&typeof e=="object"&&G(e)){let n=e.provider;return n.length>0?n:void 0}}async function zt(e){let n=Ut(e,"config","integrations.json"),r=B(e);if(r===null)return{removed:[],orphanCredentials:[],skipped:"not-configured"};let t=await T(e);if(!t.strictValidation)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};let i;try{let y=Ne(JSON.stringify(r),process.env);if(y.missing.length>0||y.text===void 0)return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"};i=JSON.parse(y.text)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let s;try{s=await Be(e,i,t,process.env)}catch{return{removed:[],orphanCredentials:[],skipped:"predicate-unavailable"}}let o=V(e),d=new Set(Object.keys(o.catalog.providers)),p=o.ownership,c=structuredClone(r);c.services??={};let f=[];for(let y of s)if(y.severity==="error"){if(y.code==="VENDOR_NOT_INSTALLED")if(y.module){let O=(c.modules??{})[y.module];O?.provider&&(f.push(`modules.${y.module}.provider=${String(O.provider)}`),delete O.provider,Object.keys(O).length===0&&delete c.modules[y.module])}else c.provider&&(f.push(`root.provider=${c.provider}`),delete c.provider);else if(y.code==="MODULE_CONFIG_DEAD"&&y.module){let A=c.modules??{};if(A[y.module]){let O=A[y.module],g=[O.provider!==void 0?"provider":void 0,O.config!==void 0?"config":void 0,O.resources!==void 0?"resources":void 0].filter(Boolean);f.push(`modules.${y.module}(${g.join("+")} 整节点)`),delete c.modules[y.module]}}else if(y.code==="BINDING_UNRESOLVED"&&y.service){let A=c.services[y.service];if(!A)continue;let O=p[y.service];if([y.instance?Ie(A.instances?.[y.instance]?.provider):void 0,Ie(A.provider),O!==void 0?Ie(c.modules?.[O]?.provider):void 0,Ie(c.provider)].filter(a=>typeof a=="string").some(a=>d.has(a)))continue;if(y.instance){let a=A.instances;if(!a||!(y.instance in a))continue;delete a[y.instance],f.push(`services.${y.service}.instances.${y.instance}`),Object.keys(a).length===0&&delete A.instances,Object.keys(A).length===0&&delete c.services[y.service]}else delete c.services[y.service],f.push(`services.${y.service}`)}}if(Object.keys(c.services).length===0&&delete c.services,f.length===0)return{removed:f,orphanCredentials:[]};let k=!c.provider&&Object.keys(c.services??{}).length===0&&Object.keys(c.config??{}).length===0&&Object.keys(c.configByInstance??{}).length===0&&!c.credentialRef&&Object.keys(c.credentialRefByInstance??{}).length===0&&(c.instances??[]).length===0&&c.defaultInstanceId==null&&Object.keys(c.modules??{}).length===0;if(!k&&(c.services??={},typeof t.module.parseIntegrationsConfig=="function"))try{t.module.parseIntegrationsConfig(c)}catch{return{removed:[],orphanCredentials:[],skipped:"validation-failed"}}let w=[];return k?Wt(n)&&Bt(n,{force:!0}):$(n,`${JSON.stringify(c,null,2)}
4
+ `),w=ne(e).map(y=>y.message),{removed:f,orphanCredentials:w}}function ke(e,n){let r=e.modules.find(i=>i.id===n);if(r)return r;let t=e.modules.filter(i=>(i.descriptor.name??i.descriptor.id)===n);if(t.length===1)return t[0];throw t.length>1?new M("MODULE_NOT_FOUND",404,`模块展示名「${n}」命中多个模块:${t.map(i=>`${i.descriptor.name}(id=${i.id})`).join(" / ")}——请改用模块 id 寻址`):new M("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块(id / 展示名均未命中)`)}function H(e,n,r){let t=new Set;for(let o of Object.values(e.catalog.providers))for(let d of Object.values(o))for(let p of d.services)t.add(p);if(e.vocabulary.includes(r)||Object.hasOwn(e.catalog.services,r)||t.has(r)||n.includes(r))return r;let i=[],s=o=>{i.includes(o)||i.push(o)};for(let o of e.vocabulary)(e.slotMeta[o]?.name??e.catalog.services[o]?.name)===r&&s(o);for(let[o,d]of Object.entries(e.catalog.services))d.name===r&&s(o);if(i.length===1)return i[0];throw i.length>1?new M("SERVICE_NOT_FOUND",404,`服务展示名「${r}」命中多个服务:${i.join(" / ")}——请改用服务 id 寻址`):new M("SERVICE_NOT_FOUND",404,`服务 ${r} 不在服务词汇(已装契约包 ∪ 已配置)`)}import{existsSync as Bn,readFileSync as Un}from"fs";import{join as te,resolve as Kt}from"path";import Jt from"ajv";var le=["provider","config","configByInstance","credentialRef","credentialRefByInstance","instances","defaultInstanceId"],ue=["provider","config"];var Y=te("config","integrations.json");function re(e,n){if(e===n)return!0;if(Array.isArray(e)&&Array.isArray(n))return e.length!==n.length?!1:e.every((r,t)=>re(r,n[t]));if(e&&n&&typeof e=="object"&&typeof n=="object"){let r=Object.keys(e),t=Object.keys(n);return r.length!==t.length?!1:r.every(i=>re(e[i],n[i]))}return!1}function Ae(e,n){if(typeof e!="string"&&e&&typeof e=="object")for(let[r,t]of Object.entries(e)){if((r==="provider"||r==="instanceId")&&typeof t=="string"&&!K.test(t))throw new M("VALIDATION_FAILED",400,`${r} 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`${n}.${r}`]);Ae(t,`${n}.${r}`)}}function be(e,n,r){if(!(!e||typeof e!="object"||Array.isArray(e))){for(let t of Object.keys(e))if(!(r&&(t==="*"||t==="**"))&&!K.test(t))throw new M("VALIDATION_FAILED",400,`${n} 键 ${t} 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)——进凭据 stem 派生,防路径逃逸`,[n])}}function Ln(e,n,r){if(r==="root"){let t=e.instances;Array.isArray(t)&&t.forEach((i,s)=>{let o=i&&typeof i=="object"?i.id:void 0;if(typeof o=="string"&&!K.test(o))throw new M("VALIDATION_FAILED",400,`instances[${s}].id 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`root.instances[${s}].id`])}),be(e.configByInstance,"root.configByInstance",!1),be(e.credentialRefByInstance,"root.credentialRefByInstance",!1)}else be(e.instances,"services.instances",!0);be(n.credentialsByInstance,"credentialsByInstance",!1)}function Ce(e,n){let r=te(e,Y),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!Bn(r))return null;try{return t(Un(r,"utf8"))}catch{return null}}function Ke(e){let n=(e.instances??[]).map(r=>r.id);return n.length===0?[]:$e(e,n)}function Gt(e,n,r,t){let{catalog:i}=V(e,t),s=i.providers[n];if(!s)return;let o=new Set;for(let d of Object.values(s))(r===void 0||d.services.includes(r))&&o.add(d.credentialType);return o.size===1?[...o][0]:void 0}function Wn(e,n,r,t,i,s){if(typeof t.type!="string"||t.type.length===0)throw new M("VALIDATION_FAILED",400,"凭据 type 缺失或为空字符串",["credentials.type"]);let o=i??Gt(e,n,r,s);if(o!==void 0&&o!=="-"&&t.type!==o)throw new M("VALIDATION_FAILED",400,`凭据 type=${t.type} 与绑定 credentialType ${o} 不一致`,["credentials.type"]);if(r===void 0)return;let{serviceSchemas:d}=V(e,s),p=d[`${n}\0${r}`];if(!p?.credentialSchema)return;let c=Kt(p.packageDir,p.credentialSchema);if(Bn(c))try{let k=new Jt({allErrors:!0}).compile(JSON.parse(Un(c,"utf8")));if(!k({type:t.type,...t.values})){let w=(k.errors??[]).map(y=>`credentials.values.${String(y.instancePath||y.params?.missingProperty||"").replace(/^\//,"")}`);throw new M("VALIDATION_FAILED",400,"凭据字段校验失败(ajv 字段级)",w)}}catch(f){if(f instanceof M)throw f}}function Je(e,n={}){let{onApplied:r,cache:t}=n;function i(c,f,k,w){let y=c!==null,A=f.length>0,O=!w&&y,g=!w&&A;O&&($(te(e,Y),`${JSON.stringify(c,null,2)}
5
+ `),t?.invalidate([te(e,Y)]));let a=O||g;a&&k.push(...ne(e));let m=a&&r!==void 0;m&&r?.();let R=[];return y&&R.push(Y),A&&R.push(...f.map(S=>_(S.stem))),{written:a,restartScheduled:m,files:R,credentials:f,issues:k}}let s;async function o(){s=await T(e)}function d(c,f){return c.filter(k=>Array.isArray(k.path)).map(k=>{let w=k.path.map(String).join(".");return f!==""&&w.startsWith(f)&&w.length>f.length?w.slice(f.length):w}).filter(k=>k.length>0)}function p(c,f,k){let w=s;if(!w||!w.strictValidation||!w.module.parseIntegrationsConfig)throw new M("CONTRACTS_NOT_RESOLVED",503,"contracts 严格校验面不可用(需 ≥0.9)——写路径门控失败(工厂边缘断言应先行拦截)");try{w.module.parseIntegrationsConfig(c)}catch(y){throw y instanceof Error&&Array.isArray(y.issues)?new M("VALIDATION_FAILED",400,"节点 schema 校验失败",d(y.issues,k)):new M("VALIDATION_FAILED",400,y instanceof Error?y.message:String(y))}}return{warmup:o,applyApp(c,f={}){Ae(c,"root"),Ln(c,f,"root");let k=[],w=Ce(e,t),y=w??{services:{}};w===null&&k.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let A={...y};for(let v of le)v in c||delete A[v];for(let[v,b]of Object.entries(c))A[v]=b;let O=typeof A.provider=="string"?A.provider:"app",g=_n(O,f.credentials,f.credentialsByInstance);for(let v of g)Wn(e,O,void 0,v.input,void 0,t);let a=g.find(v=>v.instanceId===void 0);if(f.credentials&&a&&(A.credentialRef=a.ref),f.credentialsByInstance){let v={...A.credentialRefByInstance??{}};for(let b of g)b.instanceId!==void 0&&(v[b.instanceId]=b.ref);A.credentialRefByInstance=v}let m=f.credentials!==void 0||f.credentialsByInstance!==void 0,R=re(w,A);if(R&&!m)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:k};p(A,k,"");let S=f.dryRun===!0,u=ze(e,g,S);return k.push(...Ke(A)),i(R?null:A,u,k,f.dryRun)},applyModule(c,f,k={}){Ae(f,"root");let{modules:w,catalog:y,ownership:A}=V(e,t),O=w.find(l=>l.id===c);if(!O)throw new M("MODULE_NOT_FOUND",404,`模块 ${c} 非已装模块`);if(!J({modules:w,catalog:y,ownership:A},O).writable)throw new M("VALIDATION_FAILED",400,`模块 ${c} 未声明任何 declare.owns——无模块级配置位(模块级 provider/config 作用于归属服务)`);let a=[],m=Ce(e,t);if(m===null&&Object.keys(f).length===0)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:a};m===null&&a.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let R=m??{services:{}},S={...R.modules??{}},u={...S[c]??{}};for(let l of Object.keys(f))if(!ue.includes(l))throw new M("VALIDATION_FAILED",400,`模块集成位仅接受 ${ue.join("/")} 键(收到 ${l})`,[l]);let v={...u};for(let l of ue){let h=f[l];h==null||h===""||typeof h=="object"&&!Array.isArray(h)&&Object.keys(h).length===0?delete v[l]:v[l]=h}Object.keys(v).length===0?delete S[c]:S[c]=v;let b={...R,modules:S};return re(m,b)?{written:!1,restartScheduled:!1,files:[],credentials:[],issues:a}:(p(b,a,`modules.${c}.`),a.push(...Ke(b)),i(b,[],a,k.dryRun))},applyService(c,f,k={}){Ae(f,"root"),Ln(f,k,"slot");let w=[],y=Ce(e,t);if(!de(V(e,t).vocabulary,Object.keys(y?.services??{}),c))throw new M("SERVICE_NOT_FOUND",404,`服务 ${c} 不在服务词汇(已装契约包 ∪ 已配置)`);y===null&&w.push({severity:"warning",code:"SKELETON_MATERIALIZED",message:"config/integrations.json 缺席——已物化骨架(写时自动初始化;R13 语义翻转提示)"});let A=y??{services:{}},O={...A.services??{}},g={...A,services:O};O[c]={...f};let a=f.provider,m=a!==null&&typeof a=="object"?a:void 0,R=typeof a=="string"?a:typeof m?.provider=="string"?m.provider:"app",S=c.includes(".")?c.slice(0,c.indexOf(".")):c,u=$n(R,c,S,k.credentials,k.credentialsByInstance);for(let x of u)Wn(e,R,c,x.input,typeof m?.credentialType=="string"?m.credentialType:void 0,t);let v=O[c],b=u.find(x=>x.instanceId===void 0);if(k.credentials&&b&&(v.credentialRef=b.ref),k.credentialsByInstance){let x={...v.instances??{}};for(let N of u){if(N.instanceId===void 0)continue;let j={...x[N.instanceId]??{}};j.credentialRef=N.ref,x[N.instanceId]=j}v.instances=x}let l=k.credentials!==void 0||k.credentialsByInstance!==void 0,h=re(y,g);if(h&&!l)return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:w};p(g,w,`services.${c}.`);let E=k.dryRun===!0,C=ze(e,u,E);return w.push(...Ke(g)),i(h?null:g,C,w,k.dryRun)},deleteService(c){let f=[],k=Ce(e,t);if(!de(V(e,t).vocabulary,Object.keys(k?.services??{}),c))throw new M("SERVICE_NOT_FOUND",404,`服务 ${c} 不在服务词汇(已装契约包 ∪ 已配置)`);let w={...k?.services??{}};if(!(c in w))return{written:!1,restartScheduled:!1,files:[],credentials:[],issues:f};delete w[c];let y={...k??{services:{}},services:w};$(te(e,Y),`${JSON.stringify(y,null,2)}
6
+ `),t?.invalidate([te(e,Y)]),f.push(...ne(e));let A=r!==void 0;return A&&r?.(),{written:!0,restartScheduled:A,files:[Y],credentials:[],issues:f}}}}import{existsSync as Ht}from"fs";import{join as Yt}from"path";function Ge(e){let n=Yt(e,"config","integrations.json");if(Ht(n))return{generated:!1,reason:"in-place",services:[]};let r=[];for(let s of V(e).modules)for(let o of s.descriptor.declare.providers?.slots??[])o.local===!0&&r.push({service:o.service,provider:o.provider,implementation:o.implementation});if(r.length===0)return{generated:!1,reason:"no-local-slots",services:[]};let t={},i=new Set(r.map(s=>s.provider));if(i.size===1){let[s]=i;for(let o of r)t[o.service]={};$(n,`${JSON.stringify({provider:s,services:t},null,2)}
7
+ `)}else{for(let s of r)t[s.service]={provider:s.provider,implementation:s.implementation};$(n,`${JSON.stringify({services:t},null,2)}
8
+ `)}return{generated:!0,reason:"generated",services:r.map(s=>s.service).sort()}}import{existsSync as Zt,readFileSync as qt}from"fs";import{join as Hn}from"path";function zn(e,n){let r=V(e.appDir,e.cache),t=B(e.appDir,e.cache);return{appDir:e.appDir,walk:r,catalog:r.catalog,integrations:t,contracts:n,...e.cache?{cache:e.cache}:{}}}function Kn(e){let n=new Set;for(let r of e.modules){for(let t of r.descriptor.declare.owns??[])n.add(t.service);for(let t of r.descriptor.declare.consumes??[])n.add(t.service);for(let t of r.descriptor.declare.providers?.slots??[])n.add(t.service)}return n}function Ee(e,n,r){let t=e.providers[n];return t?Object.values(t).some(i=>i.services.includes(r)):!1}function Jn(e,n){let r=[];for(let[t,i]of Object.entries(e.providers))Object.values(i).some(s=>s.services.includes(n))&&r.push(t);return r.sort()}function U(e,n){let r=e.slotMeta[n],t=e.catalog.services[n],i=r?.name??t?.name??n,s=r?.description??t?.description;return{name:i,...s!==void 0?{description:s}:{}}}var Qt=Hn("config","knowledge.json");function Xt(e,n,r){let i=r[n]?.resources;if(!i||typeof i!="object"||Array.isArray(i))return null;let s=Hn(e.appDir,Qt),o={};if(Zt(s))try{o=(e.cache?.read(s,c=>JSON.parse(c))??JSON.parse(qt(s,"utf8"))).knowledge_bases??{}}catch{o={}}let d={};for(let[p,c]of Object.entries(i)){if(!c||typeof c!="object"||Array.isArray(c))continue;let f=c,k=f.type==="knowledge"?"knowledge":String(f.type??"knowledge"),w=typeof f.datasetId=="string"&&f.datasetId!==""?f.datasetId:void 0,y=typeof f.ref=="string"&&f.ref!==""?f.ref:void 0,A=w??(y!==void 0&&typeof o[y]?.datasetId=="string"?o[y].datasetId:null),O={type:k,...w!==void 0?{datasetId:w}:{},...y!==void 0?{ref:y}:{},resolvedDatasetId:A,...typeof f.topK=="number"?{topK:f.topK}:{},...typeof f.scoreThreshold=="number"?{scoreThreshold:f.scoreThreshold}:{}};d[p]=O}return Object.keys(d).length>0?d:null}function Gn(e){return e.replace(/^@tbox\.cn\/app-/,"").replace(/^@[^/]+\//,"")}function er(e){return Gn(e.id).startsWith("provider-")||Gn(e.pkg).startsWith("provider-")}function He(e,n={}){return{modules:e.walk.modules.filter(t=>!er(t)).filter(t=>n.includeHidden===!0||t.descriptor.hidden!==!0).map(t=>({id:t.id,name:t.descriptor.name??t.descriptor.id,description:t.descriptor.description??"",...t.descriptor.hidden===!0?{hidden:!0}:{}})).sort((t,i)=>t.id.localeCompare(i.id))}}function Ye(e,n){let r=e.walk.modules.find(c=>c.id===n);if(!r)throw new M("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块`);let t=(r.descriptor.declare.consumes??[]).map(c=>{let f=U(e.walk,c.service);return{service:c.service,name:f.name,...f.description!==void 0?{description:f.description}:{},required:c.optional===!1}}),i=J(e.walk,r),s=e.integrations?.modules??{},o=s[n],d=o?{...typeof o.provider=="string"?{provider:o.provider}:{},...o.config&&typeof o.config=="object"&&!Array.isArray(o.config)?{config:o.config}:{}}:null,p=L(e.integrations,n);return{name:r.descriptor.name??r.descriptor.id,description:r.descriptor.description??"",...r.descriptor.hidden===!0?{hidden:!0}:{},ownedServices:i.ownedServices,integration:d,resources:Xt(e,n,s),binding:{provider:p.provider,layer:p.layer},configEditable:i.writable,services:t}}function Ze(e){let n=Kn(e.walk),r=e.walk.vocabulary.filter(s=>!n.has(s)).map(s=>{let o=U(e.walk,s);return{service:s,name:o.name,...o.description!==void 0?{description:o.description}:{},required:!1}}),t=e.integrations,i=null;if(t){let s={};for(let o of le)o in t&&(s[o]=t[o]);i=s}return{services:r,integration:i}}function qe(e,n){let r=e.integrations?.services??{},t=e.catalog.services[n];if(!de(e.walk.vocabulary,Object.keys(r),n))throw new M("SERVICE_NOT_FOUND",404,`服务 ${n} 不在服务词汇(已装契约包 ∪ 已配置)`);let i=r[n]??null,s=U(e.walk,n);return{service:n,name:s.name,...s.description!==void 0?{description:s.description}:{},required:t?!t.optional:!1,defaults:t?t.defaults.map(o=>({...o})):[],integration:i,suppliedBy:Jn(e.catalog,n)}}import{existsSync as qn,readFileSync as Qn,realpathSync as Yn}from"fs";import{isAbsolute as nr,join as tr,relative as rr,resolve as Zn,sep as ir}from"path";function Qe(e){let n=[];for(let[r,t]of Object.entries(e.catalog.providers)){let i=Object.values(t);i.length!==0&&n.push({provider:r,local:i.every(s=>s.local===!0),owner:i[0].owner,...i[0].name?{name:i[0].name}:{},...i[0].description?{description:i[0].description}:{}})}return{providers:n.sort((r,t)=>r.provider.localeCompare(t.provider))}}function Xe(e,n,r){let t=e.catalog.providers[n];if(!t)throw new M("PROVIDER_NOT_FOUND",404,`厂商 ${n} 不 ∈ catalog(内联声明厂商无包级档案——身份与表单经组合端点暴露)`);let i={};for(let o of Object.values(t))for(let d of o.services)(i[d]??={implementations:[]}).implementations.push({implementation:o.implementation,credentialType:o.credentialType});for(let[o,d]of Object.entries(i)){let p=U(e.walk,o);d.name=p.name,p.description!==void 0&&(d.description=p.description)}if(r?.has("integrationSchemas"))for(let[o,d]of Object.entries(i))d.integrationSchemas={configSchema:z(e,n,o)};let s=Object.values(t);return{provider:n,local:s.every(o=>o.local===!0),owner:s[0].owner,...s[0].name?{name:s[0].name}:{},...s[0].description?{description:s[0].description}:{},services:i}}function en(e,n,r){let t=e.catalog.providers[n],i=e.integrations?.services??{},s=[];if(t)for(let c of Object.values(t))c.services.includes(r)&&s.push({implementation:c.implementation,credentialType:c.credentialType});let o=i[r]?.provider,d=o&&typeof o=="object"&&o.provider===n?o:void 0;if(s.length===0&&!d)throw t?new M("SUPPLY_NOT_FOUND",404,`厂商 ${n} 未供给服务 ${r}(AI 帮我实现流:PUT 显式绑定后实施)`):new M("PROVIDER_NOT_FOUND",404,`厂商 ${n} 完全未知(不 ∈ catalog 且无任何内联声明)`);s.length===0&&d&&s.push({implementation:i[r]?.implementation??`${n}-inline@1`,credentialType:d.credentialType});let p=z(e,n,r,d?o?.configSchema:void 0);return{provider:n,service:r,implementations:s,integrationSchemas:{configSchema:p}}}function z(e,n,r,t){let i=e.walk.serviceSchemas[`${n}\0${r}`];return i?nn(e.appDir,i.packageDir,i.configSchema):typeof t=="string"?or(e.appDir,t):null}function nn(e,n,r){if(!r)return null;let t=tr(n,r);if(!qn(t))return null;try{return JSON.parse(Qn(t,"utf8"))}catch{return null}}function or(e,n){let r=Zn(e,"config","schemas"),t=Zn(e,n),i=rr(r,t);if(i===""||i.startsWith("..")||nr(i))throw new M("VALIDATION_FAILED",400,"configSchema 引用必须落在 config/schemas/ 内(禁路径逃逸)",["provider.configSchema"]);if(!qn(t))return null;let s,o;try{s=Yn(r),o=Yn(t)}catch{return null}if(o!==s&&!o.startsWith(s+ir))throw new M("VALIDATION_FAILED",400,"configSchema 引用经 symlink 逃逸出 config/schemas/(realpath 复核拒绝)",["provider.configSchema"]);try{return JSON.parse(Qn(t,"utf8"))}catch{return null}}function Xn(e){return{version:e.version,evaluation:e.evaluation,strictValidation:e.strictValidation,notes:[...e.notes]}}function et(e,n,r){let t=e.integrations,i=t?.services?.[n],s=i?.instances?.[r]??i?.instances?.["*"];if(s&&s.provider!==void 0)return"instance";if(i?.provider!==void 0)return"service";let o=e.walk.ownership[n];return o!==void 0&&L(e.integrations,o).layer==="module"?"module":typeof t?.provider=="string"&&t.provider.length>0?"app":null}function nt(e,n,r,t,i){let s=n.resolveEffectiveService(e.integrations,r,t,i);if(s.status==="ok"&&s.effective){let o=s.effective.provider,d=typeof o=="string"?o:String(o?.provider??"");return{status:"ok",provider:d,implementation:s.effective.implementation,effective:{provider:d,implementation:s.effective.implementation,...s.effective.config!==void 0?{config:{...s.effective.config}}:{},...s.effective.credentialRef!==void 0?{credentialRef:s.effective.credentialRef}:{},layer:et(e,r,t)??"app"}}}return s.status==="binding-unresolved"?{status:"binding-unresolved",statusMessage:s.message}:{status:s.status}}function tn(e){let n=e.contracts.module;if(!n.resolveEffectiveService||!n.normalizeInstances)throw new M("CONTRACTS_NOT_RESOLVED",503,"contracts 求值面缺席(契约包形态异常)——重新安装或升级应用 @tbox.cn/app-contracts 后重试");return n}function rn(e,n){let r=tn(n),{integrations:t,catalog:i}=n,s=r.buildSupplyLookup(i),o=t,p=r.normalizeInstances({instances:o?.instances,defaultInstanceId:o?.defaultInstanceId}).defaultInstanceId??"*",c=nt(n,r,e,p,s),f=et(n,e,p),k=n.integrations?.services?.[e]?.provider,w=c.provider??(typeof k=="string"?k:typeof k=="object"&&k?String(k.provider):void 0),y=new Set(Object.keys(n.catalog.providers)),A=w!==void 0&&y.has(w)?sr(n.catalog,w,e):void 0,O=i.services[e],g=O!==void 0?!O.optional:void 0,a=O?.owners[0];return{status:c.status,...c.statusMessage?{statusMessage:c.statusMessage}:{},...w!==void 0?{provider:w}:{},...w!==void 0&&f!==null?{layer:f}:{},...A!==void 0?{supplied:A}:{},...a!==void 0?{module:a}:{},...g!==void 0?{required:g}:{}}}function sr(e,n,r){return Ee(e,n,r)}function pe(e,n,r){let t=new Set([...e.walk.vocabulary,...Object.keys(e.catalog.services)]),i=e.integrations?.services??{};for(let o of Object.keys(i))t.add(o);let s={};for(let o of[...t].sort())r&&!r.includes(o)||(s[o]=rn(o,e));return{contracts:Xn(e.contracts),resolutions:s,issues:n}}function on(e,n,r){let t=tn(n),i=t.buildSupplyLookup(n.catalog),s=n.integrations,d=t.normalizeInstances({instances:s?.instances,defaultInstanceId:s?.defaultInstanceId}).instances.map(O=>O.id),p=n.integrations?.services?.[e],c=p?.instances?Object.keys(p.instances):void 0,f;d.length>0?(f=[...d],c?.includes("*")&&f.push("*")):c!==void 0&&c.length>0?f=c.includes("*")?["*"]:c:f=[];let k=f.map(O=>{let g=nt(n,t,e,O,i);return{instanceId:O,status:g.status,...g.statusMessage?{statusMessage:g.statusMessage}:{},...g.effective?{effective:g.effective}:{}}}),w=ar(n,e),A={...rn(e,n),instances:k,inheritance:w};return{contracts:Xn(n.contracts),resolution:A,issues:r.filter(O=>O.service===e)}}function ar(e,n){let r=e.integrations,t=r?.services?.[n],i=e.integrations,o=tn(e).normalizeInstances({instances:i?.instances,defaultInstanceId:i?.defaultInstanceId}).defaultInstanceId??"*",d=t?.instances?.[o]??t?.instances?.["*"],p=e.walk.ownership[n],c=p!==void 0?L(r,p):{provider:null,layer:null};return[{layer:"app",...r?.provider?{provider:r.provider}:{}},{layer:"module",...c.layer==="module"&&c.provider?{provider:c.provider}:{}},{layer:"service",...typeof t?.provider=="string"?{provider:t.provider}:{},...t?.implementation?{implementation:t.implementation}:{}},{layer:"instance",...d?.provider?{provider:d.provider}:{},...d?.implementation?{implementation:d.implementation}:{}}]}function sn(e,n,r){if(n===null)return null;let t={};for(let i of r)t[i]={configSchema:z(e,n,i)};return{provider:n,services:t}}function ie(e){return e===null||typeof e!="object"?JSON.stringify(e??null):Array.isArray(e)?`[${e.map(ie).join(",")}]`:`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${ie(e[r])}`).join(",")}}`}var cr="\0no-enum";function dr(e){let n=e.enum;return Array.isArray(n)?`[${[...new Set(n.map(ie))].sort().join(",")}]`:cr}function lr(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let n=e.type;return n===void 0?null:ie(n)}function ur(e){let n=e.map(t=>lr(t.subschema));if(n.some(t=>t===null)||new Set(n).size>1)return null;if(n[0]==='"object"'){let t=ie(e[0].subschema);return e.every(i=>ie(i.subschema)===t)?e[0].subschema:null}return new Set(e.map(t=>dr(t.subschema))).size===1?e[0].subschema:null}function Oe(e,n){let r=[],t=!0,i=new Map;for(let[o,d]of Object.entries(e.services)){let p=d.configSchema;if(p===null){r.push(o);continue}if(!p||typeof p!="object"||Array.isArray(p))continue;let c=p;c.additionalProperties===!1&&(t=!1);let f=c.properties;if(!f||typeof f!="object"||Array.isArray(f))continue;let k=Array.isArray(c.required)?c.required:[];for(let w of Object.keys(f)){let y=i.get(w)??[];y.push({service:o,subschema:f[w],required:k.includes(w)}),i.set(w,y)}}let s=[];for(let[o,d]of i)s.push({key:o,schema:ur(d),sources:d.map(({service:p,required:c})=>({service:p,required:c})),global:d.some(p=>!!p.subschema&&typeof p.subschema=="object"&&p.subschema["x-tbox-global"]===!0)});return{provider:e.provider,schemaless:r,unsupplied:[...n?.unsupplied??[]],additionalPropertiesAllowed:t,fields:s}}function an(e,n,r,t){let i=typeof t=="string"&&t.length>0?t:void 0;if(e==="app"){if(i!==void 0)return i;let d=n.integrations?.provider;return typeof d=="string"&&d.length>0?d:null}let s=n.walk.modules.find(d=>d.id===r);return!s||!J(n.walk,s).writable?null:i!==void 0?i:L(n.integrations,s.id).provider}var tt={integrationSchemas:null,integrationFieldRegistry:null};function rt(e){return{...e,fields:e.fields.filter(n=>n.global)}}function cn(e,n){let r=an("app",e,void 0,n);if(r===null)return tt;let t=sn(e,r,_e(e.catalog,r));return{integrationSchemas:t,integrationFieldRegistry:rt(Oe(t))}}function dn(e,n,r){let t=an("module",e,n,r),i=e.walk.modules.find(p=>p.id===n);if(t===null||!i)return tt;let s=(i.descriptor.declare.owns??[]).map(p=>p.service),o=p=>Ee(e.catalog,t,p),d=sn(e,t,s.filter(o));return{integrationSchemas:d,integrationFieldRegistry:rt(Oe(d,{unsupplied:[...new Set(s.filter(p=>!o(p)))]}))}}function pr(e){return cn(e).integrationSchemas}function fr(e,n){return dn(e,n).integrationSchemas}function gr(e,n){let r=e.walk.ownership[n];if(r!==void 0)return L(e.integrations,r).provider;let t=e.integrations?.provider;return typeof t=="string"&&t.length>0?t:null}function Me(e,n,r){let t=typeof r=="string"&&r.length>0?r:void 0;if(t!==void 0)return{provider:t,configSchema:z(e,t,n)};let i=e.integrations?.services?.[n]?.provider;if(i===void 0||i===""){let s=gr(e,n);return s===null?null:{provider:s,configSchema:z(e,s,n)}}if(typeof i=="string")return{provider:i,configSchema:z(e,i,n)};if(G(i)){let s=i;return{provider:s.provider,configSchema:z(e,s.provider,n,s.configSchema)}}return null}function ln(e,n,r){let t=Me(e,n,r);if(t===null)return null;let i={provider:t.provider,services:{[n]:{configSchema:t.configSchema}}};return Oe(i)}function fe(e,n){if(n===void 0||!n.startsWith("secret://"))return;let r=n.slice(9),t=se(e,r);if(t)return{type:t.type,ref:n,file:_(r),masked:ge(t.values)}}function un(e){let n=e.integrations,r={credential:fe(e.appDir,typeof n?.credentialRef=="string"?n.credentialRef:void 0)??null,byInstance:{}};for(let{id:i}of n?.instances??[]){let s=n?.credentialRefByInstance?.[i];s!==void 0&&(r.byInstance[i]=fe(e.appDir,s)??null)}let t={};for(let[i,s]of Object.entries(n?.services??{})){let o={credential:fe(e.appDir,s.credentialRef)??null,byInstance:{}};for(let[d,p]of Object.entries(s.instances??{}))o.byInstance[d]=fe(e.appDir,p.credentialRef)??null;t[i]=o}return{app:r,services:t}}function pn(e,n){return{types:(n===void 0?Object.keys(e.catalog.credentialTypes):[...new Set(Object.values(e.catalog.providers[n]??{}).map(t=>t.credentialType))]).sort().map(t=>{let i=e.catalog.credentialTypes[t];return{credentialType:t,owner:i?.owner??"",credentialSchema:i?nn(e.appDir,i.packageDir,i.credentialSchema):null}})}}import mr from"path";var vr={app:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],module:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],provider:["integrationSchemas"],service:["integrationSchemas","integrationFieldRegistry"]};function xe(e,n){if(!n||n.length===0)return new Set;let r=vr[e],t=[...new Set(n)].filter(i=>!r.includes(i));if(t.length>0)throw new M("VALIDATION_FAILED",400,`include 含未知或不适用于本端点的键:${t.join("、")}(白名单:${r.join("、")})`,["include"]);return new Set(n)}var it=["integrationSchemas","integrationFieldRegistry"];function fn(e,n,r){if(!(typeof n!="string"||n.length===0)&&!it.some(t=>r.has(t)))throw new M("VALIDATION_FAILED",400,`参数 ${e} 需与表单 include 键(${it.join("、")})同现——轴参仅重定向表单层双投影`,[e])}function yr(e,n={}){let r=je(),t=Promise.resolve(),i={appDir:e,cache:r};function s(g){if(!g.strictValidation)throw new M("CONTRACTS_NOT_RESOLVED",503,Pe(g));if(!g.ownershipBindingV6)throw new M("CONTRACTS_NOT_RESOLVED",503,`contracts ${g.version??"(版本未知)"} 不支持 v6 modules 绑定形状(OWNERSHIP_BINDING_V6 标记缺席)——升级应用 @tbox.cn/app-contracts 依赖后可用`)}function o(g){return zn(i,g)}function d(g){let a=g.integrations?.services;return a&&typeof a=="object"?Object.keys(a):[]}async function p(){let g=await T(e),a=o(g),m=a.integrations;if(m===null)return[];let R={resolveEffectiveService:c(g.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:c(g.module.buildSupplyLookup,"buildSupplyLookup"),normalizeInstances:c(g.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:g.module.RESOURCE_TYPE_IDS??[]},S=ce(e,a.walk,m,process.env);return ee({contracts:R,integrations:m,supplies:R.buildSupplyLookup(a.catalog),...S})}function c(g,a){if(typeof g!="function")throw new M("CONTRACTS_NOT_RESOLVED",503,`contracts 求值面 ${a} 缺席(形态异常)`);return g}function f(g){let a=t.then(g,g);return t=a.catch(()=>{}),a}let k={async loadModules(g){let a=await T(e);return He(o(a),g)},async loadModule(g,a){let m=xe("module",a?.include);fn("moduleProvider",a?.moduleProvider,m);let R=await T(e),S=o(R),u=ke(S.walk,g),v=Ye(S,u.id);if(m.has("serviceResolutions")&&(v.serviceResolutions=R.evaluation&&R.strictValidation?await p().then(b=>pe(S,b,v.services.map(l=>l.service))):null),m.has("integrationSchemas")||m.has("integrationFieldRegistry")){let b=dn(S,u.id,a?.moduleProvider);m.has("integrationSchemas")&&(v.integrationSchemas=b.integrationSchemas),m.has("integrationFieldRegistry")&&(v.integrationFieldRegistry=b.integrationFieldRegistry)}return v},async loadApp(g){let a=xe("app",g?.include);fn("appProvider",g?.appProvider,a);let m=await T(e),R=o(m),S=Ze(R);if(a.has("serviceResolutions")&&(S.serviceResolutions=m.evaluation&&m.strictValidation?await p().then(u=>pe(R,u)):null),a.has("integrationSchemas")||a.has("integrationFieldRegistry")){let u=cn(R,g?.appProvider);a.has("integrationSchemas")&&(S.integrationSchemas=u.integrationSchemas),a.has("integrationFieldRegistry")&&(S.integrationFieldRegistry=u.integrationFieldRegistry)}return S},async loadService(g,a){let m=xe("service",a?.include);fn("serviceProvider",a?.serviceProvider,m);let R=await T(e),S=o(R),u=H(S.walk,d(S),g),v=qe(S,u);return m.has("integrationSchemas")&&(v.integrationSchemas=Me(S,u,a?.serviceProvider)),m.has("integrationFieldRegistry")&&(v.integrationFieldRegistry=ln(S,u,a?.serviceProvider)),v},async loadServiceResolutions(g){let a=await T(e);s(a);let m=await p();return pe(o(a),m,g)},async loadServiceResolution(g){let a=await T(e);s(a);let m=o(a),R=H(m.walk,d(m),g),S=await p();return on(R,m,S)},async loadProviders(){let g=await T(e);return Qe(o(g))},async loadProvider(g,a){let m=xe("provider",a?.include),R=await T(e);return Xe(o(R),g,m)},async loadProviderService(g,a){let m=await T(e),R=o(m),S=H(R.walk,d(R),a);return en(R,g,S)},async loadCredentials(){let g=await T(e);return un(o(g))},async loadCredentialTypes(g){let a=await T(e);return pn(o(a),g)}},w=Je(e,{onApplied:n.onApplied,cache:r}),y={async writeAppIntegration(g,a){await w.warmup();let m=await T(e);return s(m),f(()=>w.applyApp(g,a))},async writeModuleIntegration(g,a,m){await w.warmup();let R=await T(e);return s(R),f(()=>{let S=ke(o(R).walk,g);return w.applyModule(S.id,a,m)})},async writeServiceIntegration(g,a,m){await w.warmup();let R=await T(e);return s(R),f(()=>{let S=o(R),u=H(S.walk,d(S),g);return w.applyService(u,a,m)})},async deleteServiceIntegration(g){await w.warmup();let a=await T(e);return s(a),f(()=>{let m=o(a),R=H(m.walk,d(m),g);return w.deleteService(R)})}},A={invalidate(){r.invalidate(),Te(e)},async resolveContracts(){return T(e)},walkManifests(){return O(e)},parseModuleDescriptor(g){return oe(g)},loadProviderCatalogRaw(){return We(e)},async readIntegrationsConfig(){return B(e,r)},async writeIntegrationsConfig(g){await w.warmup();let a=await T(e);return s(a),f(()=>Sr(e,g,r))},async ensureMockBindings(){await w.warmup();let g=await T(e);return s(g),f(()=>Ge(e))},async evaluateIntegrationServices(g){await w.warmup();let a=await T(e);s(a);let m={resolveEffectiveService:c(a.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:c(a.module.buildSupplyLookup,"buildSupplyLookup"),normalizeInstances:c(a.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:a.module.RESOURCE_TYPE_IDS??[]};return ee({...g,contracts:m})}};function O(g){return V(g,r)}return{...k,...y,...A}}function Sr(e,n,r){let t=mr.join(e,"config","integrations.json");$(t,`${JSON.stringify(n,null,2)}
9
+ `),r.invalidate([t])}export{le as APP_INTEGRATION_NODE_KEYS,M as AppToolkitError,ue as MODULE_INTEGRATION_NODE_KEYS,K as SAFE_NAME_PATTERN,Ct as assertValidModuleId,Oe as buildIntegrationFieldRegistry,jt as buildOwnershipMap,ce as buildPredicateAssembly,$e as checkInstanceKeys,xt as collectDeclaredModules,Pe as contractsNotResolvedMessage,yr as createAppToolkit,je as createFileCache,Je as createWriteCore,Lt as credentialArtifactExists,re as deepEqual,Q as deriveStem,fe as echoForRef,Cn as ensureDir,Ge as ensureMockBindings,Be as evaluateAppIntegrationIssues,ee as evaluateIntegrationServices,Ne as expandEnvVars,Tn as extractModuleIdFromSource,an as formProviderOf,Te as invalidateContractsResolver,G as isControlledInlineProvider,Mn as isValidModuleId,pr as loadAppIntegrationSchemas,Ze as loadAppView,pn as loadCredentialTypesView,un as loadCredentialsView,Ye as loadModuleDetailView,fr as loadModuleIntegrationSchemas,He as loadModulesView,we as loadProviderCatalog,We as loadProviderCatalogRaw,Xe as loadProviderDetailView,en as loadProviderServiceDetailView,Qe as loadProvidersView,qe as loadServiceDetailView,ln as loadServiceFieldRegistry,Me as loadServiceIntegrationSchemas,on as loadServiceResolutionDetail,pe as loadServiceResolutionsView,ve as manifestPath,ge as maskCredentialValues,vn as moduleDependencySchema,Rn as moduleDescriptorSchema,J as moduleOwnershipWritable,gn as pageContribSchema,oe as parseModuleDescriptor,_e as providerFootprint,yn as providerSlotContribSchema,zt as pruneIntegrationBindings,On as readAppManifest,De as readAppManifestFull,se as readCredentialFile,B as readIntegrationsConfig,Fn as readIntegrationsStrict,ne as reconcileOrphanCredentials,Vn as refToEnvKey,It as removeNpmModule,T as resolveContractsForApp,T as resolveContractsForAppExport,sn as resolveLayerIntegrationSchemas,L as resolveModuleBinding,ke as resolveModuleKey,H as resolveServiceKey,rn as resolveServiceSummary,hn as resourceNeedContribSchema,Sn as serviceConsumeContribSchema,wn as serviceOwnContribSchema,_ as stemToFilePath,pt as stemToRef,mn as tabContribSchema,bt as updateNpmModule,kt as upsertMiniappContainer,Rt as upsertNpmModule,V as walkManifests,ht as writeAppManifest,$ as writeAtomic,Ve as writeCredentialFile};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tbox.cn/app-toolkit",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "tbox 应用工具面(运行面/工具面对仗:app-sdk 给运行的应用用,app-toolkit 给操作应用的工具用)——模块解析、集成配置求值/校验/写入内核,contracts 经应用侧动态解析(沙箱与目标应用版本解耦)。",
6
6
  "exports": {
@@ -18,7 +18,7 @@
18
18
  "zod": "3.25.76"
19
19
  },
20
20
  "devDependencies": {
21
- "@tbox.cn/app-contracts": "0.11.0",
21
+ "@tbox.cn/app-contracts": "0.12.0",
22
22
  "typescript": "5.9.3",
23
23
  "tsup": "8.5.1",
24
24
  "vitest": "4.1.10",
@@ -41,7 +41,7 @@ export function loadProviderCatalogRaw(appDir: string): WalkCatalog {
41
41
  return walkManifests(appDir).catalog;
42
42
  }
43
43
 
44
- /** 桥源(形态冻结):富形态 → 桥形状投影(demand meta title/description 剥离——桥面无此字段,
44
+ /** 桥源(形态冻结):富形态 → 桥形状投影(demand meta name/description 剥离——桥面无此字段,
45
45
  * additive 差异声明见 app-sdk 桥 golden) */
46
46
  export function loadProviderCatalog(appDir: string): BridgeProviderCatalog {
47
47
  const rich = walkManifests(appDir).catalog;
@@ -0,0 +1,75 @@
1
+ import type { WalkManifestsResult, WalkModuleInfo } from './walk-manifests.js';
2
+ import { AppToolkitError } from '../core/errors.js';
3
+
4
+ /**
5
+ * 双键寻址(v7 词汇统一):路径参数双键——id 精确优先 → 展示名唯一命中兜底 → 404
6
+ * (多命中 fail-visible,message 列候选 + 指引改用 id;复用既有 404 码零新错误码)。
7
+ *
8
+ * **消费边界(O1——双键语义单点)**:仅 factory.ts 控制面七方法入口接入;
9
+ * views / write-core / CLI 恒 id-only 纯函数。
10
+ *
11
+ * **纯参数式(F2)**:configuredKeys 由调用方注入——零 integrations 依赖、零 IO,
12
+ * 解析输入恒为 walk 产物快照 + 调用方键集。
13
+ */
14
+
15
+ /** 模块双键解析:id 精确 → 展示名(descriptor.name ?? id)唯一命中 → 404。 */
16
+ export function resolveModuleKey(walk: WalkManifestsResult, key: string): WalkModuleInfo {
17
+ const byId = walk.modules.find((m) => m.id === key);
18
+ if (byId) return byId;
19
+ const byName = walk.modules.filter((m) => (m.descriptor.name ?? m.descriptor.id) === key);
20
+ if (byName.length === 1) return byName[0];
21
+ if (byName.length > 1) {
22
+ throw new AppToolkitError(
23
+ 'MODULE_NOT_FOUND',
24
+ 404,
25
+ `模块展示名「${key}」命中多个模块:${byName.map((m) => `${m.descriptor.name}(id=${m.id})`).join(' / ')}——请改用模块 id 寻址`,
26
+ );
27
+ }
28
+ throw new AppToolkitError('MODULE_NOT_FOUND', 404, `模块 ${key} 非已装模块(id / 展示名均未命中)`);
29
+ }
30
+
31
+ /** 服务双键解析 → 真实 service id:服务键集(词汇 ∪ demand ∪ 供给足迹 ∪ configuredKeys)
32
+ * 精确命中 → 展示名(slotMeta.name ?? catalog.services[].name)唯一命中 → 404。
33
+ * configuredKeys = 当前集成配置 services 节键集(调用方注入)。 */
34
+ export function resolveServiceKey(
35
+ walk: WalkManifestsResult,
36
+ configuredKeys: readonly string[],
37
+ key: string,
38
+ ): string {
39
+ // 供给足迹(providers slots 展平——纯供给无 demand/词汇的槽合法,O6 同厂商多 impl 形态)
40
+ const supplied = new Set<string>();
41
+ for (const impls of Object.values(walk.catalog.providers)) {
42
+ for (const entry of Object.values(impls)) {
43
+ for (const s of entry.services) supplied.add(s);
44
+ }
45
+ }
46
+ // 自有键判据用 hasOwn(`in` 走原型链——"toString" 等键会误放行;下游 isKnownService 虽有
47
+ // 二道防线,解析层不放行原型键才是正确语义)
48
+ if (
49
+ walk.vocabulary.includes(key)
50
+ || Object.hasOwn(walk.catalog.services, key)
51
+ || supplied.has(key)
52
+ || configuredKeys.includes(key)
53
+ ) {
54
+ return key;
55
+ }
56
+ const matches: string[] = [];
57
+ const pushMatch = (svc: string): void => {
58
+ if (!matches.includes(svc)) matches.push(svc);
59
+ };
60
+ for (const svc of walk.vocabulary) {
61
+ if ((walk.slotMeta[svc]?.name ?? walk.catalog.services[svc]?.name) === key) pushMatch(svc);
62
+ }
63
+ for (const [svc, entry] of Object.entries(walk.catalog.services)) {
64
+ if (entry.name === key) pushMatch(svc);
65
+ }
66
+ if (matches.length === 1) return matches[0];
67
+ if (matches.length > 1) {
68
+ throw new AppToolkitError(
69
+ 'SERVICE_NOT_FOUND',
70
+ 404,
71
+ `服务展示名「${key}」命中多个服务:${matches.join(' / ')}——请改用服务 id 寻址`,
72
+ );
73
+ }
74
+ throw new AppToolkitError('SERVICE_NOT_FOUND', 404, `服务 ${key} 不在服务词汇(已装契约包 ∪ 已配置)`);
75
+ }