Skip to content

Commit c2d99a5

Browse files
committed
feat : add support for browser
1 parent ec8c77b commit c2d99a5

File tree

11 files changed

+360
-26
lines changed

11 files changed

+360
-26
lines changed

README.md

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# kv-storage
22
Create data storage that uses a simple key-value method for Node, Browser, Deno, Bun, Cloudflare Workers
33

4+
[![NPM](https://nodei.co/npm/kv-storage.png?mini=true)](https://www.npmjs.com/package/kv-storage)
5+
[![npm version](https://badge.fury.io/js/kv-storage.svg)](https://www.npmjs.com/package/kv-storage)
46
## Features
57

68
* ✅ 0 Dependencies
@@ -12,7 +14,6 @@ Create data storage that uses a simple key-value method for Node, Browser, Deno,
1214
[https://codesandbox.io/p/devbox/simple-kv-storage-pzr9ld](https://codesandbox.io/p/devbox/simple-kv-storage-pzr9ld)
1315

1416
## Installation
15-
1617
```javascript
1718
npm install kv-storage
1819
```
@@ -23,14 +24,14 @@ npm install kv-storage
2324
//Node CommonJS import style
2425
const {KVStorage} = require('kv-storage')
2526

26-
//Node ES Modules import style
27+
//Node & Browser ES Modules import style
2728
import {KVStorage} from 'kv-storage'
2829

2930
//Deno import style
3031
import {KVStorage} from 'npm:kv-storage'
3132

3233
const db = await KVStorage({
33-
runtime:'node', //node | deno
34+
runtime:'node', //node | deno | browser
3435
storageName:'storage'
3536
})
3637
```
@@ -91,6 +92,26 @@ void async function main() {
9192
}()
9293
```
9394

95+
```javascript
96+
<script type="module">
97+
//Directly in Browser example
98+
import {KVStorage} from 'https://cdn.jsdelivr.net/npm/kv-storage@0.0.3/dist/mjs/kv-storage.js'
99+
100+
void async function main() {
101+
const db = await KVStorage({
102+
runtime:'browser',
103+
storageName:'storage'
104+
})
105+
106+
console.log(await db.put('key','value'))
107+
console.log(await db.get('key'))
108+
console.log(await db.list())
109+
console.log(await db.delete('key'))
110+
console.log(await db.has('key'))
111+
}()
112+
</script>
113+
```
114+
94115
## API Reference
95116

96117
### Documentation
@@ -112,7 +133,7 @@ storageName = Alphanumeric name of storage
112133
Supported runtime :
113134
- [x] `node`
114135
- [x] `deno` need `--allow-read --allow-write`
115-
- [ ] `browser`
136+
- [x] `browser`
116137
- [ ] `bun`
117138
- [ ] `cloudflare-workers`
118139
- [ ] `memory`
@@ -121,13 +142,13 @@ Supported runtime :
121142
```javascript
122143
await put(key:string,value:string)
123144
```
124-
The put() method returns a Promise that you should await on to verify a successful update
145+
The put() method returns a Promise that you should await on to verify a successful update, resolve to `true` or `false`
125146
### Read key-value pairs
126147

127148
```javascript
128149
await get(key:string)
129150
```
130-
The get() method returns a promise you can await on to get the value
151+
The get() method returns a promise you can await on to get the value, resolve to the value or `false`
131152

132153
### List keys
133154

@@ -144,15 +165,15 @@ Use a list operation to view all the keys that live in a given storage, return a
144165
await delete(key:string)
145166
```
146167

147-
To delete a key-value pair, call the delete() method
168+
To delete a key-value pair, call the delete() method, resolve to `true` or `false`
148169

149170
### Has key-value pairs
150171

151172
```javascript
152173
await has(key:string)
153174
```
154175

155-
To check for the existence of a key
176+
To check for the existence of a key, resolve to `true` or `false`
156177

157178
## License
158179

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "kv-storage",
3-
"version": "0.0.2",
3+
"version": "0.0.3",
44
"description": "Create data storage that uses a simple key-value method for Node, Browser, Deno, Bun, Cloudflare Workers",
55
"main": "dist/cjs/kv-storage.js",
66
"module": "dist/mjs/kv-storage.js",
@@ -16,14 +16,16 @@
1616
"start": "node public/test/server.js",
1717
"start-mjs": "npm run build && node public/test/server-mjs.js",
1818
"dev-ts": "nodemon -e js,ts --watch src --watch test --exec \"ts-node test/server\"",
19-
"dev-deno": "nodemon -e js,ts --watch src --watch test --exec \"deno run --allow-read --allow-write test/server-deno.ts\"",
19+
"dev-browser": "nodemon -e js,ts,html --watch src --watch test --exec \"npm run prepare-public && tsc -p tsconfig-browser.json && ts-node test/server-browser.ts\"",
20+
"dev-deno": "nodemon -e js,ts --watch src --watch test --exec \"deno run --allow-read --allow-write --unstable-sloppy-imports test/server-deno.ts\"",
2021
"dev": "nodemon -e js,ts --watch src --watch test --exec \"npm run build && npm start\"",
2122
"dev-mjs": "nodemon -e js,ts --watch src --watch test --exec \"npm run start-mjs\"",
2223
"build-win": "npm run prepare-build-win && tsc -p tsconfig-mjs.json && tsc -p tsconfig-cjs.json && echo {\"type\": \"commonjs\"}>dist\\cjs\\package.json && echo {\"type\": \"module\"}>dist\\mjs\\package.json",
2324
"prepare-build": "if exist .\\dist (echo ok) && mkdir dist && del /S /Q .\\dist\\*",
2425
"prepare-build-win": "if not exist .\\dist (mkdir dist) else (rmdir /S /Q .\\dist\\)",
2526
"prepare-typedoc": "if not exist .\\docs (mkdir docs) else (rmdir /S /Q .\\docs\\)",
26-
"typedoc":"npm run prepare-typedoc && typedoc src/kv-storage.ts src/node-kv-storage.ts src/deno-kv-storage.ts",
27+
"prepare-public": "if not exist .\\public (mkdir public) else (rmdir /S /Q .\\public\\)",
28+
"typedoc":"npm run prepare-typedoc && typedoc src/kv-storage.ts src/node-kv-storage.ts src/deno-kv-storage.ts src/browser-kv-storage.ts",
2729
"gh-deploy": "git push origin :gh-pages && git subtree push --prefix docs origin gh-pages",
2830
"gh-deploy-init": "git push origin && git subtree push --prefix docs origin gh-pages"
2931
},

src/browser-kv-storage.ts

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
interface CallbackOneParam<T1, T2 = void> {
2+
(param1: T1): T2;
3+
}
4+
5+
export class BrowserKVStorage{
6+
7+
private _databaseName:string
8+
private _storageName:string
9+
private _dbVersion:number
10+
private _iDB:IDBDatabase
11+
12+
private constructor({
13+
databaseName,
14+
storageName,
15+
dbVersion,
16+
iDB
17+
}:{
18+
databaseName:string,
19+
storageName:string,
20+
dbVersion:number,
21+
iDB:IDBDatabase
22+
}){
23+
24+
this._databaseName = databaseName
25+
this._storageName = storageName
26+
this._dbVersion = 1
27+
this._iDB = iDB
28+
}
29+
30+
private isAlphanumeric(str:string) {
31+
return /^[a-zA-Z0-9]+$/.test(str);
32+
}
33+
34+
private showError(msg:string = 'Error'){
35+
throw new Error(msg)
36+
}
37+
38+
public static async init({
39+
databaseName = "data",
40+
storageName,
41+
}:{
42+
databaseName?:string,
43+
storageName:string
44+
}): Promise<BrowserKVStorage>{
45+
46+
function isAlphanumeric(str:string) {
47+
return /^[a-zA-Z0-9]+$/.test(str);
48+
}
49+
50+
function showError(msg:string = 'Error'){
51+
throw new Error(msg)
52+
}
53+
54+
function indexedDBStuff () {
55+
// Check for IndexedDB support
56+
if (!('indexedDB' in window)) {
57+
// Can't use IndexedDB
58+
showError("This browser doesn't support IndexedDB")
59+
return
60+
} else {
61+
// Do IndexedDB stuff here
62+
}
63+
}
64+
65+
// Run IndexedDB code
66+
indexedDBStuff()
67+
68+
const dbVersion = 1
69+
70+
if(!isAlphanumeric(databaseName))showError('dataDirName must be Alphanumeric')
71+
if(!isAlphanumeric(storageName))showError('storageName must be Alphanumeric')
72+
const createdb:Promise<IDBDatabase> = new Promise((resolve) => {
73+
let request = window.indexedDB.open(databaseName,dbVersion)
74+
request.onerror = function(){
75+
console.error("Error", request.error)
76+
}
77+
request.onsuccess = function(){
78+
let db = request.result
79+
resolve(db)
80+
}
81+
request.onupgradeneeded = function(event){
82+
let db = request.result
83+
if (!db.objectStoreNames.contains(storageName)) {
84+
db.createObjectStore(storageName, {keyPath: 'key'});
85+
}
86+
}
87+
request.onblocked = function(){
88+
console.error("Error, conflict")
89+
}
90+
})
91+
92+
const iDB = await createdb
93+
94+
return new BrowserKVStorage({databaseName,storageName,dbVersion,iDB})
95+
}
96+
97+
public async put(key:string,value:string){
98+
return new Promise((resolve) => {
99+
if(!this.isAlphanumeric(key))this.showError('Key must be Alphanumeric')
100+
let transaction = this._iDB.transaction(this._storageName, "readwrite")
101+
let request = transaction.objectStore(this._storageName).put({key: key, value: value})
102+
request.onsuccess = function() {
103+
resolve(true)
104+
}
105+
request.onerror = function() {
106+
resolve(false)
107+
}
108+
})
109+
}
110+
111+
public async get(key:string){
112+
return new Promise((resolve) => {
113+
if(!this.isAlphanumeric(key))this.showError('Key must be Alphanumeric')
114+
let transaction = this._iDB.transaction(this._storageName, "readonly")
115+
let request = transaction.objectStore(this._storageName).get(key)
116+
request.onsuccess = function(event) {
117+
if(request.result != undefined){resolve(request.result.value)}else{resolve(false)}
118+
}
119+
request.onerror = function() {
120+
resolve(false)
121+
}
122+
123+
})
124+
}
125+
126+
public async delete(key:string){
127+
return new Promise((resolve) => {
128+
if(!this.isAlphanumeric(key))this.showError('Key must be Alphanumeric')
129+
let transaction = this._iDB.transaction(this._storageName, "readwrite")
130+
let request = transaction.objectStore(this._storageName).delete(key)
131+
request.onsuccess = function(event) {
132+
resolve(true)
133+
}
134+
request.onerror = function() {
135+
resolve(false)
136+
}
137+
138+
})
139+
}
140+
141+
public async has(key:string){
142+
return new Promise((resolve) => {
143+
if(!this.isAlphanumeric(key))this.showError('Key must be Alphanumeric')
144+
let transaction = this._iDB.transaction(this._storageName, "readonly")
145+
let request = transaction.objectStore(this._storageName).get(key)
146+
request.onsuccess = function(event) {
147+
if(request.result != undefined){resolve(true)}else{resolve(false)}
148+
}
149+
request.onerror = function() {
150+
resolve(false)
151+
}
152+
})
153+
}
154+
155+
public async list(){
156+
return new Promise((resolve) => {
157+
let transaction = this._iDB.transaction(this._storageName, "readonly")
158+
let request = transaction.objectStore(this._storageName).getAllKeys()
159+
request.onsuccess = function(event) {
160+
let result = {
161+
keys:request.result,
162+
complete:true
163+
}
164+
resolve(result)
165+
}
166+
request.onerror = function() {
167+
resolve(false)
168+
}
169+
})
170+
}
171+
}

src/kv-storage.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export async function KVStorage({
22
runtime = 'node',
3-
storageName = 'storage',
4-
databaseName = 'kvstorage'
3+
databaseName = 'kvstorage',
4+
storageName = 'storage'
55
}:{
66
runtime?:string,
77
storageName?:string,
@@ -21,21 +21,31 @@ export async function KVStorage({
2121

2222
switch(runtime.toLowerCase()){
2323
case 'node':
24-
const runtime = await import('./node-kv-storage')
25-
const db = await runtime.NodeKVStorage.init({
26-
storageName,
27-
dataDirName:databaseName
24+
const runnode = await import('./node-kv-storage')
25+
const dbnode = await runnode.NodeKVStorage.init({
26+
dataDirName:databaseName,
27+
storageName
2828
})
29-
return db
29+
return dbnode
3030
break
3131
case 'deno':
32-
const rundeno = await import('./deno-kv-storage.ts')
32+
const rundeno = await import('./deno-kv-storage')
3333
const dbdeno = await rundeno.DenoKVStorage.init({
34-
storageName,
35-
dataDirName:databaseName
34+
dataDirName:databaseName,
35+
storageName
3636
})
3737
return dbdeno
3838
break
39+
case 'browser':
40+
let browserpkg = './browser-kv-storage'
41+
if(window)browserpkg = './browser-kv-storage.js'
42+
const runbrowser = await import(browserpkg)
43+
const dbbrowser = await runbrowser.BrowserKVStorage.init({
44+
databaseName,
45+
storageName
46+
})
47+
return dbbrowser
48+
break
3949
default:
4050
showError('Runtime unknown')
4151
}

test/index.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<html>
2+
<body>
3+
<p>123</p>
4+
<script type="module">
5+
import {KVStorage} from './../public/src/kv-storage.js'
6+
7+
void async function main() {
8+
9+
const db = await KVStorage({
10+
runtime:'browser',
11+
storageName:'storage'
12+
})
13+
14+
console.log(await db.put('yes','no'))
15+
console.log(await db.get('yes'))
16+
console.log(await db.delete('yes'))
17+
console.log(await db.get('yes'))
18+
console.log(await db.put('yes1','no1'))
19+
console.log(await db.list())
20+
console.log(await db.has('key'))
21+
}()
22+
</script>
23+
</body>
24+
</html>

0 commit comments

Comments
 (0)