p3x-angular-http-cache-interceptor 2026.4.100 → 2026.4.103
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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
# 🔥 Cache every request in Angular, not only the GET, but all methods of this interceptor, and allows you to interact with the interceptor via specific headers and modify the request, and these specific headers will be not included in the final request v2026.4.
|
|
9
|
+
# 🔥 Cache every request in Angular, not only the GET, but all methods of this interceptor, and allows you to interact with the interceptor via specific headers and modify the request, and these specific headers will be not included in the final request v2026.4.103
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
@@ -31,7 +31,7 @@ v24.14.1
|
|
|
31
31
|
# 📦 Built on Angular
|
|
32
32
|
|
|
33
33
|
```text
|
|
34
|
-
21.2.
|
|
34
|
+
21.2.10
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
|
|
@@ -75,94 +75,121 @@ https://angular-http-cache-interceptor.corifeus.com
|
|
|
75
75
|
npm i p3x-angular-http-cache-interceptor object-hash
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Two ways to register the interceptor — **standalone** (recommended for new code) or **NgModule** (legacy, fully supported).
|
|
79
|
+
|
|
80
|
+
## Standalone / functional interceptor (Angular 16+)
|
|
81
|
+
|
|
82
|
+
In your `app.config.ts` (or wherever you build `ApplicationConfig`):
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { ApplicationConfig } from '@angular/core';
|
|
86
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
87
|
+
|
|
88
|
+
import {
|
|
89
|
+
p3xHttpCacheInterceptor,
|
|
90
|
+
provideP3xHttpCacheInterceptor,
|
|
91
|
+
CachingHeaders,
|
|
92
|
+
CachingStore,
|
|
93
|
+
} from 'p3x-angular-http-cache-interceptor';
|
|
94
|
+
|
|
95
|
+
export const appConfig: ApplicationConfig = {
|
|
96
|
+
providers: [
|
|
97
|
+
provideHttpClient(withInterceptors([p3xHttpCacheInterceptor])),
|
|
98
|
+
provideP3xHttpCacheInterceptor({
|
|
99
|
+
behavior: CachingHeaders.Cache,
|
|
100
|
+
store: CachingStore.Global,
|
|
101
|
+
}),
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The functional interceptor also works transparently with `httpResource()` — every call made through `HttpClient` (including `httpResource`) goes through the interceptor chain.
|
|
107
|
+
|
|
108
|
+
## NgModule (legacy, unchanged)
|
|
109
|
+
|
|
79
110
|
```ts
|
|
80
111
|
import { NgModule } from '@angular/core';
|
|
81
112
|
|
|
82
|
-
import { P3XHttpCacheInterceptorModule
|
|
113
|
+
import { P3XHttpCacheInterceptorModule } from 'p3x-angular-http-cache-interceptor';
|
|
83
114
|
|
|
84
115
|
@NgModule({
|
|
85
|
-
declarations: [
|
|
86
|
-
],
|
|
87
116
|
imports: [
|
|
88
|
-
P3XHttpCacheInterceptorModule
|
|
117
|
+
P3XHttpCacheInterceptorModule.forRoot({
|
|
118
|
+
behavior: CachingHeaders.Cache,
|
|
119
|
+
store: CachingStore.Global,
|
|
120
|
+
}),
|
|
89
121
|
],
|
|
90
|
-
providers: [
|
|
91
|
-
],
|
|
92
|
-
bootstrap: []
|
|
93
122
|
})
|
|
94
|
-
export class SomeModule {
|
|
123
|
+
export class SomeModule {}
|
|
95
124
|
```
|
|
96
125
|
|
|
97
|
-
###
|
|
98
|
-
```ts
|
|
99
|
-
import { P3XHttpCacheInterceptorModule, CachingHeaders, CachingStore } from 'p3x-angular-http-cache-interceptor';
|
|
126
|
+
### Configuration options
|
|
100
127
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
behavior: CachingHeaders.NoCache,
|
|
104
|
-
|
|
105
|
-
// if a request has CachingHeaders.Cache header it will cache globally
|
|
106
|
-
store: CachingStore.Global,
|
|
107
|
-
})
|
|
128
|
+
```ts
|
|
129
|
+
import { CachingHeaders, CachingStore } from 'p3x-angular-http-cache-interceptor';
|
|
108
130
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
131
|
+
// Opt-in: only cache when the request carries the Cache header
|
|
132
|
+
{
|
|
133
|
+
behavior: CachingHeaders.NoCache,
|
|
134
|
+
store: CachingStore.Global,
|
|
135
|
+
}
|
|
112
136
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
137
|
+
// Opt-out: cache by default, skip when the NoCache header is present
|
|
138
|
+
{
|
|
139
|
+
behavior: CachingHeaders.Cache,
|
|
140
|
+
store: CachingStore.PerModule, // class-based only; functional path falls back to Global
|
|
141
|
+
}
|
|
116
142
|
```
|
|
117
143
|
|
|
144
|
+
> **Note on `CachingStore.PerModule`:** the functional interceptor has no NgModule instance to own a per-module cache, so `PerModule` is treated as `Global` when using `p3xHttpCacheInterceptor`. The class-based `HttpCacheInterceptorInterceptor` still honours it via its per-instance cache.
|
|
145
|
+
|
|
118
146
|
## Example invocation in a component
|
|
119
147
|
|
|
120
148
|
With and without cache:
|
|
121
|
-
```ts
|
|
122
|
-
import { Component } from '@angular/core';
|
|
123
149
|
|
|
124
|
-
|
|
125
|
-
import {
|
|
150
|
+
```ts
|
|
151
|
+
import { Component, inject } from '@angular/core';
|
|
152
|
+
import { HttpClient } from '@angular/common/http';
|
|
153
|
+
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
154
|
+
import { firstValueFrom } from 'rxjs';
|
|
126
155
|
|
|
127
|
-
import { CachingHeaders } from 'p3x-angular-http-cache-interceptor'
|
|
156
|
+
import { CachingHeaders } from 'p3x-angular-http-cache-interceptor';
|
|
128
157
|
|
|
129
158
|
@Component({
|
|
130
159
|
selector: 'p3x-root',
|
|
131
160
|
templateUrl: './app.component.html',
|
|
132
|
-
styleUrls: ['./app.component.scss']
|
|
161
|
+
styleUrls: ['./app.component.scss'],
|
|
162
|
+
standalone: true,
|
|
133
163
|
})
|
|
134
164
|
export class AppComponent {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
private http: HttpClient,
|
|
138
|
-
private snack: MatSnackBar,
|
|
139
|
-
) {
|
|
140
|
-
}
|
|
165
|
+
private readonly http = inject(HttpClient);
|
|
166
|
+
private readonly snack = inject(MatSnackBar);
|
|
141
167
|
|
|
142
168
|
async loadCached() {
|
|
143
169
|
try {
|
|
144
|
-
const response
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
this.snack.open(`
|
|
148
|
-
|
|
170
|
+
const response: any = await firstValueFrom(
|
|
171
|
+
this.http.get('https://network.corifeus.com/public/api/random/32'),
|
|
172
|
+
);
|
|
173
|
+
this.snack.open(`Will be always the same: ${response.random}`, 'OK');
|
|
174
|
+
} catch (e) {
|
|
175
|
+
this.snack.open(`Sorry, error happened, check the console for the error`, 'OK');
|
|
176
|
+
console.error(e);
|
|
149
177
|
}
|
|
150
178
|
}
|
|
151
179
|
|
|
152
180
|
async loadNonCached() {
|
|
153
181
|
try {
|
|
154
|
-
const response
|
|
155
|
-
|
|
156
|
-
[CachingHeaders.NoCache]: '1'
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
this.snack.open(`Truly random data: ${response.random}`, 'OK')
|
|
160
|
-
} catch(e) {
|
|
161
|
-
this.snack.open(`Sorry, error happened, check the console for the error`, 'OK')
|
|
162
|
-
console.error(e)
|
|
182
|
+
const response: any = await firstValueFrom(
|
|
183
|
+
this.http.get('https://network.corifeus.com/public/api/random/32', {
|
|
184
|
+
headers: { [CachingHeaders.NoCache]: '1' },
|
|
185
|
+
}),
|
|
186
|
+
);
|
|
187
|
+
this.snack.open(`Truly random data: ${response.random}`, 'OK');
|
|
188
|
+
} catch (e) {
|
|
189
|
+
this.snack.open(`Sorry, error happened, check the console for the error`, 'OK');
|
|
190
|
+
console.error(e);
|
|
163
191
|
}
|
|
164
192
|
}
|
|
165
|
-
|
|
166
193
|
}
|
|
167
194
|
```
|
|
168
195
|
|
|
@@ -172,23 +199,22 @@ export class AppComponent {
|
|
|
172
199
|
|
|
173
200
|
---
|
|
174
201
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
If you want to quickly and affordably develop your next digital project, visit [corifeus.eu](https://corifeus.eu) for expert solutions tailored to your needs.
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## 🌐 Powerful Online Networking Tool
|
|
202
|
+
# Corifeus Network
|
|
182
203
|
|
|
183
|
-
|
|
204
|
+
AI-powered network & email toolkit — free, no signup.
|
|
184
205
|
|
|
185
|
-
|
|
186
|
-
Designed for professionals and enthusiasts, this tool provides essential features for network analysis, troubleshooting, and management.
|
|
187
|
-
Additionally, it offers tools for:
|
|
188
|
-
- 📡 Monitoring TCP, HTTP, and Ping to ensure optimal network performance and reliability.
|
|
189
|
-
- 📊 Status page management to track uptime, performance, and incidents in real time with customizable dashboards.
|
|
206
|
+
**Web** · [network.corifeus.com](https://network.corifeus.com) **MCP** · [`npm i -g p3x-network-mcp`](https://www.npmjs.com/package/p3x-network-mcp)
|
|
190
207
|
|
|
191
|
-
|
|
208
|
+
- **AI Network Assistant** — ask in plain language, get a full domain health report
|
|
209
|
+
- **Network Audit** — DNS, SSL, security headers, DNSBL, BGP, IPv6, geolocation in one call
|
|
210
|
+
- **Diagnostics** — DNS lookup & global propagation, WHOIS, reverse DNS, HTTP check, my-IP
|
|
211
|
+
- **Mail Tester** — live SPF/DKIM/DMARC + spam score + AI fix suggestions, results emailed (localized)
|
|
212
|
+
- **Monitoring** — TCP / HTTP / Ping with alerts and public status pages
|
|
213
|
+
- **MCP server** — 17 tools exposed to Claude Code, Codex, Cursor, any MCP client
|
|
214
|
+
- **Install** — `claude mcp add p3x-network -- npx p3x-network-mcp`
|
|
215
|
+
- **Try** — *"audit example.com"*, *"why do my emails land in spam? test me@example.com"*
|
|
216
|
+
- **Source** — [patrikx3/network](https://github.com/patrikx3/network) · [patrikx3/network-mcp](https://github.com/patrikx3/network-mcp)
|
|
217
|
+
- **Contact** — [patrikx3.com](https://www.patrikx3.com/en/front/contact) · [donate](https://paypal.me/patrikx3)
|
|
192
218
|
|
|
193
219
|
---
|
|
194
220
|
|
|
@@ -210,10 +236,8 @@ All my domains, including [patrikx3.com](https://patrikx3.com), [corifeus.eu](ht
|
|
|
210
236
|
|
|
211
237
|
**🚨 Important Changes:** Any breaking changes are prominently noted in the readme to keep you informed.
|
|
212
238
|
|
|
213
|
-
---
|
|
214
|
-
|
|
215
239
|
|
|
216
|
-
[**P3X-ANGULAR-HTTP-CACHE-INTERCEPTOR**](https://corifeus.com/angular-http-cache-interceptor) Build v2026.4.
|
|
240
|
+
[**P3X-ANGULAR-HTTP-CACHE-INTERCEPTOR**](https://corifeus.com/angular-http-cache-interceptor) Build v2026.4.103
|
|
217
241
|
|
|
218
242
|
[](https://www.npmjs.com/package/p3x-angular-http-cache-interceptor) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZVM4V6HVZJW6) [](https://www.patrikx3.com/en/front/contact) [](https://www.facebook.com/corifeus.software)
|
|
219
243
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, Inject, Optional, Injectable, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, Inject, Optional, Injectable, makeEnvironmentProviders, NgModule } from '@angular/core';
|
|
3
3
|
import { HttpResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
4
|
-
import {
|
|
5
|
-
import hash from 'object-hash';
|
|
4
|
+
import { of } from 'rxjs';
|
|
6
5
|
import { tap } from 'rxjs/operators';
|
|
6
|
+
import hash from 'object-hash';
|
|
7
7
|
|
|
8
8
|
// cache headers has to have a x- prefix
|
|
9
9
|
var CachingHeaders;
|
|
@@ -23,99 +23,82 @@ const P3X_HTTP_CACHE_CONFIG = new InjectionToken('P3X_HTTP_CACHE_CONFIG');
|
|
|
23
23
|
|
|
24
24
|
const hashOptions = {
|
|
25
25
|
algorithm: 'md5',
|
|
26
|
-
encoding: 'hex'
|
|
26
|
+
encoding: 'hex',
|
|
27
27
|
};
|
|
28
28
|
const globalCache = new Map();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
const DEFAULT_CONFIG = {
|
|
30
|
+
behavior: CachingHeaders.Cache,
|
|
31
|
+
store: CachingStore.Global,
|
|
32
|
+
};
|
|
33
|
+
function httpToKey(httpRequest) {
|
|
34
|
+
const body = JSON.parse(JSON.stringify(httpRequest.body));
|
|
35
|
+
return (httpRequest.method +
|
|
36
|
+
'@' + httpRequest.urlWithParams +
|
|
37
|
+
'@' + hash(httpRequest.params, hashOptions) +
|
|
38
|
+
'@' + hash(body, hashOptions));
|
|
39
|
+
}
|
|
40
|
+
function handle(httpRequest, next, config, perInstanceCache) {
|
|
41
|
+
const forcedCache = httpRequest.headers.get(CachingHeaders.Cache) !== null;
|
|
42
|
+
const forcedNoneCache = httpRequest.headers.get(CachingHeaders.NoCache) !== null;
|
|
43
|
+
let headers = httpRequest.headers.delete(CachingHeaders.NoCache);
|
|
44
|
+
headers = headers.delete(CachingHeaders.Cache);
|
|
45
|
+
httpRequest = httpRequest.clone({ headers });
|
|
46
|
+
if (forcedCache && forcedNoneCache) {
|
|
47
|
+
throw new Error('You cannot use cache and non-cache header at once!');
|
|
37
48
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
if (forcedNoneCache || (config.behavior === CachingHeaders.NoCache && !forcedCache)) {
|
|
50
|
+
return next(httpRequest);
|
|
51
|
+
}
|
|
52
|
+
if (forcedCache || (config.behavior === CachingHeaders.Cache && !forcedNoneCache)) {
|
|
53
|
+
const store = config.store === CachingStore.Global ? globalCache : perInstanceCache;
|
|
54
|
+
const key = httpToKey(httpRequest);
|
|
55
|
+
const lastResponse = store.get(key);
|
|
56
|
+
if (lastResponse) {
|
|
57
|
+
return of(lastResponse.clone());
|
|
44
58
|
}
|
|
59
|
+
return next(httpRequest).pipe(tap((stateEvent) => {
|
|
60
|
+
if (stateEvent instanceof HttpResponse) {
|
|
61
|
+
store.set(key, stateEvent.clone());
|
|
62
|
+
}
|
|
63
|
+
}));
|
|
45
64
|
}
|
|
65
|
+
console.error(config);
|
|
66
|
+
console.error(httpRequest.headers);
|
|
67
|
+
throw new Error('There is a configuration in your setup');
|
|
68
|
+
}
|
|
69
|
+
/*
|
|
70
|
+
Functional-interceptor path: there is no "module instance" to own a
|
|
71
|
+
PerModule cache, so PerModule falls back to this module-level map (one
|
|
72
|
+
per root injector, effectively Global-equivalent). The class-based
|
|
73
|
+
interceptor below still honours true PerModule via its instance field.
|
|
74
|
+
*/
|
|
75
|
+
const functionalPerInstanceCache = new Map();
|
|
76
|
+
/**
|
|
77
|
+
* Functional interceptor. Use with:
|
|
78
|
+
* `provideHttpClient(withInterceptors([p3xHttpCacheInterceptor]))`
|
|
79
|
+
* or the convenience `provideP3xHttpCacheInterceptor(config)` helper.
|
|
80
|
+
*/
|
|
81
|
+
const p3xHttpCacheInterceptor = (httpRequest, next) => {
|
|
82
|
+
const config = inject(P3X_HTTP_CACHE_CONFIG, { optional: true }) ?? DEFAULT_CONFIG;
|
|
83
|
+
return handle(httpRequest, (req) => next(req), config, functionalPerInstanceCache);
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Class-based interceptor — legacy shim kept for consumers still registering
|
|
87
|
+
* via `HTTP_INTERCEPTORS` / `P3XHttpCacheInterceptorModule.forRoot(...)`.
|
|
88
|
+
* Prefer `p3xHttpCacheInterceptor` (functional) for new code.
|
|
89
|
+
*/
|
|
90
|
+
class HttpCacheInterceptorInterceptor {
|
|
46
91
|
constructor(httpCacheConfigToken) {
|
|
47
92
|
this.cachedData = new Map();
|
|
48
|
-
this.httpCacheConfig =
|
|
49
|
-
behavior: CachingHeaders.Cache,
|
|
50
|
-
store: CachingStore.Global,
|
|
51
|
-
};
|
|
52
|
-
if (httpCacheConfigToken) {
|
|
53
|
-
this.httpCacheConfig = httpCacheConfigToken;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
httpToKey(httpRequest) {
|
|
57
|
-
const body = JSON.parse(JSON.stringify(httpRequest.body));
|
|
58
|
-
const key = httpRequest.method + '@' + httpRequest.urlWithParams + '@' + hash(httpRequest.params, hashOptions) + '@' + hash(body, hashOptions);
|
|
59
|
-
return key;
|
|
93
|
+
this.httpCacheConfig = httpCacheConfigToken ?? DEFAULT_CONFIG;
|
|
60
94
|
}
|
|
61
95
|
intercept(httpRequest, next) {
|
|
62
|
-
|
|
63
|
-
//console.log('has', httpRequest.headers.has(CachingHeaders.NoCache))
|
|
64
|
-
//console.log('value', httpRequest.headers.get(CachingHeaders.NoCache))
|
|
65
|
-
const forcedCache = httpRequest.headers.get(CachingHeaders.Cache) !== null;
|
|
66
|
-
const forcedNoneCache = httpRequest.headers.get(CachingHeaders.NoCache) !== null;
|
|
67
|
-
//console.log('forcedCache', forcedCache, 'forcedNoneCache', forcedNoneCache)
|
|
68
|
-
let headers = httpRequest.headers.delete(CachingHeaders.NoCache);
|
|
69
|
-
headers = headers.delete(CachingHeaders.Cache);
|
|
70
|
-
httpRequest = httpRequest.clone({
|
|
71
|
-
headers: headers
|
|
72
|
-
});
|
|
73
|
-
if (forcedCache && forcedNoneCache) {
|
|
74
|
-
throw new Error('You cannot use cache and non-cache header at once!');
|
|
75
|
-
}
|
|
76
|
-
else if (forcedNoneCache || (this.httpCacheConfig.behavior === CachingHeaders.NoCache && !forcedCache)) {
|
|
77
|
-
return next.handle(httpRequest);
|
|
78
|
-
}
|
|
79
|
-
else if (forcedCache || (this.httpCacheConfig.behavior === CachingHeaders.Cache && !forcedNoneCache)) {
|
|
80
|
-
// Checked if there is cached data for this URI
|
|
81
|
-
const key = this.httpToKey(httpRequest);
|
|
82
|
-
const lastResponse = this.getCache(key);
|
|
83
|
-
if (lastResponse) {
|
|
84
|
-
// In case of parallel requests to same URI,
|
|
85
|
-
// return the request already in progress
|
|
86
|
-
// otherwise return the last cached data
|
|
87
|
-
//console.info('http cache interceptor hit cache', key)
|
|
88
|
-
return (lastResponse instanceof Observable)
|
|
89
|
-
? lastResponse : of(lastResponse.clone());
|
|
90
|
-
}
|
|
91
|
-
//console.info('http cache interceptor', key)
|
|
92
|
-
// If the request of going through for first time
|
|
93
|
-
// then let the request proceed and cache the response
|
|
94
|
-
const requestHandle = next.handle(httpRequest).pipe(tap((stateEvent) => {
|
|
95
|
-
if (stateEvent instanceof HttpResponse) {
|
|
96
|
-
this.setCache(key, stateEvent.clone());
|
|
97
|
-
}
|
|
98
|
-
}));
|
|
99
|
-
// Meanwhile cache the request Observable to handle parallel request
|
|
100
|
-
//this.cachedData.set(key, requestHandle);
|
|
101
|
-
return requestHandle;
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
console.error(this.httpCacheConfig);
|
|
105
|
-
console.error(httpRequest.headers);
|
|
106
|
-
throw new Error('There is a configuration in your setup');
|
|
107
|
-
}
|
|
108
|
-
/*
|
|
109
|
-
// Also leave scope of resetting already cached data for a URI
|
|
110
|
-
if (httpRequest.headers.get("reset-cache")) {
|
|
111
|
-
this.cachedData.delete(httpRequest.urlWithParams);
|
|
112
|
-
}
|
|
113
|
-
*/
|
|
96
|
+
return handle(httpRequest, (req) => next.handle(req), this.httpCacheConfig, this.cachedData);
|
|
114
97
|
}
|
|
115
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
116
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
98
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: HttpCacheInterceptorInterceptor, deps: [{ token: P3X_HTTP_CACHE_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
99
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: HttpCacheInterceptorInterceptor }); }
|
|
117
100
|
}
|
|
118
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
101
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: HttpCacheInterceptorInterceptor, decorators: [{
|
|
119
102
|
type: Injectable
|
|
120
103
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
121
104
|
type: Inject,
|
|
@@ -124,41 +107,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
124
107
|
type: Optional
|
|
125
108
|
}] }] });
|
|
126
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Standalone / functional-provider helper.
|
|
112
|
+
*
|
|
113
|
+
* Usage in `app.config.ts`:
|
|
114
|
+
* ```ts
|
|
115
|
+
* provideHttpClient(withInterceptors([p3xHttpCacheInterceptor])),
|
|
116
|
+
* provideP3xHttpCacheInterceptor({ behavior: CachingHeaders.Cache, store: CachingStore.Global }),
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
function provideP3xHttpCacheInterceptor(httpCacheConfig) {
|
|
120
|
+
return makeEnvironmentProviders([
|
|
121
|
+
{ provide: P3X_HTTP_CACHE_CONFIG, useValue: httpCacheConfig },
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Legacy NgModule — kept intact for consumers that still bootstrap via
|
|
126
|
+
* `@NgModule({ imports: [P3XHttpCacheInterceptorModule.forRoot(...)] })`
|
|
127
|
+
* and register the class interceptor through `HTTP_INTERCEPTORS`.
|
|
128
|
+
*
|
|
129
|
+
* New code should prefer `provideP3xHttpCacheInterceptor()` +
|
|
130
|
+
* `p3xHttpCacheInterceptor` (functional).
|
|
131
|
+
*/
|
|
127
132
|
class P3XHttpCacheInterceptorModule {
|
|
128
133
|
static forRoot(httpCacheConfig) {
|
|
134
|
+
const providers = [
|
|
135
|
+
{
|
|
136
|
+
provide: P3X_HTTP_CACHE_CONFIG,
|
|
137
|
+
useValue: httpCacheConfig,
|
|
138
|
+
},
|
|
139
|
+
];
|
|
129
140
|
return {
|
|
130
141
|
ngModule: P3XHttpCacheInterceptorModule,
|
|
131
|
-
providers
|
|
132
|
-
{
|
|
133
|
-
provide: P3X_HTTP_CACHE_CONFIG,
|
|
134
|
-
useValue: httpCacheConfig
|
|
135
|
-
}
|
|
136
|
-
]
|
|
142
|
+
providers,
|
|
137
143
|
};
|
|
138
144
|
}
|
|
139
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
140
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.
|
|
141
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.
|
|
145
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: P3XHttpCacheInterceptorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
146
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.10", ngImport: i0, type: P3XHttpCacheInterceptorModule }); }
|
|
147
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: P3XHttpCacheInterceptorModule, providers: [
|
|
142
148
|
{
|
|
143
149
|
provide: HTTP_INTERCEPTORS,
|
|
144
150
|
useClass: HttpCacheInterceptorInterceptor,
|
|
145
|
-
multi: true
|
|
146
|
-
}
|
|
151
|
+
multi: true,
|
|
152
|
+
},
|
|
147
153
|
] }); }
|
|
148
154
|
}
|
|
149
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
155
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: P3XHttpCacheInterceptorModule, decorators: [{
|
|
150
156
|
type: NgModule,
|
|
151
157
|
args: [{
|
|
152
|
-
declarations: [],
|
|
153
|
-
imports: [],
|
|
154
158
|
providers: [
|
|
155
159
|
{
|
|
156
160
|
provide: HTTP_INTERCEPTORS,
|
|
157
161
|
useClass: HttpCacheInterceptorInterceptor,
|
|
158
|
-
multi: true
|
|
159
|
-
}
|
|
162
|
+
multi: true,
|
|
163
|
+
},
|
|
160
164
|
],
|
|
161
|
-
exports: []
|
|
162
165
|
}]
|
|
163
166
|
}] });
|
|
164
167
|
|
|
@@ -170,5 +173,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
170
173
|
* Generated bundle index. Do not edit.
|
|
171
174
|
*/
|
|
172
175
|
|
|
173
|
-
export { CachingHeaders, CachingStore, P3XHttpCacheInterceptorModule, P3X_HTTP_CACHE_CONFIG };
|
|
176
|
+
export { CachingHeaders, CachingStore, HttpCacheInterceptorInterceptor, P3XHttpCacheInterceptorModule, P3X_HTTP_CACHE_CONFIG, p3xHttpCacheInterceptor, provideP3xHttpCacheInterceptor };
|
|
174
177
|
//# sourceMappingURL=p3x-angular-http-cache-interceptor.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"p3x-angular-http-cache-interceptor.mjs","sources":["../../../projects/angular-http-cache-interceptor/src/lib/caching-headers.enum.ts","../../../projects/angular-http-cache-interceptor/src/lib/caching-store.enum.ts","../../../projects/angular-http-cache-interceptor/src/lib/http-cache-config.token.ts","../../../projects/angular-http-cache-interceptor/src/lib/http-cache-interceptor.interceptor.ts","../../../projects/angular-http-cache-interceptor/src/lib/http-cache-interceptor.module.ts","../../../projects/angular-http-cache-interceptor/src/public-api.ts","../../../projects/angular-http-cache-interceptor/src/p3x-angular-http-cache-interceptor.ts"],"sourcesContent":["// cache headers has to have a x- prefix\nexport enum CachingHeaders {\n NoCache = \"x-p3x-no-cache\",\n Cache = \"x-p3x-cache\",\n}\n","// cache headers has to have a x- prefix\nexport enum CachingStore {\n Global,\n PerModule\n}\n","import { InjectionToken } from \"@angular/core\";\nimport { HttpCacheConfig } from \"./http-cache-config\";\n\nexport const P3X_HTTP_CACHE_CONFIG = new InjectionToken(\n 'P3X_HTTP_CACHE_CONFIG'\n)\n","import {Inject, Injectable, Optional} from '@angular/core';\nimport { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';\nimport {Observable, of} from 'rxjs';\n\nimport hash from 'object-hash'\nimport {tap} from \"rxjs/operators\";\n\nimport {CachingHeaders} from \"./caching-headers.enum\";\nimport {CachingStore} from \"./caching-store.enum\";\n\nimport {P3X_HTTP_CACHE_CONFIG} from \"./http-cache-config.token\";\nimport {HttpCacheConfig} from \"./http-cache-config\";\n\n\nconst hashOptions = {\n algorithm: 'md5',\n encoding: 'hex'\n}\n\nconst globalCache = new Map<string, any>()\n\n@Injectable()\nexport class HttpCacheInterceptorInterceptor implements HttpInterceptor {\n\n private cachedData = new Map<string, any>()\n\n httpCacheConfig : HttpCacheConfig = {\n behavior: CachingHeaders.Cache,\n store: CachingStore.Global,\n }\n\n getCache(key: string) {\n if (this.httpCacheConfig.store === CachingStore.Global) {\n return globalCache.get(key)\n } else {\n return this.cachedData.get(key)\n }\n }\n\n setCache(key: string, value: any) {\n if (this.httpCacheConfig.store === CachingStore.Global) {\n globalCache.set(key, value)\n } else {\n this.cachedData.set(key, value)\n }\n }\n\n constructor(@Inject(P3X_HTTP_CACHE_CONFIG) @Optional() httpCacheConfigToken: HttpCacheConfig) {\n if (httpCacheConfigToken) {\n this.httpCacheConfig = httpCacheConfigToken\n }\n }\n\n httpToKey(httpRequest: HttpRequest<any>) {\n const body = JSON.parse(JSON.stringify(httpRequest.body))\n const key = httpRequest.method + '@' + httpRequest.urlWithParams + '@' + hash(httpRequest.params, hashOptions) + '@' + hash(body, hashOptions)\n return key\n }\n\n intercept(httpRequest: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\n\n\n //console.log(httpRequest)\n //console.log('has', httpRequest.headers.has(CachingHeaders.NoCache))\n //console.log('value', httpRequest.headers.get(CachingHeaders.NoCache))\n\n const forcedCache = httpRequest.headers.get(CachingHeaders.Cache) !== null\n const forcedNoneCache = httpRequest.headers.get(CachingHeaders.NoCache) !== null\n\n //console.log('forcedCache', forcedCache, 'forcedNoneCache', forcedNoneCache)\n\n let headers = httpRequest.headers.delete(CachingHeaders.NoCache)\n headers = headers.delete(CachingHeaders.Cache)\n httpRequest = httpRequest.clone({\n headers: headers\n })\n\n if (forcedCache && forcedNoneCache) {\n throw new Error('You cannot use cache and non-cache header at once!')\n } else if (forcedNoneCache || (this.httpCacheConfig.behavior === CachingHeaders.NoCache && !forcedCache)) {\n return next.handle(httpRequest);\n } else if (forcedCache || (this.httpCacheConfig.behavior === CachingHeaders.Cache && !forcedNoneCache)) {\n // Checked if there is cached data for this URI\n const key = this.httpToKey(httpRequest)\n const lastResponse = this.getCache(key);\n if (lastResponse) {\n // In case of parallel requests to same URI,\n // return the request already in progress\n // otherwise return the last cached data\n\n //console.info('http cache interceptor hit cache', key)\n\n return (lastResponse instanceof Observable)\n ? lastResponse : of(lastResponse.clone());\n }\n\n //console.info('http cache interceptor', key)\n\n // If the request of going through for first time\n // then let the request proceed and cache the response\n const requestHandle = next.handle(httpRequest).pipe(\n tap((stateEvent: any) => {\n if (stateEvent instanceof HttpResponse) {\n this.setCache(\n key,\n stateEvent.clone()\n );\n }\n })\n )\n\n // Meanwhile cache the request Observable to handle parallel request\n //this.cachedData.set(key, requestHandle);\n\n return requestHandle;\n } else {\n console.error(this.httpCacheConfig)\n console.error(httpRequest.headers)\n throw new Error('There is a configuration in your setup')\n }\n\n /*\n // Also leave scope of resetting already cached data for a URI\n if (httpRequest.headers.get(\"reset-cache\")) {\n this.cachedData.delete(httpRequest.urlWithParams);\n }\n */\n\n\n }\n}\n","import {ModuleWithProviders, NgModule} from '@angular/core';\nimport { HTTP_INTERCEPTORS } from \"@angular/common/http\";\nimport { HttpCacheInterceptorInterceptor } from './http-cache-interceptor.interceptor'\n\nimport { P3X_HTTP_CACHE_CONFIG } from \"./http-cache-config.token\";\nimport { HttpCacheConfig } from \"./http-cache-config\";\n\n@NgModule({\n declarations: [],\n imports: [\n ],\n providers: [\n {\n provide: HTTP_INTERCEPTORS,\n useClass: HttpCacheInterceptorInterceptor,\n multi: true\n }\n ],\n exports: []\n})\nexport class P3XHttpCacheInterceptorModule {\n\n static forRoot(httpCacheConfig: HttpCacheConfig): ModuleWithProviders<P3XHttpCacheInterceptorModule> {\n return {\n ngModule: P3XHttpCacheInterceptorModule,\n providers: [\n {\n provide: P3X_HTTP_CACHE_CONFIG,\n useValue: httpCacheConfig\n }\n ]\n };\n }\n\n}\n","/*\n * Public API Surface of angular-http-cache-interceptor\n */\n\nexport * from './lib/http-cache-interceptor.module';\nexport * from './lib/caching-headers.enum'\nexport * from './lib/http-cache-config'\nexport * from './lib/http-cache-config.token'\nexport * from './lib/caching-store.enum'\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"p3x-angular-http-cache-interceptor.mjs","sources":["../../../projects/angular-http-cache-interceptor/src/lib/caching-headers.enum.ts","../../../projects/angular-http-cache-interceptor/src/lib/caching-store.enum.ts","../../../projects/angular-http-cache-interceptor/src/lib/http-cache-config.token.ts","../../../projects/angular-http-cache-interceptor/src/lib/http-cache-interceptor.interceptor.ts","../../../projects/angular-http-cache-interceptor/src/lib/http-cache-interceptor.module.ts","../../../projects/angular-http-cache-interceptor/src/public-api.ts","../../../projects/angular-http-cache-interceptor/src/p3x-angular-http-cache-interceptor.ts"],"sourcesContent":["// cache headers has to have a x- prefix\nexport enum CachingHeaders {\n NoCache = \"x-p3x-no-cache\",\n Cache = \"x-p3x-cache\",\n}\n","// cache headers has to have a x- prefix\nexport enum CachingStore {\n Global,\n PerModule\n}\n","import { InjectionToken } from \"@angular/core\";\nimport { HttpCacheConfig } from \"./http-cache-config\";\n\nexport const P3X_HTTP_CACHE_CONFIG = new InjectionToken<HttpCacheConfig>(\n 'P3X_HTTP_CACHE_CONFIG'\n)\n","import { inject, Injectable, Optional, Inject } from '@angular/core';\nimport {\n HttpEvent,\n HttpHandler,\n HttpInterceptor,\n HttpInterceptorFn,\n HttpRequest,\n HttpResponse,\n} from '@angular/common/http';\nimport { Observable, of } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\nimport hash from 'object-hash';\n\nimport { CachingHeaders } from './caching-headers.enum';\nimport { CachingStore } from './caching-store.enum';\nimport { P3X_HTTP_CACHE_CONFIG } from './http-cache-config.token';\nimport { HttpCacheConfig } from './http-cache-config';\n\nconst hashOptions = {\n algorithm: 'md5',\n encoding: 'hex',\n} as const;\n\nconst globalCache = new Map<string, HttpResponse<any>>();\n\nconst DEFAULT_CONFIG: HttpCacheConfig = {\n behavior: CachingHeaders.Cache,\n store: CachingStore.Global,\n};\n\nfunction httpToKey(httpRequest: HttpRequest<any>): string {\n const body = JSON.parse(JSON.stringify(httpRequest.body));\n return (\n httpRequest.method +\n '@' + httpRequest.urlWithParams +\n '@' + hash(httpRequest.params, hashOptions) +\n '@' + hash(body, hashOptions)\n );\n}\n\nfunction handle(\n httpRequest: HttpRequest<unknown>,\n next: (req: HttpRequest<unknown>) => Observable<HttpEvent<unknown>>,\n config: HttpCacheConfig,\n perInstanceCache: Map<string, HttpResponse<any>>,\n): Observable<HttpEvent<unknown>> {\n const forcedCache = httpRequest.headers.get(CachingHeaders.Cache) !== null;\n const forcedNoneCache = httpRequest.headers.get(CachingHeaders.NoCache) !== null;\n\n let headers = httpRequest.headers.delete(CachingHeaders.NoCache);\n headers = headers.delete(CachingHeaders.Cache);\n httpRequest = httpRequest.clone({ headers });\n\n if (forcedCache && forcedNoneCache) {\n throw new Error('You cannot use cache and non-cache header at once!');\n }\n\n if (forcedNoneCache || (config.behavior === CachingHeaders.NoCache && !forcedCache)) {\n return next(httpRequest);\n }\n\n if (forcedCache || (config.behavior === CachingHeaders.Cache && !forcedNoneCache)) {\n const store = config.store === CachingStore.Global ? globalCache : perInstanceCache;\n const key = httpToKey(httpRequest);\n const lastResponse = store.get(key);\n if (lastResponse) {\n return of(lastResponse.clone());\n }\n return next(httpRequest).pipe(\n tap((stateEvent) => {\n if (stateEvent instanceof HttpResponse) {\n store.set(key, stateEvent.clone());\n }\n }),\n );\n }\n\n console.error(config);\n console.error(httpRequest.headers);\n throw new Error('There is a configuration in your setup');\n}\n\n/*\n Functional-interceptor path: there is no \"module instance\" to own a\n PerModule cache, so PerModule falls back to this module-level map (one\n per root injector, effectively Global-equivalent). The class-based\n interceptor below still honours true PerModule via its instance field.\n*/\nconst functionalPerInstanceCache = new Map<string, HttpResponse<any>>();\n\n/**\n * Functional interceptor. Use with:\n * `provideHttpClient(withInterceptors([p3xHttpCacheInterceptor]))`\n * or the convenience `provideP3xHttpCacheInterceptor(config)` helper.\n */\nexport const p3xHttpCacheInterceptor: HttpInterceptorFn = (httpRequest, next) => {\n const config = inject(P3X_HTTP_CACHE_CONFIG, { optional: true }) ?? DEFAULT_CONFIG;\n return handle(httpRequest, (req) => next(req), config, functionalPerInstanceCache);\n};\n\n/**\n * Class-based interceptor — legacy shim kept for consumers still registering\n * via `HTTP_INTERCEPTORS` / `P3XHttpCacheInterceptorModule.forRoot(...)`.\n * Prefer `p3xHttpCacheInterceptor` (functional) for new code.\n */\n@Injectable()\nexport class HttpCacheInterceptorInterceptor implements HttpInterceptor {\n private readonly cachedData = new Map<string, HttpResponse<any>>();\n private readonly httpCacheConfig: HttpCacheConfig;\n\n constructor(@Inject(P3X_HTTP_CACHE_CONFIG) @Optional() httpCacheConfigToken: HttpCacheConfig | null) {\n this.httpCacheConfig = httpCacheConfigToken ?? DEFAULT_CONFIG;\n }\n\n intercept(httpRequest: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {\n return handle(httpRequest, (req) => next.handle(req), this.httpCacheConfig, this.cachedData);\n }\n}\n","import {\n EnvironmentProviders,\n makeEnvironmentProviders,\n ModuleWithProviders,\n NgModule,\n Provider,\n} from '@angular/core';\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\n\nimport { HttpCacheInterceptorInterceptor } from './http-cache-interceptor.interceptor';\nimport { P3X_HTTP_CACHE_CONFIG } from './http-cache-config.token';\nimport { HttpCacheConfig } from './http-cache-config';\n\n/**\n * Standalone / functional-provider helper.\n *\n * Usage in `app.config.ts`:\n * ```ts\n * provideHttpClient(withInterceptors([p3xHttpCacheInterceptor])),\n * provideP3xHttpCacheInterceptor({ behavior: CachingHeaders.Cache, store: CachingStore.Global }),\n * ```\n */\nexport function provideP3xHttpCacheInterceptor(\n httpCacheConfig: HttpCacheConfig,\n): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: P3X_HTTP_CACHE_CONFIG, useValue: httpCacheConfig },\n ]);\n}\n\n/**\n * Legacy NgModule — kept intact for consumers that still bootstrap via\n * `@NgModule({ imports: [P3XHttpCacheInterceptorModule.forRoot(...)] })`\n * and register the class interceptor through `HTTP_INTERCEPTORS`.\n *\n * New code should prefer `provideP3xHttpCacheInterceptor()` +\n * `p3xHttpCacheInterceptor` (functional).\n */\n@NgModule({\n providers: [\n {\n provide: HTTP_INTERCEPTORS,\n useClass: HttpCacheInterceptorInterceptor,\n multi: true,\n },\n ],\n})\nexport class P3XHttpCacheInterceptorModule {\n static forRoot(httpCacheConfig: HttpCacheConfig): ModuleWithProviders<P3XHttpCacheInterceptorModule> {\n const providers: Provider[] = [\n {\n provide: P3X_HTTP_CACHE_CONFIG,\n useValue: httpCacheConfig,\n },\n ];\n return {\n ngModule: P3XHttpCacheInterceptorModule,\n providers,\n };\n }\n}\n","/*\n * Public API Surface of angular-http-cache-interceptor\n */\n\nexport * from './lib/http-cache-interceptor.module';\nexport * from './lib/http-cache-interceptor.interceptor';\nexport * from './lib/caching-headers.enum';\nexport * from './lib/http-cache-config';\nexport * from './lib/http-cache-config.token';\nexport * from './lib/caching-store.enum';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "p3x-angular-http-cache-interceptor",
|
|
3
3
|
"peerDependencies": {
|
|
4
|
-
"object-hash": "^
|
|
5
|
-
"@angular/common": "
|
|
6
|
-
"@angular/core": "
|
|
4
|
+
"object-hash": "^3.0.0",
|
|
5
|
+
"@angular/common": ">=16.0.0",
|
|
6
|
+
"@angular/core": ">=16.0.0"
|
|
7
7
|
},
|
|
8
8
|
"corifeus": {
|
|
9
9
|
"publish": true
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
},
|
|
25
25
|
"sideEffects": false,
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"corifeus-builder": "^
|
|
27
|
+
"corifeus-builder": "^2026.4.143"
|
|
28
28
|
},
|
|
29
|
-
"version": "2026.4.
|
|
29
|
+
"version": "2026.4.103",
|
|
30
30
|
"description": "🔥 Cache every request in Angular, not only the GET, but all methods of this interceptor, and allows you to interact with the interceptor via specific headers and modify the request, and these specific headers will be not included in the final request",
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { ModuleWithProviders, InjectionToken } from '@angular/core';
|
|
2
|
+
import { ModuleWithProviders, EnvironmentProviders, InjectionToken } from '@angular/core';
|
|
3
|
+
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpInterceptorFn } from '@angular/common/http';
|
|
4
|
+
import { Observable } from 'rxjs';
|
|
3
5
|
|
|
4
6
|
declare enum CachingHeaders {
|
|
5
7
|
NoCache = "x-p3x-no-cache",
|
|
@@ -16,6 +18,24 @@ interface HttpCacheConfig {
|
|
|
16
18
|
store: CachingStore;
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Standalone / functional-provider helper.
|
|
23
|
+
*
|
|
24
|
+
* Usage in `app.config.ts`:
|
|
25
|
+
* ```ts
|
|
26
|
+
* provideHttpClient(withInterceptors([p3xHttpCacheInterceptor])),
|
|
27
|
+
* provideP3xHttpCacheInterceptor({ behavior: CachingHeaders.Cache, store: CachingStore.Global }),
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function provideP3xHttpCacheInterceptor(httpCacheConfig: HttpCacheConfig): EnvironmentProviders;
|
|
31
|
+
/**
|
|
32
|
+
* Legacy NgModule — kept intact for consumers that still bootstrap via
|
|
33
|
+
* `@NgModule({ imports: [P3XHttpCacheInterceptorModule.forRoot(...)] })`
|
|
34
|
+
* and register the class interceptor through `HTTP_INTERCEPTORS`.
|
|
35
|
+
*
|
|
36
|
+
* New code should prefer `provideP3xHttpCacheInterceptor()` +
|
|
37
|
+
* `p3xHttpCacheInterceptor` (functional).
|
|
38
|
+
*/
|
|
19
39
|
declare class P3XHttpCacheInterceptorModule {
|
|
20
40
|
static forRoot(httpCacheConfig: HttpCacheConfig): ModuleWithProviders<P3XHttpCacheInterceptorModule>;
|
|
21
41
|
static ɵfac: i0.ɵɵFactoryDeclaration<P3XHttpCacheInterceptorModule, never>;
|
|
@@ -23,7 +43,27 @@ declare class P3XHttpCacheInterceptorModule {
|
|
|
23
43
|
static ɵinj: i0.ɵɵInjectorDeclaration<P3XHttpCacheInterceptorModule>;
|
|
24
44
|
}
|
|
25
45
|
|
|
26
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Functional interceptor. Use with:
|
|
48
|
+
* `provideHttpClient(withInterceptors([p3xHttpCacheInterceptor]))`
|
|
49
|
+
* or the convenience `provideP3xHttpCacheInterceptor(config)` helper.
|
|
50
|
+
*/
|
|
51
|
+
declare const p3xHttpCacheInterceptor: HttpInterceptorFn;
|
|
52
|
+
/**
|
|
53
|
+
* Class-based interceptor — legacy shim kept for consumers still registering
|
|
54
|
+
* via `HTTP_INTERCEPTORS` / `P3XHttpCacheInterceptorModule.forRoot(...)`.
|
|
55
|
+
* Prefer `p3xHttpCacheInterceptor` (functional) for new code.
|
|
56
|
+
*/
|
|
57
|
+
declare class HttpCacheInterceptorInterceptor implements HttpInterceptor {
|
|
58
|
+
private readonly cachedData;
|
|
59
|
+
private readonly httpCacheConfig;
|
|
60
|
+
constructor(httpCacheConfigToken: HttpCacheConfig | null);
|
|
61
|
+
intercept(httpRequest: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>>;
|
|
62
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<HttpCacheInterceptorInterceptor, [{ optional: true; }]>;
|
|
63
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<HttpCacheInterceptorInterceptor>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
declare const P3X_HTTP_CACHE_CONFIG: InjectionToken<HttpCacheConfig>;
|
|
27
67
|
|
|
28
|
-
export { CachingHeaders, CachingStore, P3XHttpCacheInterceptorModule, P3X_HTTP_CACHE_CONFIG };
|
|
68
|
+
export { CachingHeaders, CachingStore, HttpCacheInterceptorInterceptor, P3XHttpCacheInterceptorModule, P3X_HTTP_CACHE_CONFIG, p3xHttpCacheInterceptor, provideP3xHttpCacheInterceptor };
|
|
29
69
|
export type { HttpCacheConfig };
|