keyv-github 1.1.0 → 1.2.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 +44 -8
- package/dist/index.d.mts +1 -2
- package/dist/index.mjs +7 -2
- package/package.json +1 -1
- package/src/index.test.ts +34 -1
- package/src/index.ts +23 -5
package/README.md
CHANGED
|
@@ -45,11 +45,38 @@ await kv.delete("data/hello.txt");
|
|
|
45
45
|
new KeyvGithub(repoUrl, options?)
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
| Option
|
|
49
|
-
|
|
50
|
-
| `branch` | `string`
|
|
51
|
-
| `client` | `Octokit`
|
|
52
|
-
| `msg`
|
|
48
|
+
| Option | Type | Default | Description |
|
|
49
|
+
| -------- | ------------------------ | ----------------------------------- | -------------------------------------------------------- |
|
|
50
|
+
| `branch` | `string` | parsed from URL or `"main"` | Target branch |
|
|
51
|
+
| `client` | `Octokit` | `new Octokit()` | Authenticated Octokit instance |
|
|
52
|
+
| `msg` | `(key, value) => string` | `"update <key>"` / `"delete <key>"` | Customize commit messages; `value` is `null` for deletes |
|
|
53
|
+
| `prefix` | `string` | `""` | Path prefix prepended to every key (e.g. `"data/"`) |
|
|
54
|
+
| `suffix` | `string` | `""` | Path suffix appended to every key (e.g. `".json"`) |
|
|
55
|
+
|
|
56
|
+
### Store limitations
|
|
57
|
+
|
|
58
|
+
When using `KeyvGithub` directly (without wrapping in `Keyv`):
|
|
59
|
+
|
|
60
|
+
- **Values must be strings** — objects, arrays, and numbers will throw an error
|
|
61
|
+
- **TTL is not supported** — passing a TTL parameter throws an error
|
|
62
|
+
|
|
63
|
+
To store non-string values or use TTL, wrap the store with `new Keyv(store)`:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
// Direct usage: strings only, no TTL
|
|
67
|
+
await store.set("key", "string value"); // ✓
|
|
68
|
+
await store.set("key", { obj: true }); // ✗ throws error
|
|
69
|
+
await store.set("key", "value", 1000); // ✗ throws error
|
|
70
|
+
|
|
71
|
+
// With Keyv wrapper: any serializable value, TTL supported
|
|
72
|
+
const kv = new Keyv({ store });
|
|
73
|
+
await kv.set("key", { obj: true }); // ✓ serialized automatically
|
|
74
|
+
await kv.set("key", "value", 1000); // ✓ TTL handled by Keyv
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### TTL
|
|
78
|
+
|
|
79
|
+
TTL is **not enforced at the adapter level** — GitHub has no native file expiry. If you pass a `ttl` to `new Keyv({ store, ttl })`, Keyv handles it by wrapping values as `{"value":…,"expires":…}` and filtering on read. Expired files remain in the repo as inert files until overwritten or deleted. This adapter is best suited for long-lived or permanent storage.
|
|
53
80
|
|
|
54
81
|
### URL formats accepted
|
|
55
82
|
|
|
@@ -66,9 +93,7 @@ owner/repo/tree/my-branch
|
|
|
66
93
|
```ts
|
|
67
94
|
const store = new KeyvGithub("owner/repo", {
|
|
68
95
|
msg: (key, value) =>
|
|
69
|
-
value === null
|
|
70
|
-
? `chore: delete ${key}`
|
|
71
|
-
: `chore: update ${key} → ${value.slice(0, 40)}`,
|
|
96
|
+
value === null ? `chore: delete ${key}` : `chore: update ${key} → ${value.slice(0, 40)}`,
|
|
72
97
|
});
|
|
73
98
|
```
|
|
74
99
|
|
|
@@ -84,6 +109,17 @@ Keys must be valid relative file paths:
|
|
|
84
109
|
|
|
85
110
|
Invalid keys throw synchronously before any API request.
|
|
86
111
|
|
|
112
|
+
## See Also
|
|
113
|
+
|
|
114
|
+
Other Keyv storage adapters by the same author:
|
|
115
|
+
|
|
116
|
+
- [keyv-sqlite](https://github.com/snomiao/keyv-sqlite) — SQLite storage adapter
|
|
117
|
+
- [keyv-mongodb-store](https://github.com/snomiao/keyv-mongodb-store) — MongoDB storage adapter
|
|
118
|
+
- [keyv-nedb-store](https://github.com/snomiao/keyv-nedb-store) — NeDB embedded file-based adapter
|
|
119
|
+
- [keyv-dir-store](https://github.com/snomiao/keyv-dir-store) — file-per-key directory adapter with TTL via mtime
|
|
120
|
+
- [keyv-cache-proxy](https://github.com/snomiao/keyv-cache-proxy) — transparent caching proxy that wraps any object
|
|
121
|
+
- [keyv-nest](https://github.com/snomiao/keyv-nest) — hierarchical multi-layer caching adapter
|
|
122
|
+
|
|
87
123
|
## License
|
|
88
124
|
|
|
89
125
|
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -46,7 +46,7 @@ declare class KeyvGithub extends EventEmitter implements KeyvStoreAdapter {
|
|
|
46
46
|
private static isHttpError;
|
|
47
47
|
private validatePath;
|
|
48
48
|
get<Value>(key: string): Promise<StoredData<Value> | undefined>;
|
|
49
|
-
set(key: string, value: any,
|
|
49
|
+
set(key: string, value: any, ttl?: number): Promise<void>;
|
|
50
50
|
delete(key: string): Promise<boolean>;
|
|
51
51
|
has(key: string): Promise<boolean>;
|
|
52
52
|
/**
|
|
@@ -59,7 +59,6 @@ declare class KeyvGithub extends EventEmitter implements KeyvStoreAdapter {
|
|
|
59
59
|
setMany(values: Array<{
|
|
60
60
|
key: string;
|
|
61
61
|
value: any;
|
|
62
|
-
ttl?: number;
|
|
63
62
|
}>): Promise<void>;
|
|
64
63
|
/**
|
|
65
64
|
* Keyv batch-delete: deletes multiple keys in a single commit (7 API calls total).
|
package/dist/index.mjs
CHANGED
|
@@ -80,7 +80,9 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
80
80
|
throw e;
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
async set(key, value,
|
|
83
|
+
async set(key, value, ttl) {
|
|
84
|
+
if (ttl !== void 0) throw new Error("TTL is not supported natively by keyv-github. Use new Keyv(store) which handles TTL via value expiration metadata.");
|
|
85
|
+
if (typeof value !== "string") throw new Error("keyv-github only supports string values natively. Use new Keyv(store) which serializes values automatically.");
|
|
84
86
|
this.validatePath(this.toPath(key));
|
|
85
87
|
const path = this.toPath(key);
|
|
86
88
|
let sha;
|
|
@@ -197,7 +199,10 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
197
199
|
/** Keyv batch-set: writes multiple keys in a single commit (5 API calls total). */
|
|
198
200
|
async setMany(values) {
|
|
199
201
|
if (values.length === 0) return;
|
|
200
|
-
for (const { key } of values)
|
|
202
|
+
for (const { key, value } of values) {
|
|
203
|
+
if (typeof value !== "string") throw new Error("keyv-github only supports string values natively. Use new Keyv(store) which serializes values automatically.");
|
|
204
|
+
this.validatePath(this.toPath(key));
|
|
205
|
+
}
|
|
201
206
|
const entries = values.map(({ key, value }) => [this.toPath(key), String(value)]);
|
|
202
207
|
const message = entries.length === 1 ? this.msg(entries[0][0], entries[0][1]) : `batch update ${entries.length} files`;
|
|
203
208
|
await this._batchCommit({
|
package/package.json
CHANGED
package/src/index.test.ts
CHANGED
|
@@ -204,7 +204,9 @@ describe("KeyvGithub constructor", () => {
|
|
|
204
204
|
const client = makeMockClient();
|
|
205
205
|
const store = new KeyvGithub(
|
|
206
206
|
"https://github.com/owner/repo/tree/feature/my-branch",
|
|
207
|
-
{
|
|
207
|
+
{
|
|
208
|
+
client: client.rest as unknown as Octokit["rest"],
|
|
209
|
+
},
|
|
208
210
|
);
|
|
209
211
|
expect(store.branch).toBe("feature/my-branch");
|
|
210
212
|
});
|
|
@@ -294,6 +296,26 @@ describe("set", () => {
|
|
|
294
296
|
await store.set("unicode", "日本語テスト 🎉");
|
|
295
297
|
expect(mockFiles.get("unicode")?.content).toBe("日本語テスト 🎉");
|
|
296
298
|
});
|
|
299
|
+
|
|
300
|
+
test("throws when TTL is provided (not supported natively)", async () => {
|
|
301
|
+
const { store } = makeStore();
|
|
302
|
+
expect(store.set("key", "value", 1000)).rejects.toThrow(
|
|
303
|
+
"TTL is not supported natively",
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("throws when value is not a string", async () => {
|
|
308
|
+
const { store } = makeStore();
|
|
309
|
+
expect(store.set("key", { obj: true })).rejects.toThrow(
|
|
310
|
+
"only supports string values",
|
|
311
|
+
);
|
|
312
|
+
expect(store.set("key", 123)).rejects.toThrow(
|
|
313
|
+
"only supports string values",
|
|
314
|
+
);
|
|
315
|
+
expect(store.set("key", ["array"])).rejects.toThrow(
|
|
316
|
+
"only supports string values",
|
|
317
|
+
);
|
|
318
|
+
});
|
|
297
319
|
});
|
|
298
320
|
|
|
299
321
|
describe("delete", () => {
|
|
@@ -391,6 +413,17 @@ describe("setMany", () => {
|
|
|
391
413
|
).rejects.toThrow();
|
|
392
414
|
expect(mockFiles.size).toBe(0);
|
|
393
415
|
});
|
|
416
|
+
|
|
417
|
+
test("throws when any value is not a string", async () => {
|
|
418
|
+
const { store, mockFiles } = makeStore();
|
|
419
|
+
expect(
|
|
420
|
+
store.setMany([
|
|
421
|
+
{ key: "a", value: "ok" },
|
|
422
|
+
{ key: "b", value: { obj: true } },
|
|
423
|
+
]),
|
|
424
|
+
).rejects.toThrow("only supports string values");
|
|
425
|
+
expect(mockFiles.size).toBe(0);
|
|
426
|
+
});
|
|
394
427
|
});
|
|
395
428
|
|
|
396
429
|
describe("deleteMany", () => {
|
package/src/index.ts
CHANGED
|
@@ -124,7 +124,19 @@ export default class KeyvGithub
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
async set(key: string, value: any,
|
|
127
|
+
async set(key: string, value: any, ttl?: number): Promise<void> {
|
|
128
|
+
if (ttl !== undefined) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
"TTL is not supported natively by keyv-github. " +
|
|
131
|
+
"Use new Keyv(store) which handles TTL via value expiration metadata.",
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
if (typeof value !== "string") {
|
|
135
|
+
throw new Error(
|
|
136
|
+
"keyv-github only supports string values natively. " +
|
|
137
|
+
"Use new Keyv(store) which serializes values automatically.",
|
|
138
|
+
);
|
|
139
|
+
}
|
|
128
140
|
this.validatePath(this.toPath(key));
|
|
129
141
|
const path = this.toPath(key);
|
|
130
142
|
let sha: string | undefined;
|
|
@@ -257,11 +269,17 @@ export default class KeyvGithub
|
|
|
257
269
|
}
|
|
258
270
|
|
|
259
271
|
/** Keyv batch-set: writes multiple keys in a single commit (5 API calls total). */
|
|
260
|
-
async setMany(
|
|
261
|
-
values: Array<{ key: string; value: any; ttl?: number }>,
|
|
262
|
-
): Promise<void> {
|
|
272
|
+
async setMany(values: Array<{ key: string; value: any }>): Promise<void> {
|
|
263
273
|
if (values.length === 0) return;
|
|
264
|
-
for (const { key } of values)
|
|
274
|
+
for (const { key, value } of values) {
|
|
275
|
+
if (typeof value !== "string") {
|
|
276
|
+
throw new Error(
|
|
277
|
+
"keyv-github only supports string values natively. " +
|
|
278
|
+
"Use new Keyv(store) which serializes values automatically.",
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
this.validatePath(this.toPath(key));
|
|
282
|
+
}
|
|
265
283
|
const entries: [string, string][] = values.map(({ key, value }) => [
|
|
266
284
|
this.toPath(key),
|
|
267
285
|
String(value),
|