@tbox.cn/app-toolkit 0.2.0 → 0.3.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.
@@ -9,11 +9,28 @@ import type { ViewSnapshot } from './context.js';
9
9
  * v4.4 D34:domainKeys/providerBindings/configEditable 显式化;integration 仅单域
10
10
  * (writable)时在场——多域/零域/共享键无单键落点;多域回退兜底键机器拆除
11
11
  * (派生统一 = domainOfService 去重集合,moduleDomainWritable 单源)。
12
+ * 2026-09-16 双缺陷批:loadModulesView 排除 provider 家族包(供给/实施载体非可配置
13
+ * 业务模块)——walk 声明集与 loadModuleDetailView 不变(装包仍合法,详情保持 200)。
12
14
  */
13
15
 
14
- /** GET /modules:纯模块清单(demand 不在——卡片展开 = GET /modules/:m) */
16
+ /** 家族名归一(cli deriveModuleId 同源语义——依赖方向禁 import,故内联):
17
+ * `@tbox.cn/app-provider-x` / `@app/provider-y` / `provider-z` → `provider-*` */
18
+ function familyName(s: string): string {
19
+ return s.replace(/^@tbox\.cn\/app-/, '').replace(/^@[^/]+\//, '');
20
+ }
21
+
22
+ /** provider 家族包判定(模块清单排除供给/实施载体;生态三先例同源:verify-cli 排除判定 /
23
+ * guard-vendor-neutrality「provider-* 包」/ cli deriveModuleId 家族推导)。install id 与
24
+ * 包名 basename 双查 = 防 .tbox/app.json 登记漂移纵深;命名而非结构(provider-custom 零贡献
25
+ * 空壳与「零贡献合法」形态不可结构区分);未来收敛 = manifest 显式角色标记(届时整体退场)。 */
26
+ function isProviderFamily(mod: { id: string; pkg: string }): boolean {
27
+ return familyName(mod.id).startsWith('provider-') || familyName(mod.pkg).startsWith('provider-');
28
+ }
29
+
30
+ /** GET /modules:纯模块清单(demand 不在——卡片展开 = GET /modules/:m;provider 家族包不在清单) */
15
31
  export function loadModulesView(snapshot: ViewSnapshot): { modules: ModuleDeclaration[] } {
16
32
  const modules: ModuleDeclaration[] = snapshot.walk.modules
33
+ .filter((mod) => !isProviderFamily(mod))
17
34
  .map((mod) => ({
18
35
  id: mod.id,
19
36
  name: mod.descriptor.name,
@@ -42,10 +42,7 @@ export function loadProviderDetailView(snapshot: ViewSnapshot, provider: string,
42
42
  }
43
43
  if (include?.has('integrationSchemas')) {
44
44
  for (const [service, bucket] of Object.entries(services)) {
45
- const schemaEntry = snapshot.walk.serviceSchemas[`${provider}\u0000${service}`];
46
- bucket.integrationSchemas = {
47
- configSchema: schemaEntry ? readSchemaRef(snapshot.appDir, schemaEntry.packageDir, schemaEntry.configSchema) : null,
48
- };
45
+ bucket.integrationSchemas = { configSchema: resolveServiceConfigSchema(snapshot, provider, service) };
49
46
  }
50
47
  }
51
48
  const entries = Object.values(impls);
@@ -95,22 +92,15 @@ export function loadProviderServiceDetailView(
95
92
  implementations.push({ implementation: configured[service]?.implementation ?? `${provider}-inline@1`, credentialType: inlineDeclaration.credentialType });
96
93
  }
97
94
 
98
- // integrationSchemas:catalog schema(复合键)优先;内联声明 configSchema 引用应用 config/schemas/
99
- // (路径约束 H9——resolve 落 config/schemas/ + realpath 复核,违例 400)
100
- // v4.4 F5 消重:schema 表取自 snapshot.walk(原 walkManifests(appDir) 重复全量目录扫描);
101
- // v4.4 D33:credentialSchema 删净(结构归 GET /credential-types——组合单体纯 config)
102
- let configSchema: object | null = null;
103
- const schemaEntry = snapshot.walk.serviceSchemas[`${provider}\u0000${service}`];
104
- if (schemaEntry) {
105
- configSchema = readSchemaRef(snapshot.appDir, schemaEntry.packageDir, schemaEntry.configSchema);
106
- } else if (inlineDeclaration) {
107
- // 内联声明 schema 解析:引用文件在 integrations 节点(provider.configSchema)——
108
- // 形状同 config/schemas/ 约束(路径来源 = 节点声明,由服务端读应用侧)
109
- const inlineSchemaRef = (inline as { configSchema?: string } | undefined)?.configSchema;
110
- if (typeof inlineSchemaRef === 'string') {
111
- configSchema = readInlineSchema(snapshot.appDir, inlineSchemaRef);
112
- }
113
- }
95
+ // integrationSchemas:schema 解析收口 resolveServiceConfigSchema 单源(v4.7 D38——catalog 复合键 >
96
+ // 内联 ref,等价重构 O6/O7/O15 零改动即证);内联 ref 来源 = 节点声明(provider.configSchema,
97
+ // 仅受控内联声明匹配本厂商名时);路径约束 H9——resolve config/schemas/ + realpath 复核,违例 400
98
+ const configSchema = resolveServiceConfigSchema(
99
+ snapshot,
100
+ provider,
101
+ service,
102
+ inlineDeclaration ? (inline as { configSchema?: string } | undefined)?.configSchema : undefined,
103
+ );
114
104
 
115
105
  return {
116
106
  provider,
@@ -120,6 +110,22 @@ export function loadProviderServiceDetailView(
120
110
  };
121
111
  }
122
112
 
113
+ /** per-(provider, service) schema 复合解析单源(v4.7 D38):catalog 复合键(多 impl 声明序首个)
114
+ * > 内联 ref(readInlineSchema 保持私有——H9 双钉子不扩暴露);miss / 未声明 / 文件缺失 → null。
115
+ * views 层 \u0000 复合键唯一消费点(组合单体 / 供给轴批量 / 层级核心 / 服务级 include 同源)。
116
+ * (D36 registry 批若需跨包消费再升 index 导出——additive 零成本) */
117
+ export function resolveServiceConfigSchema(
118
+ snapshot: ViewSnapshot,
119
+ provider: string,
120
+ service: string,
121
+ inlineRef?: string,
122
+ ): object | null {
123
+ const entry = snapshot.walk.serviceSchemas[`${provider}\u0000${service}`];
124
+ if (entry) return readSchemaRef(snapshot.appDir, entry.packageDir, entry.configSchema);
125
+ if (typeof inlineRef === 'string') return readInlineSchema(snapshot.appDir, inlineRef);
126
+ return null;
127
+ }
128
+
123
129
  /** catalog schema 引用读取(相对包根;缺席 → null——SCHEMA_FILE_MISSING 归谓词 #6)。
124
130
  * v4.4 导出共享:层级内嵌(integration-schemas.ts)/ 凭据结构清单(credential-types.ts)同源消费。 */
125
131
  export function readSchemaRef(_appDir: string, packageDir: string, ref: string | undefined): object | null {
@@ -180,7 +180,9 @@ describe('Freshness Contract W3/W7 — agent 动线矩阵(工厂方法级;FX
180
180
  }),
181
181
  );
182
182
  const modules = await tk.loadModules();
183
- expect(modules.modules.map((m) => m.id)).toContain('provider-x');
183
+ // provider 家族包不在清单(2026-09-16 bug-fix)——排除本身随目录新增即时生效;
184
+ // loadModules 新鲜度由下方 case c(module-sdk-y)承载,供给轴新鲜度见下两行
185
+ expect(modules.modules.map((m) => m.id)).not.toContain('provider-x');
184
186
  const providers = await tk.loadProviders();
185
187
  expect(providers.providers.map((p) => p.provider)).toContain('joycity');
186
188