keyv-github 1.2.0 → 1.4.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/.releaserc.json +14 -0
- package/README.md +14 -0
- package/bun.lock +86 -19
- package/dist/index.d.mts +28 -2
- package/dist/index.mjs +65 -35
- package/package.json +2 -1
- package/src/index.test.ts +5 -5
- package/src/index.ts +100 -36
package/.releaserc.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"plugins": [
|
|
3
|
+
"@semantic-release/commit-analyzer",
|
|
4
|
+
"@semantic-release/release-notes-generator",
|
|
5
|
+
"@semantic-release/npm",
|
|
6
|
+
[
|
|
7
|
+
"@semantic-release/git",
|
|
8
|
+
{
|
|
9
|
+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"@semantic-release/github"
|
|
13
|
+
]
|
|
14
|
+
}
|
package/README.md
CHANGED
|
@@ -99,6 +99,8 @@ const store = new KeyvGithub("owner/repo", {
|
|
|
99
99
|
|
|
100
100
|
## Key rules
|
|
101
101
|
|
|
102
|
+
⚠️ **Keys are validated but NOT sanitized.** You must sanitize keys yourself before passing them to this adapter. Invalid keys will throw an error.
|
|
103
|
+
|
|
102
104
|
Keys must be valid relative file paths:
|
|
103
105
|
|
|
104
106
|
- Non-empty
|
|
@@ -109,6 +111,18 @@ Keys must be valid relative file paths:
|
|
|
109
111
|
|
|
110
112
|
Invalid keys throw synchronously before any API request.
|
|
111
113
|
|
|
114
|
+
```ts
|
|
115
|
+
// ✗ These will throw errors
|
|
116
|
+
await store.set("/absolute/path", "value"); // leading slash
|
|
117
|
+
await store.set("path/", "value"); // trailing slash
|
|
118
|
+
await store.set("path/../escape", "value"); // directory traversal
|
|
119
|
+
await store.set("path//double", "value"); // double slashes
|
|
120
|
+
|
|
121
|
+
// ✓ Valid keys
|
|
122
|
+
await store.set("data/file.txt", "value");
|
|
123
|
+
await store.set("nested/path/key.json", "value");
|
|
124
|
+
```
|
|
125
|
+
|
|
112
126
|
## See Also
|
|
113
127
|
|
|
114
128
|
Other Keyv storage adapters by the same author:
|
package/bun.lock
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"octokit": "^5.0.5",
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
+
"@semantic-release/git": "^10.0.1",
|
|
12
13
|
"@types/bun": "latest",
|
|
13
14
|
"semantic-release": "^25.0.3",
|
|
14
15
|
"tsdown": "^0.20.3",
|
|
@@ -149,7 +150,9 @@
|
|
|
149
150
|
|
|
150
151
|
"@semantic-release/commit-analyzer": ["@semantic-release/commit-analyzer@13.0.1", "", { "dependencies": { "conventional-changelog-angular": "^8.0.0", "conventional-changelog-writer": "^8.0.0", "conventional-commits-filter": "^5.0.0", "conventional-commits-parser": "^6.0.0", "debug": "^4.0.0", "import-from-esm": "^2.0.0", "lodash-es": "^4.17.21", "micromatch": "^4.0.2" }, "peerDependencies": { "semantic-release": ">=20.1.0" } }, "sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ=="],
|
|
151
152
|
|
|
152
|
-
"@semantic-release/error": ["@semantic-release/error@
|
|
153
|
+
"@semantic-release/error": ["@semantic-release/error@3.0.0", "", {}, "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw=="],
|
|
154
|
+
|
|
155
|
+
"@semantic-release/git": ["@semantic-release/git@10.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "micromatch": "^4.0.0", "p-reduce": "^2.0.0" }, "peerDependencies": { "semantic-release": ">=18.0.0" } }, "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w=="],
|
|
153
156
|
|
|
154
157
|
"@semantic-release/github": ["@semantic-release/github@12.0.6", "", { "dependencies": { "@octokit/core": "^7.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-retry": "^8.0.0", "@octokit/plugin-throttling": "^11.0.0", "@semantic-release/error": "^4.0.0", "aggregate-error": "^5.0.0", "debug": "^4.3.4", "dir-glob": "^3.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "issue-parser": "^7.0.0", "lodash-es": "^4.17.21", "mime": "^4.0.0", "p-filter": "^4.0.0", "tinyglobby": "^0.2.14", "undici": "^7.0.0", "url-join": "^5.0.0" }, "peerDependencies": { "semantic-release": ">=24.1.0" } }, "sha512-aYYFkwHW3c6YtHwQF0t0+lAjlU+87NFOZuH2CvWFD0Ylivc7MwhZMiHOJ0FMpIgPpCVib/VUAcOwvrW0KnxQtA=="],
|
|
155
158
|
|
|
@@ -193,7 +196,7 @@
|
|
|
193
196
|
|
|
194
197
|
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
|
195
198
|
|
|
196
|
-
"aggregate-error": ["aggregate-error@
|
|
199
|
+
"aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
|
|
197
200
|
|
|
198
201
|
"ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="],
|
|
199
202
|
|
|
@@ -231,7 +234,7 @@
|
|
|
231
234
|
|
|
232
235
|
"char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="],
|
|
233
236
|
|
|
234
|
-
"clean-stack": ["clean-stack@
|
|
237
|
+
"clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
|
|
235
238
|
|
|
236
239
|
"cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="],
|
|
237
240
|
|
|
@@ -299,7 +302,7 @@
|
|
|
299
302
|
|
|
300
303
|
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
|
301
304
|
|
|
302
|
-
"execa": ["execa@
|
|
305
|
+
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
|
303
306
|
|
|
304
307
|
"fast-content-type-parse": ["fast-content-type-parse@3.0.0", "", {}, "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg=="],
|
|
305
308
|
|
|
@@ -349,7 +352,7 @@
|
|
|
349
352
|
|
|
350
353
|
"https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
|
|
351
354
|
|
|
352
|
-
"human-signals": ["human-signals@
|
|
355
|
+
"human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
|
|
353
356
|
|
|
354
357
|
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
|
355
358
|
|
|
@@ -359,7 +362,7 @@
|
|
|
359
362
|
|
|
360
363
|
"import-without-cache": ["import-without-cache@0.2.5", "", {}, "sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A=="],
|
|
361
364
|
|
|
362
|
-
"indent-string": ["indent-string@
|
|
365
|
+
"indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="],
|
|
363
366
|
|
|
364
367
|
"index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="],
|
|
365
368
|
|
|
@@ -379,7 +382,7 @@
|
|
|
379
382
|
|
|
380
383
|
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
|
|
381
384
|
|
|
382
|
-
"is-stream": ["is-stream@
|
|
385
|
+
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
|
383
386
|
|
|
384
387
|
"is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
|
|
385
388
|
|
|
@@ -411,6 +414,8 @@
|
|
|
411
414
|
|
|
412
415
|
"locate-path": ["locate-path@2.0.0", "", { "dependencies": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" } }, "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA=="],
|
|
413
416
|
|
|
417
|
+
"lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
|
|
418
|
+
|
|
414
419
|
"lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="],
|
|
415
420
|
|
|
416
421
|
"lodash.capitalize": ["lodash.capitalize@4.2.1", "", {}, "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw=="],
|
|
@@ -439,7 +444,7 @@
|
|
|
439
444
|
|
|
440
445
|
"mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="],
|
|
441
446
|
|
|
442
|
-
"mimic-fn": ["mimic-fn@
|
|
447
|
+
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
|
443
448
|
|
|
444
449
|
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
|
445
450
|
|
|
@@ -459,7 +464,7 @@
|
|
|
459
464
|
|
|
460
465
|
"npm": ["npm@11.10.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^9.3.0", "@npmcli/config": "^10.7.0", "@npmcli/fs": "^5.0.0", "@npmcli/map-workspaces": "^5.0.3", "@npmcli/metavuln-calculator": "^9.0.3", "@npmcli/package-json": "^7.0.4", "@npmcli/promise-spawn": "^9.0.1", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.3", "@sigstore/tuf": "^4.0.1", "abbrev": "^4.0.0", "archy": "~1.0.0", "cacache": "^20.0.3", "chalk": "^5.6.2", "ci-info": "^4.4.0", "cli-columns": "^4.0.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", "glob": "^13.0.2", "graceful-fs": "^4.2.11", "hosted-git-info": "^9.0.2", "ini": "^6.0.0", "init-package-json": "^8.2.4", "is-cidr": "^6.0.3", "json-parse-even-better-errors": "^5.0.0", "libnpmaccess": "^10.0.3", "libnpmdiff": "^8.1.1", "libnpmexec": "^10.2.1", "libnpmfund": "^7.0.15", "libnpmorg": "^8.0.1", "libnpmpack": "^9.1.1", "libnpmpublish": "^11.1.3", "libnpmsearch": "^9.0.1", "libnpmteam": "^8.0.2", "libnpmversion": "^8.0.3", "make-fetch-happen": "^15.0.3", "minimatch": "^10.1.1", "minipass": "^7.1.1", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", "node-gyp": "^12.2.0", "nopt": "^9.0.0", "npm-audit-report": "^7.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.2", "npm-pick-manifest": "^11.0.3", "npm-profile": "^12.0.1", "npm-registry-fetch": "^19.1.1", "npm-user-validate": "^4.0.0", "p-map": "^7.0.4", "pacote": "^21.3.1", "parse-conflict-json": "^5.0.1", "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", "read": "^5.0.1", "semver": "^7.7.4", "spdx-expression-parse": "^4.0.0", "ssri": "^13.0.1", "supports-color": "^10.2.2", "tar": "^7.5.7", "text-table": "~0.2.0", "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", "validate-npm-package-name": "^7.0.2", "which": "^6.0.1" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" } }, "sha512-i8hE43iSIAMFuYVi8TxsEISdELM4fIza600aLjJ0ankGPLqd0oTPKMJqAcO/QWm307MbSlWGzJcNZ0lGMQgHPA=="],
|
|
461
466
|
|
|
462
|
-
"npm-run-path": ["npm-run-path@
|
|
467
|
+
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
|
463
468
|
|
|
464
469
|
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
|
465
470
|
|
|
@@ -467,7 +472,7 @@
|
|
|
467
472
|
|
|
468
473
|
"octokit": ["octokit@5.0.5", "", { "dependencies": { "@octokit/app": "^16.1.2", "@octokit/core": "^7.0.6", "@octokit/oauth-app": "^8.0.3", "@octokit/plugin-paginate-graphql": "^6.0.0", "@octokit/plugin-paginate-rest": "^14.0.0", "@octokit/plugin-rest-endpoint-methods": "^17.0.0", "@octokit/plugin-retry": "^8.0.3", "@octokit/plugin-throttling": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "@octokit/webhooks": "^14.0.0" } }, "sha512-4+/OFSqOjoyULo7eN7EA97DE0Xydj/PW5aIckxqQIoFjFwqXKuFCvXUJObyJfBF9Khu4RL/jlDRI9FPaMGfPnw=="],
|
|
469
474
|
|
|
470
|
-
"onetime": ["onetime@
|
|
475
|
+
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
|
471
476
|
|
|
472
477
|
"p-each-series": ["p-each-series@3.0.0", "", {}, "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw=="],
|
|
473
478
|
|
|
@@ -483,7 +488,7 @@
|
|
|
483
488
|
|
|
484
489
|
"p-map": ["p-map@7.0.4", "", {}, "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ=="],
|
|
485
490
|
|
|
486
|
-
"p-reduce": ["p-reduce@
|
|
491
|
+
"p-reduce": ["p-reduce@2.1.0", "", {}, "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw=="],
|
|
487
492
|
|
|
488
493
|
"p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="],
|
|
489
494
|
|
|
@@ -555,7 +560,7 @@
|
|
|
555
560
|
|
|
556
561
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
|
557
562
|
|
|
558
|
-
"signal-exit": ["signal-exit@
|
|
563
|
+
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
|
559
564
|
|
|
560
565
|
"signale": ["signale@1.4.0", "", { "dependencies": { "chalk": "^2.3.2", "figures": "^2.0.0", "pkg-conf": "^2.1.0" } }, "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w=="],
|
|
561
566
|
|
|
@@ -585,7 +590,7 @@
|
|
|
585
590
|
|
|
586
591
|
"strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
|
|
587
592
|
|
|
588
|
-
"strip-final-newline": ["strip-final-newline@
|
|
593
|
+
"strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
|
589
594
|
|
|
590
595
|
"strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
|
|
591
596
|
|
|
@@ -683,6 +688,16 @@
|
|
|
683
688
|
|
|
684
689
|
"@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="],
|
|
685
690
|
|
|
691
|
+
"@semantic-release/github/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="],
|
|
692
|
+
|
|
693
|
+
"@semantic-release/github/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="],
|
|
694
|
+
|
|
695
|
+
"@semantic-release/npm/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="],
|
|
696
|
+
|
|
697
|
+
"@semantic-release/npm/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="],
|
|
698
|
+
|
|
699
|
+
"@semantic-release/npm/execa": ["execa@9.6.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="],
|
|
700
|
+
|
|
686
701
|
"@semantic-release/release-notes-generator/get-stream": ["get-stream@7.0.1", "", {}, "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ=="],
|
|
687
702
|
|
|
688
703
|
"@semantic-release/release-notes-generator/read-package-up": ["read-package-up@11.0.0", "", { "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", "type-fest": "^4.6.0" } }, "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ=="],
|
|
@@ -697,8 +712,6 @@
|
|
|
697
712
|
|
|
698
713
|
"env-ci/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
|
|
699
714
|
|
|
700
|
-
"execa/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
|
|
701
|
-
|
|
702
715
|
"import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
|
703
716
|
|
|
704
717
|
"load-json-file/parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="],
|
|
@@ -1015,14 +1028,18 @@
|
|
|
1015
1028
|
|
|
1016
1029
|
"npm/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
|
1017
1030
|
|
|
1018
|
-
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
|
1019
|
-
|
|
1020
|
-
"npm-run-path/unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
|
|
1021
|
-
|
|
1022
1031
|
"parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="],
|
|
1023
1032
|
|
|
1024
1033
|
"read-pkg/parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="],
|
|
1025
1034
|
|
|
1035
|
+
"semantic-release/@semantic-release/error": ["@semantic-release/error@4.0.0", "", {}, "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ=="],
|
|
1036
|
+
|
|
1037
|
+
"semantic-release/aggregate-error": ["aggregate-error@5.0.0", "", { "dependencies": { "clean-stack": "^5.2.0", "indent-string": "^5.0.0" } }, "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw=="],
|
|
1038
|
+
|
|
1039
|
+
"semantic-release/execa": ["execa@9.6.1", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="],
|
|
1040
|
+
|
|
1041
|
+
"semantic-release/p-reduce": ["p-reduce@3.0.0", "", {}, "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q=="],
|
|
1042
|
+
|
|
1026
1043
|
"signale/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
|
|
1027
1044
|
|
|
1028
1045
|
"signale/figures": ["figures@2.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA=="],
|
|
@@ -1033,6 +1050,26 @@
|
|
|
1033
1050
|
|
|
1034
1051
|
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
|
1035
1052
|
|
|
1053
|
+
"@semantic-release/github/aggregate-error/clean-stack": ["clean-stack@5.3.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg=="],
|
|
1054
|
+
|
|
1055
|
+
"@semantic-release/github/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
|
|
1056
|
+
|
|
1057
|
+
"@semantic-release/npm/aggregate-error/clean-stack": ["clean-stack@5.3.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg=="],
|
|
1058
|
+
|
|
1059
|
+
"@semantic-release/npm/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
|
|
1060
|
+
|
|
1061
|
+
"@semantic-release/npm/execa/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
|
|
1062
|
+
|
|
1063
|
+
"@semantic-release/npm/execa/human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
|
|
1064
|
+
|
|
1065
|
+
"@semantic-release/npm/execa/is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="],
|
|
1066
|
+
|
|
1067
|
+
"@semantic-release/npm/execa/npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
|
|
1068
|
+
|
|
1069
|
+
"@semantic-release/npm/execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
|
1070
|
+
|
|
1071
|
+
"@semantic-release/npm/execa/strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="],
|
|
1072
|
+
|
|
1036
1073
|
"@semantic-release/release-notes-generator/read-package-up/read-pkg": ["read-pkg@9.0.1", "", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="],
|
|
1037
1074
|
|
|
1038
1075
|
"@semantic-release/release-notes-generator/read-package-up/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
|
@@ -1057,6 +1094,10 @@
|
|
|
1057
1094
|
|
|
1058
1095
|
"env-ci/execa/npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
|
|
1059
1096
|
|
|
1097
|
+
"env-ci/execa/onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="],
|
|
1098
|
+
|
|
1099
|
+
"env-ci/execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
|
1100
|
+
|
|
1060
1101
|
"env-ci/execa/strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
|
|
1061
1102
|
|
|
1062
1103
|
"npm/minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
|
@@ -1069,12 +1110,32 @@
|
|
|
1069
1110
|
|
|
1070
1111
|
"read-pkg/parse-json/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
|
1071
1112
|
|
|
1113
|
+
"semantic-release/aggregate-error/clean-stack": ["clean-stack@5.3.0", "", { "dependencies": { "escape-string-regexp": "5.0.0" } }, "sha512-9ngPTOhYGQqNVSfeJkYXHmF7AGWp4/nN5D/QqNQs3Dvxd1Kk/WpjHfNujKHYUQ/5CoGyOyFNoWSPk5afzP0QVg=="],
|
|
1114
|
+
|
|
1115
|
+
"semantic-release/aggregate-error/indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="],
|
|
1116
|
+
|
|
1117
|
+
"semantic-release/execa/get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="],
|
|
1118
|
+
|
|
1119
|
+
"semantic-release/execa/human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="],
|
|
1120
|
+
|
|
1121
|
+
"semantic-release/execa/is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="],
|
|
1122
|
+
|
|
1123
|
+
"semantic-release/execa/npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
|
|
1124
|
+
|
|
1125
|
+
"semantic-release/execa/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
|
1126
|
+
|
|
1127
|
+
"semantic-release/execa/strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="],
|
|
1128
|
+
|
|
1072
1129
|
"signale/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
|
1073
1130
|
|
|
1074
1131
|
"signale/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
|
1075
1132
|
|
|
1076
1133
|
"signale/figures/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
|
|
1077
1134
|
|
|
1135
|
+
"@semantic-release/npm/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
|
1136
|
+
|
|
1137
|
+
"@semantic-release/npm/execa/npm-run-path/unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
|
|
1138
|
+
|
|
1078
1139
|
"@semantic-release/release-notes-generator/read-package-up/read-pkg/normalize-package-data": ["normalize-package-data@6.0.2", "", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="],
|
|
1079
1140
|
|
|
1080
1141
|
"@semantic-release/release-notes-generator/read-package-up/read-pkg/parse-json": ["parse-json@8.3.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="],
|
|
@@ -1095,10 +1156,16 @@
|
|
|
1095
1156
|
|
|
1096
1157
|
"env-ci/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
|
1097
1158
|
|
|
1159
|
+
"env-ci/execa/onetime/mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="],
|
|
1160
|
+
|
|
1098
1161
|
"npm/minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
|
1099
1162
|
|
|
1100
1163
|
"npm/minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
|
1101
1164
|
|
|
1165
|
+
"semantic-release/execa/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
|
|
1166
|
+
|
|
1167
|
+
"semantic-release/execa/npm-run-path/unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
|
|
1168
|
+
|
|
1102
1169
|
"signale/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
|
1103
1170
|
|
|
1104
1171
|
"@semantic-release/release-notes-generator/read-package-up/read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="],
|
package/dist/index.d.mts
CHANGED
|
@@ -3,24 +3,47 @@ import { Octokit } from "octokit";
|
|
|
3
3
|
import { KeyvStoreAdapter, StoredData } from "keyv";
|
|
4
4
|
|
|
5
5
|
//#region src/index.d.ts
|
|
6
|
+
/** Minimal Map-like interface for SHA caching. */
|
|
7
|
+
interface ShaMap {
|
|
8
|
+
get(key: string): string | null | undefined;
|
|
9
|
+
set(key: string, value: string | null): void;
|
|
10
|
+
}
|
|
6
11
|
interface KeyvGithubOptions {
|
|
7
12
|
url: string;
|
|
8
13
|
branch?: string;
|
|
9
14
|
client?: Octokit | Octokit["rest"];
|
|
10
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Customize the commit message for single-key operations. value is null for deletes.
|
|
17
|
+
* @warning Consider adding `[skip ci]` to your commit messages to prevent
|
|
18
|
+
* triggering CI workflows on each key-value update.
|
|
19
|
+
*/
|
|
11
20
|
msg?: (key: string, value: string | null) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Customize the commit message for batch operations (setMany, deleteMany, clear).
|
|
23
|
+
* @param operation - 'set' | 'delete' | 'clear'
|
|
24
|
+
* @param paths - array of file paths being modified
|
|
25
|
+
* @warning Consider adding `[skip ci]` to your commit messages to prevent
|
|
26
|
+
* triggering CI workflows on each key-value update.
|
|
27
|
+
*/
|
|
28
|
+
batchMsg?: (operation: "set" | "delete" | "clear", paths: string[]) => string;
|
|
12
29
|
/** clear() deletes every file in the repo and is disabled by default. Set to true to allow it. */
|
|
13
30
|
enableClear?: boolean;
|
|
14
31
|
/** Path prefix prepended to every key (e.g. 'data/'). Defaults to ''. */
|
|
15
32
|
prefix?: string;
|
|
16
33
|
/** Path suffix appended to every key (e.g. '.json'). Defaults to ''. */
|
|
17
34
|
suffix?: string;
|
|
35
|
+
/** SHA cache map. Defaults to new Map(). Pass any keyv-like object with get/set. */
|
|
36
|
+
shaMap?: ShaMap;
|
|
18
37
|
}
|
|
19
38
|
/**
|
|
20
39
|
* Keyv storage adapter backed by a GitHub repository.
|
|
21
40
|
*
|
|
22
41
|
* Each key is a file path in the repo; the file content is the value.
|
|
23
42
|
* Example: new KeyvGithub("https://github.com/owner/repo/tree/main", { client })
|
|
43
|
+
*
|
|
44
|
+
* @warning **Keys are validated but NOT sanitized.** You must ensure keys are valid
|
|
45
|
+
* GitHub file paths before calling any method. Invalid keys throw an error.
|
|
46
|
+
* Requirements: non-empty, no leading/trailing `/`, no `//`, no `.`/`..` segments, no null bytes.
|
|
24
47
|
*/
|
|
25
48
|
declare class KeyvGithub extends EventEmitter implements KeyvStoreAdapter {
|
|
26
49
|
opts: KeyvGithubOptions;
|
|
@@ -32,9 +55,12 @@ declare class KeyvGithub extends EventEmitter implements KeyvStoreAdapter {
|
|
|
32
55
|
get branch(): string;
|
|
33
56
|
rest: Octokit["rest"];
|
|
34
57
|
private msg;
|
|
58
|
+
private batchMsg;
|
|
35
59
|
readonly enableClear: boolean;
|
|
36
60
|
readonly prefix: string;
|
|
37
61
|
readonly suffix: string;
|
|
62
|
+
/** SHA cache: key → sha (string), null (file doesn't exist), undefined (unknown). */
|
|
63
|
+
readonly shaMap: ShaMap;
|
|
38
64
|
constructor(url: string, options?: Omit<KeyvGithubOptions, "url">);
|
|
39
65
|
/** Converts a user key to the GitHub file path. */
|
|
40
66
|
private toPath;
|
|
@@ -69,4 +95,4 @@ declare class KeyvGithub extends EventEmitter implements KeyvStoreAdapter {
|
|
|
69
95
|
iterator<Value>(prefix?: string): AsyncGenerator<[string, Value | undefined]>;
|
|
70
96
|
}
|
|
71
97
|
//#endregion
|
|
72
|
-
export { KeyvGithubOptions, KeyvGithub as default };
|
|
98
|
+
export { KeyvGithubOptions, ShaMap, KeyvGithub as default };
|
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,10 @@ import { Octokit } from "octokit";
|
|
|
7
7
|
*
|
|
8
8
|
* Each key is a file path in the repo; the file content is the value.
|
|
9
9
|
* Example: new KeyvGithub("https://github.com/owner/repo/tree/main", { client })
|
|
10
|
+
*
|
|
11
|
+
* @warning **Keys are validated but NOT sanitized.** You must ensure keys are valid
|
|
12
|
+
* GitHub file paths before calling any method. Invalid keys throw an error.
|
|
13
|
+
* Requirements: non-empty, no leading/trailing `/`, no `//`, no `.`/`..` segments, no null bytes.
|
|
10
14
|
*/
|
|
11
15
|
var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
12
16
|
opts;
|
|
@@ -20,9 +24,12 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
20
24
|
}
|
|
21
25
|
rest;
|
|
22
26
|
msg;
|
|
27
|
+
batchMsg;
|
|
23
28
|
enableClear;
|
|
24
29
|
prefix;
|
|
25
30
|
suffix;
|
|
31
|
+
/** SHA cache: key → sha (string), null (file doesn't exist), undefined (unknown). */
|
|
32
|
+
shaMap;
|
|
26
33
|
constructor(url, options = {}) {
|
|
27
34
|
super();
|
|
28
35
|
const match = url.match(/(?:.*github\.com[/:])?([^/:]+)\/([^/]+?)(?:\.git)?(?:\/tree\/([^?#]+))?(?:[?#].*)?$/);
|
|
@@ -35,10 +42,16 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
35
42
|
...options
|
|
36
43
|
};
|
|
37
44
|
this.rest = options.client instanceof Octokit ? options.client.rest : options.client ?? new Octokit().rest;
|
|
38
|
-
this.msg = options.msg ?? ((key, value) => value === null ? `delete ${key}` : `update ${key}`);
|
|
45
|
+
this.msg = options.msg ?? ((key, value) => value === null ? `delete ${key} [skip ci]` : `update ${key} [skip ci]`);
|
|
46
|
+
this.batchMsg = options.batchMsg ?? ((op, paths) => {
|
|
47
|
+
const n = paths.length;
|
|
48
|
+
if (op === "clear") return `clear: remove ${n} files [skip ci]`;
|
|
49
|
+
return `batch ${op} ${n} files [skip ci]`;
|
|
50
|
+
});
|
|
39
51
|
this.enableClear = options.enableClear ?? false;
|
|
40
52
|
this.prefix = options.prefix ?? "";
|
|
41
53
|
this.suffix = options.suffix ?? "";
|
|
54
|
+
this.shaMap = options.shaMap ?? /* @__PURE__ */ new Map();
|
|
42
55
|
}
|
|
43
56
|
/** Converts a user key to the GitHub file path. */
|
|
44
57
|
toPath(key) {
|
|
@@ -65,39 +78,41 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
65
78
|
if (path.split("/").some((seg) => seg === ".." || seg === ".")) throw new Error(`Path must not contain '.' or '..' segments: ${path}`);
|
|
66
79
|
}
|
|
67
80
|
async get(key) {
|
|
68
|
-
this.
|
|
81
|
+
const path = this.toPath(key);
|
|
82
|
+
this.validatePath(path);
|
|
69
83
|
try {
|
|
70
84
|
const { data } = await this.rest.repos.getContent({
|
|
71
85
|
owner: this.owner,
|
|
72
86
|
repo: this.repo,
|
|
73
|
-
path
|
|
87
|
+
path,
|
|
74
88
|
ref: this.ref
|
|
75
89
|
});
|
|
76
|
-
if (Array.isArray(data) || data.type !== "file")
|
|
90
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
91
|
+
this.shaMap.set(path, null);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.shaMap.set(path, data.sha);
|
|
77
95
|
return Buffer.from(data.content, "base64").toString("utf-8");
|
|
78
96
|
} catch (e) {
|
|
79
|
-
if (KeyvGithub.isHttpError(e) && e.status === 404)
|
|
97
|
+
if (KeyvGithub.isHttpError(e) && e.status === 404) {
|
|
98
|
+
this.shaMap.set(path, null);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
80
101
|
throw e;
|
|
81
102
|
}
|
|
82
103
|
}
|
|
83
104
|
async set(key, value, ttl) {
|
|
84
105
|
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
106
|
if (typeof value !== "string") throw new Error("keyv-github only supports string values natively. Use new Keyv(store) which serializes values automatically.");
|
|
86
|
-
this.validatePath(this.toPath(key));
|
|
87
107
|
const path = this.toPath(key);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
path,
|
|
94
|
-
ref: this.ref
|
|
95
|
-
});
|
|
96
|
-
if (!Array.isArray(data) && data.type === "file") sha = data.sha;
|
|
97
|
-
} catch (e) {
|
|
98
|
-
if (!KeyvGithub.isHttpError(e) || e.status !== 404) throw e;
|
|
108
|
+
this.validatePath(path);
|
|
109
|
+
let cachedSha = this.shaMap.get(path);
|
|
110
|
+
if (cachedSha === void 0) {
|
|
111
|
+
await this.get(key);
|
|
112
|
+
cachedSha = this.shaMap.get(path);
|
|
99
113
|
}
|
|
100
|
-
|
|
114
|
+
const sha = cachedSha ?? void 0;
|
|
115
|
+
const { data } = await this.rest.repos.createOrUpdateFileContents({
|
|
101
116
|
owner: this.owner,
|
|
102
117
|
repo: this.repo,
|
|
103
118
|
path,
|
|
@@ -106,44 +121,58 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
106
121
|
sha,
|
|
107
122
|
branch: this.ref
|
|
108
123
|
});
|
|
124
|
+
this.shaMap.set(path, data.content?.sha ?? null);
|
|
109
125
|
}
|
|
110
126
|
async delete(key) {
|
|
111
|
-
this.validatePath(this.toPath(key));
|
|
112
127
|
const path = this.toPath(key);
|
|
128
|
+
this.validatePath(path);
|
|
129
|
+
let cachedSha = this.shaMap.get(path);
|
|
130
|
+
if (cachedSha === void 0) {
|
|
131
|
+
await this.get(key);
|
|
132
|
+
cachedSha = this.shaMap.get(path);
|
|
133
|
+
}
|
|
134
|
+
if (!cachedSha) return false;
|
|
135
|
+
const sha = cachedSha;
|
|
113
136
|
try {
|
|
114
|
-
const { data } = await this.rest.repos.getContent({
|
|
115
|
-
owner: this.owner,
|
|
116
|
-
repo: this.repo,
|
|
117
|
-
path,
|
|
118
|
-
ref: this.ref
|
|
119
|
-
});
|
|
120
|
-
if (Array.isArray(data) || data.type !== "file") return false;
|
|
121
137
|
await this.rest.repos.deleteFile({
|
|
122
138
|
owner: this.owner,
|
|
123
139
|
repo: this.repo,
|
|
124
140
|
path,
|
|
125
141
|
message: this.msg(path, null),
|
|
126
|
-
sha
|
|
142
|
+
sha,
|
|
127
143
|
branch: this.ref
|
|
128
144
|
});
|
|
145
|
+
this.shaMap.set(path, null);
|
|
129
146
|
return true;
|
|
130
147
|
} catch (e) {
|
|
131
|
-
if (KeyvGithub.isHttpError(e) && e.status === 404)
|
|
148
|
+
if (KeyvGithub.isHttpError(e) && e.status === 404) {
|
|
149
|
+
this.shaMap.set(path, null);
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
132
152
|
throw e;
|
|
133
153
|
}
|
|
134
154
|
}
|
|
135
155
|
async has(key) {
|
|
136
|
-
this.
|
|
156
|
+
const path = this.toPath(key);
|
|
157
|
+
this.validatePath(path);
|
|
137
158
|
try {
|
|
138
159
|
const { data } = await this.rest.repos.getContent({
|
|
139
160
|
owner: this.owner,
|
|
140
161
|
repo: this.repo,
|
|
141
|
-
path
|
|
162
|
+
path,
|
|
142
163
|
ref: this.ref
|
|
143
164
|
});
|
|
144
|
-
|
|
165
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
166
|
+
this.shaMap.set(path, null);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
this.shaMap.set(path, data.sha);
|
|
170
|
+
return true;
|
|
145
171
|
} catch (e) {
|
|
146
|
-
if (KeyvGithub.isHttpError(e) && e.status === 404)
|
|
172
|
+
if (KeyvGithub.isHttpError(e) && e.status === 404) {
|
|
173
|
+
this.shaMap.set(path, null);
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
147
176
|
throw e;
|
|
148
177
|
}
|
|
149
178
|
}
|
|
@@ -204,7 +233,8 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
204
233
|
this.validatePath(this.toPath(key));
|
|
205
234
|
}
|
|
206
235
|
const entries = values.map(({ key, value }) => [this.toPath(key), String(value)]);
|
|
207
|
-
const
|
|
236
|
+
const paths = entries.map(([p]) => p);
|
|
237
|
+
const message = entries.length === 1 ? this.msg(entries[0][0], entries[0][1]) : this.batchMsg("set", paths);
|
|
208
238
|
await this._batchCommit({
|
|
209
239
|
set: entries,
|
|
210
240
|
message
|
|
@@ -231,7 +261,7 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
231
261
|
const existingPaths = new Set(treeData.tree.filter((i) => i.type === "blob" && i.path).map((i) => i.path));
|
|
232
262
|
const toDelete = keys.map((k) => this.toPath(k)).filter((p) => existingPaths.has(p));
|
|
233
263
|
if (toDelete.length === 0) return false;
|
|
234
|
-
const message = toDelete.length === 1 ? this.msg(toDelete[0], null) :
|
|
264
|
+
const message = toDelete.length === 1 ? this.msg(toDelete[0], null) : this.batchMsg("delete", toDelete);
|
|
235
265
|
await this._batchCommit({
|
|
236
266
|
delete: toDelete,
|
|
237
267
|
message
|
|
@@ -254,7 +284,7 @@ var KeyvGithub = class KeyvGithub extends EventEmitter {
|
|
|
254
284
|
const allPaths = treeData.tree.filter((i) => i.type === "blob" && i.path && i.path.startsWith(this.prefix) && i.path.endsWith(this.suffix)).map((i) => i.path);
|
|
255
285
|
if (allPaths.length > 0) await this._batchCommit({
|
|
256
286
|
delete: allPaths,
|
|
257
|
-
message:
|
|
287
|
+
message: this.batchMsg("clear", allPaths)
|
|
258
288
|
});
|
|
259
289
|
}
|
|
260
290
|
async *iterator(prefix) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keyv-github",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"module": "src/index.ts",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.mts",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"octokit": "^5.0.5"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
+
"@semantic-release/git": "^10.0.1",
|
|
23
24
|
"@types/bun": "latest",
|
|
24
25
|
"semantic-release": "^25.0.3",
|
|
25
26
|
"tsdown": "^0.20.3",
|
package/src/index.test.ts
CHANGED
|
@@ -386,7 +386,7 @@ describe("setMany", () => {
|
|
|
386
386
|
expect(mockFiles.get("b/2.txt")?.content).toBe("world");
|
|
387
387
|
expect(mockFiles.get("c/3.txt")?.content).toBe("!");
|
|
388
388
|
expect(messages).toHaveLength(1); // single commit
|
|
389
|
-
expect(messages[0]).toBe("batch
|
|
389
|
+
expect(messages[0]).toBe("batch set 3 files [skip ci]");
|
|
390
390
|
});
|
|
391
391
|
|
|
392
392
|
test("uses msg hook for single-entry batch", async () => {
|
|
@@ -440,7 +440,7 @@ describe("deleteMany", () => {
|
|
|
440
440
|
expect(mockFiles.has("b")).toBe(false);
|
|
441
441
|
expect(mockFiles.has("c")).toBe(true);
|
|
442
442
|
expect(messages).toHaveLength(1); // single commit
|
|
443
|
-
expect(messages[0]).toBe("batch delete 2 files");
|
|
443
|
+
expect(messages[0]).toBe("batch delete 2 files [skip ci]");
|
|
444
444
|
});
|
|
445
445
|
|
|
446
446
|
test("returns false when no keys exist", async () => {
|
|
@@ -527,15 +527,15 @@ describe("msg hook", () => {
|
|
|
527
527
|
expect(messages[messages.length - 1]).toBe("chore: rm to/remove");
|
|
528
528
|
});
|
|
529
529
|
|
|
530
|
-
test("default msg falls back to 'update <key>' / 'delete <key>'", async () => {
|
|
530
|
+
test("default msg falls back to 'update <key> [skip ci]' / 'delete <key> [skip ci]'", async () => {
|
|
531
531
|
const { store, messages } = makeStore();
|
|
532
532
|
await store.set("k", "v");
|
|
533
|
-
expect(messages[messages.length - 1]).toBe("update k");
|
|
533
|
+
expect(messages[messages.length - 1]).toBe("update k [skip ci]");
|
|
534
534
|
|
|
535
535
|
const files2 = new Map([["k2", { content: "v", sha: "s1" }]]);
|
|
536
536
|
const { store: store2, messages: messages2 } = makeStore(files2);
|
|
537
537
|
await store2.delete("k2");
|
|
538
|
-
expect(messages2[messages2.length - 1]).toBe("delete k2");
|
|
538
|
+
expect(messages2[messages2.length - 1]).toBe("delete k2 [skip ci]");
|
|
539
539
|
});
|
|
540
540
|
});
|
|
541
541
|
|
package/src/index.ts
CHANGED
|
@@ -2,18 +2,38 @@ import { EventEmitter } from "events";
|
|
|
2
2
|
import type { KeyvStoreAdapter, StoredData } from "keyv";
|
|
3
3
|
import { Octokit } from "octokit";
|
|
4
4
|
|
|
5
|
+
/** Minimal Map-like interface for SHA caching. */
|
|
6
|
+
export interface ShaMap {
|
|
7
|
+
get(key: string): string | null | undefined;
|
|
8
|
+
set(key: string, value: string | null): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
export interface KeyvGithubOptions {
|
|
6
12
|
url: string;
|
|
7
13
|
branch?: string;
|
|
8
14
|
client?: Octokit | Octokit["rest"];
|
|
9
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Customize the commit message for single-key operations. value is null for deletes.
|
|
17
|
+
* @warning Consider adding `[skip ci]` to your commit messages to prevent
|
|
18
|
+
* triggering CI workflows on each key-value update.
|
|
19
|
+
*/
|
|
10
20
|
msg?: (key: string, value: string | null) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Customize the commit message for batch operations (setMany, deleteMany, clear).
|
|
23
|
+
* @param operation - 'set' | 'delete' | 'clear'
|
|
24
|
+
* @param paths - array of file paths being modified
|
|
25
|
+
* @warning Consider adding `[skip ci]` to your commit messages to prevent
|
|
26
|
+
* triggering CI workflows on each key-value update.
|
|
27
|
+
*/
|
|
28
|
+
batchMsg?: (operation: "set" | "delete" | "clear", paths: string[]) => string;
|
|
11
29
|
/** clear() deletes every file in the repo and is disabled by default. Set to true to allow it. */
|
|
12
30
|
enableClear?: boolean;
|
|
13
31
|
/** Path prefix prepended to every key (e.g. 'data/'). Defaults to ''. */
|
|
14
32
|
prefix?: string;
|
|
15
33
|
/** Path suffix appended to every key (e.g. '.json'). Defaults to ''. */
|
|
16
34
|
suffix?: string;
|
|
35
|
+
/** SHA cache map. Defaults to new Map(). Pass any keyv-like object with get/set. */
|
|
36
|
+
shaMap?: ShaMap;
|
|
17
37
|
}
|
|
18
38
|
|
|
19
39
|
/**
|
|
@@ -21,6 +41,10 @@ export interface KeyvGithubOptions {
|
|
|
21
41
|
*
|
|
22
42
|
* Each key is a file path in the repo; the file content is the value.
|
|
23
43
|
* Example: new KeyvGithub("https://github.com/owner/repo/tree/main", { client })
|
|
44
|
+
*
|
|
45
|
+
* @warning **Keys are validated but NOT sanitized.** You must ensure keys are valid
|
|
46
|
+
* GitHub file paths before calling any method. Invalid keys throw an error.
|
|
47
|
+
* Requirements: non-empty, no leading/trailing `/`, no `//`, no `.`/`..` segments, no null bytes.
|
|
24
48
|
*/
|
|
25
49
|
export default class KeyvGithub
|
|
26
50
|
extends EventEmitter
|
|
@@ -38,9 +62,15 @@ export default class KeyvGithub
|
|
|
38
62
|
}
|
|
39
63
|
rest: Octokit["rest"];
|
|
40
64
|
private msg: (key: string, value: string | null) => string;
|
|
65
|
+
private batchMsg: (
|
|
66
|
+
operation: "set" | "delete" | "clear",
|
|
67
|
+
paths: string[],
|
|
68
|
+
) => string;
|
|
41
69
|
readonly enableClear: boolean;
|
|
42
70
|
readonly prefix: string;
|
|
43
71
|
readonly suffix: string;
|
|
72
|
+
/** SHA cache: key → sha (string), null (file doesn't exist), undefined (unknown). */
|
|
73
|
+
readonly shaMap: ShaMap;
|
|
44
74
|
|
|
45
75
|
constructor(url: string, options: Omit<KeyvGithubOptions, "url"> = {}) {
|
|
46
76
|
super();
|
|
@@ -60,10 +90,19 @@ export default class KeyvGithub
|
|
|
60
90
|
: (options.client ?? new Octokit().rest);
|
|
61
91
|
this.msg =
|
|
62
92
|
options.msg ??
|
|
63
|
-
((key, value) =>
|
|
93
|
+
((key, value) =>
|
|
94
|
+
value === null ? `delete ${key} [skip ci]` : `update ${key} [skip ci]`);
|
|
95
|
+
this.batchMsg =
|
|
96
|
+
options.batchMsg ??
|
|
97
|
+
((op, paths) => {
|
|
98
|
+
const n = paths.length;
|
|
99
|
+
if (op === "clear") return `clear: remove ${n} files [skip ci]`;
|
|
100
|
+
return `batch ${op} ${n} files [skip ci]`;
|
|
101
|
+
});
|
|
64
102
|
this.enableClear = options.enableClear ?? false;
|
|
65
103
|
this.prefix = options.prefix ?? "";
|
|
66
104
|
this.suffix = options.suffix ?? "";
|
|
105
|
+
this.shaMap = options.shaMap ?? new Map<string, string | null>();
|
|
67
106
|
}
|
|
68
107
|
|
|
69
108
|
/** Converts a user key to the GitHub file path. */
|
|
@@ -106,20 +145,28 @@ export default class KeyvGithub
|
|
|
106
145
|
}
|
|
107
146
|
|
|
108
147
|
async get<Value>(key: string): Promise<StoredData<Value> | undefined> {
|
|
109
|
-
this.
|
|
148
|
+
const path = this.toPath(key);
|
|
149
|
+
this.validatePath(path);
|
|
110
150
|
try {
|
|
111
151
|
const { data } = await this.rest.repos.getContent({
|
|
112
152
|
owner: this.owner,
|
|
113
153
|
repo: this.repo,
|
|
114
|
-
path
|
|
154
|
+
path,
|
|
115
155
|
ref: this.ref,
|
|
116
156
|
});
|
|
117
|
-
if (Array.isArray(data) || data.type !== "file")
|
|
157
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
158
|
+
this.shaMap.set(path, null);
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
this.shaMap.set(path, data.sha);
|
|
118
162
|
return Buffer.from(data.content, "base64").toString(
|
|
119
163
|
"utf-8",
|
|
120
164
|
) as StoredData<Value>;
|
|
121
165
|
} catch (e: unknown) {
|
|
122
|
-
if (KeyvGithub.isHttpError(e) && e.status === 404)
|
|
166
|
+
if (KeyvGithub.isHttpError(e) && e.status === 404) {
|
|
167
|
+
this.shaMap.set(path, null);
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
123
170
|
throw e;
|
|
124
171
|
}
|
|
125
172
|
}
|
|
@@ -137,22 +184,19 @@ export default class KeyvGithub
|
|
|
137
184
|
"Use new Keyv(store) which serializes values automatically.",
|
|
138
185
|
);
|
|
139
186
|
}
|
|
140
|
-
this.validatePath(this.toPath(key));
|
|
141
187
|
const path = this.toPath(key);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
});
|
|
150
|
-
if (!Array.isArray(data) && data.type === "file") sha = data.sha;
|
|
151
|
-
} catch (e: unknown) {
|
|
152
|
-
if (!KeyvGithub.isHttpError(e) || e.status !== 404) throw e;
|
|
188
|
+
this.validatePath(path);
|
|
189
|
+
|
|
190
|
+
// Check shaMap first; if unknown (undefined), fetch to populate it
|
|
191
|
+
let cachedSha = this.shaMap.get(path);
|
|
192
|
+
if (cachedSha === undefined) {
|
|
193
|
+
await this.get(key); // populates shaMap
|
|
194
|
+
cachedSha = this.shaMap.get(path);
|
|
153
195
|
}
|
|
196
|
+
// cachedSha is now string (existing file) or null (doesn't exist)
|
|
197
|
+
const sha = cachedSha ?? undefined;
|
|
154
198
|
|
|
155
|
-
await this.rest.repos.createOrUpdateFileContents({
|
|
199
|
+
const { data } = await this.rest.repos.createOrUpdateFileContents({
|
|
156
200
|
owner: this.owner,
|
|
157
201
|
repo: this.repo,
|
|
158
202
|
path,
|
|
@@ -161,46 +205,65 @@ export default class KeyvGithub
|
|
|
161
205
|
sha,
|
|
162
206
|
branch: this.ref,
|
|
163
207
|
});
|
|
208
|
+
// Update shaMap with new sha from response
|
|
209
|
+
this.shaMap.set(path, data.content?.sha ?? null);
|
|
164
210
|
}
|
|
165
211
|
|
|
166
212
|
async delete(key: string): Promise<boolean> {
|
|
167
|
-
this.validatePath(this.toPath(key));
|
|
168
213
|
const path = this.toPath(key);
|
|
214
|
+
this.validatePath(path);
|
|
215
|
+
|
|
216
|
+
// Check shaMap first; if unknown (undefined), fetch to populate it
|
|
217
|
+
let cachedSha = this.shaMap.get(path);
|
|
218
|
+
if (cachedSha === undefined) {
|
|
219
|
+
await this.get(key); // populates shaMap
|
|
220
|
+
cachedSha = this.shaMap.get(path);
|
|
221
|
+
}
|
|
222
|
+
// If null or still undefined, file doesn't exist
|
|
223
|
+
if (!cachedSha) return false;
|
|
224
|
+
|
|
225
|
+
const sha = cachedSha; // narrow to string for TypeScript
|
|
169
226
|
try {
|
|
170
|
-
const { data } = await this.rest.repos.getContent({
|
|
171
|
-
owner: this.owner,
|
|
172
|
-
repo: this.repo,
|
|
173
|
-
path,
|
|
174
|
-
ref: this.ref,
|
|
175
|
-
});
|
|
176
|
-
if (Array.isArray(data) || data.type !== "file") return false;
|
|
177
227
|
await this.rest.repos.deleteFile({
|
|
178
228
|
owner: this.owner,
|
|
179
229
|
repo: this.repo,
|
|
180
230
|
path,
|
|
181
231
|
message: this.msg(path, null),
|
|
182
|
-
sha
|
|
232
|
+
sha,
|
|
183
233
|
branch: this.ref,
|
|
184
234
|
});
|
|
235
|
+
this.shaMap.set(path, null);
|
|
185
236
|
return true;
|
|
186
237
|
} catch (e: unknown) {
|
|
187
|
-
if (KeyvGithub.isHttpError(e) && e.status === 404)
|
|
238
|
+
if (KeyvGithub.isHttpError(e) && e.status === 404) {
|
|
239
|
+
this.shaMap.set(path, null);
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
188
242
|
throw e;
|
|
189
243
|
}
|
|
190
244
|
}
|
|
191
245
|
|
|
192
246
|
async has(key: string): Promise<boolean> {
|
|
193
|
-
this.
|
|
247
|
+
const path = this.toPath(key);
|
|
248
|
+
this.validatePath(path);
|
|
194
249
|
try {
|
|
195
250
|
const { data } = await this.rest.repos.getContent({
|
|
196
251
|
owner: this.owner,
|
|
197
252
|
repo: this.repo,
|
|
198
|
-
path
|
|
253
|
+
path,
|
|
199
254
|
ref: this.ref,
|
|
200
255
|
});
|
|
201
|
-
|
|
256
|
+
if (Array.isArray(data) || data.type !== "file") {
|
|
257
|
+
this.shaMap.set(path, null);
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
this.shaMap.set(path, data.sha);
|
|
261
|
+
return true;
|
|
202
262
|
} catch (e: unknown) {
|
|
203
|
-
if (KeyvGithub.isHttpError(e) && e.status === 404)
|
|
263
|
+
if (KeyvGithub.isHttpError(e) && e.status === 404) {
|
|
264
|
+
this.shaMap.set(path, null);
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
204
267
|
throw e;
|
|
205
268
|
}
|
|
206
269
|
}
|
|
@@ -284,10 +347,11 @@ export default class KeyvGithub
|
|
|
284
347
|
this.toPath(key),
|
|
285
348
|
String(value),
|
|
286
349
|
]);
|
|
350
|
+
const paths = entries.map(([p]) => p);
|
|
287
351
|
const message =
|
|
288
352
|
entries.length === 1
|
|
289
353
|
? this.msg(entries[0]![0], entries[0]![1])
|
|
290
|
-
:
|
|
354
|
+
: this.batchMsg("set", paths);
|
|
291
355
|
await this._batchCommit({ set: entries, message });
|
|
292
356
|
}
|
|
293
357
|
|
|
@@ -326,7 +390,7 @@ export default class KeyvGithub
|
|
|
326
390
|
const message =
|
|
327
391
|
toDelete.length === 1
|
|
328
392
|
? this.msg(toDelete[0]!, null)
|
|
329
|
-
:
|
|
393
|
+
: this.batchMsg("delete", toDelete);
|
|
330
394
|
await this._batchCommit({ delete: toDelete, message });
|
|
331
395
|
return true;
|
|
332
396
|
}
|
|
@@ -362,7 +426,7 @@ export default class KeyvGithub
|
|
|
362
426
|
if (allPaths.length > 0) {
|
|
363
427
|
await this._batchCommit({
|
|
364
428
|
delete: allPaths,
|
|
365
|
-
message:
|
|
429
|
+
message: this.batchMsg("clear", allPaths),
|
|
366
430
|
});
|
|
367
431
|
}
|
|
368
432
|
}
|