@tbox.cn/app-toolkit 0.3.0 → 0.4.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.
- package/dist/index.d.ts +91 -9
- package/dist/index.js +9 -8
- package/package.json +2 -2
- package/src/assembly/walk-manifests.ts +95 -28
- package/src/core/env-expansion.ts +14 -12
- package/src/core/module-schema.ts +3 -0
- package/src/dto.ts +13 -0
- package/src/index.ts +4 -0
- package/src/integrations/evaluate-app.ts +41 -0
- package/src/integrations/prune-bindings.ts +186 -0
- package/src/views/app.ts +6 -2
- package/src/views/context.ts +20 -0
- package/src/views/modules.ts +25 -13
- package/src/views/providers.ts +13 -1
- package/src/views/service-detail.ts +5 -3
- package/tests/demo-app.ts +27 -3
- package/tests/dev-manifest-catalog.test.ts +81 -1
- package/tests/module-schema.test.ts +15 -0
- package/tests/vendor-schema-keywords.test.ts +12 -0
- package/tests/views.test.ts +159 -3
package/dist/index.d.ts
CHANGED
|
@@ -139,6 +139,8 @@ declare const resourceNeedContribSchema: z.ZodObject<{
|
|
|
139
139
|
declare const moduleDescriptorSchema: z.ZodObject<{
|
|
140
140
|
schemaVersion: z.ZodDefault<z.ZodNumber>;
|
|
141
141
|
name: z.ZodString;
|
|
142
|
+
title: z.ZodOptional<z.ZodString>;
|
|
143
|
+
description: z.ZodOptional<z.ZodString>;
|
|
142
144
|
version: z.ZodDefault<z.ZodString>;
|
|
143
145
|
kind: z.ZodDefault<z.ZodEnum<["platform", "business", "third-party"]>>;
|
|
144
146
|
risk: z.ZodDefault<z.ZodObject<{
|
|
@@ -468,9 +470,13 @@ declare const moduleDescriptorSchema: z.ZodObject<{
|
|
|
468
470
|
}[];
|
|
469
471
|
};
|
|
470
472
|
env: string[];
|
|
473
|
+
title?: string | undefined;
|
|
474
|
+
description?: string | undefined;
|
|
471
475
|
}, {
|
|
472
476
|
name: string;
|
|
473
477
|
schemaVersion?: number | undefined;
|
|
478
|
+
title?: string | undefined;
|
|
479
|
+
description?: string | undefined;
|
|
474
480
|
version?: string | undefined;
|
|
475
481
|
kind?: "platform" | "business" | "third-party" | undefined;
|
|
476
482
|
risk?: {
|
|
@@ -550,14 +556,16 @@ declare function parseModuleDescriptor(raw: unknown): ParseModuleResult;
|
|
|
550
556
|
/**
|
|
551
557
|
* 配置 JSON 环境变量占位展开(纯数据形态——自 app-sdk env-expansion.ts 迁入改造)。
|
|
552
558
|
*
|
|
553
|
-
*
|
|
554
|
-
* ${NAME}
|
|
555
|
-
*
|
|
559
|
+
* 语法(语义真源 = 本文件 + 共享向量 test-fixtures/env-expansion-cases.json 防漂移):
|
|
560
|
+
* ${NAME} 占位引用;NAME 限定 [A-Z][A-Z0-9_]*(UPPER_SNAKE,最小化与正文 `${...}` 误碰)
|
|
561
|
+
* ${NAME:def} POSIX 风格缺省值:NAME 未设置时用 def(字面量,不二次展开);设置时空串也算「已设置」
|
|
562
|
+
* $${NAME} 转义为字面量 ${NAME}(原样保留一次 $)
|
|
556
563
|
*
|
|
557
564
|
* 语义(评审 N1 钉死,壳层各自包装 throw/report):
|
|
558
565
|
* - 单遍非递归:env 值内若含 `${OTHER}` 不被二次展开(注入防线);String.replace 回调形态天然单遍。
|
|
566
|
+
* 默认值内含 `${...}` 同样不展开(POSIX 同限);默认值含 `}` 不支持(同 POSIX 同限——正则 [^}] 截断)。
|
|
559
567
|
* - 值经 JSON 字符串转义注入;不做数值/布尔强制转换。
|
|
560
|
-
* - **本版为纯数据返回形态** `{ text?: string; missing: string[] }
|
|
568
|
+
* - **本版为纯数据返回形态** `{ text?: string; missing: string[] }`——缺变量(无缺省值时)不 throw,
|
|
561
569
|
* 由壳层(CLI doctor 壳 / app-sdk 桥 throw 壳 / 沙箱宿主)决定 fail-fast 还是降级:
|
|
562
570
|
* SDK 桥壳 missing 非空即 throw(错误文案逐字等价 SDK 旧版);CLI 壳同款。
|
|
563
571
|
* - 无 ${ 的文本快速路径:text 原文返回,零替换零开销。
|
|
@@ -1105,9 +1113,15 @@ declare function evaluateIntegrationServices(input: IntegrationServicePredicateI
|
|
|
1105
1113
|
* 3. serviceSchemas:per-service schema 复合键表——键 `${provider}\u0000${service}`(H2,同一服务
|
|
1106
1114
|
* 多厂商供给各自 schema 零碰撞);多 impl 同 (provider, service) 异 schema → 声明序首个
|
|
1107
1115
|
* 4. vocabulary:所有携带 service-slots.json 的已装契约包该文件 `.slots` 键并集(fs 直读、
|
|
1108
|
-
* `$comment`
|
|
1109
|
-
*
|
|
1110
|
-
*
|
|
1116
|
+
* `$comment` 忽略;探测三跳 = ① <候选>/node_modules/@tbox.cn/<pkg>/service-slots.json(包根)
|
|
1117
|
+
* ② 同包 src/service-slots.json(发布包 src 附带 / 模板 shim 链接)
|
|
1118
|
+
* ③ 候选自身 {service-slots.json, src/service-slots.json}(local/codegen 全量副本——
|
|
1119
|
+
* mall 生成应用主形态,不依赖 install);零缓存枚举,与 manifest 探测同机制;
|
|
1120
|
+
* 多行业 contracts-* 天然扩展 F8);缺席 → [](退化 demanded ∪ configured)
|
|
1121
|
+
* 5. slotMeta:词汇 meta 节(per-service {title,description} 展示元数据——消费端兜底链
|
|
1122
|
+
* 词汇 > demand > id,views/context resolveServiceDisplay 单源);多包发现序首声明胜出
|
|
1123
|
+
* (与 catalog addSlots 同语义);contracts-mall 词汇锁保证 mall 域全量覆盖;缺席 → {}
|
|
1124
|
+
* 6. domainKeyIssues:跨模块域键冲突 issue(两模块派生同一 domains 键——P13)
|
|
1111
1125
|
*
|
|
1112
1126
|
* **约束(D26;FX-3/F7 边界)**:目录枚举零缓存——readdir / node_modules 候选探测 / `.tbox/app.json` 读取 /
|
|
1113
1127
|
* dev-manifest 读取每次执行(枚举输入保持 fresh——agent 装卸模块下一笔即见);manifest/service-slots
|
|
@@ -1128,6 +1142,8 @@ interface WalkManifestsResult {
|
|
|
1128
1142
|
}>;
|
|
1129
1143
|
/** 服务词汇 = 所有携带 service-slots.json 的已装契约包 `.slots` 键并集(缺席 → []) */
|
|
1130
1144
|
vocabulary: string[];
|
|
1145
|
+
/** 词汇 meta 节:per-service {title,description} 展示元数据(多包首声明胜出;缺席 → {}) */
|
|
1146
|
+
slotMeta: Record<string, SlotMeta>;
|
|
1131
1147
|
/** 跨模块域键冲突(P13——两模块的 service 集派生同一 domains 键) */
|
|
1132
1148
|
domainKeyIssues: Array<{
|
|
1133
1149
|
severity: 'warning';
|
|
@@ -1136,6 +1152,11 @@ interface WalkManifestsResult {
|
|
|
1136
1152
|
module?: string;
|
|
1137
1153
|
}>;
|
|
1138
1154
|
}
|
|
1155
|
+
/** 槽位展示元数据(service-slots.json meta 节元素——宽松提取,字段皆可选) */
|
|
1156
|
+
interface SlotMeta {
|
|
1157
|
+
title?: string;
|
|
1158
|
+
description?: string;
|
|
1159
|
+
}
|
|
1139
1160
|
interface WalkModuleInfo {
|
|
1140
1161
|
/** install id(packages/ 目录名 / npmModules entry.id) */
|
|
1141
1162
|
id: string;
|
|
@@ -1145,12 +1166,17 @@ interface WalkModuleInfo {
|
|
|
1145
1166
|
pkg: string;
|
|
1146
1167
|
descriptor: ModuleDescriptor;
|
|
1147
1168
|
}
|
|
1148
|
-
/** 富形态供给条目:per-service {implementation, credentialType} 恒数组保真(H1
|
|
1169
|
+
/** 富形态供给条目:per-service {implementation, credentialType} 恒数组保真(H1);
|
|
1170
|
+
* title/description = 厂商展示元数据(strict manifest descriptor 透传——多包同厂商
|
|
1171
|
+
* 首声明胜出,与 owner 同语义;B1 walk 层传播) */
|
|
1149
1172
|
interface WalkProviderEntry {
|
|
1150
1173
|
provider: string;
|
|
1151
1174
|
implementation: string;
|
|
1152
1175
|
credentialType: string;
|
|
1153
1176
|
owner: string;
|
|
1177
|
+
/** 厂商展示名(manifest 模块 meta——多包首声明;缺席 = undefined) */
|
|
1178
|
+
title?: string;
|
|
1179
|
+
description?: string;
|
|
1154
1180
|
local?: boolean;
|
|
1155
1181
|
configSchema?: string;
|
|
1156
1182
|
credentialSchema?: string;
|
|
@@ -1251,6 +1277,49 @@ declare function refToEnvKey(stem: string): string;
|
|
|
1251
1277
|
*/
|
|
1252
1278
|
declare function buildPredicateAssembly(appDir: string, walk: WalkManifestsResult, integrations: Record<string, unknown>, env?: Readonly<Record<string, string | undefined>>): PredicateAssembly;
|
|
1253
1279
|
|
|
1280
|
+
/**
|
|
1281
|
+
* 应用级 integrations 求值(cli-remove-prune-and-new D2.4):doctor integration-services 规则内
|
|
1282
|
+
* "装配+求值"序列的单源抽取(FX-2b/F1 轨迹延续——此前 buildPredicateAssembly 已单源,本函数
|
|
1283
|
+
* 将 walk→supplies→assembly→evaluate 全序列收口)。
|
|
1284
|
+
*
|
|
1285
|
+
* 消费方:
|
|
1286
|
+
* - doctor integration-services 规则(外壳保留:stale 防线/文件读取/env 展开/形状守卫/分级投射)
|
|
1287
|
+
* - pruneIntegrationBindings(prune 判据 ≡ doctor 判据的构造性同源载体)
|
|
1288
|
+
*
|
|
1289
|
+
* 契约:调用方须先 `resolveContractsForApp` 并确保 `strictValidation`(本函数不再分级门控——
|
|
1290
|
+
* doctor 的 warning/error 升级指引与 prune 的 skip 语义分属两消费方,不收口)。
|
|
1291
|
+
*/
|
|
1292
|
+
declare function evaluateAppIntegrationIssues(appDir: string, integrations: Record<string, unknown>, contracts: ResolvedContracts, env?: Readonly<Record<string, string | undefined>>): Promise<IntegrationServiceIssue[]>;
|
|
1293
|
+
|
|
1294
|
+
/**
|
|
1295
|
+
* integrations.json 死绑定清理(cli-remove-prune-and-new D2 核心件)。
|
|
1296
|
+
*
|
|
1297
|
+
* 不变式:**删除判据 ≡ doctor integration-services 报错判据(构造性同源)**——消费 doctor 同一
|
|
1298
|
+
* 共享求值器 evaluateAppIntegrationIssues 的结构化 issue,code 白名单
|
|
1299
|
+
* {VENDOR_NOT_INSTALLED, BINDING_UNRESOLVED} + 守卫(绑定引用链候选 provider ∈ installedVendors
|
|
1300
|
+
* 即保留,排除活厂商错配)→ 删除域严格 = "供给载体消亡"。
|
|
1301
|
+
*
|
|
1302
|
+
* 由此推论(均已实证):需求侧孤儿绑定(demand 消失、供给在场)保留——doctor 判其合法;用户
|
|
1303
|
+
* 预配置绑定受保护;一次 remove 自愈全文件历史死债;凭据类 issue(CREDENTIAL_FILE_MISSING 等)
|
|
1304
|
+
* 刻意不进白名单,原样保留。
|
|
1305
|
+
*
|
|
1306
|
+
* 写侧三防线(镜像 write core):N1 归一化(空模块节点删 domains 键)→ parseIntegrationsConfig
|
|
1307
|
+
* 严格校验(失败弃写)→ writeAtomic。凭据孤儿只报告不清理(D9——与 DELETE 管线现行为一致)。
|
|
1308
|
+
* 全空(无任何存活绑定)→ 删文件——ensureMockBindings(缺席即生成)在重装供给时再生闭环。
|
|
1309
|
+
*
|
|
1310
|
+
* 最佳努力语义:谓词不可用(contracts 未安装/降级、env 缺失、求值 throw)→ skipped 返回 +
|
|
1311
|
+
* 文件原样,绝不阻断 remove 本体。
|
|
1312
|
+
*/
|
|
1313
|
+
interface PruneResult {
|
|
1314
|
+
/** 被清除的绑定节点描述(remove 日志行,如 'root.provider=mock' / 'services.member.account') */
|
|
1315
|
+
removed: string[];
|
|
1316
|
+
/** 孤儿凭据(D9 只报告不清理——reconcileOrphanCredentials 产物 message) */
|
|
1317
|
+
orphanCredentials: string[];
|
|
1318
|
+
/** 跳过原因(正常路径 undefined;not-configured = integrations.json 缺席,兼容态零动作) */
|
|
1319
|
+
skipped?: 'predicate-unavailable' | 'validation-failed' | 'not-configured';
|
|
1320
|
+
}
|
|
1321
|
+
declare function pruneIntegrationBindings(appDir: string): Promise<PruneResult>;
|
|
1322
|
+
|
|
1254
1323
|
/**
|
|
1255
1324
|
* .tbox/app.json npmModules 读写(自 CLI manifest.ts 迁入——assembly 层目录知识单源)。
|
|
1256
1325
|
* npmModules 登记 = sdk 包双语义磁盘足迹之一(业务包 = packages/<id>/ 目录,sdk 包 = 本清单登记)。
|
|
@@ -1562,6 +1631,10 @@ interface ServiceDemand {
|
|
|
1562
1631
|
}
|
|
1563
1632
|
/** GET /modules/:module(模块静态一站式 · PUT 读对偶) */
|
|
1564
1633
|
interface ModuleDetailView {
|
|
1634
|
+
/** B1 additive:模块 meta 展示名(manifest title;视图层兜底 name——恒有值) */
|
|
1635
|
+
title: string;
|
|
1636
|
+
/** B1 additive:模块 meta 描述(manifest description;兜底 '') */
|
|
1637
|
+
description: string;
|
|
1565
1638
|
/** v4.4 D34:demand 服务首段去重(排序;1..N;零域 = []) */
|
|
1566
1639
|
domainKeys: string[];
|
|
1567
1640
|
/** domains[换算键] 节点原值;未配置 = null;v4.4 D34:仅单域(writable)时在场——多域/零域/共享键无单键落点 */
|
|
@@ -1776,12 +1849,18 @@ interface ProviderEntry {
|
|
|
1776
1849
|
local: boolean;
|
|
1777
1850
|
/** 供给声明来源包名 */
|
|
1778
1851
|
owner: string;
|
|
1852
|
+
/** B1 additive:厂商展示名(manifest 模块 meta——多包首声明;缺席 = undefined) */
|
|
1853
|
+
title?: string;
|
|
1854
|
+
description?: string;
|
|
1779
1855
|
}
|
|
1780
1856
|
/** GET /providers/:provider:供给足迹 */
|
|
1781
1857
|
interface ProviderDetail {
|
|
1782
1858
|
provider: string;
|
|
1783
1859
|
local: boolean;
|
|
1784
1860
|
owner: string;
|
|
1861
|
+
/** B1 additive:厂商展示名(同 ProviderEntry——首声明透传) */
|
|
1862
|
+
title?: string;
|
|
1863
|
+
description?: string;
|
|
1785
1864
|
/** per (provider, service) 保真,同厂商异构合法;★ implementations 恒数组(H1——
|
|
1786
1865
|
* 多元素 = 升级窗口,UI 出 impl 选择器,PUT 显式钉版) */
|
|
1787
1866
|
services: Record<string, {
|
|
@@ -1789,6 +1868,9 @@ interface ProviderDetail {
|
|
|
1789
1868
|
implementation: string;
|
|
1790
1869
|
credentialType: string;
|
|
1791
1870
|
}>;
|
|
1871
|
+
/** B1 additive:服务展示名(resolveServiceDisplay——词汇 > demand > id;恒发) */
|
|
1872
|
+
title?: string;
|
|
1873
|
+
description?: string;
|
|
1792
1874
|
/** v4.4 F5:include=integrationSchemas 切换态批量(纯 config——凭据结构归 /credential-types) */
|
|
1793
1875
|
integrationSchemas?: {
|
|
1794
1876
|
configSchema: object | null;
|
|
@@ -2097,4 +2179,4 @@ interface AppToolkitInternals {
|
|
|
2097
2179
|
type AppToolkit = AppToolkitRead & AppToolkitWrite & AppToolkitInternals;
|
|
2098
2180
|
declare function createAppToolkit(appDir: string, options?: AppToolkitOptions): AppToolkit;
|
|
2099
2181
|
|
|
2100
|
-
export { APP_INTEGRATION_NODE_KEYS, type AppIntegrationNode, type AppManifest, type AppManifestFull, type AppToolkit, AppToolkitError, type AppToolkitErrorCode, type AppToolkitInternals, type AppToolkitOptions, type AppToolkitRead, type AppToolkitWrite, type AppView, type AppliedCredential, type BindingLayer, type BridgeProviderCatalog, type CardContrib, type ContractsResolution, type CredentialBindingEcho, type CredentialEcho, type CredentialFile, type CredentialInput, type CredentialTypeEntry, type CredentialTypesView, type CredentialValues, type CredentialsView, type DeclaredModuleInfo, type EffectiveBinding, type EnvExpansionResult, type EvaluationExports, type FileCache, type InlineVendorDeclaration, type IntegrationFieldRegistryView, type IntegrationIssue, type IntegrationServiceIssue, type IntegrationServicePredicateInput, type LayerIntegrationSchemas, type MiniappContainerEntry, type MockBindingsResult, type ModuleDeclaration, type ModuleDescriptor, type ModuleDetailView, type ModuleIntegrationNode, type ModuleMode, type ModulesView, type NpmModuleEntry, type OrphanIssue, type ParseModuleResult, type PlannedCredential, type PredicateAssembly, type PredicateContracts, type PredicateIoInputs, type ProviderBinding, type ProviderDetail, type ProviderEntry, type ProviderServiceDetail, type ProviderServiceSchemas, type ProviderServiceSchemasResult, type ProviderSlotContrib, type ProvidersView, type ReadIntegrationsResult, type ResolvedContracts, type ResolvedInstance, type ResolvedModule, type ResourceNeedContrib, SAFE_NAME_PATTERN, type SaveResult, type ServiceDemand, type ServiceDetail, type ServiceInstanceNode, type ServiceIntegrationNode, type ServiceIntegrationSchemas, type ServiceNeedContrib, type ServiceResolution, type ServiceResolutionDetail, type ServiceResolutionEntry, type ServiceResolutionsView, type ServiceStatus, type StemInput, type SupplyLookup, type ViewContext, type ViewSnapshot, type WalkCatalog, type WalkManifestsResult, type WalkModuleInfo, type WalkProviderEntry, type WriteCore, type WriteCoreOptions, type WriteOptions, assertValidModuleId, buildPredicateAssembly, checkInstanceKeys, collectDeclaredModules, contractsNotResolvedMessage, createAppToolkit, createFileCache, createWriteCore, credentialArtifactExists, deepEqual, deriveStem, echoForRef, ensureDir, ensureMockBindings, evaluateIntegrationServices, expandEnvVars, extractModuleIdFromSource, invalidateContractsResolver, isControlledInlineProvider, isValidModuleId, loadAppIntegrationSchemas, loadAppView, loadCredentialTypesView, loadCredentialsView, loadModuleDetailView, loadModuleIntegrationSchemas, loadModulesView, loadProviderCatalog, loadProviderCatalogRaw, loadProviderDetailView, loadProviderServiceDetailView, loadProvidersView, loadServiceDetailView, loadServiceIntegrationSchemas, loadServiceResolutionDetail, loadServiceResolutionsView, manifestPath, maskCredentialValues, moduleDependencySchema, moduleDescriptorSchema, pageContribSchema, parseModuleDescriptor, providerSlotContribSchema, readAppManifest, readAppManifestFull, readCredentialFile, readIntegrationsConfig, readIntegrationsStrict, reconcileOrphanCredentials, refToEnvKey, removeNpmModule, resolveContractsForApp, resolveContractsForApp as resolveContractsForAppExport, resolveLayerIntegrationSchemas, resolveServiceSummary, resourceNeedContribSchema, serviceNeedContribSchema, stemToFilePath, stemToRef, tabContribSchema, updateNpmModule, upsertMiniappContainer, upsertNpmModule, walkManifests, writeAppManifest, writeAtomic, writeCredentialFile };
|
|
2182
|
+
export { APP_INTEGRATION_NODE_KEYS, type AppIntegrationNode, type AppManifest, type AppManifestFull, type AppToolkit, AppToolkitError, type AppToolkitErrorCode, type AppToolkitInternals, type AppToolkitOptions, type AppToolkitRead, type AppToolkitWrite, type AppView, type AppliedCredential, type BindingLayer, type BridgeProviderCatalog, type CardContrib, type ContractsResolution, type CredentialBindingEcho, type CredentialEcho, type CredentialFile, type CredentialInput, type CredentialTypeEntry, type CredentialTypesView, type CredentialValues, type CredentialsView, type DeclaredModuleInfo, type EffectiveBinding, type EnvExpansionResult, type EvaluationExports, type FileCache, type InlineVendorDeclaration, type IntegrationFieldRegistryView, type IntegrationIssue, type IntegrationServiceIssue, type IntegrationServicePredicateInput, type LayerIntegrationSchemas, type MiniappContainerEntry, type MockBindingsResult, type ModuleDeclaration, type ModuleDescriptor, type ModuleDetailView, type ModuleIntegrationNode, type ModuleMode, type ModulesView, type NpmModuleEntry, type OrphanIssue, type ParseModuleResult, type PlannedCredential, type PredicateAssembly, type PredicateContracts, type PredicateIoInputs, type ProviderBinding, type ProviderDetail, type ProviderEntry, type ProviderServiceDetail, type ProviderServiceSchemas, type ProviderServiceSchemasResult, type ProviderSlotContrib, type ProvidersView, type PruneResult, type ReadIntegrationsResult, type ResolvedContracts, type ResolvedInstance, type ResolvedModule, type ResourceNeedContrib, SAFE_NAME_PATTERN, type SaveResult, type ServiceDemand, type ServiceDetail, type ServiceInstanceNode, type ServiceIntegrationNode, type ServiceIntegrationSchemas, type ServiceNeedContrib, type ServiceResolution, type ServiceResolutionDetail, type ServiceResolutionEntry, type ServiceResolutionsView, type ServiceStatus, type StemInput, type SupplyLookup, type ViewContext, type ViewSnapshot, type WalkCatalog, type WalkManifestsResult, type WalkModuleInfo, type WalkProviderEntry, type WriteCore, type WriteCoreOptions, type WriteOptions, assertValidModuleId, buildPredicateAssembly, checkInstanceKeys, collectDeclaredModules, contractsNotResolvedMessage, createAppToolkit, createFileCache, createWriteCore, credentialArtifactExists, deepEqual, deriveStem, echoForRef, ensureDir, ensureMockBindings, evaluateAppIntegrationIssues, evaluateIntegrationServices, expandEnvVars, extractModuleIdFromSource, invalidateContractsResolver, isControlledInlineProvider, isValidModuleId, loadAppIntegrationSchemas, loadAppView, loadCredentialTypesView, loadCredentialsView, loadModuleDetailView, loadModuleIntegrationSchemas, loadModulesView, loadProviderCatalog, loadProviderCatalogRaw, loadProviderDetailView, loadProviderServiceDetailView, loadProvidersView, loadServiceDetailView, loadServiceIntegrationSchemas, loadServiceResolutionDetail, loadServiceResolutionsView, manifestPath, maskCredentialValues, moduleDependencySchema, moduleDescriptorSchema, pageContribSchema, parseModuleDescriptor, providerSlotContribSchema, pruneIntegrationBindings, readAppManifest, readAppManifestFull, readCredentialFile, readIntegrationsConfig, readIntegrationsStrict, reconcileOrphanCredentials, refToEnvKey, removeNpmModule, resolveContractsForApp, resolveContractsForApp as resolveContractsForAppExport, resolveLayerIntegrationSchemas, resolveServiceSummary, resourceNeedContribSchema, serviceNeedContribSchema, stemToFilePath, stemToRef, tabContribSchema, updateNpmModule, upsertMiniappContainer, upsertNpmModule, walkManifests, writeAppManifest, writeAtomic, writeCredentialFile };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import{a as
|
|
2
|
-
`,"utf8"),i}import{mkdirSync as Xn,renameSync as et,writeFileSync as nt}from"fs";import{dirname as tt}from"path";function _(e,n){an(tt(e));let r=`${e}.tmp-${process.pid}-${Date.now()}`;nt(r,n,"utf8"),et(r,e)}function an(e){Xn(e,{recursive:!0})}function L(e){let n=e.indexOf(".");return n===-1?e:e.slice(0,n)}function F(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 U(e,n){let r=[...new Set((n.descriptor.contributes.services??[]).map(o=>L(o.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],i=new Set;for(let[o,s]of Object.entries(e.catalog.services))if(L(o)===t)for(let f of s.owners)i.add(f);return i.size>1?{writable:!1,reason:"shared-key",domainKeys:[t],domainKey:t,coOwners:[...i].sort()}:{writable:!0,domainKeys:[t],domainKey:t}}function cn(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 ln(e,n){return[...new Set(Object.values(e.providers[n]??{}).flatMap(r=>r.services))].sort()}function ee(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 dn(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 Ie(e,n){let r=new Set(n),t=[],i=(o,s)=>{let f=dn(o,s,r);f&&t.push(f)};for(let o of Object.keys(e.configByInstance??{}))i(o,"configByInstance");for(let o of Object.keys(e.credentialRefByInstance??{}))i(o,"credentialRefByInstance");for(let[o,s]of Object.entries(e.services??{}))for(let f of Object.keys(s.instances??{}))i(f,`services.${o}.instances`);return t}function ae(e){let n=[],r=e.contracts,{integrations:t,suppliedProviders:i,demandedServices:o,supplies:s,malls:f,credentialSchemaMissing:u,vendorConfigKeys:p,vendorConfigSchemaMissing:v,credentialFileMissing:S,credentialFileType:d,realmSwitchHints:y,moduleResourceNeeds:R}=e,a=f?new Set(f):void 0;for(let c of y??[])n.push({severity:"warning",code:"REALM_SWITCH_HINT",message:c});let l=new Set(Object.keys(i).map(c=>c.slice(0,c.indexOf("\0"))).filter(c=>c.length>0)),g=(c,w,x,k)=>{if(typeof x?.provider=="string"&&typeof x.implementation=="string"&&x.provider&&x.implementation)return i[X(x.provider,x.implementation)]?.credentialType;if(typeof w.provider=="string"&&typeof w.implementation=="string")return i[X(w.provider,w.implementation)]?.credentialType;let E=w.provider?.credentialType;if(typeof E=="string")return E;if(!s)return;let T=k??Object.keys(w.instances??{})[0]??"",O=r.resolveEffectiveService(t,c,T,s);if(!(O.status!=="ok"||typeof O.effective.provider!="string"))return i[X(O.effective.provider,O.effective.implementation)]?.credentialType};if(S||d)for(let[c,w]of Object.entries(t.services))for(let[x,k]of Object.entries(w.instances??{})){if(k.enabled===!1)continue;let E=k.credentialRef??w.credentialRef??t.credentialRefByInstance?.[x]??t.credentialRef;if(typeof E!="string"||!E.startsWith("secret://"))continue;let T=E.slice(9);S?.[T]===!0&&n.push({severity:"error",code:"CREDENTIAL_FILE_MISSING",service:c,instance:x,message:`integrations: 凭据文件缺失 ${T}(${c}@${x} effective ref=${E};档内 config/credentials/ 无此文件)`});let O=d?.[T];if(O){let P=g(c,w,k,x);P&&O!==P&&n.push({severity:"error",code:"CREDENTIAL_TYPE_MISMATCH",service:c,instance:x,message:`integrations: 凭据文件 ${T}.json type=${O} 与绑定 credentialType ${P} 不一致(${c}@${x}——transport 创建期将按 type 选策略)`})}}let b=(c,w)=>{if(!a)return;let x=dn(c,w,a);x&&n.push(x)};for(let[c]of Object.entries(t.configByInstance??{}))b(c,"configByInstance");for(let[c]of Object.entries(t.credentialRefByInstance??{}))b(c,"credentialRefByInstance");let C=Object.entries(t.services).filter(([,c])=>c.instances==null||c.instances["*"]!=null).map(([c])=>c);if(C.length>0){let c=Object.entries(t.services).filter(([,w])=>w.instances!=null&&w.instances["*"]==null).map(([w])=>w);c.length>0&&n.push({severity:"warning",code:"WILDCARD_ALIGNMENT",message:`integrations: 激活形态不对称(通配:${C.join(", ")};显式键集:${c.join(", ")})——动态 mallId 将在显式键集槽上 INSTANCE_NOT_FOUND(provider 业务限制表达位),确认是否齐步`})}let m=r.normalizeInstances({instances:t.instances,defaultInstanceId:t.defaultInstanceId});m.instances.length>=2&&m.defaultInstanceId===null&&n.push({severity:"warning",code:"MULTI_INSTANCE_NO_DEFAULT",message:`integrations: ${m.instances.length} 个部署实例(${m.instances.map(c=>c.id).join(", ")})均无 defaultInstanceId——无 scope 参数访问将落全局会话(默认商圈不注入)`});for(let[c,w]of Object.entries(t.services)){if(o[c]||n.push({severity:"warning",code:"SLOT_NOT_DECLARED",service:c,message:`integrations: 服务槽 ${c} 无消费方声明(拼写错误或需求方未安装)——若为拆分前旧槽位词汇(member.main/parking.main/promotion.read/shopping-guide.main),参照 cookbook·app-config 槽位迁移配方展开为新槽`}),typeof w.provider=="string"?typeof w.implementation=="string"&&!i[X(w.provider,w.implementation)]&&n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:c,message:`integrations: provider ${w.provider}/${w.implementation} 未命中已装供给(${c} 槽级)——装对应 provider 包或改绑`}):w.provider!==void 0&&!ee(w.provider)&&n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:c,message:`integrations: 内联 provider 超受控形状(${c} 槽级;允许键 provider/credentialType/configSchema)`}),u){let k=g(c,w);k&&u[k]===!0&&n.push({severity:"error",code:"SCHEMA_FILE_MISSING",service:c,message:`integrations: credentialType ${k} 的 schema 引用不存在(${c};manifest 声明指向缺失文件)`})}typeof w.provider=="object"&&typeof w.implementation!="string"&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:c,message:`integrations: 内联厂商声明必须同时提供 implementation(${c} 槽级)`});for(let[k,E]of Object.entries(w.instances??{})){b(k,`services.${c}.instances`);let T=E.provider!==void 0,O=E.implementation!==void 0;if(O&&!T&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:c,instance:k,message:`integrations: 实例级 implementation 需伴随 provider(${c}@${k}——impl-only 禁止,provider 是绑定组头)`}),T&&O){let P=E.provider,V=E.implementation;typeof P=="string"&&typeof V=="string"?i[X(P,V)]||n.push({severity:"error",code:"INSTANCE_SUPPLY_UNMATCHED",service:c,instance:k,message:`integrations: 实例级 provider 覆盖 ${P}/${V} 未命中已装供给(${c}@${k})`}):ee(P)||n.push({severity:"error",code:"INLINE_PROVIDER_INVALID",service:c,instance:k,message:`integrations: 实例级内联 provider 超受控形状(${c}@${k})`})}}}for(let[c,w]of[["root",t.provider],...Object.entries(t.domains??{}).map(([x,k])=>[`domains.${x}`,k?.provider])])typeof w!="string"||w.length===0||l.has(w)||n.push({severity:"error",code:"VENDOR_NOT_INSTALLED",module:c.startsWith("domains.")?c.slice(8):void 0,message:`integrations: ${c} provider ${w} 未命中已装供给——装对应 provider 包或 provider use 改绑`});if(s)for(let[c,w]of Object.entries(t.services)){let x=w.instances?Object.keys(w.instances):[""];for(let k of x){let E=r.resolveEffectiveService(t,c,k,s);E.status==="binding-unresolved"&&n.push({severity:"error",code:"BINDING_UNRESOLVED",service:c,instance:k||void 0,message:`integrations: ${E.message}`})}}for(let[c,w]of Object.entries(t.services))w.implementation!==void 0&&w.provider===void 0&&n.push({severity:"error",code:"IMPL_WITHOUT_PROVIDER",service:c,message:`integrations: 槽级 implementation 需伴随 provider(${c}——impl-only 禁止,provider 是绑定组头)`});let I=new Set([...Object.keys(t.services).map(c=>r.moduleDomainOf(c)),...Object.keys(o).map(c=>r.moduleDomainOf(c))]);for(let c of Object.keys(t.domains??{}))I.has(c)||n.push({severity:"warning",code:"DOMAIN_KEY_UNMATCHED",module:c,message:`integrations: domains.${c} 无对应槽位或需求声明(域前缀拼写错误?——键 = 槽位 id 点分前缀)`});if(p){let c=new Set,w=!1,x=k=>{typeof k!="string"||k.length===0||(p[k]&&c.add(k),!p[k]&&!v?.[k]&&(w=!0),v?.[k]&&(w=!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(c.size>0&&!w){let k=new Set;for(let T of c)for(let O of p[T]??[])k.add(O);let E=(T,O,P)=>{for(let[V]of Object.entries(T??{}))(P??k).has(V)||n.push({severity:"error",code:"DOMAIN_CONFIG_INVALID",message:`integrations: ${O} 键 ${V} 不在引用厂商(${[...c].join("/")})任何槽 schema properties 内(死配置)`})};E(t.config,"root.config");for(let[T,O]of Object.entries(t.configByInstance??{}))E(O,`root.configByInstance[${T}]`);for(let[T,O]of Object.entries(t.domains??{})){if(!O?.config)continue;let P=F(t,T).provider??void 0;if(P===void 0){E(O.config,`domains.${T}.config`);continue}let V=p[P];!V||v?.[P]||E(O.config,`domains.${T}.config`,new Set(V))}}}for(let[c,w]of Object.entries(o)){let x=t.services[c];if(!x){n.push({severity:"warning",code:"SLOT_NOT_CONFIGURED",service:c,message:`integrations: 服务槽 ${c}(需求方 ${w.owners.join(", ")})未配置${w.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:c,instance:k.join(", "),message:`integrations: ${c} 实例禁用(${k.join(", ")})`})}for(let[c,w]of Object.entries(t.modules??{})){let x=R?.[c];R&&!(c in R)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:c,message:`integrations: modules.${c} 未命中已装模块(键 = install id——检查 .tbox/app.json entry.id / packages/ 目录名)`});for(let[k,E]of Object.entries(w?.resources??{})){let T=E?.type;(typeof T!="string"||!r.RESOURCE_TYPE_IDS.includes(T))&&n.push({severity:"error",code:"RESOURCE_TYPE_UNKNOWN",module:c,message:`integrations: modules.${c}.resources.${k} type 非法(${String(T)};词汇表 = ${r.RESOURCE_TYPE_IDS.join("/")})`}),x&&x.size>0&&!x.has(k)&&n.push({severity:"warning",code:"RESOURCE_NOT_DECLARED",module:c,message:`integrations: modules.${c}.resources.${k} 未被模块 manifest contributes.resources 声明`})}}return n}function X(e,n){return`${e}\0${n}`}import{existsSync as ke,readFileSync as rt,readdirSync as it}from"fs";import{join as ce}from"path";function pn(e){return e.replaceAll("-","_").toUpperCase()}function un(e){if(!ke(e))return null;try{let n=JSON.parse(rt(e,"utf8"));return n&&typeof n=="object"?n:null}catch{return null}}function ot(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 be(e,n,r,t=process.env){let i={};for(let[m,I]of Object.entries(n.catalog.providers))for(let[c,w]of Object.entries(I))i[`${m}\0${c}`]={services:[...w.services],owner:w.owner,credentialType:w.credentialType};let o={};for(let[m,I]of Object.entries(n.catalog.services))o[m]={optional:I.optional,owners:[...I.owners]};let s={},f={},u={},p={};for(let m of n.modules){p[m.id]=new Set((m.descriptor.contributes.resources??[]).map(I=>I.id));for(let I of m.descriptor.contributes.providers?.slots??[]){if(I.configSchema){let c=un(ce(m.dir,I.configSchema));if(c){let w=s[I.provider]??=new Set;for(let x of ot(c))w.add(x)}else f[I.provider]=!0}I.credentialSchema&&!ke(ce(m.dir,I.credentialSchema))&&(u[I.credentialType]=!0)}}let v={},S=new Set,d=ce(e,"config","credentials");if(ke(d))for(let m of it(d)){if(!m.endsWith(".json"))continue;let I=m.slice(0,-5);S.add(I);let c=un(ce(d,m));c&&typeof c.type=="string"&&(v[I]=c.type)}let y=r,R=[],a=m=>{typeof m=="string"&&m.startsWith("secret://")&&R.push(m)};for(let m of Object.values(y.services??{}))if(m&&typeof m=="object"){a(m.credentialRef);for(let I of Object.values(m.instances??{}))I&&typeof I=="object"&&a(I.credentialRef)}for(let m of Object.values(y.credentialRefByInstance??{}))a(m);a(y.credentialRef);let l={};for(let m of R){let I=m.slice(9);t[pn(I)]===void 0&&(S.has(I)||(l[I]=!0))}let g=[];for(let[m,I]of Object.entries(y.services??{})){let c=I&&typeof I=="object"&&typeof I.provider=="string"?I.provider:void 0;for(let[w,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;c&&k&&k!==c&&g.push(`integrations: ${m}@${w} 实现覆盖跨厂商(${c} → ${k})——凭据域切换,确认该 mall 对应凭据在场`)}}let C=((Array.isArray(y.instances)?y.instances:void 0)??[]).map(m=>m&&typeof m=="object"&&typeof m.id=="string"?m.id:void 0).filter(m=>typeof m=="string");return{suppliedProviders:i,demandedServices:o,credentialFileMissing:l,credentialFileType:v,credentialSchemaMissing:u,vendorConfigKeys:s,vendorConfigSchemaMissing:f,realmSwitchHints:g,moduleResourceNeeds:p,...C.length>0?{malls:C}:{}}}import{existsSync as $,readdirSync as Ce,readFileSync as J}from"fs";import{join as j}from"path";import{existsSync as st,readFileSync as fn,mkdirSync as at,writeFileSync as ct}from"fs";import gn from"path";function le(e){return gn.join(e,".tbox","app.json")}function mn(e){let n=le(e);if(!st(n))return null;try{let r=JSON.parse(fn(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 lt(e,n){let r=le(e);at(gn.dirname(r),{recursive:!0}),ct(r,`${JSON.stringify(n,null,2)}
|
|
3
|
-
`,"utf8")}function Ae(e){let n=mn(e);if(n===null)return null;let r=le(e);try{let t=JSON.parse(fn(r,"utf8"));return{...n,miniappContainers:Array.isArray(t?.miniappContainers)?t.miniappContainers:[]}}catch{return{...n,miniappContainers:[]}}}function dt(e,n){let r=e.npmModules.filter(t=>t.id!==n.id);return{...e,npmModules:[...r,n]}}function ut(e,n){return{...e,npmModules:e.npmModules.filter(r=>r.id!==n)}}function pt(e,n){let r=(e.miniappContainers??[]).filter(t=>t.id!==n.id);return{...e,miniappContainers:[...r,n]}}function ft(e,n,r){return{...e,npmModules:e.npmModules.map(t=>t.id===n?{...t,...r}:t)}}function vn(e){return/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e)&&!e.includes("..")}function gt(e,n){if(!vn(e))throw new Error(`非法模块 id "${e}"(来自 ${n}):仅允许小写字母/数字/中划线`)}function de(e,n){let r=t=>{try{let i=JSON.parse(t),o=G(i);if(o.ok)return{kind:"strict",name:o.value.name,version:o.value.version,descriptor:o.value,contributes:o.value.contributes};if(i&&typeof i=="object"&&"contributes"in i){let s=i;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(!$(e))return null;try{return r(J(e,"utf8"))}catch{return null}}function mt(e){let n=j(e,".tbox","app.json");if(!$(n))return[];try{let r=JSON.parse(J(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 vt(e){let n=j(e,".tbox-dev.local"),r=j(n,"dev-manifest.json");if(!$(r))return[];try{let t=JSON.parse(J(r,"utf8")),i=[];for(let[o,s]of Object.entries(t.redirects??{}))typeof s!="string"||!o.startsWith("@tbox.cn/app-")||i.push({pkg:o,dir:j(n,s)});return i}catch{return[]}}function yt(e,n){let r=[],t=[e];for(let o of["apps","packages"]){let s=j(e,o);if($(s))try{for(let f of Ce(s,{withFileTypes:!0}))f.isDirectory()&&t.push(j(s,f.name))}catch{}}let i=new Set;for(let o of t){let s=j(o,"node_modules","@tbox.cn");if(!$(s))continue;let f=[];try{f=Ce(s)}catch{continue}for(let u of f){let p=j(s,u);if(i.has(p))continue;i.add(p);let v=j(p,"service-slots.json");if(!$(v))continue;let S=y=>{try{let R=JSON.parse(y);if(Array.isArray(R.slots))return R.slots.filter(a=>typeof a=="string")}catch{}return null},d=n?n.read(v,S):S(J(v,"utf8"));d!=null&&r.push({dir:p,slots:d})}}return r}function N(e,n){let r=[],t={providers:{},services:{},credentialTypes:{}},i={},o=[],s=new Set,f=new Map,u=(d,y,R)=>{for(let a of d){let l=t.providers[a.provider]??={},g=l[a.implementation];g?g.services.includes(a.service)||g.services.push(a.service):(l[a.implementation]={provider:a.provider,implementation:a.implementation,credentialType:a.credentialType,owner:y,...a.local?{local:!0}:{},...a.configSchema?{configSchema:a.configSchema}:{},...a.credentialSchema?{credentialSchema:a.credentialSchema}:{},services:[a.service]},t.credentialTypes[a.credentialType]??={owner:y,packageDir:R,...a.credentialSchema?{credentialSchema:a.credentialSchema}:{}});let b=`${a.provider}\0${a.service}`;i[b]||(i[b]={...a.configSchema?{configSchema:a.configSchema}:{},...a.credentialSchema?{credentialSchema:a.credentialSchema}:{},packageDir:R})}},p=(d,y)=>{let R=d.optional!==!1,a=d.defaults??[],l=t.services[d.service];if(l){l.optional=l.optional&&R;let C=new Set(l.defaults.map(m=>`${m.provider}\0${m.implementation}`));for(let m of a){let I=`${m.provider}\0${m.implementation}`;C.has(I)||(l.defaults.push(m),C.add(I))}l.owners.includes(y)||l.owners.push(y);return}t.services[d.service]={optional:R,defaults:[...a],...d.title?{title:d.title}:{},...d.description?{description:d.description}:{},owners:[y]};let g=d.service.includes(".")?d.service.slice(0,d.service.indexOf(".")):d.service,b=f.get(g);b===void 0?f.set(g,y):b!==y&&o.push({severity:"warning",code:"DOMAIN_KEY_CONFLICT",module:y,message:`域键 ${g} 被多模块声明(${b} 与 ${y})——domains 换算歧义(P13)`})};for(let d of mt(e)){if(s.has(d.id))continue;let y=j(e,"packages",d.id),R=j(e,"node_modules",...d.package.split("/")),a=de(j(y,"tbox.module.json"),n)??de(j(R,"tbox.module.json"),n);if(!a)continue;s.add(d.id);let l=$(j(y,"tbox.module.json"))?y:R,g=a.contributes;a.kind==="strict"&&r.push({id:d.id,dir:l,pkg:d.mode==="sdk"?d.package:`@app/${d.id}`,descriptor:a.descriptor});let b=g.providers?.slots??[];b.length&&u(b,d.package,l);let C=g.services??[];if(C.length)for(let m of C)p(m,d.package)}for(let{pkg:d,dir:y}of vt(e)){let R=de(j(y,"tbox.module.json"),n);if(!R?.name||s.has(R.name))continue;s.add(R.name);let a=R.contributes.providers?.slots??[];a.length&&u(a,d,y);let l=R.contributes.services??[];if(l.length)for(let g of l)p(g,d)}let v=j(e,"packages");if($(v)){let d=[];try{d=Ce(v,{withFileTypes:!0}).filter(y=>y.isDirectory()).map(y=>y.name)}catch{}for(let y of d){if(s.has(y))continue;let R=j(v,y),a=de(j(R,"tbox.module.json"),n);if(!a)continue;let l=a.name??y;if(s.has(l))continue;s.add(l);let g=a.contributes;a.kind==="strict"&&r.push({id:l,dir:R,pkg:`@app/${l}`,descriptor:a.descriptor});let b=g.providers?.slots??[];b.length&&u(b,`@app/${l}`,R);let C=g.services??[];if(C.length)for(let m of C)p(m,`@app/${l}`)}}let S=new Set;for(let d of yt(e,n))for(let y of d.slots)S.add(y);return{modules:r,catalog:t,serviceSchemas:i,vocabulary:[...S].sort(),domainKeyIssues:o}}function yn(e,n,r){let t=j(e,"src",n,"index.ts");if(!$(t))return!1;try{let i=J(t,"utf8");return new RegExp(`export\\s+const\\s+${r}\\b`).test(i)}catch{return!1}}function St(e){let n=j(e,"src","server","index.ts");if(!$(n))return"";try{return J(n,"utf8")}catch{return""}}function Sn(e){return e.match(/declaration\s*:\s*\{[\s\S]*?moduleId\s*:\s*['"]([^'"]+)['"]/)?.[1]}function wt(e){let n=[],r=N(e),t=Ae(e),i=new Map;for(let o of t?.npmModules??[])i.set(o.id,o.mode);for(let o of r.modules){let s=i.get(o.id)??"local",f=yn(o.dir,"server","serverModule"),u=o.descriptor.contributes;n.push({id:o.id,pkg:s==="sdk"?o.pkg:`@app/${o.id}`,mode:s,hasServerEntry:f,hasClientEntry:yn(o.dir,"client","clientModule"),hasCards:(u.cards?.length??0)>0,...f?{moduleId:Sn(St(o.dir))}:{}})}return n.sort((o,s)=>o.id.localeCompare(s.id))}import{existsSync as kr,readFileSync as br}from"fs";import{join as Cr,resolve as xr}from"path";function xe(e){return N(e).catalog}function wn(e){let n=N(e).catalog,r={};for(let[o,s]of Object.entries(n.providers)){r[o]={};for(let[f,u]of Object.entries(s))r[o][f]={provider:u.provider,implementation:u.implementation,credentialType:u.credentialType,owner:u.owner,...u.local?{local:!0}:{},...u.configSchema?{configSchema:u.configSchema}:{},...u.credentialSchema?{credentialSchema:u.credentialSchema}:{},services:[...u.services]}}let t={};for(let[o,s]of Object.entries(n.services))t[o]={optional:s.optional,defaults:s.defaults.map(f=>({...f})),owners:[...s.owners]};let i={};for(let[o,s]of Object.entries(n.credentialTypes))i[o]={owner:s.owner,...s.credentialSchema?{credentialSchema:s.credentialSchema}:{}};return{providers:r,services:t,credentialTypes:i}}import{existsSync as ht,readFileSync as Rt}from"fs";import{join as hn}from"path";var It=hn("config","integrations.json");function Y(e,n){let r=hn(e,It),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!ht(r))return null;try{return t(Rt(r,"utf8"))}catch{return null}}async function Rn(e,n){let r=await M(e),t=Y(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 o=i.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 校验失败",o.length>0?o:void 0)}throw new A("VALIDATION_FAILED",400,i instanceof Error?i.message:String(i))}return{config:t,strict:!1,contracts:r}}function ne(e,n,r){return e.includes(r)||n.includes(r)}import{existsSync as Cn,readFileSync as xn}from"fs";import{join as H,resolve as Ct}from"path";import xt from"ajv";var te=["provider","config","configByInstance","credentialRef","credentialRefByInstance","instances","defaultInstanceId"];import{readdirSync as kt,existsSync as ue,readFileSync as bt}from"fs";import{join as pe}from"path";function In(e,n,r){let t=[];if(n){let i=z({provider:e});t.push({stem:i,ref:`secret://${i}`,input:n})}for(let[i,o]of Object.entries(r??{})){let s=z({provider:e,instanceId:i});t.push({instanceId:i,stem:s,ref:`secret://${s}`,input:o})}return t}function kn(e,n,r,t,i){let o=[];if(t){let s=z({provider:e,service:n});o.push({stem:s,ref:`secret://${s}`,input:t})}for(let[s,f]of Object.entries(i??{})){let u=z({provider:e,instanceId:s,domain:r});o.push({instanceId:s,stem:u,ref:`secret://${u}`,input:f})}return o}function Oe(e,n,r){return n.map(t=>({stem:t.stem,ref:t.ref,overwrote:r?ue(pe(e,D(t.stem))):Re(e,t.stem,t.input)}))}function At(e,n){return ue(pe(e,D(n)))}function Ee(e,n){if(typeof e=="string"){e.startsWith("secret://")&&n.add(e.slice(9));return}if(Array.isArray(e)){for(let r of e)Ee(r,n);return}if(e&&typeof e=="object")for(let r of Object.values(e))Ee(r,n)}function Me(e){let n=pe(e,"config","credentials"),r=new Set,t=pe(e,"config","integrations.json");if(ue(t))try{Ee(JSON.parse(bt(t,"utf8")),r)}catch{}let i=[];if(!ue(n))return i;let o=[];try{o=kt(n).filter(s=>s.endsWith(".json")).map(s=>s.slice(0,-5))}catch{return i}for(let s of o.sort()){if(r.has(s))continue;let f=Q(e,s);i.push({severity:"warning",code:"ORPHANED_CREDENTIAL",message:`${D(s)} 不再被引用(凭据文件保留,可手动清理)`})}return i}var B=H("config","integrations.json");function Z(e,n){if(e===n)return!0;if(Array.isArray(e)&&Array.isArray(n))return e.length!==n.length?!1:e.every((r,t)=>Z(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=>Z(e[i],n[i]))}return!1}function me(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"&&!W.test(t))throw new A("VALIDATION_FAILED",400,`${r} 名含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`${n}.${r}`]);me(t,`${n}.${r}`)}}function fe(e,n,r){if(!(!e||typeof e!="object"||Array.isArray(e))){for(let t of Object.keys(e))if(!(r&&(t==="*"||t==="**"))&&!W.test(t))throw new A("VALIDATION_FAILED",400,`${n} 键 ${t} 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)——进凭据 stem 派生,防路径逃逸`,[n])}}function bn(e,n,r){if(r==="root"){let t=e.instances;Array.isArray(t)&&t.forEach((i,o)=>{let s=i&&typeof i=="object"?i.id:void 0;if(typeof s=="string"&&!W.test(s))throw new A("VALIDATION_FAILED",400,`instances[${o}].id 含非法字符(需 /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/)`,[`root.instances[${o}].id`])}),fe(e.configByInstance,"root.configByInstance",!1),fe(e.credentialRefByInstance,"root.credentialRefByInstance",!1)}else fe(e.instances,"services.instances",!0);fe(n.credentialsByInstance,"credentialsByInstance",!1)}function ge(e,n){let r=H(e,B),t=i=>JSON.parse(i);if(n)return n.read(r,t)??null;if(!Cn(r))return null;try{return t(xn(r,"utf8"))}catch{return null}}function Te(e){let n=(e.instances??[]).map(r=>r.id);return n.length===0?[]:Ie(e,n)}function Et(e,n,r,t){let{catalog:i}=N(e,t),o=i.providers[n];if(!o)return;let s=new Set;for(let f of Object.values(o))(r===void 0||f.services.includes(r))&&s.add(f.credentialType);return s.size===1?[...s][0]:void 0}function An(e,n,r,t,i,o){if(typeof t.type!="string"||t.type.length===0)throw new A("VALIDATION_FAILED",400,"凭据 type 缺失或为空字符串",["credentials.type"]);let s=i??Et(e,n,r,o);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:f}=N(e,o),u=f[`${n}\0${r}`];if(!u?.credentialSchema)return;let p=Ct(u.packageDir,u.credentialSchema);if(Cn(p))try{let S=new xt({allErrors:!0}).compile(JSON.parse(xn(p,"utf8")));if(!S({type:t.type,...t.values})){let d=(S.errors??[]).map(y=>`credentials.values.${String(y.instancePath||y.params?.missingProperty||"").replace(/^\//,"")}`);throw new A("VALIDATION_FAILED",400,"凭据字段校验失败(ajv 字段级)",d)}}catch(v){if(v instanceof A)throw v}}function je(e,n={}){let{onApplied:r,cache:t}=n;function i(p,v,S,d){let y=p!==null,R=v.length>0,a=!d&&y,l=!d&&R;a&&(_(H(e,B),`${JSON.stringify(p,null,2)}
|
|
4
|
-
`),
|
|
5
|
-
`),t?.invalidate([
|
|
6
|
-
`)}
|
|
7
|
-
`)}return{generated:!0,reason:"generated",services:r.map(o=>o.service).sort()}}function En(e){return e.replace(/^@tbox\.cn\/app-/,"").replace(/^@[^/]+\//,"")}function Tt(e){return En(e.id).startsWith("provider-")||En(e.pkg).startsWith("provider-")}function Ne(e){return{modules:e.walk.modules.filter(r=>!Tt(r)).map(r=>({id:r.id,name:r.descriptor.name,title:r.descriptor.name,description:""})).sort((r,t)=>r.id.localeCompare(t.id))}}function Ve(e,n){let r=e.walk.modules.find(u=>u.id===n);if(!r)throw new A("MODULE_NOT_FOUND",404,`模块 ${n} 非已装模块`);let t=(r.descriptor.contributes.services??[]).map(u=>({service:u.service,...u.title?{title:u.title}:{},...u.description?{description:u.description}:{},required:u.optional===!1})),i=U(e.walk,r),o=e.integrations?.domains??{},s=i.writable?o[i.domainKey]??null:null,f=i.domainKeys.map(u=>{let p=F(e.integrations,u);return{domain:u,effective:p.provider,layer:p.layer}});return{domainKeys:[...i.domainKeys],integration:s,providerBindings:f,configEditable:i.writable,services:t}}function On(e,n){let r=N(e.appDir,e.cache),t=Y(e.appDir,e.cache);return{appDir:e.appDir,walk:r,catalog:r.catalog,integrations:t,contracts:n}}function Mn(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 ve(e,n,r){let t=e.providers[n];return t?Object.values(t).some(i=>i.services.includes(r)):!1}function Tn(e,n){let r=[];for(let[t,i]of Object.entries(e.providers))Object.values(i).some(o=>o.services.includes(n))&&r.push(t);return r.sort()}function De(e){let n=Mn(e.walk),r=e.walk.vocabulary.filter(o=>!n.has(o)).map(o=>({service:o,required:!1})),t=e.integrations,i=null;if(t){let o={};for(let s of te)s in t&&(o[s]=t[s]);i=o}return{services:r,integration:i}}function Fe(e,n){let r=e.integrations?.services??{},t=e.catalog.services[n];if(!ne(e.walk.vocabulary,Object.keys(r),n))throw new A("SERVICE_NOT_FOUND",404,`服务 ${n} 不在服务词汇(已装契约包 ∪ 已配置)`);let i=r[n]??null;return{service:n,...t?.title?{title:t.title}:{title:n},...t?.description?{description:t.description}:{},required:t?!t.optional:!1,defaults:t?t.defaults.map(o=>({...o})):[],integration:i,suppliedBy:Tn(e.catalog,n)}}import{existsSync as Nn,readFileSync as Vn,realpathSync as jn}from"fs";import{isAbsolute as jt,join as Pt,relative as Nt,resolve as Pn,sep as Vt}from"path";function $e(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(o=>o.local===!0),owner:i[0].owner})}return{providers:n.sort((r,t)=>r.provider.localeCompare(t.provider))}}function _e(e,n,r){let t=e.catalog.providers[n];if(!t)throw new A("PROVIDER_NOT_FOUND",404,`厂商 ${n} 不 ∈ catalog(内联声明厂商无包级档案——身份与表单经组合端点暴露)`);let i={};for(let s of Object.values(t))for(let f of s.services)(i[f]??={implementations:[]}).implementations.push({implementation:s.implementation,credentialType:s.credentialType});if(r?.has("integrationSchemas"))for(let[s,f]of Object.entries(i))f.integrationSchemas={configSchema:K(e,n,s)};let o=Object.values(t);return{provider:n,local:o.every(s=>s.local===!0),owner:o[0].owner,services:i}}function Le(e,n,r){let t=e.catalog.providers[n],i=e.integrations?.services??{},o=[];if(t)for(let p of Object.values(t))p.services.includes(r)&&o.push({implementation:p.implementation,credentialType:p.credentialType});let s=i[r]?.provider,f=s&&typeof s=="object"&&s.provider===n?s:void 0;if(o.length===0&&!f)throw t?new A("SUPPLY_NOT_FOUND",404,`厂商 ${n} 未供给服务 ${r}(AI 帮我实现流:PUT 显式绑定后实施)`):new A("PROVIDER_NOT_FOUND",404,`厂商 ${n} 完全未知(不 ∈ catalog 且无任何内联声明)`);o.length===0&&f&&o.push({implementation:i[r]?.implementation??`${n}-inline@1`,credentialType:f.credentialType});let u=K(e,n,r,f?s?.configSchema:void 0);return{provider:n,service:r,implementations:o,integrationSchemas:{configSchema:u}}}function K(e,n,r,t){let i=e.walk.serviceSchemas[`${n}\0${r}`];return i?We(e.appDir,i.packageDir,i.configSchema):typeof t=="string"?Dt(e.appDir,t):null}function We(e,n,r){if(!r)return null;let t=Pt(n,r);if(!Nn(t))return null;try{return JSON.parse(Vn(t,"utf8"))}catch{return null}}function Dt(e,n){let r=Pn(e,"config","schemas"),t=Pn(e,n),i=Nt(r,t);if(i===""||i.startsWith("..")||jt(i))throw new A("VALIDATION_FAILED",400,"configSchema 引用必须落在 config/schemas/ 内(禁路径逃逸)",["provider.configSchema"]);if(!Nn(t))return null;let o,s;try{o=jn(r),s=jn(t)}catch{return null}if(s!==o&&!s.startsWith(o+Vt))throw new A("VALIDATION_FAILED",400,"configSchema 引用经 symlink 逃逸出 config/schemas/(realpath 复核拒绝)",["provider.configSchema"]);try{return JSON.parse(Vn(t,"utf8"))}catch{return null}}function Dn(e){return{version:e.version,evaluation:e.evaluation,strictValidation:e.strictValidation,notes:[...e.notes]}}function Fn(e,n,r){let t=e.integrations,i=L(n),o=t?.services?.[n],s=o?.instances?.[r]??o?.instances?.["*"];return s&&s.provider!==void 0?"instance":o?.provider!==void 0?"service":F(t,i).layer==="module"?"module":typeof t?.provider=="string"&&t.provider.length>0?"app":null}function $n(e,n,r,t,i){let o=n.resolveEffectiveService(e.integrations,r,t,i);if(o.status==="ok"&&o.effective){let s=o.effective.provider,f=typeof s=="string"?s:String(s?.provider??"");return{status:"ok",provider:f,implementation:o.effective.implementation,effective:{provider:f,implementation:o.effective.implementation,...o.effective.config!==void 0?{config:{...o.effective.config}}:{},...o.effective.credentialRef!==void 0?{credentialRef:o.effective.credentialRef}:{},layer:Fn(e,r,t)??"app"}}}return o.status==="binding-unresolved"?{status:"binding-unresolved",statusMessage:o.message}:{status:o.status}}function Be(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 Ke(e,n){let r=Be(n),{integrations:t,catalog:i}=n,o=r.buildSupplyLookup(i),s=t,u=r.normalizeInstances({instances:s?.instances,defaultInstanceId:s?.defaultInstanceId}).defaultInstanceId??"*",p=$n(n,r,e,u,o),v=Fn(n,e,u),S=n.integrations?.services?.[e]?.provider,d=p.provider??(typeof S=="string"?S:typeof S=="object"&&S?String(S.provider):void 0),y=new Set(Object.keys(n.catalog.providers)),R=d!==void 0&&y.has(d)?Ft(n.catalog,d,e):void 0,a=i.services[e],l=a!==void 0?!a.optional:void 0,g=a?.owners[0];return{status:p.status,...p.statusMessage?{statusMessage:p.statusMessage}:{},...d!==void 0?{provider:d}:{},...d!==void 0&&v!==null?{layer:v}:{},...R!==void 0?{supplied:R}:{},...g!==void 0?{module:g}:{},...l!==void 0?{required:l}:{}}}function Ft(e,n,r){return ve(e,n,r)}function re(e,n,r){let t=new Set([...e.walk.vocabulary,...Object.keys(e.catalog.services)]),i=e.integrations?.services??{};for(let s of Object.keys(i))t.add(s);let o={};for(let s of[...t].sort())r&&!r.includes(s)||(o[s]=Ke(s,e));return{contracts:Dn(e.contracts),resolutions:o,issues:n}}function ze(e,n,r){let t=Be(n),i=t.buildSupplyLookup(n.catalog),o=n.integrations,f=t.normalizeInstances({instances:o?.instances,defaultInstanceId:o?.defaultInstanceId}).instances.map(a=>a.id),u=n.integrations?.services?.[e],p=u?.instances?Object.keys(u.instances):void 0,v;f.length>0?(v=[...f],p?.includes("*")&&v.push("*")):p!==void 0&&p.length>0?v=p.includes("*")?["*"]:p:v=[];let S=v.map(a=>{let l=$n(n,t,e,a,i);return{instanceId:a,status:l.status,...l.statusMessage?{statusMessage:l.statusMessage}:{},...l.effective?{effective:l.effective}:{}}}),d=$t(n,e),R={...Ke(e,n),instances:S,inheritance:d};return{contracts:Dn(n.contracts),resolution:R,issues:r.filter(a=>a.service===e)}}function $t(e,n){let r=e.integrations,t=L(n),i=r?.services?.[n],o=e.integrations,f=Be(e).normalizeInstances({instances:o?.instances,defaultInstanceId:o?.defaultInstanceId}).defaultInstanceId??"*",u=i?.instances?.[f]??i?.instances?.["*"],p=F(r,t);return[{layer:"app",...r?.provider?{provider:r.provider}:{}},{layer:"module",...p.layer==="module"&&p.provider?{provider:p.provider}:{}},{layer:"service",...typeof i?.provider=="string"?{provider:i.provider}:{},...i?.implementation?{implementation:i.implementation}:{}},{layer:"instance",...u?.provider?{provider:u.provider}:{},...u?.implementation?{implementation:u.implementation}:{}}]}function Ue(e,n,r){if(n===null)return null;let t={};for(let i of r)t[i]={configSchema:K(e,n,i)};return{provider:n,services:t}}function q(e){return e===null||typeof e!="object"?JSON.stringify(e??null):Array.isArray(e)?`[${e.map(q).join(",")}]`:`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${q(e[r])}`).join(",")}}`}var _t="\0no-enum";function Lt(e){let n=e.enum;return Array.isArray(n)?`[${[...new Set(n.map(q))].sort().join(",")}]`:_t}function Wt(e){if(!e||typeof e!="object"||Array.isArray(e))return null;let n=e.type;return n===void 0?null:q(n)}function Bt(e){let n=e.map(t=>Wt(t.subschema));if(n.some(t=>t===null)||new Set(n).size>1)return null;if(n[0]==='"object"'){let t=q(e[0].subschema);return e.every(i=>q(i.subschema)===t)?e[0].subschema:null}return new Set(e.map(t=>Lt(t.subschema))).size===1?e[0].subschema:null}function _n(e,n){let r=[],t=!0,i=new Map;for(let[s,f]of Object.entries(e.services)){let u=f.configSchema;if(u===null){r.push(s);continue}if(!u||typeof u!="object"||Array.isArray(u))continue;let p=u;p.additionalProperties===!1&&(t=!1);let v=p.properties;if(!v||typeof v!="object"||Array.isArray(v))continue;let S=Array.isArray(p.required)?p.required:[];for(let d of Object.keys(v)){let y=i.get(d)??[];y.push({service:s,subschema:v[d],required:S.includes(d)}),i.set(d,y)}}let o=[];for(let[s,f]of i)o.push({key:s,schema:Bt(f),sources:f.map(({service:u,required:p})=>({service:u,required:p}))});return{provider:e.provider,schemaless:r,unsupplied:[...n?.unsupplied??[]],additionalPropertiesAllowed:t,fields:o}}function Ln(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 f=n.integrations?.provider;return typeof f=="string"&&f.length>0?f:null}let o=n.walk.modules.find(f=>f.id===r);if(!o)return null;let s=U(n.walk,o);return s.writable?i!==void 0?i:F(n.integrations,s.domainKey).provider:null}var Wn={integrationSchemas:null,integrationFieldRegistry:null};function Je(e,n){let r=Ln("app",e,void 0,n);if(r===null)return Wn;let t=Ue(e,r,ln(e.catalog,r));return{integrationSchemas:t,integrationFieldRegistry:_n(t)}}function Ye(e,n,r){let t=Ln("module",e,n,r),i=e.walk.modules.find(u=>u.id===n);if(t===null||!i)return Wn;let o=(i.descriptor.contributes.services??[]).map(u=>u.service),s=u=>ve(e.catalog,t,u),f=Ue(e,t,o.filter(s));return{integrationSchemas:f,integrationFieldRegistry:_n(f,{unsupplied:[...new Set(o.filter(u=>!s(u)))]})}}function Kt(e){return Je(e).integrationSchemas}function zt(e,n){return Ye(e,n).integrationSchemas}function He(e,n){let r=e.integrations?.services?.[n]?.provider;if(r===void 0||r===""){let t=F(e.integrations,L(n));return t.provider===null?null:{provider:t.provider,configSchema:K(e,t.provider,n)}}if(typeof r=="string")return{provider:r,configSchema:K(e,r,n)};if(ee(r)){let t=r;return{provider:t.provider,configSchema:K(e,t.provider,n,t.configSchema)}}return null}function ie(e,n){if(n===void 0||!n.startsWith("secret://"))return;let r=n.slice(9),t=Q(e,r);if(t)return{type:t.type,ref:n,file:D(r),masked:oe(t.values)}}function Ze(e){let n=e.integrations,r={credential:ie(e.appDir,typeof n?.credentialRef=="string"?n.credentialRef:void 0)??null,byInstance:{}};for(let{id:i}of n?.instances??[]){let o=n?.credentialRefByInstance?.[i];o!==void 0&&(r.byInstance[i]=ie(e.appDir,o)??null)}let t={};for(let[i,o]of Object.entries(n?.services??{})){let s={credential:ie(e.appDir,o.credentialRef)??null,byInstance:{}};for(let[f,u]of Object.entries(o.instances??{}))s.byInstance[f]=ie(e.appDir,u.credentialRef)??null;t[i]=s}return{app:r,services:t}}function qe(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?We(e.appDir,i.packageDir,i.credentialSchema):null}})}}import Ut from"path";var Jt={app:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],module:["serviceResolutions","integrationSchemas","integrationFieldRegistry"],provider:["integrationSchemas"],service:["integrationSchemas"]};function ye(e,n){if(!n||n.length===0)return new Set;let r=Jt[e],t=[...new Set(n)].filter(i=>!r.includes(i));if(t.length>0)throw new A("VALIDATION_FAILED",400,`include 含未知或不适用于本端点的键:${t.join("、")}(白名单:${r.join("、")})`,["include"]);return new Set(n)}var Bn=["integrationSchemas","integrationFieldRegistry"];function Kn(e,n,r){if(!(typeof n!="string"||n.length===0)&&!Bn.some(t=>r.has(t)))throw new A("VALIDATION_FAILED",400,`参数 ${e} 需与表单 include 键(${Bn.join("、")})同现——轴参仅重定向表单层双投影`,[e])}function Yt(e,n={}){let r=Se(),t=Promise.resolve(),i={appDir:e,cache:r};function o(a){if(!a.strictValidation)throw new A("CONTRACTS_NOT_RESOLVED",503,he(a))}function s(a){return On(i,a)}async function f(){let a=await M(e),l=s(a),g=l.integrations;if(g===null)return[];let b={resolveEffectiveService:u(a.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:u(a.module.buildSupplyLookup,"buildSupplyLookup"),moduleDomainOf:u(a.module.moduleDomainOf,"moduleDomainOf"),normalizeInstances:u(a.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:a.module.RESOURCE_TYPE_IDS??[]},C=be(e,l.walk,g,process.env);return ae({contracts:b,integrations:g,supplies:b.buildSupplyLookup(l.catalog),...C})}function u(a,l){if(typeof a!="function")throw new A("CONTRACTS_NOT_RESOLVED",503,`contracts 求值面 ${l} 缺席(形态异常)`);return a}function p(a){let l=t.then(a,a);return t=l.catch(()=>{}),l}let v={async loadModules(){let a=await M(e);return Ne(s(a))},async loadModule(a,l){let g=ye("module",l?.include);Kn("moduleProvider",l?.moduleProvider,g);let b=await M(e),C=s(b),m=Ve(C,a);if(g.has("serviceResolutions")&&(m.serviceResolutions=b.evaluation&&b.strictValidation?await f().then(I=>re(C,I,m.services.map(c=>c.service))):null),g.has("integrationSchemas")||g.has("integrationFieldRegistry")){let I=Ye(C,a,l?.moduleProvider);g.has("integrationSchemas")&&(m.integrationSchemas=I.integrationSchemas),g.has("integrationFieldRegistry")&&(m.integrationFieldRegistry=I.integrationFieldRegistry)}return m},async loadApp(a){let l=ye("app",a?.include);Kn("appProvider",a?.appProvider,l);let g=await M(e),b=s(g),C=De(b);if(l.has("serviceResolutions")&&(C.serviceResolutions=g.evaluation&&g.strictValidation?await f().then(m=>re(b,m)):null),l.has("integrationSchemas")||l.has("integrationFieldRegistry")){let m=Je(b,a?.appProvider);l.has("integrationSchemas")&&(C.integrationSchemas=m.integrationSchemas),l.has("integrationFieldRegistry")&&(C.integrationFieldRegistry=m.integrationFieldRegistry)}return C},async loadService(a,l){let g=ye("service",l?.include),b=await M(e),C=s(b),m=Fe(C,a);return g.has("integrationSchemas")&&(m.integrationSchemas=He(C,a)),m},async loadServiceResolutions(a){let l=await M(e);o(l);let g=await f();return re(s(l),g,a)},async loadServiceResolution(a){let l=await M(e);o(l);let g=await f();return ze(a,s(l),g)},async loadProviders(){let a=await M(e);return $e(s(a))},async loadProvider(a,l){let g=ye("provider",l?.include),b=await M(e);return _e(s(b),a,g)},async loadProviderService(a,l){let g=await M(e);return Le(s(g),a,l)},async loadCredentials(){let a=await M(e);return Ze(s(a))},async loadCredentialTypes(a){let l=await M(e);return qe(s(l),a)}},S=je(e,{onApplied:n.onApplied,cache:r}),d={async writeAppIntegration(a,l){await S.warmup();let g=await M(e);return o(g),p(()=>S.applyApp(a,l))},async writeModuleIntegration(a,l,g){await S.warmup();let b=await M(e);return o(b),p(()=>S.applyModule(a,l,g))},async writeServiceIntegration(a,l,g){await S.warmup();let b=await M(e);return o(b),p(()=>S.applyService(a,l,g))},async deleteServiceIntegration(a){await S.warmup();let l=await M(e);return o(l),p(()=>S.deleteService(a))}},y={invalidate(){r.invalidate(),we(e)},async resolveContracts(){return M(e)},walkManifests(){return R(e)},parseModuleDescriptor(a){return G(a)},loadProviderCatalogRaw(){return xe(e)},async readIntegrationsConfig(){return Y(e,r)},async writeIntegrationsConfig(a){await S.warmup();let l=await M(e);return o(l),p(()=>Ht(e,a,r))},async ensureMockBindings(){await S.warmup();let a=await M(e);return o(a),p(()=>Pe(e))},async evaluateIntegrationServices(a){await S.warmup();let l=await M(e);o(l);let g={resolveEffectiveService:u(l.module.resolveEffectiveService,"resolveEffectiveService"),buildSupplyLookup:u(l.module.buildSupplyLookup,"buildSupplyLookup"),moduleDomainOf:u(l.module.moduleDomainOf,"moduleDomainOf"),normalizeInstances:u(l.module.normalizeInstances,"normalizeInstances"),RESOURCE_TYPE_IDS:l.module.RESOURCE_TYPE_IDS??[]};return ae({...a,contracts:g})}};function R(a){return N(a,r)}return{...v,...d,...y}}function Ht(e,n,r){let t=Ut.join(e,"config","integrations.json");_(t,`${JSON.stringify(n,null,2)}
|
|
8
|
-
`),r.invalidate([t])}export{te as APP_INTEGRATION_NODE_KEYS,A as AppToolkitError,W as SAFE_NAME_PATTERN,gt as assertValidModuleId,be as buildPredicateAssembly,Ie as checkInstanceKeys,wt as collectDeclaredModules,he as contractsNotResolvedMessage,Yt as createAppToolkit,Se as createFileCache,je as createWriteCore,At as credentialArtifactExists,Z as deepEqual,z as deriveStem,ie as echoForRef,an as ensureDir,Pe as ensureMockBindings,ae as evaluateIntegrationServices,Yn as expandEnvVars,Sn as extractModuleIdFromSource,we as invalidateContractsResolver,ee as isControlledInlineProvider,vn as isValidModuleId,Kt as loadAppIntegrationSchemas,De as loadAppView,qe as loadCredentialTypesView,Ze as loadCredentialsView,Ve as loadModuleDetailView,zt as loadModuleIntegrationSchemas,Ne as loadModulesView,wn as loadProviderCatalog,xe as loadProviderCatalogRaw,_e as loadProviderDetailView,Le as loadProviderServiceDetailView,$e as loadProvidersView,Fe as loadServiceDetailView,He as loadServiceIntegrationSchemas,ze as loadServiceResolutionDetail,re as loadServiceResolutionsView,le as manifestPath,oe as maskCredentialValues,Xe as moduleDependencySchema,rn as moduleDescriptorSchema,Ge as pageContribSchema,G as parseModuleDescriptor,en as providerSlotContribSchema,mn as readAppManifest,Ae as readAppManifestFull,Q as readCredentialFile,Y as readIntegrationsConfig,Rn as readIntegrationsStrict,Me as reconcileOrphanCredentials,pn as refToEnvKey,ut as removeNpmModule,M as resolveContractsForApp,M as resolveContractsForAppExport,Ue as resolveLayerIntegrationSchemas,Ke as resolveServiceSummary,tn as resourceNeedContribSchema,nn as serviceNeedContribSchema,D as stemToFilePath,Qn as stemToRef,Qe as tabContribSchema,ft as updateNpmModule,pt as upsertMiniappContainer,dt as upsertNpmModule,N as walkManifests,lt as writeAppManifest,_ as writeAtomic,Re as writeCredentialFile};
|
|
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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbox.cn/app-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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.
|
|
21
|
+
"@tbox.cn/app-contracts": "0.11.0",
|
|
22
22
|
"typescript": "5.9.3",
|
|
23
23
|
"tsup": "8.5.1",
|
|
24
24
|
"vitest": "4.1.10",
|