yipedb 1.0.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/LICENSE +21 -0
- package/README.md +206 -0
- package/dist/yipedb.esm.js +1 -0
- package/dist/yipedb.min.js +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rezzvy
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# YipeDB
|
|
2
|
+
|
|
3
|
+
A simple way to use IndexedDB, with built-in file import and export.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
YipeDB simplifies working with IndexedDB Web API by removing its complexity.
|
|
8
|
+
|
|
9
|
+
- Store JSON, objects, and binary data (Blob / ArrayBuffer)
|
|
10
|
+
- Export entire database as a ZIP archive
|
|
11
|
+
- Import database from a ZIP archive
|
|
12
|
+
- Auto-increment or custom keys
|
|
13
|
+
- No schema setup required
|
|
14
|
+
|
|
15
|
+
## Installation & Usage
|
|
16
|
+
|
|
17
|
+
### Installation
|
|
18
|
+
|
|
19
|
+
#### Browser
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<script src="https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js"></script>
|
|
23
|
+
<script src="https://cdn.jsdelivr.net/gh/rezzvy/yipedb@056f5d2/dist/yipedb.min.js"></script>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
#### Node
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install yipedb
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import YipeDB from "yipedb";
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Usage
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
(async () => {
|
|
40
|
+
const db = new YipeDB("MyAppData");
|
|
41
|
+
|
|
42
|
+
await db.use("users").set({ name: "Alice", role: "Admin" });
|
|
43
|
+
|
|
44
|
+
const users = await db.use("users").getAll();
|
|
45
|
+
console.log(users);
|
|
46
|
+
})();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Examples
|
|
50
|
+
|
|
51
|
+
### Auto-increment key vs custom key
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
(async () => {
|
|
55
|
+
const db = new YipeDB("TestDB");
|
|
56
|
+
|
|
57
|
+
// auto key
|
|
58
|
+
await db.use("users").set({ name: "Nurul" });
|
|
59
|
+
|
|
60
|
+
// custom key
|
|
61
|
+
await db.use("users").set({ name: "Trisha" }, "user_2");
|
|
62
|
+
})();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Export database as downloadable file
|
|
66
|
+
|
|
67
|
+
```javascript
|
|
68
|
+
(async () => {
|
|
69
|
+
const db = new YipeDB("MyAppData");
|
|
70
|
+
await db.use("test").set("Hello!");
|
|
71
|
+
|
|
72
|
+
const zipBlob = await db.export();
|
|
73
|
+
const url = URL.createObjectURL(zipBlob);
|
|
74
|
+
const a = document.createElement("a");
|
|
75
|
+
a.href = url;
|
|
76
|
+
a.download = "backup.zip";
|
|
77
|
+
a.click();
|
|
78
|
+
})();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Import database from file
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
const db = new YipeDB("MyAppData");
|
|
85
|
+
const input = document.querySelector("input[type=file]");
|
|
86
|
+
|
|
87
|
+
input.addEventListener("change", async () => {
|
|
88
|
+
const file = input.files[0];
|
|
89
|
+
const result = await db.import(file);
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Documentation
|
|
94
|
+
|
|
95
|
+
### API Reference
|
|
96
|
+
|
|
97
|
+
#### `new YipeDB(dbName, version?)`
|
|
98
|
+
|
|
99
|
+
Creates a new database instance.
|
|
100
|
+
|
|
101
|
+
| Parameter | Type | Description |
|
|
102
|
+
| --------- | -------- | ---------------------------------------------------- |
|
|
103
|
+
| `dbName` | `string` | Database name (max 64 chars, alphanumeric, `_`, `-`) |
|
|
104
|
+
| `version` | `number` | Database version (default: `1`) |
|
|
105
|
+
|
|
106
|
+
#### `db.use(tableName)`
|
|
107
|
+
|
|
108
|
+
Access or create a table (object store).
|
|
109
|
+
|
|
110
|
+
| Parameter | Type | Description |
|
|
111
|
+
| ----------- | -------- | ----------- |
|
|
112
|
+
| `tableName` | `string` | Table name |
|
|
113
|
+
|
|
114
|
+
**Returns:** An object containing the following table operation methods.
|
|
115
|
+
|
|
116
|
+
> [!NOTE]
|
|
117
|
+
> All table methods are **async** and return a Promise.
|
|
118
|
+
|
|
119
|
+
| Method | Description | Returns |
|
|
120
|
+
| ----------------- | --------------------- | ----------------------------------------------------------------------- |
|
|
121
|
+
| `set(value, id?)` | Insert or update data | `Promise<{ key: any, value: any }>` The inserted key and value. |
|
|
122
|
+
| `get(id)` | Get single entry | `Promise<any \| null>` The stored entry object, or `null` if not found. |
|
|
123
|
+
| `getAll()` | Get all entries | `Promise<Array<any>>` An array of all stored entry objects. |
|
|
124
|
+
| `unset(id)` | Delete entry | `Promise<boolean>` Resolves to `true` upon successful deletion. |
|
|
125
|
+
| `unsetAll()` | Clear table | `Promise<boolean>` Resolves to `true` upon successful clearing. |
|
|
126
|
+
|
|
127
|
+
#### `db.export()`
|
|
128
|
+
|
|
129
|
+
Exports the entire database.
|
|
130
|
+
|
|
131
|
+
| Returns | Description |
|
|
132
|
+
| --------------- | ---------------------------- |
|
|
133
|
+
| `Promise<Blob>` | ZIP file containing all data |
|
|
134
|
+
|
|
135
|
+
#### `db.import(file, options?)`
|
|
136
|
+
|
|
137
|
+
Imports a database from a ZIP file.
|
|
138
|
+
|
|
139
|
+
| Parameter | Type | Default | Description |
|
|
140
|
+
| ------------------ | --------------------- | ------- | --------------------------------- |
|
|
141
|
+
| `file` | `Blob \| ArrayBuffer` | - | ZIP archive |
|
|
142
|
+
| `options.clear` | `boolean` | `true` | Clear existing data before import |
|
|
143
|
+
| `options.maxBytes` | `number` | `100MB` | Maximum allowed size |
|
|
144
|
+
|
|
145
|
+
**Returns:**
|
|
146
|
+
|
|
147
|
+
| Property | Type | Description |
|
|
148
|
+
| :----------- | :------- | :--------------------------------------------------------------------------------------------- |
|
|
149
|
+
| `dbName` | `string` | Name of the imported database |
|
|
150
|
+
| `exportedAt` | `string` | ISO Timestamp of when the data was originally exported |
|
|
151
|
+
| `results` | `object` | Object containing the number of successfully imported rows per table (e.g., `{ "users": 15 }`) |
|
|
152
|
+
|
|
153
|
+
### Export / Import Details
|
|
154
|
+
|
|
155
|
+
#### Export structure
|
|
156
|
+
|
|
157
|
+
The generated ZIP file contains:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
manifest.json
|
|
161
|
+
tables/
|
|
162
|
+
*.json
|
|
163
|
+
blobs/
|
|
164
|
+
*.bin
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
- `manifest.json`
|
|
168
|
+
Contains metadata, store list, version, timestamp, and checksum.
|
|
169
|
+
|
|
170
|
+
- `tables/*.json`
|
|
171
|
+
Each table is exported as structured entries:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"key": 1,
|
|
176
|
+
"valueType": "json | blob | arraybuffer | json_with_blobs",
|
|
177
|
+
"value": ...
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- `blobs/`
|
|
182
|
+
Binary data extracted and stored separately for safety and portability.
|
|
183
|
+
|
|
184
|
+
#### Supported value types
|
|
185
|
+
|
|
186
|
+
| Type | Description |
|
|
187
|
+
| ----------------- | -------------------------------------- |
|
|
188
|
+
| `json` | Plain JSON values |
|
|
189
|
+
| `blob` | Stored as binary file |
|
|
190
|
+
| `arraybuffer` | Stored as binary file |
|
|
191
|
+
| `json_with_blobs` | Object containing embedded Blob fields |
|
|
192
|
+
|
|
193
|
+
#### Import behavior
|
|
194
|
+
|
|
195
|
+
- Validates ZIP structure and manifest
|
|
196
|
+
- Verifies checksum (basic integrity check)
|
|
197
|
+
- Prevents zip bomb attacks via size limits
|
|
198
|
+
- Restores all tables and binary data correctly
|
|
199
|
+
|
|
200
|
+
## Contributing
|
|
201
|
+
|
|
202
|
+
There's always room for improvement. Feel free to contribute!
|
|
203
|
+
|
|
204
|
+
## Licensing
|
|
205
|
+
|
|
206
|
+
The project is licensed under the MIT License. Check the license file for more details.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var v=class p{#r;#s;#e;#t;static#c=100*1024*1024;static#l=/^[a-zA-Z0-9_-]{1,64}$/;static JSZip=null;constructor(e,s=1){p.#n(e),this.#r=e,this.#s=s,this.#e=null,this.#t=new Set}static#n(e){if(typeof e!="string"||!p.#l.test(e))throw new TypeError(`Invalid name "${e}". Only letters, numbers, _ and - are allowed (max 64 chars).`)}static#f(e){if(!e||typeof e!="object")throw new Error("Invalid manifest: not an object");if(typeof e.dbName!="string")throw new Error("Invalid manifest: missing dbName");if(!Array.isArray(e.stores))throw new Error("Invalid manifest: stores must be an array")}static#u(e,s){if(!Array.isArray(s))throw new Error(`Invalid table data: store "${e}" entries must be an array`);for(let t of s){if(typeof t.key>"u")throw new Error(`Invalid table data: entry missing key in store "${e}"`);if(!["json","blob","arraybuffer","json_with_blobs"].includes(t.valueType))throw new Error(`Invalid table data: unknown valueType "${t.valueType}"`);if(t.valueType==="blob"||t.valueType==="arraybuffer"){let o=t.value?.blobFile;if(typeof o!="string"||o.includes("/")||o.includes(".."))throw new Error(`Invalid table data: suspicious blobFile path "${o}"`)}}}static#i(e){let s=2166136261;for(let t=0;t<e.length;t++)s^=e.charCodeAt(t),s=Math.imul(s,16777619)>>>0;return s.toString(16).padStart(8,"0")}async#o(e){if(this.#e&&this.#e.objectStoreNames.contains(e))return this.#e;if(this.#e){let s=this.#e.version+1;return this.#e.close(),this.#e=null,this.#a(e,s)}return this.#a(e,this.#s)}#a(e,s){return new Promise((t,o)=>{let a=indexedDB.open(this.#r,s);a.onupgradeneeded=r=>{let i=r.target.result;for(let w of this.#t)i.objectStoreNames.contains(w)||i.createObjectStore(w,{keyPath:"key",autoIncrement:!0});i.objectStoreNames.contains(e)||i.createObjectStore(e,{keyPath:"key",autoIncrement:!0})},a.onsuccess=r=>{this.#e=r.target.result,this.#s=this.#e.version,t(this.#e)},a.onerror=()=>o(a.error)})}async#b(){if(!this.#e){let e=[...this.#t][0];if(e)await this.#o(e);else return[]}return[...this.#e.objectStoreNames]}use(e){p.#n(e),this.#t.add(e);let s=t=>this.#o(t);return{async set(t,o){let a=await s(e),r=o!==void 0?{key:o,value:t}:{value:t};return new Promise((i,w)=>{let S=a.transaction(e,"readwrite"),c=o!==void 0?S.objectStore(e).put(r):S.objectStore(e).add(r);c.onsuccess=()=>i({key:c.result,value:t}),c.onerror=()=>w(c.error)})},async get(t){let o=await s(e);return new Promise((a,r)=>{let i=o.transaction(e,"readonly").objectStore(e).get(t);i.onsuccess=()=>a(i.result??null),i.onerror=()=>r(i.error)})},async getAll(){let t=await s(e);return new Promise((o,a)=>{let r=t.transaction(e,"readonly").objectStore(e).getAll();r.onsuccess=()=>o(r.result),r.onerror=()=>a(r.error)})},async unset(t){let o=await s(e);return new Promise((a,r)=>{let i=o.transaction(e,"readwrite").objectStore(e).delete(t);i.onsuccess=()=>a(!0),i.onerror=()=>r(i.error)})},async unsetAll(){let t=await s(e);return new Promise((o,a)=>{let r=t.transaction(e,"readwrite").objectStore(e).clear();r.onsuccess=()=>o(!0),r.onerror=()=>a(r.error)})}}}async export(){let e=p.JSZip;if(!e)throw new Error("JSZip not found. Please ensure it is injected via YipeDB.JSZip = JSZip.");let s=new e,t=s.folder("blobs"),o=s.folder("tables"),a=await this.#b(),r={dbName:this.#r,exportedAt:new Date().toISOString(),version:this.#e.version,stores:[]};for(let c of a){let j=await this.use(c).getAll(),l=[];for(let u of j){let f=u.value,b={key:u.key,valueType:"json",value:null};if(f instanceof Blob){let n=`${c}_${u.key}.bin`;t.file(n,await f.arrayBuffer()),b.valueType="blob",b.value={blobFile:n,type:f.type}}else if(f instanceof ArrayBuffer){let n=`${c}_${u.key}.bin`;t.file(n,f),b.valueType="arraybuffer",b.value={blobFile:n}}else if(f!==null&&typeof f=="object"){let n={...f},y=!1;for(let[h,d]of Object.entries(n))if(d instanceof Blob){let m=`${c}_${u.key}_${h}.bin`;t.file(m,await d.arrayBuffer()),n[h]={_yipe_blob:!0,blobFile:m,type:d.type},y=!0}b.valueType=y?"json_with_blobs":"json",b.value=n}else b.value=f;l.push(b)}o.file(`${c}.json`,JSON.stringify(l)),r.stores.push(c)}let i=JSON.stringify(r,null,2);r._checksum=p.#i(i);let w=JSON.stringify(r,null,2);return s.file("manifest.json",w),await s.generateAsync({type:"blob",compression:"DEFLATE"})}async import(e,{clear:s=!0,maxBytes:t=p.#c}={}){let o=p.JSZip;if(!o)throw new Error("JSZip not found. Please ensure it is injected via YipeDB.JSZip = JSZip.");let a=e instanceof Blob?e.size:e.byteLength??0;if(a>t)throw new Error(`Import rejected: file too large (${a} bytes, max ${t})`);let r=await o.loadAsync(e),i=0;for(let[,l]of Object.entries(r.files))if(!l.dir){let u=await l.async("arraybuffer");if(i+=u.byteLength,i>t)throw new Error(`Import rejected: extracted content exceeds ${t} bytes (zip bomb?)`)}let w=r.file("manifest.json");if(!w)throw new Error("Invalid archive: manifest.json not found");let S=await w.async("string"),c=JSON.parse(S);if(c._checksum){let{_checksum:l,...u}=c,f=p.#i(JSON.stringify(u,null,2));if(l!==f)throw new Error("Import rejected: manifest checksum mismatch \u2014 file may be corrupted or tampered")}p.#f(c);let j={};for(let l of c.stores){if(s){let n=await this.#o(l);await new Promise((y,h)=>{let d=n.transaction(l,"readwrite").objectStore(l).clear();d.onsuccess=y,d.onerror=()=>h(d.error)})}let u=r.file(`tables/${l}.json`);if(!u)throw new Error(`Missing table file: tables/${l}.json`);let f=await u.async("string"),b=JSON.parse(f);p.#u(l,b);for(let n of b){let y;if(n.valueType==="blob"){let h=await r.file(`blobs/${n.value.blobFile}`).async("arraybuffer");y=new Blob([h],{type:n.value.type||""})}else if(n.valueType==="arraybuffer")y=await r.file(`blobs/${n.value.blobFile}`).async("arraybuffer");else if(n.valueType==="json_with_blobs"){y={...n.value};for(let[h,d]of Object.entries(y))if(d&&d._yipe_blob){let m=await r.file(`blobs/${d.blobFile}`).async("arraybuffer");y[h]=new Blob([m],{type:d.type||""})}}else y=n.value;await this.use(l).set(y,n.key)}j[l]=b.length}return{dbName:c.dbName,exportedAt:c.exportedAt,results:j}}};import g from"jszip";v.JSZip=g;var A=v;export{A as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(()=>{var v=class w{#r;#s;#e;#t;static#c=100*1024*1024;static#l=/^[a-zA-Z0-9_-]{1,64}$/;static JSZip=null;constructor(e,s=1){w.#n(e),this.#r=e,this.#s=s,this.#e=null,this.#t=new Set}static#n(e){if(typeof e!="string"||!w.#l.test(e))throw new TypeError(`Invalid name "${e}". Only letters, numbers, _ and - are allowed (max 64 chars).`)}static#f(e){if(!e||typeof e!="object")throw new Error("Invalid manifest: not an object");if(typeof e.dbName!="string")throw new Error("Invalid manifest: missing dbName");if(!Array.isArray(e.stores))throw new Error("Invalid manifest: stores must be an array")}static#u(e,s){if(!Array.isArray(s))throw new Error(`Invalid table data: store "${e}" entries must be an array`);for(let t of s){if(typeof t.key>"u")throw new Error(`Invalid table data: entry missing key in store "${e}"`);if(!["json","blob","arraybuffer","json_with_blobs"].includes(t.valueType))throw new Error(`Invalid table data: unknown valueType "${t.valueType}"`);if(t.valueType==="blob"||t.valueType==="arraybuffer"){let o=t.value?.blobFile;if(typeof o!="string"||o.includes("/")||o.includes(".."))throw new Error(`Invalid table data: suspicious blobFile path "${o}"`)}}}static#i(e){let s=2166136261;for(let t=0;t<e.length;t++)s^=e.charCodeAt(t),s=Math.imul(s,16777619)>>>0;return s.toString(16).padStart(8,"0")}async#o(e){if(this.#e&&this.#e.objectStoreNames.contains(e))return this.#e;if(this.#e){let s=this.#e.version+1;return this.#e.close(),this.#e=null,this.#a(e,s)}return this.#a(e,this.#s)}#a(e,s){return new Promise((t,o)=>{let a=indexedDB.open(this.#r,s);a.onupgradeneeded=r=>{let i=r.target.result;for(let p of this.#t)i.objectStoreNames.contains(p)||i.createObjectStore(p,{keyPath:"key",autoIncrement:!0});i.objectStoreNames.contains(e)||i.createObjectStore(e,{keyPath:"key",autoIncrement:!0})},a.onsuccess=r=>{this.#e=r.target.result,this.#s=this.#e.version,t(this.#e)},a.onerror=()=>o(a.error)})}async#b(){if(!this.#e){let e=[...this.#t][0];if(e)await this.#o(e);else return[]}return[...this.#e.objectStoreNames]}use(e){w.#n(e),this.#t.add(e);let s=t=>this.#o(t);return{async set(t,o){let a=await s(e),r=o!==void 0?{key:o,value:t}:{value:t};return new Promise((i,p)=>{let S=a.transaction(e,"readwrite"),c=o!==void 0?S.objectStore(e).put(r):S.objectStore(e).add(r);c.onsuccess=()=>i({key:c.result,value:t}),c.onerror=()=>p(c.error)})},async get(t){let o=await s(e);return new Promise((a,r)=>{let i=o.transaction(e,"readonly").objectStore(e).get(t);i.onsuccess=()=>a(i.result??null),i.onerror=()=>r(i.error)})},async getAll(){let t=await s(e);return new Promise((o,a)=>{let r=t.transaction(e,"readonly").objectStore(e).getAll();r.onsuccess=()=>o(r.result),r.onerror=()=>a(r.error)})},async unset(t){let o=await s(e);return new Promise((a,r)=>{let i=o.transaction(e,"readwrite").objectStore(e).delete(t);i.onsuccess=()=>a(!0),i.onerror=()=>r(i.error)})},async unsetAll(){let t=await s(e);return new Promise((o,a)=>{let r=t.transaction(e,"readwrite").objectStore(e).clear();r.onsuccess=()=>o(!0),r.onerror=()=>a(r.error)})}}}async export(){let e=w.JSZip;if(!e)throw new Error("JSZip not found. Please ensure it is injected via YipeDB.JSZip = JSZip.");let s=new e,t=s.folder("blobs"),o=s.folder("tables"),a=await this.#b(),r={dbName:this.#r,exportedAt:new Date().toISOString(),version:this.#e.version,stores:[]};for(let c of a){let j=await this.use(c).getAll(),l=[];for(let u of j){let f=u.value,b={key:u.key,valueType:"json",value:null};if(f instanceof Blob){let n=`${c}_${u.key}.bin`;t.file(n,await f.arrayBuffer()),b.valueType="blob",b.value={blobFile:n,type:f.type}}else if(f instanceof ArrayBuffer){let n=`${c}_${u.key}.bin`;t.file(n,f),b.valueType="arraybuffer",b.value={blobFile:n}}else if(f!==null&&typeof f=="object"){let n={...f},y=!1;for(let[h,d]of Object.entries(n))if(d instanceof Blob){let m=`${c}_${u.key}_${h}.bin`;t.file(m,await d.arrayBuffer()),n[h]={_yipe_blob:!0,blobFile:m,type:d.type},y=!0}b.valueType=y?"json_with_blobs":"json",b.value=n}else b.value=f;l.push(b)}o.file(`${c}.json`,JSON.stringify(l)),r.stores.push(c)}let i=JSON.stringify(r,null,2);r._checksum=w.#i(i);let p=JSON.stringify(r,null,2);return s.file("manifest.json",p),await s.generateAsync({type:"blob",compression:"DEFLATE"})}async import(e,{clear:s=!0,maxBytes:t=w.#c}={}){let o=w.JSZip;if(!o)throw new Error("JSZip not found. Please ensure it is injected via YipeDB.JSZip = JSZip.");let a=e instanceof Blob?e.size:e.byteLength??0;if(a>t)throw new Error(`Import rejected: file too large (${a} bytes, max ${t})`);let r=await o.loadAsync(e),i=0;for(let[,l]of Object.entries(r.files))if(!l.dir){let u=await l.async("arraybuffer");if(i+=u.byteLength,i>t)throw new Error(`Import rejected: extracted content exceeds ${t} bytes (zip bomb?)`)}let p=r.file("manifest.json");if(!p)throw new Error("Invalid archive: manifest.json not found");let S=await p.async("string"),c=JSON.parse(S);if(c._checksum){let{_checksum:l,...u}=c,f=w.#i(JSON.stringify(u,null,2));if(l!==f)throw new Error("Import rejected: manifest checksum mismatch \u2014 file may be corrupted or tampered")}w.#f(c);let j={};for(let l of c.stores){if(s){let n=await this.#o(l);await new Promise((y,h)=>{let d=n.transaction(l,"readwrite").objectStore(l).clear();d.onsuccess=y,d.onerror=()=>h(d.error)})}let u=r.file(`tables/${l}.json`);if(!u)throw new Error(`Missing table file: tables/${l}.json`);let f=await u.async("string"),b=JSON.parse(f);w.#u(l,b);for(let n of b){let y;if(n.valueType==="blob"){let h=await r.file(`blobs/${n.value.blobFile}`).async("arraybuffer");y=new Blob([h],{type:n.value.type||""})}else if(n.valueType==="arraybuffer")y=await r.file(`blobs/${n.value.blobFile}`).async("arraybuffer");else if(n.valueType==="json_with_blobs"){y={...n.value};for(let[h,d]of Object.entries(y))if(d&&d._yipe_blob){let m=await r.file(`blobs/${d.blobFile}`).async("arraybuffer");y[h]=new Blob([m],{type:d.type||""})}}else y=n.value;await this.use(l).set(y,n.key)}j[l]=b.length}return{dbName:c.dbName,exportedAt:c.exportedAt,results:j}}};typeof window<"u"&&(v.JSZip=window.JSZip||null,window.YipeDB=v);})();
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "yipedb",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A simple way to use IndexedDB, with built-in file import and export.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/yipedb.esm.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/yipedb.esm.js"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/rezzvy/yipedb.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/rezzvy/yipedb/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/rezzvy/yipedb#readme",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build:browser": "esbuild ./src/index.browser.js --bundle --minify --platform=browser --format=iife --outfile=dist/yipedb.min.js",
|
|
23
|
+
"build:esm": "esbuild ./src/index.esm.js --bundle --minify --format=esm --external:jszip --outfile=dist/yipedb.esm.js",
|
|
24
|
+
"build": "npm run build:browser && npm run build:esm"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"indexeddb",
|
|
28
|
+
"nosql",
|
|
29
|
+
"browser-database",
|
|
30
|
+
"offline-storage",
|
|
31
|
+
"blob-storage",
|
|
32
|
+
"file-import",
|
|
33
|
+
"file-export",
|
|
34
|
+
"wrapper"
|
|
35
|
+
],
|
|
36
|
+
"author": "rezzvy",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"esbuild": "^0.27.4"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"jszip": "^3.10.1"
|
|
43
|
+
}
|
|
44
|
+
}
|