@b4moss/ss-cachian 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -6
- package/dist/cache.d.ts +39 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +269 -0
- package/dist/cache.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +223 -0
- package/dist/config.js.map +1 -0
- package/dist/driver/firestore.d.ts +24 -0
- package/dist/driver/firestore.d.ts.map +1 -0
- package/dist/driver/firestore.js +191 -0
- package/dist/driver/firestore.js.map +1 -0
- package/dist/driver/memory.d.ts +17 -0
- package/dist/driver/memory.d.ts.map +1 -0
- package/dist/driver/memory.js +94 -0
- package/dist/driver/memory.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +53 -0
- package/dist/types.js.map +1 -0
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -2,15 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
TypeScript / JavaScript port of [ss-cachian](https://github.com/b4moss/ss-cachian).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
Semantics match the Go package at `go/sscachian` (**v0.9.0**): versioned keys, multilayer
|
|
6
|
+
write-back, Exact Purge, Memory / Firestore drivers, and **config-driven** `loadTypes`.
|
|
7
|
+
Specs: [docs/specs](../../docs/specs/).
|
|
7
8
|
|
|
8
|
-
## Install
|
|
9
|
+
## Install
|
|
9
10
|
|
|
10
11
|
```bash
|
|
11
12
|
npm install @b4moss/ss-cachian
|
|
12
13
|
```
|
|
13
14
|
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { define, newMemoryStore, defaultKeyBuilder } from "@b4moss/ss-cachian";
|
|
19
|
+
|
|
20
|
+
const cache = define<string>("users")
|
|
21
|
+
.withLayers(newMemoryStore())
|
|
22
|
+
.withKeyBuilder(defaultKeyBuilder)
|
|
23
|
+
.build();
|
|
24
|
+
|
|
25
|
+
const kc = { appSlug: "app", tenantId: "t1", queryType: "user" };
|
|
26
|
+
await cache.set(kc, "alice");
|
|
27
|
+
const got = await cache.get(kc); // { ok: true, value: "alice" }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Config-driven (v0.9.0)
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createRegistry, loadTypes } from "@b4moss/ss-cachian";
|
|
34
|
+
|
|
35
|
+
const reg = createRegistry();
|
|
36
|
+
reg.registerLoader("load_users", async () => "alice");
|
|
37
|
+
const types = await loadTypes(reg, "./sscachian.yaml");
|
|
38
|
+
const cache = types.get("users");
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Firestore (Emulator / GCP):
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { define, newFirestoreStore, newMemoryStore } from "@b4moss/ss-cachian";
|
|
45
|
+
|
|
46
|
+
const fs = await newFirestoreStore({ projectId: "my-project" });
|
|
47
|
+
const cache = define("users").withLayers(newMemoryStore(), fs).build();
|
|
48
|
+
```
|
|
49
|
+
|
|
14
50
|
## Develop
|
|
15
51
|
|
|
16
52
|
```bash
|
|
@@ -18,10 +54,10 @@ cd node/sscachian
|
|
|
18
54
|
npm ci
|
|
19
55
|
npm run lint
|
|
20
56
|
npm test
|
|
21
|
-
|
|
57
|
+
# Firestore tests need FIRESTORE_EMULATOR_HOST (CI starts the emulator)
|
|
22
58
|
```
|
|
23
59
|
|
|
24
60
|
## Publish
|
|
25
61
|
|
|
26
|
-
Tags `v*` on `main`
|
|
27
|
-
|
|
62
|
+
Tags `v*` on `main` (or Actions → **npm publish** → Run workflow) publish via
|
|
63
|
+
**npm Trusted Publisher (OIDC)**. See [.github/CI.md](../../.github/CI.md).
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type DurationMs, type KeyBuilder, type KeyContext, type Layer, type Loader, type TypeGuard } from "./types.js";
|
|
2
|
+
export declare class Builder<T> {
|
|
3
|
+
#private;
|
|
4
|
+
constructor(name: string);
|
|
5
|
+
withLayers(...layers: Layer[]): this;
|
|
6
|
+
withKeyBuilder(kb: KeyBuilder | null): this;
|
|
7
|
+
withLayerTTL(ttl: DurationMs): this;
|
|
8
|
+
withPolicy(ttl: DurationMs): this;
|
|
9
|
+
withLayerTTLs(...ttls: DurationMs[]): this;
|
|
10
|
+
withLoader(loader: Loader<T>): this;
|
|
11
|
+
/** Optional runtime type check on Get (Go type assertion equivalent). */
|
|
12
|
+
withTypeGuard(guard: TypeGuard<T>): this;
|
|
13
|
+
build(): CacheType<T>;
|
|
14
|
+
}
|
|
15
|
+
export declare function define<T = unknown>(name: string): Builder<T>;
|
|
16
|
+
export declare class CacheType<T> {
|
|
17
|
+
#private;
|
|
18
|
+
constructor(name: string, layers: Layer[], ttls: DurationMs[], kb: KeyBuilder, loader: Loader<T> | null, guard?: TypeGuard<T>);
|
|
19
|
+
name(): string;
|
|
20
|
+
layers(): Layer[];
|
|
21
|
+
layerTTL(i: number): DurationMs;
|
|
22
|
+
buildKey(kc: KeyContext, version: number, signal?: AbortSignal): Promise<string>;
|
|
23
|
+
versionKey(kc: KeyContext, signal?: AbortSignal): Promise<string>;
|
|
24
|
+
currentVersion(kc: KeyContext, signal?: AbortSignal): Promise<number>;
|
|
25
|
+
bumpVersion(kc: KeyContext, signal?: AbortSignal): Promise<number>;
|
|
26
|
+
buildLatestKey(kc: KeyContext, signal?: AbortSignal): Promise<string>;
|
|
27
|
+
get(kc: KeyContext, signal?: AbortSignal): Promise<{
|
|
28
|
+
value: T;
|
|
29
|
+
ok: true;
|
|
30
|
+
} | {
|
|
31
|
+
value?: undefined;
|
|
32
|
+
ok: false;
|
|
33
|
+
}>;
|
|
34
|
+
set(kc: KeyContext, value: T, signal?: AbortSignal): Promise<void>;
|
|
35
|
+
delete(kc: KeyContext, signal?: AbortSignal): Promise<void>;
|
|
36
|
+
purge(kc: KeyContext, layerIdx?: number[], signal?: AbortSignal): Promise<void>;
|
|
37
|
+
getOrLoad(kc: KeyContext, signal?: AbortSignal): Promise<T>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,MAAM,EACX,KAAK,SAAS,EAUf,MAAM,YAAY,CAAC;AA4BpB,qBAAa,OAAO,CAAC,CAAC;;gBASR,IAAI,EAAE,MAAM;IAIxB,UAAU,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAKpC,cAAc,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI;IAK3C,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IAKnC,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IAIjC,aAAa,CAAC,GAAG,IAAI,EAAE,UAAU,EAAE,GAAG,IAAI;IAM1C,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;IAKnC,yEAAyE;IACzE,aAAa,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAKxC,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC;CAyBtB;AAED,wBAAgB,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAE5D;AAED,qBAAa,SAAS,CAAC,CAAC;;gBASpB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,KAAK,EAAE,EACf,IAAI,EAAE,UAAU,EAAE,EAClB,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,EACxB,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;IAUtB,IAAI,IAAI,MAAM;IAId,MAAM,IAAI,KAAK,EAAE;IAIjB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU;IAazB,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAMhF,UAAU,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAavE,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAI/D,WAAW,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAMlE,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAyBrE,GAAG,CACP,EAAE,EAAE,UAAU,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,KAAK,CAAC,EAAE,SAAS,CAAC;QAAC,EAAE,EAAE,KAAK,CAAA;KAAE,CAAC;IAY/D,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAelE,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAc3D,KAAK,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,GAAE,MAAM,EAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAmCnF,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;CAUlE"}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { ErrCorruptVersion, ErrInvalidLayerIndex, ErrInvalidVersion, ErrNoKeyBuilder, ErrNoLayer, ErrNoLoader, ErrNegativeTTL, ErrTypeMismatch, defaultKeyBuilder, } from "./types.js";
|
|
2
|
+
function logWarn(msg, err) {
|
|
3
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
4
|
+
console.warn(msg, detail);
|
|
5
|
+
}
|
|
6
|
+
function asInt64(v) {
|
|
7
|
+
if (typeof v === "number") {
|
|
8
|
+
if (!Number.isInteger(v))
|
|
9
|
+
throw ErrCorruptVersion;
|
|
10
|
+
return v;
|
|
11
|
+
}
|
|
12
|
+
if (typeof v === "bigint") {
|
|
13
|
+
const n = Number(v);
|
|
14
|
+
if (!Number.isSafeInteger(n))
|
|
15
|
+
throw ErrCorruptVersion;
|
|
16
|
+
return n;
|
|
17
|
+
}
|
|
18
|
+
throw ErrCorruptVersion;
|
|
19
|
+
}
|
|
20
|
+
function castValue(v, guard) {
|
|
21
|
+
if (guard) {
|
|
22
|
+
if (!guard(v))
|
|
23
|
+
throw ErrTypeMismatch;
|
|
24
|
+
return v;
|
|
25
|
+
}
|
|
26
|
+
return v;
|
|
27
|
+
}
|
|
28
|
+
export class Builder {
|
|
29
|
+
#name;
|
|
30
|
+
#layers = [];
|
|
31
|
+
#ttls = [];
|
|
32
|
+
#single = null;
|
|
33
|
+
#kb = defaultKeyBuilder;
|
|
34
|
+
#loader = null;
|
|
35
|
+
#guard;
|
|
36
|
+
constructor(name) {
|
|
37
|
+
this.#name = name;
|
|
38
|
+
}
|
|
39
|
+
withLayers(...layers) {
|
|
40
|
+
this.#layers = [...layers];
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
withKeyBuilder(kb) {
|
|
44
|
+
this.#kb = kb;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
withLayerTTL(ttl) {
|
|
48
|
+
this.#single = ttl;
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
withPolicy(ttl) {
|
|
52
|
+
return this.withLayerTTL(ttl);
|
|
53
|
+
}
|
|
54
|
+
withLayerTTLs(...ttls) {
|
|
55
|
+
this.#ttls = [...ttls];
|
|
56
|
+
this.#single = null;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
withLoader(loader) {
|
|
60
|
+
this.#loader = loader;
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
/** Optional runtime type check on Get (Go type assertion equivalent). */
|
|
64
|
+
withTypeGuard(guard) {
|
|
65
|
+
this.#guard = guard;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
build() {
|
|
69
|
+
if (this.#layers.length === 0)
|
|
70
|
+
throw ErrNoLayer;
|
|
71
|
+
if (this.#kb == null)
|
|
72
|
+
throw ErrNoKeyBuilder;
|
|
73
|
+
const ttls = new Array(this.#layers.length).fill(0);
|
|
74
|
+
if (this.#single != null) {
|
|
75
|
+
if (this.#single < 0)
|
|
76
|
+
throw ErrNegativeTTL;
|
|
77
|
+
for (let i = 0; i < ttls.length; i++)
|
|
78
|
+
ttls[i] = this.#single;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
for (let i = 0; i < ttls.length; i++) {
|
|
82
|
+
if (i < this.#ttls.length) {
|
|
83
|
+
const t = this.#ttls[i];
|
|
84
|
+
if (t < 0)
|
|
85
|
+
throw ErrNegativeTTL;
|
|
86
|
+
ttls[i] = t;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return new CacheType(this.#name, [...this.#layers], ttls, this.#kb, this.#loader, this.#guard);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export function define(name) {
|
|
94
|
+
return new Builder(name);
|
|
95
|
+
}
|
|
96
|
+
export class CacheType {
|
|
97
|
+
#name;
|
|
98
|
+
#layers;
|
|
99
|
+
#ttls;
|
|
100
|
+
#kb;
|
|
101
|
+
#loader;
|
|
102
|
+
#guard;
|
|
103
|
+
constructor(name, layers, ttls, kb, loader, guard) {
|
|
104
|
+
this.#name = name;
|
|
105
|
+
this.#layers = layers;
|
|
106
|
+
this.#ttls = ttls;
|
|
107
|
+
this.#kb = kb;
|
|
108
|
+
this.#loader = loader;
|
|
109
|
+
this.#guard = guard;
|
|
110
|
+
}
|
|
111
|
+
name() {
|
|
112
|
+
return this.#name;
|
|
113
|
+
}
|
|
114
|
+
layers() {
|
|
115
|
+
return [...this.#layers];
|
|
116
|
+
}
|
|
117
|
+
layerTTL(i) {
|
|
118
|
+
if (i < 0 || i >= this.#ttls.length)
|
|
119
|
+
return 0;
|
|
120
|
+
return this.#ttls[i];
|
|
121
|
+
}
|
|
122
|
+
#l1() {
|
|
123
|
+
return this.#layers[0];
|
|
124
|
+
}
|
|
125
|
+
async #logicalPrefix(kc, signal) {
|
|
126
|
+
return await this.#kb(kc, signal);
|
|
127
|
+
}
|
|
128
|
+
async buildKey(kc, version, signal) {
|
|
129
|
+
if (version < 1)
|
|
130
|
+
throw ErrInvalidVersion;
|
|
131
|
+
const prefix = await this.#logicalPrefix(kc, signal);
|
|
132
|
+
return `${prefix}:${version}`;
|
|
133
|
+
}
|
|
134
|
+
async versionKey(kc, signal) {
|
|
135
|
+
const prefix = await this.#logicalPrefix(kc, signal);
|
|
136
|
+
return `${prefix}:__version__`;
|
|
137
|
+
}
|
|
138
|
+
async #ensureCurrentVersion(kc, signal) {
|
|
139
|
+
const vk = await this.versionKey(kc, signal);
|
|
140
|
+
const { entry, hit } = await this.#l1().get(vk, signal);
|
|
141
|
+
if (hit)
|
|
142
|
+
return asInt64(entry.value);
|
|
143
|
+
await this.#l1().set(vk, { value: 1, createdAt: new Date(0), expiresAt: null }, 0, signal);
|
|
144
|
+
return 1;
|
|
145
|
+
}
|
|
146
|
+
currentVersion(kc, signal) {
|
|
147
|
+
return this.#ensureCurrentVersion(kc, signal);
|
|
148
|
+
}
|
|
149
|
+
async bumpVersion(kc, signal) {
|
|
150
|
+
const vk = await this.versionKey(kc, signal);
|
|
151
|
+
await this.#ensureCurrentVersion(kc, signal);
|
|
152
|
+
return this.#l1().incr(vk, signal);
|
|
153
|
+
}
|
|
154
|
+
async buildLatestKey(kc, signal) {
|
|
155
|
+
const v = await this.#ensureCurrentVersion(kc, signal);
|
|
156
|
+
return this.buildKey(kc, v, signal);
|
|
157
|
+
}
|
|
158
|
+
async #writeBack(key, e, upToExclusive, signal) {
|
|
159
|
+
for (let j = 0; j < upToExclusive; j++) {
|
|
160
|
+
try {
|
|
161
|
+
await this.#layers[j].set(key, e, this.layerTTL(j), signal);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
logWarn(`sscachian: write-back to layer ${j} failed:`, err);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async #writeAll(key, e, signal) {
|
|
169
|
+
for (let i = 0; i < this.#layers.length; i++) {
|
|
170
|
+
try {
|
|
171
|
+
await this.#layers[i].set(key, e, this.layerTTL(i), signal);
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
logWarn(`sscachian: write-back to layer ${i} failed:`, err);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async get(kc, signal) {
|
|
179
|
+
const key = await this.buildLatestKey(kc, signal);
|
|
180
|
+
for (let i = 0; i < this.#layers.length; i++) {
|
|
181
|
+
const { entry, hit } = await this.#layers[i].get(key, signal);
|
|
182
|
+
if (!hit)
|
|
183
|
+
continue;
|
|
184
|
+
await this.#writeBack(key, entry, i, signal);
|
|
185
|
+
const tv = castValue(entry.value, this.#guard);
|
|
186
|
+
return { value: tv, ok: true };
|
|
187
|
+
}
|
|
188
|
+
return { ok: false };
|
|
189
|
+
}
|
|
190
|
+
async set(kc, value, signal) {
|
|
191
|
+
await this.#ensureCurrentVersion(kc, signal);
|
|
192
|
+
const newV = await this.bumpVersion(kc, signal);
|
|
193
|
+
const key = await this.buildKey(kc, newV, signal);
|
|
194
|
+
const entry = { value, createdAt: new Date(0), expiresAt: null };
|
|
195
|
+
await this.#l1().set(key, entry, this.layerTTL(0), signal);
|
|
196
|
+
for (let i = 1; i < this.#layers.length; i++) {
|
|
197
|
+
try {
|
|
198
|
+
await this.#layers[i].set(key, entry, this.layerTTL(i), signal);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
logWarn(`sscachian: set layer ${i} failed:`, err);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async delete(kc, signal) {
|
|
206
|
+
const v = await this.#ensureCurrentVersion(kc, signal);
|
|
207
|
+
const key = await this.buildKey(kc, v, signal);
|
|
208
|
+
await this.#l1().delete(key, signal);
|
|
209
|
+
for (let i = 1; i < this.#layers.length; i++) {
|
|
210
|
+
try {
|
|
211
|
+
await this.#layers[i].delete(key, signal);
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
logWarn(`sscachian: delete layer ${i} failed:`, err);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
await this.bumpVersion(kc, signal);
|
|
218
|
+
}
|
|
219
|
+
async purge(kc, layerIdx = [], signal) {
|
|
220
|
+
const prefix = await this.#logicalPrefix(kc, signal);
|
|
221
|
+
const targets = this.#resolveLayerIndexes(layerIdx);
|
|
222
|
+
const includesL1 = targets.includes(0);
|
|
223
|
+
for (const i of targets) {
|
|
224
|
+
try {
|
|
225
|
+
await this.#layers[i].purgeExact(prefix, signal);
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
if (includesL1) {
|
|
229
|
+
if (i === 0)
|
|
230
|
+
throw err;
|
|
231
|
+
logWarn(`sscachian: purge layer ${i} failed:`, err);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
throw err;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
#resolveLayerIndexes(layerIdx) {
|
|
239
|
+
const n = this.#layers.length;
|
|
240
|
+
if (layerIdx.length === 0) {
|
|
241
|
+
return Array.from({ length: n }, (_, i) => i);
|
|
242
|
+
}
|
|
243
|
+
const seen = new Set();
|
|
244
|
+
const out = [];
|
|
245
|
+
for (const i of layerIdx) {
|
|
246
|
+
if (i < 0 || i >= n)
|
|
247
|
+
throw ErrInvalidLayerIndex;
|
|
248
|
+
if (seen.has(i))
|
|
249
|
+
continue;
|
|
250
|
+
seen.add(i);
|
|
251
|
+
out.push(i);
|
|
252
|
+
}
|
|
253
|
+
out.sort((a, b) => a - b);
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
async getOrLoad(kc, signal) {
|
|
257
|
+
const got = await this.get(kc, signal);
|
|
258
|
+
if (got.ok)
|
|
259
|
+
return got.value;
|
|
260
|
+
if (this.#loader == null)
|
|
261
|
+
throw ErrNoLoader;
|
|
262
|
+
const loaded = await this.#loader(kc, signal);
|
|
263
|
+
const ver = await this.#ensureCurrentVersion(kc, signal);
|
|
264
|
+
const key = await this.buildKey(kc, ver, signal);
|
|
265
|
+
await this.#writeAll(key, { value: loaded, createdAt: new Date(0), expiresAt: null }, signal);
|
|
266
|
+
return loaded;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CacheType } from "./cache.js";
|
|
2
|
+
import { type DurationMs, type KeyBuilder, type Loader } from "./types.js";
|
|
3
|
+
export type Registry = {
|
|
4
|
+
registerKeyBuilder(name: string, kb: KeyBuilder): void;
|
|
5
|
+
registerLoader<T>(name: string, loader: Loader<T>): void;
|
|
6
|
+
/** @internal */
|
|
7
|
+
lookupKeyBuilder(name: string): KeyBuilder | undefined;
|
|
8
|
+
/** @internal */
|
|
9
|
+
lookupLoader(name: string): Loader<unknown> | undefined;
|
|
10
|
+
};
|
|
11
|
+
export declare function createRegistry(): Registry;
|
|
12
|
+
/** Go time.ParseDuration-compatible parser (ns/us/ms/s/m/h). */
|
|
13
|
+
export declare function parseDuration(s: string): DurationMs;
|
|
14
|
+
export declare function loadTypesYAML<T = unknown>(reg: Registry, data: string | Uint8Array): Promise<Map<string, CacheType<T>>>;
|
|
15
|
+
export declare function loadTypesJSON<T = unknown>(reg: Registry, data: string | Uint8Array): Promise<Map<string, CacheType<T>>>;
|
|
16
|
+
export declare function loadTypes<T = unknown>(reg: Registry, filePath: string): Promise<Map<string, CacheType<T>>>;
|
|
17
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAU,MAAM,YAAY,CAAC;AAG/C,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,UAAU,EAEf,KAAK,MAAM,EACZ,MAAM,YAAY,CAAC;AAIpB,MAAM,MAAM,QAAQ,GAAG;IACrB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI,CAAC;IACvD,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACzD,gBAAgB;IAChB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IACvD,gBAAgB;IAChB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;CACzD,CAAC;AAEF,wBAAgB,cAAc,IAAI,QAAQ,CAsBzC;AAqBD,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,UAAU,CA2BnD;AAoID,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAC7C,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,MAAM,GAAG,UAAU,GACxB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CASpC;AAED,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAC7C,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,MAAM,GAAG,UAAU,GACxB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CASpC;AAED,wBAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EACzC,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAMpC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parse as parseYaml } from "yaml";
|
|
4
|
+
import { define } from "./cache.js";
|
|
5
|
+
import { newFirestoreStore } from "./driver/firestore.js";
|
|
6
|
+
import { newMemoryStore } from "./driver/memory.js";
|
|
7
|
+
import { ErrInvalidConfig, ErrNegativeTTL, defaultKeyBuilder, } from "./types.js";
|
|
8
|
+
const SCHEMA_VERSION = "0.9";
|
|
9
|
+
export function createRegistry() {
|
|
10
|
+
const keyBuilders = new Map([["default", defaultKeyBuilder]]);
|
|
11
|
+
const loaders = new Map();
|
|
12
|
+
return {
|
|
13
|
+
registerKeyBuilder(name, kb) {
|
|
14
|
+
if (!name)
|
|
15
|
+
throw new Error(`${ErrInvalidConfig.message}: empty key builder name`);
|
|
16
|
+
if (kb == null)
|
|
17
|
+
throw new Error(`${ErrInvalidConfig.message}: nil key builder`);
|
|
18
|
+
keyBuilders.set(name, kb);
|
|
19
|
+
},
|
|
20
|
+
registerLoader(name, loader) {
|
|
21
|
+
if (!name)
|
|
22
|
+
throw new Error(`${ErrInvalidConfig.message}: empty loader name`);
|
|
23
|
+
if (loader == null)
|
|
24
|
+
throw new Error(`${ErrInvalidConfig.message}: nil loader`);
|
|
25
|
+
loaders.set(name, loader);
|
|
26
|
+
},
|
|
27
|
+
lookupKeyBuilder(name) {
|
|
28
|
+
return keyBuilders.get(name);
|
|
29
|
+
},
|
|
30
|
+
lookupLoader(name) {
|
|
31
|
+
return loaders.get(name);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Go time.ParseDuration-compatible parser (ns/us/ms/s/m/h). */
|
|
36
|
+
export function parseDuration(s) {
|
|
37
|
+
if (s === "" || s === "0")
|
|
38
|
+
return 0;
|
|
39
|
+
const re = /(-?\d+(?:\.\d+)?)(ns|us|µs|μs|ms|s|m|h)/g;
|
|
40
|
+
let total = 0;
|
|
41
|
+
let matched = 0;
|
|
42
|
+
let m;
|
|
43
|
+
const units = {
|
|
44
|
+
ns: 1e-6,
|
|
45
|
+
us: 0.001,
|
|
46
|
+
µs: 0.001,
|
|
47
|
+
μs: 0.001,
|
|
48
|
+
ms: 1,
|
|
49
|
+
s: 1000,
|
|
50
|
+
m: 60_000,
|
|
51
|
+
h: 3_600_000,
|
|
52
|
+
};
|
|
53
|
+
while ((m = re.exec(s)) !== null) {
|
|
54
|
+
matched += m[0].length;
|
|
55
|
+
const n = Number(m[1]);
|
|
56
|
+
const u = m[2];
|
|
57
|
+
total += n * (units[u] ?? 0);
|
|
58
|
+
}
|
|
59
|
+
if (matched !== s.length || Number.isNaN(total)) {
|
|
60
|
+
throw new Error(`${ErrInvalidConfig.message}: invalid ttl ${JSON.stringify(s)}`);
|
|
61
|
+
}
|
|
62
|
+
if (total < 0)
|
|
63
|
+
throw ErrNegativeTTL;
|
|
64
|
+
return total;
|
|
65
|
+
}
|
|
66
|
+
function optionalTTL(v) {
|
|
67
|
+
if (v == null)
|
|
68
|
+
return { set: false, ms: 0 };
|
|
69
|
+
if (typeof v !== "string") {
|
|
70
|
+
throw new Error(`${ErrInvalidConfig.message}: ttl must be a string duration`);
|
|
71
|
+
}
|
|
72
|
+
if (v === "")
|
|
73
|
+
return { set: false, ms: 0 };
|
|
74
|
+
return { set: true, ms: parseDuration(v) };
|
|
75
|
+
}
|
|
76
|
+
function schemaVersion(v) {
|
|
77
|
+
if (v == null || v === "") {
|
|
78
|
+
throw new Error(`${ErrInvalidConfig.message}: schema_version is required`);
|
|
79
|
+
}
|
|
80
|
+
if (typeof v !== "string") {
|
|
81
|
+
throw new Error(`${ErrInvalidConfig.message}: schema_version must be a string`);
|
|
82
|
+
}
|
|
83
|
+
return v;
|
|
84
|
+
}
|
|
85
|
+
function stringOptions(opts) {
|
|
86
|
+
if (opts == null)
|
|
87
|
+
return {};
|
|
88
|
+
if (typeof opts !== "object" || Array.isArray(opts)) {
|
|
89
|
+
throw new Error(`${ErrInvalidConfig.message}: options must be a map`);
|
|
90
|
+
}
|
|
91
|
+
const out = {};
|
|
92
|
+
for (const [k, v] of Object.entries(opts)) {
|
|
93
|
+
if (typeof v !== "string") {
|
|
94
|
+
throw new Error(`${ErrInvalidConfig.message}: option ${JSON.stringify(k)} must be a string`);
|
|
95
|
+
}
|
|
96
|
+
out[k] = v;
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
async function buildLayer(rl) {
|
|
101
|
+
const driver = rl.driver;
|
|
102
|
+
if (typeof driver !== "string" || driver === "") {
|
|
103
|
+
throw new Error(`${ErrInvalidConfig.message}: driver must not be empty`);
|
|
104
|
+
}
|
|
105
|
+
const opts = stringOptions(rl.options);
|
|
106
|
+
if (driver === "memory") {
|
|
107
|
+
for (const k of Object.keys(opts)) {
|
|
108
|
+
throw new Error(`${ErrInvalidConfig.message}: unknown memory option ${JSON.stringify(k)}`);
|
|
109
|
+
}
|
|
110
|
+
return newMemoryStore();
|
|
111
|
+
}
|
|
112
|
+
if (driver === "firestore") {
|
|
113
|
+
const projectId = opts.project_id;
|
|
114
|
+
const collection = opts.collection;
|
|
115
|
+
for (const k of Object.keys(opts)) {
|
|
116
|
+
if (k !== "project_id" && k !== "collection") {
|
|
117
|
+
throw new Error(`${ErrInvalidConfig.message}: unknown firestore option ${JSON.stringify(k)}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return newFirestoreStore({ projectId, collection });
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`${ErrInvalidConfig.message}: unknown driver ${JSON.stringify(driver)}`);
|
|
123
|
+
}
|
|
124
|
+
async function buildOneType(reg, rt) {
|
|
125
|
+
if (typeof rt.name !== "string" || rt.name === "") {
|
|
126
|
+
throw new Error(`${ErrInvalidConfig.message}: type name must not be empty`);
|
|
127
|
+
}
|
|
128
|
+
if (!Array.isArray(rt.layers) || rt.layers.length === 0) {
|
|
129
|
+
throw new Error(`${ErrInvalidConfig.message}: type ${JSON.stringify(rt.name)}: layers must not be empty`);
|
|
130
|
+
}
|
|
131
|
+
const kbName = rt.key_builder == null || rt.key_builder === ""
|
|
132
|
+
? "default"
|
|
133
|
+
: typeof rt.key_builder === "string"
|
|
134
|
+
? rt.key_builder
|
|
135
|
+
: null;
|
|
136
|
+
if (kbName == null) {
|
|
137
|
+
throw new Error(`${ErrInvalidConfig.message}: key_builder must be a string`);
|
|
138
|
+
}
|
|
139
|
+
const kb = reg.lookupKeyBuilder(kbName);
|
|
140
|
+
if (!kb) {
|
|
141
|
+
throw new Error(`${ErrInvalidConfig.message}: unknown key_builder ${JSON.stringify(kbName)}`);
|
|
142
|
+
}
|
|
143
|
+
let loader;
|
|
144
|
+
if (rt.loader != null && rt.loader !== "") {
|
|
145
|
+
if (typeof rt.loader !== "string") {
|
|
146
|
+
throw new Error(`${ErrInvalidConfig.message}: loader must be a string`);
|
|
147
|
+
}
|
|
148
|
+
const found = reg.lookupLoader(rt.loader);
|
|
149
|
+
if (!found) {
|
|
150
|
+
throw new Error(`${ErrInvalidConfig.message}: unknown loader ${JSON.stringify(rt.loader)}`);
|
|
151
|
+
}
|
|
152
|
+
loader = found;
|
|
153
|
+
}
|
|
154
|
+
const typeTTL = optionalTTL(rt.ttl);
|
|
155
|
+
const layers = [];
|
|
156
|
+
const ttls = [];
|
|
157
|
+
for (let i = 0; i < rt.layers.length; i++) {
|
|
158
|
+
const rl = rt.layers[i];
|
|
159
|
+
layers.push(await buildLayer(rl));
|
|
160
|
+
const layerTTL = optionalTTL(rl.ttl);
|
|
161
|
+
if (layerTTL.set)
|
|
162
|
+
ttls.push(layerTTL.ms);
|
|
163
|
+
else if (typeTTL.set)
|
|
164
|
+
ttls.push(typeTTL.ms);
|
|
165
|
+
else
|
|
166
|
+
ttls.push(0);
|
|
167
|
+
}
|
|
168
|
+
const b = define(rt.name).withLayers(...layers).withKeyBuilder(kb).withLayerTTLs(...ttls);
|
|
169
|
+
if (loader)
|
|
170
|
+
b.withLoader(loader);
|
|
171
|
+
return b.build();
|
|
172
|
+
}
|
|
173
|
+
async function buildTypes(reg, raw) {
|
|
174
|
+
const ver = schemaVersion(raw.schema_version);
|
|
175
|
+
if (ver !== SCHEMA_VERSION) {
|
|
176
|
+
throw new Error(`${ErrInvalidConfig.message}: unsupported schema_version ${JSON.stringify(ver)}`);
|
|
177
|
+
}
|
|
178
|
+
if (!Array.isArray(raw.types) || raw.types.length === 0) {
|
|
179
|
+
throw new Error(`${ErrInvalidConfig.message}: types must not be empty`);
|
|
180
|
+
}
|
|
181
|
+
const out = new Map();
|
|
182
|
+
for (const rt of raw.types) {
|
|
183
|
+
const name = typeof rt.name === "string" ? rt.name : "";
|
|
184
|
+
if (out.has(name)) {
|
|
185
|
+
throw new Error(`${ErrInvalidConfig.message}: duplicate type name ${JSON.stringify(name)}`);
|
|
186
|
+
}
|
|
187
|
+
const ct = await buildOneType(reg, rt);
|
|
188
|
+
out.set(ct.name(), ct);
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
export async function loadTypesYAML(reg, data) {
|
|
193
|
+
const text = typeof data === "string" ? data : Buffer.from(data).toString("utf8");
|
|
194
|
+
let raw;
|
|
195
|
+
try {
|
|
196
|
+
raw = parseYaml(text);
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
throw new Error(`${ErrInvalidConfig.message}: yaml: ${e instanceof Error ? e.message : e}`);
|
|
200
|
+
}
|
|
201
|
+
return buildTypes(reg, raw ?? {});
|
|
202
|
+
}
|
|
203
|
+
export async function loadTypesJSON(reg, data) {
|
|
204
|
+
const text = typeof data === "string" ? data : Buffer.from(data).toString("utf8");
|
|
205
|
+
let raw;
|
|
206
|
+
try {
|
|
207
|
+
raw = JSON.parse(text);
|
|
208
|
+
}
|
|
209
|
+
catch (e) {
|
|
210
|
+
throw new Error(`${ErrInvalidConfig.message}: json: ${e instanceof Error ? e.message : e}`);
|
|
211
|
+
}
|
|
212
|
+
return buildTypes(reg, raw ?? {});
|
|
213
|
+
}
|
|
214
|
+
export async function loadTypes(reg, filePath) {
|
|
215
|
+
const data = await fs.readFile(filePath);
|
|
216
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
217
|
+
if (ext === ".json")
|
|
218
|
+
return loadTypesJSON(reg, data);
|
|
219
|
+
if (ext === ".yaml" || ext === ".yml")
|
|
220
|
+
return loadTypesYAML(reg, data);
|
|
221
|
+
throw new Error(`${ErrInvalidConfig.message}: unsupported config extension ${JSON.stringify(ext)}`);
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Firestore } from "@google-cloud/firestore";
|
|
2
|
+
import { type DurationMs, type Entry, type Layer } from "../types.js";
|
|
3
|
+
export type FirestoreOptions = {
|
|
4
|
+
projectId?: string;
|
|
5
|
+
collection?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare class FirestoreStore implements Layer {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(client: Firestore, collection: string);
|
|
10
|
+
static create(opts?: FirestoreOptions): Promise<FirestoreStore>;
|
|
11
|
+
close(): Promise<void>;
|
|
12
|
+
get(key: string, _signal?: AbortSignal): Promise<{
|
|
13
|
+
entry: Entry;
|
|
14
|
+
hit: boolean;
|
|
15
|
+
}>;
|
|
16
|
+
set(key: string, entry: Entry, ttl: DurationMs, _signal?: AbortSignal): Promise<void>;
|
|
17
|
+
delete(key: string, _signal?: AbortSignal): Promise<void>;
|
|
18
|
+
incr(key: string, _signal?: AbortSignal): Promise<number>;
|
|
19
|
+
purgeExact(logicalPrefix: string, _signal?: AbortSignal): Promise<void>;
|
|
20
|
+
/** Tests only. */
|
|
21
|
+
clearCollection(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare function newFirestoreStore(opts?: FirestoreOptions): Promise<FirestoreStore>;
|
|
24
|
+
//# sourceMappingURL=firestore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firestore.d.ts","sourceRoot":"","sources":["../../src/driver/firestore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAqB,MAAM,yBAAyB,CAAC;AAEvE,OAAO,EACL,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,KAAK,EAOX,MAAM,aAAa,CAAC;AAIrB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAQF,qBAAa,cAAe,YAAW,KAAK;;gBAI9B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM;WAKpC,MAAM,CAAC,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC;IAOnE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IA2BhF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBrF,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAiDzD,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7E,kBAAkB;IACZ,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC;AAED,wBAAsB,iBAAiB,CAAC,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAExF"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { Firestore } from "@google-cloud/firestore";
|
|
2
|
+
import { ErrEmptyKey, ErrIncrOverflow, ErrNegativeTTL, ErrNotInteger, isExpired, isVersionDataKey, } from "../types.js";
|
|
3
|
+
const defaultCollection = "sscachian";
|
|
4
|
+
export class FirestoreStore {
|
|
5
|
+
#client;
|
|
6
|
+
#collection;
|
|
7
|
+
constructor(client, collection) {
|
|
8
|
+
this.#client = client;
|
|
9
|
+
this.#collection = collection;
|
|
10
|
+
}
|
|
11
|
+
static async create(opts = {}) {
|
|
12
|
+
const projectId = opts.projectId || "ss-cachian-dev";
|
|
13
|
+
const collection = opts.collection || defaultCollection;
|
|
14
|
+
const client = new Firestore({ projectId });
|
|
15
|
+
return new FirestoreStore(client, collection);
|
|
16
|
+
}
|
|
17
|
+
async close() {
|
|
18
|
+
await this.#client.terminate();
|
|
19
|
+
}
|
|
20
|
+
#doc(key) {
|
|
21
|
+
return this.#client.collection(this.#collection).doc(key);
|
|
22
|
+
}
|
|
23
|
+
async get(key, _signal) {
|
|
24
|
+
if (key === "")
|
|
25
|
+
throw ErrEmptyKey;
|
|
26
|
+
const snap = await this.#doc(key).get();
|
|
27
|
+
if (!snap.exists)
|
|
28
|
+
return { entry: emptyEntry(), hit: false };
|
|
29
|
+
const f = snap.data();
|
|
30
|
+
const expiresAt = toDateOrNull(f.expires_at);
|
|
31
|
+
if (isExpired(expiresAt))
|
|
32
|
+
return { entry: emptyEntry(), hit: false };
|
|
33
|
+
let val = null;
|
|
34
|
+
const raw = f.value;
|
|
35
|
+
if (raw != null && (typeof raw === "string" ? raw.length > 0 : raw.length > 0)) {
|
|
36
|
+
const text = typeof raw === "string" ? raw : Buffer.from(raw).toString("utf8");
|
|
37
|
+
try {
|
|
38
|
+
val = JSON.parse(text);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
throw new Error("sscachian/firestore: invalid JSON value");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
entry: {
|
|
46
|
+
value: val,
|
|
47
|
+
createdAt: toDateOrNull(f.created_at) ?? new Date(0),
|
|
48
|
+
expiresAt,
|
|
49
|
+
},
|
|
50
|
+
hit: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async set(key, entry, ttl, _signal) {
|
|
54
|
+
if (key === "")
|
|
55
|
+
throw ErrEmptyKey;
|
|
56
|
+
if (ttl < 0)
|
|
57
|
+
throw ErrNegativeTTL;
|
|
58
|
+
const now = new Date();
|
|
59
|
+
let createdAt = entry.createdAt.getTime() === 0 ? now : entry.createdAt;
|
|
60
|
+
let expiresAt = entry.expiresAt;
|
|
61
|
+
if (ttl > 0) {
|
|
62
|
+
expiresAt = new Date(now.getTime() + ttl);
|
|
63
|
+
}
|
|
64
|
+
let raw;
|
|
65
|
+
try {
|
|
66
|
+
raw = JSON.stringify(entry.value === undefined ? null : entry.value);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
throw new Error(`sscachian/firestore: marshal value: ${String(err)}`);
|
|
70
|
+
}
|
|
71
|
+
const data = {
|
|
72
|
+
value: Buffer.from(raw, "utf8"),
|
|
73
|
+
created_at: createdAt,
|
|
74
|
+
expires_at: expiresAt ?? new Date(0),
|
|
75
|
+
};
|
|
76
|
+
await this.#doc(key).set(data);
|
|
77
|
+
}
|
|
78
|
+
async delete(key, _signal) {
|
|
79
|
+
if (key === "")
|
|
80
|
+
throw ErrEmptyKey;
|
|
81
|
+
try {
|
|
82
|
+
await this.#doc(key).delete();
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// missing is ok
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async incr(key, _signal) {
|
|
89
|
+
if (key === "")
|
|
90
|
+
throw ErrEmptyKey;
|
|
91
|
+
const ref = this.#doc(key);
|
|
92
|
+
let last;
|
|
93
|
+
for (let attempt = 0; attempt < 8; attempt++) {
|
|
94
|
+
try {
|
|
95
|
+
const out = await this.#client.runTransaction(async (tx) => {
|
|
96
|
+
const snap = await tx.get(ref);
|
|
97
|
+
let n = 0;
|
|
98
|
+
if (snap.exists) {
|
|
99
|
+
const f = snap.data();
|
|
100
|
+
const text = typeof f.value === "string"
|
|
101
|
+
? f.value
|
|
102
|
+
: Buffer.from(f.value ?? []).toString("utf8");
|
|
103
|
+
let val;
|
|
104
|
+
try {
|
|
105
|
+
val = JSON.parse(text);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
throw ErrNotInteger;
|
|
109
|
+
}
|
|
110
|
+
n = asIncrInt(val);
|
|
111
|
+
}
|
|
112
|
+
if (n >= Number.MAX_SAFE_INTEGER)
|
|
113
|
+
throw ErrIncrOverflow;
|
|
114
|
+
n += 1;
|
|
115
|
+
const raw = JSON.stringify(n);
|
|
116
|
+
tx.set(ref, {
|
|
117
|
+
value: Buffer.from(raw, "utf8"),
|
|
118
|
+
created_at: new Date(),
|
|
119
|
+
expires_at: new Date(0),
|
|
120
|
+
});
|
|
121
|
+
return n;
|
|
122
|
+
});
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
last = err;
|
|
127
|
+
if (err === ErrNotInteger || err === ErrIncrOverflow)
|
|
128
|
+
throw err;
|
|
129
|
+
const code = err.code;
|
|
130
|
+
const aborted = code === 10 ||
|
|
131
|
+
code === "ABORTED" ||
|
|
132
|
+
(err instanceof Error && /ABORTED|aborted/i.test(err.message));
|
|
133
|
+
if (!aborted)
|
|
134
|
+
throw err;
|
|
135
|
+
await sleep((attempt + 1) * 5);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
throw last instanceof Error ? last : new Error(String(last));
|
|
139
|
+
}
|
|
140
|
+
async purgeExact(logicalPrefix, _signal) {
|
|
141
|
+
if (logicalPrefix === "")
|
|
142
|
+
throw ErrEmptyKey;
|
|
143
|
+
const snap = await this.#client.collection(this.#collection).get();
|
|
144
|
+
for (const doc of snap.docs) {
|
|
145
|
+
if (!isVersionDataKey(logicalPrefix, doc.id))
|
|
146
|
+
continue;
|
|
147
|
+
await doc.ref.delete();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** Tests only. */
|
|
151
|
+
async clearCollection() {
|
|
152
|
+
const snap = await this.#client.collection(this.#collection).get();
|
|
153
|
+
for (const doc of snap.docs) {
|
|
154
|
+
await doc.ref.delete();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export async function newFirestoreStore(opts) {
|
|
159
|
+
return FirestoreStore.create(opts);
|
|
160
|
+
}
|
|
161
|
+
function emptyEntry() {
|
|
162
|
+
return { value: undefined, createdAt: new Date(0), expiresAt: null };
|
|
163
|
+
}
|
|
164
|
+
function toDateOrNull(v) {
|
|
165
|
+
if (v == null)
|
|
166
|
+
return null;
|
|
167
|
+
if (v instanceof Date) {
|
|
168
|
+
if (v.getTime() === 0)
|
|
169
|
+
return null;
|
|
170
|
+
return v;
|
|
171
|
+
}
|
|
172
|
+
if (typeof v === "object" && v !== null && "toDate" in v && typeof v.toDate === "function") {
|
|
173
|
+
const d = v.toDate();
|
|
174
|
+
if (d.getTime() === 0)
|
|
175
|
+
return null;
|
|
176
|
+
return d;
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
function asIncrInt(v) {
|
|
181
|
+
if (typeof v === "number") {
|
|
182
|
+
if (!Number.isInteger(v))
|
|
183
|
+
throw ErrNotInteger;
|
|
184
|
+
return v;
|
|
185
|
+
}
|
|
186
|
+
throw ErrNotInteger;
|
|
187
|
+
}
|
|
188
|
+
function sleep(ms) {
|
|
189
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=firestore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firestore.js","sourceRoot":"","sources":["../../src/driver/firestore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type DurationMs, type Entry, type Layer } from "../types.js";
|
|
2
|
+
/** Process-local Layer (mutex via sync Map ops on event loop). */
|
|
3
|
+
export declare class MemoryStore implements Layer {
|
|
4
|
+
#private;
|
|
5
|
+
/** Test helper: store arbitrary raw value. */
|
|
6
|
+
injectRaw(key: string, v: unknown): void;
|
|
7
|
+
get(key: string, _signal?: AbortSignal): Promise<{
|
|
8
|
+
entry: Entry;
|
|
9
|
+
hit: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
set(key: string, entry: Entry, ttl: DurationMs, _signal?: AbortSignal): Promise<void>;
|
|
12
|
+
delete(key: string, _signal?: AbortSignal): Promise<void>;
|
|
13
|
+
incr(key: string, _signal?: AbortSignal): Promise<number>;
|
|
14
|
+
purgeExact(logicalPrefix: string, _signal?: AbortSignal): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function newMemoryStore(): MemoryStore;
|
|
17
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/driver/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,KAAK,EAOX,MAAM,aAAa,CAAC;AAErB,kEAAkE;AAClE,qBAAa,WAAY,YAAW,KAAK;;IAGvC,8CAA8C;IAC9C,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,GAAG,IAAI;IAIlC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IAehF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAerF,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAczD,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAM9E;AAED,wBAAgB,cAAc,IAAI,WAAW,CAE5C"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ErrEmptyKey, ErrIncrOverflow, ErrNegativeTTL, ErrNotInteger, isExpired, isVersionDataKey, } from "../types.js";
|
|
2
|
+
/** Process-local Layer (mutex via sync Map ops on event loop). */
|
|
3
|
+
export class MemoryStore {
|
|
4
|
+
#m = new Map();
|
|
5
|
+
/** Test helper: store arbitrary raw value. */
|
|
6
|
+
injectRaw(key, v) {
|
|
7
|
+
this.#m.set(key, v);
|
|
8
|
+
}
|
|
9
|
+
async get(key, _signal) {
|
|
10
|
+
if (key === "")
|
|
11
|
+
throw ErrEmptyKey;
|
|
12
|
+
const raw = this.#m.get(key);
|
|
13
|
+
if (raw === undefined)
|
|
14
|
+
return { entry: emptyEntry(), hit: false };
|
|
15
|
+
if (!isEntry(raw)) {
|
|
16
|
+
this.#m.delete(key);
|
|
17
|
+
return { entry: emptyEntry(), hit: false };
|
|
18
|
+
}
|
|
19
|
+
if (isExpired(raw.expiresAt)) {
|
|
20
|
+
this.#m.delete(key);
|
|
21
|
+
return { entry: emptyEntry(), hit: false };
|
|
22
|
+
}
|
|
23
|
+
return { entry: { ...raw }, hit: true };
|
|
24
|
+
}
|
|
25
|
+
async set(key, entry, ttl, _signal) {
|
|
26
|
+
if (key === "")
|
|
27
|
+
throw ErrEmptyKey;
|
|
28
|
+
if (ttl < 0)
|
|
29
|
+
throw ErrNegativeTTL;
|
|
30
|
+
const now = new Date();
|
|
31
|
+
const stored = {
|
|
32
|
+
value: entry.value,
|
|
33
|
+
createdAt: entry.createdAt.getTime() === 0 ? now : new Date(entry.createdAt),
|
|
34
|
+
expiresAt: entry.expiresAt,
|
|
35
|
+
};
|
|
36
|
+
if (ttl > 0) {
|
|
37
|
+
stored.expiresAt = new Date(now.getTime() + ttl);
|
|
38
|
+
}
|
|
39
|
+
this.#m.set(key, stored);
|
|
40
|
+
}
|
|
41
|
+
async delete(key, _signal) {
|
|
42
|
+
if (key === "")
|
|
43
|
+
throw ErrEmptyKey;
|
|
44
|
+
this.#m.delete(key);
|
|
45
|
+
}
|
|
46
|
+
async incr(key, _signal) {
|
|
47
|
+
if (key === "")
|
|
48
|
+
throw ErrEmptyKey;
|
|
49
|
+
const raw = this.#m.get(key);
|
|
50
|
+
let n = 0;
|
|
51
|
+
if (raw !== undefined) {
|
|
52
|
+
if (!isEntry(raw))
|
|
53
|
+
throw ErrNotInteger;
|
|
54
|
+
n = asIncrInt(raw.value);
|
|
55
|
+
}
|
|
56
|
+
if (n >= Number.MAX_SAFE_INTEGER)
|
|
57
|
+
throw ErrIncrOverflow;
|
|
58
|
+
n += 1;
|
|
59
|
+
this.#m.set(key, { value: n, createdAt: new Date(), expiresAt: null });
|
|
60
|
+
return n;
|
|
61
|
+
}
|
|
62
|
+
async purgeExact(logicalPrefix, _signal) {
|
|
63
|
+
if (logicalPrefix === "")
|
|
64
|
+
throw ErrEmptyKey;
|
|
65
|
+
for (const k of [...this.#m.keys()]) {
|
|
66
|
+
if (isVersionDataKey(logicalPrefix, k))
|
|
67
|
+
this.#m.delete(k);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export function newMemoryStore() {
|
|
72
|
+
return new MemoryStore();
|
|
73
|
+
}
|
|
74
|
+
function emptyEntry() {
|
|
75
|
+
return { value: undefined, createdAt: new Date(0), expiresAt: null };
|
|
76
|
+
}
|
|
77
|
+
function isEntry(v) {
|
|
78
|
+
if (v == null || typeof v !== "object")
|
|
79
|
+
return false;
|
|
80
|
+
const o = v;
|
|
81
|
+
return "value" in o && "createdAt" in o && "expiresAt" in o;
|
|
82
|
+
}
|
|
83
|
+
function asIncrInt(v) {
|
|
84
|
+
if (typeof v === "number" && Number.isInteger(v))
|
|
85
|
+
return v;
|
|
86
|
+
if (typeof v === "bigint") {
|
|
87
|
+
const n = Number(v);
|
|
88
|
+
if (!Number.isSafeInteger(n))
|
|
89
|
+
throw ErrNotInteger;
|
|
90
|
+
return n;
|
|
91
|
+
}
|
|
92
|
+
throw ErrNotInteger;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/driver/memory.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Semantics follow the Go package at go/sscachian (v0.7.0 PoC).
|
|
2
|
+
* @b4moss/ss-cachian — Node.js / TypeScript port of ss-cachian (Go v0.7.0+ parity).
|
|
4
3
|
*/
|
|
5
4
|
export declare const SSCACHIAN_RUNTIME: "node";
|
|
6
|
-
export
|
|
5
|
+
export { ErrEmptyKey, ErrNegativeTTL, ErrNotInteger, ErrIncrOverflow, ErrNoLayer, ErrNoKeyBuilder, ErrInvalidVersion, ErrNoLoader, ErrTypeMismatch, ErrInvalidContext, ErrCorruptVersion, ErrInvalidLayerIndex, ErrInvalidConfig, SscachianError, isVersionDataKey, defaultKeyBuilder, type Entry, type Layer, type DurationMs, type KeyContext, type KeyBuilder, type Loader, type TypeGuard, } from "./types.js";
|
|
6
|
+
export { define, Builder, CacheType } from "./cache.js";
|
|
7
|
+
export { MemoryStore, newMemoryStore } from "./driver/memory.js";
|
|
8
|
+
export { FirestoreStore, newFirestoreStore, type FirestoreOptions, } from "./driver/firestore.js";
|
|
9
|
+
export { createRegistry, loadTypes, loadTypesYAML, loadTypesJSON, parseDuration, type Registry, } from "./config.js";
|
|
7
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,iBAAiB,EAAG,MAAe,CAAC;AAEjD,OAAO,EACL,WAAW,EACX,cAAc,EACd,aAAa,EACb,eAAe,EACf,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,KAAK,EACV,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,SAAS,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,aAAa,EACb,aAAa,EACb,KAAK,QAAQ,GACd,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Semantics follow the Go package at go/sscachian (v0.7.0 PoC).
|
|
2
|
+
* @b4moss/ss-cachian — Node.js / TypeScript port of ss-cachian (Go v0.7.0+ parity).
|
|
4
3
|
*/
|
|
5
4
|
export const SSCACHIAN_RUNTIME = "node";
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
}
|
|
5
|
+
export { ErrEmptyKey, ErrNegativeTTL, ErrNotInteger, ErrIncrOverflow, ErrNoLayer, ErrNoKeyBuilder, ErrInvalidVersion, ErrNoLoader, ErrTypeMismatch, ErrInvalidContext, ErrCorruptVersion, ErrInvalidLayerIndex, ErrInvalidConfig, SscachianError, isVersionDataKey, defaultKeyBuilder, } from "./types.js";
|
|
6
|
+
export { define, Builder, CacheType } from "./cache.js";
|
|
7
|
+
export { MemoryStore, newMemoryStore } from "./driver/memory.js";
|
|
8
|
+
export { FirestoreStore, newFirestoreStore, } from "./driver/firestore.js";
|
|
9
|
+
export { createRegistry, loadTypes, loadTypesYAML, loadTypesJSON, parseDuration, } from "./config.js";
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAe,CAAC;AAEjD,OAAO,EACL,WAAW,EACX,cAAc,EACd,aAAa,EACb,eAAe,EACf,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GAQlB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EACL,cAAc,EACd,iBAAiB,GAElB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,cAAc,EACd,SAAS,EACT,aAAa,EACb,aAAa,EACb,aAAa,GAEd,MAAM,aAAa,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Shared errors and Layer contract (Go parity). */
|
|
2
|
+
export declare class SscachianError extends Error {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare const ErrEmptyKey: SscachianError;
|
|
6
|
+
export declare const ErrNegativeTTL: SscachianError;
|
|
7
|
+
export declare const ErrNotInteger: SscachianError;
|
|
8
|
+
export declare const ErrIncrOverflow: SscachianError;
|
|
9
|
+
export declare const ErrNoLayer: SscachianError;
|
|
10
|
+
export declare const ErrNoKeyBuilder: SscachianError;
|
|
11
|
+
export declare const ErrInvalidVersion: SscachianError;
|
|
12
|
+
export declare const ErrNoLoader: SscachianError;
|
|
13
|
+
export declare const ErrTypeMismatch: SscachianError;
|
|
14
|
+
export declare const ErrInvalidContext: SscachianError;
|
|
15
|
+
export declare const ErrCorruptVersion: SscachianError;
|
|
16
|
+
export declare const ErrInvalidLayerIndex: SscachianError;
|
|
17
|
+
export declare const ErrInvalidConfig: SscachianError;
|
|
18
|
+
/** On-Layer storage wrapper. */
|
|
19
|
+
export type Entry = {
|
|
20
|
+
value: unknown;
|
|
21
|
+
createdAt: Date;
|
|
22
|
+
/** Invalid / epoch 0 means no expiry (Go zero time). */
|
|
23
|
+
expiresAt: Date | null;
|
|
24
|
+
};
|
|
25
|
+
export declare function noExpiry(): null;
|
|
26
|
+
export declare function isExpired(expiresAt: Date | null, now?: Date): boolean;
|
|
27
|
+
/** TTL in milliseconds. 0 = no expiry from TTL arg. */
|
|
28
|
+
export type DurationMs = number;
|
|
29
|
+
export type Layer = {
|
|
30
|
+
get(key: string, signal?: AbortSignal): Promise<{
|
|
31
|
+
entry: Entry;
|
|
32
|
+
hit: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
set(key: string, entry: Entry, ttl: DurationMs, signal?: AbortSignal): Promise<void>;
|
|
35
|
+
delete(key: string, signal?: AbortSignal): Promise<void>;
|
|
36
|
+
incr(key: string, signal?: AbortSignal): Promise<number>;
|
|
37
|
+
purgeExact(logicalPrefix: string, signal?: AbortSignal): Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
/** True when key is `{logicalPrefix}:{digits}` (digits non-empty). */
|
|
40
|
+
export declare function isVersionDataKey(logicalPrefix: string, key: string): boolean;
|
|
41
|
+
export type KeyContext = {
|
|
42
|
+
appSlug: string;
|
|
43
|
+
tenantId: string;
|
|
44
|
+
queryType: string;
|
|
45
|
+
};
|
|
46
|
+
export type KeyBuilder = (kc: KeyContext, signal?: AbortSignal) => Promise<string> | string;
|
|
47
|
+
export type Loader<T> = (kc: KeyContext, signal?: AbortSignal) => Promise<T>;
|
|
48
|
+
export type TypeGuard<T> = (v: unknown) => v is T;
|
|
49
|
+
export declare function defaultKeyBuilder(kc: KeyContext): string;
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,eAAO,MAAM,WAAW,gBAA6C,CAAC;AACtE,eAAO,MAAM,cAAc,gBAAgD,CAAC;AAC5E,eAAO,MAAM,aAAa,gBAA2D,CAAC;AACtF,eAAO,MAAM,eAAe,gBAAiD,CAAC;AAC9E,eAAO,MAAM,UAAU,gBAAwD,CAAC;AAChF,eAAO,MAAM,eAAe,gBAA8D,CAAC;AAC3F,eAAO,MAAM,iBAAiB,gBAAwD,CAAC;AACvF,eAAO,MAAM,WAAW,gBAAyD,CAAC;AAClF,eAAO,MAAM,eAAe,gBAA8D,CAAC;AAC3F,eAAO,MAAM,iBAAiB,gBAAuD,CAAC;AACtF,eAAO,MAAM,iBAAiB,gBAAiE,CAAC;AAChG,eAAO,MAAM,oBAAoB,gBAAuD,CAAC;AACzF,eAAO,MAAM,gBAAgB,gBAAkD,CAAC;AAEhF,gCAAgC;AAChC,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,wDAAwD;IACxD,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB,CAAC;AAEF,wBAAgB,QAAQ,IAAI,IAAI,CAE/B;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,OAAa,GAAG,OAAO,CAI3E;AAED,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAChF,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,UAAU,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAU5E;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;AAC5F,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AAC7E,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;AAElD,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,UAAU,GAAG,MAAM,CAKxD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Shared errors and Layer contract (Go parity). */
|
|
2
|
+
export class SscachianError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "SscachianError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export const ErrEmptyKey = new SscachianError("sscachian: empty key");
|
|
9
|
+
export const ErrNegativeTTL = new SscachianError("sscachian: negative TTL");
|
|
10
|
+
export const ErrNotInteger = new SscachianError("sscachian: value is not an integer");
|
|
11
|
+
export const ErrIncrOverflow = new SscachianError("sscachian: incr overflow");
|
|
12
|
+
export const ErrNoLayer = new SscachianError("sscachian: no layers configured");
|
|
13
|
+
export const ErrNoKeyBuilder = new SscachianError("sscachian: key builder not configured");
|
|
14
|
+
export const ErrInvalidVersion = new SscachianError("sscachian: version must be >= 1");
|
|
15
|
+
export const ErrNoLoader = new SscachianError("sscachian: loader not configured");
|
|
16
|
+
export const ErrTypeMismatch = new SscachianError("sscachian: cached value type mismatch");
|
|
17
|
+
export const ErrInvalidContext = new SscachianError("sscachian: invalid key context");
|
|
18
|
+
export const ErrCorruptVersion = new SscachianError("sscachian: corrupt current-version value");
|
|
19
|
+
export const ErrInvalidLayerIndex = new SscachianError("sscachian: invalid layer index");
|
|
20
|
+
export const ErrInvalidConfig = new SscachianError("sscachian: invalid config");
|
|
21
|
+
export function noExpiry() {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
export function isExpired(expiresAt, now = new Date()) {
|
|
25
|
+
if (expiresAt == null)
|
|
26
|
+
return false;
|
|
27
|
+
if (expiresAt.getTime() === 0)
|
|
28
|
+
return false;
|
|
29
|
+
return !(expiresAt.getTime() > now.getTime());
|
|
30
|
+
}
|
|
31
|
+
/** True when key is `{logicalPrefix}:{digits}` (digits non-empty). */
|
|
32
|
+
export function isVersionDataKey(logicalPrefix, key) {
|
|
33
|
+
if (logicalPrefix === "" || key === "")
|
|
34
|
+
return false;
|
|
35
|
+
const want = `${logicalPrefix}:`;
|
|
36
|
+
if (!key.startsWith(want))
|
|
37
|
+
return false;
|
|
38
|
+
const rest = key.slice(want.length);
|
|
39
|
+
if (rest === "")
|
|
40
|
+
return false;
|
|
41
|
+
for (const ch of rest) {
|
|
42
|
+
if (ch < "0" || ch > "9")
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
export function defaultKeyBuilder(kc) {
|
|
48
|
+
if (!kc.appSlug || !kc.tenantId || !kc.queryType) {
|
|
49
|
+
throw ErrInvalidContext;
|
|
50
|
+
}
|
|
51
|
+
return `${kc.appSlug}:cache:${kc.tenantId}:${kc.queryType}`;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b4moss/ss-cachian",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Server-side cache strategy library (TypeScript/JavaScript).
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Server-side cache strategy library (TypeScript/JavaScript). Config-driven Cache Types (v0.9.0) with Go parity.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "tsc -p tsconfig.json",
|
|
25
25
|
"lint": "tsc -p tsconfig.json --noEmit",
|
|
26
|
-
"test": "npm run build && node --test dist/**/*.test.js",
|
|
26
|
+
"test": "rm -rf dist && npm run build && node --test 'dist/**/*.test.js'",
|
|
27
27
|
"prepublishOnly": "npm run build"
|
|
28
28
|
},
|
|
29
29
|
"repository": {
|
|
@@ -49,7 +49,11 @@
|
|
|
49
49
|
"versioned-cache"
|
|
50
50
|
],
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@types/node": "^22.
|
|
52
|
+
"@types/node": "^22.20.4",
|
|
53
53
|
"typescript": "^5.8.2"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@google-cloud/firestore": "^7.11.6",
|
|
57
|
+
"yaml": "^2.7.0"
|
|
54
58
|
}
|
|
55
59
|
}
|