@supersoniks/concorde 4.7.3 → 4.8.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 +1 -1
- package/ai/AGENTS.md +4 -0
- package/ai/cursor/rules/concorde.mdc +11 -1
- package/ai/jetbrains/rules/concorde.md +8 -0
- package/ai/skills/concorde/SKILL.md +29 -2
- package/ai/skills/concorde-scope/SKILL.md +2 -2
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +289 -289
- package/concorde-core.es.js +4839 -4546
- package/dist/concorde-core.bundle.js +289 -289
- package/dist/concorde-core.es.js +4839 -4546
- package/dist/docs-mock-api-sw.js +19 -0
- package/dist/docs-mock-api-sw.js.map +2 -2
- package/dist/robots.txt +2 -0
- package/docs/assets/index-wyNMyWT9.js +11196 -0
- package/docs/docs-mock-api-sw.js +19 -0
- package/docs/docs-mock-api-sw.js.map +2 -2
- package/docs/index.html +1 -1
- package/docs/robots.txt +2 -0
- package/package.json +9 -1
- package/public/docs-mock-api-sw.js +19 -0
- package/public/docs-mock-api-sw.js.map +2 -2
- package/public/robots.txt +2 -0
- package/src/core/components/functional/example/example.ts +3 -3
- package/src/core/components/ui/captcha/captcha.md +0 -12
- package/src/core/components/ui/icon/icon.ts +17 -2
- package/src/core/components/ui/menu/menu.ts +12 -3
- package/src/core/decorators/api.post.spec.ts +293 -0
- package/src/core/decorators/api.spec.ts +7 -14
- package/src/core/decorators/api.ts +648 -15
- package/src/core/decorators/subscriber/bind.ts +13 -5
- package/src/core/decorators/subscriber/dynamicPath.spec.ts +53 -0
- package/src/core/decorators/subscriber/dynamicPath.ts +23 -1
- package/src/core/decorators/subscriber/handle.ts +3 -1
- package/src/core/decorators/subscriber/onAssign.ts +10 -2
- package/src/core/decorators/subscriber/publish.ts +12 -2
- package/src/core/utils/PublisherProxy.ts +95 -11
- package/src/core/utils/api.ts +72 -3
- package/src/core/utils/dpOptions.spec.ts +56 -0
- package/src/core/utils/endpoint.ts +3 -3
- package/src/decorators.ts +17 -1
- package/src/docs/_core-concept/dataFlow.md +9 -3
- package/src/docs/_decorators/bind.md +2 -2
- package/src/docs/_decorators/get.md +13 -4
- package/src/docs/_decorators/handle.md +5 -1
- package/src/docs/_decorators/on-assign.md +2 -0
- package/src/docs/_decorators/patch.md +45 -0
- package/src/docs/_decorators/post.md +93 -0
- package/src/docs/_decorators/publish.md +1 -1
- package/src/docs/_decorators/put.md +43 -0
- package/src/docs/_decorators/subscribe.md +4 -1
- package/src/docs/_directives/sub.md +1 -1
- package/src/docs/_getting-started/my-first-component.md +1 -1
- package/src/docs/_misc/api-configuration.md +3 -1
- package/src/docs/_misc/dataProviderKey.md +2 -2
- package/src/docs/_misc/dynamic-path.md +71 -0
- package/src/docs/_misc/endpoint.md +5 -3
- package/src/docs/components/docs-demo-sources.ts +102 -3
- package/src/docs/components/docs-lit-demo-raw.ts +2 -26
- package/src/docs/components/docs-lit-demo.ts +9 -42
- package/src/docs/components/docs-source-excerpt.ts +53 -0
- package/src/docs/components/docs-source-link.ts +24 -8
- package/src/docs/components/docs-source-raw.ts +34 -0
- package/src/docs/example/decorators-demo-geo.ts +2 -2
- package/src/docs/example/decorators-demo-post.ts +249 -0
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +5 -5
- package/src/docs/example/decorators-demo.ts +1 -0
- package/src/docs/example/docs-api-config-demos.ts +5 -5
- package/src/docs/mock-api/router.ts +20 -0
- package/src/docs/navigation/navigation.ts +16 -0
- package/src/docs/search/docs-search.json +540 -15
- package/src/tsconfig.json +24 -0
- package/src/tsconfig.tsbuildinfo +1 -1
- package/vite.config.mts +1 -1
- package/docs/assets/index-D9pxaQYK.js +0 -7508
- package/docs/src/core/components/functional/date/date.md +0 -290
- package/docs/src/core/components/functional/fetch/fetch.md +0 -125
- package/docs/src/core/components/functional/if/if.md +0 -9
- package/docs/src/core/components/functional/list/list.md +0 -65
- package/docs/src/core/components/functional/mix/mix.md +0 -41
- package/docs/src/core/components/functional/queue/queue.md +0 -72
- package/docs/src/core/components/functional/router/router.md +0 -94
- package/docs/src/core/components/functional/sdui/default-library.json +0 -108
- package/docs/src/core/components/functional/sdui/example.json +0 -99
- package/docs/src/core/components/functional/sdui/sdui.md +0 -356
- package/docs/src/core/components/functional/states/states.md +0 -87
- package/docs/src/core/components/functional/submit/submit.md +0 -114
- package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
- package/docs/src/core/components/functional/value/value.md +0 -35
- package/docs/src/core/components/ui/alert/alert.md +0 -121
- package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -0
- package/docs/src/core/components/ui/badge/badge.md +0 -127
- package/docs/src/core/components/ui/button/button.md +0 -182
- package/docs/src/core/components/ui/captcha/captcha.md +0 -24
- package/docs/src/core/components/ui/card/card.md +0 -97
- package/docs/src/core/components/ui/divider/divider.md +0 -35
- package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -77
- package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -129
- package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -77
- package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -44
- package/docs/src/core/components/ui/form/input/input.md +0 -142
- package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -133
- package/docs/src/core/components/ui/form/radio/radio.md +0 -57
- package/docs/src/core/components/ui/form/select/select.md +0 -71
- package/docs/src/core/components/ui/form/switch/switch.md +0 -57
- package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
- package/docs/src/core/components/ui/group/group.md +0 -75
- package/docs/src/core/components/ui/icon/icon.md +0 -125
- package/docs/src/core/components/ui/icon/icons.json +0 -1
- package/docs/src/core/components/ui/image/image.md +0 -107
- package/docs/src/core/components/ui/link/link.md +0 -43
- package/docs/src/core/components/ui/loader/loader.md +0 -55
- package/docs/src/core/components/ui/menu/menu.md +0 -329
- package/docs/src/core/components/ui/modal/modal.md +0 -119
- package/docs/src/core/components/ui/pop/pop.md +0 -96
- package/docs/src/core/components/ui/progress/progress.md +0 -63
- package/docs/src/core/components/ui/table/table.md +0 -455
- package/docs/src/core/components/ui/toast/toast.md +0 -166
- package/docs/src/core/components/ui/tooltip/tooltip.md +0 -82
- package/docs/src/docs/_core-concept/dataFlow.md +0 -73
- package/docs/src/docs/_core-concept/overview.md +0 -57
- package/docs/src/docs/_core-concept/subscriber.md +0 -75
- package/docs/src/docs/_decorators/ancestor-attribute.md +0 -79
- package/docs/src/docs/_decorators/auto-subscribe.md +0 -202
- package/docs/src/docs/_decorators/bind.md +0 -167
- package/docs/src/docs/_decorators/get.md +0 -68
- package/docs/src/docs/_decorators/handle.md +0 -171
- package/docs/src/docs/_decorators/on-assign.md +0 -388
- package/docs/src/docs/_decorators/publish.md +0 -55
- package/docs/src/docs/_decorators/subscribe.md +0 -97
- package/docs/src/docs/_decorators/wait-for-ancestors.md +0 -163
- package/docs/src/docs/_directives/sub.md +0 -91
- package/docs/src/docs/_getting-started/ai-agents.md +0 -56
- package/docs/src/docs/_getting-started/concorde-manual-install.md +0 -133
- package/docs/src/docs/_getting-started/concorde-outside.md +0 -33
- package/docs/src/docs/_getting-started/create-a-component.md +0 -139
- package/docs/src/docs/_getting-started/my-first-component.md +0 -236
- package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -120
- package/docs/src/docs/_getting-started/pubsub.md +0 -37
- package/docs/src/docs/_getting-started/start.md +0 -47
- package/docs/src/docs/_getting-started/theming.md +0 -91
- package/docs/src/docs/_misc/api-configuration.md +0 -79
- package/docs/src/docs/_misc/dataProviderKey.md +0 -168
- package/docs/src/docs/_misc/docs-mock-api.md +0 -60
- package/docs/src/docs/_misc/endpoint.md +0 -43
- package/docs/src/docs/_misc/html-integration.md +0 -13
- package/docs/src/docs/search/docs-search.json +0 -8532
- package/docs/src/tag-list.json +0 -1
- package/docs/src/tsconfig-model.json +0 -23
- package/docs/src/tsconfig.json +0 -1050
- package/php/get-challenge.php +0 -34
- package/php/some-service.php +0 -42
|
@@ -13,57 +13,24 @@ import { prismCSS } from "../prism";
|
|
|
13
13
|
import * as Prism from "prismjs";
|
|
14
14
|
import "prismjs/components/prism-typescript";
|
|
15
15
|
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
): string | null {
|
|
23
|
-
const lines = source.split("\n");
|
|
24
|
-
const needle = `@customElement("${liveTag}")`;
|
|
25
|
-
let start = -1;
|
|
26
|
-
for (let i = 0; i < lines.length; i++) {
|
|
27
|
-
if (lines[i].includes(needle)) {
|
|
28
|
-
start = i;
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (start < 0) return null;
|
|
33
|
-
|
|
34
|
-
let end = lines.length;
|
|
35
|
-
for (let i = start + 1; i < lines.length; i++) {
|
|
36
|
-
if (lines[i].includes("@customElement(")) {
|
|
37
|
-
end = i;
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return lines.slice(start, end).join("\n");
|
|
42
|
-
}
|
|
16
|
+
import { DOCS_SOURCE_RAW } from "./docs-source-raw";
|
|
17
|
+
import {
|
|
18
|
+
excerptLines,
|
|
19
|
+
excerptForCustomElement,
|
|
20
|
+
resolveSourceExcerpt,
|
|
21
|
+
} from "./docs-source-excerpt";
|
|
43
22
|
|
|
44
|
-
|
|
45
|
-
source: string,
|
|
46
|
-
start?: number,
|
|
47
|
-
end?: number,
|
|
48
|
-
): string {
|
|
49
|
-
const lines = source.split("\n");
|
|
50
|
-
if (!start && !end) return source;
|
|
51
|
-
const from = Math.max(1, start ?? 1) - 1;
|
|
52
|
-
const to = end ?? lines.length;
|
|
53
|
-
return lines.slice(from, to).join("\n");
|
|
54
|
-
}
|
|
23
|
+
export { excerptForCustomElement } from "./docs-source-excerpt";
|
|
55
24
|
|
|
56
25
|
function resolveDemoExcerpt(
|
|
57
26
|
raw: string,
|
|
58
27
|
liveTag: string,
|
|
59
28
|
cfg: DocsLitDemoConfig,
|
|
60
29
|
): string {
|
|
61
|
-
const auto = excerptForCustomElement(raw, liveTag);
|
|
62
|
-
if (auto) return auto;
|
|
63
30
|
if (cfg.excerptStart != null || cfg.excerptEnd != null) {
|
|
64
31
|
return excerptLines(raw, cfg.excerptStart, cfg.excerptEnd);
|
|
65
32
|
}
|
|
66
|
-
return raw;
|
|
33
|
+
return resolveSourceExcerpt(raw, liveTag);
|
|
67
34
|
}
|
|
68
35
|
|
|
69
36
|
function highlightTs(code: string): string {
|
|
@@ -112,7 +79,7 @@ export class DocsLitDemo extends LitElement {
|
|
|
112
79
|
const cfg = this.config;
|
|
113
80
|
if (!cfg?.sources[0]) return;
|
|
114
81
|
|
|
115
|
-
const raw =
|
|
82
|
+
const raw = DOCS_SOURCE_RAW[cfg.sources[0].path];
|
|
116
83
|
if (!raw) {
|
|
117
84
|
console.warn(`[docs-lit-demo] No raw source for ${cfg.sources[0].path}`);
|
|
118
85
|
return;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Extrait la classe Lit d'une démo à partir de `@customElement("liveTag")`. */
|
|
2
|
+
export function excerptForCustomElement(
|
|
3
|
+
source: string,
|
|
4
|
+
liveTag: string,
|
|
5
|
+
): string | null {
|
|
6
|
+
const lines = source.split("\n");
|
|
7
|
+
const needle = `@customElement("${liveTag}")`;
|
|
8
|
+
let start = -1;
|
|
9
|
+
for (let i = 0; i < lines.length; i++) {
|
|
10
|
+
if (lines[i].includes(needle)) {
|
|
11
|
+
start = i;
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (start < 0) return null;
|
|
16
|
+
|
|
17
|
+
let end = lines.length;
|
|
18
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
19
|
+
if (lines[i].includes("@customElement(")) {
|
|
20
|
+
end = i;
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return lines.slice(start, end).join("\n");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function excerptLines(
|
|
28
|
+
source: string,
|
|
29
|
+
start?: number,
|
|
30
|
+
end?: number,
|
|
31
|
+
): string {
|
|
32
|
+
const lines = source.split("\n");
|
|
33
|
+
if (!start && !end) return source;
|
|
34
|
+
const from = Math.max(1, start ?? 1) - 1;
|
|
35
|
+
const to = end ?? lines.length;
|
|
36
|
+
return lines.slice(from, to).join("\n");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveSourceExcerpt(
|
|
40
|
+
raw: string,
|
|
41
|
+
liveTag: string,
|
|
42
|
+
options?: { line?: number; excerptEnd?: number },
|
|
43
|
+
): string {
|
|
44
|
+
const byTag = excerptForCustomElement(raw, liveTag);
|
|
45
|
+
if (byTag) return byTag;
|
|
46
|
+
if (options?.line != null) {
|
|
47
|
+
const end =
|
|
48
|
+
options.excerptEnd ??
|
|
49
|
+
Math.min(raw.split("\n").length, options.line + 72);
|
|
50
|
+
return excerptLines(raw, options.line, end);
|
|
51
|
+
}
|
|
52
|
+
return raw;
|
|
53
|
+
}
|
|
@@ -53,20 +53,36 @@ export function docsSourceLink(source: DocsSource) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export function docsSourceLinks(sources: DocsSource[]) {
|
|
56
|
-
if (
|
|
56
|
+
if (sources.length === 0) return nothing;
|
|
57
57
|
return html`
|
|
58
58
|
<div
|
|
59
|
-
class="flex flex-wrap items-center gap-x-1 gap-y-1 mb-
|
|
59
|
+
class="flex flex-wrap items-center gap-x-1 gap-y-1 mb-3 pb-3 border-b border-neutral-200/80 dark:border-neutral-700/80"
|
|
60
60
|
>
|
|
61
61
|
<span class="text-xs uppercase tracking-wide text-neutral-400 mr-1"
|
|
62
62
|
>Source</span
|
|
63
63
|
>
|
|
64
|
-
${
|
|
65
|
-
i
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
${editorAvailable
|
|
65
|
+
? sources.map((s, i) =>
|
|
66
|
+
i === 0
|
|
67
|
+
? docsSourceLink(s)
|
|
68
|
+
: html`<span class="text-neutral-300 dark:text-neutral-600"
|
|
69
|
+
>·</span
|
|
70
|
+
>${docsSourceLink(s)}`,
|
|
71
|
+
)
|
|
72
|
+
: sources.map(
|
|
73
|
+
(s, i) => html`
|
|
74
|
+
${i > 0
|
|
75
|
+
? html`<span class="text-neutral-300 dark:text-neutral-600"
|
|
76
|
+
>·</span
|
|
77
|
+
>`
|
|
78
|
+
: nothing}
|
|
79
|
+
<span
|
|
80
|
+
class="text-xs font-mono text-neutral-500 dark:text-neutral-400"
|
|
81
|
+
title=${s.path}
|
|
82
|
+
>${s.label ?? s.path.split("/").pop()}</span
|
|
83
|
+
>
|
|
84
|
+
`,
|
|
85
|
+
)}
|
|
70
86
|
</div>
|
|
71
87
|
`;
|
|
72
88
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sources brutes des démos doc (`?raw`) — `import.meta.glob` pour éviter les imports manuels.
|
|
3
|
+
* Clés alignées sur `DOCS_DEMO_SOURCE_REGISTRY` / `DOCS_LIT_DEMO_REGISTRY` (`src/docs/...`).
|
|
4
|
+
*/
|
|
5
|
+
const rawModules = import.meta.glob<string>(
|
|
6
|
+
[
|
|
7
|
+
"../example/**/*.ts",
|
|
8
|
+
"../mock-api/**/*.ts",
|
|
9
|
+
"../../core/components/functional/**/*.demo.ts",
|
|
10
|
+
"../../core/components/functional/queue/queue.ts",
|
|
11
|
+
"../../core/components/functional/list/list.ts",
|
|
12
|
+
],
|
|
13
|
+
{ query: "?raw", import: "default", eager: true },
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
function toRegistryPath(globKey: string): string {
|
|
17
|
+
if (globKey.startsWith("../example/")) {
|
|
18
|
+
return `src/docs/example/${globKey.slice("../example/".length)}`;
|
|
19
|
+
}
|
|
20
|
+
if (globKey.startsWith("../mock-api/")) {
|
|
21
|
+
return `src/docs/mock-api/${globKey.slice("../mock-api/".length)}`;
|
|
22
|
+
}
|
|
23
|
+
if (globKey.startsWith("../../core/components/functional/")) {
|
|
24
|
+
return `src/core/components/functional/${globKey.slice("../../core/components/functional/".length)}`;
|
|
25
|
+
}
|
|
26
|
+
return globKey;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const DOCS_SOURCE_RAW: Record<string, string> = Object.fromEntries(
|
|
30
|
+
Object.entries(rawModules).map(([key, content]) => [toRegistryPath(key), content]),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
/** @deprecated Alias — préférer `DOCS_SOURCE_RAW`. */
|
|
34
|
+
export const DOCS_LIT_DEMO_RAW = DOCS_SOURCE_RAW;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { APIConfiguration } from "@supersoniks/concorde/core/utils/api";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ApiResult } from "@supersoniks/concorde/core/utils/api";
|
|
3
3
|
import { Endpoint } from "@supersoniks/concorde/core/utils/endpoint";
|
|
4
4
|
import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
|
|
5
5
|
import { get, set } from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
@@ -47,5 +47,5 @@ export const geoCommunesApiGetEndpointDynamic = new Endpoint<GeoCommuneRow[]>(
|
|
|
47
47
|
);
|
|
48
48
|
|
|
49
49
|
export const geoCommunesApiGetPublishKey = new DataProviderKey<
|
|
50
|
-
|
|
50
|
+
ApiResult<GeoCommuneRow[]>
|
|
51
51
|
>(geoCommunesApiGetEndpoint.path);
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { html, LitElement, nothing } from "lit";
|
|
2
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
3
|
+
import { post, publish, type ApiResult } from "@supersoniks/concorde/decorators";
|
|
4
|
+
import type { APIConfiguration } from "@supersoniks/concorde/core/utils/api";
|
|
5
|
+
import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
|
|
6
|
+
import { Endpoint } from "@supersoniks/concorde/core/utils/endpoint";
|
|
7
|
+
import {
|
|
8
|
+
dp,
|
|
9
|
+
set,
|
|
10
|
+
} from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
11
|
+
import { DOCS_MOCK_REQRES_SERVICE } from "../mock-api/urls";
|
|
12
|
+
import { tailwind } from "../tailwind";
|
|
13
|
+
import "./decorators-demo-init";
|
|
14
|
+
|
|
15
|
+
type RegisterResult = {
|
|
16
|
+
id?: number;
|
|
17
|
+
token?: string;
|
|
18
|
+
email?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type RegisterRequest = {
|
|
22
|
+
email: string;
|
|
23
|
+
password: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const registerPostEndpoint = new Endpoint<RegisterResult>("api/register");
|
|
27
|
+
|
|
28
|
+
type SessionSyncResult = {
|
|
29
|
+
ok?: boolean;
|
|
30
|
+
sessionId?: string;
|
|
31
|
+
serverTime?: number;
|
|
32
|
+
echo?: { note?: string };
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type SessionSyncRequest = {
|
|
36
|
+
note: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const sessionSyncPostEndpoint = new Endpoint<
|
|
40
|
+
SessionSyncResult,
|
|
41
|
+
{ sessionId: string }
|
|
42
|
+
>("api/sessions/${sessionId}/sync");
|
|
43
|
+
|
|
44
|
+
const reqresApiConfiguration: APIConfiguration = {
|
|
45
|
+
serviceURL: DOCS_MOCK_REQRES_SERVICE,
|
|
46
|
+
token: null,
|
|
47
|
+
userName: null,
|
|
48
|
+
password: null,
|
|
49
|
+
authToken: null,
|
|
50
|
+
tokenProvider: null,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const docsDemoReqresApiConfigurationKey =
|
|
54
|
+
new DataProviderKey<APIConfiguration>("docsDemoReqresApiConfiguration");
|
|
55
|
+
|
|
56
|
+
set(docsDemoReqresApiConfigurationKey, reqresApiConfiguration);
|
|
57
|
+
|
|
58
|
+
export const docsDemoPostRequestKey = new DataProviderKey<RegisterRequest>(
|
|
59
|
+
"docsDemoPostRequest",
|
|
60
|
+
);
|
|
61
|
+
/** Clé body distincte — la page doc monte les deux démos live en même temps. */
|
|
62
|
+
export const docsDemoPostPublishRequestKey = new DataProviderKey<RegisterRequest>(
|
|
63
|
+
"docsDemoPostPublishRequest",
|
|
64
|
+
);
|
|
65
|
+
export const docsDemoPostTriggerKey = new DataProviderKey<number>(
|
|
66
|
+
"docsDemoPostTrigger",
|
|
67
|
+
);
|
|
68
|
+
export const docsDemoPostDynamicRequestKey = new DataProviderKey<SessionSyncRequest>(
|
|
69
|
+
"docsDemoPostDynamicRequest",
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
@customElement("demo-api-post")
|
|
73
|
+
export class DemoApiPost extends LitElement {
|
|
74
|
+
static styles = [tailwind];
|
|
75
|
+
|
|
76
|
+
@post(
|
|
77
|
+
registerPostEndpoint,
|
|
78
|
+
docsDemoPostRequestKey,
|
|
79
|
+
docsDemoReqresApiConfigurationKey,
|
|
80
|
+
{ triggerKey: docsDemoPostTriggerKey },
|
|
81
|
+
)
|
|
82
|
+
@state()
|
|
83
|
+
payload?: ApiResult<RegisterResult> | null;
|
|
84
|
+
|
|
85
|
+
connectedCallback() {
|
|
86
|
+
super.connectedCallback();
|
|
87
|
+
set(docsDemoPostRequestKey, {
|
|
88
|
+
email: "demo@concorde.local",
|
|
89
|
+
password: "demo-password",
|
|
90
|
+
});
|
|
91
|
+
set(docsDemoPostTriggerKey, 0);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private send() {
|
|
95
|
+
set(docsDemoPostRequestKey, {
|
|
96
|
+
email: "demo@concorde.local",
|
|
97
|
+
password: "demo-password",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private resendSameBody() {
|
|
102
|
+
dp(docsDemoPostTriggerKey).invalidate();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
render() {
|
|
106
|
+
const result = this.payload?.result;
|
|
107
|
+
const status = this.payload?.response?.status;
|
|
108
|
+
return html`
|
|
109
|
+
<div class="space-y-4">
|
|
110
|
+
<p class="text-sm text-neutral-600 dark:text-neutral-400">
|
|
111
|
+
<code>@post</code> vers le mock
|
|
112
|
+
<code>POST /docs-mock-api/api/register</code> — body lu depuis
|
|
113
|
+
<code>docsDemoPostRequest</code>.
|
|
114
|
+
</p>
|
|
115
|
+
<div class="flex flex-wrap gap-2">
|
|
116
|
+
<sonic-button @click=${this.send}>Set body & POST</sonic-button>
|
|
117
|
+
<sonic-button variant="secondary" @click=${this.resendSameBody}>
|
|
118
|
+
invalidate trigger (re-POST)
|
|
119
|
+
</sonic-button>
|
|
120
|
+
</div>
|
|
121
|
+
<div
|
|
122
|
+
class="rounded border border-neutral-200 dark:border-neutral-700 p-3 text-sm space-y-1"
|
|
123
|
+
>
|
|
124
|
+
<p>HTTP status: <strong>${status ?? "—"}</strong></p>
|
|
125
|
+
${result?.id != null
|
|
126
|
+
? html`<p>id: <span class="font-mono">${result.id}</span></p>`
|
|
127
|
+
: nothing}
|
|
128
|
+
${result?.email
|
|
129
|
+
? html`<p>email: <span class="font-mono">${result.email}</span></p>`
|
|
130
|
+
: nothing}
|
|
131
|
+
${result?.token
|
|
132
|
+
? html`<p>
|
|
133
|
+
token:
|
|
134
|
+
<span class="font-mono break-all">${result.token}</span>
|
|
135
|
+
</p>`
|
|
136
|
+
: nothing}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@customElement("demo-api-post-dynamic")
|
|
144
|
+
export class DemoApiPostDynamic extends LitElement {
|
|
145
|
+
static styles = [tailwind];
|
|
146
|
+
|
|
147
|
+
@property({ type: String }) sessionId = "alpha";
|
|
148
|
+
|
|
149
|
+
@post(
|
|
150
|
+
sessionSyncPostEndpoint,
|
|
151
|
+
docsDemoPostDynamicRequestKey,
|
|
152
|
+
docsDemoReqresApiConfigurationKey,
|
|
153
|
+
)
|
|
154
|
+
@state()
|
|
155
|
+
payload?: ApiResult<SessionSyncResult> | null;
|
|
156
|
+
|
|
157
|
+
connectedCallback() {
|
|
158
|
+
super.connectedCallback();
|
|
159
|
+
set(docsDemoPostDynamicRequestKey, { note: "docs @post dynamic path" });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private setSession(sessionId: string) {
|
|
163
|
+
this.sessionId = sessionId;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
render() {
|
|
167
|
+
const result = this.payload?.result;
|
|
168
|
+
const status = this.payload?.response?.status;
|
|
169
|
+
const requestUrl = this.payload?.request?.url ?? "";
|
|
170
|
+
return html`
|
|
171
|
+
<div class="space-y-4">
|
|
172
|
+
<p class="text-sm text-neutral-600 dark:text-neutral-400">
|
|
173
|
+
<code>@post</code> vers
|
|
174
|
+
<code>api/sessions/${"${sessionId}"}/sync</code> — changer
|
|
175
|
+
<code>sessionId</code> sur l'hôte relance le POST (même body).
|
|
176
|
+
</p>
|
|
177
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
178
|
+
<span class="text-sm text-neutral-500">sessionId :</span>
|
|
179
|
+
${(["alpha", "beta", "gamma"] as const).map(
|
|
180
|
+
(id) => html`
|
|
181
|
+
<sonic-button
|
|
182
|
+
variant=${this.sessionId === id ? "primary" : "secondary"}
|
|
183
|
+
size="sm"
|
|
184
|
+
@click=${() => this.setSession(id)}
|
|
185
|
+
>
|
|
186
|
+
${id}
|
|
187
|
+
</sonic-button>
|
|
188
|
+
`,
|
|
189
|
+
)}
|
|
190
|
+
</div>
|
|
191
|
+
<div
|
|
192
|
+
class="rounded border border-neutral-200 dark:border-neutral-700 p-3 text-sm space-y-1"
|
|
193
|
+
>
|
|
194
|
+
<p>HTTP status: <strong>${status ?? "—"}</strong></p>
|
|
195
|
+
<p>
|
|
196
|
+
Dernier path :
|
|
197
|
+
<span class="font-mono text-xs break-all">${requestUrl || "—"}</span>
|
|
198
|
+
</p>
|
|
199
|
+
<p>
|
|
200
|
+
Réponse <code>sessionId</code> :
|
|
201
|
+
<strong class="font-mono">${result?.sessionId ?? "—"}</strong>
|
|
202
|
+
</p>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
`;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@customElement("demo-api-post-publish")
|
|
210
|
+
export class DemoApiPostPublish extends LitElement {
|
|
211
|
+
static styles = [tailwind];
|
|
212
|
+
|
|
213
|
+
@post(
|
|
214
|
+
registerPostEndpoint,
|
|
215
|
+
docsDemoPostPublishRequestKey,
|
|
216
|
+
docsDemoReqresApiConfigurationKey,
|
|
217
|
+
)
|
|
218
|
+
@publish(
|
|
219
|
+
registerPostEndpoint.getDataProviderKey() as DataProviderKey<
|
|
220
|
+
ApiResult<RegisterResult>
|
|
221
|
+
>,
|
|
222
|
+
)
|
|
223
|
+
@state()
|
|
224
|
+
payload?: ApiResult<RegisterResult> | null;
|
|
225
|
+
|
|
226
|
+
connectedCallback() {
|
|
227
|
+
super.connectedCallback();
|
|
228
|
+
set(docsDemoPostPublishRequestKey, {
|
|
229
|
+
email: "publish@concorde.local",
|
|
230
|
+
password: "secret",
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
render() {
|
|
235
|
+
const email = this.payload?.result?.email;
|
|
236
|
+
return html`
|
|
237
|
+
<div class="space-y-3 text-sm">
|
|
238
|
+
<p class="text-neutral-600 dark:text-neutral-400">
|
|
239
|
+
<code>@post</code> + <code>@publish</code> sur le même champ — même
|
|
240
|
+
pattern que <code>@get</code> + <code>@publish</code>.
|
|
241
|
+
</p>
|
|
242
|
+
<p>
|
|
243
|
+
Result email:
|
|
244
|
+
<strong class="font-mono">${email ?? "—"}</strong>
|
|
245
|
+
</p>
|
|
246
|
+
</div>
|
|
247
|
+
`;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -3,7 +3,7 @@ import { customElement, property, state } from "lit/decorators.js";
|
|
|
3
3
|
import { get, handle, publish, subscribe } from "@supersoniks/concorde/decorators";
|
|
4
4
|
import type {
|
|
5
5
|
APIConfiguration,
|
|
6
|
-
|
|
6
|
+
ApiResult,
|
|
7
7
|
} from "@supersoniks/concorde/core/utils/api";
|
|
8
8
|
import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
|
|
9
9
|
import { sub } from "@supersoniks/concorde/directives";
|
|
@@ -92,7 +92,7 @@ export class DemoApiGet extends LitElement {
|
|
|
92
92
|
|
|
93
93
|
@get(geoCommunesApiGetEndpoint, docsDemoGeoApiConfigurationKey)
|
|
94
94
|
@state()
|
|
95
|
-
geoApiPayload?:
|
|
95
|
+
geoApiPayload?: ApiResult<GeoCommuneRow[]>;
|
|
96
96
|
|
|
97
97
|
render() {
|
|
98
98
|
const rows = this.geoApiPayload?.result;
|
|
@@ -102,7 +102,7 @@ export class DemoApiGet extends LitElement {
|
|
|
102
102
|
<p class="text-sm text-neutral-600 dark:text-neutral-400">
|
|
103
103
|
<code>@get</code> — même service que
|
|
104
104
|
<code>sonic-queue</code> (<code>/docs-mock-api/geo/</code>).
|
|
105
|
-
Propriété typée <code>
|
|
105
|
+
Propriété typée <code>ApiResult<T></code>.
|
|
106
106
|
</p>
|
|
107
107
|
${status != null
|
|
108
108
|
? html`<p class="text-xs text-neutral-500">HTTP ${status}</p>`
|
|
@@ -141,7 +141,7 @@ export class DemoApiGetConfigurationKey extends LitElement {
|
|
|
141
141
|
|
|
142
142
|
@get(geoCommunesApiGetEndpointDynamic, docsDemoDynApiConfKeyTemplate)
|
|
143
143
|
@state()
|
|
144
|
-
geoApiPayloadDyn?:
|
|
144
|
+
geoApiPayloadDyn?: ApiResult<GeoCommuneRow[]>;
|
|
145
145
|
|
|
146
146
|
private touchCurrentConfigPublisher() {
|
|
147
147
|
const key =
|
|
@@ -237,7 +237,7 @@ export class DemoApiGetPublishSubscribe extends LitElement {
|
|
|
237
237
|
@get(geoCommunesApiGetEndpoint)
|
|
238
238
|
@publish(geoCommunesApiGetPublishKey)
|
|
239
239
|
@state()
|
|
240
|
-
geoApiPayloadPublished:
|
|
240
|
+
geoApiPayloadPublished: ApiResult<GeoCommuneRow[]> | null = null;
|
|
241
241
|
|
|
242
242
|
@state()
|
|
243
243
|
@subscribe(geoCommunesApiGetPublishKey.result)
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { tailwind } from "../tailwind";
|
|
25
25
|
import "./decorators-demo-bind-demos";
|
|
26
26
|
import "./decorators-demo-subscribe-publish-get-demos";
|
|
27
|
+
import "./decorators-demo-post";
|
|
27
28
|
|
|
28
29
|
@customElement("demo-ancestor-attribute")
|
|
29
30
|
export class DemoAncestorAttribute extends LitElement {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html, LitElement, nothing } from "lit";
|
|
2
2
|
import { customElement, state } from "lit/decorators.js";
|
|
3
3
|
import { get } from "@supersoniks/concorde/core/decorators/api";
|
|
4
|
-
import type {
|
|
4
|
+
import type { ApiResult } from "@supersoniks/concorde/core/utils/api";
|
|
5
5
|
import { Endpoint } from "@supersoniks/concorde/core/utils/endpoint";
|
|
6
6
|
import { set } from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
7
7
|
import { wording } from "@supersoniks/concorde/core/directives/Wording";
|
|
@@ -33,7 +33,7 @@ type ProtectedResult = {
|
|
|
33
33
|
|
|
34
34
|
const protectedEndpoint = new Endpoint<ProtectedResult>("api/config/protected");
|
|
35
35
|
|
|
36
|
-
function resultPanel(payload:
|
|
36
|
+
function resultPanel(payload: ApiResult<ProtectedResult> | null | undefined) {
|
|
37
37
|
const status = payload?.response?.status;
|
|
38
38
|
const r = payload?.result;
|
|
39
39
|
if (payload === null) {
|
|
@@ -66,7 +66,7 @@ export class DocsApiConfigBearerDemo extends LitElement {
|
|
|
66
66
|
|
|
67
67
|
@get(protectedEndpoint, docsApiConfBearerKey)
|
|
68
68
|
@state()
|
|
69
|
-
private payload:
|
|
69
|
+
private payload: ApiResult<ProtectedResult> | null = null;
|
|
70
70
|
|
|
71
71
|
render() {
|
|
72
72
|
return html`
|
|
@@ -86,7 +86,7 @@ export class DocsApiConfigTokenProviderDemo extends LitElement {
|
|
|
86
86
|
|
|
87
87
|
@get(protectedEndpoint, docsApiConfTokenProviderKey)
|
|
88
88
|
@state()
|
|
89
|
-
private payload:
|
|
89
|
+
private payload: ApiResult<ProtectedResult> | null = null;
|
|
90
90
|
|
|
91
91
|
render() {
|
|
92
92
|
return html`
|
|
@@ -107,7 +107,7 @@ export class DocsApiConfigStaleTokenDemo extends LitElement {
|
|
|
107
107
|
|
|
108
108
|
@get(protectedEndpoint, docsApiConfStaleTokenKey)
|
|
109
109
|
@state()
|
|
110
|
-
private payload:
|
|
110
|
+
private payload: ApiResult<ProtectedResult> | null = null;
|
|
111
111
|
|
|
112
112
|
render() {
|
|
113
113
|
const refreshed =
|
|
@@ -180,6 +180,26 @@ export async function handleDocsMockApiRequest(
|
|
|
180
180
|
);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
const sessionSyncMatch = subPath.match(/^\/api\/sessions\/([^/]+)\/sync$/);
|
|
184
|
+
if (sessionSyncMatch && method === "POST") {
|
|
185
|
+
const sessionId = decodeURIComponent(sessionSyncMatch[1]);
|
|
186
|
+
let body: Record<string, unknown> = {};
|
|
187
|
+
try {
|
|
188
|
+
const text = await request.text();
|
|
189
|
+
if (text.trim()) {
|
|
190
|
+
body = JSON.parse(text) as Record<string, unknown>;
|
|
191
|
+
}
|
|
192
|
+
} catch {
|
|
193
|
+
body = {};
|
|
194
|
+
}
|
|
195
|
+
return json({
|
|
196
|
+
ok: true,
|
|
197
|
+
sessionId,
|
|
198
|
+
serverTime: Date.now(),
|
|
199
|
+
echo: body,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
183
203
|
if (subPath === "/api/register/echo" && method === "GET") {
|
|
184
204
|
const email = url.searchParams.get("email") ?? "";
|
|
185
205
|
const password = url.searchParams.get("password") ?? "";
|
|
@@ -153,6 +153,18 @@ export class DocsNavigation extends LitElement {
|
|
|
153
153
|
label: "@get",
|
|
154
154
|
href: "#docs/_decorators/get.md/get",
|
|
155
155
|
},
|
|
156
|
+
{
|
|
157
|
+
label: "@post",
|
|
158
|
+
href: "#docs/_decorators/post.md/post",
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
label: "@put",
|
|
162
|
+
href: "#docs/_decorators/put.md/put",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
label: "@patch",
|
|
166
|
+
href: "#docs/_decorators/patch.md/patch",
|
|
167
|
+
},
|
|
156
168
|
{
|
|
157
169
|
label: "@onAssign",
|
|
158
170
|
href: "#docs/_decorators/on-assign.md/on-assign",
|
|
@@ -174,6 +186,10 @@ export class DocsNavigation extends LitElement {
|
|
|
174
186
|
label: "Endpoint",
|
|
175
187
|
href: "#docs/_misc/endpoint.md/endpoint",
|
|
176
188
|
},
|
|
189
|
+
{
|
|
190
|
+
label: "Dynamic paths",
|
|
191
|
+
href: "#docs/_misc/dynamic-path.md/dynamic-path",
|
|
192
|
+
},
|
|
177
193
|
{
|
|
178
194
|
label: "API configuration",
|
|
179
195
|
href: "#docs/_misc/api-configuration.md/api-configuration",
|