@craft-ng/core 0.1.1 → 0.1.3
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/fesm2022/craft-ng-core.mjs +159 -1
- package/fesm2022/craft-ng-core.mjs.map +1 -1
- package/package.json +1 -1
- package/types/craft-ng-core.d.ts +491 -366
package/types/craft-ng-core.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import { WritableSignal, Signal, Injector, InjectionToken, Provider, ValueEqualityFn, Type, EventEmitter, ResourceRef, ResourceOptions, ResourceStatus, ResourceLoaderParams, ResourceStreamingLoader } from '@angular/core';
|
|
3
3
|
import { CompatFieldState, FieldState, ReadonlyArrayLike, MaybeFieldTree, Subfields, FieldTree, SchemaPathTree, PathKind, SchemaPath, SchemaPathRules, ValidationError } from '@angular/forms/signals';
|
|
4
4
|
import { AbstractControl } from '@angular/forms';
|
|
5
5
|
|
|
6
|
-
type ReadonlySource<T> = Signal<T | undefined> & {
|
|
7
|
-
preserveLastValue: Signal<T | undefined>;
|
|
8
|
-
} & SourceBranded;
|
|
9
|
-
|
|
10
6
|
declare const SourceBranded: {
|
|
11
7
|
[SourceBrand]: true;
|
|
12
8
|
};
|
|
@@ -24,367 +20,9 @@ declare function createMethodHandlers<State>(methodsData: Record<string, ((...ar
|
|
|
24
20
|
onStateChange?: (newValue: State) => void;
|
|
25
21
|
}): Record<string, Function>;
|
|
26
22
|
|
|
27
|
-
type
|
|
28
|
-
set: (value: T) => void;
|
|
23
|
+
type ReadonlySource<T> = Signal<T | undefined> & {
|
|
29
24
|
preserveLastValue: Signal<T | undefined>;
|
|
30
25
|
} & SourceBranded;
|
|
31
|
-
/**
|
|
32
|
-
* Creates a source for event-driven communication with lazy emission semantics.
|
|
33
|
-
*
|
|
34
|
-
* Sources are the foundation of event-driven patterns in ng-craft, enabling:
|
|
35
|
-
* - Discrete event emissions (unlike continuous signals)
|
|
36
|
-
* - Lazy behavior (undefined until explicitly set)
|
|
37
|
-
* - Decoupled communication between components and stores
|
|
38
|
-
* - Automatic triggering of queries, mutations, and async methods
|
|
39
|
-
* - Multi-listener support with independent subscription timing
|
|
40
|
-
*
|
|
41
|
-
* @remarks
|
|
42
|
-
* **Core Concept:**
|
|
43
|
-
* Sources implement event emitter pattern with reactive semantics:
|
|
44
|
-
* - Emit only when explicitly set (not on every read like signals)
|
|
45
|
-
* - Listeners receive `undefined` on first read (lazy semantics)
|
|
46
|
-
* - New listeners don't receive previous emissions by default
|
|
47
|
-
* - Use `preserveLastValue` to get the last emitted value immediately
|
|
48
|
-
*
|
|
49
|
-
* **Difference from Signals:**
|
|
50
|
-
* - **Signals**: Always have a value, recompute on access, continuous state
|
|
51
|
-
* - **Sources**: Emit on explicit set, lazy by default, discrete events
|
|
52
|
-
* - Sources are for events/actions, signals are for state
|
|
53
|
-
*
|
|
54
|
-
* **Use Cases:**
|
|
55
|
-
* - **User actions**: Button clicks, form submissions, custom events
|
|
56
|
-
* - **Navigation events**: Route changes, tab switches
|
|
57
|
-
* - **Data events**: Reload triggers, refresh requests
|
|
58
|
-
* - **Coordination**: Communication between disconnected components
|
|
59
|
-
* - **Store inputs**: Triggering queries/mutations from components
|
|
60
|
-
* - **Event buses**: Decoupled event communication
|
|
61
|
-
*
|
|
62
|
-
* **Integration with Queries/Mutations:**
|
|
63
|
-
* - Bind to method using `afterRecomputation(source, callback)`
|
|
64
|
-
* - Query/mutation executes automatically when source emits
|
|
65
|
-
* - No manual method exposed (source-based triggering)
|
|
66
|
-
*
|
|
67
|
-
* **Listener Semantics:**
|
|
68
|
-
* - **Standard listener**: Returns `undefined` until source emits, then returns new values only
|
|
69
|
-
* - **preserveLastValue**: Returns last emitted value immediately, then tracks new values
|
|
70
|
-
* - Useful for late subscribers that need current state
|
|
71
|
-
*
|
|
72
|
-
* **Limitations:**
|
|
73
|
-
* Sources are signals and behave differently from observables.
|
|
74
|
-
* Understanding these three key limitations is important:
|
|
75
|
-
* - **Multiple sets in same cycle**: When a source is set multiple times during the same cycle
|
|
76
|
-
* (between the first set and the Change Detection that executes all consumer callbacks),
|
|
77
|
-
* consumers will only react once during CD and will only see the last set value.
|
|
78
|
-
* Intermediate values are discarded.
|
|
79
|
-
* - **Multiple sources order**: Within the same cycle, if multiple sources are triggered,
|
|
80
|
-
* consumers cannot determine the order in which the sources were set.
|
|
81
|
-
* The original emission sequence is not preserved.
|
|
82
|
-
* - **Consumer execution order**: When multiple sources are triggered in the same cycle,
|
|
83
|
-
* consumer callbacks are invoked in the order they were declared, not in the order
|
|
84
|
-
* their source producers were triggered.
|
|
85
|
-
* - **No synchronous intermediate value reactions**: Unlike observables, sources cannot react
|
|
86
|
-
* to each intermediate value synchronously. A mechanism similar to observables
|
|
87
|
-
* (or using native Observable API) without RxJS is being considered to enable
|
|
88
|
-
* synchronous reactions to intermediate values, matching the behavior currently
|
|
89
|
-
* offered by observables.
|
|
90
|
-
*
|
|
91
|
-
* @template T - The type of values emitted by the source
|
|
92
|
-
*
|
|
93
|
-
* @param options - Optional configuration:
|
|
94
|
-
* - `equal`: Custom equality function for change detection (prevents duplicate emissions)
|
|
95
|
-
* - `debugName`: Name for debugging purposes
|
|
96
|
-
*
|
|
97
|
-
* @returns A source object with:
|
|
98
|
-
* - `()`: Read current value (undefined until first emission)
|
|
99
|
-
* - `set(value)`: Emit a value to all listeners
|
|
100
|
-
* - `preserveLastValue`: Alternative signal that returns last value immediately
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* Basic source for user actions
|
|
104
|
-
* ```ts
|
|
105
|
-
* const { injectCraft } = craft(
|
|
106
|
-
* { name: '', providedIn: 'root' },
|
|
107
|
-
* craftSources({
|
|
108
|
-
* loadUser: source<string>(),
|
|
109
|
-
* }),
|
|
110
|
-
* craftQuery('user', ({ loadUser }) =>
|
|
111
|
-
* query({
|
|
112
|
-
* method: afterRecomputation(loadUser, (userId) => userId),
|
|
113
|
-
* loader: async ({ params }) => {
|
|
114
|
-
* const response = await fetch(`/api/users/${params}`);
|
|
115
|
-
* return response.json();
|
|
116
|
-
* },
|
|
117
|
-
* })
|
|
118
|
-
* )
|
|
119
|
-
* );
|
|
120
|
-
*
|
|
121
|
-
* const store = injectCraft();
|
|
122
|
-
*
|
|
123
|
-
* // Query executes automatically when source emits
|
|
124
|
-
* store.setLoadUser('user-123');
|
|
125
|
-
* // -> loadUser source emits 'user-123'
|
|
126
|
-
* // -> user query executes with params 'user-123'
|
|
127
|
-
*
|
|
128
|
-
* store.setLoadUser('user-456');
|
|
129
|
-
* // -> user query executes again with params 'user-456'
|
|
130
|
-
* ```
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* Source for form submission
|
|
134
|
-
* ```ts
|
|
135
|
-
* type FormData = { name: string; email: string };
|
|
136
|
-
*
|
|
137
|
-
* const { injectCraft } = craft(
|
|
138
|
-
* { name: '', providedIn: 'root' },
|
|
139
|
-
* craftSources({
|
|
140
|
-
* submitForm: source<FormData>(),
|
|
141
|
-
* }),
|
|
142
|
-
* craftMutations(({ submitForm }) => ({
|
|
143
|
-
* submit: mutation({
|
|
144
|
-
* method: afterRecomputation(submitForm, (data) => data),
|
|
145
|
-
* loader: async ({ params }) => {
|
|
146
|
-
* const response = await fetch('/api/submit', {
|
|
147
|
-
* method: 'POST',
|
|
148
|
-
* body: JSON.stringify(params),
|
|
149
|
-
* });
|
|
150
|
-
* return response.json();
|
|
151
|
-
* },
|
|
152
|
-
* }),
|
|
153
|
-
* }))
|
|
154
|
-
* );
|
|
155
|
-
*
|
|
156
|
-
* const store = injectCraft();
|
|
157
|
-
*
|
|
158
|
-
* // In component template:
|
|
159
|
-
* // <form (submit)="onSubmit()">
|
|
160
|
-
* // <input name="name" [(ngModel)]="formData.name" />
|
|
161
|
-
* // <input name="email" [(ngModel)]="formData.email" />
|
|
162
|
-
* // </form>
|
|
163
|
-
*
|
|
164
|
-
* onSubmit() {
|
|
165
|
-
* // Mutation executes automatically
|
|
166
|
-
* this.store.setSubmitForm(this.formData);
|
|
167
|
-
* // -> submitForm source emits
|
|
168
|
-
* // -> submit mutation executes
|
|
169
|
-
* }
|
|
170
|
-
* ```
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* Source for reload/refresh actions
|
|
174
|
-
* ```ts
|
|
175
|
-
* const { injectCraft } = craft(
|
|
176
|
-
* { name: '', providedIn: 'root' },
|
|
177
|
-
* craftSources({
|
|
178
|
-
* reload: source<void>(),
|
|
179
|
-
* }),
|
|
180
|
-
* craftQuery('data', ({ reload }) =>
|
|
181
|
-
* query(
|
|
182
|
-
* {
|
|
183
|
-
* params: () => ({}),
|
|
184
|
-
* loader: async () => {
|
|
185
|
-
* const response = await fetch('/api/data');
|
|
186
|
-
* return response.json();
|
|
187
|
-
* },
|
|
188
|
-
* },
|
|
189
|
-
* insertReloadOnSource(reload)
|
|
190
|
-
* )
|
|
191
|
-
* )
|
|
192
|
-
* );
|
|
193
|
-
*
|
|
194
|
-
* const store = injectCraft();
|
|
195
|
-
*
|
|
196
|
-
* // Trigger reload from anywhere
|
|
197
|
-
* store.setReload();
|
|
198
|
-
* // -> reload source emits
|
|
199
|
-
* // -> query reloads
|
|
200
|
-
*
|
|
201
|
-
* // In component:
|
|
202
|
-
* // <button (click)="store.setReload()">Refresh</button>
|
|
203
|
-
* ```
|
|
204
|
-
*
|
|
205
|
-
* @example
|
|
206
|
-
* Multiple sources for different actions
|
|
207
|
-
* ```ts
|
|
208
|
-
* const { injectCraft } = craft(
|
|
209
|
-
* { name: '', providedIn: 'root' },
|
|
210
|
-
* craftSources({
|
|
211
|
-
* addTodo: source<{ text: string }>(),
|
|
212
|
-
* deleteTodo: source<string>(),
|
|
213
|
-
* toggleTodo: source<string>(),
|
|
214
|
-
* }),
|
|
215
|
-
* craftMutations(({ addTodo, deleteTodo, toggleTodo }) => ({
|
|
216
|
-
* create: mutation({
|
|
217
|
-
* method: afterRecomputation(addTodo, (data) => data),
|
|
218
|
-
* loader: async ({ params }) => {
|
|
219
|
-
* const response = await fetch('/api/todos', {
|
|
220
|
-
* method: 'POST',
|
|
221
|
-
* body: JSON.stringify(params),
|
|
222
|
-
* });
|
|
223
|
-
* return response.json();
|
|
224
|
-
* },
|
|
225
|
-
* }),
|
|
226
|
-
* delete: mutation({
|
|
227
|
-
* method: afterRecomputation(deleteTodo, (id) => id),
|
|
228
|
-
* loader: async ({ params }) => {
|
|
229
|
-
* await fetch(`/api/todos/${params}`, { method: 'DELETE' });
|
|
230
|
-
* return { deleted: true };
|
|
231
|
-
* },
|
|
232
|
-
* }),
|
|
233
|
-
* toggle: mutation({
|
|
234
|
-
* method: afterRecomputation(toggleTodo, (id) => id),
|
|
235
|
-
* loader: async ({ params }) => {
|
|
236
|
-
* const response = await fetch(`/api/todos/${params}/toggle`, {
|
|
237
|
-
* method: 'PATCH',
|
|
238
|
-
* });
|
|
239
|
-
* return response.json();
|
|
240
|
-
* },
|
|
241
|
-
* }),
|
|
242
|
-
* }))
|
|
243
|
-
* );
|
|
244
|
-
*
|
|
245
|
-
* const store = injectCraft();
|
|
246
|
-
*
|
|
247
|
-
* // Different actions trigger different mutations
|
|
248
|
-
* store.setAddTodo({ text: 'Buy milk' });
|
|
249
|
-
* store.setToggleTodo('todo-123');
|
|
250
|
-
* store.setDeleteTodo('todo-456');
|
|
251
|
-
* ```
|
|
252
|
-
*
|
|
253
|
-
* @example
|
|
254
|
-
* Late listener with preserveLastValue
|
|
255
|
-
* ```ts
|
|
256
|
-
* const mySource = source<string>();
|
|
257
|
-
*
|
|
258
|
-
* // Early listener
|
|
259
|
-
* const listener1 = computed(() => mySource());
|
|
260
|
-
* console.log(listener1()); // undefined
|
|
261
|
-
*
|
|
262
|
-
* // Emit value
|
|
263
|
-
* mySource.set('Hello');
|
|
264
|
-
* console.log(listener1()); // 'Hello'
|
|
265
|
-
*
|
|
266
|
-
* // Late listener (after emission)
|
|
267
|
-
* const listener2 = computed(() => mySource());
|
|
268
|
-
* console.log(listener2()); // undefined (doesn't get previous emission)
|
|
269
|
-
*
|
|
270
|
-
* mySource.set('World');
|
|
271
|
-
* console.log(listener1()); // 'World'
|
|
272
|
-
* console.log(listener2()); // 'World'
|
|
273
|
-
*
|
|
274
|
-
* // Using preserveLastValue for late listeners
|
|
275
|
-
* const listener3 = computed(() => mySource.preserveLastValue());
|
|
276
|
-
* console.log(listener3()); // 'World' (gets last value immediately)
|
|
277
|
-
* ```
|
|
278
|
-
*
|
|
279
|
-
* @example
|
|
280
|
-
* Custom equality to prevent duplicate emissions
|
|
281
|
-
* ```ts
|
|
282
|
-
* type Params = { id: string; timestamp: number };
|
|
283
|
-
*
|
|
284
|
-
* const paramsSource = source<Params>({
|
|
285
|
-
* equal: (a, b) => a?.id === b?.id, // Compare only by id
|
|
286
|
-
* });
|
|
287
|
-
*
|
|
288
|
-
* const listener = computed(() => paramsSource());
|
|
289
|
-
*
|
|
290
|
-
* paramsSource.set({ id: 'item-1', timestamp: Date.now() });
|
|
291
|
-
* // -> listener receives value
|
|
292
|
-
*
|
|
293
|
-
* paramsSource.set({ id: 'item-1', timestamp: Date.now() });
|
|
294
|
-
* // -> listener does NOT receive value (same id)
|
|
295
|
-
*
|
|
296
|
-
* paramsSource.set({ id: 'item-2', timestamp: Date.now() });
|
|
297
|
-
* // -> listener receives value (different id)
|
|
298
|
-
* ```
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* Source for coordinating multiple components
|
|
302
|
-
* ```ts
|
|
303
|
-
* // Global source (outside component)
|
|
304
|
-
* const refreshAllSource = source<void>();
|
|
305
|
-
*
|
|
306
|
-
* // Component A
|
|
307
|
-
* @Component({
|
|
308
|
-
* selector: 'app-data-view',
|
|
309
|
-
* template: '...',
|
|
310
|
-
* })
|
|
311
|
-
* export class DataViewComponent {
|
|
312
|
-
* { injectCraft } = craft(
|
|
313
|
-
* { name: '', providedIn: 'root' },
|
|
314
|
-
* craftQuery('data', () =>
|
|
315
|
-
* query(
|
|
316
|
-
* {
|
|
317
|
-
* params: () => ({}),
|
|
318
|
-
* loader: async () => {
|
|
319
|
-
* const response = await fetch('/api/data');
|
|
320
|
-
* return response.json();
|
|
321
|
-
* },
|
|
322
|
-
* },
|
|
323
|
-
* insertReloadOnSource(refreshAllSource)
|
|
324
|
-
* )
|
|
325
|
-
* )
|
|
326
|
-
* );
|
|
327
|
-
*
|
|
328
|
-
* store = this.injectCraft();
|
|
329
|
-
* }
|
|
330
|
-
*
|
|
331
|
-
* // Component B
|
|
332
|
-
* @Component({
|
|
333
|
-
* selector: 'app-refresh-button',
|
|
334
|
-
* template: '<button (click)="refresh()">Refresh All</button>',
|
|
335
|
-
* })
|
|
336
|
-
* export class RefreshButtonComponent {
|
|
337
|
-
* refresh() {
|
|
338
|
-
* // Triggers refresh in all components listening to this source
|
|
339
|
-
* refreshAllSource.set();
|
|
340
|
-
* }
|
|
341
|
-
* }
|
|
342
|
-
* ```
|
|
343
|
-
*
|
|
344
|
-
* @example
|
|
345
|
-
* Source with complex payload
|
|
346
|
-
* ```ts
|
|
347
|
-
* type SearchParams = {
|
|
348
|
-
* query: string;
|
|
349
|
-
* filters: string[];
|
|
350
|
-
* page: number;
|
|
351
|
-
* };
|
|
352
|
-
*
|
|
353
|
-
* const { injectCraft } = craft(
|
|
354
|
-
* { name: '', providedIn: 'root' },
|
|
355
|
-
* craftSources({
|
|
356
|
-
* search: source<SearchParams>(),
|
|
357
|
-
* }),
|
|
358
|
-
* craftQuery('results', ({ search }) =>
|
|
359
|
-
* query({
|
|
360
|
-
* method: afterRecomputation(search, (params) => params),
|
|
361
|
-
* loader: async ({ params }) => {
|
|
362
|
-
* const queryString = new URLSearchParams({
|
|
363
|
-
* q: params.query,
|
|
364
|
-
* filters: params.filters.join(','),
|
|
365
|
-
* page: String(params.page),
|
|
366
|
-
* });
|
|
367
|
-
* const response = await fetch(`/api/search?${queryString}`);
|
|
368
|
-
* return response.json();
|
|
369
|
-
* },
|
|
370
|
-
* })
|
|
371
|
-
* )
|
|
372
|
-
* );
|
|
373
|
-
*
|
|
374
|
-
* const store = injectCraft();
|
|
375
|
-
*
|
|
376
|
-
* // Emit complex search parameters
|
|
377
|
-
* store.setSearch({
|
|
378
|
-
* query: 'angular',
|
|
379
|
-
* filters: ['tutorial', 'advanced'],
|
|
380
|
-
* page: 1,
|
|
381
|
-
* });
|
|
382
|
-
* ```
|
|
383
|
-
*/
|
|
384
|
-
declare function signalSource<T>(options?: {
|
|
385
|
-
equal?: ValueEqualityFn<NoInfer<T> | undefined>;
|
|
386
|
-
debugName?: string;
|
|
387
|
-
}): SignalSource<T>;
|
|
388
26
|
|
|
389
27
|
/**
|
|
390
28
|
* Creates a derived readonly source that transforms source emissions through a callback function.
|
|
@@ -691,7 +329,7 @@ declare function signalSource<T>(options?: {
|
|
|
691
329
|
* // -> mutation receives exact same object
|
|
692
330
|
* ```
|
|
693
331
|
*/
|
|
694
|
-
declare function afterRecomputation<State, SourceType>(_source:
|
|
332
|
+
declare function afterRecomputation<State, SourceType>(_source: ReadonlySource<SourceType>, callback: (source: SourceType) => State): ReadonlySource<State>;
|
|
695
333
|
|
|
696
334
|
type ContextConstraints = {
|
|
697
335
|
props: {};
|
|
@@ -2167,6 +1805,368 @@ declare function craft<outputs1 extends ContextConstraints, standaloneOutputs1 e
|
|
|
2167
1805
|
implements?: ToImplementContract;
|
|
2168
1806
|
}>;
|
|
2169
1807
|
|
|
1808
|
+
type SignalSource<T> = Signal<T | undefined> & {
|
|
1809
|
+
set: (value: T) => void;
|
|
1810
|
+
preserveLastValue: Signal<T | undefined>;
|
|
1811
|
+
} & SourceBranded;
|
|
1812
|
+
/**
|
|
1813
|
+
* Creates a source for event-driven communication with lazy emission semantics.
|
|
1814
|
+
*
|
|
1815
|
+
* Sources are the foundation of event-driven patterns in ng-craft, enabling:
|
|
1816
|
+
* - Discrete event emissions (unlike continuous signals)
|
|
1817
|
+
* - Lazy behavior (undefined until explicitly set)
|
|
1818
|
+
* - Decoupled communication between components and stores
|
|
1819
|
+
* - Automatic triggering of queries, mutations, and async methods
|
|
1820
|
+
* - Multi-listener support with independent subscription timing
|
|
1821
|
+
*
|
|
1822
|
+
* @remarks
|
|
1823
|
+
* **Core Concept:**
|
|
1824
|
+
* Sources implement event emitter pattern with reactive semantics:
|
|
1825
|
+
* - Emit only when explicitly set (not on every read like signals)
|
|
1826
|
+
* - Listeners receive `undefined` on first read (lazy semantics)
|
|
1827
|
+
* - New listeners don't receive previous emissions by default
|
|
1828
|
+
* - Use `preserveLastValue` to get the last emitted value immediately
|
|
1829
|
+
*
|
|
1830
|
+
* **Difference from Signals:**
|
|
1831
|
+
* - **Signals**: Always have a value, recompute on access, continuous state
|
|
1832
|
+
* - **Sources**: Emit on explicit set, lazy by default, discrete events
|
|
1833
|
+
* - Sources are for events/actions, signals are for state
|
|
1834
|
+
*
|
|
1835
|
+
* **Use Cases:**
|
|
1836
|
+
* - **User actions**: Button clicks, form submissions, custom events
|
|
1837
|
+
* - **Navigation events**: Route changes, tab switches
|
|
1838
|
+
* - **Data events**: Reload triggers, refresh requests
|
|
1839
|
+
* - **Coordination**: Communication between disconnected components
|
|
1840
|
+
* - **Store inputs**: Triggering queries/mutations from components
|
|
1841
|
+
* - **Event buses**: Decoupled event communication
|
|
1842
|
+
*
|
|
1843
|
+
* **Integration with Queries/Mutations:**
|
|
1844
|
+
* - Bind to method using `afterRecomputation(source, callback)`
|
|
1845
|
+
* - Query/mutation executes automatically when source emits
|
|
1846
|
+
* - No manual method exposed (source-based triggering)
|
|
1847
|
+
*
|
|
1848
|
+
* **Listener Semantics:**
|
|
1849
|
+
* - **Standard listener**: Returns `undefined` until source emits, then returns new values only
|
|
1850
|
+
* - **preserveLastValue**: Returns last emitted value immediately, then tracks new values
|
|
1851
|
+
* - Useful for late subscribers that need current state
|
|
1852
|
+
*
|
|
1853
|
+
* **Limitations:**
|
|
1854
|
+
* Sources are signals and behave differently from observables.
|
|
1855
|
+
* Understanding these three key limitations is important:
|
|
1856
|
+
* - **Multiple sets in same cycle**: When a source is set multiple times during the same cycle
|
|
1857
|
+
* (between the first set and the Change Detection that executes all consumer callbacks),
|
|
1858
|
+
* consumers will only react once during CD and will only see the last set value.
|
|
1859
|
+
* Intermediate values are discarded.
|
|
1860
|
+
* - **Multiple sources order**: Within the same cycle, if multiple sources are triggered,
|
|
1861
|
+
* consumers cannot determine the order in which the sources were set.
|
|
1862
|
+
* The original emission sequence is not preserved.
|
|
1863
|
+
* - **Consumer execution order**: When multiple sources are triggered in the same cycle,
|
|
1864
|
+
* consumer callbacks are invoked in the order they were declared, not in the order
|
|
1865
|
+
* their source producers were triggered.
|
|
1866
|
+
* - **No synchronous intermediate value reactions**: Unlike observables, sources cannot react
|
|
1867
|
+
* to each intermediate value synchronously. A mechanism similar to observables
|
|
1868
|
+
* (or using native Observable API) without RxJS is being considered to enable
|
|
1869
|
+
* synchronous reactions to intermediate values, matching the behavior currently
|
|
1870
|
+
* offered by observables.
|
|
1871
|
+
*
|
|
1872
|
+
* @template T - The type of values emitted by the source
|
|
1873
|
+
*
|
|
1874
|
+
* @param options - Optional configuration:
|
|
1875
|
+
* - `equal`: Custom equality function for change detection (prevents duplicate emissions)
|
|
1876
|
+
* - `debugName`: Name for debugging purposes
|
|
1877
|
+
*
|
|
1878
|
+
* @returns A source object with:
|
|
1879
|
+
* - `()`: Read current value (undefined until first emission)
|
|
1880
|
+
* - `set(value)`: Emit a value to all listeners
|
|
1881
|
+
* - `preserveLastValue`: Alternative signal that returns last value immediately
|
|
1882
|
+
*
|
|
1883
|
+
* @example
|
|
1884
|
+
* Basic source for user actions
|
|
1885
|
+
* ```ts
|
|
1886
|
+
* const { injectCraft } = craft(
|
|
1887
|
+
* { name: '', providedIn: 'root' },
|
|
1888
|
+
* craftSources({
|
|
1889
|
+
* loadUser: source<string>(),
|
|
1890
|
+
* }),
|
|
1891
|
+
* craftQuery('user', ({ loadUser }) =>
|
|
1892
|
+
* query({
|
|
1893
|
+
* method: afterRecomputation(loadUser, (userId) => userId),
|
|
1894
|
+
* loader: async ({ params }) => {
|
|
1895
|
+
* const response = await fetch(`/api/users/${params}`);
|
|
1896
|
+
* return response.json();
|
|
1897
|
+
* },
|
|
1898
|
+
* })
|
|
1899
|
+
* )
|
|
1900
|
+
* );
|
|
1901
|
+
*
|
|
1902
|
+
* const store = injectCraft();
|
|
1903
|
+
*
|
|
1904
|
+
* // Query executes automatically when source emits
|
|
1905
|
+
* store.setLoadUser('user-123');
|
|
1906
|
+
* // -> loadUser source emits 'user-123'
|
|
1907
|
+
* // -> user query executes with params 'user-123'
|
|
1908
|
+
*
|
|
1909
|
+
* store.setLoadUser('user-456');
|
|
1910
|
+
* // -> user query executes again with params 'user-456'
|
|
1911
|
+
* ```
|
|
1912
|
+
*
|
|
1913
|
+
* @example
|
|
1914
|
+
* Source for form submission
|
|
1915
|
+
* ```ts
|
|
1916
|
+
* type FormData = { name: string; email: string };
|
|
1917
|
+
*
|
|
1918
|
+
* const { injectCraft } = craft(
|
|
1919
|
+
* { name: '', providedIn: 'root' },
|
|
1920
|
+
* craftSources({
|
|
1921
|
+
* submitForm: source<FormData>(),
|
|
1922
|
+
* }),
|
|
1923
|
+
* craftMutations(({ submitForm }) => ({
|
|
1924
|
+
* submit: mutation({
|
|
1925
|
+
* method: afterRecomputation(submitForm, (data) => data),
|
|
1926
|
+
* loader: async ({ params }) => {
|
|
1927
|
+
* const response = await fetch('/api/submit', {
|
|
1928
|
+
* method: 'POST',
|
|
1929
|
+
* body: JSON.stringify(params),
|
|
1930
|
+
* });
|
|
1931
|
+
* return response.json();
|
|
1932
|
+
* },
|
|
1933
|
+
* }),
|
|
1934
|
+
* }))
|
|
1935
|
+
* );
|
|
1936
|
+
*
|
|
1937
|
+
* const store = injectCraft();
|
|
1938
|
+
*
|
|
1939
|
+
* // In component template:
|
|
1940
|
+
* // <form (submit)="onSubmit()">
|
|
1941
|
+
* // <input name="name" [(ngModel)]="formData.name" />
|
|
1942
|
+
* // <input name="email" [(ngModel)]="formData.email" />
|
|
1943
|
+
* // </form>
|
|
1944
|
+
*
|
|
1945
|
+
* onSubmit() {
|
|
1946
|
+
* // Mutation executes automatically
|
|
1947
|
+
* this.store.setSubmitForm(this.formData);
|
|
1948
|
+
* // -> submitForm source emits
|
|
1949
|
+
* // -> submit mutation executes
|
|
1950
|
+
* }
|
|
1951
|
+
* ```
|
|
1952
|
+
*
|
|
1953
|
+
* @example
|
|
1954
|
+
* Source for reload/refresh actions
|
|
1955
|
+
* ```ts
|
|
1956
|
+
* const { injectCraft } = craft(
|
|
1957
|
+
* { name: '', providedIn: 'root' },
|
|
1958
|
+
* craftSources({
|
|
1959
|
+
* reload: source<void>(),
|
|
1960
|
+
* }),
|
|
1961
|
+
* craftQuery('data', ({ reload }) =>
|
|
1962
|
+
* query(
|
|
1963
|
+
* {
|
|
1964
|
+
* params: () => ({}),
|
|
1965
|
+
* loader: async () => {
|
|
1966
|
+
* const response = await fetch('/api/data');
|
|
1967
|
+
* return response.json();
|
|
1968
|
+
* },
|
|
1969
|
+
* },
|
|
1970
|
+
* insertReloadOnSource(reload)
|
|
1971
|
+
* )
|
|
1972
|
+
* )
|
|
1973
|
+
* );
|
|
1974
|
+
*
|
|
1975
|
+
* const store = injectCraft();
|
|
1976
|
+
*
|
|
1977
|
+
* // Trigger reload from anywhere
|
|
1978
|
+
* store.setReload();
|
|
1979
|
+
* // -> reload source emits
|
|
1980
|
+
* // -> query reloads
|
|
1981
|
+
*
|
|
1982
|
+
* // In component:
|
|
1983
|
+
* // <button (click)="store.setReload()">Refresh</button>
|
|
1984
|
+
* ```
|
|
1985
|
+
*
|
|
1986
|
+
* @example
|
|
1987
|
+
* Multiple sources for different actions
|
|
1988
|
+
* ```ts
|
|
1989
|
+
* const { injectCraft } = craft(
|
|
1990
|
+
* { name: '', providedIn: 'root' },
|
|
1991
|
+
* craftSources({
|
|
1992
|
+
* addTodo: source<{ text: string }>(),
|
|
1993
|
+
* deleteTodo: source<string>(),
|
|
1994
|
+
* toggleTodo: source<string>(),
|
|
1995
|
+
* }),
|
|
1996
|
+
* craftMutations(({ addTodo, deleteTodo, toggleTodo }) => ({
|
|
1997
|
+
* create: mutation({
|
|
1998
|
+
* method: afterRecomputation(addTodo, (data) => data),
|
|
1999
|
+
* loader: async ({ params }) => {
|
|
2000
|
+
* const response = await fetch('/api/todos', {
|
|
2001
|
+
* method: 'POST',
|
|
2002
|
+
* body: JSON.stringify(params),
|
|
2003
|
+
* });
|
|
2004
|
+
* return response.json();
|
|
2005
|
+
* },
|
|
2006
|
+
* }),
|
|
2007
|
+
* delete: mutation({
|
|
2008
|
+
* method: afterRecomputation(deleteTodo, (id) => id),
|
|
2009
|
+
* loader: async ({ params }) => {
|
|
2010
|
+
* await fetch(`/api/todos/${params}`, { method: 'DELETE' });
|
|
2011
|
+
* return { deleted: true };
|
|
2012
|
+
* },
|
|
2013
|
+
* }),
|
|
2014
|
+
* toggle: mutation({
|
|
2015
|
+
* method: afterRecomputation(toggleTodo, (id) => id),
|
|
2016
|
+
* loader: async ({ params }) => {
|
|
2017
|
+
* const response = await fetch(`/api/todos/${params}/toggle`, {
|
|
2018
|
+
* method: 'PATCH',
|
|
2019
|
+
* });
|
|
2020
|
+
* return response.json();
|
|
2021
|
+
* },
|
|
2022
|
+
* }),
|
|
2023
|
+
* }))
|
|
2024
|
+
* );
|
|
2025
|
+
*
|
|
2026
|
+
* const store = injectCraft();
|
|
2027
|
+
*
|
|
2028
|
+
* // Different actions trigger different mutations
|
|
2029
|
+
* store.setAddTodo({ text: 'Buy milk' });
|
|
2030
|
+
* store.setToggleTodo('todo-123');
|
|
2031
|
+
* store.setDeleteTodo('todo-456');
|
|
2032
|
+
* ```
|
|
2033
|
+
*
|
|
2034
|
+
* @example
|
|
2035
|
+
* Late listener with preserveLastValue
|
|
2036
|
+
* ```ts
|
|
2037
|
+
* const mySource = source<string>();
|
|
2038
|
+
*
|
|
2039
|
+
* // Early listener
|
|
2040
|
+
* const listener1 = computed(() => mySource());
|
|
2041
|
+
* console.log(listener1()); // undefined
|
|
2042
|
+
*
|
|
2043
|
+
* // Emit value
|
|
2044
|
+
* mySource.set('Hello');
|
|
2045
|
+
* console.log(listener1()); // 'Hello'
|
|
2046
|
+
*
|
|
2047
|
+
* // Late listener (after emission)
|
|
2048
|
+
* const listener2 = computed(() => mySource());
|
|
2049
|
+
* console.log(listener2()); // undefined (doesn't get previous emission)
|
|
2050
|
+
*
|
|
2051
|
+
* mySource.set('World');
|
|
2052
|
+
* console.log(listener1()); // 'World'
|
|
2053
|
+
* console.log(listener2()); // 'World'
|
|
2054
|
+
*
|
|
2055
|
+
* // Using preserveLastValue for late listeners
|
|
2056
|
+
* const listener3 = computed(() => mySource.preserveLastValue());
|
|
2057
|
+
* console.log(listener3()); // 'World' (gets last value immediately)
|
|
2058
|
+
* ```
|
|
2059
|
+
*
|
|
2060
|
+
* @example
|
|
2061
|
+
* Custom equality to prevent duplicate emissions
|
|
2062
|
+
* ```ts
|
|
2063
|
+
* type Params = { id: string; timestamp: number };
|
|
2064
|
+
*
|
|
2065
|
+
* const paramsSource = source<Params>({
|
|
2066
|
+
* equal: (a, b) => a?.id === b?.id, // Compare only by id
|
|
2067
|
+
* });
|
|
2068
|
+
*
|
|
2069
|
+
* const listener = computed(() => paramsSource());
|
|
2070
|
+
*
|
|
2071
|
+
* paramsSource.set({ id: 'item-1', timestamp: Date.now() });
|
|
2072
|
+
* // -> listener receives value
|
|
2073
|
+
*
|
|
2074
|
+
* paramsSource.set({ id: 'item-1', timestamp: Date.now() });
|
|
2075
|
+
* // -> listener does NOT receive value (same id)
|
|
2076
|
+
*
|
|
2077
|
+
* paramsSource.set({ id: 'item-2', timestamp: Date.now() });
|
|
2078
|
+
* // -> listener receives value (different id)
|
|
2079
|
+
* ```
|
|
2080
|
+
*
|
|
2081
|
+
* @example
|
|
2082
|
+
* Source for coordinating multiple components
|
|
2083
|
+
* ```ts
|
|
2084
|
+
* // Global source (outside component)
|
|
2085
|
+
* const refreshAllSource = source<void>();
|
|
2086
|
+
*
|
|
2087
|
+
* // Component A
|
|
2088
|
+
* @Component({
|
|
2089
|
+
* selector: 'app-data-view',
|
|
2090
|
+
* template: '...',
|
|
2091
|
+
* })
|
|
2092
|
+
* export class DataViewComponent {
|
|
2093
|
+
* { injectCraft } = craft(
|
|
2094
|
+
* { name: '', providedIn: 'root' },
|
|
2095
|
+
* craftQuery('data', () =>
|
|
2096
|
+
* query(
|
|
2097
|
+
* {
|
|
2098
|
+
* params: () => ({}),
|
|
2099
|
+
* loader: async () => {
|
|
2100
|
+
* const response = await fetch('/api/data');
|
|
2101
|
+
* return response.json();
|
|
2102
|
+
* },
|
|
2103
|
+
* },
|
|
2104
|
+
* insertReloadOnSource(refreshAllSource)
|
|
2105
|
+
* )
|
|
2106
|
+
* )
|
|
2107
|
+
* );
|
|
2108
|
+
*
|
|
2109
|
+
* store = this.injectCraft();
|
|
2110
|
+
* }
|
|
2111
|
+
*
|
|
2112
|
+
* // Component B
|
|
2113
|
+
* @Component({
|
|
2114
|
+
* selector: 'app-refresh-button',
|
|
2115
|
+
* template: '<button (click)="refresh()">Refresh All</button>',
|
|
2116
|
+
* })
|
|
2117
|
+
* export class RefreshButtonComponent {
|
|
2118
|
+
* refresh() {
|
|
2119
|
+
* // Triggers refresh in all components listening to this source
|
|
2120
|
+
* refreshAllSource.set();
|
|
2121
|
+
* }
|
|
2122
|
+
* }
|
|
2123
|
+
* ```
|
|
2124
|
+
*
|
|
2125
|
+
* @example
|
|
2126
|
+
* Source with complex payload
|
|
2127
|
+
* ```ts
|
|
2128
|
+
* type SearchParams = {
|
|
2129
|
+
* query: string;
|
|
2130
|
+
* filters: string[];
|
|
2131
|
+
* page: number;
|
|
2132
|
+
* };
|
|
2133
|
+
*
|
|
2134
|
+
* const { injectCraft } = craft(
|
|
2135
|
+
* { name: '', providedIn: 'root' },
|
|
2136
|
+
* craftSources({
|
|
2137
|
+
* search: source<SearchParams>(),
|
|
2138
|
+
* }),
|
|
2139
|
+
* craftQuery('results', ({ search }) =>
|
|
2140
|
+
* query({
|
|
2141
|
+
* method: afterRecomputation(search, (params) => params),
|
|
2142
|
+
* loader: async ({ params }) => {
|
|
2143
|
+
* const queryString = new URLSearchParams({
|
|
2144
|
+
* q: params.query,
|
|
2145
|
+
* filters: params.filters.join(','),
|
|
2146
|
+
* page: String(params.page),
|
|
2147
|
+
* });
|
|
2148
|
+
* const response = await fetch(`/api/search?${queryString}`);
|
|
2149
|
+
* return response.json();
|
|
2150
|
+
* },
|
|
2151
|
+
* })
|
|
2152
|
+
* )
|
|
2153
|
+
* );
|
|
2154
|
+
*
|
|
2155
|
+
* const store = injectCraft();
|
|
2156
|
+
*
|
|
2157
|
+
* // Emit complex search parameters
|
|
2158
|
+
* store.setSearch({
|
|
2159
|
+
* query: 'angular',
|
|
2160
|
+
* filters: ['tutorial', 'advanced'],
|
|
2161
|
+
* page: 1,
|
|
2162
|
+
* });
|
|
2163
|
+
* ```
|
|
2164
|
+
*/
|
|
2165
|
+
declare function signalSource<T>(options?: {
|
|
2166
|
+
equal?: ValueEqualityFn<NoInfer<T> | undefined>;
|
|
2167
|
+
debugName?: string;
|
|
2168
|
+
}): SignalSource<T>;
|
|
2169
|
+
|
|
2170
2170
|
type ExtractSignalPropsAndMethods<State, StateKeysTuple, Acc extends {
|
|
2171
2171
|
props: {};
|
|
2172
2172
|
methods: Record<string, Function>;
|
|
@@ -9265,5 +9265,130 @@ declare function insertFormSubmit<FormValue, MutationValue, MutationParams, Muta
|
|
|
9265
9265
|
submitExceptions: Signal<ToSubmitExceptions<InsertMetaInCraftExceptionIfExists<MutationExceptions['params'], 'params', MutationIdentifier> | InsertMetaInCraftExceptionIfExists<MutationExceptions['loader'], 'loader', MutationIdentifier>, SuccessExceptions, ErrorExceptions, ExceptionExceptions, FormIdentifier>[]>;
|
|
9266
9266
|
}>;
|
|
9267
9267
|
|
|
9268
|
-
|
|
9268
|
+
type ArrayObjectDeepPath<State extends object> = ObjectDeepPath<State> extends infer Path ? Path extends string ? AccessTypeObjectPropertyByDottedPath<State, DottedPathPathToTuple<Path>> extends Array<any> ? Path : never : never : never;
|
|
9269
|
+
type DottedPathToCamel<Path extends string> = Path extends `${infer Head}.${infer Tail}` ? `${Head}${Capitalize<DottedPathToCamel<Tail>>}` : Path;
|
|
9270
|
+
type EntitiesUtilsToMap<EntityHelperFns, Entity, K, HasStateIdentifier, StateIdentifier, HasPath, Path, Acc = {}> = EntityHelperFns extends [infer First, ...infer Rest] ? First extends (data: infer Payload) => infer R ? R extends EntitiesUtilBrand<infer Name> ? EntitiesUtilsToMap<Rest, Entity, K, HasStateIdentifier, StateIdentifier, HasPath, Path, Acc & {
|
|
9271
|
+
[key in Name as `${HasPath extends true ? `${DottedPathToCamel<Path & string>}${Capitalize<string & key>}` : key & string}`]: (payload: MergeObject$1<{
|
|
9272
|
+
[key in Exclude<keyof Payload, 'identifier'> as `${key extends 'entities' ? never : key & string}`]: key extends 'entity' ? Entity : key extends 'ids' ? K[] : key extends 'newEntities' ? Entity[] : `Not implemented mapping for ${key & string}`;
|
|
9273
|
+
}, HasStateIdentifier extends true ? {
|
|
9274
|
+
select: StateIdentifier extends (...args: any) => infer R ? R : never;
|
|
9275
|
+
} : {}>) => void;
|
|
9276
|
+
}> : 'No EntitiesBranded Name Detected' : false : Acc;
|
|
9277
|
+
/**
|
|
9278
|
+
* Creates an insertion that adds entity collection management methods to state, query, or queryParam primitives.
|
|
9279
|
+
*
|
|
9280
|
+
* Provides type-safe manipulation of arrays of entities with operations like add, remove, update, and upsert.
|
|
9281
|
+
* Supports nested properties via dot notation paths and custom entity identifiers.
|
|
9282
|
+
*
|
|
9283
|
+
* @template State - The state type (array or object containing arrays)
|
|
9284
|
+
* @template K - The type of entity identifiers (string or number)
|
|
9285
|
+
* @template PreviousInsertionsOutputs - Combined outputs from previous insertions
|
|
9286
|
+
* @template EntityHelperFns - Tuple type of entity utility functions to expose
|
|
9287
|
+
* @template StateIdentifier - Type of identifier function for parallel queries
|
|
9288
|
+
* @template Path - Dot-notation path to nested array (inferred from state structure)
|
|
9289
|
+
*
|
|
9290
|
+
* @param config - Configuration object
|
|
9291
|
+
* @param config.methods - Array of entity utility functions (addOne, removeOne, updateOne, etc.) to expose as methods
|
|
9292
|
+
* @param config.identifier - Optional custom function to extract unique ID from entities.
|
|
9293
|
+
* Defaults to `entity.id` for objects or `entity` for primitives
|
|
9294
|
+
* @param config.path - Optional dot-notation path to nested array property (e.g., 'catalog.products').
|
|
9295
|
+
* Method names are prefixed with camelCase path when provided
|
|
9296
|
+
*
|
|
9297
|
+
* @returns Insertion function that adds entity management methods to the primitive
|
|
9298
|
+
*
|
|
9299
|
+
* @example
|
|
9300
|
+
* // Basic usage with primitives
|
|
9301
|
+
* const tags = state(
|
|
9302
|
+
* [] as string[],
|
|
9303
|
+
* insertEntities({
|
|
9304
|
+
* methods: [addOne, addMany, removeOne],
|
|
9305
|
+
* })
|
|
9306
|
+
* );
|
|
9307
|
+
* tags.addOne({ entity: 'typescript' });
|
|
9308
|
+
* tags.addMany({ newEntities: ['angular', 'signals'] });
|
|
9309
|
+
*
|
|
9310
|
+
* @example
|
|
9311
|
+
* // With objects having default id property
|
|
9312
|
+
* interface Product {
|
|
9313
|
+
* id: string;
|
|
9314
|
+
* name: string;
|
|
9315
|
+
* price: number;
|
|
9316
|
+
* }
|
|
9317
|
+
* const products = state(
|
|
9318
|
+
* [] as Product[],
|
|
9319
|
+
* insertEntities({
|
|
9320
|
+
* methods: [addOne, setOne, removeOne],
|
|
9321
|
+
* })
|
|
9322
|
+
* );
|
|
9323
|
+
* products.addOne({ entity: { id: '1', name: 'Laptop', price: 999 } });
|
|
9324
|
+
*
|
|
9325
|
+
* @example
|
|
9326
|
+
* // With custom identifier
|
|
9327
|
+
* interface User {
|
|
9328
|
+
* uuid: string;
|
|
9329
|
+
* name: string;
|
|
9330
|
+
* }
|
|
9331
|
+
* const users = state(
|
|
9332
|
+
* [] as User[],
|
|
9333
|
+
* insertEntities({
|
|
9334
|
+
* methods: [setOne, removeOne],
|
|
9335
|
+
* identifier: (user) => user.uuid,
|
|
9336
|
+
* })
|
|
9337
|
+
* );
|
|
9338
|
+
*
|
|
9339
|
+
* @example
|
|
9340
|
+
* // With nested path
|
|
9341
|
+
* interface Catalog {
|
|
9342
|
+
* total: number;
|
|
9343
|
+
* products: Array<{ id: string; name: string }>;
|
|
9344
|
+
* }
|
|
9345
|
+
* const catalog = state(
|
|
9346
|
+
* { total: 0, products: [] } as Catalog,
|
|
9347
|
+
* insertEntities({
|
|
9348
|
+
* methods: [addMany, removeOne],
|
|
9349
|
+
* path: 'products',
|
|
9350
|
+
* })
|
|
9351
|
+
* );
|
|
9352
|
+
* catalog.productsAddMany({ newEntities: [{ id: '1', name: 'Item' }] });
|
|
9353
|
+
*
|
|
9354
|
+
* @example
|
|
9355
|
+
* // With parallel queries
|
|
9356
|
+
* const userQuery = query(
|
|
9357
|
+
* {
|
|
9358
|
+
* params: () => 'userId',
|
|
9359
|
+
* identifier: (params) => params,
|
|
9360
|
+
* loader: async ({ params }) => fetchUserPosts(params),
|
|
9361
|
+
* },
|
|
9362
|
+
* insertEntities({
|
|
9363
|
+
* methods: [addOne],
|
|
9364
|
+
* })
|
|
9365
|
+
* );
|
|
9366
|
+
* userQuery.addOne({
|
|
9367
|
+
* select: 'user-123', // Target specific query instance
|
|
9368
|
+
* entity: { id: 'post-1', title: 'New Post' },
|
|
9369
|
+
* });
|
|
9370
|
+
*
|
|
9371
|
+
* @see {@link https://github.com/ng-angular-stack/ng-craft/blob/main/apps/docs/insertions/insert-entities.md | insertEntities Documentation}
|
|
9372
|
+
*/
|
|
9373
|
+
declare function insertEntities<State, K extends string | number, PreviousInsertionsOutputs, const EntityHelperFns extends unknown[], StateIdentifier, const Path = State extends Array<infer Entity> ? never : State extends object ? ArrayObjectDeepPath<State> : never, StateType = State extends Array<infer R> ? R : State extends object ? Path extends string ? AccessTypeObjectPropertyByDottedPath<State, DottedPathPathToTuple<Path>> extends Array<infer Entity> ? Entity : never : never : never, HasStateIdentifier = [unknown] extends [StateIdentifier] ? false : StateIdentifier extends (...args: any) => infer R ? [unknown] extends [R] ? false : true : false, IsEntityIdentifierOptional = StateType extends {
|
|
9374
|
+
id: NoInfer<K>;
|
|
9375
|
+
} ? true : StateType extends string | number ? true : false>(config: {
|
|
9376
|
+
methods: EntityHelperFns;
|
|
9377
|
+
} & MergeObject$1<IsEntityIdentifierOptional extends true ? {
|
|
9378
|
+
identifier?: IdSelector<NoInfer<StateType>, NoInfer<K>>;
|
|
9379
|
+
} : {
|
|
9380
|
+
identifier: IdSelector<NoInfer<StateType>, NoInfer<K>>;
|
|
9381
|
+
}, [
|
|
9382
|
+
Path
|
|
9383
|
+
] extends [never] ? {} : {
|
|
9384
|
+
path: Path;
|
|
9385
|
+
}>): (context: InsertionStateFactoryContext<State, PreviousInsertionsOutputs> & {
|
|
9386
|
+
identifier?: StateIdentifier;
|
|
9387
|
+
}) => Prettify<EntitiesUtilsToMap<EntityHelperFns, StateType, K, HasStateIdentifier, StateIdentifier, "path" extends keyof typeof config ? true : false, Path>> & {
|
|
9388
|
+
testState: State;
|
|
9389
|
+
testPath: Path;
|
|
9390
|
+
testHasPath: "path" extends keyof typeof config ? true : false;
|
|
9391
|
+
};
|
|
9392
|
+
|
|
9393
|
+
export { CRAFT_EXCEPTION_SYMBOL, EXTERNALLY_PROVIDED, EmptyContext, GlobalPersisterHandlerService, STORE_CONFIG_TOKEN, SourceBrand, SourceBranded, VALIDATOR_OUTPUT_SYMBOL, addMany, addOne, afterRecomputation, asyncProcess, cAsyncValidate, cAsyncValidator, cEmail, cMax, cMaxLength, cMin, cMinLength, cPattern, cRequired, cValidate, cValidator, capitalize, computedIds, computedSource, computedTotal, contract, craft, craftAsyncProcesses, craftComputedStates, craftException, craftFactoryEntries, craftInject, craftInputs, craftMutations, craftQuery, craftQueryParam, craftQueryParams, craftSetAllQueriesParamsStandalone, craftSources, craftState, createMethodHandlers, fromEventToSource$, injectService, insertEntities, insertForm, insertFormAttributes, insertFormSubmit, insertLocalStoragePersister, insertNoopTypingAnchor, insertPaginationPlaceholderData, insertReactOnMutation, insertSelect, insertSelectFormTree, isCraftException, isSource, linkedSource, localStoragePersister, map, mapOne, mutation, on$, partialContext, query, queryParam, reactiveWritableSignal, removeAll, removeMany, removeOne, resourceById, serializeQueryParams, serializedQueryParamsObjectToString, setAll, setMany, setOne, signalSource, source$, sourceFromEvent, stackedSource, state, toInject, toSource, toggleMany, toggleOne, updateMany, updateOne, upsertMany, upsertOne, validatedFormValueSymbol };
|
|
9269
9394
|
export type { AnyCraftException, AsyncProcessExceptionConstraints, AsyncProcessOutput, AsyncProcessRef, CEmailException, CMaxException, CMaxLengthException, CMinException, CMinLengthException, CRequiredException, CloudProxy, CloudProxySource, ContextConstraints, ContextInput, CraftException, CraftExceptionMeta, CraftExceptionResult, CraftFactory, CraftFactoryEntries, CraftFactoryUtility, DeferredExtract, EntitiesUtilBrand, EqualParams, ExcludeByCode, ExcludeCommonKeys, ExposedStateInsertions, ExtractCodeFromCraftResultUnion, ExtractCraftException, ExtractSignalPropsAndMethods, FilterMethodsBoundToSources, FilterPrivateFields, FilterSource, FlatRecord, FormNodeExceptions, FormWithInsertions, FromEventToSource$, HasChild$1 as HasChild, HasKeys, IdSelector, Identifier, InferInjectedType, InjectService2InsertionContext, InjectService2InsertionFactory, InjectService2Insertions, InjectService2Output, InjectService2Public, InsertFormAttributesConfig, InsertFormAttributesContext, InsertMetaInCraftExceptionIfExists, InsertionFormFactoryContext, InsertionsFormFactory, IsAny, IsEmptyObject, IsNever, IsUnknown, MakeOptionalPropertiesRequired$1 as MakeOptionalPropertiesRequired, MergeObject$1 as MergeObject, MergeObjects$1 as MergeObjects, MergeTwoContexts, MutationOutput, MutationRef, Not, OmitStrict, PartialContext, Prettify, QueryOutput, QueryParamConfig, QueryParamExceptions, QueryParamNavigationOptions$1 as QueryParamNavigationOptions, QueryParamOutput, QueryParamsToState, QueryRef, ReadonlySource, ReadonlySource$, RemoveIndexSignature, ReplaceStoreConfigToken, ResourceByIdHandler, ResourceByIdLikeAsyncProcessExceptions, ResourceByIdLikeExceptions, ResourceByIdLikeMutationExceptions, ResourceByIdLikeMutationRef, ResourceByIdLikeQueryRef, ResourceByIdRef, ResourceLikeAsyncProcessExceptions, ResourceLikeExceptions, ResourceLikeMutationExceptions, ResourceLikeMutationRef, ResourceLikeQueryRef, SignalSource, Source$, SourceFromEvent, SourceSetterMethods, SourceSubscribe, SpecificCraftQueryParamOutputs, SpecificCraftQueryParamsOutputs, StackSource, StateOutput, StoreConfigConstraints, StoreConfigToken, StripCraftException, ToConnectableMethodFromInject, ToConnectableSourceFromInject, ToInjectBindings, UnionToIntersection$1 as UnionToIntersection, UnionToTuple$1 as UnionToTuple, Update, ValidatedFormValue, ValidatorBindingContext, ValidatorModel, ValidatorOutput, ValidatorPending, ValidatorSuccess, ValidatorType, ValidatorUtilBrand };
|