locality-idb 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +451 -1
- package/dist/index.cjs +331 -63
- package/dist/index.d.cts +363 -188
- package/dist/index.d.mts +363 -188
- package/dist/index.iife.js +331 -63
- package/dist/index.mjs +320 -64
- package/dist/index.umd.js +331 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
- [Select/Query Records](#selectquery-records)
|
|
42
42
|
- [Update Records](#update-records)
|
|
43
43
|
- [Delete Records](#delete-records)
|
|
44
|
+
- [Transactions](#transactions)
|
|
45
|
+
- [Export Database](#export-database)
|
|
44
46
|
- [API Reference](#-api-reference)
|
|
45
47
|
- [Locality Class](#locality-class)
|
|
46
48
|
- [Schema Functions](#schema-functions)
|
|
@@ -64,6 +66,8 @@
|
|
|
64
66
|
- 🛠️ **Rich Column Types**: Support for various data types including custom types
|
|
65
67
|
- ✅ **Built-in Validation**: Automatic data type validation for built-in column types during insert and update operations
|
|
66
68
|
- 🔧 **Custom Validators**: Define custom validation logic for columns to enforce complex rules
|
|
69
|
+
- 🔒 **Atomic Transactions**: Execute multiple operations across tables with automatic rollback on failure
|
|
70
|
+
- 📤 **Database Export**: Export database data as JSON for backup, migration, or debugging
|
|
67
71
|
|
|
68
72
|
---
|
|
69
73
|
|
|
@@ -205,6 +209,8 @@ Locality IDB supports a wide range of column types:
|
|
|
205
209
|
| `text()` / `string()` | Text strings | `column.text()` |
|
|
206
210
|
| `char(length?)` | Fixed-length string | `column.char(10)` |
|
|
207
211
|
| `varchar(length?)` | Variable-length string | `column.varchar(255)` |
|
|
212
|
+
| `email()` | Email strings | `column.email()` |
|
|
213
|
+
| `url()` | URL strings | `column.url()` |
|
|
208
214
|
| `bool()` / `boolean()` | Boolean values | `column.bool()` |
|
|
209
215
|
| `date()` | Date objects | `column.date()` |
|
|
210
216
|
| `timestamp()` | ISO 8601 timestamps ([auto-generated](#utility-functions)) | `column.timestamp()` |
|
|
@@ -251,7 +257,7 @@ const productId: ProductId = 2 as ProductId;
|
|
|
251
257
|
// userId = productId; // ❌ Type error!
|
|
252
258
|
```
|
|
253
259
|
|
|
254
|
-
##### String Types (`text`, `string`, `char`, `varchar`)
|
|
260
|
+
##### String Types (`text`, `string`, `char`, `varchar`, `email`, `url`)
|
|
255
261
|
|
|
256
262
|
```typescript
|
|
257
263
|
// Literal unions for enum-like behavior
|
|
@@ -277,8 +283,40 @@ const profileSchema = defineSchema({
|
|
|
277
283
|
website: column.varchar<URL>(500).optional(),
|
|
278
284
|
},
|
|
279
285
|
});
|
|
286
|
+
|
|
287
|
+
// or use specialized `email` & `url` methods + types with built-in validation
|
|
288
|
+
const advancedProfileSchema = defineSchema({
|
|
289
|
+
profiles: {
|
|
290
|
+
id: column.int().pk().auto(),
|
|
291
|
+
email: column.email().unique(), // Validates emails
|
|
292
|
+
website: column.url().optional(), // Validates URLs (internally uses URL constructor)
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### Auto-generated Types (`uuid`, `timestamp`)
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
const schema = defineSchema({
|
|
301
|
+
sessions: {
|
|
302
|
+
id: column.uuid().pk(), // Auto-generated UUID v4
|
|
303
|
+
idWithDefault: column.uuid().pk().default(uuid({ version: 'v6' })), // Replace auto-generated UUID v4
|
|
304
|
+
createdAt: column.timestamp(), // Auto-generated timestamp
|
|
305
|
+
defaultTs: column.timestamp().default(getTimestamp()), // Auto-generated timestamp with default using utility built-in function
|
|
306
|
+
customTs: column.timestamp().default(new Chronos().toLocalISOString() as Timestamp), // Default timestamp with custom format
|
|
307
|
+
},
|
|
308
|
+
});
|
|
280
309
|
```
|
|
281
310
|
|
|
311
|
+
> **Note:**
|
|
312
|
+
>
|
|
313
|
+
> - Auto-generated values can be overridden by providing explicit values during insert.
|
|
314
|
+
> - Use the `default()` modifier to set custom default values instead of auto-generated ones.
|
|
315
|
+
> - Auto-generated values are generated at runtime during insert operations.
|
|
316
|
+
> - Type extensions for `uuid` and `timestamp` are not applicable since they are already typed.
|
|
317
|
+
> - For custom UUID versions, use [`uuid`](https://toolbox.nazmul-nhb.dev/docs/utilities/hash/uuid) utility from [`nhb-toolbox`](https://www.npmjs.com/package/nhb-toolbox).
|
|
318
|
+
> - For custom timestamp formats, use date libraries like [`Chronos`](https://toolbox.nazmul-nhb.dev/docs/classes/Chronos) (from [`nhb-toolbox`](https://www.npmjs.com/package/nhb-toolbox)) or [`date-fns`](https://www.npmjs.com/package/date-fns) to generate ISO 8601 strings.
|
|
319
|
+
|
|
282
320
|
##### Boolean Types (`bool`, `boolean`)
|
|
283
321
|
|
|
284
322
|
```typescript
|
|
@@ -688,6 +726,163 @@ await db
|
|
|
688
726
|
.run();
|
|
689
727
|
```
|
|
690
728
|
|
|
729
|
+
### Transactions
|
|
730
|
+
|
|
731
|
+
Transactions enable you to perform multiple operations across multiple tables atomically. All operations in a transaction either succeed together or fail together, ensuring data consistency.
|
|
732
|
+
|
|
733
|
+
#### Basic Transaction
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
// Create a user and their first post atomically
|
|
737
|
+
await db.transaction(['users', 'posts'], async (ctx) => {
|
|
738
|
+
const newUser = await ctx
|
|
739
|
+
.insert('users')
|
|
740
|
+
.values({ name: 'John Doe', email: 'john@example.com' })
|
|
741
|
+
.run();
|
|
742
|
+
|
|
743
|
+
await ctx
|
|
744
|
+
.insert('posts')
|
|
745
|
+
.values({
|
|
746
|
+
userId: newUser.id,
|
|
747
|
+
title: 'My First Post',
|
|
748
|
+
content: 'Hello World!',
|
|
749
|
+
})
|
|
750
|
+
.run();
|
|
751
|
+
});
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
#### Transaction with Multiple Operations
|
|
755
|
+
|
|
756
|
+
```typescript
|
|
757
|
+
// Transfer data between tables atomically
|
|
758
|
+
await db.transaction(['users', 'posts', 'comments'], async (ctx) => {
|
|
759
|
+
// Update user
|
|
760
|
+
await ctx
|
|
761
|
+
.update('users')
|
|
762
|
+
.set({ isActive: true })
|
|
763
|
+
.where((user) => user.id === 1)
|
|
764
|
+
.run();
|
|
765
|
+
|
|
766
|
+
// Create post
|
|
767
|
+
const post = await ctx
|
|
768
|
+
.insert('posts')
|
|
769
|
+
.values({ userId: 1, title: 'New Post', content: 'Content' })
|
|
770
|
+
.run();
|
|
771
|
+
|
|
772
|
+
// Add comment
|
|
773
|
+
await ctx
|
|
774
|
+
.insert('comments')
|
|
775
|
+
.values({ postId: post.id, userId: 1, text: 'First comment!' })
|
|
776
|
+
.run();
|
|
777
|
+
|
|
778
|
+
// Query within transaction
|
|
779
|
+
const userPosts = await ctx
|
|
780
|
+
.from('posts')
|
|
781
|
+
.where((p) => p.userId === 1)
|
|
782
|
+
.findAll();
|
|
783
|
+
|
|
784
|
+
console.log(`User now has ${userPosts.length} posts`);
|
|
785
|
+
});
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
#### Automatic Rollback
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
try {
|
|
792
|
+
await db.transaction(['users', 'posts'], async (ctx) => {
|
|
793
|
+
const user = await ctx
|
|
794
|
+
.insert('users')
|
|
795
|
+
.values({ name: 'Alice', email: 'alice@example.com' })
|
|
796
|
+
.run();
|
|
797
|
+
|
|
798
|
+
// This will cause the entire transaction to rollback
|
|
799
|
+
throw new Error('Something went wrong!');
|
|
800
|
+
|
|
801
|
+
// This never executes
|
|
802
|
+
await ctx
|
|
803
|
+
.insert('posts')
|
|
804
|
+
.values({ userId: user.id, title: 'Post' })
|
|
805
|
+
.run();
|
|
806
|
+
});
|
|
807
|
+
} catch (error) {
|
|
808
|
+
console.error('Transaction failed:', error);
|
|
809
|
+
// No data was inserted - transaction was rolled back
|
|
810
|
+
}
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
> **Note:**
|
|
814
|
+
>
|
|
815
|
+
> - Transactions guarantee atomicity: all operations succeed or all fail.
|
|
816
|
+
> - If any operation fails or an error is thrown, the entire transaction is automatically rolled back.
|
|
817
|
+
> - Transaction context (`ctx`) provides `insert()`, `update()`, `delete()`, and `from()` methods.
|
|
818
|
+
> - All operations must be performed on tables specified in the transaction.
|
|
819
|
+
|
|
820
|
+
### Export Database
|
|
821
|
+
|
|
822
|
+
Export your database data as JSON for backup, migration, or debugging purposes. The export includes metadata and table data, and automatically triggers a browser download.
|
|
823
|
+
|
|
824
|
+
#### Export All Tables
|
|
825
|
+
|
|
826
|
+
```typescript
|
|
827
|
+
// Export entire database with pretty-printed JSON
|
|
828
|
+
await db.export();
|
|
829
|
+
// Downloads: my-database-2026-02-04T10-30-45-123Z.json
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
#### Export Specific Tables
|
|
833
|
+
|
|
834
|
+
```typescript
|
|
835
|
+
// Export only users and posts tables
|
|
836
|
+
await db.export({
|
|
837
|
+
tables: ['users', 'posts'],
|
|
838
|
+
filename: 'users-posts-backup.json',
|
|
839
|
+
});
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
#### Export with Custom Options
|
|
843
|
+
|
|
844
|
+
```typescript
|
|
845
|
+
// Export with custom configuration
|
|
846
|
+
await db.export({
|
|
847
|
+
tables: ['users'], // Optional: specific tables
|
|
848
|
+
filename: 'users-export.json', // Optional: custom filename
|
|
849
|
+
pretty: false, // Optional: compact JSON (default: true)
|
|
850
|
+
includeMetadata: true, // Optional: include metadata (default: true)
|
|
851
|
+
});
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
#### Export Data Structure
|
|
855
|
+
|
|
856
|
+
The exported JSON file contains:
|
|
857
|
+
|
|
858
|
+
```json
|
|
859
|
+
{
|
|
860
|
+
"metadata": {
|
|
861
|
+
"dbName": "my-database",
|
|
862
|
+
"version": 1,
|
|
863
|
+
"exportedAt": "2026-02-04T10:30:45.123Z",
|
|
864
|
+
"tables": ["users", "posts"]
|
|
865
|
+
},
|
|
866
|
+
"data": {
|
|
867
|
+
"users": [
|
|
868
|
+
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
|
|
869
|
+
{ "id": 2, "name": "Bob", "email": "bob@example.com" }
|
|
870
|
+
],
|
|
871
|
+
"posts": [
|
|
872
|
+
{ "id": 1, "userId": 1, "title": "First Post", "content": "..." }
|
|
873
|
+
]
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
> **Note:**
|
|
879
|
+
>
|
|
880
|
+
> - Exported files are automatically downloaded in the browser.
|
|
881
|
+
> - Default filename format: `{dbName}-{timestamp}.json`
|
|
882
|
+
> - Metadata is included by default but can be disabled.
|
|
883
|
+
> - Use `pretty: true` (default) for human-readable JSON.
|
|
884
|
+
> - Use `pretty: false` for compact JSON (smaller file size).
|
|
885
|
+
|
|
691
886
|
---
|
|
692
887
|
|
|
693
888
|
## 📚 API Reference
|
|
@@ -827,6 +1022,105 @@ const allUsers = await db.from('users').findAll();
|
|
|
827
1022
|
console.log(allUsers);
|
|
828
1023
|
```
|
|
829
1024
|
|
|
1025
|
+
#### `transaction<Tables>(tables: Tables[], callback: TransactionCallback): Promise<void>`
|
|
1026
|
+
|
|
1027
|
+
Executes multiple database operations across multiple tables in a single atomic transaction.
|
|
1028
|
+
|
|
1029
|
+
**Parameters:**
|
|
1030
|
+
|
|
1031
|
+
- `tables`: Array of table names to include in the transaction
|
|
1032
|
+
- `callback`: Async function that receives a transaction context and performs operations
|
|
1033
|
+
|
|
1034
|
+
**Returns:** Promise that resolves when the transaction completes successfully
|
|
1035
|
+
|
|
1036
|
+
**Transaction Context Methods:**
|
|
1037
|
+
|
|
1038
|
+
- `ctx.insert(table)`: Insert records within the transaction
|
|
1039
|
+
- `ctx.update(table)`: Update records within the transaction
|
|
1040
|
+
- `ctx.delete(table)`: Delete records within the transaction
|
|
1041
|
+
- `ctx.from(table)`: Query records within the transaction
|
|
1042
|
+
|
|
1043
|
+
**Example:**
|
|
1044
|
+
|
|
1045
|
+
```typescript
|
|
1046
|
+
// Create user and post atomically
|
|
1047
|
+
await db.transaction(['users', 'posts'], async (ctx) => {
|
|
1048
|
+
const user = await ctx
|
|
1049
|
+
.insert('users')
|
|
1050
|
+
.values({ name: 'Alice', email: 'alice@example.com' })
|
|
1051
|
+
.run();
|
|
1052
|
+
|
|
1053
|
+
await ctx
|
|
1054
|
+
.insert('posts')
|
|
1055
|
+
.values({ userId: user.id, title: 'First Post', content: 'Hello!' })
|
|
1056
|
+
.run();
|
|
1057
|
+
});
|
|
1058
|
+
```
|
|
1059
|
+
|
|
1060
|
+
> **Important:**
|
|
1061
|
+
>
|
|
1062
|
+
> - All operations succeed or all fail (atomicity).
|
|
1063
|
+
> - If any operation fails or an error is thrown, the entire transaction is rolled back.
|
|
1064
|
+
> - Only tables specified in the `tables` array can be accessed within the transaction.
|
|
1065
|
+
> - Transactions use IndexedDB's native transaction mechanism.
|
|
1066
|
+
|
|
1067
|
+
#### `export(options?: ExportOptions): Promise<void>`
|
|
1068
|
+
|
|
1069
|
+
Exports database data as a JSON file and triggers a browser download.
|
|
1070
|
+
|
|
1071
|
+
**Parameters:**
|
|
1072
|
+
|
|
1073
|
+
- `options`: Optional export configuration
|
|
1074
|
+
- `options.tables`: Array of table names to export (default: all tables)
|
|
1075
|
+
- `options.filename`: Custom filename (default: `{dbName}-{timestamp}.json`)
|
|
1076
|
+
- `options.pretty`: Enable pretty-printed JSON (default: `true`)
|
|
1077
|
+
- `options.includeMetadata`: Include export metadata (default: `true`)
|
|
1078
|
+
|
|
1079
|
+
**Returns:** Promise that resolves when the export completes
|
|
1080
|
+
|
|
1081
|
+
**Example:**
|
|
1082
|
+
|
|
1083
|
+
```typescript
|
|
1084
|
+
// Export all tables with default settings
|
|
1085
|
+
await db.export();
|
|
1086
|
+
|
|
1087
|
+
// Export specific tables with custom filename
|
|
1088
|
+
await db.export({
|
|
1089
|
+
tables: ['users', 'posts'],
|
|
1090
|
+
filename: 'backup-2026-02-04.json',
|
|
1091
|
+
pretty: true,
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
// Export without metadata in compact format
|
|
1095
|
+
await db.export({
|
|
1096
|
+
pretty: false,
|
|
1097
|
+
includeMetadata: false,
|
|
1098
|
+
});
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
**Exported JSON Structure:**
|
|
1102
|
+
|
|
1103
|
+
```typescript
|
|
1104
|
+
{
|
|
1105
|
+
metadata?: { // Optional (when includeMetadata = true)
|
|
1106
|
+
dbName: string;
|
|
1107
|
+
version: number;
|
|
1108
|
+
exportedAt: string; // ISO 8601 timestamp
|
|
1109
|
+
tables: string[];
|
|
1110
|
+
};
|
|
1111
|
+
data: {
|
|
1112
|
+
[tableName: string]: Array<Record<string, any>>;
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
> **Note:**
|
|
1118
|
+
>
|
|
1119
|
+
> - Automatically triggers a file download in the browser.
|
|
1120
|
+
> - Exported data includes all records from specified tables.
|
|
1121
|
+
> - Use for backup, debugging, or data migration.
|
|
1122
|
+
> - File download works in browser environments only.
|
|
1123
|
+
|
|
830
1124
|
---
|
|
831
1125
|
|
|
832
1126
|
### Schema Functions
|
|
@@ -1028,6 +1322,40 @@ const emailColumn = column.text().validate((val) => { /* ... */ });
|
|
|
1028
1322
|
const validatorFn = emailColumn[ValidateFn]; // Function reference
|
|
1029
1323
|
```
|
|
1030
1324
|
|
|
1325
|
+
#### `onUpdate<T>(updater: (currentValue: T) => T): Column`
|
|
1326
|
+
|
|
1327
|
+
Sets a function to auto-update the column value during update operations.
|
|
1328
|
+
|
|
1329
|
+
```typescript
|
|
1330
|
+
const schema = defineSchema({
|
|
1331
|
+
users: {
|
|
1332
|
+
id: column.int().pk().auto(),
|
|
1333
|
+
name: column.text(),
|
|
1334
|
+
updatedAt: column.timestamp().onUpdate(() => getTimestamp()),
|
|
1335
|
+
},
|
|
1336
|
+
});
|
|
1337
|
+
```
|
|
1338
|
+
|
|
1339
|
+
> **Note:**
|
|
1340
|
+
>
|
|
1341
|
+
> - The updater function is called automatically during update operations.
|
|
1342
|
+
> - **Important**: It overrides any value provided during updates.
|
|
1343
|
+
> - It receives the current value of the column and should return the updated value.
|
|
1344
|
+
> - This is useful for fields like `"updatedAt"` timestamps that need to be refreshed on each update.
|
|
1345
|
+
> - If multiple updaters are chained, only the last one is used.
|
|
1346
|
+
> - Should not be used with auto-generated indexed columns like primary keys.
|
|
1347
|
+
> - The updated value is validated according to the column's type and custom validators (if any).
|
|
1348
|
+
|
|
1349
|
+
**Access the `OnUpdate` symbol (advanced):**
|
|
1350
|
+
|
|
1351
|
+
```typescript
|
|
1352
|
+
import { OnUpdate } from 'locality-idb';
|
|
1353
|
+
|
|
1354
|
+
// Access updater function programmatically
|
|
1355
|
+
const updatedAtColumn = column.timestamp().onUpdate(() => getTimestamp());
|
|
1356
|
+
const updaterFn = updatedAtColumn[OnUpdate]; // Function reference
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1031
1359
|
---
|
|
1032
1360
|
|
|
1033
1361
|
### Query Methods
|
|
@@ -1329,6 +1657,86 @@ isTimestamp('invalid'); // false
|
|
|
1329
1657
|
isTimestamp(123); // false
|
|
1330
1658
|
```
|
|
1331
1659
|
|
|
1660
|
+
#### `isUUID(value: unknown): value is UUID<UUIDVersion>`
|
|
1661
|
+
|
|
1662
|
+
Checks if a value is a valid UUID string (v1, v4, or v5).
|
|
1663
|
+
|
|
1664
|
+
**Parameters:**
|
|
1665
|
+
|
|
1666
|
+
- `value`: The value to check
|
|
1667
|
+
|
|
1668
|
+
**Returns:** `true` if the value is a valid UUID, otherwise `false`
|
|
1669
|
+
|
|
1670
|
+
**Example:**
|
|
1671
|
+
|
|
1672
|
+
```typescript
|
|
1673
|
+
import { isUUID } from 'locality-idb';
|
|
1674
|
+
|
|
1675
|
+
// Valid UUIDs
|
|
1676
|
+
isUUID('d9428888-122b-11e8-b642-0ed5f89f718b'); // true (v1)
|
|
1677
|
+
isUUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8'); // true (v1)
|
|
1678
|
+
isUUID('550e8400-e29b-41d4-a716-446655440000'); // true (v4)
|
|
1679
|
+
|
|
1680
|
+
// Invalid formats
|
|
1681
|
+
isUUID('not-a-uuid'); // false
|
|
1682
|
+
isUUID('12345678-1234-1234-1234-123456789abc'); // false (invalid version)
|
|
1683
|
+
isUUID(123456789); // false
|
|
1684
|
+
```
|
|
1685
|
+
|
|
1686
|
+
#### `isEmail(value: unknown): value is EmailString`
|
|
1687
|
+
|
|
1688
|
+
Checks if a value is a valid email string.
|
|
1689
|
+
|
|
1690
|
+
**Parameters:**
|
|
1691
|
+
|
|
1692
|
+
- `value`: The value to check
|
|
1693
|
+
|
|
1694
|
+
**Returns:** `true` if the value is a valid email, otherwise `false`
|
|
1695
|
+
|
|
1696
|
+
**Example:**
|
|
1697
|
+
|
|
1698
|
+
```typescript
|
|
1699
|
+
import { isEmail } from 'locality-idb';
|
|
1700
|
+
|
|
1701
|
+
// Valid emails
|
|
1702
|
+
isEmail('user@example.com'); // true
|
|
1703
|
+
isEmail('first.last@sub.domain.co.uk'); // true
|
|
1704
|
+
isEmail('user+filter@example.org'); // true
|
|
1705
|
+
|
|
1706
|
+
// Invalid emails
|
|
1707
|
+
isEmail('plain-string'); // false
|
|
1708
|
+
isEmail('user@.com'); // false
|
|
1709
|
+
isEmail('@example.com'); // false
|
|
1710
|
+
isEmail('user@domain'); // false
|
|
1711
|
+
isEmail(12345); // false
|
|
1712
|
+
```
|
|
1713
|
+
|
|
1714
|
+
#### `isURL(value: unknown): value is URLString`
|
|
1715
|
+
|
|
1716
|
+
Checks if a value is a valid URL string.
|
|
1717
|
+
|
|
1718
|
+
**Parameters:**
|
|
1719
|
+
|
|
1720
|
+
- `value`: The value to check
|
|
1721
|
+
|
|
1722
|
+
**Returns:** `true` if the value is a valid URL, otherwise `false`
|
|
1723
|
+
|
|
1724
|
+
**Example:**
|
|
1725
|
+
|
|
1726
|
+
```typescript
|
|
1727
|
+
import { isURL } from 'locality-idb';
|
|
1728
|
+
|
|
1729
|
+
// Valid URLs
|
|
1730
|
+
isURL('https://example.com'); // true
|
|
1731
|
+
isURL('ftp://files.test/path?q=1'); // true
|
|
1732
|
+
|
|
1733
|
+
// Invalid URLs
|
|
1734
|
+
isURL('example.com'); // false (missing protocol)
|
|
1735
|
+
isURL('http://'); // false (empty domain)
|
|
1736
|
+
isURL('//cdn.domain/image.png'); // false (`URL` constructor cannot parse it)
|
|
1737
|
+
isURL(123456); // false
|
|
1738
|
+
```
|
|
1739
|
+
|
|
1332
1740
|
#### `openDBWithStores(name: string, stores: StoreConfig[], version?: number): Promise<IDBDatabase>`
|
|
1333
1741
|
|
|
1334
1742
|
Opens an IndexedDB database with specified stores (low-level API).
|
|
@@ -1530,6 +1938,48 @@ type Selected = SelectFields<User, { name: true; email: true }>;
|
|
|
1530
1938
|
// { name: string; email: string }
|
|
1531
1939
|
```
|
|
1532
1940
|
|
|
1941
|
+
### Transaction & Export Types
|
|
1942
|
+
|
|
1943
|
+
```typescript
|
|
1944
|
+
import type {
|
|
1945
|
+
TransactionContext,
|
|
1946
|
+
TransactionCallback,
|
|
1947
|
+
ExportOptions,
|
|
1948
|
+
ExportData,
|
|
1949
|
+
} from 'locality-idb';
|
|
1950
|
+
|
|
1951
|
+
// TransactionContext: Context object provided to transaction callback
|
|
1952
|
+
type TxContext = TransactionContext<Schema, TableName, ['users', 'posts']>;
|
|
1953
|
+
|
|
1954
|
+
// TransactionCallback: Function signature for transaction operations
|
|
1955
|
+
type TxCallback = TransactionCallback<Schema, TableName, ['users']>;
|
|
1956
|
+
|
|
1957
|
+
// ExportOptions: Configuration options for database export
|
|
1958
|
+
type ExportOpts = ExportOptions<'users' | 'posts'>;
|
|
1959
|
+
/*
|
|
1960
|
+
{
|
|
1961
|
+
tables?: ('users' | 'posts')[];
|
|
1962
|
+
filename?: string;
|
|
1963
|
+
pretty?: boolean;
|
|
1964
|
+
includeMetadata?: boolean;
|
|
1965
|
+
}
|
|
1966
|
+
*/
|
|
1967
|
+
|
|
1968
|
+
// ExportData: Structure of exported database data
|
|
1969
|
+
type Exported = ExportData;
|
|
1970
|
+
/*
|
|
1971
|
+
{
|
|
1972
|
+
metadata?: {
|
|
1973
|
+
dbName: string;
|
|
1974
|
+
version: number;
|
|
1975
|
+
exportedAt: Timestamp;
|
|
1976
|
+
tables: string[];
|
|
1977
|
+
};
|
|
1978
|
+
data: Record<string, GenericObject[]>;
|
|
1979
|
+
}
|
|
1980
|
+
*/
|
|
1981
|
+
```
|
|
1982
|
+
|
|
1533
1983
|
---
|
|
1534
1984
|
|
|
1535
1985
|
## 📄 License
|