@tbox.cn/app-toolkit 0.1.0 → 0.2.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/README.md +2 -2
- package/dist/{chunk-VV3ERZXS.js → chunk-KPD3LUH4.js} +1 -1
- package/dist/contracts-resolver-E4SECBOG.js +1 -0
- package/dist/index.d.ts +157 -32
- package/dist/index.js +7 -7
- package/package.json +1 -1
- package/src/assembly/provider-catalog.ts +6 -1
- package/src/assembly/walk-manifests.ts +2 -1
- package/src/core/contracts-resolver.ts +3 -2
- package/src/core/credential-format.ts +4 -2
- package/src/core/errors.ts +9 -3
- package/src/dto.ts +81 -11
- package/src/factory.ts +84 -13
- package/src/index.ts +13 -4
- package/src/integrations/domain-binding.ts +81 -0
- package/src/integrations/predicate.ts +5 -5
- package/src/integrations/read.ts +23 -3
- package/src/integrations/write.ts +78 -23
- package/src/views/app.ts +7 -5
- package/src/views/context.ts +3 -6
- package/src/views/credential-types.ts +28 -0
- package/src/views/credentials.ts +57 -0
- package/src/views/integration-schemas.ts +53 -0
- package/src/views/modules.ts +15 -13
- package/src/views/providers.ts +18 -9
- package/src/views/service-detail.ts +3 -4
- package/src/views/service-resolutions.ts +31 -25
- package/tests/credentials-view.test.ts +152 -0
- package/tests/demo-app.ts +14 -1
- package/tests/naming-alignment.test.ts +8 -5
- package/tests/vendor-schema-keywords.test.ts +101 -0
- package/tests/views.test.ts +414 -10
- package/tests/write-core.test.ts +81 -4
- package/dist/contracts-resolver-QM4FBQQV.js +0 -1
package/tests/write-core.test.ts
CHANGED
|
@@ -22,10 +22,16 @@ interface Harness {
|
|
|
22
22
|
credFile(stem: string): string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
function harness(opts: { rejectMarker?: string } = {}): Harness {
|
|
25
|
+
function harness(opts: { rejectMarker?: string; zodRejectPaths?: string[][] } = {}): Harness {
|
|
26
26
|
const app = createTempApp('tbox-write-core-');
|
|
27
27
|
const store = join(app.appDir, 'contracts-store');
|
|
28
|
-
writeFakeContractsPackage(store, {
|
|
28
|
+
writeFakeContractsPackage(store, {
|
|
29
|
+
version: '0.9.0',
|
|
30
|
+
withStrict: true,
|
|
31
|
+
rejectMarker: opts.rejectMarker,
|
|
32
|
+
zodRejectPaths: opts.zodRejectPaths,
|
|
33
|
+
slots: ['parking.query'],
|
|
34
|
+
});
|
|
29
35
|
linkContracts(app.appDir, store, { subdir: 'apps/server' });
|
|
30
36
|
writeAppFile(app.appDir, INTEGRATIONS_FILE, JSON.stringify({ services: {} }, null, 2));
|
|
31
37
|
const tk = createAppToolkit(app.appDir);
|
|
@@ -122,18 +128,89 @@ describe('写核心管线(FX-1c)', () => {
|
|
|
122
128
|
expect(readFileSync(h.credFile('joycity-parking.query'), 'utf8')).toBe(before);
|
|
123
129
|
});
|
|
124
130
|
|
|
125
|
-
it('T5
|
|
131
|
+
it('T5 严格校验失败次序(A1):400 VALIDATION_FAILED + message 直通 + 凭据零落盘 + integrations 零变更', async () => {
|
|
126
132
|
h.app.dispose();
|
|
127
133
|
h = harness({ rejectMarker: '__reject__' });
|
|
128
134
|
await expect(
|
|
129
135
|
h.tk.writeServiceIntegration('parking.query', { provider: 'joycity', __reject__: true } as never, {
|
|
130
136
|
credentials: { type: 'api-key', values: { apiKey: 'X' } },
|
|
131
137
|
}),
|
|
132
|
-
).rejects.
|
|
138
|
+
).rejects.toMatchObject({
|
|
139
|
+
code: 'VALIDATION_FAILED',
|
|
140
|
+
httpStatus: 400,
|
|
141
|
+
message: expect.stringContaining('fake strict reject'),
|
|
142
|
+
});
|
|
133
143
|
expect(existsSync(h.credFile('joycity-parking.query'))).toBe(false);
|
|
134
144
|
expect((h.readConfig().services as Record<string, unknown>)['parking.query']).toBeUndefined();
|
|
135
145
|
});
|
|
136
146
|
|
|
147
|
+
it('T9 zod 形拒绝(A1):400 + fields 节点相对前缀剥离(applyService)', async () => {
|
|
148
|
+
h.app.dispose();
|
|
149
|
+
h = harness({ zodRejectPaths: [['services', 'parking.query', 'config', 'x']] });
|
|
150
|
+
await expect(
|
|
151
|
+
h.tk.writeServiceIntegration('parking.query', { provider: 'joycity', config: { x: 1 } }),
|
|
152
|
+
).rejects.toMatchObject({ code: 'VALIDATION_FAILED', httpStatus: 400, fields: ['config.x'] });
|
|
153
|
+
expect(existsSync(h.credFile('joycity-parking.query'))).toBe(false);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('T10 zod 形拒绝 root 级(A1):applyApp fields 原样(无前缀可剥)', async () => {
|
|
157
|
+
h.app.dispose();
|
|
158
|
+
h = harness({ zodRejectPaths: [['config', 'requestTimeoutMs']] });
|
|
159
|
+
await expect(
|
|
160
|
+
h.tk.writeAppIntegration({ provider: 'mock-x', config: { requestTimeoutMs: 1 } } as never),
|
|
161
|
+
).rejects.toMatchObject({ code: 'VALIDATION_FAILED', httpStatus: 400, fields: ['config.requestTimeoutMs'] });
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('T11 敌对服务名(A2):路径参数不在词汇 → 404(身份判据先于 deriveStem)', async () => {
|
|
165
|
+
await expect(
|
|
166
|
+
h.tk.writeServiceIntegration('a/b', { provider: 'joycity' }, { credentials: { type: 'api-key', values: { apiKey: 'X' } } }),
|
|
167
|
+
).rejects.toMatchObject({ code: 'SERVICE_NOT_FOUND', httpStatus: 404 });
|
|
168
|
+
await expect(h.tk.deleteServiceIntegration('a/b')).rejects.toMatchObject({ code: 'SERVICE_NOT_FOUND', httpStatus: 404 });
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('T11b 敌对 provider 值位(第一道防线对照):400 + fields', async () => {
|
|
172
|
+
await expect(
|
|
173
|
+
h.tk.writeServiceIntegration('parking.query', { provider: 'a/b' }, { credentials: { type: 'api-key', values: { apiKey: 'X' } } }),
|
|
174
|
+
).rejects.toMatchObject({ code: 'VALIDATION_FAILED', httpStatus: 400, fields: ['root.provider'] });
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('T12 credentials 缺 type(A1):400 fields credentials.type(无声明厂商亦要求非空字符串)', async () => {
|
|
178
|
+
await expect(
|
|
179
|
+
h.tk.writeServiceIntegration('parking.query', { provider: 'joycity' }, { credentials: { type: '', values: { apiKey: 'X' } } }),
|
|
180
|
+
).rejects.toMatchObject({ code: 'VALIDATION_FAILED', httpStatus: 400, fields: ['credentials.type'] });
|
|
181
|
+
await expect(
|
|
182
|
+
h.tk.writeAppIntegration({ provider: 'p-x' } as never, {
|
|
183
|
+
credentialsByInstance: { 'm-1': { values: { apiKey: 'X' } } },
|
|
184
|
+
} as never),
|
|
185
|
+
).rejects.toMatchObject({ code: 'VALIDATION_FAILED', httpStatus: 400, fields: ['credentials.type'] });
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('W1 未知服务 PUT/DELETE 404(A2):词汇 ∪ 已配置判据外', async () => {
|
|
189
|
+
await expect(h.tk.writeServiceIntegration('typo.query', { provider: 'mock' })).rejects.toMatchObject({
|
|
190
|
+
code: 'SERVICE_NOT_FOUND',
|
|
191
|
+
httpStatus: 404,
|
|
192
|
+
});
|
|
193
|
+
await expect(h.tk.deleteServiceIntegration('typo.query')).rejects.toMatchObject({
|
|
194
|
+
code: 'SERVICE_NOT_FOUND',
|
|
195
|
+
httpStatus: 404,
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('W2 已配置孤儿键 PUT/DELETE 200(A2 判据含已配置——词汇外可继续写/删)', async () => {
|
|
200
|
+
// 预置孤儿键(不在词汇)+ 节点变更(避开 no-diff 短路——本用例锚身份判据非幂等语义)
|
|
201
|
+
writeAppFile(h.app.appDir, INTEGRATIONS_FILE, JSON.stringify({ services: { 'orphan.key': { provider: 'mock', config: { a: 1 } } } }, null, 2));
|
|
202
|
+
const r = await h.tk.writeServiceIntegration('orphan.key', { provider: 'mock' });
|
|
203
|
+
expect(r.written).toBe(true);
|
|
204
|
+
const d = await h.tk.deleteServiceIntegration('orphan.key');
|
|
205
|
+
expect(d.written).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('W3 词汇成员 DELETE 缺席节点:幂等 written:false(幂等语义仅判据内成员保留)', async () => {
|
|
209
|
+
const r = await h.tk.deleteServiceIntegration('parking.query');
|
|
210
|
+
expect(r.written).toBe(false);
|
|
211
|
+
expect(r.files).toEqual([]);
|
|
212
|
+
});
|
|
213
|
+
|
|
137
214
|
it('T6 恶意 map 键 400(F4):instances id / slot instances 键 / credentialsByInstance 键 / ByInstance 键', async () => {
|
|
138
215
|
// root.instances[].id
|
|
139
216
|
await expect(
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as a,c as b}from"./chunk-VV3ERZXS.js";export{b as invalidateContractsResolver,a as resolveContractsForApp};
|