@supersoniks/concorde 4.7.3 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/ai/AGENTS.md +4 -0
- package/ai/cursor/rules/concorde.mdc +11 -1
- package/ai/jetbrains/rules/concorde.md +8 -0
- package/ai/skills/concorde/SKILL.md +29 -2
- package/ai/skills/concorde-scope/SKILL.md +2 -2
- package/build-infos.json +1 -1
- package/concorde-core.bundle.js +289 -289
- package/concorde-core.es.js +4839 -4546
- package/dist/concorde-core.bundle.js +289 -289
- package/dist/concorde-core.es.js +4839 -4546
- package/dist/docs-mock-api-sw.js +19 -0
- package/dist/docs-mock-api-sw.js.map +2 -2
- package/dist/robots.txt +2 -0
- package/docs/assets/index-wyNMyWT9.js +11196 -0
- package/docs/docs-mock-api-sw.js +19 -0
- package/docs/docs-mock-api-sw.js.map +2 -2
- package/docs/index.html +1 -1
- package/docs/robots.txt +2 -0
- package/package.json +9 -1
- package/public/docs-mock-api-sw.js +19 -0
- package/public/docs-mock-api-sw.js.map +2 -2
- package/public/robots.txt +2 -0
- package/src/core/components/functional/example/example.ts +3 -3
- package/src/core/components/ui/captcha/captcha.md +0 -12
- package/src/core/components/ui/icon/icon.ts +17 -2
- package/src/core/components/ui/menu/menu.ts +12 -3
- package/src/core/decorators/api.post.spec.ts +293 -0
- package/src/core/decorators/api.spec.ts +7 -14
- package/src/core/decorators/api.ts +648 -15
- package/src/core/decorators/subscriber/bind.ts +13 -5
- package/src/core/decorators/subscriber/dynamicPath.spec.ts +53 -0
- package/src/core/decorators/subscriber/dynamicPath.ts +23 -1
- package/src/core/decorators/subscriber/handle.ts +3 -1
- package/src/core/decorators/subscriber/onAssign.ts +10 -2
- package/src/core/decorators/subscriber/publish.ts +12 -2
- package/src/core/utils/PublisherProxy.ts +95 -11
- package/src/core/utils/api.ts +72 -3
- package/src/core/utils/dpOptions.spec.ts +56 -0
- package/src/core/utils/endpoint.ts +3 -3
- package/src/decorators.ts +17 -1
- package/src/docs/_core-concept/dataFlow.md +9 -3
- package/src/docs/_decorators/bind.md +2 -2
- package/src/docs/_decorators/get.md +13 -4
- package/src/docs/_decorators/handle.md +5 -1
- package/src/docs/_decorators/on-assign.md +2 -0
- package/src/docs/_decorators/patch.md +45 -0
- package/src/docs/_decorators/post.md +93 -0
- package/src/docs/_decorators/publish.md +1 -1
- package/src/docs/_decorators/put.md +43 -0
- package/src/docs/_decorators/subscribe.md +4 -1
- package/src/docs/_directives/sub.md +1 -1
- package/src/docs/_getting-started/my-first-component.md +1 -1
- package/src/docs/_misc/api-configuration.md +3 -1
- package/src/docs/_misc/dataProviderKey.md +2 -2
- package/src/docs/_misc/dynamic-path.md +71 -0
- package/src/docs/_misc/endpoint.md +5 -3
- package/src/docs/components/docs-demo-sources.ts +102 -3
- package/src/docs/components/docs-lit-demo-raw.ts +2 -26
- package/src/docs/components/docs-lit-demo.ts +9 -42
- package/src/docs/components/docs-source-excerpt.ts +53 -0
- package/src/docs/components/docs-source-link.ts +24 -8
- package/src/docs/components/docs-source-raw.ts +34 -0
- package/src/docs/example/decorators-demo-geo.ts +2 -2
- package/src/docs/example/decorators-demo-post.ts +249 -0
- package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +5 -5
- package/src/docs/example/decorators-demo.ts +1 -0
- package/src/docs/example/docs-api-config-demos.ts +5 -5
- package/src/docs/mock-api/router.ts +20 -0
- package/src/docs/navigation/navigation.ts +16 -0
- package/src/docs/search/docs-search.json +540 -15
- package/src/tsconfig.json +24 -0
- package/src/tsconfig.tsbuildinfo +1 -1
- package/vite.config.mts +1 -1
- package/docs/assets/index-D9pxaQYK.js +0 -7508
- package/docs/src/core/components/functional/date/date.md +0 -290
- package/docs/src/core/components/functional/fetch/fetch.md +0 -125
- package/docs/src/core/components/functional/if/if.md +0 -9
- package/docs/src/core/components/functional/list/list.md +0 -65
- package/docs/src/core/components/functional/mix/mix.md +0 -41
- package/docs/src/core/components/functional/queue/queue.md +0 -72
- package/docs/src/core/components/functional/router/router.md +0 -94
- package/docs/src/core/components/functional/sdui/default-library.json +0 -108
- package/docs/src/core/components/functional/sdui/example.json +0 -99
- package/docs/src/core/components/functional/sdui/sdui.md +0 -356
- package/docs/src/core/components/functional/states/states.md +0 -87
- package/docs/src/core/components/functional/submit/submit.md +0 -114
- package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
- package/docs/src/core/components/functional/value/value.md +0 -35
- package/docs/src/core/components/ui/alert/alert.md +0 -121
- package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -0
- package/docs/src/core/components/ui/badge/badge.md +0 -127
- package/docs/src/core/components/ui/button/button.md +0 -182
- package/docs/src/core/components/ui/captcha/captcha.md +0 -24
- package/docs/src/core/components/ui/card/card.md +0 -97
- package/docs/src/core/components/ui/divider/divider.md +0 -35
- package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -77
- package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -129
- package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -77
- package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -44
- package/docs/src/core/components/ui/form/input/input.md +0 -142
- package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -133
- package/docs/src/core/components/ui/form/radio/radio.md +0 -57
- package/docs/src/core/components/ui/form/select/select.md +0 -71
- package/docs/src/core/components/ui/form/switch/switch.md +0 -57
- package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
- package/docs/src/core/components/ui/group/group.md +0 -75
- package/docs/src/core/components/ui/icon/icon.md +0 -125
- package/docs/src/core/components/ui/icon/icons.json +0 -1
- package/docs/src/core/components/ui/image/image.md +0 -107
- package/docs/src/core/components/ui/link/link.md +0 -43
- package/docs/src/core/components/ui/loader/loader.md +0 -55
- package/docs/src/core/components/ui/menu/menu.md +0 -329
- package/docs/src/core/components/ui/modal/modal.md +0 -119
- package/docs/src/core/components/ui/pop/pop.md +0 -96
- package/docs/src/core/components/ui/progress/progress.md +0 -63
- package/docs/src/core/components/ui/table/table.md +0 -455
- package/docs/src/core/components/ui/toast/toast.md +0 -166
- package/docs/src/core/components/ui/tooltip/tooltip.md +0 -82
- package/docs/src/docs/_core-concept/dataFlow.md +0 -73
- package/docs/src/docs/_core-concept/overview.md +0 -57
- package/docs/src/docs/_core-concept/subscriber.md +0 -75
- package/docs/src/docs/_decorators/ancestor-attribute.md +0 -79
- package/docs/src/docs/_decorators/auto-subscribe.md +0 -202
- package/docs/src/docs/_decorators/bind.md +0 -167
- package/docs/src/docs/_decorators/get.md +0 -68
- package/docs/src/docs/_decorators/handle.md +0 -171
- package/docs/src/docs/_decorators/on-assign.md +0 -388
- package/docs/src/docs/_decorators/publish.md +0 -55
- package/docs/src/docs/_decorators/subscribe.md +0 -97
- package/docs/src/docs/_decorators/wait-for-ancestors.md +0 -163
- package/docs/src/docs/_directives/sub.md +0 -91
- package/docs/src/docs/_getting-started/ai-agents.md +0 -56
- package/docs/src/docs/_getting-started/concorde-manual-install.md +0 -133
- package/docs/src/docs/_getting-started/concorde-outside.md +0 -33
- package/docs/src/docs/_getting-started/create-a-component.md +0 -139
- package/docs/src/docs/_getting-started/my-first-component.md +0 -236
- package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -120
- package/docs/src/docs/_getting-started/pubsub.md +0 -37
- package/docs/src/docs/_getting-started/start.md +0 -47
- package/docs/src/docs/_getting-started/theming.md +0 -91
- package/docs/src/docs/_misc/api-configuration.md +0 -79
- package/docs/src/docs/_misc/dataProviderKey.md +0 -168
- package/docs/src/docs/_misc/docs-mock-api.md +0 -60
- package/docs/src/docs/_misc/endpoint.md +0 -43
- package/docs/src/docs/_misc/html-integration.md +0 -13
- package/docs/src/docs/search/docs-search.json +0 -8532
- package/docs/src/tag-list.json +0 -1
- package/docs/src/tsconfig-model.json +0 -23
- package/docs/src/tsconfig.json +0 -1050
- package/php/get-challenge.php +0 -34
- package/php/some-service.php +0 -42
|
@@ -8,11 +8,12 @@ import HTML, {
|
|
|
8
8
|
} from "@supersoniks/concorde/core/utils/HTML";
|
|
9
9
|
import API, {
|
|
10
10
|
APIConfiguration,
|
|
11
|
-
type
|
|
11
|
+
type ApiResult,
|
|
12
12
|
} from "@supersoniks/concorde/core/utils/api";
|
|
13
13
|
import DataProvider from "../utils/PublisherProxy";
|
|
14
14
|
import { ConnectedComponent, setSubscribable } from "./subscriber/common";
|
|
15
15
|
import {
|
|
16
|
+
type DynamicPathOptions,
|
|
16
17
|
extractDynamicDependencies,
|
|
17
18
|
resolveDynamicPath,
|
|
18
19
|
} from "./subscriber/dynamicPath";
|
|
@@ -77,6 +78,22 @@ function isLitHost(component: unknown): component is LitHost {
|
|
|
77
78
|
);
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Regroupe plusieurs déclencheurs synchrones (mutations `onInternalMutation`,
|
|
83
|
+
* `rebindAll`, etc.) en un seul appel par frame — même principe que
|
|
84
|
+
* `dynamicPropertyWatch.ts` (`scheduleObservedPropertyChanges`).
|
|
85
|
+
*/
|
|
86
|
+
function createAnimationFrameCoalescedRunner(run: () => void): () => void {
|
|
87
|
+
let frameId: number | null = null;
|
|
88
|
+
return () => {
|
|
89
|
+
if (frameId !== null) return;
|
|
90
|
+
frameId = requestAnimationFrame(() => {
|
|
91
|
+
frameId = null;
|
|
92
|
+
run();
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
80
97
|
function scheduleAfterHostReady(
|
|
81
98
|
component: unknown,
|
|
82
99
|
callback: () => void,
|
|
@@ -90,8 +107,9 @@ function scheduleAfterHostReady(
|
|
|
90
107
|
cancelled = true;
|
|
91
108
|
};
|
|
92
109
|
}
|
|
93
|
-
|
|
94
|
-
|
|
110
|
+
// HTMLElement classique : config ancêtre déjà lisible ; sinon watchScopedConfiguration.
|
|
111
|
+
callback();
|
|
112
|
+
return () => {};
|
|
95
113
|
}
|
|
96
114
|
|
|
97
115
|
/**
|
|
@@ -133,7 +151,8 @@ function watchScopedConfiguration(
|
|
|
133
151
|
attributeFilter: [...SCOPE_WATCH_ATTRIBUTES],
|
|
134
152
|
});
|
|
135
153
|
}
|
|
136
|
-
node = (node.parentNode ||
|
|
154
|
+
node = (node.parentNode ||
|
|
155
|
+
(node as ShadowRoot).host) as SearchableDomElement;
|
|
137
156
|
}
|
|
138
157
|
cleanups.push(() => observer.disconnect());
|
|
139
158
|
|
|
@@ -161,7 +180,7 @@ function detachConfigPublisher(state: ApiGetState): void {
|
|
|
161
180
|
|
|
162
181
|
/**
|
|
163
182
|
* Décorateur **`@get`** : charge des données via `API.getDetailed` et assigne un
|
|
164
|
-
* `
|
|
183
|
+
* `ApiResult<T>` (`request`, `response`, `result` typé `T`) ou `null`.
|
|
165
184
|
* Le path est un `Endpoint<T, Ue>` ; les placeholders `${nomPropriété}` sont résolus sur l'instance (`Ue` contraint l’hôte).
|
|
166
185
|
*
|
|
167
186
|
* **Scoped (défaut)** : `HTML.getApiConfiguration(host)` avec `host` = l’élément connecté
|
|
@@ -174,19 +193,19 @@ function detachConfigPublisher(state: ApiGetState): void {
|
|
|
174
193
|
*
|
|
175
194
|
* @example
|
|
176
195
|
* @get(new Endpoint<User, { userId: string }>("users/${userId}"))
|
|
177
|
-
* payload?:
|
|
196
|
+
* payload?: ApiResult<User>;
|
|
178
197
|
*
|
|
179
198
|
* @example
|
|
180
199
|
* const apiConf = new DataProviderKey<APIConfiguration>("myApiConf");
|
|
181
200
|
* PublisherManager.get("myApiConf").set({ serviceURL: "...", token: null, ... });
|
|
182
201
|
* @get(new Endpoint<Thing, { id: string }>("things/${id}"), apiConf)
|
|
183
|
-
* payload?:
|
|
202
|
+
* payload?: ApiResult<Thing>;
|
|
184
203
|
*/
|
|
185
204
|
export function get<T, Ue = any>(
|
|
186
205
|
endpoint: Endpoint<T, Ue>,
|
|
187
206
|
): <K extends string>(
|
|
188
207
|
target: DataProviderKeyHost<Ue> & {
|
|
189
|
-
[P in K]?:
|
|
208
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
190
209
|
},
|
|
191
210
|
propertyKey: K,
|
|
192
211
|
) => void;
|
|
@@ -196,18 +215,50 @@ export function get<T, Ue = any, Uk = any>(
|
|
|
196
215
|
): <K extends string>(
|
|
197
216
|
target: DataProviderKeyHost<Ue> &
|
|
198
217
|
DataProviderKeyHost<Uk> & {
|
|
199
|
-
[P in K]?:
|
|
218
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
200
219
|
},
|
|
201
220
|
propertyKey: K,
|
|
202
221
|
) => void;
|
|
203
222
|
export function get<T, Ue = any, Uk = any>(
|
|
204
223
|
endpoint: Endpoint<T, Ue>,
|
|
205
|
-
|
|
224
|
+
options: GetOptions,
|
|
206
225
|
): <K extends string>(
|
|
207
|
-
target:
|
|
226
|
+
target: DataProviderKeyHost<Ue> & {
|
|
227
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
228
|
+
},
|
|
229
|
+
propertyKey: K,
|
|
230
|
+
) => void;
|
|
231
|
+
export function get<T, Ue = any, Uk = any, Ut = any>(
|
|
232
|
+
endpoint: Endpoint<T, Ue>,
|
|
233
|
+
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
234
|
+
options: GetOptions,
|
|
235
|
+
): <K extends string>(
|
|
236
|
+
target: DataProviderKeyHost<Ue> &
|
|
237
|
+
DataProviderKeyHost<Uk> & {
|
|
238
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
239
|
+
},
|
|
240
|
+
propertyKey: K,
|
|
241
|
+
) => void;
|
|
242
|
+
export function get<T, Ue = any, Uk = any, _Ut = any>(
|
|
243
|
+
endpoint: Endpoint<T, Ue>,
|
|
244
|
+
configurationKeyOrOptions?:
|
|
245
|
+
| DataProviderKey<APIConfiguration, Uk>
|
|
246
|
+
| GetOptions,
|
|
247
|
+
maybeOptions?: GetOptions,
|
|
248
|
+
): <K extends string>(
|
|
249
|
+
target: object & { [P in K]?: ApiResult<T> | null | undefined },
|
|
208
250
|
propertyKey: K,
|
|
209
251
|
) => void {
|
|
210
252
|
const pathTemplate = endpoint.path;
|
|
253
|
+
const configurationKey = isGetOptions(configurationKeyOrOptions)
|
|
254
|
+
? undefined
|
|
255
|
+
: configurationKeyOrOptions;
|
|
256
|
+
const options = isGetOptions(configurationKeyOrOptions)
|
|
257
|
+
? configurationKeyOrOptions
|
|
258
|
+
: maybeOptions;
|
|
259
|
+
const pathOptions: DynamicPathOptions = {
|
|
260
|
+
skipEmptyPlaceholder: options?.skipEmptyPlaceholder,
|
|
261
|
+
};
|
|
211
262
|
const configurationKeyPath = configurationKey?.path;
|
|
212
263
|
const endpointDynamicDependencies = extractDynamicDependencies(pathTemplate);
|
|
213
264
|
const configKeyDynamicDependencies = configurationKeyPath
|
|
@@ -247,7 +298,7 @@ export function get<T, Ue = any, Uk = any>(
|
|
|
247
298
|
|
|
248
299
|
const runFetch = () => {
|
|
249
300
|
const resolution = isDynamicPath
|
|
250
|
-
? resolveDynamicPath(component, pathTemplate)
|
|
301
|
+
? resolveDynamicPath(component, pathTemplate, pathOptions)
|
|
251
302
|
: { ready: true, path: pathTemplate };
|
|
252
303
|
if (!resolution.ready || !resolution.path) {
|
|
253
304
|
comp[propertyKey] = undefined;
|
|
@@ -255,7 +306,11 @@ export function get<T, Ue = any, Uk = any>(
|
|
|
255
306
|
}
|
|
256
307
|
let config: APIConfiguration | null = null;
|
|
257
308
|
if (usesPublisherConfig && configurationKeyPath) {
|
|
258
|
-
const configRes = resolveDynamicPath(
|
|
309
|
+
const configRes = resolveDynamicPath(
|
|
310
|
+
component,
|
|
311
|
+
configurationKeyPath,
|
|
312
|
+
pathOptions,
|
|
313
|
+
);
|
|
259
314
|
if (!configRes.ready || !configRes.path) {
|
|
260
315
|
comp[propertyKey] = undefined;
|
|
261
316
|
return;
|
|
@@ -280,7 +335,7 @@ export function get<T, Ue = any, Uk = any>(
|
|
|
280
335
|
const api = new API(config);
|
|
281
336
|
void api
|
|
282
337
|
.getDetailed<T>(resolution.path)
|
|
283
|
-
.then((payload?:
|
|
338
|
+
.then((payload?: ApiResult<T>) => {
|
|
284
339
|
if (generation !== state.requestGeneration) return;
|
|
285
340
|
comp[propertyKey] = payload;
|
|
286
341
|
});
|
|
@@ -289,7 +344,11 @@ export function get<T, Ue = any, Uk = any>(
|
|
|
289
344
|
const rebindPublisherConfig = () => {
|
|
290
345
|
if (!usesPublisherConfig || !configurationKeyPath) return;
|
|
291
346
|
detachConfigPublisher(state);
|
|
292
|
-
const configRes = resolveDynamicPath(
|
|
347
|
+
const configRes = resolveDynamicPath(
|
|
348
|
+
component,
|
|
349
|
+
configurationKeyPath,
|
|
350
|
+
pathOptions,
|
|
351
|
+
);
|
|
293
352
|
if (!configRes.ready || !configRes.path) {
|
|
294
353
|
comp[propertyKey] = undefined;
|
|
295
354
|
return;
|
|
@@ -353,3 +412,577 @@ export function get<T, Ue = any, Uk = any>(
|
|
|
353
412
|
});
|
|
354
413
|
};
|
|
355
414
|
}
|
|
415
|
+
|
|
416
|
+
export type GetOptions = DynamicPathOptions;
|
|
417
|
+
|
|
418
|
+
export type ApiSendOptions<Uk = any> = DynamicPathOptions & {
|
|
419
|
+
/** Intervalle de renvoi automatique (ms). 0 ou absent = pas de polling. */
|
|
420
|
+
refetchEveryMs?: number;
|
|
421
|
+
/** Ne pas envoyer si le body publisher est null/undefined (défaut: true). */
|
|
422
|
+
skipIfBodyMissing?: boolean;
|
|
423
|
+
/**
|
|
424
|
+
* Relancer l'envoi quand le body publisher mute (défaut: true).
|
|
425
|
+
* `false` : le body est lu au moment de l'envoi ; déclencher via `triggerKey.invalidate()`.
|
|
426
|
+
*/
|
|
427
|
+
autoPostOnBodyMutation?: boolean;
|
|
428
|
+
/** Publisher dont `invalidate()` relance l'envoi (relit le body courant). */
|
|
429
|
+
triggerKey?: DataProviderKey<unknown, Uk>;
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
/** @deprecated Alias — préférer `ApiSendOptions`. */
|
|
433
|
+
export type PostOptions<Uk = any> = ApiSendOptions<Uk>;
|
|
434
|
+
export type PutOptions<Uk = any> = ApiSendOptions<Uk>;
|
|
435
|
+
export type PatchOptions<Uk = any> = ApiSendOptions<Uk>;
|
|
436
|
+
|
|
437
|
+
function isGetOptions(value: unknown): value is GetOptions {
|
|
438
|
+
if (!value || typeof value !== "object") return false;
|
|
439
|
+
return "skipEmptyPlaceholder" in value;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function isApiSendOptions(value: unknown): value is ApiSendOptions {
|
|
443
|
+
if (!value || typeof value !== "object") return false;
|
|
444
|
+
return (
|
|
445
|
+
"refetchEveryMs" in value ||
|
|
446
|
+
"skipIfBodyMissing" in value ||
|
|
447
|
+
"autoPostOnBodyMutation" in value ||
|
|
448
|
+
"skipEmptyPlaceholder" in value ||
|
|
449
|
+
"triggerKey" in value
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
type ApiSendState = ApiGetState & {
|
|
454
|
+
bodyPublisher: DataProvider | null;
|
|
455
|
+
bodyMutationHandler: (() => void) | null;
|
|
456
|
+
triggerPublisher: DataProvider | null;
|
|
457
|
+
triggerInvalidateHandler: (() => void) | null;
|
|
458
|
+
refetchTimeoutId: ReturnType<typeof setTimeout> | null;
|
|
459
|
+
refetchEveryMs: number;
|
|
460
|
+
skipIfBodyMissing: boolean;
|
|
461
|
+
autoPostOnBodyMutation: boolean;
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
function detachBodyPublisher(state: ApiSendState): void {
|
|
465
|
+
if (state.bodyPublisher && state.bodyMutationHandler) {
|
|
466
|
+
state.bodyPublisher.offInternalMutation(state.bodyMutationHandler);
|
|
467
|
+
}
|
|
468
|
+
state.bodyPublisher = null;
|
|
469
|
+
state.bodyMutationHandler = null;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function detachTriggerPublisher(state: ApiSendState): void {
|
|
473
|
+
if (state.triggerPublisher && state.triggerInvalidateHandler) {
|
|
474
|
+
state.triggerPublisher.offInvalidate(state.triggerInvalidateHandler);
|
|
475
|
+
}
|
|
476
|
+
state.triggerPublisher = null;
|
|
477
|
+
state.triggerInvalidateHandler = null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function clearSendRefetch(state: ApiSendState): void {
|
|
481
|
+
if (state.refetchTimeoutId) {
|
|
482
|
+
clearTimeout(state.refetchTimeoutId);
|
|
483
|
+
state.refetchTimeoutId = null;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function readBodyFromPublisher(publisher: DataProvider | null): unknown {
|
|
488
|
+
if (!publisher || typeof publisher.get !== "function") return undefined;
|
|
489
|
+
return publisher.get();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
type ApiSendMethod = "POST" | "PUT" | "PATCH";
|
|
493
|
+
|
|
494
|
+
type ApiSendDetailedCaller = (
|
|
495
|
+
api: API,
|
|
496
|
+
path: string,
|
|
497
|
+
body: unknown,
|
|
498
|
+
) => Promise<ApiResult<unknown> | undefined>;
|
|
499
|
+
|
|
500
|
+
function createApiSendDecorator<T, B, Ue = any, Uk = any, Ut = any>(
|
|
501
|
+
method: ApiSendMethod,
|
|
502
|
+
callDetailed: ApiSendDetailedCaller,
|
|
503
|
+
) {
|
|
504
|
+
return function (
|
|
505
|
+
endpoint: Endpoint<T, Ue>,
|
|
506
|
+
bodyKey: DataProviderKey<B>,
|
|
507
|
+
configurationKeyOrOptions?:
|
|
508
|
+
| DataProviderKey<APIConfiguration, Uk>
|
|
509
|
+
| ApiSendOptions<Ut>,
|
|
510
|
+
maybeOptions?: ApiSendOptions<Ut>,
|
|
511
|
+
): <K extends string>(
|
|
512
|
+
target: object & { [P in K]?: ApiResult<T> | null | undefined },
|
|
513
|
+
propertyKey: K,
|
|
514
|
+
) => void {
|
|
515
|
+
const pathTemplate = endpoint.path;
|
|
516
|
+
const bodyKeyPath = bodyKey.path;
|
|
517
|
+
const configurationKey = isApiSendOptions(configurationKeyOrOptions)
|
|
518
|
+
? undefined
|
|
519
|
+
: configurationKeyOrOptions;
|
|
520
|
+
const options = isApiSendOptions(configurationKeyOrOptions)
|
|
521
|
+
? configurationKeyOrOptions
|
|
522
|
+
: maybeOptions;
|
|
523
|
+
const configurationKeyPath = configurationKey?.path;
|
|
524
|
+
const triggerKeyPath = options?.triggerKey?.path;
|
|
525
|
+
const endpointDynamicDependencies = extractDynamicDependencies(pathTemplate);
|
|
526
|
+
const bodyKeyDynamicDependencies = extractDynamicDependencies(bodyKeyPath);
|
|
527
|
+
const configKeyDynamicDependencies = configurationKeyPath
|
|
528
|
+
? extractDynamicDependencies(configurationKeyPath)
|
|
529
|
+
: [];
|
|
530
|
+
const triggerKeyDynamicDependencies = triggerKeyPath
|
|
531
|
+
? extractDynamicDependencies(triggerKeyPath)
|
|
532
|
+
: [];
|
|
533
|
+
const mergedDynamicDependencies = [
|
|
534
|
+
...new Set([
|
|
535
|
+
...endpointDynamicDependencies,
|
|
536
|
+
...bodyKeyDynamicDependencies,
|
|
537
|
+
...configKeyDynamicDependencies,
|
|
538
|
+
...triggerKeyDynamicDependencies,
|
|
539
|
+
]),
|
|
540
|
+
];
|
|
541
|
+
const isDynamicPath = endpointDynamicDependencies.length > 0;
|
|
542
|
+
const usesPublisherConfig = Boolean(configurationKeyPath);
|
|
543
|
+
const refetchEveryMs = options?.refetchEveryMs ?? 0;
|
|
544
|
+
const skipIfBodyMissing = options?.skipIfBodyMissing ?? true;
|
|
545
|
+
const autoPostOnBodyMutation = options?.autoPostOnBodyMutation ?? true;
|
|
546
|
+
const pathOptions: DynamicPathOptions = {
|
|
547
|
+
skipEmptyPlaceholder: options?.skipEmptyPlaceholder,
|
|
548
|
+
};
|
|
549
|
+
const stateKeyPrefix = `__${method.toLowerCase()}_state_`;
|
|
550
|
+
|
|
551
|
+
return function (target: object, propertyKey: string) {
|
|
552
|
+
if (!target) return;
|
|
553
|
+
setSubscribable(target);
|
|
554
|
+
const stateKey = `${stateKeyPrefix}${propertyKey}`;
|
|
555
|
+
|
|
556
|
+
(target as ConnectedComponent).__onConnected__((component) => {
|
|
557
|
+
const comp = component as Record<string, unknown>;
|
|
558
|
+
let state = comp[stateKey] as ApiSendState | undefined;
|
|
559
|
+
if (!state) {
|
|
560
|
+
state = {
|
|
561
|
+
cleanupWatchers: [],
|
|
562
|
+
requestGeneration: 0,
|
|
563
|
+
configPublisher: null,
|
|
564
|
+
configMutationHandler: null,
|
|
565
|
+
scopeWatchCleanup: null,
|
|
566
|
+
bodyPublisher: null,
|
|
567
|
+
bodyMutationHandler: null,
|
|
568
|
+
triggerPublisher: null,
|
|
569
|
+
triggerInvalidateHandler: null,
|
|
570
|
+
refetchTimeoutId: null,
|
|
571
|
+
refetchEveryMs,
|
|
572
|
+
skipIfBodyMissing,
|
|
573
|
+
autoPostOnBodyMutation,
|
|
574
|
+
};
|
|
575
|
+
comp[stateKey] = state;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
state.cleanupWatchers.forEach((cleanup) => cleanup());
|
|
579
|
+
state.cleanupWatchers = [];
|
|
580
|
+
state.requestGeneration++;
|
|
581
|
+
state.refetchEveryMs = refetchEveryMs;
|
|
582
|
+
state.skipIfBodyMissing = skipIfBodyMissing;
|
|
583
|
+
state.autoPostOnBodyMutation = autoPostOnBodyMutation;
|
|
584
|
+
clearSendRefetch(state);
|
|
585
|
+
|
|
586
|
+
const scheduleRefetch = () => {
|
|
587
|
+
clearSendRefetch(state);
|
|
588
|
+
if (!state.refetchEveryMs || state.refetchEveryMs <= 0) return;
|
|
589
|
+
state.refetchTimeoutId = setTimeout(() => {
|
|
590
|
+
state.refetchTimeoutId = null;
|
|
591
|
+
runSend();
|
|
592
|
+
}, state.refetchEveryMs);
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
const runSend = () => {
|
|
596
|
+
const resolution = isDynamicPath
|
|
597
|
+
? resolveDynamicPath(component, pathTemplate, pathOptions)
|
|
598
|
+
: { ready: true, path: pathTemplate };
|
|
599
|
+
if (!resolution.ready || !resolution.path) {
|
|
600
|
+
comp[propertyKey] = undefined;
|
|
601
|
+
scheduleRefetch();
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const bodyResolution = resolveDynamicPath(
|
|
606
|
+
component,
|
|
607
|
+
bodyKeyPath,
|
|
608
|
+
pathOptions,
|
|
609
|
+
);
|
|
610
|
+
if (!bodyResolution.ready || !bodyResolution.path) {
|
|
611
|
+
comp[propertyKey] = undefined;
|
|
612
|
+
scheduleRefetch();
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const bodyPublisher = getPublisherFromPath(bodyResolution.path);
|
|
617
|
+
const body = readBodyFromPublisher(bodyPublisher);
|
|
618
|
+
if (
|
|
619
|
+
state.skipIfBodyMissing &&
|
|
620
|
+
(body === null || body === undefined)
|
|
621
|
+
) {
|
|
622
|
+
scheduleRefetch();
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
let config: APIConfiguration | null = null;
|
|
627
|
+
if (usesPublisherConfig && configurationKeyPath) {
|
|
628
|
+
const configRes = resolveDynamicPath(
|
|
629
|
+
component,
|
|
630
|
+
configurationKeyPath,
|
|
631
|
+
pathOptions,
|
|
632
|
+
);
|
|
633
|
+
if (!configRes.ready || !configRes.path) {
|
|
634
|
+
comp[propertyKey] = undefined;
|
|
635
|
+
scheduleRefetch();
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const configPublisher = getPublisherFromPath(configRes.path);
|
|
639
|
+
config = readApiConfigurationFromPublisher(configPublisher);
|
|
640
|
+
} else {
|
|
641
|
+
config = resolveScopedConfiguration(component);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (!isScopedConfigurationReady(config)) {
|
|
645
|
+
if (!usesPublisherConfig && !state.scopeWatchCleanup) {
|
|
646
|
+
const scopeWatch = watchScopedConfiguration(component, runSend);
|
|
647
|
+
state.scopeWatchCleanup = scopeWatch;
|
|
648
|
+
state.cleanupWatchers.push(() => {
|
|
649
|
+
scopeWatch();
|
|
650
|
+
state.scopeWatchCleanup = null;
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
scheduleRefetch();
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const generation = ++state.requestGeneration;
|
|
658
|
+
const api = new API(config);
|
|
659
|
+
void callDetailed(api, resolution.path, body).then(
|
|
660
|
+
(payload?: ApiResult<unknown>) => {
|
|
661
|
+
if (generation !== state.requestGeneration) return;
|
|
662
|
+
comp[propertyKey] = payload;
|
|
663
|
+
scheduleRefetch();
|
|
664
|
+
},
|
|
665
|
+
);
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
const scheduleSend = createAnimationFrameCoalescedRunner(runSend);
|
|
669
|
+
|
|
670
|
+
const rebindBodyPublisher = () => {
|
|
671
|
+
detachBodyPublisher(state);
|
|
672
|
+
if (!state.autoPostOnBodyMutation) {
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const bodyResolution = resolveDynamicPath(
|
|
676
|
+
component,
|
|
677
|
+
bodyKeyPath,
|
|
678
|
+
pathOptions,
|
|
679
|
+
);
|
|
680
|
+
if (!bodyResolution.ready || !bodyResolution.path) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const publisher = getPublisherFromPath(bodyResolution.path);
|
|
684
|
+
if (!publisher) return;
|
|
685
|
+
const mutationHandler = () => scheduleSend();
|
|
686
|
+
publisher.onInternalMutation(mutationHandler);
|
|
687
|
+
state.bodyPublisher = publisher;
|
|
688
|
+
state.bodyMutationHandler = mutationHandler;
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
const rebindTriggerPublisher = () => {
|
|
692
|
+
detachTriggerPublisher(state);
|
|
693
|
+
if (!triggerKeyPath) return;
|
|
694
|
+
const triggerResolution = resolveDynamicPath(
|
|
695
|
+
component,
|
|
696
|
+
triggerKeyPath,
|
|
697
|
+
pathOptions,
|
|
698
|
+
);
|
|
699
|
+
if (!triggerResolution.ready || !triggerResolution.path) {
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
const publisher = getPublisherFromPath(triggerResolution.path);
|
|
703
|
+
if (!publisher) return;
|
|
704
|
+
const invalidateHandler = () => scheduleSend();
|
|
705
|
+
publisher.onInvalidate(invalidateHandler);
|
|
706
|
+
state.triggerPublisher = publisher;
|
|
707
|
+
state.triggerInvalidateHandler = invalidateHandler;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
const rebindPublisherConfig = () => {
|
|
711
|
+
if (!usesPublisherConfig || !configurationKeyPath) return;
|
|
712
|
+
detachConfigPublisher(state);
|
|
713
|
+
const configRes = resolveDynamicPath(
|
|
714
|
+
component,
|
|
715
|
+
configurationKeyPath,
|
|
716
|
+
pathOptions,
|
|
717
|
+
);
|
|
718
|
+
if (!configRes.ready || !configRes.path) {
|
|
719
|
+
comp[propertyKey] = undefined;
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const publisher = getPublisherFromPath(configRes.path);
|
|
723
|
+
if (!publisher) {
|
|
724
|
+
comp[propertyKey] = undefined;
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const mutationHandler = () => scheduleSend();
|
|
728
|
+
publisher.onInternalMutation(mutationHandler);
|
|
729
|
+
state.configPublisher = publisher;
|
|
730
|
+
state.configMutationHandler = mutationHandler;
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
const rebindAll = () => {
|
|
734
|
+
rebindBodyPublisher();
|
|
735
|
+
rebindTriggerPublisher();
|
|
736
|
+
rebindPublisherConfig();
|
|
737
|
+
if (state.autoPostOnBodyMutation) {
|
|
738
|
+
scheduleSend();
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
if (
|
|
743
|
+
usesPublisherConfig ||
|
|
744
|
+
bodyKeyDynamicDependencies.length ||
|
|
745
|
+
triggerKeyDynamicDependencies.length
|
|
746
|
+
) {
|
|
747
|
+
for (const dependency of mergedDynamicDependencies) {
|
|
748
|
+
const unsubscribe = observeDynamicProperty(
|
|
749
|
+
getDynamicWatchKeys.watcherStore,
|
|
750
|
+
getDynamicWatchKeys.hooked,
|
|
751
|
+
component,
|
|
752
|
+
dependency,
|
|
753
|
+
() => rebindAll(),
|
|
754
|
+
);
|
|
755
|
+
state.cleanupWatchers.push(unsubscribe);
|
|
756
|
+
}
|
|
757
|
+
rebindAll();
|
|
758
|
+
} else {
|
|
759
|
+
const startScopedSend = () => {
|
|
760
|
+
if (isDynamicPath) {
|
|
761
|
+
for (const dependency of endpointDynamicDependencies) {
|
|
762
|
+
const unsubscribe = observeDynamicProperty(
|
|
763
|
+
getDynamicWatchKeys.watcherStore,
|
|
764
|
+
getDynamicWatchKeys.hooked,
|
|
765
|
+
component,
|
|
766
|
+
dependency,
|
|
767
|
+
() => scheduleSend(),
|
|
768
|
+
);
|
|
769
|
+
state.cleanupWatchers.push(unsubscribe);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
rebindBodyPublisher();
|
|
773
|
+
rebindTriggerPublisher();
|
|
774
|
+
if (state.autoPostOnBodyMutation) {
|
|
775
|
+
scheduleSend();
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
state.cleanupWatchers.push(
|
|
779
|
+
scheduleAfterHostReady(component, startScopedSend),
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
(target as ConnectedComponent).__onDisconnected__((component) => {
|
|
785
|
+
const comp = component as Record<string, unknown>;
|
|
786
|
+
const state = comp[stateKey] as ApiSendState | undefined;
|
|
787
|
+
if (!state) return;
|
|
788
|
+
detachConfigPublisher(state);
|
|
789
|
+
detachBodyPublisher(state);
|
|
790
|
+
detachTriggerPublisher(state);
|
|
791
|
+
clearSendRefetch(state);
|
|
792
|
+
state.cleanupWatchers.forEach((cleanup) => cleanup());
|
|
793
|
+
state.cleanupWatchers = [];
|
|
794
|
+
state.requestGeneration++;
|
|
795
|
+
comp[propertyKey] = undefined;
|
|
796
|
+
});
|
|
797
|
+
};
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Décorateur **`@post`** : envoie des données via `API.postDetailed` et assigne un
|
|
803
|
+
* `ApiResult<T>` (`request`, `response`, `result` typé `T`).
|
|
804
|
+
*
|
|
805
|
+
* Le body est lu depuis un `DataProviderKey` (mutations et assignations relancent le POST).
|
|
806
|
+
*
|
|
807
|
+
* @example
|
|
808
|
+
* @post(new Endpoint<SyncResult, { sessionId: string }>("sessions/${sessionId}/sync"), syncRequestKey)
|
|
809
|
+
* payload?: ApiResult<SyncResult>;
|
|
810
|
+
*/
|
|
811
|
+
export function post<T, B, Ue = any>(
|
|
812
|
+
endpoint: Endpoint<T, Ue>,
|
|
813
|
+
bodyKey: DataProviderKey<B>,
|
|
814
|
+
): <K extends string>(
|
|
815
|
+
target: DataProviderKeyHost<Ue> & {
|
|
816
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
817
|
+
},
|
|
818
|
+
propertyKey: K,
|
|
819
|
+
) => void;
|
|
820
|
+
export function post<T, B, Ue = any, Uk = any>(
|
|
821
|
+
endpoint: Endpoint<T, Ue>,
|
|
822
|
+
bodyKey: DataProviderKey<B>,
|
|
823
|
+
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
824
|
+
): <K extends string>(
|
|
825
|
+
target: DataProviderKeyHost<Ue> &
|
|
826
|
+
DataProviderKeyHost<Uk> & {
|
|
827
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
828
|
+
},
|
|
829
|
+
propertyKey: K,
|
|
830
|
+
) => void;
|
|
831
|
+
export function post<T, B, Ue = any, Uk = any>(
|
|
832
|
+
endpoint: Endpoint<T, Ue>,
|
|
833
|
+
bodyKey: DataProviderKey<B>,
|
|
834
|
+
options: PostOptions<Uk>,
|
|
835
|
+
): <K extends string>(
|
|
836
|
+
target: DataProviderKeyHost<Ue> & {
|
|
837
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
838
|
+
},
|
|
839
|
+
propertyKey: K,
|
|
840
|
+
) => void;
|
|
841
|
+
export function post<T, B, Ue = any, Uk = any, Ut = any>(
|
|
842
|
+
endpoint: Endpoint<T, Ue>,
|
|
843
|
+
bodyKey: DataProviderKey<B>,
|
|
844
|
+
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
845
|
+
options: PostOptions<Ut>,
|
|
846
|
+
): <K extends string>(
|
|
847
|
+
target: DataProviderKeyHost<Ue> &
|
|
848
|
+
DataProviderKeyHost<Uk> & {
|
|
849
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
850
|
+
},
|
|
851
|
+
propertyKey: K,
|
|
852
|
+
) => void;
|
|
853
|
+
export function post<T, B, Ue = any, Uk = any, Ut = any>(
|
|
854
|
+
endpoint: Endpoint<T, Ue>,
|
|
855
|
+
bodyKey: DataProviderKey<B>,
|
|
856
|
+
configurationKeyOrOptions?:
|
|
857
|
+
| DataProviderKey<APIConfiguration, Uk>
|
|
858
|
+
| PostOptions<Ut>,
|
|
859
|
+
maybeOptions?: PostOptions<Ut>,
|
|
860
|
+
): <K extends string>(
|
|
861
|
+
target: object & { [P in K]?: ApiResult<T> | null | undefined },
|
|
862
|
+
propertyKey: K,
|
|
863
|
+
) => void {
|
|
864
|
+
return createApiSendDecorator<T, B, Ue, Uk, Ut>(
|
|
865
|
+
"POST",
|
|
866
|
+
(api, path, body) => api.postDetailed<T, B>(path, body as B),
|
|
867
|
+
)(endpoint, bodyKey, configurationKeyOrOptions, maybeOptions);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/** `@put` — même modèle que `@post` via `API.putDetailed`. */
|
|
871
|
+
export function put<T, B, Ue = any>(
|
|
872
|
+
endpoint: Endpoint<T, Ue>,
|
|
873
|
+
bodyKey: DataProviderKey<B>,
|
|
874
|
+
): <K extends string>(
|
|
875
|
+
target: DataProviderKeyHost<Ue> & {
|
|
876
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
877
|
+
},
|
|
878
|
+
propertyKey: K,
|
|
879
|
+
) => void;
|
|
880
|
+
export function put<T, B, Ue = any, Uk = any>(
|
|
881
|
+
endpoint: Endpoint<T, Ue>,
|
|
882
|
+
bodyKey: DataProviderKey<B>,
|
|
883
|
+
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
884
|
+
): <K extends string>(
|
|
885
|
+
target: DataProviderKeyHost<Ue> &
|
|
886
|
+
DataProviderKeyHost<Uk> & {
|
|
887
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
888
|
+
},
|
|
889
|
+
propertyKey: K,
|
|
890
|
+
) => void;
|
|
891
|
+
export function put<T, B, Ue = any, Uk = any>(
|
|
892
|
+
endpoint: Endpoint<T, Ue>,
|
|
893
|
+
bodyKey: DataProviderKey<B>,
|
|
894
|
+
options: PutOptions<Uk>,
|
|
895
|
+
): <K extends string>(
|
|
896
|
+
target: DataProviderKeyHost<Ue> & {
|
|
897
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
898
|
+
},
|
|
899
|
+
propertyKey: K,
|
|
900
|
+
) => void;
|
|
901
|
+
export function put<T, B, Ue = any, Uk = any, Ut = any>(
|
|
902
|
+
endpoint: Endpoint<T, Ue>,
|
|
903
|
+
bodyKey: DataProviderKey<B>,
|
|
904
|
+
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
905
|
+
options: PutOptions<Ut>,
|
|
906
|
+
): <K extends string>(
|
|
907
|
+
target: DataProviderKeyHost<Ue> &
|
|
908
|
+
DataProviderKeyHost<Uk> & {
|
|
909
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
910
|
+
},
|
|
911
|
+
propertyKey: K,
|
|
912
|
+
) => void;
|
|
913
|
+
export function put<T, B, Ue = any, Uk = any, Ut = any>(
|
|
914
|
+
endpoint: Endpoint<T, Ue>,
|
|
915
|
+
bodyKey: DataProviderKey<B>,
|
|
916
|
+
configurationKeyOrOptions?:
|
|
917
|
+
| DataProviderKey<APIConfiguration, Uk>
|
|
918
|
+
| PutOptions<Ut>,
|
|
919
|
+
maybeOptions?: PutOptions<Ut>,
|
|
920
|
+
): <K extends string>(
|
|
921
|
+
target: object & { [P in K]?: ApiResult<T> | null | undefined },
|
|
922
|
+
propertyKey: K,
|
|
923
|
+
) => void {
|
|
924
|
+
return createApiSendDecorator<T, B, Ue, Uk, Ut>(
|
|
925
|
+
"PUT",
|
|
926
|
+
(api, path, body) => api.putDetailed<T, B>(path, body as B),
|
|
927
|
+
)(endpoint, bodyKey, configurationKeyOrOptions, maybeOptions);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/** `@patch` — même modèle que `@post` via `API.patchDetailed`. */
|
|
931
|
+
export function patch<T, B, Ue = any>(
|
|
932
|
+
endpoint: Endpoint<T, Ue>,
|
|
933
|
+
bodyKey: DataProviderKey<B>,
|
|
934
|
+
): <K extends string>(
|
|
935
|
+
target: DataProviderKeyHost<Ue> & {
|
|
936
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
937
|
+
},
|
|
938
|
+
propertyKey: K,
|
|
939
|
+
) => void;
|
|
940
|
+
export function patch<T, B, Ue = any, Uk = any>(
|
|
941
|
+
endpoint: Endpoint<T, Ue>,
|
|
942
|
+
bodyKey: DataProviderKey<B>,
|
|
943
|
+
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
944
|
+
): <K extends string>(
|
|
945
|
+
target: DataProviderKeyHost<Ue> &
|
|
946
|
+
DataProviderKeyHost<Uk> & {
|
|
947
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
948
|
+
},
|
|
949
|
+
propertyKey: K,
|
|
950
|
+
) => void;
|
|
951
|
+
export function patch<T, B, Ue = any, Uk = any>(
|
|
952
|
+
endpoint: Endpoint<T, Ue>,
|
|
953
|
+
bodyKey: DataProviderKey<B>,
|
|
954
|
+
options: PatchOptions<Uk>,
|
|
955
|
+
): <K extends string>(
|
|
956
|
+
target: DataProviderKeyHost<Ue> & {
|
|
957
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
958
|
+
},
|
|
959
|
+
propertyKey: K,
|
|
960
|
+
) => void;
|
|
961
|
+
export function patch<T, B, Ue = any, Uk = any, Ut = any>(
|
|
962
|
+
endpoint: Endpoint<T, Ue>,
|
|
963
|
+
bodyKey: DataProviderKey<B>,
|
|
964
|
+
configurationKey: DataProviderKey<APIConfiguration, Uk>,
|
|
965
|
+
options: PatchOptions<Ut>,
|
|
966
|
+
): <K extends string>(
|
|
967
|
+
target: DataProviderKeyHost<Ue> &
|
|
968
|
+
DataProviderKeyHost<Uk> & {
|
|
969
|
+
[P in K]?: ApiResult<T> | null | undefined;
|
|
970
|
+
},
|
|
971
|
+
propertyKey: K,
|
|
972
|
+
) => void;
|
|
973
|
+
export function patch<T, B, Ue = any, Uk = any, Ut = any>(
|
|
974
|
+
endpoint: Endpoint<T, Ue>,
|
|
975
|
+
bodyKey: DataProviderKey<B>,
|
|
976
|
+
configurationKeyOrOptions?:
|
|
977
|
+
| DataProviderKey<APIConfiguration, Uk>
|
|
978
|
+
| PatchOptions<Ut>,
|
|
979
|
+
maybeOptions?: PatchOptions<Ut>,
|
|
980
|
+
): <K extends string>(
|
|
981
|
+
target: object & { [P in K]?: ApiResult<T> | null | undefined },
|
|
982
|
+
propertyKey: K,
|
|
983
|
+
) => void {
|
|
984
|
+
return createApiSendDecorator<T, B, Ue, Uk, Ut>(
|
|
985
|
+
"PATCH",
|
|
986
|
+
(api, path, body) => api.patchDetailed<T, B>(path, body as B),
|
|
987
|
+
)(endpoint, bodyKey, configurationKeyOrOptions, maybeOptions);
|
|
988
|
+
}
|