@supersoniks/concorde 4.9.7 → 4.9.91

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 (72) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +265 -265
  3. package/concorde-core.es.js +4600 -4385
  4. package/dist/concorde-core.bundle.js +265 -265
  5. package/dist/concorde-core.es.js +4600 -4385
  6. package/dist/js/core/components/functional/queue/queue.js +25 -153
  7. package/dist/js/core/components/functional/queue/queue.js.map +1 -1
  8. package/dist/js/core/components/ui/_css/scroll.js +2 -0
  9. package/dist/js/core/components/ui/_css/scroll.js.map +1 -1
  10. package/dist/js/core/decorators/api.js +92 -2
  11. package/dist/js/core/decorators/api.js.map +1 -1
  12. package/dist/js/core/utils/SafariScrollGuard.js +384 -0
  13. package/dist/js/core/utils/SafariScrollGuard.js.map +1 -0
  14. package/dist/js/decorators.js +4 -0
  15. package/dist/js/decorators.js.map +1 -1
  16. package/dist/js/utils.js +3 -0
  17. package/dist/js/utils.js.map +1 -1
  18. package/dist/types/core/components/functional/queue/queue.d.ts +8 -24
  19. package/dist/types/core/components/functional/queue/queue.d.ts.map +1 -1
  20. package/dist/types/core/components/ui/_css/scroll.d.ts.map +1 -1
  21. package/dist/types/core/decorators/api.d.ts +82 -60
  22. package/dist/types/core/decorators/api.d.ts.map +1 -1
  23. package/dist/types/core/utils/SafariScrollGuard.d.ts +36 -0
  24. package/dist/types/core/utils/SafariScrollGuard.d.ts.map +1 -0
  25. package/dist/types/decorators.d.ts +3 -1
  26. package/dist/types/decorators.d.ts.map +1 -1
  27. package/dist/types/utils.d.ts +1 -0
  28. package/dist/types/utils.d.ts.map +1 -1
  29. package/docs/assets/index-BL6WVF7g.css +1 -0
  30. package/docs/assets/{index-hElUgV9_.js → index-DVn8AeyA.js} +572 -555
  31. package/docs/crawl/docs/_decorators/get.html +64 -81
  32. package/docs/crawl/docs/_decorators/patch.html +35 -23
  33. package/docs/crawl/docs/_decorators/post.html +72 -72
  34. package/docs/crawl/docs/_decorators/put.html +36 -21
  35. package/docs/crawl/docs/_getting-started/ai-agents.html +45 -6
  36. package/docs/crawl/hubs/decorators.html +141 -69
  37. package/docs/crawl/hubs/remote-data.html +141 -69
  38. package/docs/index.html +2 -2
  39. package/docs/llms-full.txt +203 -149
  40. package/docs/llms.txt +4 -4
  41. package/docs/src/core/components/functional/queue/queue.md +0 -0
  42. package/docs/src/core/components/ui/button/button.md +0 -0
  43. package/docs/src/docs/_decorators/get.md +55 -81
  44. package/docs/src/docs/_decorators/patch.md +36 -25
  45. package/docs/src/docs/_decorators/post.md +71 -62
  46. package/docs/src/docs/_decorators/put.md +37 -24
  47. package/docs/src/docs/_getting-started/ai-agents.md +24 -4
  48. package/docs/src/docs/search/docs-search.json +151 -1
  49. package/docs/src/tsconfig.json +3 -0
  50. package/package.json +6 -2
  51. package/src/core/components/functional/queue/queue.ts +33 -164
  52. package/src/core/components/ui/_css/scroll.ts +3 -0
  53. package/src/core/decorators/api.post.spec.ts +79 -1
  54. package/src/core/decorators/api.spec.ts +100 -1
  55. package/src/core/decorators/api.ts +252 -138
  56. package/src/core/utils/SafariScrollGuard.ts +429 -0
  57. package/src/decorators.ts +7 -0
  58. package/src/docs/_decorators/get.md +81 -80
  59. package/src/docs/_decorators/patch.md +36 -25
  60. package/src/docs/_decorators/post.md +99 -62
  61. package/src/docs/_decorators/put.md +37 -24
  62. package/src/docs/components/docs-demo-sources.ts +1 -6
  63. package/src/docs/example/decorators-demo-geo.ts +0 -21
  64. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +41 -132
  65. package/src/docs/search/docs-search.json +156 -241
  66. package/src/docs/tailwind/css/tailwind.css +0 -0
  67. package/src/tsconfig.json +3 -0
  68. package/src/tsconfig.tsbuildinfo +1 -1
  69. package/src/utils.ts +13 -0
  70. package/vite.config.mts +4 -0
  71. package/vitest.setup.ts +22 -0
  72. package/docs/assets/index-Bnp7gVaA.css +0 -1
@@ -4,8 +4,13 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>@get — Concorde</title>
7
- <meta name="description" content="Loads data through API.getDetailed. The decorated property is ApiResult&lt;T&gt; | null: request, response (or null for dataProvider(...) resolution without HTTP), and typed result.">
8
- <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/get, get, @get, decorator, API.getDetailed, ApiResult | null, request, response, null, dataProvider(...), result, Endpoint, ApiResult">
7
+ <meta name="description" content="@get loads data and stores the result in an ApiResult&lt;T&gt; | null property.">
8
+ <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/get, get, @get, decorator, ApiResult | null, payload.result, payload.response, payload.request,
9
+
10
+ The first argument is always an
11
+ [, serviceURL, refetch(component),
12
+
13
+ ## Options (, skipEmptyPlaceholder">
9
14
  <meta name="concorde-doc-id" content="docs/_decorators/get">
10
15
  <link rel="canonical" href="https://concorde.supersoniks.org/crawl/docs/_decorators/get.html">
11
16
  </head>
@@ -15,104 +20,82 @@
15
20
  </header>
16
21
  <main>
17
22
  <article>
18
- <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @get</strong>. Loads data through API.getDetailed. The decorated property is ApiResult&lt;T&gt; | null: request, response (or null for dataProvider(...) resolution without HTTP), and typed result. <span>Doc ID: <code>docs/_decorators/get</code>. Keywords: Concorde, supersoniks, docs/_decorators/get, get, @get, decorator, API.getDetailed, ApiResult | null, request, response, null, dataProvider(...), result, Endpoint, ApiResult. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/get.html">https://concorde.supersoniks.org/crawl/docs/_decorators/get.html</a>.</span></p>
23
+ <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @get</strong>. @get loads data and stores the result in an ApiResult&lt;T&gt; | null property. <span>Doc ID: <code>docs/_decorators/get</code>. Keywords: Concorde, supersoniks, docs/_decorators/get, get, @get, decorator, ApiResult | null, payload.result, payload.response, payload.request,
24
+
25
+ The first argument is always an
26
+ [, serviceURL, refetch(component),
27
+
28
+ ## Options (, skipEmptyPlaceholder. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/get.html">https://concorde.supersoniks.org/crawl/docs/_decorators/get.html</a>.</span></p>
19
29
  <h1 id="get">@get</h1>
20
- <p>Loads data through <a href="../../core/utils/api.ts"><code>API.getDetailed</code></a>. The decorated property is <strong><code>ApiResult&lt;T&gt; | null</code></strong>: <code>request</code>, <code>response</code> (or <code>null</code> for <code>dataProvider(...)</code> resolution without HTTP), and typed <code>result</code>.</p>
21
- <p>Pass an <a href="../_misc/endpoint.html#endpoint"><code>Endpoint&lt;T&gt;</code></a> as the first argument. Import <code>get</code> and <code>ApiResult</code> from <code>@supersoniks/concorde/decorators</code>, and <code>Endpoint</code> from <code>@supersoniks/concorde/utils/endpoint</code>.</p>
22
- <h2 id="configuration">Configuration</h2>
30
+ <p><code>@get</code> loads data and stores the result in an <code>ApiResult&lt;T&gt; | null</code> property.</p>
23
31
  <ul>
24
- <li><strong>Default:</strong> <code>HTML.getApiConfiguration(host)</code> (ancestor <code>serviceURL</code>, etc.).</li>
25
- <li><strong>Second argument:</strong> <code>DataProviderKey&lt;APIConfiguration&gt;</code> — config is read from the publisher at the resolved path; internal mutations trigger another GET. See <a href="../_misc/api-configuration.html#api-configuration">API configuration</a> for mock demos.</li>
32
+ <li><code>payload.result</code>: typed data;</li>
33
+ <li><code>payload.response</code>: the HTTP response;</li>
34
+ <li><code>payload.request</code>: the request that was sent.</li>
26
35
  </ul>
27
- <h2 id="dynamic-path">Dynamic path</h2>
28
- <p><code>${prop}</code> on the endpoint or config key is resolved on the host. While a placeholder is <code>null</code> or <code>undefined</code>, no GET runs. Optional <code>skipEmptyPlaceholder: true</code> also blocks <code>&quot;&quot;</code> (empty string only). Details: <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a>.</p>
29
- <h2 id="options-getoptions">Options (<code>GetOptions</code>)</h2>
30
- <p>Pass as the <strong>second</strong> argument (scoped config) or <strong>third</strong> (with a configuration key). Same shape as send decorators where applicable:</p>
31
- <table>
32
- <thead>
33
- <tr>
34
- <th>Option</th>
35
- <th>Description</th>
36
- </tr>
37
- </thead>
38
- <tbody><tr>
39
- <td><code>skipEmptyPlaceholder</code></td>
40
- <td>Treat <code>&quot;&quot;</code> as not ready (see <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path</a>).</td>
41
- </tr>
42
- <tr>
43
- <td><code>refetchEveryMs</code></td>
44
- <td>Automatic polling interval (ms). <code>0</code> or omitted = no polling.</td>
45
- </tr>
46
- <tr>
47
- <td><code>triggerKey</code></td>
48
- <td><code>DataProviderKey</code> — <code>PublisherManager.get(...).invalidate()</code> on that publisher re-runs the GET.</td>
49
- </tr>
50
- </tbody></table>
51
- <h3 id="manual-refetch-triggerkey">Manual refetch (<code>triggerKey</code>)</h3>
52
- <p>Same pattern as <a href="./post.html#post">@post</a>: a publisher acts as a <strong>signal</strong>, independent of the response payload.</p>
53
- <pre><code class="language-typescript">import { get, type ApiResult } from &quot;@supersoniks/concorde/decorators&quot;;
54
- import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
55
- import { DataProviderKey } from &quot;@supersoniks/concorde/dataProviderKey&quot;;
56
- import { dp } from &quot;@supersoniks/concorde/core/utils/PublisherProxy&quot;;
36
+ <h2 id="minimal-usage">Minimal usage</h2>
37
+ <pre><code class="language-typescript">const usersEndpoint = new Endpoint&lt;User[]&gt;(&quot;users&quot;);
57
38
 
58
- const geoCommunesEndpoint = new Endpoint&lt;GeoCommuneRow[]&gt;(
59
- &quot;communes?limit=5&amp;fields=nom,code&quot;,
60
- );
61
- const geoCommunesRefreshKey = new DataProviderKey&lt;void&gt;(
62
- &quot;docsDemoGeoCommunesRefresh&quot;,
63
- );
39
+ @get(usersEndpoint)
40
+ @state()
41
+ payload: ApiResult&lt;User[]&gt; | null = null;
42
+ </code></pre>
43
+ <p>The first argument is always an
44
+ <a href="../_misc/endpoint.html#endpoint"><code>Endpoint&lt;T&gt;</code></a>. API configuration is read
45
+ from the HTML scope (<code>serviceURL</code>, token, etc.), so the component is usually
46
+ placed below an element that provides this configuration.</p>
47
+ <h2 id="refetching-a-get">Refetching a GET</h2>
48
+ <h3 id="from-the-component">From the component</h3>
49
+ <p>Keep the decorator in a constant to access <code>refetch(component)</code>. Refetch only
50
+ targets the instance passed as the argument, even before it has received a
51
+ result.</p>
52
+ <pre><code class="language-typescript">const usersGet = get(new Endpoint&lt;User[]&gt;(&quot;users&quot;));
64
53
 
65
- @get(geoCommunesEndpoint, apiConfigurationKey, {
66
- triggerKey: geoCommunesRefreshKey,
67
- })
54
+ @usersGet
68
55
  @state()
69
- payload: ApiResult&lt;GeoCommuneRow[]&gt; | null = null;
56
+ payload: ApiResult&lt;User[]&gt; | null = null;
70
57
 
71
- // Same component or anywhere else:
72
- dp(geoCommunesRefreshKey).invalidate();
58
+ refresh() {
59
+ usersGet.refetch(this);
60
+ }
61
+ </code></pre>
62
+ <h2 id="options-getoptions">Options (<code>GetOptions</code>)</h2>
63
+ <p>Options are the second argument, or the third argument when an API
64
+ configuration key is provided.</p>
65
+ <ul>
66
+ <li><code>skipEmptyPlaceholder</code>: blocks the GET when <code>${prop}</code> is <code>&quot;&quot;</code>.</li>
67
+ <li><code>refetchEveryMs</code>: automatically runs the GET again after this interval
68
+ (milliseconds). Omit the option, or use <code>0</code>, to disable polling.</li>
69
+ </ul>
70
+ <p>With a configuration key, use:</p>
71
+ <pre><code class="language-typescript">@get(usersEndpoint, apiConfigurationKey)
73
72
  </code></pre>
74
- <p>Prefer <code>triggerKey</code> over mutating the API configuration publisher when you only want to <strong>reload the same URL</strong> — no need to touch <code>serviceURL</code>, tokens, etc.</p>
75
- <p>The docs mock adds an <strong><code>X-Fetched-At</code></strong> response header on <code>/docs-mock-api/geo/communes</code> so live demos can show when the last fetch happened (<code>response.headers.get(&quot;X-Fetched-At&quot;)</code>).</p>
76
73
  <h2 id="when-the-get-runs-again">When the GET runs again</h2>
77
74
  <ul>
78
- <li>A referenced Lit property changes (endpoint path and/or config key contains <code>${...}</code>).</li>
79
- <li><code>set</code> on the active configuration publisher (<code>onInternalMutation</code>).</li>
80
- <li><code>triggerKey</code> publisher <code>invalidate()</code>.</li>
81
- <li><code>refetchEveryMs</code> polling (after each successful fetch).</li>
75
+ <li>when the component connects and configuration is available;</li>
76
+ <li>when a property used in <code>${...}</code> changes;</li>
77
+ <li>when a configuration publisher changes;</li>
78
+ <li>after each response when <code>refetchEveryMs</code> is set.</li>
82
79
  </ul>
80
+ <p>See <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a> for
81
+ dynamic path details.</p>
83
82
  <h2 id="import">Import</h2>
84
83
  <pre><code class="language-typescript">import { get, type ApiResult } from &quot;@supersoniks/concorde/decorators&quot;;
85
- import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
86
84
  import { DataProviderKey } from &quot;@supersoniks/concorde/dataProviderKey&quot;;
85
+ import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
87
86
  </code></pre>
88
- <h2 id="minimal-example">Minimal example</h2>
89
- <p>Same demo service as <a href="../../core/components/functional/queue/queue.demo.ts"><code>sonic-queue</code></a> (<code>/docs-mock-api/geo/</code>). Publisher setup lives in <code>decorators-demo-geo.ts</code> and <code>decorators-demo-subscribe-publish-get-demos.ts</code>.</p>
90
- <pre><code class="language-typescript">@get(new Endpoint&lt;User&gt;(&quot;users/${userId}&quot;))
91
- @state()
92
- payload: ApiResult&lt;User&gt; | null = null;
93
- </code></pre>
94
- <h2 id="live-demos">Live demos</h2>
95
- <p><code>@get</code> with <strong><code>triggerKey</code></strong> — refresh button + <code>X-Fetched-At</code> timestamp in the UI:</p>
87
+ <h2 id="demos">Demos</h2>
96
88
  <pre><code>&lt;docs-demo-sources for=&quot;demo-api-get&quot;&gt;&lt;/docs-demo-sources&gt;
97
89
  &lt;demo-api-get&gt;&lt;/demo-api-get&gt;
98
- </code></pre>
99
- <p>Dynamic config and endpoint path. Manual refetch is triggered <strong>from a separate component</strong> (same <code>triggerKey</code> publisher):</p>
100
- <pre><code>&lt;docs-demo-sources for=&quot;demo-api-get-configuration-key&quot;&gt;&lt;/docs-demo-sources&gt;
90
+ &lt;docs-demo-sources for=&quot;demo-api-get-configuration-key&quot;&gt;&lt;/docs-demo-sources&gt;
101
91
  &lt;demo-api-get-configuration-key&gt;&lt;/demo-api-get-configuration-key&gt;
102
- &lt;demo-api-get-refresh-remote&gt;&lt;/demo-api-get-refresh-remote&gt;
103
- </code></pre>
104
- <p>Scoped <code>@get</code> with <code>@publish</code> / <code>@subscribe</code> on the payload (see <a href="./publish.html#publish">@publish</a> and <a href="./subscribe.html#subscribe">@subscribe</a>) — wrap under an ancestor with <code>serviceURL=&quot;/docs-mock-api/geo/&quot;</code>:</p>
105
- <pre><code>&lt;div serviceURL=&quot;/docs-mock-api/geo/&quot;&gt;
106
- &lt;docs-demo-sources for=&quot;demo-api-get-publish-subscribe&quot;&gt;&lt;/docs-demo-sources&gt;
107
- &lt;demo-api-get-publish-subscribe&gt;&lt;/demo-api-get-publish-subscribe&gt;
108
- &lt;/div&gt;
109
92
  </code></pre>
110
- <p>Stale responses are ignored if the path or generation changed before the request finished.</p>
111
- <h2 id="see-also">See also</h2>
112
- <ul>
113
- <li><a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a></li>
114
- <li><a href="./post.html#post">@post</a> · <a href="./put.html#put">@put</a> · <a href="./patch.html#patch">@patch</a> — send decorators (same path rules)</li>
115
- </ul>
93
+ <p>See <a href="./post.html#post">@post</a>,
94
+ <a href="./put.html#put">@put</a>, and
95
+ <a href="./patch.html#patch">@patch</a> for write operations.</p>
96
+ <h2 id="advanced">Advanced</h2>
97
+ <p>External invalidation is currently available through <code>triggerKey</code>; it is kept
98
+ out of the main usage examples.</p>
116
99
 
117
100
  </article>
118
101
  </main>
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>@patch — Concorde</title>
7
- <meta name="description" content="Sends data through API.patchDetailed. Same model as @post: decorated property is ApiResult&lt;T&gt; | null (request, response, result).">
8
- <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/patch, patch, @patch, decorator, API.patchDetailed, ApiResult | null, request, response, result, Endpoint, DataProviderKey, ApiResult, @supersoniks/concorde/decorators">
7
+ <meta name="description" content="@patch applies a partial update with the body from a publisher. It uses the">
8
+ <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/patch, patch, @patch, decorator, Endpoint, DataProviderKey, ApiResult, send(component), autoPostOnBodyMutation: false, autoPostOnBodyMutation, skipIfBodyMissing, refetchEveryMs, skipEmptyPlaceholder">
9
9
  <meta name="concorde-doc-id" content="docs/_decorators/patch">
10
10
  <link rel="canonical" href="https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html">
11
11
  </head>
@@ -15,34 +15,46 @@
15
15
  </header>
16
16
  <main>
17
17
  <article>
18
- <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @patch</strong>. Sends data through API.patchDetailed. Same model as @post: decorated property is ApiResult&lt;T&gt; | null (request, response, result). <span>Doc ID: <code>docs/_decorators/patch</code>. Keywords: Concorde, supersoniks, docs/_decorators/patch, patch, @patch, decorator, API.patchDetailed, ApiResult | null, request, response, result, Endpoint, DataProviderKey, ApiResult, @supersoniks/concorde/decorators. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html">https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html</a>.</span></p>
18
+ <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @patch</strong>. @patch applies a partial update with the body from a publisher. It uses the <span>Doc ID: <code>docs/_decorators/patch</code>. Keywords: Concorde, supersoniks, docs/_decorators/patch, patch, @patch, decorator, Endpoint, DataProviderKey, ApiResult, send(component), autoPostOnBodyMutation: false, autoPostOnBodyMutation, skipIfBodyMissing, refetchEveryMs, skipEmptyPlaceholder. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html">https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html</a>.</span></p>
19
19
  <h1 id="patch">@patch</h1>
20
- <p>Sends data through <a href="../../core/utils/api.ts"><code>API.patchDetailed</code></a>. Same model as <a href="./post.html#post">@post</a>: decorated property is <strong><code>ApiResult&lt;T&gt; | null</code></strong> (<code>request</code>, <code>response</code>, <code>result</code>).</p>
21
- <p>Pass an <a href="../_misc/endpoint.html#endpoint"><code>Endpoint&lt;T&gt;</code></a> and a <code>DataProviderKey</code> for the <strong>request body</strong>. Import <code>patch</code> and <code>ApiResult</code> from <code>@supersoniks/concorde/decorators</code>.</p>
22
- <h2 id="configuration">Configuration</h2>
23
- <p>Same as <a href="./post.html#post">@post</a> / <a href="./get.html#get">@get</a>: scoped <code>HTML.getApiConfiguration(host)</code> or <code>DataProviderKey&lt;APIConfiguration&gt;</code> as third argument.</p>
24
- <h2 id="options-patchoptions">Options (<code>PatchOptions</code>)</h2>
25
- <p>Same shape as <code>PostOptions</code> on <a href="./post.html#post">@post</a> (<code>ApiSendOptions</code>): <code>refetchEveryMs</code>, <code>skipIfBodyMissing</code>, <code>autoPostOnBodyMutation</code>, <code>triggerKey</code>, <code>skipEmptyPlaceholder</code>. See <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a> for <code>${sessionId}</code> and empty-string behaviour.</p>
20
+ <p><code>@patch</code> applies a partial update with the body from a publisher. It uses the
21
+ same model as <a href="./post.html#post">@post</a>:
22
+ <code>Endpoint&lt;T&gt;</code>, <code>DataProviderKey&lt;B&gt;</code>, <code>ApiResult&lt;T&gt;</code>, options, and the
23
+ <code>send(component)</code> handle.</p>
24
+ <h2 id="minimal-usage">Minimal usage</h2>
25
+ <pre><code class="language-typescript">const bodyKey = new DataProviderKey&lt;Partial&lt;User&gt;&gt;(&quot;users.patch&quot;);
26
+ const patchUser = patch(new Endpoint&lt;User&gt;(&quot;users/42&quot;), bodyKey);
27
+
28
+ @patchUser
29
+ @state()
30
+ payload: ApiResult&lt;User&gt; | null = null;
31
+ </code></pre>
32
+ <p>To run the operation again from the component:</p>
33
+ <pre><code class="language-typescript">savePatch() {
34
+ patchUser.send(this);
35
+ }
36
+ </code></pre>
37
+ <p>The PATCH is also sent automatically when the body mutates, unless
38
+ <code>autoPostOnBodyMutation: false</code> is set. The available options are described in
39
+ <a href="./post.html#post">@post</a>:</p>
40
+ <ul>
41
+ <li><code>autoPostOnBodyMutation</code></li>
42
+ <li><code>skipIfBodyMissing</code></li>
43
+ <li><code>refetchEveryMs</code></li>
44
+ <li><code>skipEmptyPlaceholder</code></li>
45
+ </ul>
46
+ <p>Pass explicit API configuration as the third argument:</p>
47
+ <pre><code class="language-typescript">@patch(endpoint, bodyKey, apiConfigurationKey)
48
+ </code></pre>
26
49
  <h2 id="import">Import</h2>
27
50
  <pre><code class="language-typescript">import { patch, type ApiResult } from &quot;@supersoniks/concorde/decorators&quot;;
28
- import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
29
51
  import { DataProviderKey } from &quot;@supersoniks/concorde/dataProviderKey&quot;;
30
- </code></pre>
31
- <h2 id="example">Example</h2>
32
- <pre><code class="language-typescript">const patchBodyKey = new DataProviderKey&amp;lt;Partial&amp;lt;Resource&amp;gt;&amp;gt;(&quot;resourcePatch&quot;);
33
-
34
- @patch(
35
- new Endpoint&amp;lt;Resource, { resourceId: string }&amp;gt;(&quot;resources/${resourceId}&quot;),
36
- patchBodyKey,
37
- { skipEmptyPlaceholder: true },
38
- )
39
- @state()
40
- payload?: ApiResult&amp;lt;Resource&amp;gt; | null;
52
+ import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
41
53
  </code></pre>
42
54
  <h2 id="see-also">See also</h2>
43
55
  <ul>
44
- <li><a href="./post.html#post">@post</a> — POST (live demos)</li>
45
- <li><a href="./put.html#put">@put</a> — full replacement (PUT)</li>
56
+ <li><a href="./post.html#post">@post</a> — options and triggers</li>
57
+ <li><a href="./put.html#put">@put</a> — full replacement</li>
46
58
  <li><a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a></li>
47
59
  </ul>
48
60
 
@@ -4,8 +4,12 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>@post — Concorde</title>
7
- <meta name="description" content="Sends data through API.postDetailed. The decorated property is ApiResult&lt;T&gt; | null: request, response, and typed result.">
8
- <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/post, post, @post, decorator, API.postDetailed, ApiResult | null, request, response, result, Endpoint, DataProviderKey, ApiResult, @supersoniks/concorde/decorators">
7
+ <meta name="description" content="@post sends the contents of a publisher and stores the response in an">
8
+ <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/post, post, @post, decorator, ApiResult | null, Endpoint, DataProviderKey,
9
+
10
+ The current body is read from , send(component),
11
+
12
+ , PostOptions, autoPostOnBodyMutation, true">
9
13
  <meta name="concorde-doc-id" content="docs/_decorators/post">
10
14
  <link rel="canonical" href="https://concorde.supersoniks.org/crawl/docs/_decorators/post.html">
11
15
  </head>
@@ -15,86 +19,82 @@
15
19
  </header>
16
20
  <main>
17
21
  <article>
18
- <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @post</strong>. Sends data through API.postDetailed. The decorated property is ApiResult&lt;T&gt; | null: request, response, and typed result. <span>Doc ID: <code>docs/_decorators/post</code>. Keywords: Concorde, supersoniks, docs/_decorators/post, post, @post, decorator, API.postDetailed, ApiResult | null, request, response, result, Endpoint, DataProviderKey, ApiResult, @supersoniks/concorde/decorators. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/post.html">https://concorde.supersoniks.org/crawl/docs/_decorators/post.html</a>.</span></p>
22
+ <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @post</strong>. @post sends the contents of a publisher and stores the response in an <span>Doc ID: <code>docs/_decorators/post</code>. Keywords: Concorde, supersoniks, docs/_decorators/post, post, @post, decorator, ApiResult | null, Endpoint, DataProviderKey,
23
+
24
+ The current body is read from , send(component),
25
+
26
+ , PostOptions, autoPostOnBodyMutation, true. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/post.html">https://concorde.supersoniks.org/crawl/docs/_decorators/post.html</a>.</span></p>
19
27
  <h1 id="post">@post</h1>
20
- <p>Sends data through <a href="../../core/utils/api.ts"><code>API.postDetailed</code></a>. The decorated property is <strong><code>ApiResult&lt;T&gt; | null</code></strong>: <code>request</code>, <code>response</code>, and typed <code>result</code>.</p>
21
- <p>Pass an <a href="../_misc/endpoint.html#endpoint"><code>Endpoint&lt;T&gt;</code></a> as the first argument and a <code>DataProviderKey</code> for the <strong>request body</strong> as the second. Import <code>post</code> and <code>ApiResult</code> from <code>@supersoniks/concorde/decorators</code>, and <code>Endpoint</code> from <code>@supersoniks/concorde/utils/endpoint</code>.</p>
22
- <h2 id="configuration">Configuration</h2>
23
- <p>Same as <a href="./get.html#get">@get</a>: scoped <code>HTML.getApiConfiguration(host)</code> by default, or <code>DataProviderKey&lt;APIConfiguration&gt;</code> as third argument. See <a href="../_misc/api-configuration.html#api-configuration">API configuration</a> for mock demos.</p>
24
- <h2 id="optional-postoptions-third-or-fourth-argument">Optional <code>PostOptions</code> (third or fourth argument)</h2>
25
- <table>
26
- <thead>
27
- <tr>
28
- <th>Option</th>
29
- <th>Description</th>
30
- </tr>
31
- </thead>
32
- <tbody><tr>
33
- <td><code>refetchEveryMs</code></td>
34
- <td>Re-post on an interval (ms).</td>
35
- </tr>
36
- <tr>
37
- <td><code>skipIfBodyMissing</code></td>
38
- <td>Skip when body publisher is <code>null</code>/<code>undefined</code> (default: <code>true</code>).</td>
39
- </tr>
40
- <tr>
41
- <td><code>autoPostOnBodyMutation</code></td>
42
- <td>Re-post when the body publisher mutates (default: <code>true</code>). <code>false</code> = manual via <code>triggerKey.invalidate()</code>.</td>
43
- </tr>
44
- <tr>
45
- <td><code>skipEmptyPlaceholder</code></td>
46
- <td>If <code>true</code>, a placeholder resolved to <code>&#39;&#39;</code> blocks the request (empty string only — not <code>0</code> or <code>false</code>). See <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic paths</a>.</td>
47
- </tr>
48
- <tr>
49
- <td><code>triggerKey</code></td>
50
- <td><code>DataProviderKey</code> — <code>invalidate()</code> re-runs the POST with the current body.</td>
51
- </tr>
52
- </tbody></table>
53
- <h2 id="when-the-post-runs-again">When the POST runs again</h2>
28
+ <p><code>@post</code> sends the contents of a publisher and stores the response in an
29
+ <code>ApiResult&lt;T&gt; | null</code> property.</p>
30
+ <h2 id="minimal-usage">Minimal usage</h2>
31
+ <p>Pass an <code>Endpoint&lt;T&gt;</code> and a <code>DataProviderKey&lt;B&gt;</code> for the request body.</p>
32
+ <pre><code class="language-typescript">const userBodyKey = new DataProviderKey&lt;CreateUser&gt;(&quot;users.form&quot;);
33
+ const createUser = post(new Endpoint&lt;User&gt;(&quot;users&quot;), userBodyKey);
34
+
35
+ @createUser
36
+ @state()
37
+ payload: ApiResult&lt;User&gt; | null = null;
38
+ </code></pre>
39
+ <p>The current body is read from <code>userBodyKey</code>. By default, the POST is sent when
40
+ the component connects and after each body mutation. Mutations in the same
41
+ frame are coalesced into one request.</p>
42
+ <p>API configuration is read from the HTML scope, as with
43
+ <a href="./get.html#get">@get</a>.</p>
44
+ <h2 id="sending-the-post-again">Sending the POST again</h2>
45
+ <h3 id="from-the-component">From the component</h3>
46
+ <p>Keep the decorator to access <code>send(component)</code>. The body is read again when the
47
+ operation runs.</p>
48
+ <pre><code class="language-typescript">saveAgain() {
49
+ createUser.send(this);
50
+ }
51
+ </code></pre>
52
+ <p><code>send()</code> is useful for “Save” or “Retry” buttons. It can repeat an operation
53
+ with side effects.</p>
54
+ <h2 id="options-postoptions">Options (<code>PostOptions</code>)</h2>
55
+ <p>Options are the third argument, or the fourth argument when a configuration key
56
+ is provided.</p>
57
+ <ul>
58
+ <li><code>autoPostOnBodyMutation</code>: send after a body mutation (default: <code>true</code>). Set
59
+ it to <code>false</code> to use <code>send()</code>.</li>
60
+ <li><code>skipIfBodyMissing</code>: skip when the body is <code>null</code> or <code>undefined</code> (default:
61
+ <code>true</code>).</li>
62
+ <li><code>refetchEveryMs</code>: repeat the POST at this interval. Use it only when
63
+ repeating the operation is intended.</li>
64
+ <li><code>skipEmptyPlaceholder</code>: block the request when a <code>${...}</code> placeholder is
65
+ <code>&quot;&quot;</code>.</li>
66
+ </ul>
67
+ <p>With a configuration key:</p>
68
+ <pre><code class="language-typescript">@post(endpoint, userBodyKey, apiConfigurationKey)
69
+ </code></pre>
70
+ <p>See <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a> for
71
+ dynamic path details.</p>
72
+ <h2 id="when-the-post-is-sent">When the POST is sent</h2>
54
73
  <ul>
55
- <li>Body publisher <code>onInternalMutation</code> when <code>autoPostOnBodyMutation</code> is <code>true</code> (default). Plusieurs mutations synchrones dans la même frame sont regroupées en <strong>un seul POST</strong> via <code>requestAnimationFrame</code>.</li>
56
- <li>Endpoint path dependency changes (<code>${sessionId}</code> on the host).</li>
57
- <li>Configuration publisher mutation.</li>
58
- <li><code>triggerKey</code> publisher <code>invalidate()</code>.</li>
59
- <li><code>refetchEveryMs</code> timer (if set).</li>
74
+ <li>when the component connects and the body and configuration are available;</li>
75
+ <li>after a body mutation, unless <code>autoPostOnBodyMutation: false</code>;</li>
76
+ <li>when a property used in <code>${...}</code> changes;</li>
77
+ <li>when a configuration publisher changes;</li>
78
+ <li>when <code>send()</code> is called;</li>
79
+ <li>after each response when <code>refetchEveryMs</code> is set.</li>
60
80
  </ul>
61
81
  <h2 id="import">Import</h2>
62
- <pre><code class="language-typescript">import { post, publish, type ApiResult } from &quot;@supersoniks/concorde/decorators&quot;;
63
- import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
82
+ <pre><code class="language-typescript">import { post, type ApiResult } from &quot;@supersoniks/concorde/decorators&quot;;
64
83
  import { DataProviderKey } from &quot;@supersoniks/concorde/dataProviderKey&quot;;
84
+ import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
65
85
  </code></pre>
66
- <h2 id="minimal-example">Minimal example</h2>
67
- <p>Mock service: <code>POST /docs-mock-api/api/register</code> (same route as <a href="../../core/components/functional/submit/submit.html#submit"><code>sonic-submit</code></a> demos). Publisher setup lives in <code>decorators-demo-post.ts</code>.</p>
68
- <pre><code class="language-typescript">const syncRequest = new DataProviderKey&amp;lt;SyncRequest&amp;gt;(&quot;syncRequest&quot;);
69
- const syncTrigger = new DataProviderKey&amp;lt;number&amp;gt;(&quot;syncTrigger&quot;);
70
-
71
- @post(
72
- new Endpoint&amp;lt;SyncResponse, { sessionId: string }&amp;gt;(&quot;sessions/${sessionId}/sync&quot;),
73
- syncRequest,
74
- { triggerKey: syncTrigger },
75
- )
76
- @state()
77
- payload?: ApiResult&amp;lt;SyncResponse&amp;gt; | null;
78
- </code></pre>
79
- <h2 id="live-demos">Live demos</h2>
86
+ <h2 id="demos">Demos</h2>
80
87
  <pre><code>&lt;docs-demo-sources for=&quot;demo-api-post&quot;&gt;&lt;/docs-demo-sources&gt;
81
88
  &lt;demo-api-post&gt;&lt;/demo-api-post&gt;
82
- </code></pre>
83
- <p>Dynamic endpoint path — changing <code>sessionId</code> on the host re-runs the POST (<code>POST /docs-mock-api/api/sessions/{id}/sync</code>):</p>
84
- <pre><code>&lt;docs-demo-sources for=&quot;demo-api-post-dynamic&quot;&gt;&lt;/docs-demo-sources&gt;
89
+ &lt;docs-demo-sources for=&quot;demo-api-post-dynamic&quot;&gt;&lt;/docs-demo-sources&gt;
85
90
  &lt;demo-api-post-dynamic&gt;&lt;/demo-api-post-dynamic&gt;
86
91
  </code></pre>
87
- <p><code>@post</code> + <code>@publish</code> on the same property (see <a href="./publish.html#publish">@publish</a>):</p>
88
- <pre><code>&lt;docs-demo-sources for=&quot;demo-api-post-publish&quot;&gt;&lt;/docs-demo-sources&gt;
89
- &lt;demo-api-post-publish&gt;&lt;/demo-api-post-publish&gt;
90
- </code></pre>
91
- <p>Stale responses are ignored if the path or generation changed before the request finished.</p>
92
- <p><strong>Note:</strong> plusieurs composants <code>@post</code> sur la même page qui partagent le même <code>bodyKey</code> enverront chacun une requête à chaque mutation du body — utiliser une clé par composant (voir les deux démos live ci-dessus).</p>
93
- <p>Path placeholders (<code>${sessionId}</code>, …): <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a>.</p>
94
- <h2 id="see-also">See also</h2>
95
- <ul>
96
- <li><a href="./put.html#put">@put</a> · <a href="./patch.html#patch">@patch</a> — same decorator model, <code>PUT</code> / <code>PATCH</code> via <code>putDetailed</code> / <code>patchDetailed</code></li>
97
- </ul>
92
+ <p>See <a href="./put.html#put">@put</a> and
93
+ <a href="./patch.html#patch">@patch</a>: they use the same model with a
94
+ different HTTP method.</p>
95
+ <h2 id="advanced">Advanced</h2>
96
+ <p>External invalidation is currently available through <code>triggerKey</code>; it is kept
97
+ out of the main usage examples.</p>
98
98
 
99
99
  </article>
100
100
  </main>
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>@put — Concorde</title>
7
- <meta name="description" content="Sends data through API.putDetailed. Same model as @post: decorated property is ApiResult&lt;T&gt; | null (request, response, result).">
8
- <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/put, put, @put, decorator, API.putDetailed, ApiResult | null, request, response, result, Endpoint, DataProviderKey, ApiResult, @supersoniks/concorde/decorators">
7
+ <meta name="description" content="@put replaces a resource with the body from a publisher. It uses exactly the">
8
+ <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/put, put, @put, decorator, Endpoint, DataProviderKey, ApiResult, send(component), autoPostOnBodyMutation: false, autoPostOnBodyMutation, skipIfBodyMissing, refetchEveryMs, skipEmptyPlaceholder">
9
9
  <meta name="concorde-doc-id" content="docs/_decorators/put">
10
10
  <link rel="canonical" href="https://concorde.supersoniks.org/crawl/docs/_decorators/put.html">
11
11
  </head>
@@ -15,32 +15,47 @@
15
15
  </header>
16
16
  <main>
17
17
  <article>
18
- <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @put</strong>. Sends data through API.putDetailed. Same model as @post: decorated property is ApiResult&lt;T&gt; | null (request, response, result). <span>Doc ID: <code>docs/_decorators/put</code>. Keywords: Concorde, supersoniks, docs/_decorators/put, put, @put, decorator, API.putDetailed, ApiResult | null, request, response, result, Endpoint, DataProviderKey, ApiResult, @supersoniks/concorde/decorators. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/put.html">https://concorde.supersoniks.org/crawl/docs/_decorators/put.html</a>.</span></p>
18
+ <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @put</strong>. @put replaces a resource with the body from a publisher. It uses exactly the <span>Doc ID: <code>docs/_decorators/put</code>. Keywords: Concorde, supersoniks, docs/_decorators/put, put, @put, decorator, Endpoint, DataProviderKey, ApiResult, send(component), autoPostOnBodyMutation: false, autoPostOnBodyMutation, skipIfBodyMissing, refetchEveryMs, skipEmptyPlaceholder. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/put.html">https://concorde.supersoniks.org/crawl/docs/_decorators/put.html</a>.</span></p>
19
19
  <h1 id="put">@put</h1>
20
- <p>Sends data through <a href="../../core/utils/api.ts"><code>API.putDetailed</code></a>. Same model as <a href="./post.html#post">@post</a>: decorated property is <strong><code>ApiResult&lt;T&gt; | null</code></strong> (<code>request</code>, <code>response</code>, <code>result</code>).</p>
21
- <p>Pass an <a href="../_misc/endpoint.html#endpoint"><code>Endpoint&lt;T&gt;</code></a> and a <code>DataProviderKey</code> for the <strong>request body</strong>. Import <code>put</code> and <code>ApiResult</code> from <code>@supersoniks/concorde/decorators</code>.</p>
22
- <h2 id="configuration">Configuration</h2>
23
- <p>Same as <a href="./post.html#post">@post</a> / <a href="./get.html#get">@get</a>: scoped <code>HTML.getApiConfiguration(host)</code> or <code>DataProviderKey&lt;APIConfiguration&gt;</code> as third argument.</p>
24
- <h2 id="options-putoptions">Options (<code>PutOptions</code>)</h2>
25
- <p>Same shape as <code>PostOptions</code> on <a href="./post.html#post">@post</a> (<code>ApiSendOptions</code>): <code>refetchEveryMs</code>, <code>skipIfBodyMissing</code>, <code>autoPostOnBodyMutation</code>, <code>triggerKey</code>, <code>skipEmptyPlaceholder</code>. See <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a> for <code>${sessionId}</code> and empty-string behaviour.</p>
20
+ <p><code>@put</code> replaces a resource with the body from a publisher. It uses exactly the
21
+ same model as <a href="./post.html#post">@post</a>:
22
+ <code>Endpoint&lt;T&gt;</code>, <code>DataProviderKey&lt;B&gt;</code>, <code>ApiResult&lt;T&gt;</code>, options, and the
23
+ <code>send(component)</code> handle.</p>
24
+ <h2 id="minimal-usage">Minimal usage</h2>
25
+ <pre><code class="language-typescript">const bodyKey = new DataProviderKey&lt;UpdateUser&gt;(&quot;users.form&quot;);
26
+ const updateUser = put(new Endpoint&lt;User&gt;(&quot;users/42&quot;), bodyKey);
27
+
28
+ @updateUser
29
+ @state()
30
+ payload: ApiResult&lt;User&gt; | null = null;
31
+ </code></pre>
32
+ <p>To run the operation again from the component:</p>
33
+ <pre><code class="language-typescript">update() {
34
+ updateUser.send(this);
35
+ }
36
+ </code></pre>
37
+ <p>The PUT is also sent automatically when the body mutates, unless
38
+ <code>autoPostOnBodyMutation: false</code> is set. See
39
+ <a href="./post.html#post">@post</a> for the option details:</p>
40
+ <ul>
41
+ <li><code>autoPostOnBodyMutation</code></li>
42
+ <li><code>skipIfBodyMissing</code></li>
43
+ <li><code>refetchEveryMs</code></li>
44
+ <li><code>skipEmptyPlaceholder</code></li>
45
+ </ul>
46
+ <p>Pass explicit API configuration as the third argument:</p>
47
+ <pre><code class="language-typescript">@put(endpoint, bodyKey, apiConfigurationKey)
48
+ </code></pre>
26
49
  <h2 id="import">Import</h2>
27
50
  <pre><code class="language-typescript">import { put, type ApiResult } from &quot;@supersoniks/concorde/decorators&quot;;
28
- import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
29
51
  import { DataProviderKey } from &quot;@supersoniks/concorde/dataProviderKey&quot;;
52
+ import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
30
53
  </code></pre>
31
- <h2 id="example">Example</h2>
32
- <pre><code class="language-typescript">const bodyKey = new DataProviderKey&amp;lt;UpdatePayload&amp;gt;(&quot;resourceBody&quot;);
33
-
34
- @put(new Endpoint&amp;lt;Resource, { resourceId: string }&amp;gt;(&quot;resources/${resourceId}&quot;), bodyKey)
35
- @state()
36
- payload?: ApiResult&amp;lt;Resource&amp;gt; | null;
37
- </code></pre>
38
- <p>Changing <code>resourceId</code> on the host re-runs the PUT when the path becomes ready — see <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a>.</p>
39
54
  <h2 id="see-also">See also</h2>
40
55
  <ul>
41
- <li><a href="./post.html#post">@post</a> — POST (live demos, polling, <code>@publish</code>)</li>
42
- <li><a href="./patch.html#patch">@patch</a> — partial update (PATCH)</li>
43
- <li><a href="../_misc/endpoint.html#endpoint">Endpoint</a> · <a href="../_misc/api-configuration.html#api-configuration">API configuration</a></li>
56
+ <li><a href="./post.html#post">@post</a> — options and triggers</li>
57
+ <li><a href="./patch.html#patch">@patch</a> — partial update</li>
58
+ <li><a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a></li>
44
59
  </ul>
45
60
 
46
61
  </article>