Skip to content

Commit 02a38b4

Browse files
committed
init
0 parents  commit 02a38b4

19 files changed

+5979
-0
lines changed

.eslintignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
coverage
3+
dist

.eslintrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": ["eslint-config-unjs"],
3+
"rules": {
4+
"unicorn/no-null": "off"
5+
}
6+
}

.github/workflows/autofix.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: autofix.ci # needed to securely identify the workflow
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: ["main"]
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
autofix:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
- run: corepack enable
17+
- uses: actions/setup-node@v3
18+
with:
19+
node-version: 18
20+
cache: "pnpm"
21+
- run: pnpm install
22+
- name: Fix lint issues
23+
run: pnpm run lint:fix
24+
- uses: autofix-ci/action@8caa572fd27b0019a65e4c695447089c8d3138b9
25+
with:
26+
commit-message: "chore: apply automated fixes"

.github/workflows/ci.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
ci:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v3
16+
- run: corepack enable
17+
- uses: actions/setup-node@v3
18+
with:
19+
node-version: 18
20+
cache: "pnpm"
21+
- run: pnpm install
22+
- run: pnpm lint
23+
- run: pnpm test:types
24+
- run: pnpm build
25+
- run: pnpm vitest --coverage
26+
- uses: codecov/codecov-action@v3

.gitignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
node_modules
2+
coverage
3+
dist
4+
types
5+
.vscode
6+
.DS_Store
7+
.eslintcache
8+
*.log*
9+
*.conf*
10+
*.env*
11+
12+
test/tmp

.prettierrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# 🗑️ cachecan
2+
3+
[![npm version][npm-version-src]][npm-version-href]
4+
[![Codecov][codecov-src]][codecov-href]
5+
6+
Like a trashcan, but for your cache.
7+
8+
Wrap functions to cache results. Supports [_any storage_](#storage), such as Redis, MongoDB, Cloudflare KV, localStorage, and even your file system.
9+
10+
```bash
11+
npm i cachecan
12+
# or
13+
pnpm i cachecan
14+
```
15+
16+
```tsx
17+
import { createCache } from 'cachecan'
18+
const [cache] = createCache({
19+
storage,
20+
})
21+
22+
// Usage
23+
const cacheGetData = cache(getData, { key: "data" })
24+
const data = await cacheGetData()
25+
26+
const cacheGetData = cache(
27+
async () => { ... },
28+
{ key: "data", maxAge: 60, }
29+
)
30+
const data = await cacheGetOtherData()
31+
```
32+
33+
## Batteries not included
34+
35+
`cachecan` is a [tiny](https://bundlephobia.com/package/cachecan) cache wrapper. It does not actually include a cache.
36+
37+
### The batteries included setup
38+
39+
If you want to get started quickly. You should read on to learn how to customize your cache first.
40+
41+
```bash
42+
npm i cachecan seroval unstorage
43+
# or
44+
pnpm i cachecan seroval unstorage
45+
```
46+
47+
```tsx
48+
import { createCache } from "cachecan";
49+
import { deserialize, serialize } from "seroval";
50+
import { createStorage } from "unstorage";
51+
import fsDriver from "unstorage/drivers/fs";
52+
53+
const storage = createStorage({
54+
driver: fsDriver({ base: "./tmp" }),
55+
});
56+
57+
const [cache] = createCache({
58+
storage,
59+
serialize,
60+
deserialize,
61+
defaults: {
62+
maxAge: 60,
63+
},
64+
});
65+
```
66+
67+
### Storage
68+
69+
The cache storage is powered by [`unstorage`](https://unstorage.unjs.io), which allows you to use any of their drivers.
70+
71+
File system storage is useful for dev environments, easily transition to a hosted storage when moving to production.
72+
73+
```tsx
74+
import { Storage, createStorage } from "unstorage";
75+
import cloudflareKVHTTPDriver from "unstorage/drivers/cloudflare-kv-http";
76+
import fsDriver from "unstorage/drivers/fs";
77+
78+
const isProduction = process.env.NODE_ENV === "production";
79+
80+
const storage = createStorage({
81+
driver: isProduction
82+
? cloudflareKVHTTPDriver({
83+
accountId: "my-account-id",
84+
namespaceId: "my-kv-namespace-id",
85+
apiToken: "supersecret-api-token",
86+
})
87+
: fsDriver({ base: "./tmp" }),
88+
});
89+
```
90+
91+
### Serializers
92+
93+
To keep library small it does not ship with any serializers, defaulting to `JSON.stringify` and `JSON.parse`. This is not sufficient for all use cases, so you can provide your own serializer.
94+
95+
I use [`seroval`](https://github.com/lxsmnsyc/seroval), here's a [list of more serializers](https://github.com/lxsmnsyc/seroval/tree/main/benchmark#libraries).
96+
97+
```tsx
98+
import { deserialize, serialize } from "seroval";
99+
100+
const [cache] = createCache({
101+
storage,
102+
serialize,
103+
deserialize,
104+
});
105+
```
106+
107+
## Usage
108+
109+
### Purging the cache
110+
111+
The created cache has a `purge` method that can be used to clear the cache storage.
112+
113+
```tsx
114+
import { createCache } from "cachecan";
115+
116+
const [cache, { purge }] = createCache({
117+
storage,
118+
});
119+
await purge("users");
120+
await purge(["user", 1]);
121+
// Purge all cached items
122+
await purge();
123+
```
124+
125+
### Populating the cache
126+
127+
The created cache has a `store` method that can be used to populate the cache storage. Useful to hydrate the cache with pre-existing data.
128+
129+
```tsx
130+
const users = [
131+
{
132+
hello: "populated",
133+
},
134+
];
135+
136+
const [cache, { store }] = createCache();
137+
138+
await store(
139+
// Key
140+
"users",
141+
// Value
142+
users,
143+
{
144+
// Optional, override cache default maxAge
145+
// 60 seconds
146+
maxAge: 60,
147+
},
148+
);
149+
```
150+
151+
## License
152+
153+
Published under [MIT License](./LICENSE).
154+
155+
<!-- Badges -->
156+
157+
[npm-version-src]: https://img.shields.io/npm/v/cachecan?style=flat&colorA=18181B&colorB=F0DB4F
158+
[npm-version-href]: https://npmjs.com/package/cachecan
159+
[codecov-src]: https://img.shields.io/codecov/c/gh/ryoid/cachecan/main?style=flat&colorA=18181B&colorB=F0DB4F
160+
[codecov-href]: https://codecov.io/gh/ryoid/cachecan

package.json

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"name": "cachecan",
3+
"version": "0.0.0",
4+
"description": "Wrap your functions to cache their results. Supports any storage, such as Redis, MongoDB, Vercel KV, Cloudflare KV, localStorage, and even your file system.",
5+
"repository": "ryoid/cachecan",
6+
"homepage": "https://github.com/ryoid/cachecan",
7+
"bugs": {
8+
"url": "https://github.com/ryoid/cachecan/issues"
9+
},
10+
"license": "MIT",
11+
"sideEffects": false,
12+
"type": "module",
13+
"main": "./dist/index.cjs",
14+
"module": "./dist/index.mjs",
15+
"types": "./dist/index.d.ts",
16+
"exports": {
17+
".": {
18+
"require": {
19+
"types": "./dist/index.d.cts",
20+
"default": "./dist/index.cjs"
21+
},
22+
"import": {
23+
"types": "./dist/index.d.mts",
24+
"default": "./dist/index.mjs"
25+
}
26+
}
27+
},
28+
"files": [
29+
"dist"
30+
],
31+
"scripts": {
32+
"build": "unbuild",
33+
"dev": "vitest dev",
34+
"play": "jiti playground",
35+
"lint": "eslint --cache --ext .ts,.js,.mjs,.cjs . && prettier -c src test",
36+
"lint:fix": "eslint --cache --ext .ts,.js,.mjs,.cjs . --fix && prettier -c src test -w",
37+
"prepack": "pnpm run build",
38+
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
39+
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
40+
"test:types": "tsc --noEmit --skipLibCheck"
41+
},
42+
"peerDependencies": {
43+
"unstorage": "^1.10.1"
44+
},
45+
"devDependencies": {
46+
"@types/node": "^20.11.0",
47+
"@vitest/coverage-v8": "^1.2.0",
48+
"changelogen": "^0.5.5",
49+
"eslint": "^8.56.0",
50+
"eslint-config-unjs": "^0.2.1",
51+
"jiti": "^1.21.0",
52+
"prettier": "^3.2.1",
53+
"seroval": "^1.0.4",
54+
"typescript": "^5.3.3",
55+
"unbuild": "^2.0.0",
56+
"unstorage": "^1.10.1",
57+
"vitest": "^1.2.0"
58+
},
59+
"engines": {
60+
"node": ">=18"
61+
},
62+
"packageManager": "pnpm@8.6.12"
63+
}

playground/index.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* v8 ignore start */
2+
/* eslint-disable @typescript-eslint/no-unused-vars */
3+
import { deserialize, serialize } from "seroval";
4+
import { createStorage } from "unstorage";
5+
import fsDriver from "unstorage/drivers/fs";
6+
import { CacheItem, createCache, resolveKey } from "../src";
7+
8+
const storage = createStorage({
9+
driver: fsDriver({ base: "./tmp" }),
10+
});
11+
12+
const users = [];
13+
14+
storage.setItem(resolveKey("users"), {
15+
value: users,
16+
expires: Date.now() + 60 * 1000,
17+
} satisfies CacheItem);
18+
19+
const [cache, { purge }] = createCache({
20+
storage,
21+
serialize,
22+
deserialize,
23+
defaults: {
24+
maxAge: 60 * 60 * 24,
25+
},
26+
});
27+
/* v8 ignore stop */

0 commit comments

Comments
 (0)