@supersoniks/concorde 4.9.9 → 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 (48) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +241 -241
  3. package/concorde-core.es.js +2908 -2845
  4. package/dist/concorde-core.bundle.js +241 -241
  5. package/dist/concorde-core.es.js +2908 -2845
  6. package/dist/js/core/decorators/api.js +92 -2
  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 +82 -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-BL6WVF7g.css +1 -0
  15. package/docs/assets/{index-hElUgV9_.js → index-DVn8AeyA.js} +572 -555
  16. package/docs/crawl/docs/_decorators/get.html +64 -81
  17. package/docs/crawl/docs/_decorators/patch.html +35 -23
  18. package/docs/crawl/docs/_decorators/post.html +72 -72
  19. package/docs/crawl/docs/_decorators/put.html +36 -21
  20. package/docs/crawl/docs/_getting-started/ai-agents.html +45 -6
  21. package/docs/crawl/hubs/decorators.html +141 -69
  22. package/docs/crawl/hubs/remote-data.html +141 -69
  23. package/docs/index.html +2 -2
  24. package/docs/llms-full.txt +203 -149
  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 +55 -81
  29. package/docs/src/docs/_decorators/patch.md +36 -25
  30. package/docs/src/docs/_decorators/post.md +71 -62
  31. package/docs/src/docs/_decorators/put.md +37 -24
  32. package/docs/src/docs/_getting-started/ai-agents.md +24 -4
  33. package/docs/src/docs/search/docs-search.json +151 -1
  34. package/docs/src/tsconfig.json +3 -0
  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 +100 -1
  38. package/src/core/decorators/api.ts +252 -138
  39. package/src/decorators.ts +7 -0
  40. package/src/docs/_decorators/get.md +81 -80
  41. package/src/docs/_decorators/patch.md +36 -25
  42. package/src/docs/_decorators/post.md +99 -62
  43. package/src/docs/_decorators/put.md +37 -24
  44. package/src/docs/components/docs-demo-sources.ts +1 -6
  45. package/src/docs/example/decorators-demo-geo.ts +0 -21
  46. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +41 -132
  47. package/src/docs/search/docs-search.json +128 -133
  48. package/docs/assets/index-Bnp7gVaA.css +0 -1
@@ -1,123 +1,97 @@
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 `ApiResult<T> | null` property.
4
4
 
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`.
5
+ - `payload.result`: typed data;
6
+ - `payload.response`: the HTTP response;
7
+ - `payload.request`: the request that was sent.
6
8
 
7
- ## Configuration
9
+ ## Minimal usage
8
10
 
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.
11
-
12
- ## Dynamic path
13
-
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).
11
+ ```typescript
12
+ const usersEndpoint = new Endpoint<User[]>("users");
15
13
 
16
- ## Options (`GetOptions`)
14
+ @get(usersEndpoint)
15
+ @state()
16
+ payload: ApiResult<User[]> | null = null;
17
+ ```
17
18
 
18
- Pass as the **second** argument (scoped config) or **third** (with a configuration key). Same shape as send decorators where applicable:
19
+ The first argument is always an
20
+ [`Endpoint<T>`](#docs/_misc/endpoint.md/endpoint). API configuration is read
21
+ from the HTML scope (`serviceURL`, token, etc.), so the component is usually
22
+ placed below an element that provides this configuration.
19
23
 
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. |
24
+ ## Refetching a GET
25
25
 
26
- ### Manual refetch (`triggerKey`)
26
+ ### From the component
27
27
 
28
- Same pattern as [@post](#docs/_decorators/post.md/post): a publisher acts as a **signal**, independent of the response payload.
28
+ Keep the decorator in a constant to access `refetch(component)`. Refetch only
29
+ targets the instance passed as the argument, even before it has received a
30
+ result.
29
31
 
30
32
  ```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
- })
33
+ const usersGet = get(new Endpoint<User[]>("users"));
34
+
35
+ @usersGet
46
36
  @state()
47
- payload: ApiResult<GeoCommuneRow[]> | null = null;
37
+ payload: ApiResult<User[]> | null = null;
48
38
 
49
- // Same component or anywhere else:
50
- dp(geoCommunesRefreshKey).invalidate();
39
+ refresh() {
40
+ usersGet.refetch(this);
41
+ }
51
42
  ```
52
43
 
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.
44
+ ## Options (`GetOptions`)
45
+
46
+ Options are the second argument, or the third argument when an API
47
+ configuration key is provided.
48
+
49
+ - `skipEmptyPlaceholder`: blocks the GET when `${prop}` is `""`.
50
+ - `refetchEveryMs`: automatically runs the GET again after this interval
51
+ (milliseconds). Omit the option, or use `0`, to disable polling.
54
52
 
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")`).
53
+ With a configuration key, use:
54
+
55
+ ```typescript
56
+ @get(usersEndpoint, apiConfigurationKey)
57
+ ```
56
58
 
57
59
  ## When the GET runs again
58
60
 
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).
61
+ - when the component connects and configuration is available;
62
+ - when a property used in `${...}` changes;
63
+ - when a configuration publisher changes;
64
+ - after each response when `refetchEveryMs` is set.
65
+
66
+ See [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path) for
67
+ dynamic path details.
63
68
 
64
69
  ## Import
65
70
 
66
71
  <sonic-code language="typescript">
67
72
  <template>
68
73
  import { get, type ApiResult } from "@supersoniks/concorde/decorators";
69
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
70
74
  import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
75
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
71
76
  </template>
72
77
  </sonic-code>
73
78
 
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:
79
+ ## Demos
89
80
 
90
81
  <sonic-code>
91
82
  <template>
92
83
  <docs-demo-sources for="demo-api-get"></docs-demo-sources>
93
84
  <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
85
  <docs-demo-sources for="demo-api-get-configuration-key"></docs-demo-sources>
102
86
  <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
87
  </template>
116
88
  </sonic-code>
117
89
 
118
- Stale responses are ignored if the path or generation changed before the request finished.
90
+ See [@post](#docs/_decorators/post.md/post),
91
+ [@put](#docs/_decorators/put.md/put), and
92
+ [@patch](#docs/_decorators/patch.md/patch) for write operations.
119
93
 
120
- ## See also
94
+ ## Advanced
121
95
 
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)
96
+ External invalidation is currently available through `triggerKey`; it is kept
97
+ out of the main usage examples.
@@ -1,45 +1,56 @@
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> | null = null;
17
+ ```
18
+
19
+ To run the operation again from the component:
20
+
21
+ ```typescript
22
+ savePatch() {
23
+ patchUser.send(this);
24
+ }
25
+ ```
26
+
27
+ The PATCH is also sent automatically when the body mutates, unless
28
+ `autoPostOnBodyMutation: false` is set. The available options are described in
29
+ [@post](#docs/_decorators/post.md/post):
10
30
 
11
- ## Options (`PatchOptions`)
31
+ - `autoPostOnBodyMutation`
32
+ - `skipIfBodyMissing`
33
+ - `refetchEveryMs`
34
+ - `skipEmptyPlaceholder`
12
35
 
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.
36
+ Pass explicit API configuration as the third argument:
37
+
38
+ ```typescript
39
+ @patch(endpoint, bodyKey, apiConfigurationKey)
40
+ ```
14
41
 
15
42
  ## Import
16
43
 
17
44
  <sonic-code language="typescript">
18
45
  <template>
19
46
  import { patch, type ApiResult } from "@supersoniks/concorde/decorators";
20
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
21
47
  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;
48
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
38
49
  </template>
39
50
  </sonic-code>
40
51
 
41
52
  ## See also
42
53
 
43
- - [@post](#docs/_decorators/post.md/post) — POST (live demos)
44
- - [@put](#docs/_decorators/put.md/put) — full replacement (PUT)
54
+ - [@post](#docs/_decorators/post.md/post) — options and triggers
55
+ - [@put](#docs/_decorators/put.md/put) — full replacement
45
56
  - [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path)
@@ -1,93 +1,102 @@
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
+ `ApiResult<T> | null` property.
4
5
 
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`.
6
+ ## Minimal usage
6
7
 
7
- ## Configuration
8
+ Pass an `Endpoint<T>` and a `DataProviderKey<B>` for the request body.
8
9
 
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.
10
+ ```typescript
11
+ const userBodyKey = new DataProviderKey<CreateUser>("users.form");
12
+ const createUser = post(new Endpoint<User>("users"), userBodyKey);
10
13
 
11
- ## Optional `PostOptions` (third or fourth argument)
14
+ @createUser
15
+ @state()
16
+ payload: ApiResult<User> | null = null;
17
+ ```
12
18
 
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. |
19
+ The current body is read from `userBodyKey`. By default, the POST is sent when
20
+ the component connects and after each body mutation. Mutations in the same
21
+ frame are coalesced into one request.
20
22
 
21
- ## When the POST runs again
23
+ API configuration is read from the HTML scope, as with
24
+ [@get](#docs/_decorators/get.md/get).
22
25
 
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).
26
+ ## Sending the POST again
28
27
 
29
- ## Import
28
+ ### From the component
30
29
 
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>
30
+ Keep the decorator to access `send(component)`. The body is read again when the
31
+ operation runs.
32
+
33
+ ```typescript
34
+ saveAgain() {
35
+ createUser.send(this);
36
+ }
37
+ ```
38
38
 
39
- ## Minimal example
39
+ `send()` is useful for “Save” or “Retry” buttons. It can repeat an operation
40
+ with side effects.
40
41
 
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`.
42
+ ## Options (`PostOptions`)
43
+
44
+ Options are the third argument, or the fourth argument when a configuration key
45
+ is provided.
46
+
47
+ - `autoPostOnBodyMutation`: send after a body mutation (default: `true`). Set
48
+ it to `false` to use `send()`.
49
+ - `skipIfBodyMissing`: skip when the body is `null` or `undefined` (default:
50
+ `true`).
51
+ - `refetchEveryMs`: repeat the POST at this interval. Use it only when
52
+ repeating the operation is intended.
53
+ - `skipEmptyPlaceholder`: block the request when a `${...}` placeholder is
54
+ `""`.
55
+
56
+ With a configuration key:
57
+
58
+ ```typescript
59
+ @post(endpoint, userBodyKey, apiConfigurationKey)
60
+ ```
61
+
62
+ See [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path) for
63
+ dynamic path details.
64
+
65
+ ## When the POST is sent
66
+
67
+ - when the component connects and the body and configuration are available;
68
+ - after a body mutation, unless `autoPostOnBodyMutation: false`;
69
+ - when a property used in `${...}` changes;
70
+ - when a configuration publisher changes;
71
+ - when `send()` is called;
72
+ - after each response when `refetchEveryMs` is set.
73
+
74
+ ## Import
42
75
 
43
76
  <sonic-code language="typescript">
44
77
  <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;
78
+ import { post, type ApiResult } from "@supersoniks/concorde/decorators";
79
+ import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
80
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
55
81
  </template>
56
82
  </sonic-code>
57
83
 
58
- ## Live demos
84
+ ## Demos
59
85
 
60
86
  <sonic-code>
61
87
  <template>
62
88
  <docs-demo-sources for="demo-api-post"></docs-demo-sources>
63
89
  <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
90
  <docs-demo-sources for="demo-api-post-dynamic"></docs-demo-sources>
72
91
  <demo-api-post-dynamic></demo-api-post-dynamic>
73
92
  </template>
74
93
  </sonic-code>
75
94
 
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).
95
+ See [@put](#docs/_decorators/put.md/put) and
96
+ [@patch](#docs/_decorators/patch.md/patch): they use the same model with a
97
+ different HTTP method.
90
98
 
91
- ## See also
99
+ ## Advanced
92
100
 
93
- - [@put](#docs/_decorators/put.md/put) · [@patch](#docs/_decorators/patch.md/patch) — same decorator model, `PUT` / `PATCH` via `putDetailed` / `patchDetailed`
101
+ External invalidation is currently available through `triggerKey`; it is kept
102
+ out of the main usage examples.
@@ -1,43 +1,56 @@
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> | null = null;
17
+ ```
18
+
19
+ To run the operation again from the component:
20
+
21
+ ```typescript
22
+ update() {
23
+ updateUser.send(this);
24
+ }
25
+ ```
26
+
27
+ The PUT is also sent automatically when the body mutates, unless
28
+ `autoPostOnBodyMutation: false` is set. See
29
+ [@post](#docs/_decorators/post.md/post) for the option details:
10
30
 
11
- ## Options (`PutOptions`)
31
+ - `autoPostOnBodyMutation`
32
+ - `skipIfBodyMissing`
33
+ - `refetchEveryMs`
34
+ - `skipEmptyPlaceholder`
12
35
 
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.
36
+ Pass explicit API configuration as the third argument:
37
+
38
+ ```typescript
39
+ @put(endpoint, bodyKey, apiConfigurationKey)
40
+ ```
14
41
 
15
42
  ## Import
16
43
 
17
44
  <sonic-code language="typescript">
18
45
  <template>
19
46
  import { put, type ApiResult } from "@supersoniks/concorde/decorators";
20
- import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
21
47
  import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
48
+ import { Endpoint } from "@supersoniks/concorde/utils/endpoint";
22
49
  </template>
23
50
  </sonic-code>
24
51
 
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
52
  ## See also
40
53
 
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)
54
+ - [@post](#docs/_decorators/post.md/post) — options and triggers
55
+ - [@patch](#docs/_decorators/patch.md/patch) — partial update
56
+ - [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path)
@@ -26,16 +26,36 @@ node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
26
26
 
27
27
  | Flag | Effect |
28
28
  |------|--------|
29
- | `--merge-agents` | Append to an existing `AGENTS.md` instead of replacing it |
30
- | `--overlay <dir>` | Copy extra rules/skills from another layer (e.g. starter kit) |
29
+ | `--skip-agents` | Never write `AGENTS.md` (skills / rules only) |
30
+ | `--merge-agents` | Opt-in: keep the project preamble and append / refresh the Concorde block |
31
+ | `--force-agents` | Opt-in: **replace** the whole `AGENTS.md` (destructive) |
32
+ | `--overlay <dir>` | Extra rules/skills + optional `AGENTS.concorde.md` for project-only Concorde agent notes |
31
33
  | `--cursor-only` | Install only `.cursor/skills` and `.cursor/rules` |
32
34
  | `--jetbrains-only` | Install only `.aiassistant/rules/` |
33
35
 
36
+ ## `AGENTS.md` policy (non-invasive)
37
+
38
+ | Situation | Default |
39
+ |-----------|---------|
40
+ | No `AGENTS.md` | Create the Concorde guide |
41
+ | File with `<!-- concorde-ai -->` | Refresh the managed zone only |
42
+ | File **without** marker (project notes) | **Left untouched** — skills / rules are enough |
43
+ | `--merge-agents` / `--force-agents` / `--skip-agents` | See flags above |
44
+
45
+ ```text
46
+ [optional project preamble — short, project-only]
47
+ <!-- concorde-ai -->
48
+ <package ai/AGENTS.md>
49
+ [--- + overlay AGENTS.concorde.md]
50
+ ```
51
+
52
+ Everything **after** `<!-- concorde-ai -->` is replaced on each `ai-init` run (idempotent). Do not paste a full copy of the Concorde guide above the marker — put project-specific notes in `AGENTS.concorde.md` (overlay). If the preamble duplicates package `AGENTS.md`, `ai-init` slims or drops it and prints a warning. Legacy filenames `AGENTS.overlay.md` / `AGENTS.starter.md` are still accepted with a deprecation warning.
53
+
34
54
  ## What gets installed
35
55
 
36
56
  | Path | Role |
37
57
  |------|------|
38
- | `AGENTS.md` | Project-level guide for agents (Concorde conventions) |
58
+ | `AGENTS.md` | Created only if missing; existing project-owned files are left alone unless `--merge-agents` / `--force-agents` |
39
59
  | `.cursor/skills/concorde/` | Core Lit + DataProvider patterns |
40
60
  | `.cursor/skills/concorde-imports/` | Short `@supersoniks/concorde/…` import paths |
41
61
  | `.cursor/skills/concorde-scope/` | `serviceURL`, `formDataProvider`, API configuration |
@@ -49,7 +69,7 @@ node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
49
69
 
50
70
  1. **Starter project:** [Installation](#docs/_getting-started/concorde-outside.md/concorde-outside) — `yarn ai:sync` is wired in the kit.
51
71
  2. **Existing / manual Vite project:** [Manual installation](#docs/_getting-started/concorde-manual-install.md/concorde-manual-install), then **`ai-init`** after `yarn add @supersoniks/concorde`.
52
- 3. Commit `AGENTS.md`, `.cursor/`, and `.aiassistant/` if your team shares agent settings.
72
+ 3. Commit `.cursor/` and `.aiassistant/` (and `AGENTS.md` only if you opted in / it was created) if your team shares agent settings.
53
73
  4. Re-run the same command when you bump `@supersoniks/concorde` to refresh skills from `node_modules/@supersoniks/concorde/ai/`.
54
74
  5. In Cursor, skills under `.cursor/skills/` are picked up automatically; mention a skill in chat for focused tasks (e.g. migration → `concorde-get-set-dp`).
55
75