@spoosh/angular 0.3.0 → 0.5.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @spoosh/angular
2
2
 
3
- Angular signals integration for Spoosh - `injectRead`, `injectWrite`, and `injectInfiniteRead`.
3
+ Angular signals integration for Spoosh - `injectRead`, `injectLazyRead`, `injectWrite`, and `injectInfiniteRead`.
4
4
 
5
5
  **[Documentation](https://spoosh.dev/docs/integrations/angular)** · **Requirements:** TypeScript >= 5.0, Angular >= 16.0
6
6
 
@@ -23,13 +23,13 @@ const spoosh = new Spoosh<ApiSchema, Error>("/api").use([
23
23
  cachePlugin({ staleTime: 5000 }),
24
24
  ]);
25
25
 
26
- export const { injectRead, injectWrite, injectInfiniteRead } =
26
+ export const { injectRead, injectLazyRead, injectWrite, injectInfiniteRead } =
27
27
  createAngularSpoosh(spoosh);
28
28
  ```
29
29
 
30
30
  ### injectRead
31
31
 
32
- Fetch data with automatic caching and refetching using Angular signals.
32
+ Fetch data with automatic caching and triggering using Angular signals.
33
33
 
34
34
  ```typescript
35
35
  @Component({
@@ -74,6 +74,28 @@ export class UserListComponent {
74
74
  }
75
75
  ```
76
76
 
77
+ ### injectLazyRead
78
+
79
+ Lazy data fetching for print/download/export scenarios. Does not auto-fetch on mount.
80
+
81
+ ```typescript
82
+ @Component({
83
+ template: `
84
+ <button (click)="handlePrint('123')" [disabled]="order.loading()">
85
+ {{ order.loading() ? "Loading..." : "Print" }}
86
+ </button>
87
+ `,
88
+ })
89
+ export class PrintOrderComponent {
90
+ order = injectLazyRead((api) => api("orders/:id").GET);
91
+
92
+ async handlePrint(orderId: string) {
93
+ const { data } = await this.order.trigger({ params: { id: orderId } });
94
+ if (data) this.printService.printReceipt(data);
95
+ }
96
+ }
97
+ ```
98
+
77
99
  ### injectWrite
78
100
 
79
101
  Trigger mutations with loading and error states.
@@ -187,7 +209,7 @@ export class PostListComponent {
187
209
  | `loading` | `Signal<boolean>` | True during initial load |
188
210
  | `fetching` | `Signal<boolean>` | True during any fetch |
189
211
  | `meta` | `Signal<PluginResults>` | Plugin metadata (e.g., `transformedData`) |
190
- | `refetch` | `() => Promise` | Manually trigger refetch |
212
+ | `trigger` | `() => Promise` | Manually trigger fetch |
191
213
  | `abort` | `() => void` | Abort current request |
192
214
 
193
215
  ### injectWrite(writeFn)
@@ -202,7 +224,6 @@ export class PostListComponent {
202
224
  | `loading` | `Signal<boolean>` | True while mutation is in progress |
203
225
  | `meta` | `Signal<PluginResults>` | Plugin metadata |
204
226
  | `input` | `TriggerOptions \| undefined` | Last trigger input |
205
- | `reset` | `() => void` | Reset state |
206
227
  | `abort` | `() => void` | Abort current request |
207
228
 
208
229
  ### injectInfiniteRead(readFn, options)
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _spoosh_core from '@spoosh/core';
2
- import { PluginArray, StateManager, EventEmitter, PluginExecutor, ReadClient, SpooshResponse, WriteClient, MethodOptionsMap, CoreRequestOptionsBase, SpooshPlugin, PluginTypeConfig, InfiniteRequestOptions, ResolveTypes, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
2
+ import { PluginArray, StateManager, EventEmitter, PluginExecutor, ReadClient, TagOptions, SpooshResponse, WriteClient, MethodOptionsMap, CoreRequestOptionsBase, SpooshPlugin, PluginTypeConfig, InfiniteRequestOptions, ResolveTypes, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
3
3
  import { Signal } from '@angular/core';
4
4
 
5
5
  interface SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins extends PluginArray> {
@@ -14,10 +14,8 @@ interface SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins extends Plu
14
14
  };
15
15
  }
16
16
  type EnabledOption = boolean | (() => boolean);
17
- interface BaseReadOptions {
17
+ interface BaseReadOptions extends TagOptions {
18
18
  enabled?: EnabledOption;
19
- tags?: string[];
20
- additionalTags?: string[];
21
19
  }
22
20
  interface BaseReadResult<TData, TError, TPluginResult = Record<string, unknown>> {
23
21
  data: Signal<TData | undefined>;
@@ -26,7 +24,7 @@ interface BaseReadResult<TData, TError, TPluginResult = Record<string, unknown>>
26
24
  fetching: Signal<boolean>;
27
25
  meta: Signal<TPluginResult>;
28
26
  abort: () => void;
29
- refetch: () => Promise<SpooshResponse<TData, TError>>;
27
+ trigger: () => Promise<SpooshResponse<TData, TError>>;
30
28
  }
31
29
  interface BaseWriteResult<TData, TError, TOptions, TPluginResult = Record<string, unknown>> {
32
30
  trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
@@ -34,7 +32,13 @@ interface BaseWriteResult<TData, TError, TOptions, TPluginResult = Record<string
34
32
  error: Signal<TError | undefined>;
35
33
  loading: Signal<boolean>;
36
34
  meta: Signal<TPluginResult>;
37
- reset: () => void;
35
+ abort: () => void;
36
+ }
37
+ interface BaseLazyReadResult<TData, TError, TOptions> {
38
+ trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
39
+ data: Signal<TData | undefined>;
40
+ error: Signal<TError | undefined>;
41
+ loading: Signal<boolean>;
38
42
  abort: () => void;
39
43
  }
40
44
  type PageContext<TData, TRequest> = {
@@ -42,7 +46,8 @@ type PageContext<TData, TRequest> = {
42
46
  allResponses: TData[];
43
47
  request: TRequest;
44
48
  };
45
- interface BaseInfiniteReadOptions<TData, TItem, TRequest> extends BaseReadOptions {
49
+ interface BaseInfiniteReadOptions<TData, TItem, TRequest> extends TagOptions {
50
+ enabled?: EnabledOption;
46
51
  canFetchNext: (ctx: PageContext<TData, TRequest>) => boolean;
47
52
  canFetchPrev?: (ctx: PageContext<TData, TRequest>) => boolean;
48
53
  nextPageRequest: (ctx: PageContext<TData, TRequest>) => Partial<TRequest>;
@@ -62,7 +67,7 @@ interface BaseInfiniteReadResult<TData, TError, TItem, TPluginResult = Record<st
62
67
  meta: Signal<TPluginResult>;
63
68
  fetchNext: () => Promise<void>;
64
69
  fetchPrev: () => Promise<void>;
65
- refetch: () => Promise<void>;
70
+ trigger: () => Promise<void>;
66
71
  abort: () => void;
67
72
  }
68
73
  type QueryRequestOptions = CoreRequestOptionsBase;
@@ -149,6 +154,23 @@ type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
149
154
  body: infer B;
150
155
  } ? B : never;
151
156
 
157
+ declare function createInjectLazyRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>>(readFn: (api: ReadApiClient<TSchema, TDefaultError>) => TMethod) => BaseLazyReadResult<TMethod extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
158
+ data: unknown;
159
+ error?: undefined;
160
+ }> extends {
161
+ data: infer D;
162
+ } ? D : unknown : unknown, [TMethod extends (...args: never[]) => infer R_1 ? Extract<Awaited<R_1>, {
163
+ error: unknown;
164
+ data?: undefined;
165
+ }> extends {
166
+ error: infer E;
167
+ } ? E : unknown : unknown] extends [unknown] ? TDefaultError : TMethod extends (...args: never[]) => infer R_1 ? Extract<Awaited<R_1>, {
168
+ error: unknown;
169
+ data?: undefined;
170
+ }> extends {
171
+ error: infer E;
172
+ } ? E : unknown : unknown, TMethod extends (...args: infer A) => unknown ? A[0] extends object ? Pick<A[0], Extract<keyof A[0], "query" | "body" | "params">> : object : object> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
173
+
152
174
  type AnyInfiniteRequestOptions = InfiniteRequestOptions;
153
175
  declare function createInjectInfiniteRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TRequest extends AnyInfiniteRequestOptions = AnyInfiniteRequestOptions, TItem = unknown>(readFn: TReadFn, readOptions: BaseInfiniteReadOptions<TReadFn extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
154
176
  data: unknown;
@@ -320,8 +342,9 @@ type SpooshAngularFunctions<TDefaultError, TSchema, TPlugins extends PluginArray
320
342
  injectRead: ReturnType<typeof createInjectRead<TSchema, TDefaultError, TPlugins>>;
321
343
  injectWrite: ReturnType<typeof createInjectWrite<TSchema, TDefaultError, TPlugins>>;
322
344
  injectInfiniteRead: ReturnType<typeof createInjectInfiniteRead<TSchema, TDefaultError, TPlugins>>;
345
+ injectLazyRead: ReturnType<typeof createInjectLazyRead<TSchema, TDefaultError, TPlugins>>;
323
346
  } & MergePluginInstanceApi<TPlugins, TSchema>;
324
347
 
325
348
  declare function createAngularSpoosh<TSchema, TDefaultError, TPlugins extends PluginArray, TApi>(instance: SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins>): SpooshAngularFunctions<TDefaultError, TSchema, TPlugins>;
326
349
 
327
- export { type AngularOptionsMap, type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type EnabledOption, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type PageContext, type ReadApiClient, type ResponseInputFields, type SpooshInstanceShape, type WriteApiClient, type WriteResponseInputFields, createAngularSpoosh };
350
+ export { type AngularOptionsMap, type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseLazyReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type EnabledOption, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type PageContext, type ReadApiClient, type ResponseInputFields, type SpooshInstanceShape, type WriteApiClient, type WriteResponseInputFields, createAngularSpoosh };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _spoosh_core from '@spoosh/core';
2
- import { PluginArray, StateManager, EventEmitter, PluginExecutor, ReadClient, SpooshResponse, WriteClient, MethodOptionsMap, CoreRequestOptionsBase, SpooshPlugin, PluginTypeConfig, InfiniteRequestOptions, ResolveTypes, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
2
+ import { PluginArray, StateManager, EventEmitter, PluginExecutor, ReadClient, TagOptions, SpooshResponse, WriteClient, MethodOptionsMap, CoreRequestOptionsBase, SpooshPlugin, PluginTypeConfig, InfiniteRequestOptions, ResolveTypes, ResolverContext, ResolveResultTypes, MergePluginInstanceApi } from '@spoosh/core';
3
3
  import { Signal } from '@angular/core';
4
4
 
5
5
  interface SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins extends PluginArray> {
@@ -14,10 +14,8 @@ interface SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins extends Plu
14
14
  };
15
15
  }
16
16
  type EnabledOption = boolean | (() => boolean);
17
- interface BaseReadOptions {
17
+ interface BaseReadOptions extends TagOptions {
18
18
  enabled?: EnabledOption;
19
- tags?: string[];
20
- additionalTags?: string[];
21
19
  }
22
20
  interface BaseReadResult<TData, TError, TPluginResult = Record<string, unknown>> {
23
21
  data: Signal<TData | undefined>;
@@ -26,7 +24,7 @@ interface BaseReadResult<TData, TError, TPluginResult = Record<string, unknown>>
26
24
  fetching: Signal<boolean>;
27
25
  meta: Signal<TPluginResult>;
28
26
  abort: () => void;
29
- refetch: () => Promise<SpooshResponse<TData, TError>>;
27
+ trigger: () => Promise<SpooshResponse<TData, TError>>;
30
28
  }
31
29
  interface BaseWriteResult<TData, TError, TOptions, TPluginResult = Record<string, unknown>> {
32
30
  trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
@@ -34,7 +32,13 @@ interface BaseWriteResult<TData, TError, TOptions, TPluginResult = Record<string
34
32
  error: Signal<TError | undefined>;
35
33
  loading: Signal<boolean>;
36
34
  meta: Signal<TPluginResult>;
37
- reset: () => void;
35
+ abort: () => void;
36
+ }
37
+ interface BaseLazyReadResult<TData, TError, TOptions> {
38
+ trigger: (options?: TOptions) => Promise<SpooshResponse<TData, TError>>;
39
+ data: Signal<TData | undefined>;
40
+ error: Signal<TError | undefined>;
41
+ loading: Signal<boolean>;
38
42
  abort: () => void;
39
43
  }
40
44
  type PageContext<TData, TRequest> = {
@@ -42,7 +46,8 @@ type PageContext<TData, TRequest> = {
42
46
  allResponses: TData[];
43
47
  request: TRequest;
44
48
  };
45
- interface BaseInfiniteReadOptions<TData, TItem, TRequest> extends BaseReadOptions {
49
+ interface BaseInfiniteReadOptions<TData, TItem, TRequest> extends TagOptions {
50
+ enabled?: EnabledOption;
46
51
  canFetchNext: (ctx: PageContext<TData, TRequest>) => boolean;
47
52
  canFetchPrev?: (ctx: PageContext<TData, TRequest>) => boolean;
48
53
  nextPageRequest: (ctx: PageContext<TData, TRequest>) => Partial<TRequest>;
@@ -62,7 +67,7 @@ interface BaseInfiniteReadResult<TData, TError, TItem, TPluginResult = Record<st
62
67
  meta: Signal<TPluginResult>;
63
68
  fetchNext: () => Promise<void>;
64
69
  fetchPrev: () => Promise<void>;
65
- refetch: () => Promise<void>;
70
+ trigger: () => Promise<void>;
66
71
  abort: () => void;
67
72
  }
68
73
  type QueryRequestOptions = CoreRequestOptionsBase;
@@ -149,6 +154,23 @@ type ExtractMethodBody<T> = ExtractMethodOptions<T> extends {
149
154
  body: infer B;
150
155
  } ? B : never;
151
156
 
157
+ declare function createInjectLazyRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TMethod extends (...args: never[]) => Promise<SpooshResponse<unknown, unknown>>>(readFn: (api: ReadApiClient<TSchema, TDefaultError>) => TMethod) => BaseLazyReadResult<TMethod extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
158
+ data: unknown;
159
+ error?: undefined;
160
+ }> extends {
161
+ data: infer D;
162
+ } ? D : unknown : unknown, [TMethod extends (...args: never[]) => infer R_1 ? Extract<Awaited<R_1>, {
163
+ error: unknown;
164
+ data?: undefined;
165
+ }> extends {
166
+ error: infer E;
167
+ } ? E : unknown : unknown] extends [unknown] ? TDefaultError : TMethod extends (...args: never[]) => infer R_1 ? Extract<Awaited<R_1>, {
168
+ error: unknown;
169
+ data?: undefined;
170
+ }> extends {
171
+ error: infer E;
172
+ } ? E : unknown : unknown, TMethod extends (...args: infer A) => unknown ? A[0] extends object ? Pick<A[0], Extract<keyof A[0], "query" | "body" | "params">> : object : object> & WriteResponseInputFields<ExtractResponseQuery<TMethod>, ExtractResponseBody<TMethod>, ExtractResponseParamNames<TMethod>>;
173
+
152
174
  type AnyInfiniteRequestOptions = InfiniteRequestOptions;
153
175
  declare function createInjectInfiniteRead<TSchema, TDefaultError, TPlugins extends readonly SpooshPlugin<PluginTypeConfig>[]>(options: Omit<SpooshInstanceShape<unknown, TSchema, TDefaultError, TPlugins>, "_types">): <TReadFn extends (api: ReadApiClient<TSchema, TDefaultError>) => Promise<SpooshResponse<unknown, unknown>>, TRequest extends AnyInfiniteRequestOptions = AnyInfiniteRequestOptions, TItem = unknown>(readFn: TReadFn, readOptions: BaseInfiniteReadOptions<TReadFn extends (...args: never[]) => infer R ? Extract<Awaited<R>, {
154
176
  data: unknown;
@@ -320,8 +342,9 @@ type SpooshAngularFunctions<TDefaultError, TSchema, TPlugins extends PluginArray
320
342
  injectRead: ReturnType<typeof createInjectRead<TSchema, TDefaultError, TPlugins>>;
321
343
  injectWrite: ReturnType<typeof createInjectWrite<TSchema, TDefaultError, TPlugins>>;
322
344
  injectInfiniteRead: ReturnType<typeof createInjectInfiniteRead<TSchema, TDefaultError, TPlugins>>;
345
+ injectLazyRead: ReturnType<typeof createInjectLazyRead<TSchema, TDefaultError, TPlugins>>;
323
346
  } & MergePluginInstanceApi<TPlugins, TSchema>;
324
347
 
325
348
  declare function createAngularSpoosh<TSchema, TDefaultError, TPlugins extends PluginArray, TApi>(instance: SpooshInstanceShape<TApi, TSchema, TDefaultError, TPlugins>): SpooshAngularFunctions<TDefaultError, TSchema, TPlugins>;
326
349
 
327
- export { type AngularOptionsMap, type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type EnabledOption, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type PageContext, type ReadApiClient, type ResponseInputFields, type SpooshInstanceShape, type WriteApiClient, type WriteResponseInputFields, createAngularSpoosh };
350
+ export { type AngularOptionsMap, type BaseInfiniteReadOptions, type BaseInfiniteReadResult, type BaseLazyReadResult, type BaseReadOptions, type BaseReadResult, type BaseWriteResult, type EnabledOption, type ExtractMethodBody, type ExtractMethodData, type ExtractMethodError, type ExtractMethodOptions, type ExtractMethodQuery, type ExtractResponseBody, type ExtractResponseParamNames, type ExtractResponseQuery, type PageContext, type ReadApiClient, type ResponseInputFields, type SpooshInstanceShape, type WriteApiClient, type WriteResponseInputFields, createAngularSpoosh };
package/dist/index.js CHANGED
@@ -33,8 +33,7 @@ function createInjectRead(options) {
33
33
  const destroyRef = (0, import_core.inject)(import_core.DestroyRef);
34
34
  const {
35
35
  enabled: enabledOption = true,
36
- tags = void 0,
37
- additionalTags = void 0,
36
+ tags,
38
37
  ...pluginOpts
39
38
  } = readOptions ?? {};
40
39
  const getEnabled = () => typeof enabledOption === "function" ? enabledOption() : enabledOption;
@@ -137,7 +136,7 @@ function createInjectRead(options) {
137
136
  initialRequestOptions?.params
138
137
  );
139
138
  const initialResolvedTags = (0, import_core2.resolveTags)(
140
- { tags, additionalTags },
139
+ tags !== void 0 ? { tags } : void 0,
141
140
  initialResolvedPath
142
141
  );
143
142
  const initialQueryKey = stateManager.createQueryKey({
@@ -162,7 +161,7 @@ function createInjectRead(options) {
162
161
  const pathSegments = capturedCall.path.split("/").filter(Boolean);
163
162
  const resolvedPath = (0, import_core2.resolvePath)(pathSegments, requestOptions?.params);
164
163
  const resolvedTags = (0, import_core2.resolveTags)(
165
- { tags, additionalTags },
164
+ tags !== void 0 ? { tags } : void 0,
166
165
  resolvedPath
167
166
  );
168
167
  const queryKey = stateManager.createQueryKey({
@@ -268,7 +267,7 @@ function createInjectRead(options) {
268
267
  const abort = () => {
269
268
  currentController?.abort();
270
269
  };
271
- const refetch = () => {
270
+ const trigger = () => {
272
271
  if (currentController) {
273
272
  if (!isMounted) {
274
273
  currentController.mount();
@@ -288,7 +287,7 @@ function createInjectRead(options) {
288
287
  loading: loadingSignal,
289
288
  fetching: fetchingSignal,
290
289
  abort,
291
- refetch
290
+ trigger
292
291
  };
293
292
  return result;
294
293
  };
@@ -334,14 +333,6 @@ function createInjectWrite(options) {
334
333
  currentSubscription();
335
334
  }
336
335
  });
337
- const reset = () => {
338
- if (currentQueryKey) {
339
- stateManager.deleteCache(currentQueryKey);
340
- }
341
- dataSignal.set(void 0);
342
- errorSignal.set(void 0);
343
- loadingSignal.set(false);
344
- };
345
336
  const abort = () => {
346
337
  currentController?.abort();
347
338
  };
@@ -432,7 +423,6 @@ function createInjectWrite(options) {
432
423
  data: dataSignal,
433
424
  error: errorSignal,
434
425
  loading: loadingSignal,
435
- reset,
436
426
  abort
437
427
  };
438
428
  return result;
@@ -449,7 +439,6 @@ function createInjectInfiniteRead(options) {
449
439
  const {
450
440
  enabled: enabledOption = true,
451
441
  tags,
452
- additionalTags,
453
442
  canFetchNext,
454
443
  nextPageRequest,
455
444
  merger,
@@ -617,7 +606,7 @@ function createInjectInfiniteRead(options) {
617
606
  initialRequestOptions?.params
618
607
  );
619
608
  const initialResolvedTags = (0, import_core6.resolveTags)(
620
- { tags, additionalTags },
609
+ tags !== void 0 ? { tags } : void 0,
621
610
  initialResolvedPath
622
611
  );
623
612
  const initialBaseOptionsForKey = {
@@ -640,7 +629,7 @@ function createInjectInfiniteRead(options) {
640
629
  const pathSegments = capturedCall.path.split("/").filter(Boolean);
641
630
  const resolvedPath = (0, import_core6.resolvePath)(pathSegments, requestOptions?.params);
642
631
  const resolvedTags = (0, import_core6.resolveTags)(
643
- { tags, additionalTags },
632
+ tags !== void 0 ? { tags } : void 0,
644
633
  resolvedPath
645
634
  );
646
635
  const baseOptionsForKey = {
@@ -732,7 +721,7 @@ function createInjectInfiniteRead(options) {
732
721
  fetchingPrevSignal.set(false);
733
722
  }
734
723
  };
735
- const refetch = async () => {
724
+ const trigger = async () => {
736
725
  if (!currentController) return;
737
726
  if (!isMounted) {
738
727
  currentController.mount();
@@ -765,7 +754,131 @@ function createInjectInfiniteRead(options) {
765
754
  canFetchPrev: canFetchPrevSignal,
766
755
  fetchNext,
767
756
  fetchPrev,
768
- refetch,
757
+ trigger,
758
+ abort
759
+ };
760
+ return result;
761
+ };
762
+ }
763
+
764
+ // src/injectLazyRead/index.ts
765
+ var import_core7 = require("@angular/core");
766
+ var import_core8 = require("@spoosh/core");
767
+ function createInjectLazyRead(options) {
768
+ const { api, stateManager, pluginExecutor, eventEmitter } = options;
769
+ return function injectLazyRead(readFn) {
770
+ const destroyRef = (0, import_core7.inject)(import_core7.DestroyRef);
771
+ const captureSelector = () => {
772
+ const selectorResult = {
773
+ call: null,
774
+ selector: null
775
+ };
776
+ const selectorProxy = (0, import_core8.createSelectorProxy)(
777
+ (result2) => {
778
+ selectorResult.call = result2.call;
779
+ selectorResult.selector = result2.selector;
780
+ }
781
+ );
782
+ readFn(selectorProxy);
783
+ if (!selectorResult.selector) {
784
+ throw new Error(
785
+ 'injectLazyRead requires selecting an HTTP method (GET). Example: injectLazyRead((api) => api("posts").GET)'
786
+ );
787
+ }
788
+ return selectorResult.selector;
789
+ };
790
+ const hookId = `angular-${Math.random().toString(36).slice(2)}`;
791
+ let currentQueryKey = null;
792
+ let currentController = null;
793
+ let currentSubscription = null;
794
+ const dataSignal = (0, import_core7.signal)(void 0);
795
+ const errorSignal = (0, import_core7.signal)(void 0);
796
+ const loadingSignal = (0, import_core7.signal)(false);
797
+ const lastTriggerOptionsSignal = (0, import_core7.signal)(void 0);
798
+ const inputSignal = (0, import_core7.signal)({});
799
+ destroyRef.onDestroy(() => {
800
+ if (currentSubscription) {
801
+ currentSubscription();
802
+ }
803
+ });
804
+ const abort = () => {
805
+ currentController?.abort();
806
+ };
807
+ const trigger = async (triggerOptions) => {
808
+ const selectedEndpoint = captureSelector();
809
+ const params = triggerOptions?.params;
810
+ const pathSegments = selectedEndpoint.path.split("/").filter(Boolean);
811
+ (0, import_core8.resolvePath)(pathSegments, params);
812
+ const queryKey = stateManager.createQueryKey({
813
+ path: pathSegments,
814
+ method: selectedEndpoint.method,
815
+ options: triggerOptions
816
+ });
817
+ const needsNewController = !currentController || currentQueryKey !== queryKey;
818
+ if (needsNewController) {
819
+ if (currentSubscription) {
820
+ currentSubscription();
821
+ }
822
+ const controller = (0, import_core8.createOperationController)({
823
+ operationType: "read",
824
+ path: pathSegments,
825
+ method: selectedEndpoint.method,
826
+ tags: [],
827
+ stateManager,
828
+ eventEmitter,
829
+ pluginExecutor,
830
+ hookId,
831
+ requestOptions: triggerOptions,
832
+ fetchFn: async (fetchOpts) => {
833
+ const pathMethods = api(selectedEndpoint.path);
834
+ const method = pathMethods[selectedEndpoint.method];
835
+ return method(fetchOpts);
836
+ }
837
+ });
838
+ currentSubscription = controller.subscribe(() => {
839
+ const state = controller.getState();
840
+ dataSignal.set(state.data);
841
+ errorSignal.set(state.error);
842
+ });
843
+ currentController = controller;
844
+ currentQueryKey = queryKey;
845
+ }
846
+ lastTriggerOptionsSignal.set(triggerOptions);
847
+ const opts = triggerOptions;
848
+ const inputInner = {};
849
+ if (opts?.query !== void 0) {
850
+ inputInner.query = opts.query;
851
+ }
852
+ if (opts?.body !== void 0) {
853
+ inputInner.body = opts.body;
854
+ }
855
+ if (opts?.params !== void 0) {
856
+ inputInner.params = opts.params;
857
+ }
858
+ inputSignal.set(inputInner);
859
+ loadingSignal.set(true);
860
+ currentController.setPluginOptions(triggerOptions);
861
+ try {
862
+ const response = await currentController.execute(triggerOptions);
863
+ if (response.error) {
864
+ errorSignal.set(response.error);
865
+ } else {
866
+ errorSignal.set(void 0);
867
+ }
868
+ return response;
869
+ } catch (err) {
870
+ errorSignal.set(err);
871
+ throw err;
872
+ } finally {
873
+ loadingSignal.set(false);
874
+ }
875
+ };
876
+ const result = {
877
+ trigger,
878
+ input: inputSignal,
879
+ data: dataSignal,
880
+ error: errorSignal,
881
+ loading: loadingSignal,
769
882
  abort
770
883
  };
771
884
  return result;
@@ -793,6 +906,14 @@ function createAngularSpoosh(instance) {
793
906
  eventEmitter,
794
907
  pluginExecutor
795
908
  });
909
+ const injectLazyRead = createInjectLazyRead(
910
+ {
911
+ api,
912
+ stateManager,
913
+ eventEmitter,
914
+ pluginExecutor
915
+ }
916
+ );
796
917
  const instanceApiContext = {
797
918
  api,
798
919
  stateManager,
@@ -813,6 +934,7 @@ function createAngularSpoosh(instance) {
813
934
  injectRead,
814
935
  injectWrite,
815
936
  injectInfiniteRead,
937
+ injectLazyRead,
816
938
  ...instanceApis
817
939
  };
818
940
  }
package/dist/index.mjs CHANGED
@@ -18,8 +18,7 @@ function createInjectRead(options) {
18
18
  const destroyRef = inject(DestroyRef);
19
19
  const {
20
20
  enabled: enabledOption = true,
21
- tags = void 0,
22
- additionalTags = void 0,
21
+ tags,
23
22
  ...pluginOpts
24
23
  } = readOptions ?? {};
25
24
  const getEnabled = () => typeof enabledOption === "function" ? enabledOption() : enabledOption;
@@ -122,7 +121,7 @@ function createInjectRead(options) {
122
121
  initialRequestOptions?.params
123
122
  );
124
123
  const initialResolvedTags = resolveTags(
125
- { tags, additionalTags },
124
+ tags !== void 0 ? { tags } : void 0,
126
125
  initialResolvedPath
127
126
  );
128
127
  const initialQueryKey = stateManager.createQueryKey({
@@ -147,7 +146,7 @@ function createInjectRead(options) {
147
146
  const pathSegments = capturedCall.path.split("/").filter(Boolean);
148
147
  const resolvedPath = resolvePath(pathSegments, requestOptions?.params);
149
148
  const resolvedTags = resolveTags(
150
- { tags, additionalTags },
149
+ tags !== void 0 ? { tags } : void 0,
151
150
  resolvedPath
152
151
  );
153
152
  const queryKey = stateManager.createQueryKey({
@@ -253,7 +252,7 @@ function createInjectRead(options) {
253
252
  const abort = () => {
254
253
  currentController?.abort();
255
254
  };
256
- const refetch = () => {
255
+ const trigger = () => {
257
256
  if (currentController) {
258
257
  if (!isMounted) {
259
258
  currentController.mount();
@@ -273,7 +272,7 @@ function createInjectRead(options) {
273
272
  loading: loadingSignal,
274
273
  fetching: fetchingSignal,
275
274
  abort,
276
- refetch
275
+ trigger
277
276
  };
278
277
  return result;
279
278
  };
@@ -324,14 +323,6 @@ function createInjectWrite(options) {
324
323
  currentSubscription();
325
324
  }
326
325
  });
327
- const reset = () => {
328
- if (currentQueryKey) {
329
- stateManager.deleteCache(currentQueryKey);
330
- }
331
- dataSignal.set(void 0);
332
- errorSignal.set(void 0);
333
- loadingSignal.set(false);
334
- };
335
326
  const abort = () => {
336
327
  currentController?.abort();
337
328
  };
@@ -422,7 +413,6 @@ function createInjectWrite(options) {
422
413
  data: dataSignal,
423
414
  error: errorSignal,
424
415
  loading: loadingSignal,
425
- reset,
426
416
  abort
427
417
  };
428
418
  return result;
@@ -451,7 +441,6 @@ function createInjectInfiniteRead(options) {
451
441
  const {
452
442
  enabled: enabledOption = true,
453
443
  tags,
454
- additionalTags,
455
444
  canFetchNext,
456
445
  nextPageRequest,
457
446
  merger,
@@ -619,7 +608,7 @@ function createInjectInfiniteRead(options) {
619
608
  initialRequestOptions?.params
620
609
  );
621
610
  const initialResolvedTags = resolveTags3(
622
- { tags, additionalTags },
611
+ tags !== void 0 ? { tags } : void 0,
623
612
  initialResolvedPath
624
613
  );
625
614
  const initialBaseOptionsForKey = {
@@ -642,7 +631,7 @@ function createInjectInfiniteRead(options) {
642
631
  const pathSegments = capturedCall.path.split("/").filter(Boolean);
643
632
  const resolvedPath = resolvePath3(pathSegments, requestOptions?.params);
644
633
  const resolvedTags = resolveTags3(
645
- { tags, additionalTags },
634
+ tags !== void 0 ? { tags } : void 0,
646
635
  resolvedPath
647
636
  );
648
637
  const baseOptionsForKey = {
@@ -734,7 +723,7 @@ function createInjectInfiniteRead(options) {
734
723
  fetchingPrevSignal.set(false);
735
724
  }
736
725
  };
737
- const refetch = async () => {
726
+ const trigger = async () => {
738
727
  if (!currentController) return;
739
728
  if (!isMounted) {
740
729
  currentController.mount();
@@ -767,7 +756,135 @@ function createInjectInfiniteRead(options) {
767
756
  canFetchPrev: canFetchPrevSignal,
768
757
  fetchNext,
769
758
  fetchPrev,
770
- refetch,
759
+ trigger,
760
+ abort
761
+ };
762
+ return result;
763
+ };
764
+ }
765
+
766
+ // src/injectLazyRead/index.ts
767
+ import { signal as signal4, DestroyRef as DestroyRef4, inject as inject4 } from "@angular/core";
768
+ import {
769
+ createOperationController as createOperationController3,
770
+ createSelectorProxy as createSelectorProxy4,
771
+ resolvePath as resolvePath4
772
+ } from "@spoosh/core";
773
+ function createInjectLazyRead(options) {
774
+ const { api, stateManager, pluginExecutor, eventEmitter } = options;
775
+ return function injectLazyRead(readFn) {
776
+ const destroyRef = inject4(DestroyRef4);
777
+ const captureSelector = () => {
778
+ const selectorResult = {
779
+ call: null,
780
+ selector: null
781
+ };
782
+ const selectorProxy = createSelectorProxy4(
783
+ (result2) => {
784
+ selectorResult.call = result2.call;
785
+ selectorResult.selector = result2.selector;
786
+ }
787
+ );
788
+ readFn(selectorProxy);
789
+ if (!selectorResult.selector) {
790
+ throw new Error(
791
+ 'injectLazyRead requires selecting an HTTP method (GET). Example: injectLazyRead((api) => api("posts").GET)'
792
+ );
793
+ }
794
+ return selectorResult.selector;
795
+ };
796
+ const hookId = `angular-${Math.random().toString(36).slice(2)}`;
797
+ let currentQueryKey = null;
798
+ let currentController = null;
799
+ let currentSubscription = null;
800
+ const dataSignal = signal4(void 0);
801
+ const errorSignal = signal4(void 0);
802
+ const loadingSignal = signal4(false);
803
+ const lastTriggerOptionsSignal = signal4(void 0);
804
+ const inputSignal = signal4({});
805
+ destroyRef.onDestroy(() => {
806
+ if (currentSubscription) {
807
+ currentSubscription();
808
+ }
809
+ });
810
+ const abort = () => {
811
+ currentController?.abort();
812
+ };
813
+ const trigger = async (triggerOptions) => {
814
+ const selectedEndpoint = captureSelector();
815
+ const params = triggerOptions?.params;
816
+ const pathSegments = selectedEndpoint.path.split("/").filter(Boolean);
817
+ resolvePath4(pathSegments, params);
818
+ const queryKey = stateManager.createQueryKey({
819
+ path: pathSegments,
820
+ method: selectedEndpoint.method,
821
+ options: triggerOptions
822
+ });
823
+ const needsNewController = !currentController || currentQueryKey !== queryKey;
824
+ if (needsNewController) {
825
+ if (currentSubscription) {
826
+ currentSubscription();
827
+ }
828
+ const controller = createOperationController3({
829
+ operationType: "read",
830
+ path: pathSegments,
831
+ method: selectedEndpoint.method,
832
+ tags: [],
833
+ stateManager,
834
+ eventEmitter,
835
+ pluginExecutor,
836
+ hookId,
837
+ requestOptions: triggerOptions,
838
+ fetchFn: async (fetchOpts) => {
839
+ const pathMethods = api(selectedEndpoint.path);
840
+ const method = pathMethods[selectedEndpoint.method];
841
+ return method(fetchOpts);
842
+ }
843
+ });
844
+ currentSubscription = controller.subscribe(() => {
845
+ const state = controller.getState();
846
+ dataSignal.set(state.data);
847
+ errorSignal.set(state.error);
848
+ });
849
+ currentController = controller;
850
+ currentQueryKey = queryKey;
851
+ }
852
+ lastTriggerOptionsSignal.set(triggerOptions);
853
+ const opts = triggerOptions;
854
+ const inputInner = {};
855
+ if (opts?.query !== void 0) {
856
+ inputInner.query = opts.query;
857
+ }
858
+ if (opts?.body !== void 0) {
859
+ inputInner.body = opts.body;
860
+ }
861
+ if (opts?.params !== void 0) {
862
+ inputInner.params = opts.params;
863
+ }
864
+ inputSignal.set(inputInner);
865
+ loadingSignal.set(true);
866
+ currentController.setPluginOptions(triggerOptions);
867
+ try {
868
+ const response = await currentController.execute(triggerOptions);
869
+ if (response.error) {
870
+ errorSignal.set(response.error);
871
+ } else {
872
+ errorSignal.set(void 0);
873
+ }
874
+ return response;
875
+ } catch (err) {
876
+ errorSignal.set(err);
877
+ throw err;
878
+ } finally {
879
+ loadingSignal.set(false);
880
+ }
881
+ };
882
+ const result = {
883
+ trigger,
884
+ input: inputSignal,
885
+ data: dataSignal,
886
+ error: errorSignal,
887
+ loading: loadingSignal,
771
888
  abort
772
889
  };
773
890
  return result;
@@ -795,6 +912,14 @@ function createAngularSpoosh(instance) {
795
912
  eventEmitter,
796
913
  pluginExecutor
797
914
  });
915
+ const injectLazyRead = createInjectLazyRead(
916
+ {
917
+ api,
918
+ stateManager,
919
+ eventEmitter,
920
+ pluginExecutor
921
+ }
922
+ );
798
923
  const instanceApiContext = {
799
924
  api,
800
925
  stateManager,
@@ -815,6 +940,7 @@ function createAngularSpoosh(instance) {
815
940
  injectRead,
816
941
  injectWrite,
817
942
  injectInfiniteRead,
943
+ injectLazyRead,
818
944
  ...instanceApis
819
945
  };
820
946
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spoosh/angular",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "license": "MIT",
5
5
  "description": "Angular signals integration for Spoosh API client",
6
6
  "keywords": [
@@ -34,11 +34,11 @@
34
34
  }
35
35
  },
36
36
  "peerDependencies": {
37
- "@spoosh/core": ">=0.6.0",
37
+ "@spoosh/core": ">=0.7.0",
38
38
  "@angular/core": ">=16.0.0"
39
39
  },
40
40
  "devDependencies": {
41
- "@spoosh/core": "0.6.0"
41
+ "@spoosh/core": "0.9.0"
42
42
  },
43
43
  "scripts": {
44
44
  "dev": "tsup --watch",