@supersoniks/concorde 4.9.9 → 4.9.92

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 (48) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +241 -241
  3. package/concorde-core.es.js +2931 -2851
  4. package/dist/concorde-core.bundle.js +241 -241
  5. package/dist/concorde-core.es.js +2931 -2851
  6. package/dist/js/core/decorators/api.js +146 -43
  7. package/dist/js/core/decorators/api.js.map +1 -1
  8. package/dist/js/decorators.js +4 -0
  9. package/dist/js/decorators.js.map +1 -1
  10. package/dist/types/core/decorators/api.d.ts +87 -60
  11. package/dist/types/core/decorators/api.d.ts.map +1 -1
  12. package/dist/types/decorators.d.ts +3 -1
  13. package/dist/types/decorators.d.ts.map +1 -1
  14. package/docs/assets/index-D2Q3JyQ6.css +1 -0
  15. package/docs/assets/{index-hElUgV9_.js → index-DURr6O71.js} +651 -736
  16. package/docs/crawl/docs/_decorators/get.html +89 -81
  17. package/docs/crawl/docs/_decorators/patch.html +43 -23
  18. package/docs/crawl/docs/_decorators/post.html +101 -72
  19. package/docs/crawl/docs/_decorators/put.html +44 -21
  20. package/docs/crawl/docs/_getting-started/ai-agents.html +45 -6
  21. package/docs/crawl/hubs/decorators.html +145 -70
  22. package/docs/crawl/hubs/remote-data.html +145 -70
  23. package/docs/index.html +2 -2
  24. package/docs/llms-full.txt +276 -147
  25. package/docs/llms.txt +4 -4
  26. package/docs/src/core/components/functional/queue/queue.md +0 -0
  27. package/docs/src/core/components/ui/button/button.md +0 -0
  28. package/docs/src/docs/_decorators/get.md +88 -80
  29. package/docs/src/docs/_decorators/patch.md +41 -25
  30. package/docs/src/docs/_decorators/post.md +104 -62
  31. package/docs/src/docs/_decorators/put.md +42 -24
  32. package/docs/src/docs/_getting-started/ai-agents.md +24 -4
  33. package/docs/src/docs/search/docs-search.json +182 -112
  34. package/docs/src/tsconfig.json +270 -267
  35. package/package.json +1 -1
  36. package/src/core/decorators/api.post.spec.ts +79 -1
  37. package/src/core/decorators/api.spec.ts +141 -1
  38. package/src/core/decorators/api.ts +330 -180
  39. package/src/decorators.ts +7 -0
  40. package/src/docs/_decorators/get.md +88 -80
  41. package/src/docs/_decorators/patch.md +41 -25
  42. package/src/docs/_decorators/post.md +104 -62
  43. package/src/docs/_decorators/put.md +42 -24
  44. package/src/docs/components/docs-demo-sources.ts +9 -14
  45. package/src/docs/example/decorators-demo-geo.ts +0 -21
  46. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +42 -133
  47. package/src/docs/search/docs-search.json +128 -133
  48. package/docs/assets/index-Bnp7gVaA.css +0 -1
package/src/decorators.ts CHANGED
@@ -19,6 +19,8 @@ export const get = api.get;
19
19
  export const post = api.post;
20
20
  export const put = api.put;
21
21
  export const patch = api.patch;
22
+ export const refetch = api.refetch;
23
+ export const send = api.send;
22
24
  export {
23
25
  DataProviderKey,
24
26
  type DataProviderKeyHost,
@@ -27,6 +29,9 @@ export { Endpoint };
27
29
  export type { ApiResult, ApiGetResult } from "./core/utils/api";
28
30
  export type {
29
31
  ApiSendOptions,
32
+ ApiSendDecoratorHandle,
33
+ ApiMethodActionOptions,
34
+ GetDecoratorHandle,
30
35
  GetOptions,
31
36
  PostOptions,
32
37
  PutOptions,
@@ -57,4 +62,6 @@ window["concorde-decorator-subscriber"] = {
57
62
  post: api.post,
58
63
  put: api.put,
59
64
  patch: api.patch,
65
+ refetch: api.refetch,
66
+ send: api.send,
60
67
  };
@@ -1,123 +1,131 @@
1
1
  # @get
2
2
 
3
- Loads data through [`API.getDetailed`](../../core/utils/api.ts). The decorated property is **`ApiResult<T> | null`**: `request`, `response` (or `null` for `dataProvider(...)` resolution without HTTP), and typed `result`.
3
+ `@get` loads data and stores the result in an optional `ApiResult<T>` property.
4
+ The property is `undefined` until a result is available.
4
5
 
5
- Pass an [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint) as the first argument. Import `get` and `ApiResult` from `@supersoniks/concorde/decorators`, and `Endpoint` from `@supersoniks/concorde/utils/endpoint`.
6
+ - `payload.result`: typed data;
7
+ - `payload.response`: the HTTP response;
8
+ - `payload.request`: the request that was sent.
6
9
 
7
- ## Configuration
10
+ ## Minimal usage
8
11
 
9
- - **Default:** `HTML.getApiConfiguration(host)` (ancestor `serviceURL`, etc.).
10
- - **Second argument:** `DataProviderKey<APIConfiguration>` — config is read from the publisher at the resolved path; internal mutations trigger another GET. See [API configuration](#docs/_misc/api-configuration.md/api-configuration) for mock demos.
12
+ ```typescript
13
+ const usersEndpoint = new Endpoint<User[]>("users");
11
14
 
12
- ## Dynamic path
15
+ @get(usersEndpoint)
16
+ @state()
17
+ payload?: ApiResult<User[]>;
18
+ ```
13
19
 
14
- `${prop}` on the endpoint or config key is resolved on the host. While a placeholder is `null` or `undefined`, no GET runs. Optional `skipEmptyPlaceholder: true` also blocks `""` (empty string only). Details: [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path).
20
+ The first argument is always an
21
+ [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint). API configuration is read
22
+ from the HTML scope (`serviceURL`, token, etc.), so the component is usually
23
+ placed below an element that provides this configuration.
15
24
 
16
- ## Options (`GetOptions`)
25
+ ## Refetching a GET
17
26
 
18
- Pass as the **second** argument (scoped config) or **third** (with a configuration key). Same shape as send decorators where applicable:
27
+ ### From the component
19
28
 
20
- | Option | Description |
21
- |--------|-------------|
22
- | `skipEmptyPlaceholder` | Treat `""` as not ready (see [Dynamic path](#docs/_misc/dynamic-path.md/dynamic-path)). |
23
- | `refetchEveryMs` | Automatic polling interval (ms). `0` or omitted = no polling. |
24
- | `triggerKey` | `DataProviderKey` — `PublisherManager.get(...).invalidate()` on that publisher re-runs the GET. |
29
+ Keep the decorator in a constant to access `refetch(component)`. Refetch only
30
+ targets the instance passed as the argument, even before it has received a
31
+ result.
25
32
 
26
- ### Manual refetch (`triggerKey`)
33
+ ```typescript
34
+ const usersGet = get(new Endpoint<User[]>("users"));
27
35
 
28
- Same pattern as [@post](#docs/_decorators/post.md/post): a publisher acts as a **signal**, independent of the response payload.
36
+ @usersGet
37
+ @state()
38
+ payload?: ApiResult<User[]>;
39
+
40
+ async refresh() {
41
+ const payload = await usersGet.refetch(this);
42
+ console.log(payload?.result);
43
+ }
44
+ ```
45
+
46
+ `refetch(component)` returns a `Promise<ApiResult<T> | undefined>` that resolves
47
+ after the GET has completed.
48
+
49
+ ### From a method decorator
50
+
51
+ The refetch can decorate a local method. The default is `after`; if the
52
+ method returns a Promise, the GET waits for its resolution. The decorated method
53
+ call also waits for the refetch to complete.
29
54
 
30
55
  ```typescript
31
- import { get, type ApiResult } from "@supersoniks/concorde/decorators";
32
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
33
- import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
34
- import { dp } from "@supersoniks/concorde/core/utils/PublisherProxy";
35
-
36
- const geoCommunesEndpoint = new Endpoint<GeoCommuneRow[]>(
37
- "communes?limit=5&fields=nom,code",
38
- );
39
- const geoCommunesRefreshKey = new DataProviderKey<void>(
40
- "docsDemoGeoCommunesRefresh",
41
- );
42
-
43
- @get(geoCommunesEndpoint, apiConfigurationKey, {
44
- triggerKey: geoCommunesRefreshKey,
45
- })
46
- @state()
47
- payload: ApiResult<GeoCommuneRow[]> | null = null;
56
+ import { refetch } from "@supersoniks/concorde/decorators";
57
+
58
+ @refetch(usersGet)
59
+ async reload() {
60
+ this.userId = "42";
61
+ }
62
+ ```
63
+
64
+ Use `{ when: "before" }` when the GET must complete before the method runs:
48
65
 
49
- // Same component or anywhere else:
50
- dp(geoCommunesRefreshKey).invalidate();
66
+ ```typescript
67
+ @refetch(usersGet, { when: "before" })
68
+ reloadBefore() {
69
+ // The refetch has completed before this method runs.
70
+ }
51
71
  ```
52
72
 
53
- Prefer `triggerKey` over mutating the API configuration publisher when you only want to **reload the same URL** — no need to touch `serviceURL`, tokens, etc.
73
+ The method decorator adds an explicit trigger; changes to dynamic endpoint
74
+ properties and configuration publishers keep their existing automatic behavior.
54
75
 
55
- The docs mock adds an **`X-Fetched-At`** response header on `/docs-mock-api/geo/communes` so live demos can show when the last fetch happened (`response.headers.get("X-Fetched-At")`).
76
+ ## Options (`GetOptions`)
77
+
78
+ Options are the second argument, or the third argument when an API
79
+ configuration key is provided.
80
+
81
+ - `skipEmptyPlaceholder`: blocks the GET when `${prop}` is `""`.
82
+ - `refetchEveryMs`: automatically runs the GET again after this interval
83
+ (milliseconds). Omit the option, or use `0`, to disable polling.
84
+ - `triggerKey`: a publisher whose `invalidate()` runs the GET again.
85
+
86
+ With a configuration key, use:
87
+
88
+ ```typescript
89
+ @get(usersEndpoint, apiConfigurationKey)
90
+ ```
56
91
 
57
92
  ## When the GET runs again
58
93
 
59
- - A referenced Lit property changes (endpoint path and/or config key contains `${...}`).
60
- - `set` on the active configuration publisher (`onInternalMutation`).
61
- - `triggerKey` publisher `invalidate()`.
62
- - `refetchEveryMs` polling (after each successful fetch).
94
+ - when the component connects and configuration is available;
95
+ - when a property used in `${...}` changes;
96
+ - when a configuration publisher changes;
97
+ - when the `triggerKey` publisher is invalidated;
98
+ - after each response when `refetchEveryMs` is set.
99
+
100
+ See [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path) for
101
+ dynamic path details.
63
102
 
64
103
  ## Import
65
104
 
66
105
  <sonic-code language="typescript">
67
106
  <template>
68
107
  import { get, type ApiResult } from "@supersoniks/concorde/decorators";
69
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
70
108
  import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
109
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
71
110
  </template>
72
111
  </sonic-code>
73
112
 
74
- ## Minimal example
75
-
76
- Same demo service as [`sonic-queue`](../../core/components/functional/queue/queue.demo.ts) (`/docs-mock-api/geo/`). Publisher setup lives in `decorators-demo-geo.ts` and `decorators-demo-subscribe-publish-get-demos.ts`.
77
-
78
- <sonic-code language="typescript">
79
- <template>
80
- @get(new Endpoint<User>("users/${userId}"))
81
- @state()
82
- payload: ApiResult<User> | null = null;
83
- </template>
84
- </sonic-code>
85
-
86
- ## Live demos
87
-
88
- `@get` with **`triggerKey`** — refresh button + `X-Fetched-At` timestamp in the UI:
113
+ ## Demos
89
114
 
90
115
  <sonic-code>
91
116
  <template>
92
117
  <docs-demo-sources for="demo-api-get"></docs-demo-sources>
93
118
  <demo-api-get></demo-api-get>
94
- </template>
95
- </sonic-code>
96
-
97
- Dynamic config and endpoint path. Manual refetch is triggered **from a separate component** (same `triggerKey` publisher):
98
-
99
- <sonic-code>
100
- <template>
101
119
  <docs-demo-sources for="demo-api-get-configuration-key"></docs-demo-sources>
102
120
  <demo-api-get-configuration-key></demo-api-get-configuration-key>
103
- <demo-api-get-refresh-remote></demo-api-get-refresh-remote>
104
- </template>
105
- </sonic-code>
106
-
107
- Scoped `@get` with `@publish` / `@subscribe` on the payload (see [@publish](#docs/_decorators/publish.md/publish) and [@subscribe](#docs/_decorators/subscribe.md/subscribe)) — wrap under an ancestor with `serviceURL="/docs-mock-api/geo/"`:
108
-
109
- <sonic-code>
110
- <template>
111
- <div serviceURL="/docs-mock-api/geo/">
112
- <docs-demo-sources for="demo-api-get-publish-subscribe"></docs-demo-sources>
113
- <demo-api-get-publish-subscribe></demo-api-get-publish-subscribe>
114
- </div>
115
121
  </template>
116
122
  </sonic-code>
117
123
 
118
- Stale responses are ignored if the path or generation changed before the request finished.
124
+ See [@post](#docs/_decorators/post.md/post),
125
+ [@put](#docs/_decorators/put.md/put), and
126
+ [@patch](#docs/_decorators/patch.md/patch) for write operations.
119
127
 
120
- ## See also
128
+ ## Advanced
121
129
 
122
- - [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path)
123
- - [@post](#docs/_decorators/post.md/post) · [@put](#docs/_decorators/put.md/put) · [@patch](#docs/_decorators/patch.md/patch) — send decorators (same path rules)
130
+ External invalidation is currently available through `triggerKey`; it is kept
131
+ out of the main usage examples.
@@ -1,45 +1,61 @@
1
1
  # @patch
2
2
 
3
- Sends data through [`API.patchDetailed`](../../core/utils/api.ts). Same model as [@post](#docs/_decorators/post.md/post): decorated property is **`ApiResult<T> | null`** (`request`, `response`, `result`).
3
+ `@patch` applies a partial update with the body from a publisher. It uses the
4
+ same model as [@post](#docs/_decorators/post.md/post):
5
+ `Endpoint<T>`, `DataProviderKey<B>`, `ApiResult<T>`, options, and the
6
+ `send(component)` handle.
4
7
 
5
- Pass an [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint) and a `DataProviderKey` for the **request body**. Import `patch` and `ApiResult` from `@supersoniks/concorde/decorators`.
8
+ ## Minimal usage
6
9
 
7
- ## Configuration
10
+ ```typescript
11
+ const bodyKey = new DataProviderKey<Partial<User>>("users.patch");
12
+ const patchUser = patch(new Endpoint<User>("users/42"), bodyKey);
8
13
 
9
- Same as [@post](#docs/_decorators/post.md/post) / [@get](#docs/_decorators/get.md/get): scoped `HTML.getApiConfiguration(host)` or `DataProviderKey<APIConfiguration>` as third argument.
14
+ @patchUser
15
+ @state()
16
+ payload?: ApiResult<User>;
17
+ ```
18
+
19
+ To run the operation again from the component:
20
+
21
+ ```typescript
22
+ async savePatch() {
23
+ await patchUser.send(this);
24
+ }
25
+ ```
26
+
27
+ `send(component)` returns a Promise resolved after the PATCH completes. See
28
+ [@post](#docs/_decorators/post.md/post) for the method-decorator form and the
29
+ `when: "before"` option.
10
30
 
11
- ## Options (`PatchOptions`)
31
+ The PATCH is also sent automatically when the body mutates, unless
32
+ `autoPostOnBodyMutation: false` is set. The available options are described in
33
+ [@post](#docs/_decorators/post.md/post):
12
34
 
13
- Same shape as `PostOptions` on [@post](#docs/_decorators/post.md/post) (`ApiSendOptions`): `refetchEveryMs`, `skipIfBodyMissing`, `autoPostOnBodyMutation`, `triggerKey`, `skipEmptyPlaceholder`. See [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path) for `${sessionId}` and empty-string behaviour.
35
+ - `autoPostOnBodyMutation`
36
+ - `skipIfBodyMissing`
37
+ - `refetchEveryMs`
38
+ - `skipEmptyPlaceholder`
39
+ - `triggerKey`
40
+
41
+ Pass explicit API configuration as the third argument:
42
+
43
+ ```typescript
44
+ @patch(endpoint, bodyKey, apiConfigurationKey)
45
+ ```
14
46
 
15
47
  ## Import
16
48
 
17
49
  <sonic-code language="typescript">
18
50
  <template>
19
51
  import { patch, type ApiResult } from "@supersoniks/concorde/decorators";
20
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
21
52
  import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
22
- </template>
23
- </sonic-code>
24
-
25
- ## Example
26
-
27
- <sonic-code language="typescript">
28
- <template>
29
- const patchBodyKey = new DataProviderKey&lt;Partial&lt;Resource&gt;&gt;("resourcePatch");
30
-
31
- @patch(
32
- new Endpoint&lt;Resource, { resourceId: string }&gt;("resources/${resourceId}"),
33
- patchBodyKey,
34
- { skipEmptyPlaceholder: true },
35
- )
36
- @state()
37
- payload?: ApiResult&lt;Resource&gt; | null;
53
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
38
54
  </template>
39
55
  </sonic-code>
40
56
 
41
57
  ## See also
42
58
 
43
- - [@post](#docs/_decorators/post.md/post) — POST (live demos)
44
- - [@put](#docs/_decorators/put.md/put) — full replacement (PUT)
59
+ - [@post](#docs/_decorators/post.md/post) — options and triggers
60
+ - [@put](#docs/_decorators/put.md/put) — full replacement
45
61
  - [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path)
@@ -1,93 +1,135 @@
1
1
  # @post
2
2
 
3
- Sends data through [`API.postDetailed`](../../core/utils/api.ts). The decorated property is **`ApiResult<T> | null`**: `request`, `response`, and typed `result`.
3
+ `@post` sends the contents of a publisher and stores the response in an
4
+ optional `ApiResult<T>` property. The property is `undefined` until a result
5
+ is available.
4
6
 
5
- Pass an [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint) as the first argument and a `DataProviderKey` for the **request body** as the second. Import `post` and `ApiResult` from `@supersoniks/concorde/decorators`, and `Endpoint` from `@supersoniks/concorde/utils/endpoint`.
7
+ ## Minimal usage
6
8
 
7
- ## Configuration
9
+ Pass an `Endpoint<T>` and a `DataProviderKey<B>` for the request body.
8
10
 
9
- Same as [@get](#docs/_decorators/get.md/get): scoped `HTML.getApiConfiguration(host)` by default, or `DataProviderKey<APIConfiguration>` as third argument. See [API configuration](#docs/_misc/api-configuration.md/api-configuration) for mock demos.
11
+ ```typescript
12
+ const userBodyKey = new DataProviderKey<CreateUser>("users.form");
13
+ const createUser = post(new Endpoint<User>("users"), userBodyKey);
10
14
 
11
- ## Optional `PostOptions` (third or fourth argument)
15
+ @createUser
16
+ @state()
17
+ payload?: ApiResult<User>;
18
+ ```
12
19
 
13
- | Option | Description |
14
- |--------|-------------|
15
- | `refetchEveryMs` | Re-post on an interval (ms). |
16
- | `skipIfBodyMissing` | Skip when body publisher is `null`/`undefined` (default: `true`). |
17
- | `autoPostOnBodyMutation` | Re-post when the body publisher mutates (default: `true`). `false` = manual via `triggerKey.invalidate()`. |
18
- | `skipEmptyPlaceholder` | If `true`, a placeholder resolved to `''` blocks the request (empty string only — not `0` or `false`). See [Dynamic paths](#docs/_misc/dynamic-path.md/dynamic-path). |
19
- | `triggerKey` | `DataProviderKey` — `invalidate()` re-runs the POST with the current body. |
20
+ The current body is read from `userBodyKey`. By default, the POST is sent when
21
+ the component connects and after each body mutation. Mutations in the same
22
+ frame are coalesced into one request.
20
23
 
21
- ## When the POST runs again
24
+ API configuration is read from the HTML scope, as with
25
+ [@get](#docs/_decorators/get.md/get).
22
26
 
23
- - Body publisher `onInternalMutation` when `autoPostOnBodyMutation` is `true` (default). Plusieurs mutations synchrones dans la même frame sont regroupées en **un seul POST** via `requestAnimationFrame`.
24
- - Endpoint path dependency changes (`${sessionId}` on the host).
25
- - Configuration publisher mutation.
26
- - `triggerKey` publisher `invalidate()`.
27
- - `refetchEveryMs` timer (if set).
27
+ ## Sending the POST again
28
28
 
29
- ## Import
29
+ ### From the component
30
30
 
31
- <sonic-code language="typescript">
32
- <template>
33
- import { post, publish, type ApiResult } from "@supersoniks/concorde/decorators";
34
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
35
- import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
36
- </template>
37
- </sonic-code>
31
+ Keep the decorator to access `send(component)`. The body is read again when the
32
+ operation runs.
33
+
34
+ ```typescript
35
+ async saveAgain() {
36
+ const payload = await createUser.send(this);
37
+ console.log(payload?.result);
38
+ }
39
+ ```
40
+
41
+ `send()` returns a `Promise<ApiResult<T> | undefined>` that resolves after the
42
+ operation completes. It is useful for “Save” or “Retry” buttons and can repeat
43
+ an operation with side effects.
44
+
45
+ ### From a method decorator
46
+
47
+ The send action can decorate a local method. It runs after the method by
48
+ default, waits for an eventual Promise to resolve, and the decorated method
49
+ call waits for the send to complete:
50
+
51
+ ```typescript
52
+ import { send } from "@supersoniks/concorde/decorators";
53
+
54
+ @send(createUser)
55
+ async save() {
56
+ // Prepare local state or validate the form.
57
+ }
58
+ ```
59
+
60
+ Use `{ when: "before" }` when the send must complete before the method runs:
61
+
62
+ ```typescript
63
+ @send(createUser, { when: "before" })
64
+ saveBefore() {
65
+ // The POST has completed before this method runs.
66
+ }
67
+ ```
68
+
69
+ The method decorator adds an explicit send. If the method also mutates the body
70
+ publisher, set `autoPostOnBodyMutation: false` when the decorated method must
71
+ be the only trigger.
72
+
73
+ ## Options (`PostOptions`)
74
+
75
+ Options are the third argument, or the fourth argument when a configuration key
76
+ is provided.
77
+
78
+ - `autoPostOnBodyMutation`: send after a body mutation (default: `true`). Set
79
+ it to `false` to use `send()`.
80
+ - `skipIfBodyMissing`: skip when the body is `null` or `undefined` (default:
81
+ `true`).
82
+ - `refetchEveryMs`: repeat the POST at this interval. Use it only when
83
+ repeating the operation is intended.
84
+ - `skipEmptyPlaceholder`: block the request when a `${...}` placeholder is
85
+ `""`.
86
+ - `triggerKey`: a publisher whose `invalidate()` sends the POST again.
87
+
88
+ With a configuration key:
38
89
 
39
- ## Minimal example
90
+ ```typescript
91
+ @post(endpoint, userBodyKey, apiConfigurationKey)
92
+ ```
40
93
 
41
- Mock service: `POST /docs-mock-api/api/register` (same route as [`sonic-submit`](#core/components/functional/submit/submit.md/submit) demos). Publisher setup lives in `decorators-demo-post.ts`.
94
+ See [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path) for
95
+ dynamic path details.
96
+
97
+ ## When the POST is sent
98
+
99
+ - when the component connects and the body and configuration are available;
100
+ - after a body mutation, unless `autoPostOnBodyMutation: false`;
101
+ - when a property used in `${...}` changes;
102
+ - when a configuration publisher changes;
103
+ - when the `triggerKey` publisher is invalidated;
104
+ - when `send()` is called;
105
+ - after each response when `refetchEveryMs` is set.
106
+
107
+ ## Import
42
108
 
43
109
  <sonic-code language="typescript">
44
110
  <template>
45
- const syncRequest = new DataProviderKey&lt;SyncRequest&gt;("syncRequest");
46
- const syncTrigger = new DataProviderKey&lt;number&gt;("syncTrigger");
47
-
48
- @post(
49
- new Endpoint&lt;SyncResponse, { sessionId: string }&gt;("sessions/${sessionId}/sync"),
50
- syncRequest,
51
- { triggerKey: syncTrigger },
52
- )
53
- @state()
54
- payload?: ApiResult&lt;SyncResponse&gt; | null;
111
+ import { post, type ApiResult } from "@supersoniks/concorde/decorators";
112
+ import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
113
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
55
114
  </template>
56
115
  </sonic-code>
57
116
 
58
- ## Live demos
117
+ ## Demos
59
118
 
60
119
  <sonic-code>
61
120
  <template>
62
121
  <docs-demo-sources for="demo-api-post"></docs-demo-sources>
63
122
  <demo-api-post></demo-api-post>
64
- </template>
65
- </sonic-code>
66
-
67
- Dynamic endpoint path — changing `sessionId` on the host re-runs the POST (`POST /docs-mock-api/api/sessions/{id}/sync`):
68
-
69
- <sonic-code>
70
- <template>
71
123
  <docs-demo-sources for="demo-api-post-dynamic"></docs-demo-sources>
72
124
  <demo-api-post-dynamic></demo-api-post-dynamic>
73
125
  </template>
74
126
  </sonic-code>
75
127
 
76
- `@post` + `@publish` on the same property (see [@publish](#docs/_decorators/publish.md/publish)):
77
-
78
- <sonic-code>
79
- <template>
80
- <docs-demo-sources for="demo-api-post-publish"></docs-demo-sources>
81
- <demo-api-post-publish></demo-api-post-publish>
82
- </template>
83
- </sonic-code>
84
-
85
- Stale responses are ignored if the path or generation changed before the request finished.
86
-
87
- **Note:** plusieurs composants `@post` sur la même page qui partagent le même `bodyKey` enverront chacun une requête à chaque mutation du body — utiliser une clé par composant (voir les deux démos live ci-dessus).
88
-
89
- Path placeholders (`${sessionId}`, …): [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path).
128
+ See [@put](#docs/_decorators/put.md/put) and
129
+ [@patch](#docs/_decorators/patch.md/patch): they use the same model with a
130
+ different HTTP method.
90
131
 
91
- ## See also
132
+ ## Advanced
92
133
 
93
- - [@put](#docs/_decorators/put.md/put) · [@patch](#docs/_decorators/patch.md/patch) — same decorator model, `PUT` / `PATCH` via `putDetailed` / `patchDetailed`
134
+ External invalidation is currently available through `triggerKey`; it is kept
135
+ out of the main usage examples.
@@ -1,43 +1,61 @@
1
1
  # @put
2
2
 
3
- Sends data through [`API.putDetailed`](../../core/utils/api.ts). Same model as [@post](#docs/_decorators/post.md/post): decorated property is **`ApiResult<T> | null`** (`request`, `response`, `result`).
3
+ `@put` replaces a resource with the body from a publisher. It uses exactly the
4
+ same model as [@post](#docs/_decorators/post.md/post):
5
+ `Endpoint<T>`, `DataProviderKey<B>`, `ApiResult<T>`, options, and the
6
+ `send(component)` handle.
4
7
 
5
- Pass an [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint) and a `DataProviderKey` for the **request body**. Import `put` and `ApiResult` from `@supersoniks/concorde/decorators`.
8
+ ## Minimal usage
6
9
 
7
- ## Configuration
10
+ ```typescript
11
+ const bodyKey = new DataProviderKey<UpdateUser>("users.form");
12
+ const updateUser = put(new Endpoint<User>("users/42"), bodyKey);
8
13
 
9
- Same as [@post](#docs/_decorators/post.md/post) / [@get](#docs/_decorators/get.md/get): scoped `HTML.getApiConfiguration(host)` or `DataProviderKey<APIConfiguration>` as third argument.
14
+ @updateUser
15
+ @state()
16
+ payload?: ApiResult<User>;
17
+ ```
18
+
19
+ To run the operation again from the component:
20
+
21
+ ```typescript
22
+ async update() {
23
+ await updateUser.send(this);
24
+ }
25
+ ```
26
+
27
+ `send(component)` returns a Promise resolved after the PUT completes. See
28
+ [@post](#docs/_decorators/post.md/post) for the method-decorator form and the
29
+ `when: "before"` option.
30
+
31
+ The PUT is also sent automatically when the body mutates, unless
32
+ `autoPostOnBodyMutation: false` is set. See
33
+ [@post](#docs/_decorators/post.md/post) for the option details:
10
34
 
11
- ## Options (`PutOptions`)
35
+ - `autoPostOnBodyMutation`
36
+ - `skipIfBodyMissing`
37
+ - `refetchEveryMs`
38
+ - `skipEmptyPlaceholder`
39
+ - `triggerKey`
12
40
 
13
- Same shape as `PostOptions` on [@post](#docs/_decorators/post.md/post) (`ApiSendOptions`): `refetchEveryMs`, `skipIfBodyMissing`, `autoPostOnBodyMutation`, `triggerKey`, `skipEmptyPlaceholder`. See [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path) for `${sessionId}` and empty-string behaviour.
41
+ Pass explicit API configuration as the third argument:
42
+
43
+ ```typescript
44
+ @put(endpoint, bodyKey, apiConfigurationKey)
45
+ ```
14
46
 
15
47
  ## Import
16
48
 
17
49
  <sonic-code language="typescript">
18
50
  <template>
19
51
  import { put, type ApiResult } from "@supersoniks/concorde/decorators";
20
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
21
52
  import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
53
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
22
54
  </template>
23
55
  </sonic-code>
24
56
 
25
- ## Example
26
-
27
- <sonic-code language="typescript">
28
- <template>
29
- const bodyKey = new DataProviderKey&lt;UpdatePayload&gt;("resourceBody");
30
-
31
- @put(new Endpoint&lt;Resource, { resourceId: string }&gt;("resources/${resourceId}"), bodyKey)
32
- @state()
33
- payload?: ApiResult&lt;Resource&gt; | null;
34
- </template>
35
- </sonic-code>
36
-
37
- Changing `resourceId` on the host re-runs the PUT when the path becomes ready — see [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path).
38
-
39
57
  ## See also
40
58
 
41
- - [@post](#docs/_decorators/post.md/post) — POST (live demos, polling, `@publish`)
42
- - [@patch](#docs/_decorators/patch.md/patch) — partial update (PATCH)
43
- - [Endpoint](#docs/_misc/endpoint.md/endpoint) · [API configuration](#docs/_misc/api-configuration.md/api-configuration)
59
+ - [@post](#docs/_decorators/post.md/post) — options and triggers
60
+ - [@patch](#docs/_decorators/patch.md/patch) — partial update
61
+ - [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path)