@assebc/ng-signal-http 1.0.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.
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, makeEnvironmentProviders, inject, signal, DestroyRef, Injectable, Injector, PLATFORM_ID, computed, untracked, runInInjectionContext, effect } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
const SIGNAL_HTTP_CONFIG = new InjectionToken('SIGNAL_HTTP_CONFIG');
|
|
6
|
+
/**
|
|
7
|
+
* Registers `ng-signal-http` in an Angular application.
|
|
8
|
+
* Call once in `app.config.ts` inside `ApplicationConfig.providers`.
|
|
9
|
+
*
|
|
10
|
+
* @param config - Global HTTP configuration applied to all requests.
|
|
11
|
+
* @returns Angular `EnvironmentProviders` to add to your app config.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* export const appConfig: ApplicationConfig = {
|
|
15
|
+
* providers: [provideSignalHttp({ baseUrl: 'https://api.example.com' })],
|
|
16
|
+
* };
|
|
17
|
+
*/
|
|
18
|
+
function provideSignalHttp(config = {}) {
|
|
19
|
+
return makeEnvironmentProviders([
|
|
20
|
+
{
|
|
21
|
+
provide: SIGNAL_HTTP_CONFIG,
|
|
22
|
+
useValue: config
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Error thrown when an HTTP request receives a non-2xx response.
|
|
29
|
+
* Extends the native `Error` class and adds HTTP-specific helpers.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* effect(() => {
|
|
33
|
+
* const err = query.error();
|
|
34
|
+
* if (err instanceof HttpError && err.isUnauthorized) router.navigate(['/login']);
|
|
35
|
+
* });
|
|
36
|
+
*/
|
|
37
|
+
class HttpError extends Error {
|
|
38
|
+
status;
|
|
39
|
+
response;
|
|
40
|
+
/**
|
|
41
|
+
* @param message - Human-readable error description.
|
|
42
|
+
* @param status - HTTP status code (e.g. 404, 500).
|
|
43
|
+
* @param response - The raw `Response` object, if available.
|
|
44
|
+
*/
|
|
45
|
+
constructor(message, status, response) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.status = status;
|
|
48
|
+
this.response = response;
|
|
49
|
+
this.name = 'HttpError';
|
|
50
|
+
Object.setPrototypeOf(this, HttpError.prototype);
|
|
51
|
+
}
|
|
52
|
+
get isClientError() {
|
|
53
|
+
return this.status >= 400 && this.status < 500;
|
|
54
|
+
}
|
|
55
|
+
get isServerError() {
|
|
56
|
+
return this.status >= 500;
|
|
57
|
+
}
|
|
58
|
+
get isTimeout() {
|
|
59
|
+
return this.status === 408;
|
|
60
|
+
}
|
|
61
|
+
get isNotFound() {
|
|
62
|
+
return this.status === 404;
|
|
63
|
+
}
|
|
64
|
+
get isUnauthorized() {
|
|
65
|
+
return this.status === 401;
|
|
66
|
+
}
|
|
67
|
+
get isForbidden() {
|
|
68
|
+
return this.status === 403;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Low-level HTTP service that wraps the native Fetch API.
|
|
74
|
+
* Prefer `querySignal` and `mutationSignal` for component use;
|
|
75
|
+
* use this directly in guards, resolvers, and async effects.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const http = inject(SignalHttpClient);
|
|
79
|
+
* const user = await http.executeRequest<User>({ url: '/users/1', method: 'GET' });
|
|
80
|
+
*/
|
|
81
|
+
class SignalHttpClient {
|
|
82
|
+
config = inject(SIGNAL_HTTP_CONFIG, { optional: true }) ?? {};
|
|
83
|
+
/**
|
|
84
|
+
* Fires a GET request and returns a read-only signal updated when the response arrives.
|
|
85
|
+
* Must be called from an injection context. The request is aborted on host destroy.
|
|
86
|
+
*
|
|
87
|
+
* @param url - Absolute or base-relative URL.
|
|
88
|
+
* @param options - Per-request overrides (headers, params, timeout, signal).
|
|
89
|
+
* @returns A read-only `Signal<T | null>` — `null` until the response arrives.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* readonly user = inject(SignalHttpClient).get<User>('/users/1');
|
|
93
|
+
*/
|
|
94
|
+
get(url, options) {
|
|
95
|
+
return this.createSignal({ ...options, url, method: 'GET' });
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Fires a POST request and returns a read-only signal updated when the response arrives.
|
|
99
|
+
* Must be called from an injection context. The request is aborted on host destroy.
|
|
100
|
+
*
|
|
101
|
+
* @param url - Absolute or base-relative URL.
|
|
102
|
+
* @param body - Request body; serialised to JSON.
|
|
103
|
+
* @param options - Per-request overrides.
|
|
104
|
+
* @returns A read-only `Signal<T | null>` — `null` until the response arrives.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* readonly result = inject(SignalHttpClient).post<Token>('/auth/login', credentials);
|
|
108
|
+
*/
|
|
109
|
+
post(url, body, options) {
|
|
110
|
+
return this.createSignal({ ...options, url, method: 'POST', body });
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Fires a PUT request and returns a read-only signal updated when the response arrives.
|
|
114
|
+
* Must be called from an injection context. The request is aborted on host destroy.
|
|
115
|
+
*
|
|
116
|
+
* @param url - Absolute or base-relative URL.
|
|
117
|
+
* @param body - Request body; serialised to JSON.
|
|
118
|
+
* @param options - Per-request overrides.
|
|
119
|
+
* @returns A read-only `Signal<T | null>` — `null` until the response arrives.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* readonly updated = inject(SignalHttpClient).put<User>('/users/1', { name: 'Alice' });
|
|
123
|
+
*/
|
|
124
|
+
put(url, body, options) {
|
|
125
|
+
return this.createSignal({ ...options, url, method: 'PUT', body });
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Fires a PATCH request and returns a read-only signal updated when the response arrives.
|
|
129
|
+
* Must be called from an injection context. The request is aborted on host destroy.
|
|
130
|
+
*
|
|
131
|
+
* @param url - Absolute or base-relative URL.
|
|
132
|
+
* @param body - Partial request body; serialised to JSON.
|
|
133
|
+
* @param options - Per-request overrides.
|
|
134
|
+
* @returns A read-only `Signal<T | null>` — `null` until the response arrives.
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* readonly patched = inject(SignalHttpClient).patch<User>('/users/1', { email: 'new@example.com' });
|
|
138
|
+
*/
|
|
139
|
+
patch(url, body, options) {
|
|
140
|
+
return this.createSignal({ ...options, url, method: 'PATCH', body });
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Fires a DELETE request and returns a read-only signal updated when the response arrives.
|
|
144
|
+
* Must be called from an injection context. The request is aborted on host destroy.
|
|
145
|
+
*
|
|
146
|
+
* @param url - Absolute or base-relative URL.
|
|
147
|
+
* @param options - Per-request overrides.
|
|
148
|
+
* @returns A read-only `Signal<T | null>` — `null` until the response arrives.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* readonly deleted = inject(SignalHttpClient).delete<void>('/users/1');
|
|
152
|
+
*/
|
|
153
|
+
delete(url, options) {
|
|
154
|
+
return this.createSignal({ ...options, url, method: 'DELETE' });
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Executes a raw HTTP request and returns a `Promise`.
|
|
158
|
+
* Use this in effects, event handlers, guards, and resolvers where async/await is preferred.
|
|
159
|
+
* Runs request → response → error interceptors in registration order.
|
|
160
|
+
* `AbortError` is re-thrown without passing through error interceptors.
|
|
161
|
+
*
|
|
162
|
+
* @param config - Full request configuration including method and URL.
|
|
163
|
+
* @returns A `Promise` that resolves with the parsed response body.
|
|
164
|
+
* @throws `HttpError` on non-2xx responses; `AbortError` on cancellation.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* const token = await http.executeRequest<Token>({ url: '/auth/login', method: 'POST', body: creds });
|
|
168
|
+
*/
|
|
169
|
+
async executeRequest(config) {
|
|
170
|
+
let processedConfig = { ...config };
|
|
171
|
+
for (const interceptor of this.config.interceptors ?? []) {
|
|
172
|
+
if (interceptor.request) {
|
|
173
|
+
processedConfig = await interceptor.request(processedConfig);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const url = this.buildUrl(processedConfig);
|
|
177
|
+
const headers = this.buildHeaders(processedConfig);
|
|
178
|
+
const timeout = processedConfig.timeout ?? this.config.timeout;
|
|
179
|
+
const controller = new AbortController();
|
|
180
|
+
let timeoutId;
|
|
181
|
+
if (timeout) {
|
|
182
|
+
timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
183
|
+
}
|
|
184
|
+
if (processedConfig.signal) {
|
|
185
|
+
if (processedConfig.signal.aborted) {
|
|
186
|
+
controller.abort(processedConfig.signal.reason);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
processedConfig.signal.addEventListener('abort', () => controller.abort(processedConfig.signal?.reason), { once: true });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const init = {
|
|
194
|
+
method: processedConfig.method,
|
|
195
|
+
headers,
|
|
196
|
+
signal: controller.signal,
|
|
197
|
+
};
|
|
198
|
+
if (processedConfig.body !== undefined) {
|
|
199
|
+
init.body = JSON.stringify(processedConfig.body);
|
|
200
|
+
}
|
|
201
|
+
let response = await fetch(url, init);
|
|
202
|
+
for (const interceptor of this.config.interceptors ?? []) {
|
|
203
|
+
if (interceptor.response) {
|
|
204
|
+
response = await interceptor.response(response);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
throw new HttpError(`HTTP ${response.status}: ${response.statusText}`, response.status, response);
|
|
209
|
+
}
|
|
210
|
+
return this.parseResponse(response);
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
let err = error instanceof Error ? error : new Error(String(error));
|
|
217
|
+
for (const interceptor of this.config.interceptors ?? []) {
|
|
218
|
+
if (interceptor.error) {
|
|
219
|
+
err = await interceptor.error(err);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
throw err;
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
clearTimeout(timeoutId);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
createSignal(config) {
|
|
229
|
+
const result = signal(null, ...(ngDevMode ? [{ debugName: "result" }] : /* istanbul ignore next */ []));
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
inject(DestroyRef).onDestroy(() => controller.abort());
|
|
232
|
+
this.executeRequest({ ...config, signal: controller.signal })
|
|
233
|
+
.then(data => result.set(data))
|
|
234
|
+
.catch((err) => {
|
|
235
|
+
if (!(err instanceof Error && err.name === 'AbortError')) {
|
|
236
|
+
console.error('[ng-signal-http]', err);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
return result.asReadonly();
|
|
240
|
+
}
|
|
241
|
+
buildUrl(config) {
|
|
242
|
+
let url;
|
|
243
|
+
if (config.url.startsWith('http://') || config.url.startsWith('https://')) {
|
|
244
|
+
url = config.url;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
const base = this.config.baseUrl?.replace(/\/$/, '') ?? '';
|
|
248
|
+
const path = config.url.startsWith('/') ? config.url : `/${config.url}`;
|
|
249
|
+
url = base ? `${base}${path}` : config.url;
|
|
250
|
+
}
|
|
251
|
+
if (config.params && Object.keys(config.params).length > 0) {
|
|
252
|
+
const params = new URLSearchParams();
|
|
253
|
+
for (const [key, value] of Object.entries(config.params)) {
|
|
254
|
+
params.append(key, String(value));
|
|
255
|
+
}
|
|
256
|
+
url += `?${params.toString()}`;
|
|
257
|
+
}
|
|
258
|
+
return url;
|
|
259
|
+
}
|
|
260
|
+
buildHeaders(config) {
|
|
261
|
+
return {
|
|
262
|
+
'Content-Type': 'application/json',
|
|
263
|
+
...this.config.headers,
|
|
264
|
+
...config.headers,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
async parseResponse(response) {
|
|
268
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
269
|
+
if (contentType.includes('application/json')) {
|
|
270
|
+
return response.json();
|
|
271
|
+
}
|
|
272
|
+
return response.text();
|
|
273
|
+
}
|
|
274
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SignalHttpClient, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
275
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SignalHttpClient, providedIn: 'root' });
|
|
276
|
+
}
|
|
277
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SignalHttpClient, decorators: [{
|
|
278
|
+
type: Injectable,
|
|
279
|
+
args: [{ providedIn: 'root' }]
|
|
280
|
+
}] });
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Creates a reactive GET query bound to the current Angular injection context.
|
|
284
|
+
*
|
|
285
|
+
* Fetches immediately (unless `lazy: true`) and re-fetches automatically whenever
|
|
286
|
+
* any signal read inside the `url` factory changes. The in-flight request is
|
|
287
|
+
* aborted when the host component or service is destroyed.
|
|
288
|
+
*
|
|
289
|
+
* @template T - The expected response data type.
|
|
290
|
+
* @param url - A static URL string or a factory that returns a URL or `RequestConfig`.
|
|
291
|
+
* Signal reads inside the factory are tracked — changing them triggers a re-fetch.
|
|
292
|
+
* @param options - Query behaviour: lazy loading, retry, stale time, polling, callbacks, etc.
|
|
293
|
+
* @returns An `HttpClientResult<T>` with reactive signals and control methods.
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* // Static URL — fetch once on init
|
|
297
|
+
* const posts = querySignal<Post[]>('/posts');
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* // Reactive factory — refetches when postId() changes
|
|
301
|
+
* const postId = signal(1);
|
|
302
|
+
* const post = querySignal<Post>(() => `/posts/${postId()}`);
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* // With options
|
|
306
|
+
* const data = querySignal('/feed', {
|
|
307
|
+
* retry: 3,
|
|
308
|
+
* refetchOnFocus: true,
|
|
309
|
+
* staleTime: 60_000,
|
|
310
|
+
* onError: (err) => console.error(err),
|
|
311
|
+
* });
|
|
312
|
+
*/
|
|
313
|
+
function querySignal(url, options) {
|
|
314
|
+
const httpClient = inject(SignalHttpClient);
|
|
315
|
+
const destroyRef = inject(DestroyRef);
|
|
316
|
+
const injector = inject(Injector);
|
|
317
|
+
const isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
318
|
+
const factory = typeof url === 'string' ? () => url : url;
|
|
319
|
+
const data = signal(options?.initialValue ?? null, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
320
|
+
const loading = signal(!options?.lazy, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
321
|
+
const error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
322
|
+
const status = signal(options?.lazy ? 'idle' : 'loading', ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
323
|
+
const lastFetchAt = signal(0, ...(ngDevMode ? [{ debugName: "lastFetchAt" }] : /* istanbul ignore next */ []));
|
|
324
|
+
const isStale = computed(() => {
|
|
325
|
+
if (!options?.staleTime || lastFetchAt() === 0)
|
|
326
|
+
return false;
|
|
327
|
+
return Date.now() - lastFetchAt() > options.staleTime;
|
|
328
|
+
}, ...(ngDevMode ? [{ debugName: "isStale" }] : /* istanbul ignore next */ []));
|
|
329
|
+
let abortController;
|
|
330
|
+
const doFetch = async () => {
|
|
331
|
+
abortController?.abort();
|
|
332
|
+
abortController = new AbortController();
|
|
333
|
+
loading.set(true);
|
|
334
|
+
status.set('loading');
|
|
335
|
+
error.set(null);
|
|
336
|
+
try {
|
|
337
|
+
const urlResult = untracked(factory);
|
|
338
|
+
const requestConfig = typeof urlResult === 'string'
|
|
339
|
+
? { url: urlResult, method: 'GET' }
|
|
340
|
+
: urlResult;
|
|
341
|
+
const result = await attemptWithRetry(httpClient, requestConfig, abortController.signal, options?.retry);
|
|
342
|
+
data.set(result);
|
|
343
|
+
status.set('success');
|
|
344
|
+
lastFetchAt.set(Date.now());
|
|
345
|
+
options?.onSuccess?.(result);
|
|
346
|
+
}
|
|
347
|
+
catch (e) {
|
|
348
|
+
if (isAbortError(e))
|
|
349
|
+
return;
|
|
350
|
+
const err = toError(e);
|
|
351
|
+
error.set(err);
|
|
352
|
+
status.set('error');
|
|
353
|
+
options?.onError?.(err);
|
|
354
|
+
}
|
|
355
|
+
finally {
|
|
356
|
+
loading.set(false);
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
// Reactive effect — tracks signals in factory(), refetches when they change.
|
|
360
|
+
// lazy skips the first run so no fetch fires on init.
|
|
361
|
+
let isFirstRun = options?.lazy ?? false;
|
|
362
|
+
runInInjectionContext(injector, () => {
|
|
363
|
+
effect(() => {
|
|
364
|
+
factory();
|
|
365
|
+
if (isFirstRun) {
|
|
366
|
+
isFirstRun = false;
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
untracked(() => doFetch());
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
if (options?.refetchInterval && isBrowser) {
|
|
373
|
+
const id = setInterval(() => {
|
|
374
|
+
if (!loading())
|
|
375
|
+
doFetch();
|
|
376
|
+
}, options.refetchInterval);
|
|
377
|
+
destroyRef.onDestroy(() => clearInterval(id));
|
|
378
|
+
}
|
|
379
|
+
if (options?.refetchOnFocus && isBrowser) {
|
|
380
|
+
const handler = () => {
|
|
381
|
+
if (isStale() && !loading())
|
|
382
|
+
doFetch();
|
|
383
|
+
};
|
|
384
|
+
window.addEventListener('focus', handler);
|
|
385
|
+
destroyRef.onDestroy(() => window.removeEventListener('focus', handler));
|
|
386
|
+
}
|
|
387
|
+
if (options?.refetchOnReconnect && isBrowser) {
|
|
388
|
+
const handler = () => {
|
|
389
|
+
if (!loading())
|
|
390
|
+
doFetch();
|
|
391
|
+
};
|
|
392
|
+
window.addEventListener('online', handler);
|
|
393
|
+
destroyRef.onDestroy(() => window.removeEventListener('online', handler));
|
|
394
|
+
}
|
|
395
|
+
destroyRef.onDestroy(() => {
|
|
396
|
+
abortController?.abort();
|
|
397
|
+
});
|
|
398
|
+
return {
|
|
399
|
+
data: data.asReadonly(),
|
|
400
|
+
loading: loading.asReadonly(),
|
|
401
|
+
error: error.asReadonly(),
|
|
402
|
+
status: status.asReadonly(),
|
|
403
|
+
isStale,
|
|
404
|
+
refetch: doFetch,
|
|
405
|
+
invalidate: () => lastFetchAt.set(0),
|
|
406
|
+
reset: () => {
|
|
407
|
+
abortController?.abort();
|
|
408
|
+
data.set(options?.initialValue ?? null);
|
|
409
|
+
loading.set(false);
|
|
410
|
+
error.set(null);
|
|
411
|
+
status.set('idle');
|
|
412
|
+
lastFetchAt.set(0);
|
|
413
|
+
},
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
417
|
+
async function attemptWithRetry(client, config, signal, retry, attempt = 1) {
|
|
418
|
+
try {
|
|
419
|
+
return await client.executeRequest({ ...config, signal });
|
|
420
|
+
}
|
|
421
|
+
catch (e) {
|
|
422
|
+
const err = toError(e);
|
|
423
|
+
if (shouldRetry(err, attempt, retry)) {
|
|
424
|
+
await sleep(getRetryDelay(attempt, retry));
|
|
425
|
+
return attemptWithRetry(client, config, signal, retry, attempt + 1);
|
|
426
|
+
}
|
|
427
|
+
throw err;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function shouldRetry(err, attempt, retry) {
|
|
431
|
+
if (isAbortError(err))
|
|
432
|
+
return false;
|
|
433
|
+
const config = normalizeRetry(retry);
|
|
434
|
+
if (!config || attempt > config.count)
|
|
435
|
+
return false;
|
|
436
|
+
return config.shouldRetry ? config.shouldRetry(err, attempt) : true;
|
|
437
|
+
}
|
|
438
|
+
function getRetryDelay(attempt, retry) {
|
|
439
|
+
const config = normalizeRetry(retry);
|
|
440
|
+
if (!config?.delay)
|
|
441
|
+
return 0;
|
|
442
|
+
return typeof config.delay === 'function' ? config.delay(attempt) : config.delay;
|
|
443
|
+
}
|
|
444
|
+
function normalizeRetry(retry) {
|
|
445
|
+
if (retry === undefined)
|
|
446
|
+
return undefined;
|
|
447
|
+
return typeof retry === 'number' ? { count: retry } : retry;
|
|
448
|
+
}
|
|
449
|
+
function isAbortError(e) {
|
|
450
|
+
return e instanceof Error && e.name === 'AbortError';
|
|
451
|
+
}
|
|
452
|
+
function toError(e) {
|
|
453
|
+
return e instanceof Error ? e : new Error(String(e));
|
|
454
|
+
}
|
|
455
|
+
function sleep(ms) {
|
|
456
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Creates an imperative mutation bound to the current Angular injection context.
|
|
461
|
+
*
|
|
462
|
+
* Does nothing until `mutate(input)` is called. Calling `mutate()` while a previous
|
|
463
|
+
* request is in flight cancels the previous request automatically.
|
|
464
|
+
* The in-flight request is aborted when the host component or service is destroyed.
|
|
465
|
+
*
|
|
466
|
+
* @template TInput - The input type passed to `mutate()`.
|
|
467
|
+
* @template TOutput - The response data type returned by the server.
|
|
468
|
+
* @param requestFactory - Receives the mutation input and returns a `RequestConfig`.
|
|
469
|
+
* @param options - Optional lifecycle callbacks (`onSuccess`, `onError`, `onSettled`).
|
|
470
|
+
* @returns A `MutationResult<TInput, TOutput>` with reactive signals and a `mutate` trigger.
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* const createPost = mutationSignal<NewPost, Post>(
|
|
474
|
+
* (input) => ({ url: '/posts', method: 'POST', body: input }),
|
|
475
|
+
* { onSuccess: (post) => console.log('Created:', post.id) },
|
|
476
|
+
* );
|
|
477
|
+
*
|
|
478
|
+
* // Trigger from an event handler:
|
|
479
|
+
* await createPost.mutate({ title: 'Hello', body: 'World', userId: 1 });
|
|
480
|
+
*/
|
|
481
|
+
function mutationSignal(requestFactory, options) {
|
|
482
|
+
const httpClient = inject(SignalHttpClient);
|
|
483
|
+
const destroyRef = inject(DestroyRef);
|
|
484
|
+
const isPending = signal(false, ...(ngDevMode ? [{ debugName: "isPending" }] : /* istanbul ignore next */ []));
|
|
485
|
+
const error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
486
|
+
const data = signal(null, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
487
|
+
let abortController;
|
|
488
|
+
const mutate = async (input) => {
|
|
489
|
+
abortController?.abort();
|
|
490
|
+
abortController = new AbortController();
|
|
491
|
+
isPending.set(true);
|
|
492
|
+
error.set(null);
|
|
493
|
+
try {
|
|
494
|
+
const config = requestFactory(input);
|
|
495
|
+
const result = await httpClient.executeRequest({ ...config, signal: abortController.signal });
|
|
496
|
+
data.set(result);
|
|
497
|
+
options?.onSuccess?.(result, input);
|
|
498
|
+
options?.onSettled?.(result, null, input);
|
|
499
|
+
return result;
|
|
500
|
+
}
|
|
501
|
+
catch (e) {
|
|
502
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
503
|
+
error.set(err);
|
|
504
|
+
options?.onError?.(err, input);
|
|
505
|
+
options?.onSettled?.(null, err, input);
|
|
506
|
+
throw err;
|
|
507
|
+
}
|
|
508
|
+
finally {
|
|
509
|
+
isPending.set(false);
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
destroyRef.onDestroy(() => {
|
|
513
|
+
abortController?.abort();
|
|
514
|
+
});
|
|
515
|
+
return {
|
|
516
|
+
isPending: isPending.asReadonly(),
|
|
517
|
+
error: error.asReadonly(),
|
|
518
|
+
data: data.asReadonly(),
|
|
519
|
+
mutate,
|
|
520
|
+
reset: () => {
|
|
521
|
+
isPending.set(false);
|
|
522
|
+
error.set(null);
|
|
523
|
+
data.set(null);
|
|
524
|
+
},
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Generated bundle index. Do not edit.
|
|
530
|
+
*/
|
|
531
|
+
|
|
532
|
+
export { HttpError, SIGNAL_HTTP_CONFIG, SignalHttpClient, mutationSignal, provideSignalHttp, querySignal };
|
|
533
|
+
//# sourceMappingURL=assebc-ng-signal-http.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assebc-ng-signal-http.mjs","sources":["../../../projects/signal-http/src/lib/core/providers.ts","../../../projects/signal-http/src/lib/core/http-error.ts","../../../projects/signal-http/src/lib/core/signal-http-client.ts","../../../projects/signal-http/src/lib/query/query-signal.ts","../../../projects/signal-http/src/lib/mutation/mutation-signal.ts","../../../projects/signal-http/src/assebc-ng-signal-http.ts"],"sourcesContent":["import { InjectionToken, makeEnvironmentProviders, EnvironmentProviders } from '@angular/core';\nimport { SignalHttpConfig } from '../types';\n\nexport const SIGNAL_HTTP_CONFIG = new InjectionToken<SignalHttpConfig>(\n 'SIGNAL_HTTP_CONFIG'\n);\n\n/**\n * Registers `ng-signal-http` in an Angular application.\n * Call once in `app.config.ts` inside `ApplicationConfig.providers`.\n *\n * @param config - Global HTTP configuration applied to all requests.\n * @returns Angular `EnvironmentProviders` to add to your app config.\n *\n * @example\n * export const appConfig: ApplicationConfig = {\n * providers: [provideSignalHttp({ baseUrl: 'https://api.example.com' })],\n * };\n */\nexport function provideSignalHttp(config: SignalHttpConfig = {}): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: SIGNAL_HTTP_CONFIG,\n useValue: config\n }\n ]);\n}","/**\n * Error thrown when an HTTP request receives a non-2xx response.\n * Extends the native `Error` class and adds HTTP-specific helpers.\n *\n * @example\n * effect(() => {\n * const err = query.error();\n * if (err instanceof HttpError && err.isUnauthorized) router.navigate(['/login']);\n * });\n */\nexport class HttpError extends Error {\n /**\n * @param message - Human-readable error description.\n * @param status - HTTP status code (e.g. 404, 500).\n * @param response - The raw `Response` object, if available.\n */\n constructor(\n message: string,\n public readonly status: number,\n public readonly response?: Response\n ) {\n super(message);\n this.name = 'HttpError';\n Object.setPrototypeOf(this, HttpError.prototype);\n }\n\n get isClientError(): boolean {\n return this.status >= 400 && this.status < 500;\n }\n\n get isServerError(): boolean {\n return this.status >= 500;\n }\n\n get isTimeout(): boolean { \n return this.status === 408;\n }\n\n get isNotFound(): boolean {\n return this.status === 404;\n }\n\n get isUnauthorized(): boolean {\n return this.status === 401;\n }\n\n get isForbidden(): boolean {\n return this.status === 403;\n }\n}","import { DestroyRef, inject, Injectable, Signal, signal } from \"@angular/core\";\nimport { SIGNAL_HTTP_CONFIG } from \"./providers\";\nimport { RequestConfig } from \"../types\";\nimport { HttpError } from \"./http-error\";\n\n/**\n * Low-level HTTP service that wraps the native Fetch API.\n * Prefer `querySignal` and `mutationSignal` for component use;\n * use this directly in guards, resolvers, and async effects.\n *\n * @example\n * const http = inject(SignalHttpClient);\n * const user = await http.executeRequest<User>({ url: '/users/1', method: 'GET' });\n */\n@Injectable({ providedIn: 'root' })\nexport class SignalHttpClient {\n private readonly config = inject(SIGNAL_HTTP_CONFIG, { optional: true }) ?? {};\n\n /**\n * Fires a GET request and returns a read-only signal updated when the response arrives.\n * Must be called from an injection context. The request is aborted on host destroy.\n *\n * @param url - Absolute or base-relative URL.\n * @param options - Per-request overrides (headers, params, timeout, signal).\n * @returns A read-only `Signal<T | null>` — `null` until the response arrives.\n *\n * @example\n * readonly user = inject(SignalHttpClient).get<User>('/users/1');\n */\n get<T>(url: string, options?: Partial<RequestConfig>): Signal<T | null> {\n return this.createSignal<T>({ ...options, url, method: 'GET' });\n }\n\n /**\n * Fires a POST request and returns a read-only signal updated when the response arrives.\n * Must be called from an injection context. The request is aborted on host destroy.\n *\n * @param url - Absolute or base-relative URL.\n * @param body - Request body; serialised to JSON.\n * @param options - Per-request overrides.\n * @returns A read-only `Signal<T | null>` — `null` until the response arrives.\n *\n * @example\n * readonly result = inject(SignalHttpClient).post<Token>('/auth/login', credentials);\n */\n post<T>(url: string, body?: unknown, options?: Partial<RequestConfig>): Signal<T | null> {\n return this.createSignal<T>({ ...options, url, method: 'POST', body });\n }\n\n /**\n * Fires a PUT request and returns a read-only signal updated when the response arrives.\n * Must be called from an injection context. The request is aborted on host destroy.\n *\n * @param url - Absolute or base-relative URL.\n * @param body - Request body; serialised to JSON.\n * @param options - Per-request overrides.\n * @returns A read-only `Signal<T | null>` — `null` until the response arrives.\n *\n * @example\n * readonly updated = inject(SignalHttpClient).put<User>('/users/1', { name: 'Alice' });\n */\n put<T>(url: string, body?: unknown, options?: Partial<RequestConfig>): Signal<T | null> {\n return this.createSignal<T>({ ...options, url, method: 'PUT', body });\n }\n\n /**\n * Fires a PATCH request and returns a read-only signal updated when the response arrives.\n * Must be called from an injection context. The request is aborted on host destroy.\n *\n * @param url - Absolute or base-relative URL.\n * @param body - Partial request body; serialised to JSON.\n * @param options - Per-request overrides.\n * @returns A read-only `Signal<T | null>` — `null` until the response arrives.\n *\n * @example\n * readonly patched = inject(SignalHttpClient).patch<User>('/users/1', { email: 'new@example.com' });\n */\n patch<T>(url: string, body?: unknown, options?: Partial<RequestConfig>): Signal<T | null> {\n return this.createSignal<T>({ ...options, url, method: 'PATCH', body });\n }\n\n /**\n * Fires a DELETE request and returns a read-only signal updated when the response arrives.\n * Must be called from an injection context. The request is aborted on host destroy.\n *\n * @param url - Absolute or base-relative URL.\n * @param options - Per-request overrides.\n * @returns A read-only `Signal<T | null>` — `null` until the response arrives.\n *\n * @example\n * readonly deleted = inject(SignalHttpClient).delete<void>('/users/1');\n */\n delete<T>(url: string, options?: Partial<RequestConfig>): Signal<T | null> {\n return this.createSignal<T>({ ...options, url, method: 'DELETE' });\n }\n\n /**\n * Executes a raw HTTP request and returns a `Promise`.\n * Use this in effects, event handlers, guards, and resolvers where async/await is preferred.\n * Runs request → response → error interceptors in registration order.\n * `AbortError` is re-thrown without passing through error interceptors.\n *\n * @param config - Full request configuration including method and URL.\n * @returns A `Promise` that resolves with the parsed response body.\n * @throws `HttpError` on non-2xx responses; `AbortError` on cancellation.\n *\n * @example\n * const token = await http.executeRequest<Token>({ url: '/auth/login', method: 'POST', body: creds });\n */\n async executeRequest<T>(config: RequestConfig): Promise<T> {\n let processedConfig = { ...config };\n\n for (const interceptor of this.config.interceptors ?? []) {\n if (interceptor.request) {\n processedConfig = await interceptor.request(processedConfig);\n }\n }\n\n const url = this.buildUrl(processedConfig);\n const headers = this.buildHeaders(processedConfig);\n const timeout = processedConfig.timeout ?? this.config.timeout;\n\n const controller = new AbortController();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n if (timeout) {\n timeoutId = setTimeout(() => controller.abort(), timeout);\n }\n\n if (processedConfig.signal) {\n if (processedConfig.signal.aborted) {\n controller.abort(processedConfig.signal.reason);\n } else {\n processedConfig.signal.addEventListener(\n 'abort',\n () => controller.abort(processedConfig.signal?.reason),\n { once: true }\n );\n }\n }\n\n try {\n const init: RequestInit = {\n method: processedConfig.method,\n headers,\n signal: controller.signal,\n };\n\n if (processedConfig.body !== undefined) {\n init.body = JSON.stringify(processedConfig.body);\n }\n\n let response = await fetch(url, init);\n\n for (const interceptor of this.config.interceptors ?? []) {\n if (interceptor.response) {\n response = await interceptor.response(response);\n }\n }\n\n if (!response.ok) {\n throw new HttpError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status,\n response\n );\n }\n\n return this.parseResponse<T>(response);\n\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw error;\n }\n\n let err = error instanceof Error ? error : new Error(String(error));\n\n for (const interceptor of this.config.interceptors ?? []) {\n if (interceptor.error) {\n err = await interceptor.error(err);\n }\n }\n\n throw err;\n\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private createSignal<T>(config: RequestConfig): Signal<T | null> {\n const result = signal<T | null>(null);\n const controller = new AbortController();\n\n inject(DestroyRef).onDestroy(() => controller.abort());\n\n this.executeRequest<T>({ ...config, signal: controller.signal })\n .then(data => result.set(data))\n .catch((err: unknown) => {\n if (!(err instanceof Error && err.name === 'AbortError')) {\n console.error('[ng-signal-http]', err);\n }\n });\n\n return result.asReadonly();\n }\n\n private buildUrl(config: RequestConfig): string {\n let url: string;\n\n if (config.url.startsWith('http://') || config.url.startsWith('https://')) {\n url = config.url;\n } else {\n const base = this.config.baseUrl?.replace(/\\/$/, '') ?? '';\n const path = config.url.startsWith('/') ? config.url : `/${config.url}`;\n url = base ? `${base}${path}` : config.url;\n }\n\n if (config.params && Object.keys(config.params).length > 0) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(config.params)) {\n params.append(key, String(value));\n }\n url += `?${params.toString()}`;\n }\n\n return url;\n }\n\n private buildHeaders(config: RequestConfig): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n ...config.headers,\n };\n }\n\n private async parseResponse<T>(response: Response): Promise<T> {\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n return response.json() as Promise<T>;\n }\n return response.text() as unknown as Promise<T>;\n }\n}\n","import {\n computed,\n DestroyRef,\n effect,\n inject,\n Injector,\n PLATFORM_ID,\n runInInjectionContext,\n signal,\n untracked,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { SignalHttpClient } from '../core/signal-http-client';\nimport { HttpClientOptions, HttpClientResult, HttpClientStatus, RequestConfig, RetryConfig } from '../types';\nimport { UrlFactory } from './query.types';\n\n/**\n * Creates a reactive GET query bound to the current Angular injection context.\n *\n * Fetches immediately (unless `lazy: true`) and re-fetches automatically whenever\n * any signal read inside the `url` factory changes. The in-flight request is\n * aborted when the host component or service is destroyed.\n *\n * @template T - The expected response data type.\n * @param url - A static URL string or a factory that returns a URL or `RequestConfig`.\n * Signal reads inside the factory are tracked — changing them triggers a re-fetch.\n * @param options - Query behaviour: lazy loading, retry, stale time, polling, callbacks, etc.\n * @returns An `HttpClientResult<T>` with reactive signals and control methods.\n *\n * @example\n * // Static URL — fetch once on init\n * const posts = querySignal<Post[]>('/posts');\n *\n * @example\n * // Reactive factory — refetches when postId() changes\n * const postId = signal(1);\n * const post = querySignal<Post>(() => `/posts/${postId()}`);\n *\n * @example\n * // With options\n * const data = querySignal('/feed', {\n * retry: 3,\n * refetchOnFocus: true,\n * staleTime: 60_000,\n * onError: (err) => console.error(err),\n * });\n */\nexport function querySignal<T>(\n url: string | UrlFactory,\n options?: HttpClientOptions<T>\n): HttpClientResult<T> {\n const httpClient = inject(SignalHttpClient);\n const destroyRef = inject(DestroyRef);\n const injector = inject(Injector);\n const isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n const factory: UrlFactory = typeof url === 'string' ? () => url : url;\n\n const data = signal<T | null>(options?.initialValue ?? null);\n const loading = signal<boolean>(!options?.lazy);\n const error = signal<Error | null>(null);\n const status = signal<HttpClientStatus>(options?.lazy ? 'idle' : 'loading');\n const lastFetchAt = signal<number>(0);\n\n const isStale = computed(() => {\n if (!options?.staleTime || lastFetchAt() === 0) return false;\n return Date.now() - lastFetchAt() > options.staleTime;\n });\n\n let abortController: AbortController | undefined;\n\n const doFetch = async (): Promise<void> => {\n abortController?.abort();\n abortController = new AbortController();\n\n loading.set(true);\n status.set('loading');\n error.set(null);\n\n try {\n const urlResult = untracked(factory);\n const requestConfig: RequestConfig =\n typeof urlResult === 'string'\n ? { url: urlResult, method: 'GET' }\n : urlResult;\n\n const result = await attemptWithRetry<T>(httpClient, requestConfig, abortController.signal, options?.retry);\n data.set(result);\n status.set('success');\n lastFetchAt.set(Date.now());\n options?.onSuccess?.(result);\n } catch (e) {\n if (isAbortError(e)) return;\n const err = toError(e);\n error.set(err);\n status.set('error');\n options?.onError?.(err);\n } finally {\n loading.set(false);\n }\n };\n\n // Reactive effect — tracks signals in factory(), refetches when they change.\n // lazy skips the first run so no fetch fires on init.\n let isFirstRun = options?.lazy ?? false;\n runInInjectionContext(injector, () => {\n effect(() => {\n factory();\n if (isFirstRun) {\n isFirstRun = false;\n return;\n }\n untracked(() => doFetch());\n });\n });\n\n if (options?.refetchInterval && isBrowser) {\n const id = setInterval(() => {\n if (!loading()) doFetch();\n }, options.refetchInterval);\n destroyRef.onDestroy(() => clearInterval(id));\n }\n\n if (options?.refetchOnFocus && isBrowser) {\n const handler = () => {\n if (isStale() && !loading()) doFetch();\n };\n window.addEventListener('focus', handler);\n destroyRef.onDestroy(() => window.removeEventListener('focus', handler));\n }\n\n if (options?.refetchOnReconnect && isBrowser) {\n const handler = () => {\n if (!loading()) doFetch();\n };\n window.addEventListener('online', handler);\n destroyRef.onDestroy(() => window.removeEventListener('online', handler));\n }\n\n destroyRef.onDestroy(() => {\n abortController?.abort();\n });\n\n return {\n data: data.asReadonly(),\n loading: loading.asReadonly(),\n error: error.asReadonly(),\n status: status.asReadonly(),\n isStale,\n refetch: doFetch,\n invalidate: () => lastFetchAt.set(0),\n reset: () => {\n abortController?.abort();\n data.set(options?.initialValue ?? null);\n loading.set(false);\n error.set(null);\n status.set('idle');\n lastFetchAt.set(0);\n },\n };\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nasync function attemptWithRetry<T>(\n client: SignalHttpClient,\n config: RequestConfig,\n signal: AbortSignal,\n retry?: number | RetryConfig,\n attempt = 1\n): Promise<T> {\n try {\n return await client.executeRequest<T>({ ...config, signal });\n } catch (e) {\n const err = toError(e);\n if (shouldRetry(err, attempt, retry)) {\n await sleep(getRetryDelay(attempt, retry));\n return attemptWithRetry(client, config, signal, retry, attempt + 1);\n }\n throw err;\n }\n}\n\nfunction shouldRetry(err: Error, attempt: number, retry?: number | RetryConfig): boolean {\n if (isAbortError(err)) return false;\n const config = normalizeRetry(retry);\n if (!config || attempt > config.count) return false;\n return config.shouldRetry ? config.shouldRetry(err, attempt) : true;\n}\n\nfunction getRetryDelay(attempt: number, retry?: number | RetryConfig): number {\n const config = normalizeRetry(retry);\n if (!config?.delay) return 0;\n return typeof config.delay === 'function' ? config.delay(attempt) : config.delay;\n}\n\nfunction normalizeRetry(retry?: number | RetryConfig): RetryConfig | undefined {\n if (retry === undefined) return undefined;\n return typeof retry === 'number' ? { count: retry } : retry;\n}\n\nfunction isAbortError(e: unknown): e is Error {\n return e instanceof Error && e.name === 'AbortError';\n}\n\nfunction toError(e: unknown): Error {\n return e instanceof Error ? e : new Error(String(e));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n","import { DestroyRef, inject, signal } from '@angular/core';\nimport { SignalHttpClient } from '../core/signal-http-client';\nimport { MutationOptions, MutationResult } from '../types';\nimport { MutationFactory } from './mutation.types';\n\n/**\n * Creates an imperative mutation bound to the current Angular injection context.\n *\n * Does nothing until `mutate(input)` is called. Calling `mutate()` while a previous\n * request is in flight cancels the previous request automatically.\n * The in-flight request is aborted when the host component or service is destroyed.\n *\n * @template TInput - The input type passed to `mutate()`.\n * @template TOutput - The response data type returned by the server.\n * @param requestFactory - Receives the mutation input and returns a `RequestConfig`.\n * @param options - Optional lifecycle callbacks (`onSuccess`, `onError`, `onSettled`).\n * @returns A `MutationResult<TInput, TOutput>` with reactive signals and a `mutate` trigger.\n *\n * @example\n * const createPost = mutationSignal<NewPost, Post>(\n * (input) => ({ url: '/posts', method: 'POST', body: input }),\n * { onSuccess: (post) => console.log('Created:', post.id) },\n * );\n *\n * // Trigger from an event handler:\n * await createPost.mutate({ title: 'Hello', body: 'World', userId: 1 });\n */\nexport function mutationSignal<TInput, TOutput>(\n requestFactory: MutationFactory<TInput>,\n options?: MutationOptions<TInput, TOutput>\n): MutationResult<TInput, TOutput> {\n const httpClient = inject(SignalHttpClient);\n const destroyRef = inject(DestroyRef);\n\n const isPending = signal<boolean>(false);\n const error = signal<Error | null>(null);\n const data = signal<TOutput | null>(null);\n\n let abortController: AbortController | undefined;\n\n const mutate = async (input: TInput): Promise<TOutput> => {\n abortController?.abort();\n abortController = new AbortController();\n\n isPending.set(true);\n error.set(null);\n\n try {\n const config = requestFactory(input);\n const result = await httpClient.executeRequest<TOutput>({ ...config, signal: abortController.signal });\n\n data.set(result);\n options?.onSuccess?.(result, input);\n options?.onSettled?.(result, null, input);\n return result;\n\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n error.set(err);\n options?.onError?.(err, input);\n options?.onSettled?.(null, err, input);\n throw err;\n\n } finally {\n isPending.set(false);\n }\n };\n\n destroyRef.onDestroy(() => {\n abortController?.abort();\n });\n\n return {\n isPending: isPending.asReadonly(),\n error: error.asReadonly(),\n data: data.asReadonly(),\n mutate,\n reset: () => {\n isPending.set(false);\n error.set(null);\n data.set(null);\n },\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@assebc/ng-signal-http",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "^21.2.0",
|
|
6
|
+
"@angular/core": "^21.2.0"
|
|
7
|
+
},
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/assebc/ng-signal-http.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/assebc/ng-signal-http/issues"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/assebc/ng-signal-http#readme",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"angular",
|
|
20
|
+
"signals",
|
|
21
|
+
"http",
|
|
22
|
+
"zoneless",
|
|
23
|
+
"fetch",
|
|
24
|
+
"rxjs-free"
|
|
25
|
+
],
|
|
26
|
+
"module": "fesm2022/assebc-ng-signal-http.mjs",
|
|
27
|
+
"typings": "types/assebc-ng-signal-http.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
"./package.json": {
|
|
30
|
+
"default": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./types/assebc-ng-signal-http.d.ts",
|
|
34
|
+
"default": "./fesm2022/assebc-ng-signal-http.mjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"type": "module",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"tslib": "^2.3.0"
|
|
40
|
+
}
|
|
41
|
+
}
|