@supersoniks/concorde 4.9.92 → 4.9.94
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 +299 -292
- package/concorde-core.es.js +10139 -6035
- package/dist/concorde-core.bundle.js +299 -292
- package/dist/concorde-core.es.js +10139 -6035
- package/dist/docs-mock-api-sw.js +110 -0
- package/dist/docs-mock-api-sw.js.map +3 -3
- package/dist/js/core/components/functional/functional.js +1 -0
- package/dist/js/core/components/functional/functional.js.map +1 -1
- package/dist/js/core/components/functional/jsonata/jsonata.js +119 -0
- package/dist/js/core/components/functional/jsonata/jsonata.js.map +1 -0
- package/dist/js/core/components/ui/button/button.js +1 -1
- package/dist/js/core/components/ui/button/button.js.map +1 -1
- package/dist/js/core/decorators/Subscriber.js +1 -0
- package/dist/js/core/decorators/Subscriber.js.map +1 -1
- package/dist/js/core/decorators/api.js +108 -16
- package/dist/js/core/decorators/api.js.map +1 -1
- package/dist/js/core/decorators/subscriber/derive.js +60 -0
- package/dist/js/core/decorators/subscriber/derive.js.map +1 -0
- package/dist/js/core/utils/api.js +29 -8
- package/dist/js/core/utils/api.js.map +1 -1
- package/dist/js/core/utils/derive.js +246 -0
- package/dist/js/core/utils/derive.js.map +1 -0
- package/dist/js/core/utils/jsonataHelpers.js +69 -0
- package/dist/js/core/utils/jsonataHelpers.js.map +1 -0
- package/dist/js/core/utils/jsonataRuntime.js +75 -0
- package/dist/js/core/utils/jsonataRuntime.js.map +1 -0
- package/dist/js/utils.js +2 -0
- package/dist/js/utils.js.map +1 -1
- package/dist/types/core/components/functional/functional.d.ts +1 -0
- package/dist/types/core/components/functional/functional.d.ts.map +1 -1
- package/dist/types/core/components/functional/jsonata/jsonata.d.ts +29 -0
- package/dist/types/core/components/functional/jsonata/jsonata.d.ts.map +1 -0
- package/dist/types/core/components/ui/button/button.d.ts +1 -1
- package/dist/types/core/components/ui/button/button.d.ts.map +1 -1
- package/dist/types/core/components/ui/form/checkbox/checkbox.d.ts +3 -3
- package/dist/types/core/components/ui/form/input/input.d.ts +3 -3
- package/dist/types/core/components/ui/form/input-autocomplete/input-autocomplete.d.ts +3 -3
- package/dist/types/core/components/ui/form/textarea/textarea.d.ts +3 -3
- package/dist/types/core/decorators/Subscriber.d.ts +2 -0
- package/dist/types/core/decorators/Subscriber.d.ts.map +1 -1
- package/dist/types/core/decorators/api.d.ts +21 -12
- package/dist/types/core/decorators/api.d.ts.map +1 -1
- package/dist/types/core/decorators/subscriber/derive.d.ts +30 -0
- package/dist/types/core/decorators/subscriber/derive.d.ts.map +1 -0
- package/dist/types/core/utils/api.d.ts +1 -1
- package/dist/types/core/utils/api.d.ts.map +1 -1
- package/dist/types/core/utils/derive.d.ts +40 -0
- package/dist/types/core/utils/derive.d.ts.map +1 -0
- package/dist/types/core/utils/jsonataHelpers.d.ts +15 -0
- package/dist/types/core/utils/jsonataHelpers.d.ts.map +1 -0
- package/dist/types/core/utils/jsonataRuntime.d.ts +13 -0
- package/dist/types/core/utils/jsonataRuntime.d.ts.map +1 -0
- package/dist/types/mixins.d.ts +3 -3
- package/dist/types/utils.d.ts +2 -0
- package/dist/types/utils.d.ts.map +1 -1
- package/docs/assets/{index-DURr6O71.js → index-DpIkksht.js} +652 -479
- package/docs/crawl/docs/_decorators/get.html +27 -6
- package/docs/crawl/docs/_decorators/patch.html +6 -0
- package/docs/crawl/docs/_decorators/post.html +8 -0
- package/docs/crawl/docs/_decorators/put.html +6 -0
- package/docs/crawl/hubs/decorators.html +36 -31
- package/docs/crawl/hubs/remote-data.html +36 -31
- package/docs/index.html +1 -1
- package/docs/llms-full.txt +47 -3
- package/docs/src/docs/_decorators/get.md +31 -0
- package/docs/src/docs/_decorators/patch.md +9 -0
- package/docs/src/docs/_decorators/post.md +11 -0
- package/docs/src/docs/_decorators/put.md +9 -0
- package/docs/src/docs/search/docs-search.json +120 -5
- package/docs/src/tsconfig.json +268 -268
- package/package.json +28 -3
- package/public/docs-mock-api-sw.js +110 -0
- package/public/docs-mock-api-sw.js.map +3 -3
- package/src/core/components/functional/functional.ts +1 -0
- package/src/core/components/functional/jsonata/jsonata.md +56 -0
- package/src/core/components/functional/jsonata/jsonata.spec.ts +202 -0
- package/src/core/components/functional/jsonata/jsonata.ts +116 -0
- package/src/core/components/ui/button/button.ts +2 -2
- package/src/core/decorators/Subscriber.ts +2 -0
- package/src/core/decorators/api.post.spec.ts +99 -4
- package/src/core/decorators/api.spec.ts +90 -0
- package/src/core/decorators/api.ts +212 -92
- package/src/core/decorators/subscriber/derive.ts +95 -0
- package/src/core/utils/api.spec.ts +73 -0
- package/src/core/utils/api.ts +44 -11
- package/src/core/utils/derive.spec.ts +190 -0
- package/src/core/utils/derive.ts +357 -0
- package/src/core/utils/jsonataHelpers.ts +100 -0
- package/src/core/utils/jsonataRuntime.ts +88 -0
- package/src/docs/_core-concept/dataFlow.md +9 -0
- package/src/docs/_decorators/get.md +31 -0
- package/src/docs/_decorators/patch.md +9 -0
- package/src/docs/_decorators/post.md +11 -0
- package/src/docs/_decorators/put.md +9 -0
- package/src/docs/_misc/docs-mock-api.md +3 -0
- package/src/docs/components/docs-demo-sources.ts +40 -0
- package/src/docs/docs.ts +1 -0
- package/src/docs/example/decorators-demo-post.ts +70 -0
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +59 -0
- package/src/docs/example/docs-jsonata-demos.ts +128 -0
- package/src/docs/mock-api/fixtures-jsonata.ts +131 -0
- package/src/docs/mock-api/router.ts +26 -0
- package/src/docs/navigation/navigation.ts +4 -0
- package/src/docs/search/docs-search.json +300 -5
- package/src/tsconfig.json +18 -0
- package/src/tsconfig.tsbuildinfo +1 -1
- package/src/utils.ts +13 -0
|
@@ -228,36 +228,72 @@ class ApiOperationController {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
type
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
231
|
+
type ApiHandlerMethod<T> = (this: object, payload?: ApiResult<T>) => void;
|
|
232
|
+
|
|
233
|
+
export interface GetDecoratorHandle<T, Host extends object = object> {
|
|
234
|
+
(
|
|
235
|
+
target: object,
|
|
236
|
+
propertyKey: string | symbol,
|
|
237
|
+
descriptor: TypedPropertyDescriptor<ApiHandlerMethod<T>>,
|
|
238
|
+
): void;
|
|
239
|
+
<K extends string>(
|
|
240
|
+
target: Host & {
|
|
241
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
242
|
+
},
|
|
243
|
+
propertyKey: K,
|
|
244
|
+
): void;
|
|
245
|
+
/**
|
|
246
|
+
* Relance le GET pour cette instance connectée.
|
|
247
|
+
*
|
|
243
248
|
* Le handle peut être conservé :
|
|
244
249
|
* `const usersGet = get(new Endpoint<User[]>("users"))`.
|
|
245
250
|
*
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
* La Promise est résolue après la fin du GET.
|
|
252
|
+
*/
|
|
253
|
+
refetch(component: Host): Promise<ApiResult<T> | undefined>;
|
|
254
|
+
}
|
|
250
255
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
+
type ApiResultHandler<T> = (
|
|
257
|
+
component: object,
|
|
258
|
+
payload: ApiResult<T> | undefined,
|
|
259
|
+
) => void;
|
|
260
|
+
|
|
261
|
+
type GetDecoratorHandleInternals<
|
|
262
|
+
T,
|
|
263
|
+
Host extends object = object,
|
|
264
|
+
> = GetDecoratorHandle<T, Host> & {
|
|
265
|
+
registerResultHandler(target: object, handler: ApiResultHandler<T>): void;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
type ApiSendDecoratorHandleInternals<
|
|
269
|
+
T,
|
|
270
|
+
Host extends object = object,
|
|
271
|
+
> = ApiSendDecoratorHandle<T, Host> & {
|
|
272
|
+
registerResultHandler(target: object, handler: ApiResultHandler<T>): void;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
let nextApiHandlerPropertyId = 0;
|
|
276
|
+
|
|
277
|
+
export interface ApiSendDecoratorHandle<T, Host extends object = object> {
|
|
278
|
+
(
|
|
279
|
+
target: object,
|
|
280
|
+
propertyKey: string | symbol,
|
|
281
|
+
descriptor: TypedPropertyDescriptor<ApiHandlerMethod<T>>,
|
|
282
|
+
): void;
|
|
283
|
+
<K extends string>(
|
|
284
|
+
target: Host & {
|
|
285
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
286
|
+
},
|
|
287
|
+
propertyKey: K,
|
|
288
|
+
): void;
|
|
289
|
+
/**
|
|
290
|
+
* Relance l'opération d'écriture avec le body courant.
|
|
291
|
+
*
|
|
256
292
|
* Disponible avec `post`, `put` et `patch`.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
293
|
+
* La Promise est résolue après la fin de l'opération.
|
|
294
|
+
*/
|
|
295
|
+
send(component: Host): Promise<ApiResult<T> | undefined>;
|
|
296
|
+
}
|
|
261
297
|
|
|
262
298
|
export type ApiMethodActionOptions = {
|
|
263
299
|
/**
|
|
@@ -352,7 +388,7 @@ function detachConfigPublisher(state: ApiGetState): void {
|
|
|
352
388
|
|
|
353
389
|
/**
|
|
354
390
|
* Décorateur **`@get`** : charge des données via `API.getDetailed` et assigne un
|
|
355
|
-
* `ApiResult<T>` (`request`, `response`, `result` typé `T`) ou `
|
|
391
|
+
* `ApiResult<T>` (`request`, `response`, `result` typé `T`) ou `undefined`.
|
|
356
392
|
* Le path est un `Endpoint<T, Ue>` ; les placeholders `${nomPropriété}` sont résolus sur l'instance (`Ue` contraint l’hôte).
|
|
357
393
|
*
|
|
358
394
|
* **Scoped (défaut)** : `HTML.getApiConfiguration(host)` avec `host` = l’élément connecté
|
|
@@ -374,6 +410,9 @@ function detachConfigPublisher(state: ApiGetState): void {
|
|
|
374
410
|
* @get(new Endpoint<User, { userId: string }>("users/${userId}"))
|
|
375
411
|
* payload?: ApiResult<User>;
|
|
376
412
|
*
|
|
413
|
+
* @get(new Endpoint<User[]>("users"))
|
|
414
|
+
* onUsers(payload?: ApiResult<User[]>) {}
|
|
415
|
+
*
|
|
377
416
|
* @example
|
|
378
417
|
* const apiConf = new DataProviderKey<APIConfiguration>("myApiConf");
|
|
379
418
|
* PublisherManager.get("myApiConf").set({ serviceURL: "...", token: null, ... });
|
|
@@ -400,10 +439,7 @@ export function get<T, Ue = any>(
|
|
|
400
439
|
export function get<T, Ue = any, Uk = any>(
|
|
401
440
|
endpoint: Endpoint<T, Ue>,
|
|
402
441
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
403
|
-
): GetDecoratorHandle<
|
|
404
|
-
T,
|
|
405
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
406
|
-
>;
|
|
442
|
+
): GetDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
407
443
|
export function get<T, Ue = any, Uk = any>(
|
|
408
444
|
endpoint: Endpoint<T, Ue>,
|
|
409
445
|
options: GetOptions,
|
|
@@ -412,15 +448,11 @@ export function get<T, Ue = any, Uk = any, Ut = any>(
|
|
|
412
448
|
endpoint: Endpoint<T, Ue>,
|
|
413
449
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
414
450
|
options: GetOptions,
|
|
415
|
-
): GetDecoratorHandle<
|
|
416
|
-
T,
|
|
417
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
418
|
-
>;
|
|
451
|
+
): GetDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
419
452
|
export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
420
453
|
endpoint: Endpoint<T, Ue>,
|
|
421
454
|
configurationKeyOrOptions?:
|
|
422
|
-
|
|
423
|
-
| GetOptions,
|
|
455
|
+
DataProviderKey<APIConfiguration, Uk> | GetOptions,
|
|
424
456
|
maybeOptions?: GetOptions,
|
|
425
457
|
): GetDecoratorHandle<T, object> {
|
|
426
458
|
const pathTemplate = endpoint.path;
|
|
@@ -453,9 +485,33 @@ export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
|
453
485
|
const usesPublisherConfig = Boolean(configurationKeyPath);
|
|
454
486
|
const refetchEveryMs = options?.refetchEveryMs ?? 0;
|
|
455
487
|
const operationController = new ApiOperationController();
|
|
456
|
-
|
|
457
|
-
const
|
|
488
|
+
const resultHandlers = new WeakMap<object, Set<ApiResultHandler<T>>>();
|
|
489
|
+
const decoratedTargets = new WeakSet<object>();
|
|
490
|
+
const operationPropertyKeys = new WeakMap<object, Set<string>>();
|
|
491
|
+
let handlerPropertyKey: string | undefined;
|
|
492
|
+
|
|
493
|
+
const decorator = function (
|
|
494
|
+
target: object,
|
|
495
|
+
propertyKey: string,
|
|
496
|
+
descriptor?: PropertyDescriptor,
|
|
497
|
+
) {
|
|
498
|
+
if (descriptor) {
|
|
499
|
+
const handler = descriptor.value as ApiHandlerMethod<T> | undefined;
|
|
500
|
+
if (!handler) return;
|
|
501
|
+
|
|
502
|
+
(decorator as GetDecoratorHandleInternals<T>).registerResultHandler(
|
|
503
|
+
target,
|
|
504
|
+
(component, payload) => handler.call(component, payload),
|
|
505
|
+
);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
458
508
|
if (!target) return;
|
|
509
|
+
if (decoratedTargets.has(target)) {
|
|
510
|
+
operationPropertyKeys.get(target)?.add(propertyKey);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
decoratedTargets.add(target);
|
|
514
|
+
operationPropertyKeys.set(target, new Set([propertyKey]));
|
|
459
515
|
setSubscribable(target);
|
|
460
516
|
const stateKey = `__get_state_${propertyKey}`;
|
|
461
517
|
|
|
@@ -495,12 +551,18 @@ export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
|
495
551
|
}, state.refetchEveryMs);
|
|
496
552
|
};
|
|
497
553
|
|
|
554
|
+
const assignPayload = (payload: ApiResult<T> | undefined) => {
|
|
555
|
+
operationPropertyKeys.get(target)?.forEach((key) => {
|
|
556
|
+
comp[key] = payload;
|
|
557
|
+
});
|
|
558
|
+
};
|
|
559
|
+
|
|
498
560
|
const runFetch = async (): Promise<ApiResult<T> | undefined> => {
|
|
499
561
|
const resolution = isDynamicPath
|
|
500
562
|
? resolveDynamicPath(component, pathTemplate, pathOptions)
|
|
501
563
|
: { ready: true, path: pathTemplate };
|
|
502
564
|
if (!resolution.ready || !resolution.path) {
|
|
503
|
-
|
|
565
|
+
assignPayload(undefined);
|
|
504
566
|
scheduleRefetch();
|
|
505
567
|
return undefined;
|
|
506
568
|
}
|
|
@@ -512,7 +574,7 @@ export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
|
512
574
|
pathOptions,
|
|
513
575
|
);
|
|
514
576
|
if (!configRes.ready || !configRes.path) {
|
|
515
|
-
|
|
577
|
+
assignPayload(undefined);
|
|
516
578
|
scheduleRefetch();
|
|
517
579
|
return undefined;
|
|
518
580
|
}
|
|
@@ -540,8 +602,13 @@ export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
|
540
602
|
const api = new API(config);
|
|
541
603
|
const payload = await api.getDetailed<T>(resolution.path);
|
|
542
604
|
if (generation !== state.requestGeneration) return payload;
|
|
543
|
-
|
|
605
|
+
operationPropertyKeys.get(target)?.forEach((key) => {
|
|
606
|
+
comp[key] = payload;
|
|
607
|
+
});
|
|
544
608
|
scheduleRefetch();
|
|
609
|
+
resultHandlers
|
|
610
|
+
.get(target)
|
|
611
|
+
?.forEach((handler) => handler(component, payload));
|
|
545
612
|
return payload;
|
|
546
613
|
};
|
|
547
614
|
|
|
@@ -582,12 +649,12 @@ export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
|
582
649
|
pathOptions,
|
|
583
650
|
);
|
|
584
651
|
if (!configRes.ready || !configRes.path) {
|
|
585
|
-
|
|
652
|
+
assignPayload(undefined);
|
|
586
653
|
return;
|
|
587
654
|
}
|
|
588
655
|
const publisher = getPublisherFromPath(configRes.path);
|
|
589
656
|
if (!publisher) {
|
|
590
|
-
|
|
657
|
+
assignPayload(undefined);
|
|
591
658
|
return;
|
|
592
659
|
}
|
|
593
660
|
const mutationHandler = scheduleFetchAndIgnoreErrors;
|
|
@@ -651,9 +718,11 @@ export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
|
651
718
|
state.cleanupWatchers.forEach((cleanup) => cleanup());
|
|
652
719
|
state.cleanupWatchers = [];
|
|
653
720
|
state.requestGeneration++;
|
|
654
|
-
|
|
721
|
+
operationPropertyKeys.get(target)?.forEach((key) => {
|
|
722
|
+
comp[key] = undefined;
|
|
723
|
+
});
|
|
655
724
|
});
|
|
656
|
-
} as
|
|
725
|
+
} as GetDecoratorHandleInternals<T>;
|
|
657
726
|
|
|
658
727
|
decorator.refetch = (component: object) => {
|
|
659
728
|
return operationController.run(component) as Promise<
|
|
@@ -661,6 +730,20 @@ export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
|
661
730
|
>;
|
|
662
731
|
};
|
|
663
732
|
|
|
733
|
+
decorator.registerResultHandler = (target, handler) => {
|
|
734
|
+
let handlers = resultHandlers.get(target);
|
|
735
|
+
if (!handlers) {
|
|
736
|
+
handlers = new Set();
|
|
737
|
+
resultHandlers.set(target, handlers);
|
|
738
|
+
}
|
|
739
|
+
handlers.add(handler);
|
|
740
|
+
|
|
741
|
+
if (!decoratedTargets.has(target)) {
|
|
742
|
+
handlerPropertyKey ??= `__get_handler_${nextApiHandlerPropertyId++}`;
|
|
743
|
+
decorator(target, handlerPropertyKey);
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
|
|
664
747
|
return decorator;
|
|
665
748
|
}
|
|
666
749
|
|
|
@@ -754,22 +837,21 @@ function readBodyFromPublisher(publisher: DataProvider | null): unknown {
|
|
|
754
837
|
|
|
755
838
|
type ApiSendMethod = "POST" | "PUT" | "PATCH";
|
|
756
839
|
|
|
757
|
-
type ApiSendDetailedCaller = (
|
|
840
|
+
type ApiSendDetailedCaller<T> = (
|
|
758
841
|
api: API,
|
|
759
842
|
path: string,
|
|
760
843
|
body: unknown,
|
|
761
|
-
) => Promise<ApiResult<
|
|
844
|
+
) => Promise<ApiResult<T> | undefined>;
|
|
762
845
|
|
|
763
846
|
function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
764
847
|
method: ApiSendMethod,
|
|
765
|
-
callDetailed: ApiSendDetailedCaller
|
|
848
|
+
callDetailed: ApiSendDetailedCaller<T>,
|
|
766
849
|
) {
|
|
767
850
|
return function (
|
|
768
851
|
endpoint: Endpoint<T, Ue>,
|
|
769
852
|
bodyKey: DataProviderKey<B>,
|
|
770
853
|
configurationKeyOrOptions?:
|
|
771
|
-
|
|
772
|
-
| ApiSendOptions<Ut>,
|
|
854
|
+
DataProviderKey<APIConfiguration, Uk> | ApiSendOptions<Ut>,
|
|
773
855
|
maybeOptions?: ApiSendOptions<Ut>,
|
|
774
856
|
): ApiSendDecoratorHandle<T, object> {
|
|
775
857
|
const pathTemplate = endpoint.path;
|
|
@@ -809,9 +891,33 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
809
891
|
};
|
|
810
892
|
const stateKeyPrefix = `__${method.toLowerCase()}_state_`;
|
|
811
893
|
const operationController = new ApiOperationController();
|
|
812
|
-
|
|
813
|
-
const
|
|
894
|
+
const resultHandlers = new WeakMap<object, Set<ApiResultHandler<T>>>();
|
|
895
|
+
const decoratedTargets = new WeakSet<object>();
|
|
896
|
+
const operationPropertyKeys = new WeakMap<object, Set<string>>();
|
|
897
|
+
let handlerPropertyKey: string | undefined;
|
|
898
|
+
|
|
899
|
+
const decorator = function (
|
|
900
|
+
target: object,
|
|
901
|
+
propertyKey: string,
|
|
902
|
+
descriptor?: PropertyDescriptor,
|
|
903
|
+
) {
|
|
904
|
+
if (descriptor) {
|
|
905
|
+
const handler = descriptor.value as ApiHandlerMethod<T> | undefined;
|
|
906
|
+
if (!handler) return;
|
|
907
|
+
|
|
908
|
+
(decorator as ApiSendDecoratorHandleInternals<T>).registerResultHandler(
|
|
909
|
+
target,
|
|
910
|
+
(component, payload) => handler.call(component, payload),
|
|
911
|
+
);
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
814
914
|
if (!target) return;
|
|
915
|
+
if (decoratedTargets.has(target)) {
|
|
916
|
+
operationPropertyKeys.get(target)?.add(propertyKey);
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
decoratedTargets.add(target);
|
|
920
|
+
operationPropertyKeys.set(target, new Set([propertyKey]));
|
|
815
921
|
setSubscribable(target);
|
|
816
922
|
const stateKey = `${stateKeyPrefix}${propertyKey}`;
|
|
817
923
|
|
|
@@ -857,12 +963,18 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
857
963
|
}, state.refetchEveryMs);
|
|
858
964
|
};
|
|
859
965
|
|
|
860
|
-
const
|
|
966
|
+
const assignPayload = (payload: ApiResult<T> | undefined) => {
|
|
967
|
+
operationPropertyKeys.get(target)?.forEach((key) => {
|
|
968
|
+
comp[key] = payload;
|
|
969
|
+
});
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
const runSend = async (): Promise<ApiResult<T> | undefined> => {
|
|
861
973
|
const resolution = isDynamicPath
|
|
862
974
|
? resolveDynamicPath(component, pathTemplate, pathOptions)
|
|
863
975
|
: { ready: true, path: pathTemplate };
|
|
864
976
|
if (!resolution.ready || !resolution.path) {
|
|
865
|
-
|
|
977
|
+
assignPayload(undefined);
|
|
866
978
|
scheduleRefetch();
|
|
867
979
|
return undefined;
|
|
868
980
|
}
|
|
@@ -873,7 +985,7 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
873
985
|
pathOptions,
|
|
874
986
|
);
|
|
875
987
|
if (!bodyResolution.ready || !bodyResolution.path) {
|
|
876
|
-
|
|
988
|
+
assignPayload(undefined);
|
|
877
989
|
scheduleRefetch();
|
|
878
990
|
return undefined;
|
|
879
991
|
}
|
|
@@ -896,7 +1008,7 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
896
1008
|
pathOptions,
|
|
897
1009
|
);
|
|
898
1010
|
if (!configRes.ready || !configRes.path) {
|
|
899
|
-
|
|
1011
|
+
assignPayload(undefined);
|
|
900
1012
|
scheduleRefetch();
|
|
901
1013
|
return undefined;
|
|
902
1014
|
}
|
|
@@ -924,10 +1036,23 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
924
1036
|
|
|
925
1037
|
const generation = ++state.requestGeneration;
|
|
926
1038
|
const api = new API(config);
|
|
927
|
-
|
|
1039
|
+
let payload: ApiResult<T> | undefined;
|
|
1040
|
+
try {
|
|
1041
|
+
payload = await callDetailed(api, resolution.path, body);
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
if (generation === state.requestGeneration) {
|
|
1044
|
+
resultHandlers
|
|
1045
|
+
.get(target)
|
|
1046
|
+
?.forEach((handler) => handler(component, undefined));
|
|
1047
|
+
}
|
|
1048
|
+
throw error;
|
|
1049
|
+
}
|
|
928
1050
|
if (generation !== state.requestGeneration) return payload;
|
|
929
|
-
|
|
1051
|
+
assignPayload(payload);
|
|
930
1052
|
scheduleRefetch();
|
|
1053
|
+
resultHandlers
|
|
1054
|
+
.get(target)
|
|
1055
|
+
?.forEach((handler) => handler(component, payload));
|
|
931
1056
|
return payload;
|
|
932
1057
|
};
|
|
933
1058
|
|
|
@@ -989,12 +1114,12 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
989
1114
|
pathOptions,
|
|
990
1115
|
);
|
|
991
1116
|
if (!configRes.ready || !configRes.path) {
|
|
992
|
-
|
|
1117
|
+
assignPayload(undefined);
|
|
993
1118
|
return;
|
|
994
1119
|
}
|
|
995
1120
|
const publisher = getPublisherFromPath(configRes.path);
|
|
996
1121
|
if (!publisher) {
|
|
997
|
-
|
|
1122
|
+
assignPayload(undefined);
|
|
998
1123
|
return;
|
|
999
1124
|
}
|
|
1000
1125
|
const mutationHandler = scheduleSendAndIgnoreErrors;
|
|
@@ -1067,9 +1192,11 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
1067
1192
|
state.cleanupWatchers.forEach((cleanup) => cleanup());
|
|
1068
1193
|
state.cleanupWatchers = [];
|
|
1069
1194
|
state.requestGeneration++;
|
|
1070
|
-
|
|
1195
|
+
operationPropertyKeys.get(target)?.forEach((key) => {
|
|
1196
|
+
comp[key] = undefined;
|
|
1197
|
+
});
|
|
1071
1198
|
});
|
|
1072
|
-
} as
|
|
1199
|
+
} as ApiSendDecoratorHandleInternals<T>;
|
|
1073
1200
|
|
|
1074
1201
|
decorator.send = (component: object) => {
|
|
1075
1202
|
return operationController.run(component) as Promise<
|
|
@@ -1077,6 +1204,20 @@ function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
1077
1204
|
>;
|
|
1078
1205
|
};
|
|
1079
1206
|
|
|
1207
|
+
decorator.registerResultHandler = (target, handler) => {
|
|
1208
|
+
let handlers = resultHandlers.get(target);
|
|
1209
|
+
if (!handlers) {
|
|
1210
|
+
handlers = new Set();
|
|
1211
|
+
resultHandlers.set(target, handlers);
|
|
1212
|
+
}
|
|
1213
|
+
handlers.add(handler);
|
|
1214
|
+
|
|
1215
|
+
if (!decoratedTargets.has(target)) {
|
|
1216
|
+
handlerPropertyKey ??= `__${method.toLowerCase()}_handler_${nextApiHandlerPropertyId++}`;
|
|
1217
|
+
decorator(target, handlerPropertyKey);
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1080
1221
|
return decorator;
|
|
1081
1222
|
};
|
|
1082
1223
|
}
|
|
@@ -1107,10 +1248,7 @@ export function post<T, B, Ue = any, Uk = any>(
|
|
|
1107
1248
|
endpoint: Endpoint<T, Ue>,
|
|
1108
1249
|
bodyKey: DataProviderKey<B>,
|
|
1109
1250
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
1110
|
-
): ApiSendDecoratorHandle<
|
|
1111
|
-
T,
|
|
1112
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
1113
|
-
>;
|
|
1251
|
+
): ApiSendDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
1114
1252
|
export function post<T, B, Ue = any, Uk = any>(
|
|
1115
1253
|
endpoint: Endpoint<T, Ue>,
|
|
1116
1254
|
bodyKey: DataProviderKey<B>,
|
|
@@ -1121,16 +1259,12 @@ export function post<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
1121
1259
|
bodyKey: DataProviderKey<B>,
|
|
1122
1260
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
1123
1261
|
options: PostOptions<Ut>,
|
|
1124
|
-
): ApiSendDecoratorHandle<
|
|
1125
|
-
T,
|
|
1126
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
1127
|
-
>;
|
|
1262
|
+
): ApiSendDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
1128
1263
|
export function post<T, B, Ue = any, Uk = any, Ut = any>(
|
|
1129
1264
|
endpoint: Endpoint<T, Ue>,
|
|
1130
1265
|
bodyKey: DataProviderKey<B>,
|
|
1131
1266
|
configurationKeyOrOptions?:
|
|
1132
|
-
|
|
1133
|
-
| PostOptions<Ut>,
|
|
1267
|
+
DataProviderKey<APIConfiguration, Uk> | PostOptions<Ut>,
|
|
1134
1268
|
maybeOptions?: PostOptions<Ut>,
|
|
1135
1269
|
): ApiSendDecoratorHandle<T, object> {
|
|
1136
1270
|
return createApiSendDecorator<T, B, Ue, Uk, Ut>("POST", (api, path, body) =>
|
|
@@ -1147,10 +1281,7 @@ export function put<T, B, Ue = any, Uk = any>(
|
|
|
1147
1281
|
endpoint: Endpoint<T, Ue>,
|
|
1148
1282
|
bodyKey: DataProviderKey<B>,
|
|
1149
1283
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
1150
|
-
): ApiSendDecoratorHandle<
|
|
1151
|
-
T,
|
|
1152
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
1153
|
-
>;
|
|
1284
|
+
): ApiSendDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
1154
1285
|
export function put<T, B, Ue = any, Uk = any>(
|
|
1155
1286
|
endpoint: Endpoint<T, Ue>,
|
|
1156
1287
|
bodyKey: DataProviderKey<B>,
|
|
@@ -1161,16 +1292,12 @@ export function put<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
1161
1292
|
bodyKey: DataProviderKey<B>,
|
|
1162
1293
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
1163
1294
|
options: PutOptions<Ut>,
|
|
1164
|
-
): ApiSendDecoratorHandle<
|
|
1165
|
-
T,
|
|
1166
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
1167
|
-
>;
|
|
1295
|
+
): ApiSendDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
1168
1296
|
export function put<T, B, Ue = any, Uk = any, Ut = any>(
|
|
1169
1297
|
endpoint: Endpoint<T, Ue>,
|
|
1170
1298
|
bodyKey: DataProviderKey<B>,
|
|
1171
1299
|
configurationKeyOrOptions?:
|
|
1172
|
-
|
|
1173
|
-
| PutOptions<Ut>,
|
|
1300
|
+
DataProviderKey<APIConfiguration, Uk> | PutOptions<Ut>,
|
|
1174
1301
|
maybeOptions?: PutOptions<Ut>,
|
|
1175
1302
|
): ApiSendDecoratorHandle<T, object> {
|
|
1176
1303
|
return createApiSendDecorator<T, B, Ue, Uk, Ut>("PUT", (api, path, body) =>
|
|
@@ -1187,10 +1314,7 @@ export function patch<T, B, Ue = any, Uk = any>(
|
|
|
1187
1314
|
endpoint: Endpoint<T, Ue>,
|
|
1188
1315
|
bodyKey: DataProviderKey<B>,
|
|
1189
1316
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
1190
|
-
): ApiSendDecoratorHandle<
|
|
1191
|
-
T,
|
|
1192
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
1193
|
-
>;
|
|
1317
|
+
): ApiSendDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
1194
1318
|
export function patch<T, B, Ue = any, Uk = any>(
|
|
1195
1319
|
endpoint: Endpoint<T, Ue>,
|
|
1196
1320
|
bodyKey: DataProviderKey<B>,
|
|
@@ -1201,16 +1325,12 @@ export function patch<T, B, Ue = any, Uk = any, Ut = any>(
|
|
|
1201
1325
|
bodyKey: DataProviderKey<B>,
|
|
1202
1326
|
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
1203
1327
|
options: PatchOptions<Ut>,
|
|
1204
|
-
): ApiSendDecoratorHandle<
|
|
1205
|
-
T,
|
|
1206
|
-
DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>
|
|
1207
|
-
>;
|
|
1328
|
+
): ApiSendDecoratorHandle<T, DataProviderKeyHost<Ue> & DataProviderKeyHost<Uk>>;
|
|
1208
1329
|
export function patch<T, B, Ue = any, Uk = any, Ut = any>(
|
|
1209
1330
|
endpoint: Endpoint<T, Ue>,
|
|
1210
1331
|
bodyKey: DataProviderKey<B>,
|
|
1211
1332
|
configurationKeyOrOptions?:
|
|
1212
|
-
|
|
1213
|
-
| PatchOptions<Ut>,
|
|
1333
|
+
DataProviderKey<APIConfiguration, Uk> | PatchOptions<Ut>,
|
|
1214
1334
|
maybeOptions?: PatchOptions<Ut>,
|
|
1215
1335
|
): ApiSendDecoratorHandle<T, object> {
|
|
1216
1336
|
return createApiSendDecorator<T, B, Ue, Uk, Ut>("PATCH", (api, path, body) =>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DataProviderKey,
|
|
3
|
+
DataProviderKeyHost,
|
|
4
|
+
} from "../../utils/dataProviderKey";
|
|
5
|
+
import {
|
|
6
|
+
derive as deriveFn,
|
|
7
|
+
type DeriveHandle,
|
|
8
|
+
} from "../../utils/derive";
|
|
9
|
+
|
|
10
|
+
export type DeriveDecoratorOptions<
|
|
11
|
+
I extends Record<string, unknown>,
|
|
12
|
+
O,
|
|
13
|
+
V = Record<string, unknown>,
|
|
14
|
+
> = {
|
|
15
|
+
from: { [K in keyof I]: DataProviderKey<I[K]> };
|
|
16
|
+
to: DataProviderKey<O>;
|
|
17
|
+
/** Expression JSONata (string) ou fonction TS. */
|
|
18
|
+
expr?: string;
|
|
19
|
+
fn?: (inputs: I, vars: V) => O | Promise<O>;
|
|
20
|
+
variables?: DataProviderKey<V>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const HANDLES = new WeakMap<object, DeriveHandle[]>();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Décorateur optionnel aligné `@handle` : lance un `derive` au `connectedCallback`
|
|
27
|
+
* et l’arrête au `disconnectedCallback`.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* @derive({
|
|
32
|
+
* from: { s: sessionsKey },
|
|
33
|
+
* to: palmaresKey,
|
|
34
|
+
* variables: formKey,
|
|
35
|
+
* fn: (i, v) => i.s.slice(0, Number(v.top) || 5),
|
|
36
|
+
* })
|
|
37
|
+
* class MyWidget extends LitElement {}
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function deriveDecorator<
|
|
41
|
+
I extends Record<string, unknown>,
|
|
42
|
+
O,
|
|
43
|
+
V = Record<string, unknown>,
|
|
44
|
+
>(options: DeriveDecoratorOptions<I, O, V>) {
|
|
45
|
+
return function <T extends DataProviderKeyHost<object>>(
|
|
46
|
+
ctor: new (...args: any[]) => T,
|
|
47
|
+
): void {
|
|
48
|
+
const proto = ctor.prototype as T & {
|
|
49
|
+
connectedCallback?: () => void;
|
|
50
|
+
disconnectedCallback?: () => void;
|
|
51
|
+
};
|
|
52
|
+
const connected = proto.connectedCallback;
|
|
53
|
+
const disconnected = proto.disconnectedCallback;
|
|
54
|
+
|
|
55
|
+
proto.connectedCallback = function (this: T) {
|
|
56
|
+
connected?.call(this);
|
|
57
|
+
const compute =
|
|
58
|
+
options.fn ??
|
|
59
|
+
(async (inputs: I, vars: V) => {
|
|
60
|
+
if (!options.expr) {
|
|
61
|
+
throw new Error("@derive : fournir `expr` ou `fn`.");
|
|
62
|
+
}
|
|
63
|
+
const { compileJsonata } = await import(
|
|
64
|
+
"../../utils/jsonataRuntime"
|
|
65
|
+
);
|
|
66
|
+
const expr = compileJsonata(options.expr);
|
|
67
|
+
return expr.evaluate({}, {
|
|
68
|
+
...(vars as Record<string, unknown>),
|
|
69
|
+
...inputs,
|
|
70
|
+
}) as O;
|
|
71
|
+
});
|
|
72
|
+
const handle = deriveFn({
|
|
73
|
+
inputs: options.from,
|
|
74
|
+
output: options.to,
|
|
75
|
+
variables: options.variables,
|
|
76
|
+
compute,
|
|
77
|
+
});
|
|
78
|
+
const list = HANDLES.get(this) ?? [];
|
|
79
|
+
list.push(handle);
|
|
80
|
+
HANDLES.set(this, list);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
proto.disconnectedCallback = function (this: T) {
|
|
84
|
+
const list = HANDLES.get(this);
|
|
85
|
+
if (list) {
|
|
86
|
+
for (const h of list) h.stop();
|
|
87
|
+
HANDLES.delete(this);
|
|
88
|
+
}
|
|
89
|
+
disconnected?.call(this);
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Alias public — éviter le conflit de nom avec la primitive `derive`. */
|
|
95
|
+
export { deriveDecorator as derive };
|