@supersoniks/concorde 4.2.1 → 4.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.
Files changed (75) hide show
  1. package/README.md +163 -0
  2. package/build-infos.json +1 -1
  3. package/concorde-core.bundle.js +585 -670
  4. package/concorde-core.es.js +7165 -9505
  5. package/dist/concorde-core.bundle.js +585 -670
  6. package/dist/concorde-core.es.js +7165 -9505
  7. package/docs/assets/index-DP1oMukw.js +4949 -0
  8. package/docs/assets/index-DZtxIZCW.css +1 -0
  9. package/docs/index.html +2 -2
  10. package/{src/docs/_misc → docs/src/docs/_decorators}/ancestor-attribute.md +15 -31
  11. package/docs/src/docs/_decorators/bind.md +164 -0
  12. package/docs/src/docs/_decorators/get.md +65 -0
  13. package/docs/src/docs/_decorators/publish.md +54 -0
  14. package/docs/src/docs/_decorators/subscribe.md +36 -0
  15. package/docs/src/docs/_misc/dataProviderKey.md +135 -0
  16. package/docs/src/docs/_misc/endpoint.md +42 -0
  17. package/docs/src/docs/search/docs-search.json +850 -710
  18. package/docs/src/tsconfig.json +43 -4
  19. package/package.json +25 -4
  20. package/php/get-challenge.php +34 -0
  21. package/php/some-service.php +42 -0
  22. package/scripts/pre-build.mjs +4 -0
  23. package/src/core/_types/endpoint.ts +4 -0
  24. package/src/core/_types/key.ts +1 -0
  25. package/src/core/components/functional/example/example.ts +38 -6
  26. package/src/core/decorators/Subscriber.ts +2 -0
  27. package/src/core/decorators/api.spec.ts +150 -0
  28. package/src/core/decorators/api.ts +244 -0
  29. package/src/core/decorators/subscriber/bind.ts +57 -145
  30. package/src/core/decorators/subscriber/dynamicPath.ts +77 -0
  31. package/src/core/decorators/subscriber/dynamicPropertyWatch.ts +105 -0
  32. package/src/core/decorators/subscriber/onAssign.ts +11 -147
  33. package/src/core/decorators/subscriber/publish.spec.ts +21 -0
  34. package/src/core/decorators/subscriber/publish.ts +148 -0
  35. package/src/core/decorators/subscriber/publisherPath.ts +13 -0
  36. package/src/core/decorators/subscriber/subscribe.spec.ts +21 -0
  37. package/src/core/decorators/subscriber/subscribe.ts +32 -0
  38. package/src/core/decorators/subscriber/subscribe.type-test.ts +32 -0
  39. package/src/core/utils/api.ts +83 -15
  40. package/src/core/utils/dataProviderKey.spec.ts +34 -0
  41. package/src/core/utils/dataProviderKey.ts +86 -0
  42. package/src/core/utils/endpoint.spec.ts +41 -0
  43. package/src/core/utils/endpoint.ts +87 -0
  44. package/src/decorators.ts +14 -0
  45. package/{docs/src/docs/_misc → src/docs/_decorators}/ancestor-attribute.md +15 -31
  46. package/src/docs/_decorators/bind.md +164 -0
  47. package/src/docs/_decorators/get.md +65 -0
  48. package/src/docs/_decorators/publish.md +54 -0
  49. package/src/docs/_decorators/subscribe.md +36 -0
  50. package/src/docs/_misc/dataProviderKey.md +135 -0
  51. package/src/docs/_misc/endpoint.md +42 -0
  52. package/src/docs/example/decorators-demo-bind-demos.ts +210 -0
  53. package/src/docs/example/decorators-demo-geo.ts +45 -0
  54. package/src/docs/example/decorators-demo-init.ts +228 -0
  55. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +324 -0
  56. package/src/docs/example/decorators-demo.ts +12 -459
  57. package/src/docs/navigation/navigation.ts +27 -10
  58. package/src/docs/search/docs-search.json +1059 -609
  59. package/src/tsconfig-model.json +1 -1
  60. package/src/tsconfig.json +65 -1
  61. package/src/tsconfig.tsbuildinfo +1 -1
  62. package/src/utils.ts +8 -1
  63. package/vite/config.js +25 -6
  64. package/vite.config.mts +13 -0
  65. package/docs/assets/index-B0IJ9I_B.js +0 -4918
  66. package/docs/assets/index-B3QHEJTV.css +0 -1
  67. package/docs/src/docs/_misc/bind.md +0 -436
  68. package/docs/src/docs/_misc/key.md +0 -135
  69. package/src/docs/_misc/bind.md +0 -362
  70. /package/docs/src/docs/{_misc → _decorators}/auto-subscribe.md +0 -0
  71. /package/docs/src/docs/{_misc → _decorators}/on-assign.md +0 -0
  72. /package/docs/src/docs/{_misc → _decorators}/wait-for-ancestors.md +0 -0
  73. /package/src/docs/{_misc → _decorators}/auto-subscribe.md +0 -0
  74. /package/src/docs/{_misc → _decorators}/on-assign.md +0 -0
  75. /package/src/docs/{_misc → _decorators}/wait-for-ancestors.md +0 -0
@@ -15,8 +15,8 @@
15
15
  "module": "esnext",
16
16
  "moduleResolution": "bundler",
17
17
  "paths": {
18
- "./_types/key.spec": [
19
- "/usr2/sites/concorde/src/core/_types/key.spec.ts"
18
+ "./_types/endpoint": [
19
+ "/usr2/sites/concorde/src/core/_types/endpoint.ts"
20
20
  ],
21
21
  "./_types/key": [
22
22
  "/usr2/sites/concorde/src/core/_types/key.ts"
@@ -774,6 +774,12 @@
774
774
  "./decorators/Subscriber": [
775
775
  "/usr2/sites/concorde/src/core/decorators/Subscriber.ts"
776
776
  ],
777
+ "./decorators/api.spec": [
778
+ "/usr2/sites/concorde/src/core/decorators/api.spec.ts"
779
+ ],
780
+ "./decorators/api": [
781
+ "/usr2/sites/concorde/src/core/decorators/api.ts"
782
+ ],
777
783
  "./decorators/lifecycle": [
778
784
  "/usr2/sites/concorde/src/core/decorators/lifecycle.ts"
779
785
  ],
@@ -792,6 +798,12 @@
792
798
  "./decorators/subscriber/common": [
793
799
  "/usr2/sites/concorde/src/core/decorators/subscriber/common.ts"
794
800
  ],
801
+ "./decorators/subscriber/dynamicPath": [
802
+ "/usr2/sites/concorde/src/core/decorators/subscriber/dynamicPath.ts"
803
+ ],
804
+ "./decorators/subscriber/dynamicPropertyWatch": [
805
+ "/usr2/sites/concorde/src/core/decorators/subscriber/dynamicPropertyWatch.ts"
806
+ ],
795
807
  "./decorators/subscriber/onAssign": [
796
808
  "/usr2/sites/concorde/src/core/decorators/subscriber/onAssign.ts"
797
809
  ],
@@ -801,6 +813,9 @@
801
813
  "./decorators/subscriber/publish": [
802
814
  "/usr2/sites/concorde/src/core/decorators/subscriber/publish.ts"
803
815
  ],
816
+ "./decorators/subscriber/publisherPath": [
817
+ "/usr2/sites/concorde/src/core/decorators/subscriber/publisherPath.ts"
818
+ ],
804
819
  "./decorators/subscriber/subscribe.spec": [
805
820
  "/usr2/sites/concorde/src/core/decorators/subscriber/subscribe.spec.ts"
806
821
  ],
@@ -870,6 +885,18 @@
870
885
  "./utils/api": [
871
886
  "/usr2/sites/concorde/src/core/utils/api.ts"
872
887
  ],
888
+ "./utils/dataProviderKey.spec": [
889
+ "/usr2/sites/concorde/src/core/utils/dataProviderKey.spec.ts"
890
+ ],
891
+ "./utils/dataProviderKey": [
892
+ "/usr2/sites/concorde/src/core/utils/dataProviderKey.ts"
893
+ ],
894
+ "./utils/endpoint.spec": [
895
+ "/usr2/sites/concorde/src/core/utils/endpoint.spec.ts"
896
+ ],
897
+ "./utils/endpoint": [
898
+ "/usr2/sites/concorde/src/core/utils/endpoint.ts"
899
+ ],
873
900
  "./utils/route.spec": [
874
901
  "/usr2/sites/concorde/src/core/utils/route.spec.ts"
875
902
  ],
@@ -885,6 +912,18 @@
885
912
  "./docs": [
886
913
  "/usr2/sites/concorde/src/docs/docs.ts"
887
914
  ],
915
+ "./example/decorators-demo-bind-demos": [
916
+ "/usr2/sites/concorde/src/docs/example/decorators-demo-bind-demos.ts"
917
+ ],
918
+ "./example/decorators-demo-geo": [
919
+ "/usr2/sites/concorde/src/docs/example/decorators-demo-geo.ts"
920
+ ],
921
+ "./example/decorators-demo-init": [
922
+ "/usr2/sites/concorde/src/docs/example/decorators-demo-init.ts"
923
+ ],
924
+ "./example/decorators-demo-subscribe-publish-get-demos": [
925
+ "/usr2/sites/concorde/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts"
926
+ ],
888
927
  "./example/decorators-demo": [
889
928
  "/usr2/sites/concorde/src/docs/example/decorators-demo.ts"
890
929
  ],
@@ -924,8 +963,8 @@
924
963
  "./TestUtils": [
925
964
  "/usr2/sites/concorde/src/test-utils/TestUtils.ts"
926
965
  ],
927
- "@supersoniks/concorde/key": [
928
- "/usr2/sites/concorde/src/core/_types/key.ts"
966
+ "@supersoniks/concorde/dataProviderKey": [
967
+ "/usr2/sites/concorde/src/core/utils/dataProviderKey.ts"
929
968
  ],
930
969
  "@supersoniks/concorde/*": [
931
970
  "./*"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supersoniks/concorde",
3
- "version": "4.2.1",
3
+ "version": "4.4.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "",
@@ -17,9 +17,12 @@
17
17
  "exports": {
18
18
  "./core/components/ui/icon/icons.json": "./src/core/components/ui/icon/icons.json",
19
19
  "./core/components/functional/sdui/default-library.json": "./src/core/components/functional/sdui/default-library.json",
20
+ "./dataProviderKey": "./src/core/utils/dataProviderKey.ts",
20
21
  "./*": "./src/*.ts",
21
22
  "./vite-config": "./vite/config.js",
22
23
  "./rollup-plugin-*": "./rollup/plugin-*.js",
24
+ "./_types/endpoint": "./src/core/_types/endpoint.ts",
25
+ "./_types/key": "./src/core/_types/key.ts",
23
26
  "./_types/types": "./src/core/_types/types.ts",
24
27
  "./date": "./src/core/components/functional/date/date.ts",
25
28
  "./functional/date": "./src/core/components/functional/date/date.ts",
@@ -271,13 +274,23 @@
271
274
  "./ui/ui": "./src/core/components/ui/ui.ts",
272
275
  "./core": "./src/core/core.ts",
273
276
  "./decorators/Subscriber": "./src/core/decorators/Subscriber.ts",
277
+ "./decorators/api.spec": "./src/core/decorators/api.spec.ts",
278
+ "./decorators/api": "./src/core/decorators/api.ts",
274
279
  "./decorators/lifecycle": "./src/core/decorators/lifecycle.ts",
275
280
  "./decorators/subscriber/ancestorAttribute": "./src/core/decorators/subscriber/ancestorAttribute.ts",
276
281
  "./decorators/subscriber/autoFill": "./src/core/decorators/subscriber/autoFill.ts",
277
282
  "./decorators/subscriber/autoSubscribe": "./src/core/decorators/subscriber/autoSubscribe.ts",
278
283
  "./decorators/subscriber/bind": "./src/core/decorators/subscriber/bind.ts",
279
284
  "./decorators/subscriber/common": "./src/core/decorators/subscriber/common.ts",
285
+ "./decorators/subscriber/dynamicPath": "./src/core/decorators/subscriber/dynamicPath.ts",
286
+ "./decorators/subscriber/dynamicPropertyWatch": "./src/core/decorators/subscriber/dynamicPropertyWatch.ts",
280
287
  "./decorators/subscriber/onAssign": "./src/core/decorators/subscriber/onAssign.ts",
288
+ "./decorators/subscriber/publish.spec": "./src/core/decorators/subscriber/publish.spec.ts",
289
+ "./decorators/subscriber/publish": "./src/core/decorators/subscriber/publish.ts",
290
+ "./decorators/subscriber/publisherPath": "./src/core/decorators/subscriber/publisherPath.ts",
291
+ "./decorators/subscriber/subscribe.spec": "./src/core/decorators/subscriber/subscribe.spec.ts",
292
+ "./decorators/subscriber/subscribe": "./src/core/decorators/subscriber/subscribe.ts",
293
+ "./decorators/subscriber/subscribe.type-test": "./src/core/decorators/subscriber/subscribe.type-test.ts",
281
294
  "./directives/DataProvider": "./src/core/directives/DataProvider.ts",
282
295
  "./directives/Wording": "./src/core/directives/Wording.ts",
283
296
  "./mixins/Fetcher": "./src/core/mixins/Fetcher.ts",
@@ -298,11 +311,19 @@
298
311
  "./utils/Utils": "./src/core/utils/Utils.ts",
299
312
  "./utils/aesCrypto": "./src/core/utils/aesCrypto.ts",
300
313
  "./utils/api": "./src/core/utils/api.ts",
314
+ "./utils/dataProviderKey.spec": "./src/core/utils/dataProviderKey.spec.ts",
315
+ "./utils/dataProviderKey": "./src/core/utils/dataProviderKey.ts",
316
+ "./utils/endpoint.spec": "./src/core/utils/endpoint.spec.ts",
317
+ "./utils/endpoint": "./src/core/utils/endpoint.ts",
301
318
  "./utils/route.spec": "./src/core/utils/route.spec.ts",
302
319
  "./utils/route": "./src/core/utils/route.ts",
303
320
  "./utils/url-pattern": "./src/core/utils/url-pattern.ts",
304
321
  "./code": "./src/docs/code.ts",
305
322
  "./docs": "./src/docs/docs.ts",
323
+ "./example/decorators-demo-bind-demos": "./src/docs/example/decorators-demo-bind-demos.ts",
324
+ "./example/decorators-demo-geo": "./src/docs/example/decorators-demo-geo.ts",
325
+ "./example/decorators-demo-init": "./src/docs/example/decorators-demo-init.ts",
326
+ "./example/decorators-demo-subscribe-publish-get-demos": "./src/docs/example/decorators-demo-subscribe-publish-get-demos.ts",
306
327
  "./example/decorators-demo": "./src/docs/example/decorators-demo.ts",
307
328
  "./example/users": "./src/docs/example/users.ts",
308
329
  "./header/header": "./src/docs/header/header.ts",
@@ -320,7 +341,7 @@
320
341
  "devDependencies": {
321
342
  "@tailwindcss/typography": "^0.5.12",
322
343
  "@types/node": "^24.5.2",
323
- "@vitejs/plugin-basic-ssl": "^2.1.0",
344
+ "@vitejs/plugin-basic-ssl": "^2.3.0",
324
345
  "altcha": "^1.0.7",
325
346
  "autoprefixer": "^10.4.19",
326
347
  "baseline-browser-mapping": "^2.8.31",
@@ -333,8 +354,8 @@
333
354
  "rollup-plugin-postcss-lit": "^2.1.0",
334
355
  "tailwindcss": "^3.4.3",
335
356
  "typescript": "^5.4.3",
336
- "vite": "^7.1.5",
337
- "vitest": "^3.2.4"
357
+ "vite": "^8.0.0",
358
+ "vitest": "^4.0.0"
338
359
  },
339
360
  "dependencies": {
340
361
  "@lit-labs/motion": "^1.0.7",
@@ -0,0 +1,34 @@
1
+ <?php
2
+ /* *
3
+ * Call get-challenge on auto-hosted latcha service at https://altcha.supersoniks.org
4
+ * */
5
+
6
+ // Autoriser toutes les origines
7
+ header("Access-Control-Allow-Origin: *");
8
+
9
+ // Autoriser les méthodes HTTP spécifiques
10
+ header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
11
+
12
+ // Autoriser certains en-têtes spécifiques
13
+ header("Access-Control-Allow-Headers: Content-Type, Authorization");
14
+
15
+ // Si la méthode est OPTIONS, terminer la requête ici
16
+ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
17
+ http_response_code(200);
18
+ exit();
19
+ }
20
+
21
+ function getChallenge($key){
22
+ $maxNumber=20000;
23
+ $queryString = $params = [
24
+ 'key' => $key,
25
+ 'maxNumber' => $maxNumber
26
+ ];
27
+ // Générer la chaîne de requête
28
+ $queryString = http_build_query($params);
29
+ $url = "https://altcha.supersoniks.org/get-challenge?key=".$queryString;
30
+ $response = file_get_contents($url);
31
+ return $response;
32
+ }
33
+
34
+ echo getChallenge($_GET['key']);
@@ -0,0 +1,42 @@
1
+ <?php
2
+ /* *
3
+ * Call verify-solution on auto-hosted latcha service at https://altcha.supersoniks.org
4
+ * */
5
+
6
+
7
+ // Autoriser toutes les origines
8
+ header("Access-Control-Allow-Origin: *");
9
+
10
+ // Autoriser les méthodes HTTP spécifiques
11
+ header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
12
+
13
+ // Autoriser certains en-têtes spécifiques
14
+ header("Access-Control-Allow-Headers: Content-Type, Authorization, x-altcha-spam-filter");
15
+
16
+ // Si la méthode est OPTIONS, terminer la requête ici
17
+ if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
18
+ http_response_code(200);
19
+ exit();
20
+ }
21
+
22
+ function verifySolution($key, $solution){
23
+ $queryString = $params = [
24
+ 'key' => $key,
25
+ 'altcha' => $solution
26
+ ];
27
+ // Générer la chaîne de requête
28
+ $queryString = http_build_query($params);
29
+ $url = "https://altcha.supersoniks.org/verify-solution?".$queryString;
30
+ $response = file_get_contents($url);
31
+ return $response;
32
+ }
33
+
34
+ /**
35
+ * Get json posted data
36
+ */
37
+
38
+ // Get the posted data
39
+
40
+ $data = json_decode(file_get_contents("php://input"));
41
+
42
+ echo verifySolution($data->captchakey, $data->captchatoken);
@@ -99,6 +99,9 @@ jsonString = jsonString;
99
99
 
100
100
  const tsConfig = JSON.parse(jsonString);
101
101
  tsConfig.compilerOptions.paths = { ...shortPathMapping };
102
+ tsConfig.compilerOptions.paths["@supersoniks/concorde/dataProviderKey"] = [
103
+ path.resolve(__dirname, "../src/core/utils/dataProviderKey.ts"),
104
+ ];
102
105
  tsConfig.compilerOptions.paths["@supersoniks/concorde/*"] = ["./*"];
103
106
  tsConfig.compilerOptions.paths["@concorde/*"] = ["./*"];
104
107
  fs.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2));
@@ -113,6 +116,7 @@ const pExports = {
113
116
  "./src/core/components/ui/icon/icons.json",
114
117
  "./core/components/functional/sdui/default-library.json":
115
118
  "./src/core/components/functional/sdui/default-library.json",
119
+ "./dataProviderKey": "./src/core/utils/dataProviderKey.ts",
116
120
  "./*": "./src/*.ts",
117
121
  "./vite-config": "./vite/config.js",
118
122
  "./rollup-plugin-*": "./rollup/plugin-*.js",
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Réexport : définition dans [`utils/endpoint`](../utils/endpoint.ts) — `Endpoint<T, U = any>`.
3
+ */
4
+ export { Endpoint } from "../utils/endpoint";
@@ -0,0 +1 @@
1
+ export { DataProviderKey } from "../utils/dataProviderKey";
@@ -1,11 +1,43 @@
1
- import {html, LitElement} from "lit";
2
- import {customElement, property} from "lit/decorators.js";
3
- import Subscriber from "@supersoniks/concorde/core/mixins/Subscriber";
1
+ import { html, LitElement } from "lit";
2
+ import { customElement, property, state } from "lit/decorators.js";
3
+ import { Endpoint } from "@supersoniks/concorde/utils";
4
+ import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
5
+ import {
6
+ get,
7
+ publish,
8
+ subscribe,
9
+ ApiGetResult,
10
+ } from "@supersoniks/concorde/decorators";
11
+
12
+ /** Same API as the queue demo: https://geo.api.gouv.fr/ */
13
+ type City = { nom: string; code: string };
14
+
15
+ const endpoint = new Endpoint<City[], { limit: number }>(
16
+ "communes?limit=$limit&fields=nom,code",
17
+ );
18
+
19
+ /** Même path que l’endpoint ; type = charge utile `@get` pour `@publish`. */
20
+ const dpKey = new DataProviderKey<ApiGetResult<City[]>>(endpoint.path);
21
+
4
22
  const tagName = "sonic-example"; // For Astro.build
5
23
  @customElement(tagName)
6
- export class SonicComponent extends Subscriber(LitElement) {
7
- @property() text = "Example";
24
+ export class SonicComponent extends LitElement {
25
+ @property({ type: Number })
26
+ limit = 5;
27
+
28
+ @get(endpoint)
29
+ @publish(dpKey)
30
+ geoCommunesPayload?: ApiGetResult<City[]>;
31
+
32
+ @state()
33
+ @subscribe(dpKey.result)
34
+ geoCommunesResult?: City[];
35
+
8
36
  render() {
9
- return html`<div>${this.text}</div>`;
37
+ return html` <span part="api-get-demo">
38
+ · get: ${JSON.stringify(this.geoCommunesPayload?.result ?? null)} · HTTP
39
+ ${this.geoCommunesPayload?.response?.status ?? "—"} · subscribe:
40
+ ${JSON.stringify(this.geoCommunesResult ?? null)}</span
41
+ >`;
10
42
  }
11
43
  }
@@ -1,4 +1,6 @@
1
1
  export { bind } from "./subscriber/bind";
2
+ export { publish } from "./subscriber/publish";
3
+ export { subscribe } from "./subscriber/subscribe";
2
4
  export { onAssign } from "./subscriber/onAssign";
3
5
  export { autoSubscribe } from "./subscriber/autoSubscribe";
4
6
  export { autoFill } from "./subscriber/autoFill";
@@ -0,0 +1,150 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { Endpoint } from "../utils/endpoint";
3
+ import { DataProviderKey } from "../utils/dataProviderKey";
4
+ import API, {
5
+ APIConfiguration,
6
+ type ApiGetResult,
7
+ } from "@supersoniks/concorde/core/utils/api";
8
+ import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
9
+ import { get } from "./api";
10
+
11
+ const staticConfig: APIConfiguration = {
12
+ serviceURL: "https://api.example.test",
13
+ token: null,
14
+ userName: null,
15
+ password: null,
16
+ authToken: null,
17
+ tokenProvider: null,
18
+ };
19
+
20
+ async function flushGetMicrotasks() {
21
+ await Promise.resolve();
22
+ await Promise.resolve();
23
+ }
24
+
25
+ function mockPayload<T>(result: T) {
26
+ return {
27
+ request: new Request("https://api.example.test/items/1"),
28
+ response: new Response(JSON.stringify(result), {
29
+ status: 200,
30
+ headers: { "Content-Type": "application/json" },
31
+ }),
32
+ result,
33
+ };
34
+ }
35
+
36
+ describe("get", () => {
37
+ beforeEach(() => {
38
+ vi.spyOn(API.prototype, "getDetailed").mockResolvedValue(
39
+ mockPayload({ id: "loaded" }) as never,
40
+ );
41
+ });
42
+
43
+ afterEach(() => {
44
+ vi.restoreAllMocks();
45
+ document.body.replaceChildren();
46
+ });
47
+
48
+ it("assigne ApiGetResult avec configurationKey (publisher)", async () => {
49
+ const pubId = "getSpecPub1";
50
+ PublisherManager.get(pubId).set(staticConfig);
51
+ const confKey = new DataProviderKey<APIConfiguration>(pubId);
52
+
53
+ const itemEp = new Endpoint<{ id: string }>("items/1");
54
+ const tag = "test-api-get-config-key";
55
+ class C extends HTMLElement {
56
+ @get(itemEp, confKey)
57
+ payload: ApiGetResult<{ id: string }> | null = null;
58
+ }
59
+ if (!customElements.get(tag)) {
60
+ customElements.define(tag, C);
61
+ }
62
+ const el = document.createElement(tag) as InstanceType<typeof C>;
63
+ document.body.appendChild(el);
64
+ await flushGetMicrotasks();
65
+ expect(el.payload?.result).toEqual({ id: "loaded" });
66
+ expect(el.payload?.response?.ok).toBe(true);
67
+ expect(el.payload?.request.url).toContain("api.example.test");
68
+ expect(API.prototype.getDetailed).toHaveBeenCalledWith("items/1");
69
+ });
70
+
71
+ it("endpoint dynamique avec configurationKey", async () => {
72
+ const pubId = "getSpecPub2";
73
+ PublisherManager.get(pubId).set(staticConfig);
74
+ const confKey = new DataProviderKey<APIConfiguration>(pubId);
75
+ const rowEp = new Endpoint<{ id: string }>("rows/${rowId}");
76
+
77
+ class TestRow extends HTMLElement {
78
+ rowId = "42";
79
+
80
+ @get(rowEp, confKey)
81
+ payload: ApiGetResult<{ id: string }> | null = null;
82
+ }
83
+
84
+ const tag = "test-api-get-row";
85
+ if (!customElements.get(tag)) {
86
+ customElements.define(tag, TestRow);
87
+ }
88
+
89
+ const el = document.createElement(tag) as InstanceType<typeof TestRow>;
90
+ document.body.appendChild(el);
91
+ await flushGetMicrotasks();
92
+
93
+ expect(API.prototype.getDetailed).toHaveBeenCalledWith("rows/42");
94
+ expect(el.payload?.result).toEqual({ id: "loaded" });
95
+ });
96
+
97
+ it("mode scoped lit la configuration sur les ancêtres (getApiConfiguration)", async () => {
98
+ const dataEp = new Endpoint<{ id: string }>("scoped-endpoint");
99
+
100
+ class TestScoped extends HTMLElement {
101
+ @get(dataEp)
102
+ payload: ApiGetResult<{ id: string }> | null = null;
103
+ }
104
+
105
+ const tag = "test-api-get-scoped";
106
+ if (!customElements.get(tag)) {
107
+ customElements.define(tag, TestScoped);
108
+ }
109
+
110
+ const wrap = document.createElement("div");
111
+ wrap.setAttribute("serviceURL", "https://from-ancestor.test");
112
+ const el = document.createElement(tag) as InstanceType<typeof TestScoped>;
113
+ wrap.appendChild(el);
114
+ document.body.appendChild(wrap);
115
+
116
+ await flushGetMicrotasks();
117
+
118
+ expect(API.prototype.getDetailed).toHaveBeenCalledWith("scoped-endpoint");
119
+ expect(el.payload?.result).toEqual({ id: "loaded" });
120
+ });
121
+
122
+ it("relance le GET quand le publisher de config mute (onInternalMutation)", async () => {
123
+ const pubId = "getSpecPubMut";
124
+ const pub = PublisherManager.get(pubId);
125
+ pub.set(staticConfig);
126
+ const confKey = new DataProviderKey<APIConfiguration>(pubId);
127
+ const itemEp = new Endpoint<{ id: string }>("items/1");
128
+ const tag = "test-api-get-mutation";
129
+
130
+ class C extends HTMLElement {
131
+ @get(itemEp, confKey)
132
+ payload: ApiGetResult<{ id: string }> | null = null;
133
+ }
134
+ if (!customElements.get(tag)) {
135
+ customElements.define(tag, C);
136
+ }
137
+ const el = document.createElement(tag) as InstanceType<typeof C>;
138
+ document.body.appendChild(el);
139
+ await flushGetMicrotasks();
140
+ expect(API.prototype.getDetailed).toHaveBeenCalledTimes(1);
141
+
142
+ pub.set({
143
+ ...staticConfig,
144
+ serviceURL: "https://api.example.test/v2",
145
+ });
146
+ await flushGetMicrotasks();
147
+ expect(API.prototype.getDetailed).toHaveBeenCalledTimes(2);
148
+ expect(el.payload?.result).toEqual({ id: "loaded" });
149
+ });
150
+ });