@supersoniks/concorde 4.9.91 → 4.9.93
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/ai/cursor/rules/concorde.mdc +7 -0
- package/ai/jetbrains/rules/concorde.md +6 -0
- package/ai/skills/concorde/SKILL.md +48 -0
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +257 -257
- package/concorde-core.es.js +3174 -3086
- package/dist/concorde-core.bundle.js +257 -257
- package/dist/concorde-core.es.js +3174 -3086
- package/dist/js/core/decorators/api.js +168 -63
- package/dist/js/core/decorators/api.js.map +1 -1
- package/dist/js/core/utils/api.js +29 -8
- package/dist/js/core/utils/api.js.map +1 -1
- package/dist/types/core/decorators/api.d.ts +30 -16
- package/dist/types/core/decorators/api.d.ts.map +1 -1
- package/dist/types/core/utils/api.d.ts +1 -1
- package/dist/types/core/utils/api.d.ts.map +1 -1
- package/docs/assets/{index-BL6WVF7g.css → index-D2Q3JyQ6.css} +1 -1
- package/docs/assets/{index-DVn8AeyA.js → index-DURr6O71.js} +466 -568
- package/docs/crawl/docs/_decorators/get.html +35 -10
- package/docs/crawl/docs/_decorators/patch.html +13 -5
- package/docs/crawl/docs/_decorators/post.html +39 -10
- package/docs/crawl/docs/_decorators/put.html +13 -5
- package/docs/crawl/hubs/decorators.html +43 -40
- package/docs/crawl/hubs/remote-data.html +43 -40
- package/docs/index.html +2 -2
- package/docs/llms-full.txt +98 -23
- package/docs/llms.txt +1 -1
- package/docs/src/docs/_decorators/get.md +39 -5
- package/docs/src/docs/_decorators/patch.md +8 -3
- package/docs/src/docs/_decorators/post.md +39 -6
- package/docs/src/docs/_decorators/put.md +8 -3
- package/docs/src/docs/search/docs-search.json +103 -183
- package/docs/src/tsconfig.json +268 -268
- package/package.json +1 -1
- package/src/core/decorators/api.post.spec.ts +101 -6
- package/src/core/decorators/api.spec.ts +137 -6
- package/src/core/decorators/api.ts +304 -148
- package/src/core/utils/api.spec.ts +73 -0
- package/src/core/utils/api.ts +44 -11
- package/src/docs/_decorators/get.md +43 -5
- package/src/docs/_decorators/patch.md +16 -2
- package/src/docs/_decorators/post.md +23 -7
- package/src/docs/_decorators/put.md +16 -2
- package/src/docs/components/docs-demo-sources.ts +22 -8
- package/src/docs/example/decorators-demo-post.ts +70 -0
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +61 -2
- package/src/docs/search/docs-search.json +122 -7
- package/src/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -95,14 +95,14 @@ describe("post", () => {
|
|
|
95
95
|
vi.mocked(API.prototype.postDetailed).mockClear();
|
|
96
96
|
|
|
97
97
|
pub.set({ value: "second" });
|
|
98
|
-
localPost.send(el);
|
|
99
|
-
await flushSendFrames();
|
|
98
|
+
const payload = await localPost.send(el);
|
|
100
99
|
|
|
101
100
|
expect(API.prototype.postDetailed).toHaveBeenCalledTimes(1);
|
|
102
101
|
expect(API.prototype.postDetailed).toHaveBeenCalledWith(
|
|
103
102
|
"items/local-send",
|
|
104
103
|
{ value: "second" },
|
|
105
104
|
);
|
|
105
|
+
expect(payload?.result).toEqual({ ok: true });
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
it("peut décorer une méthode avec send après sa résolution", async () => {
|
|
@@ -303,6 +303,91 @@ describe("post", () => {
|
|
|
303
303
|
);
|
|
304
304
|
expect(el.payload?.result).toEqual({ ok: true });
|
|
305
305
|
});
|
|
306
|
+
|
|
307
|
+
it("transmet le payload complet et conserve le retrigger du POST", async () => {
|
|
308
|
+
const bodyPubId = "postSpecHandlerBody";
|
|
309
|
+
const triggerPubId = "postSpecHandlerTrigger";
|
|
310
|
+
PublisherManager.get(bodyPubId).set({ tick: 1 });
|
|
311
|
+
const bodyKey = new DataProviderKey<{ tick: number }>(bodyPubId);
|
|
312
|
+
const triggerKey = new DataProviderKey<number>(triggerPubId);
|
|
313
|
+
const ep = new Endpoint<{ ok: boolean }>("items/handler");
|
|
314
|
+
const localPost = post(ep, bodyKey, {
|
|
315
|
+
autoPostOnBodyMutation: false,
|
|
316
|
+
triggerKey,
|
|
317
|
+
});
|
|
318
|
+
const received: Array<ApiResult<{ ok: boolean }> | undefined> = [];
|
|
319
|
+
const errorPayload = mockPayload({ ok: false });
|
|
320
|
+
errorPayload.response = new Response(JSON.stringify({ error: true }), {
|
|
321
|
+
status: 409,
|
|
322
|
+
headers: { "Content-Type": "application/json" },
|
|
323
|
+
});
|
|
324
|
+
vi.mocked(API.prototype.postDetailed).mockResolvedValueOnce(
|
|
325
|
+
errorPayload as never,
|
|
326
|
+
);
|
|
327
|
+
const tag = "test-api-post-handler";
|
|
328
|
+
|
|
329
|
+
class C extends HTMLElement {
|
|
330
|
+
@localPost
|
|
331
|
+
onPayload(payload: ApiResult<{ ok: boolean }> | undefined) {
|
|
332
|
+
received.push(payload);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (!customElements.get(tag)) {
|
|
336
|
+
customElements.define(tag, C);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const wrap = document.createElement("div");
|
|
340
|
+
wrap.setAttribute("serviceURL", "https://api.example.test");
|
|
341
|
+
const el = document.createElement(tag) as InstanceType<typeof C>;
|
|
342
|
+
wrap.appendChild(el);
|
|
343
|
+
document.body.appendChild(wrap);
|
|
344
|
+
await flushSendFrames();
|
|
345
|
+
|
|
346
|
+
expect(API.prototype.postDetailed).not.toHaveBeenCalled();
|
|
347
|
+
await localPost.send(el);
|
|
348
|
+
expect(received).toHaveLength(1);
|
|
349
|
+
expect(received[0]?.response?.status).toBe(409);
|
|
350
|
+
|
|
351
|
+
PublisherManager.get(triggerPubId).invalidate();
|
|
352
|
+
await flushSendFrames();
|
|
353
|
+
expect(API.prototype.postDetailed).toHaveBeenCalledTimes(2);
|
|
354
|
+
expect(received).toHaveLength(2);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("transmet undefined à une méthode @post sur une erreur de transport", async () => {
|
|
358
|
+
const bodyPubId = "postSpecHandlerTransportBody";
|
|
359
|
+
PublisherManager.get(bodyPubId).set({ tick: 1 });
|
|
360
|
+
const bodyKey = new DataProviderKey<{ tick: number }>(bodyPubId);
|
|
361
|
+
const ep = new Endpoint<{ ok: boolean }>("items/handler-transport");
|
|
362
|
+
const localPost = post(ep, bodyKey, {
|
|
363
|
+
autoPostOnBodyMutation: false,
|
|
364
|
+
});
|
|
365
|
+
const received: Array<ApiResult<{ ok: boolean }> | undefined> = [];
|
|
366
|
+
vi.mocked(API.prototype.postDetailed).mockRejectedValueOnce(
|
|
367
|
+
new Error("network failure"),
|
|
368
|
+
);
|
|
369
|
+
const tag = "test-api-post-handler-transport";
|
|
370
|
+
|
|
371
|
+
class C extends HTMLElement {
|
|
372
|
+
@localPost
|
|
373
|
+
onPayload(payload: ApiResult<{ ok: boolean }> | undefined) {
|
|
374
|
+
received.push(payload);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (!customElements.get(tag)) {
|
|
378
|
+
customElements.define(tag, C);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const wrap = document.createElement("div");
|
|
382
|
+
wrap.setAttribute("serviceURL", "https://api.example.test");
|
|
383
|
+
const el = document.createElement(tag) as InstanceType<typeof C>;
|
|
384
|
+
wrap.appendChild(el);
|
|
385
|
+
document.body.appendChild(wrap);
|
|
386
|
+
await flushSendFrames();
|
|
387
|
+
|
|
388
|
+
await expect(localPost.send(el)).rejects.toThrow("network failure");
|
|
389
|
+
expect(received).toEqual([undefined]);
|
|
390
|
+
});
|
|
306
391
|
});
|
|
307
392
|
|
|
308
393
|
describe("put / patch", () => {
|
|
@@ -319,11 +404,15 @@ describe("put / patch", () => {
|
|
|
319
404
|
PublisherManager.get(bodyPubId).set({ name: "x" });
|
|
320
405
|
const bodyKey = new DataProviderKey<{ name: string }>(bodyPubId);
|
|
321
406
|
const ep = new Endpoint<{ ok: boolean }>("items/1");
|
|
407
|
+
const localPut = put(ep, bodyKey);
|
|
408
|
+
const received: Array<ApiResult<{ ok: boolean }> | undefined> = [];
|
|
322
409
|
const tag = "test-api-put";
|
|
323
410
|
|
|
324
411
|
class C extends HTMLElement {
|
|
325
|
-
@
|
|
326
|
-
payload: ApiResult<{ ok: boolean }> |
|
|
412
|
+
@localPut
|
|
413
|
+
onPayload(payload: ApiResult<{ ok: boolean }> | undefined) {
|
|
414
|
+
received.push(payload);
|
|
415
|
+
}
|
|
327
416
|
}
|
|
328
417
|
if (!customElements.get(tag)) {
|
|
329
418
|
customElements.define(tag, C);
|
|
@@ -338,6 +427,7 @@ describe("put / patch", () => {
|
|
|
338
427
|
expect(API.prototype.putDetailed).toHaveBeenCalledWith("items/1", {
|
|
339
428
|
name: "x",
|
|
340
429
|
});
|
|
430
|
+
expect(received).toHaveLength(1);
|
|
341
431
|
});
|
|
342
432
|
|
|
343
433
|
it("@patch appelle patchDetailed", async () => {
|
|
@@ -348,11 +438,15 @@ describe("put / patch", () => {
|
|
|
348
438
|
PublisherManager.get(bodyPubId).set({ name: "y" });
|
|
349
439
|
const bodyKey = new DataProviderKey<{ name: string }>(bodyPubId);
|
|
350
440
|
const ep = new Endpoint<{ ok: boolean }>("items/1");
|
|
441
|
+
const localPatch = patch(ep, bodyKey);
|
|
442
|
+
const received: Array<ApiResult<{ ok: boolean }> | undefined> = [];
|
|
351
443
|
const tag = "test-api-patch";
|
|
352
444
|
|
|
353
445
|
class C extends HTMLElement {
|
|
354
|
-
@
|
|
355
|
-
payload: ApiResult<{ ok: boolean }> |
|
|
446
|
+
@localPatch
|
|
447
|
+
onPayload(payload: ApiResult<{ ok: boolean }> | undefined) {
|
|
448
|
+
received.push(payload);
|
|
449
|
+
}
|
|
356
450
|
}
|
|
357
451
|
if (!customElements.get(tag)) {
|
|
358
452
|
customElements.define(tag, C);
|
|
@@ -367,5 +461,6 @@ describe("put / patch", () => {
|
|
|
367
461
|
expect(API.prototype.patchDetailed).toHaveBeenCalledWith("items/1", {
|
|
368
462
|
name: "y",
|
|
369
463
|
});
|
|
464
|
+
expect(received).toHaveLength(1);
|
|
370
465
|
});
|
|
371
466
|
});
|
|
@@ -190,6 +190,96 @@ describe("get", () => {
|
|
|
190
190
|
expect(el.payload?.result).toEqual({ id: "loaded" });
|
|
191
191
|
});
|
|
192
192
|
|
|
193
|
+
it("transmet le payload complet à une méthode @get", async () => {
|
|
194
|
+
const itemEp = new Endpoint<{ id: string }>("items/handler");
|
|
195
|
+
const received: Array<ApiResult<{ id: string }> | undefined> = [];
|
|
196
|
+
const tag = "test-api-get-handler";
|
|
197
|
+
const errorPayload = mockPayload({ id: "error" });
|
|
198
|
+
errorPayload.response = new Response(JSON.stringify({ error: true }), {
|
|
199
|
+
status: 422,
|
|
200
|
+
headers: { "Content-Type": "application/json" },
|
|
201
|
+
});
|
|
202
|
+
vi.mocked(API.prototype.getDetailed).mockResolvedValueOnce(
|
|
203
|
+
errorPayload as never,
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
class C extends HTMLElement {
|
|
207
|
+
@get(itemEp)
|
|
208
|
+
onPayload(payload: ApiResult<{ id: string }> | undefined) {
|
|
209
|
+
received.push(payload);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (!customElements.get(tag)) {
|
|
213
|
+
customElements.define(tag, C);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const wrap = document.createElement("div");
|
|
217
|
+
wrap.setAttribute("serviceURL", "https://api.example.test");
|
|
218
|
+
wrap.appendChild(document.createElement(tag));
|
|
219
|
+
document.body.appendChild(wrap);
|
|
220
|
+
await flushGetFrames();
|
|
221
|
+
|
|
222
|
+
expect(received).toHaveLength(1);
|
|
223
|
+
expect(received[0]?.result).toEqual({ id: "error" });
|
|
224
|
+
expect(received[0]?.response?.status).toBe(422);
|
|
225
|
+
expect(received[0]?.request.url).toContain("api.example.test");
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("transmet undefined à une méthode @get quand aucun payload n'est produit", async () => {
|
|
229
|
+
vi.mocked(API.prototype.getDetailed).mockResolvedValueOnce(undefined);
|
|
230
|
+
const itemEp = new Endpoint<{ id: string }>("items/handler-error");
|
|
231
|
+
const received: Array<ApiResult<{ id: string }> | undefined> = [];
|
|
232
|
+
const tag = "test-api-get-handler-undefined";
|
|
233
|
+
|
|
234
|
+
class C extends HTMLElement {
|
|
235
|
+
@get(itemEp)
|
|
236
|
+
onPayload(payload: ApiResult<{ id: string }> | undefined) {
|
|
237
|
+
received.push(payload);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (!customElements.get(tag)) {
|
|
241
|
+
customElements.define(tag, C);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const wrap = document.createElement("div");
|
|
245
|
+
wrap.setAttribute("serviceURL", "https://api.example.test");
|
|
246
|
+
wrap.appendChild(document.createElement(tag));
|
|
247
|
+
document.body.appendChild(wrap);
|
|
248
|
+
await flushGetFrames();
|
|
249
|
+
|
|
250
|
+
expect(received).toEqual([undefined]);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("permet d'appliquer un handle get directement à une méthode", async () => {
|
|
254
|
+
const itemEp = new Endpoint<{ id: string }>("items/method");
|
|
255
|
+
const localGet = get(itemEp);
|
|
256
|
+
const received: Array<ApiResult<{ id: string }> | undefined> = [];
|
|
257
|
+
const tag = "test-api-get-method-handler";
|
|
258
|
+
|
|
259
|
+
class C extends HTMLElement {
|
|
260
|
+
@localGet
|
|
261
|
+
onPayload(payload: ApiResult<{ id: string }> | undefined) {
|
|
262
|
+
received.push(payload);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (!customElements.get(tag)) {
|
|
266
|
+
customElements.define(tag, C);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const wrap = document.createElement("div");
|
|
270
|
+
wrap.setAttribute("serviceURL", "https://api.example.test");
|
|
271
|
+
const el = document.createElement(tag) as InstanceType<typeof C>;
|
|
272
|
+
wrap.appendChild(el);
|
|
273
|
+
document.body.appendChild(wrap);
|
|
274
|
+
await flushGetFrames();
|
|
275
|
+
|
|
276
|
+
expect(received).toHaveLength(1);
|
|
277
|
+
expect(received[0]?.result).toEqual({ id: "loaded" });
|
|
278
|
+
|
|
279
|
+
await localGet.refetch(el);
|
|
280
|
+
expect(received).toHaveLength(2);
|
|
281
|
+
});
|
|
282
|
+
|
|
193
283
|
it("expose un refetch local avant et après le premier payload", async () => {
|
|
194
284
|
const pubId = "getSpecLocalRefetch";
|
|
195
285
|
PublisherManager.get(pubId).set(staticConfig);
|
|
@@ -209,16 +299,18 @@ describe("get", () => {
|
|
|
209
299
|
const el = document.createElement(tag) as InstanceType<typeof C>;
|
|
210
300
|
document.body.appendChild(el);
|
|
211
301
|
|
|
212
|
-
localGet.refetch(el);
|
|
213
|
-
|
|
302
|
+
const firstRefetch = localGet.refetch(el);
|
|
303
|
+
expect(firstRefetch).toBeInstanceOf(Promise);
|
|
304
|
+
const firstPayload = await firstRefetch;
|
|
214
305
|
expect(API.prototype.getDetailed).toHaveBeenCalledTimes(1);
|
|
306
|
+
expect(firstPayload?.result).toEqual({ id: "loaded" });
|
|
215
307
|
|
|
216
308
|
vi.mocked(API.prototype.getDetailed).mockClear();
|
|
217
309
|
el.payload = mockPayload({ id: "manual" });
|
|
218
|
-
localGet.refetch(el);
|
|
219
|
-
await flushGetFrames();
|
|
310
|
+
const secondPayload = await localGet.refetch(el);
|
|
220
311
|
|
|
221
312
|
expect(API.prototype.getDetailed).toHaveBeenCalledTimes(1);
|
|
313
|
+
expect(secondPayload?.result).toEqual({ id: "loaded" });
|
|
222
314
|
expect(el.payload?.result).toEqual({ id: "loaded" });
|
|
223
315
|
});
|
|
224
316
|
|
|
@@ -246,8 +338,7 @@ describe("get", () => {
|
|
|
246
338
|
vi.mocked(API.prototype.getDetailed).mockClear();
|
|
247
339
|
|
|
248
340
|
el.remove();
|
|
249
|
-
localGet.refetch(el);
|
|
250
|
-
await flushGetFrames();
|
|
341
|
+
await localGet.refetch(el);
|
|
251
342
|
|
|
252
343
|
expect(API.prototype.getDetailed).not.toHaveBeenCalled();
|
|
253
344
|
});
|
|
@@ -289,6 +380,46 @@ describe("get", () => {
|
|
|
289
380
|
expect(API.prototype.getDetailed).toHaveBeenCalledWith("rows/84");
|
|
290
381
|
});
|
|
291
382
|
|
|
383
|
+
it("attend le refetch avant la méthode avec when before", async () => {
|
|
384
|
+
const pubId = "getSpecMethodRefetchBefore";
|
|
385
|
+
PublisherManager.get(pubId).set(staticConfig);
|
|
386
|
+
const confKey = new DataProviderKey<APIConfiguration>(pubId);
|
|
387
|
+
const localGet = get(
|
|
388
|
+
new Endpoint<{ id: string }>("items/before"),
|
|
389
|
+
confKey,
|
|
390
|
+
);
|
|
391
|
+
const events: string[] = [];
|
|
392
|
+
const tag = "test-api-get-method-refetch-before";
|
|
393
|
+
|
|
394
|
+
class C extends HTMLElement {
|
|
395
|
+
@localGet
|
|
396
|
+
payload: ApiResult<{ id: string }> | null = null;
|
|
397
|
+
|
|
398
|
+
@refetch(localGet, { when: "before" })
|
|
399
|
+
reload() {
|
|
400
|
+
events.push("method");
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (!customElements.get(tag)) {
|
|
404
|
+
customElements.define(tag, C);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const el = document.createElement(tag) as InstanceType<typeof C>;
|
|
408
|
+
document.body.appendChild(el);
|
|
409
|
+
await flushGetFrames();
|
|
410
|
+
vi.mocked(API.prototype.getDetailed).mockClear();
|
|
411
|
+
events.length = 0;
|
|
412
|
+
vi.mocked(API.prototype.getDetailed).mockImplementation(async () => {
|
|
413
|
+
events.push("request");
|
|
414
|
+
return mockPayload({ id: "loaded" }) as never;
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
await el.reload();
|
|
418
|
+
|
|
419
|
+
expect(events).toEqual(["request", "method"]);
|
|
420
|
+
expect(API.prototype.getDetailed).toHaveBeenCalledWith("items/before");
|
|
421
|
+
});
|
|
422
|
+
|
|
292
423
|
it("refetch automatique avec refetchEveryMs", async () => {
|
|
293
424
|
vi.useFakeTimers();
|
|
294
425
|
const itemEp = new Endpoint<{ id: string }>("items/1");
|