@datum-cloud/strapi-revalidate 0.1.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/.env.example +5 -0
- package/LICENSE +121 -0
- package/README.md +227 -0
- package/dist/cache/drivers/file.d.ts +37 -0
- package/dist/cache/drivers/file.d.ts.map +1 -0
- package/dist/cache/drivers/file.js +151 -0
- package/dist/cache/drivers/file.js.map +1 -0
- package/dist/cache/drivers/memory.d.ts +20 -0
- package/dist/cache/drivers/memory.d.ts.map +1 -0
- package/dist/cache/drivers/memory.js +76 -0
- package/dist/cache/drivers/memory.js.map +1 -0
- package/dist/cache/drivers/redis.d.ts +25 -0
- package/dist/cache/drivers/redis.d.ts.map +1 -0
- package/dist/cache/drivers/redis.js +36 -0
- package/dist/cache/drivers/redis.js.map +1 -0
- package/dist/cache/index.d.ts +28 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +54 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/manager.d.ts +55 -0
- package/dist/cache/manager.d.ts.map +1 -0
- package/dist/cache/manager.js +73 -0
- package/dist/cache/manager.js.map +1 -0
- package/dist/cache/types.d.ts +33 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +9 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/client/graphql.d.ts +46 -0
- package/dist/client/graphql.d.ts.map +1 -0
- package/dist/client/graphql.js +97 -0
- package/dist/client/graphql.js.map +1 -0
- package/dist/client/index.d.ts +28 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +38 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/rest.d.ts +23 -0
- package/dist/client/rest.d.ts.map +1 -0
- package/dist/client/rest.js +25 -0
- package/dist/client/rest.js.map +1 -0
- package/dist/content/articles.d.ts +36 -0
- package/dist/content/articles.d.ts.map +1 -0
- package/dist/content/articles.js +157 -0
- package/dist/content/articles.js.map +1 -0
- package/dist/content/authors.d.ts +28 -0
- package/dist/content/authors.d.ts.map +1 -0
- package/dist/content/authors.js +115 -0
- package/dist/content/authors.js.map +1 -0
- package/dist/content/index.d.ts +11 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +10 -0
- package/dist/content/index.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/types/config.d.ts +108 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +49 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/strapi.d.ts +103 -0
- package/dist/types/strapi.d.ts.map +1 -0
- package/dist/types/strapi.js +11 -0
- package/dist/types/strapi.js.map +1 -0
- package/dist/webhook/handler.d.ts +38 -0
- package/dist/webhook/handler.d.ts.map +1 -0
- package/dist/webhook/handler.js +156 -0
- package/dist/webhook/handler.js.map +1 -0
- package/dist/webhook/index.d.ts +9 -0
- package/dist/webhook/index.d.ts.map +1 -0
- package/dist/webhook/index.js +7 -0
- package/dist/webhook/index.js.map +1 -0
- package/dist/webhook/tags.d.ts +22 -0
- package/dist/webhook/tags.d.ts.map +1 -0
- package/dist/webhook/tags.js +39 -0
- package/dist/webhook/tags.js.map +1 -0
- package/dist/webhook/types.d.ts +60 -0
- package/dist/webhook/types.d.ts.map +1 -0
- package/dist/webhook/types.js +6 -0
- package/dist/webhook/types.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis cache driver — STUB.
|
|
3
|
+
*
|
|
4
|
+
* The interface is exported so config typing and exports stay stable.
|
|
5
|
+
* Actual ioredis-backed implementation is planned for v1.x; consumers
|
|
6
|
+
* that try to instantiate this driver will get a clear runtime error.
|
|
7
|
+
*/
|
|
8
|
+
import type { CacheDriver, CacheSetOptions } from '../types.js';
|
|
9
|
+
/** Configuration for the (not-yet-implemented) Redis driver. */
|
|
10
|
+
export interface RedisDriverOptions {
|
|
11
|
+
redisUrl: string;
|
|
12
|
+
keyPrefix?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Stubbed Redis `CacheDriver`. Every method throws. */
|
|
15
|
+
export declare class RedisCacheDriver implements CacheDriver {
|
|
16
|
+
private readonly options;
|
|
17
|
+
constructor(options: RedisDriverOptions);
|
|
18
|
+
get<T>(_key: string): Promise<T | null>;
|
|
19
|
+
set<T>(_key: string, _data: T, _options?: CacheSetOptions): Promise<void>;
|
|
20
|
+
delete(_key: string): Promise<void>;
|
|
21
|
+
deleteByTag(_tag: string): Promise<void>;
|
|
22
|
+
clear(): Promise<void>;
|
|
23
|
+
keys(_prefix?: string): Promise<string[]>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=redis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../src/cache/drivers/redis.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhE,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,wDAAwD;AACxD,qBAAa,gBAAiB,YAAW,WAAW;IAElD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAEjC,OAAO,EAAE,kBAAkB;IAIjC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAKvC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAGhD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis cache driver — STUB.
|
|
3
|
+
*
|
|
4
|
+
* The interface is exported so config typing and exports stay stable.
|
|
5
|
+
* Actual ioredis-backed implementation is planned for v1.x; consumers
|
|
6
|
+
* that try to instantiate this driver will get a clear runtime error.
|
|
7
|
+
*/
|
|
8
|
+
const NOT_IMPLEMENTED_MESSAGE = 'Redis driver: not implemented in v0.1.0. Install ioredis and use file/memory driver, or wait for v1.x.';
|
|
9
|
+
/** Stubbed Redis `CacheDriver`. Every method throws. */
|
|
10
|
+
export class RedisCacheDriver {
|
|
11
|
+
// Stored to satisfy strict property init while keeping the stub honest.
|
|
12
|
+
options;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
async get(_key) {
|
|
17
|
+
void this.options;
|
|
18
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
19
|
+
}
|
|
20
|
+
async set(_key, _data, _options) {
|
|
21
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
22
|
+
}
|
|
23
|
+
async delete(_key) {
|
|
24
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
25
|
+
}
|
|
26
|
+
async deleteByTag(_tag) {
|
|
27
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
28
|
+
}
|
|
29
|
+
async clear() {
|
|
30
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
31
|
+
}
|
|
32
|
+
async keys(_prefix) {
|
|
33
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../../src/cache/drivers/redis.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,MAAM,uBAAuB,GAC3B,wGAAwG,CAAC;AAE3G,wDAAwD;AACxD,MAAM,OAAO,gBAAgB;IAC3B,wEAAwE;IACvD,OAAO,CAAqB;IAE7C,YAAY,OAA2B;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,IAAY;QACvB,KAAK,IAAI,CAAC,OAAO,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,KAAQ,EAAE,QAA0B;QAC7D,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAY;QAC5B,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAgB;QACzB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public cache surface.
|
|
3
|
+
*
|
|
4
|
+
* `createCache(config)` is the factory most users want — it builds primary
|
|
5
|
+
* and fallback drivers from a `RevalidateConfig` and wraps them in a
|
|
6
|
+
* `CacheManager`. Driver classes and the `CacheDriver` interface are
|
|
7
|
+
* re-exported for users who want to hand-wire a custom topology.
|
|
8
|
+
*/
|
|
9
|
+
import type { RevalidateConfig } from '../types/config.js';
|
|
10
|
+
import { CacheManager } from './manager.js';
|
|
11
|
+
export type { CacheDriver, CacheSetOptions } from './types.js';
|
|
12
|
+
export { CacheManager } from './manager.js';
|
|
13
|
+
export type { CacheManagerOptions } from './manager.js';
|
|
14
|
+
export { FileCacheDriver } from './drivers/file.js';
|
|
15
|
+
export type { FileDriverOptions } from './drivers/file.js';
|
|
16
|
+
export { MemoryCacheDriver } from './drivers/memory.js';
|
|
17
|
+
export { RedisCacheDriver } from './drivers/redis.js';
|
|
18
|
+
export type { RedisDriverOptions } from './drivers/redis.js';
|
|
19
|
+
/**
|
|
20
|
+
* Build a `CacheManager` from a validated `RevalidateConfig`.
|
|
21
|
+
*
|
|
22
|
+
* The primary driver is whichever was configured (`file` by default); the
|
|
23
|
+
* fallback driver is always a file-backed cache pointed at
|
|
24
|
+
* `config.cache.fallbackDir` so persistence survives process restarts even
|
|
25
|
+
* when the primary is in-memory.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createCache(config: RevalidateConfig): CacheManager;
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,YAAY,CASlE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public cache surface.
|
|
3
|
+
*
|
|
4
|
+
* `createCache(config)` is the factory most users want — it builds primary
|
|
5
|
+
* and fallback drivers from a `RevalidateConfig` and wraps them in a
|
|
6
|
+
* `CacheManager`. Driver classes and the `CacheDriver` interface are
|
|
7
|
+
* re-exported for users who want to hand-wire a custom topology.
|
|
8
|
+
*/
|
|
9
|
+
import { FileCacheDriver } from './drivers/file.js';
|
|
10
|
+
import { MemoryCacheDriver } from './drivers/memory.js';
|
|
11
|
+
import { RedisCacheDriver } from './drivers/redis.js';
|
|
12
|
+
import { CacheManager } from './manager.js';
|
|
13
|
+
export { CacheManager } from './manager.js';
|
|
14
|
+
export { FileCacheDriver } from './drivers/file.js';
|
|
15
|
+
export { MemoryCacheDriver } from './drivers/memory.js';
|
|
16
|
+
export { RedisCacheDriver } from './drivers/redis.js';
|
|
17
|
+
/**
|
|
18
|
+
* Build a `CacheManager` from a validated `RevalidateConfig`.
|
|
19
|
+
*
|
|
20
|
+
* The primary driver is whichever was configured (`file` by default); the
|
|
21
|
+
* fallback driver is always a file-backed cache pointed at
|
|
22
|
+
* `config.cache.fallbackDir` so persistence survives process restarts even
|
|
23
|
+
* when the primary is in-memory.
|
|
24
|
+
*/
|
|
25
|
+
export function createCache(config) {
|
|
26
|
+
const primary = buildDriver(config);
|
|
27
|
+
const fallback = new FileCacheDriver({ dir: config.cache.fallbackDir });
|
|
28
|
+
return new CacheManager({
|
|
29
|
+
primary,
|
|
30
|
+
fallback,
|
|
31
|
+
defaultTtl: config.cache.ttl,
|
|
32
|
+
debug: config.debug,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function buildDriver(config) {
|
|
36
|
+
const { driver } = config.cache;
|
|
37
|
+
switch (driver) {
|
|
38
|
+
case 'file':
|
|
39
|
+
return new FileCacheDriver({ dir: config.cache.dir });
|
|
40
|
+
case 'memory':
|
|
41
|
+
return new MemoryCacheDriver();
|
|
42
|
+
case 'redis': {
|
|
43
|
+
const redisUrl = config.cache.redisUrl;
|
|
44
|
+
if (!redisUrl) {
|
|
45
|
+
throw new Error('Redis driver requires `cache.redisUrl` to be set.');
|
|
46
|
+
}
|
|
47
|
+
return new RedisCacheDriver({
|
|
48
|
+
redisUrl,
|
|
49
|
+
keyPrefix: config.cache.keyPrefix,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAI5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,MAAwB;IAClD,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IACxE,OAAO,IAAI,YAAY,CAAC;QACtB,OAAO;QACP,QAAQ;QACR,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG;QAC5B,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,MAAwB;IAC3C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;IAChC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACxD,KAAK,QAAQ;YACX,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACjC,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YACvC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;YACvE,CAAC;YACD,OAAO,IAAI,gBAAgB,CAAC;gBAC1B,QAAQ;gBACR,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;aAClC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CacheManager — the composition layer the public API talks to.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Track tag membership across writes so `invalidate(tag)` is O(tagged keys).
|
|
6
|
+
* - Mirror every successful `set()` to a persistent fallback driver with no
|
|
7
|
+
* TTL, so Strapi outages don't take the site down.
|
|
8
|
+
* - Provide `getWithFallback()` for read paths: short-TTL hit > fetch >
|
|
9
|
+
* long-lived fallback hit.
|
|
10
|
+
*
|
|
11
|
+
* Drivers themselves stay storage-only; tag accounting lives here.
|
|
12
|
+
*/
|
|
13
|
+
import type { CacheDriver, CacheSetOptions } from './types.js';
|
|
14
|
+
/** Options for instantiating a `CacheManager`. */
|
|
15
|
+
export interface CacheManagerOptions {
|
|
16
|
+
/** Primary driver — honours TTL, serves hot reads. */
|
|
17
|
+
primary: CacheDriver;
|
|
18
|
+
/** Persistent fallback driver — never expires, written on every successful set. */
|
|
19
|
+
fallback: CacheDriver;
|
|
20
|
+
/** Default TTL (seconds) applied when `set` is called without one. */
|
|
21
|
+
defaultTtl?: number;
|
|
22
|
+
/** When true, hits/misses are logged via `console.debug`. */
|
|
23
|
+
debug?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Cache facade. All content fetchers and the webhook handler talk to this,
|
|
27
|
+
* not to a driver directly.
|
|
28
|
+
*/
|
|
29
|
+
export declare class CacheManager {
|
|
30
|
+
private readonly primary;
|
|
31
|
+
private readonly fallback;
|
|
32
|
+
private readonly defaultTtl;
|
|
33
|
+
private readonly debug;
|
|
34
|
+
constructor(options: CacheManagerOptions);
|
|
35
|
+
/** Read from the primary cache. Returns `null` on miss or expiry. */
|
|
36
|
+
get<T>(key: string): Promise<T | null>;
|
|
37
|
+
/** Read from the persistent fallback cache. Returns `null` if never populated. */
|
|
38
|
+
getFallback<T>(key: string): Promise<T | null>;
|
|
39
|
+
/**
|
|
40
|
+
* Write to both the primary cache (with TTL + tags) and the fallback cache
|
|
41
|
+
* (no TTL, no tags). Tag accounting happens at the driver level.
|
|
42
|
+
*/
|
|
43
|
+
set<T>(key: string, data: T, options?: CacheSetOptions): Promise<void>;
|
|
44
|
+
/** Remove a single key from the primary cache. Fallback is preserved by design. */
|
|
45
|
+
delete(key: string): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Invalidate every primary-cache key associated with `tag`. The fallback
|
|
48
|
+
* cache is intentionally untouched — if the upcoming refetch fails, stale
|
|
49
|
+
* data should still serve.
|
|
50
|
+
*/
|
|
51
|
+
invalidate(tag: string): Promise<void>;
|
|
52
|
+
/** Invalidate all primary-cache entries. Fallback is preserved. */
|
|
53
|
+
invalidateAll(): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/cache/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D,kDAAkD;AAClD,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,OAAO,EAAE,WAAW,CAAC;IACrB,mFAAmF;IACnF,QAAQ,EAAE,WAAW,CAAC;IACtB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAU;gBAEpB,OAAO,EAAE,mBAAmB;IAOxC,qEAAqE;IAC/D,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAQ5C,kFAAkF;IAC5E,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAIpD;;;OAGG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhF,mFAAmF;IAC7E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC;;;;OAIG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C,mEAAmE;IAC7D,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAMrC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CacheManager — the composition layer the public API talks to.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Track tag membership across writes so `invalidate(tag)` is O(tagged keys).
|
|
6
|
+
* - Mirror every successful `set()` to a persistent fallback driver with no
|
|
7
|
+
* TTL, so Strapi outages don't take the site down.
|
|
8
|
+
* - Provide `getWithFallback()` for read paths: short-TTL hit > fetch >
|
|
9
|
+
* long-lived fallback hit.
|
|
10
|
+
*
|
|
11
|
+
* Drivers themselves stay storage-only; tag accounting lives here.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Cache facade. All content fetchers and the webhook handler talk to this,
|
|
15
|
+
* not to a driver directly.
|
|
16
|
+
*/
|
|
17
|
+
export class CacheManager {
|
|
18
|
+
primary;
|
|
19
|
+
fallback;
|
|
20
|
+
defaultTtl;
|
|
21
|
+
debug;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.primary = options.primary;
|
|
24
|
+
this.fallback = options.fallback;
|
|
25
|
+
this.defaultTtl = options.defaultTtl ?? 3600;
|
|
26
|
+
this.debug = options.debug ?? false;
|
|
27
|
+
}
|
|
28
|
+
/** Read from the primary cache. Returns `null` on miss or expiry. */
|
|
29
|
+
async get(key) {
|
|
30
|
+
const value = await this.primary.get(key);
|
|
31
|
+
if (this.debug) {
|
|
32
|
+
console.debug(`[strapi-revalidate] cache ${value === null ? 'MISS' : 'HIT'} → ${key}`);
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
/** Read from the persistent fallback cache. Returns `null` if never populated. */
|
|
37
|
+
async getFallback(key) {
|
|
38
|
+
return this.fallback.get(key);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Write to both the primary cache (with TTL + tags) and the fallback cache
|
|
42
|
+
* (no TTL, no tags). Tag accounting happens at the driver level.
|
|
43
|
+
*/
|
|
44
|
+
async set(key, data, options = {}) {
|
|
45
|
+
const ttl = options.ttl ?? this.defaultTtl;
|
|
46
|
+
await this.primary.set(key, data, { ttl, tags: options.tags });
|
|
47
|
+
// Fallback: no TTL, no tag indexing — it exists purely to survive outages.
|
|
48
|
+
await this.fallback.set(key, data);
|
|
49
|
+
}
|
|
50
|
+
/** Remove a single key from the primary cache. Fallback is preserved by design. */
|
|
51
|
+
async delete(key) {
|
|
52
|
+
await this.primary.delete(key);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Invalidate every primary-cache key associated with `tag`. The fallback
|
|
56
|
+
* cache is intentionally untouched — if the upcoming refetch fails, stale
|
|
57
|
+
* data should still serve.
|
|
58
|
+
*/
|
|
59
|
+
async invalidate(tag) {
|
|
60
|
+
await this.primary.deleteByTag(tag);
|
|
61
|
+
if (this.debug) {
|
|
62
|
+
console.debug(`[strapi-revalidate] invalidated tag → ${tag}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Invalidate all primary-cache entries. Fallback is preserved. */
|
|
66
|
+
async invalidateAll() {
|
|
67
|
+
await this.primary.clear();
|
|
68
|
+
if (this.debug) {
|
|
69
|
+
console.debug('[strapi-revalidate] invalidated all');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/cache/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAgBH;;;GAGG;AACH,MAAM,OAAO,YAAY;IACN,OAAO,CAAc;IACrB,QAAQ,CAAc;IACtB,UAAU,CAAS;IACnB,KAAK,CAAU;IAEhC,YAAY,OAA4B;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;QAC7C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;IACtC,CAAC;IAED,qEAAqE;IACrE,KAAK,CAAC,GAAG,CAAI,GAAW;QACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAI,GAAG,CAAC,CAAC;QAC7C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kFAAkF;IAClF,KAAK,CAAC,WAAW,CAAI,GAAW;QAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAI,GAAG,CAAC,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAI,GAAW,EAAE,IAAO,EAAE,UAA2B,EAAE;QAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC;QAC3C,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,2EAA2E;QAC3E,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,mFAAmF;IACnF,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,GAAW;QAC1B,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache driver contract.
|
|
3
|
+
*
|
|
4
|
+
* Implementations are responsible for storage details (filesystem, in-memory
|
|
5
|
+
* Map, Redis, etc.). The `CacheManager` layered above provides tag tracking
|
|
6
|
+
* and fallback semantics so drivers stay simple.
|
|
7
|
+
*/
|
|
8
|
+
/** Options accepted by `CacheDriver.set`. */
|
|
9
|
+
export interface CacheSetOptions {
|
|
10
|
+
/** Time-to-live in **seconds**. Omit for no expiry. */
|
|
11
|
+
ttl?: number;
|
|
12
|
+
/** Tag names associated with this key. Drivers may persist these to support `deleteByTag`. */
|
|
13
|
+
tags?: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Storage-agnostic cache contract. All public cache APIs accept anything
|
|
17
|
+
* that satisfies this interface.
|
|
18
|
+
*/
|
|
19
|
+
export interface CacheDriver {
|
|
20
|
+
/** Returns the cached value for `key`, or `null` if missing or expired. */
|
|
21
|
+
get<T>(key: string): Promise<T | null>;
|
|
22
|
+
/** Stores `data` under `key` with optional ttl (seconds) and tag list. */
|
|
23
|
+
set<T>(key: string, data: T, options?: CacheSetOptions): Promise<void>;
|
|
24
|
+
/** Removes a single key. No-op if absent. */
|
|
25
|
+
delete(key: string): Promise<void>;
|
|
26
|
+
/** Removes every key associated with `tag`. */
|
|
27
|
+
deleteByTag(tag: string): Promise<void>;
|
|
28
|
+
/** Removes every key managed by this driver. */
|
|
29
|
+
clear(): Promise<void>;
|
|
30
|
+
/** Lists all keys, optionally filtered by a string prefix. */
|
|
31
|
+
keys(prefix?: string): Promise<string[]>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,6CAA6C;AAC7C,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEvC,0EAA0E;IAC1E,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvE,6CAA6C;IAC7C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC,+CAA+C;IAC/C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC,gDAAgD;IAChD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,8DAA8D;IAC9D,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC1C"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache driver contract.
|
|
3
|
+
*
|
|
4
|
+
* Implementations are responsible for storage details (filesystem, in-memory
|
|
5
|
+
* Map, Redis, etc.). The `CacheManager` layered above provides tag tracking
|
|
6
|
+
* and fallback semantics so drivers stay simple.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL transport for Strapi v5.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from datum.net's `graphqlQuery()` with two additions: configurable
|
|
5
|
+
* retry with exponential backoff, and a structured `StrapiClient` surface so
|
|
6
|
+
* the same instance is reused across fetchers (no module-level state).
|
|
7
|
+
*/
|
|
8
|
+
/** Generic Strapi GraphQL response envelope. */
|
|
9
|
+
export interface GraphQLResponse<T> {
|
|
10
|
+
data: T;
|
|
11
|
+
errors?: Array<{
|
|
12
|
+
message: string;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
/** Configuration for a `GraphQLStrapiClient`. */
|
|
16
|
+
export interface GraphQLClientOptions {
|
|
17
|
+
/** Strapi base URL (no trailing `/graphql`). */
|
|
18
|
+
url: string;
|
|
19
|
+
/** Strapi API token. Sent as `Authorization: Bearer <token>`. */
|
|
20
|
+
token: string;
|
|
21
|
+
/** Per-request timeout in **milliseconds**. */
|
|
22
|
+
timeout: number;
|
|
23
|
+
/** Number of retries on transport failure (timeout, network, 5xx). 0 disables retry. */
|
|
24
|
+
retry: number;
|
|
25
|
+
/** When true, logs request lifecycle via `console.debug`. */
|
|
26
|
+
debug?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Strapi GraphQL client.
|
|
30
|
+
*
|
|
31
|
+
* `query<T>()` returns the unwrapped `data` payload or `null` on failure;
|
|
32
|
+
* callers are expected to treat `null` as "Strapi unreachable / invalid"
|
|
33
|
+
* and fall back to stale cache.
|
|
34
|
+
*/
|
|
35
|
+
export declare class GraphQLStrapiClient {
|
|
36
|
+
private readonly options;
|
|
37
|
+
constructor(options: GraphQLClientOptions);
|
|
38
|
+
/**
|
|
39
|
+
* Execute a GraphQL operation. Returns the `data` payload on success,
|
|
40
|
+
* `null` if the server returns an error envelope, a non-2xx status,
|
|
41
|
+
* times out, or all retries are exhausted.
|
|
42
|
+
*/
|
|
43
|
+
query<T>(query: string, variables?: Record<string, unknown>): Promise<T | null>;
|
|
44
|
+
private executeOnce;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=graphql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/client/graphql.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,gDAAgD;AAChD,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrC;AAED,iDAAiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,wFAAwF;IACxF,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;gBAEnC,OAAO,EAAE,oBAAoB;IAIzC;;;;OAIG;IACG,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;YAiC3E,WAAW;CAwC1B"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL transport for Strapi v5.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from datum.net's `graphqlQuery()` with two additions: configurable
|
|
5
|
+
* retry with exponential backoff, and a structured `StrapiClient` surface so
|
|
6
|
+
* the same instance is reused across fetchers (no module-level state).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Strapi GraphQL client.
|
|
10
|
+
*
|
|
11
|
+
* `query<T>()` returns the unwrapped `data` payload or `null` on failure;
|
|
12
|
+
* callers are expected to treat `null` as "Strapi unreachable / invalid"
|
|
13
|
+
* and fall back to stale cache.
|
|
14
|
+
*/
|
|
15
|
+
export class GraphQLStrapiClient {
|
|
16
|
+
options;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.options = options;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Execute a GraphQL operation. Returns the `data` payload on success,
|
|
22
|
+
* `null` if the server returns an error envelope, a non-2xx status,
|
|
23
|
+
* times out, or all retries are exhausted.
|
|
24
|
+
*/
|
|
25
|
+
async query(query, variables = {}) {
|
|
26
|
+
const { retry } = this.options;
|
|
27
|
+
let lastError = null;
|
|
28
|
+
for (let attempt = 0; attempt <= retry; attempt++) {
|
|
29
|
+
try {
|
|
30
|
+
const result = await this.executeOnce(query, variables);
|
|
31
|
+
if (result !== null)
|
|
32
|
+
return result;
|
|
33
|
+
// result === null means a structured Strapi error (4xx / GraphQL errors).
|
|
34
|
+
// Don't retry those — they won't get better.
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
lastError = err;
|
|
39
|
+
if (this.options.debug) {
|
|
40
|
+
console.debug(`[strapi-revalidate] graphql attempt ${attempt + 1}/${retry + 1} failed:`, err);
|
|
41
|
+
}
|
|
42
|
+
if (attempt < retry) {
|
|
43
|
+
await sleep(backoffMs(attempt));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (lastError instanceof Error && lastError.name === 'AbortError') {
|
|
48
|
+
console.error(`Strapi request timed out after ${this.options.timeout}ms`);
|
|
49
|
+
}
|
|
50
|
+
else if (lastError) {
|
|
51
|
+
console.error('Error fetching from Strapi:', lastError);
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
async executeOnce(query, variables) {
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch(`${this.options.url.replace(/\/$/, '')}/graphql`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
Authorization: `Bearer ${this.options.token}`,
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({ query, variables }),
|
|
66
|
+
signal: controller.signal,
|
|
67
|
+
});
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
const text = await response.text();
|
|
70
|
+
console.error(`Strapi GraphQL error: ${response.status} ${response.statusText}`, text);
|
|
71
|
+
// 5xx is retryable — surface as a thrown error so the retry loop fires.
|
|
72
|
+
if (response.status >= 500) {
|
|
73
|
+
throw new Error(`Strapi ${response.status} ${response.statusText}`);
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const result = (await response.json());
|
|
78
|
+
if (result.errors && result.errors.length > 0) {
|
|
79
|
+
console.error('Strapi GraphQL errors:', result.errors);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return result.data;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
clearTimeout(timeoutId);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function sleep(ms) {
|
|
90
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
91
|
+
}
|
|
92
|
+
/** Exponential backoff with a sane cap. Attempt is 0-indexed. */
|
|
93
|
+
function backoffMs(attempt) {
|
|
94
|
+
const base = 200 * 2 ** attempt;
|
|
95
|
+
return Math.min(base, 2000);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=graphql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphql.js","sourceRoot":"","sources":["../../src/client/graphql.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public client surface.
|
|
3
|
+
*
|
|
4
|
+
* `createStrapiClient(config)` picks the right transport (graphql today,
|
|
5
|
+
* rest later) and returns a unified `StrapiClient`. All built-in content
|
|
6
|
+
* fetchers receive a client through their `fetch*` helpers rather than
|
|
7
|
+
* instantiating one themselves — so the same connection, timeout, and
|
|
8
|
+
* retry policy applies across the package.
|
|
9
|
+
*/
|
|
10
|
+
import type { RevalidateConfig } from '../types/config.js';
|
|
11
|
+
import { GraphQLStrapiClient } from './graphql.js';
|
|
12
|
+
export { GraphQLStrapiClient } from './graphql.js';
|
|
13
|
+
export type { GraphQLClientOptions, GraphQLResponse } from './graphql.js';
|
|
14
|
+
export { createRestClient, RestStrapiClient } from './rest.js';
|
|
15
|
+
export type { RestClientOptions } from './rest.js';
|
|
16
|
+
/**
|
|
17
|
+
* Anything the package's content fetchers know how to talk to.
|
|
18
|
+
*
|
|
19
|
+
* Today this is exclusively the GraphQL client; the REST stub is planned
|
|
20
|
+
* to satisfy the same shape via a `query`-style adapter in a future release.
|
|
21
|
+
*/
|
|
22
|
+
export type StrapiClient = GraphQLStrapiClient;
|
|
23
|
+
/**
|
|
24
|
+
* Build a `StrapiClient` from a validated `RevalidateConfig`. Throws
|
|
25
|
+
* `Error` if the configured transport isn't implemented yet (REST).
|
|
26
|
+
*/
|
|
27
|
+
export declare function createStrapiClient(config: RevalidateConfig): StrapiClient;
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,YAAY,CAoBzE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public client surface.
|
|
3
|
+
*
|
|
4
|
+
* `createStrapiClient(config)` picks the right transport (graphql today,
|
|
5
|
+
* rest later) and returns a unified `StrapiClient`. All built-in content
|
|
6
|
+
* fetchers receive a client through their `fetch*` helpers rather than
|
|
7
|
+
* instantiating one themselves — so the same connection, timeout, and
|
|
8
|
+
* retry policy applies across the package.
|
|
9
|
+
*/
|
|
10
|
+
import { GraphQLStrapiClient } from './graphql.js';
|
|
11
|
+
import { createRestClient } from './rest.js';
|
|
12
|
+
export { GraphQLStrapiClient } from './graphql.js';
|
|
13
|
+
export { createRestClient, RestStrapiClient } from './rest.js';
|
|
14
|
+
/**
|
|
15
|
+
* Build a `StrapiClient` from a validated `RevalidateConfig`. Throws
|
|
16
|
+
* `Error` if the configured transport isn't implemented yet (REST).
|
|
17
|
+
*/
|
|
18
|
+
export function createStrapiClient(config) {
|
|
19
|
+
if (config.transport === 'rest') {
|
|
20
|
+
// Surfaced via the stub for a consistent error message.
|
|
21
|
+
createRestClient({
|
|
22
|
+
url: config.url,
|
|
23
|
+
token: config.token,
|
|
24
|
+
timeout: config.timeout,
|
|
25
|
+
retry: config.retry,
|
|
26
|
+
});
|
|
27
|
+
// Unreachable — createRestClient throws — but keeps the return type honest.
|
|
28
|
+
throw new Error('REST transport not yet implemented');
|
|
29
|
+
}
|
|
30
|
+
return new GraphQLStrapiClient({
|
|
31
|
+
url: config.url,
|
|
32
|
+
token: config.token,
|
|
33
|
+
timeout: config.timeout,
|
|
34
|
+
retry: config.retry,
|
|
35
|
+
debug: config.debug,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAW/D;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAwB;IACzD,IAAI,MAAM,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;QAChC,wDAAwD;QACxD,gBAAgB,CAAC;YACf,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QACH,4EAA4E;QAC5E,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,IAAI,mBAAmB,CAAC;QAC7B,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,KAAK,EAAE,MAAM,CAAC,KAAK;KACpB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST transport for Strapi — STUB.
|
|
3
|
+
*
|
|
4
|
+
* The interface is exported for forward compatibility; runtime usage throws
|
|
5
|
+
* a clear error. v0.1.0 only ships the GraphQL transport because every
|
|
6
|
+
* built-in content fetcher uses GraphQL.
|
|
7
|
+
*/
|
|
8
|
+
/** Configuration for the (not-yet-implemented) REST client. */
|
|
9
|
+
export interface RestClientOptions {
|
|
10
|
+
url: string;
|
|
11
|
+
token: string;
|
|
12
|
+
timeout: number;
|
|
13
|
+
retry: number;
|
|
14
|
+
}
|
|
15
|
+
/** Stubbed REST client. Constructor is callable so config typing works; all reads throw. */
|
|
16
|
+
export declare class RestStrapiClient {
|
|
17
|
+
private readonly options;
|
|
18
|
+
constructor(options: RestClientOptions);
|
|
19
|
+
get<T>(_path: string, _params?: Record<string, unknown>): Promise<T | null>;
|
|
20
|
+
}
|
|
21
|
+
/** Factory that mirrors `createStrapiClient` shape. Throws on first use. */
|
|
22
|
+
export declare function createRestClient(_options: RestClientOptions): RestStrapiClient;
|
|
23
|
+
//# sourceMappingURL=rest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/client/rest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAKD,4FAA4F;AAC5F,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;gBAEhC,OAAO,EAAE,iBAAiB;IAIhC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;CAIlF;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,gBAAgB,CAE9E"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST transport for Strapi — STUB.
|
|
3
|
+
*
|
|
4
|
+
* The interface is exported for forward compatibility; runtime usage throws
|
|
5
|
+
* a clear error. v0.1.0 only ships the GraphQL transport because every
|
|
6
|
+
* built-in content fetcher uses GraphQL.
|
|
7
|
+
*/
|
|
8
|
+
const NOT_IMPLEMENTED_MESSAGE = 'REST transport not yet implemented. Use transport: "graphql" or pin to a future v1.x release.';
|
|
9
|
+
/** Stubbed REST client. Constructor is callable so config typing works; all reads throw. */
|
|
10
|
+
export class RestStrapiClient {
|
|
11
|
+
// Stored to keep strict property init quiet and document intent.
|
|
12
|
+
options;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
async get(_path, _params) {
|
|
17
|
+
void this.options;
|
|
18
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Factory that mirrors `createStrapiClient` shape. Throws on first use. */
|
|
22
|
+
export function createRestClient(_options) {
|
|
23
|
+
throw new Error(NOT_IMPLEMENTED_MESSAGE);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=rest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["../../src/client/rest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,MAAM,uBAAuB,GAC3B,+FAA+F,CAAC;AAElG,4FAA4F;AAC5F,MAAM,OAAO,gBAAgB;IAC3B,iEAAiE;IAChD,OAAO,CAAoB;IAE5C,YAAY,OAA0B;QACpC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,KAAa,EAAE,OAAiC;QAC3D,KAAK,IAAI,CAAC,OAAO,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;CACF;AAED,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB,CAAC,QAA2B;IAC1D,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAC3C,CAAC"}
|