locality-idb 1.5.4 β†’ 1.5.7

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 CHANGED
@@ -26,6 +26,15 @@
26
26
 
27
27
  ---
28
28
 
29
+ ## Why Not Raw IndexedDB?
30
+
31
+ If you're weighing using `Locality IDB` vs. the raw `IndexedDB` API:
32
+
33
+ - **Type safety**: schema-driven types reduce runtime errors.
34
+ - **Query ergonomics**: SQL-like query builder replaces verbose cursor boilerplate.
35
+ - **Validation built-in**: column type checks and custom validators run automatically.
36
+ - **Consistency**: reusable schema + shared helpers keep data access uniform.
37
+
29
38
  ## πŸ“‹ Table of Contents
30
39
 
31
40
  - [Features](#-features)
@@ -56,6 +65,7 @@
56
65
  - [Utility Functions](#utility-functions)
57
66
  - [Validation](#validation)
58
67
  - [Type System](#-type-system)
68
+ - [FAQ / Common Pitfalls](#-faq--common-pitfalls)
59
69
  - [License](#-license)
60
70
 
61
71
  ---
@@ -64,16 +74,16 @@
64
74
 
65
75
  - 🎯 **Type-Safe**: Full TypeScript support with automatic type inference
66
76
  - πŸ” **SQL-like Queries**: Familiar query syntax inspired by Drizzle ORM
67
- - πŸš€ **Modern API**: Clean and intuitive interface for IndexedDB operations
77
+ - πŸš€ **Modern API**: Clean and intuitive interface for `IndexedDB` operations
68
78
  - πŸ“¦ **Zero Dependencies**: Lightweight with only development dependencies
69
79
  - πŸ”„ **Auto-Generation**: Automatic UUID and timestamp generation
70
80
  - 🎨 **Schema-First**: Define your database schema with a simple, declarative API
71
81
  - πŸ› οΈ **Rich Column Types**: Support for various data types including custom types
72
- - βœ… **Built-in Validation**: Automatic data type validation for built-in column types during insert and update operations
82
+ - βœ… **Built-in Validation**: Validation for built-in column types during insert and update operations
73
83
  - πŸ”§ **Custom Validators**: Define custom validation logic for columns to enforce complex rules
74
- - πŸ”’ **Atomic Transactions**: Execute multiple operations across tables with automatic rollback on failure
84
+ - πŸ”’ **Transactions**: Execute multiple operations across tables with automatic rollback on failure
75
85
  - πŸ“€ **Database Export**: Export database data as JSON for backup, migration, or debugging
76
- - πŸ“₯ **Database Import**: Import exported data with merge, replace, or upsert modes
86
+ - πŸ“₯ **Database Import**: Import exported data with `'merge'`, `'replace'`, or `'upsert'` modes
77
87
 
78
88
  ---
79
89
 
@@ -322,9 +332,10 @@ const schema = defineSchema({
322
332
  > - Auto-generated values can be overridden by providing explicit values during insert.
323
333
  > - Use the `default()` modifier to set custom default values instead of auto-generated ones.
324
334
  > - Auto-generated values are generated at runtime during insert operations.
335
+ > - `onUpdate()` modifier can be used to auto-update values on update operations (e.g. `updatedAt` timestamp).
325
336
  > - Type extensions for `uuid` and `timestamp` are not applicable since they are already typed.
326
337
  > - 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).
327
- > - 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.
338
+ > - For custom timestamp formats, use date libraries like [`Chronos`](https://toolbox.nazmul-nhb.dev/docs/classes/Chronos) or [`getTimestamp`](https://toolbox.nazmul-nhb.dev/docs/utilities/date/getTimestamp) (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.
328
339
 
329
340
  ##### Boolean Types (`bool`, `boolean`)
330
341
 
@@ -2214,16 +2225,13 @@ type UserRow = $InferRow<typeof schema.users.columns>;
2214
2225
 
2215
2226
  ### Branded Types
2216
2227
 
2217
- Locality IDB uses branded types for better type safety:
2228
+ Locality IDB uses branded type for UUIDv4 for better type safety:
2218
2229
 
2219
2230
  ```typescript
2220
- import type { UUID, Timestamp } from 'locality-idb';
2231
+ import type { UUID } from 'locality-idb';
2221
2232
 
2222
2233
  // UUID types are branded with their version
2223
2234
  type UserId = UUID<'v4'>; // Branded UUID v4
2224
-
2225
- // Timestamps are branded ISO 8601 strings
2226
- type CreatedAt = Timestamp; // Branded timestamp string
2227
2235
  ```
2228
2236
 
2229
2237
  ### Helper Types
@@ -2325,6 +2333,15 @@ type PagedResult = PageResult<User, null>;
2325
2333
 
2326
2334
  ---
2327
2335
 
2336
+ ## ❓ FAQ / Common Pitfalls
2337
+
2338
+ - **Schema changes aren’t automatic**: any schema change should bump the database `version` so the upgrade path runs.
2339
+ - **Index queries require indexes**: `where('field', value)` only works for primary keys or fields defined with `.index()` or `.unique()`.
2340
+ - **Predicate filters are in-memory**: `where((row) => ...)` filters client-side after fetching rows, so prefer indexes for large datasets.
2341
+ - **IndexedDB is browser-only**: calls will fail in SSR/Node environments without a shim.
2342
+
2343
+ ---
2344
+
2328
2345
  ## πŸ“„ License
2329
2346
 
2330
2347
  [MIT](LICENSE) Β© [Nazmul Hassan](https://github.com/nazmul-nhb)
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/primitives.js
3
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/primitives.js
4
4
  function isNumber(value) {
5
5
  return typeof value === "number" && Number.isFinite(value);
6
6
  }
@@ -24,7 +24,7 @@ function isNonEmptyString(value) {
24
24
  }
25
25
 
26
26
  //#endregion
27
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/non-primitives.js
27
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/non-primitives.js
28
28
  function isArray(value) {
29
29
  return Array.isArray(value);
30
30
  }
@@ -54,13 +54,13 @@ function isMap(value) {
54
54
  }
55
55
 
56
56
  //#endregion
57
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/string/utilities.js
57
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/string/utilities.js
58
58
  const extractNumbersFromString = (input) => {
59
59
  return (input.match(/\d+/g) || [])?.map(Number);
60
60
  };
61
61
 
62
62
  //#endregion
63
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/specials.js
63
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/specials.js
64
64
  function isEmail$1(value) {
65
65
  return isString(value) && /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value);
66
66
  }
@@ -82,7 +82,7 @@ function isNumericString(value) {
82
82
  }
83
83
 
84
84
  //#endregion
85
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/array/sort.js
85
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/array/sort.js
86
86
  function naturalSort(a, b, options) {
87
87
  const { caseInsensitive = true, localeAware = false } = options || {};
88
88
  const _createChunks = (str) => {
@@ -151,7 +151,7 @@ function sortAnArray(array, options) {
151
151
 
152
152
  //#endregion
153
153
  //#region src/core.ts
154
- /** Symbol key for column column data type */
154
+ /** Symbol key for column data type */
155
155
  const ColumnType = Symbol("ColumnType");
156
156
  /** Symbol key for primary key marker */
157
157
  const IsPrimaryKey = Symbol("IsPrimaryKey");
@@ -401,7 +401,7 @@ function uuidV4(uppercase = false) {
401
401
  * * Get current timestamp in ISO 8601 format
402
402
  * @param value Optional date input (string, number, or Date object). Defaults to {@link Date new Date()}
403
403
  * @remarks If the provided value is invalid, the current date and time will be used.
404
- * @return Timestamp string in ISO 8601 format
404
+ * @returns Timestamp string in ISO 8601 format
405
405
  */
406
406
  function getTimestamp(value) {
407
407
  let date = value instanceof Date ? value : new Date(isNonEmptyString(value) ? value.replace(/['"]/g, "") : value ?? Date.now());
@@ -705,7 +705,7 @@ var SelectQuery = class {
705
705
  return this;
706
706
  }
707
707
  /**
708
- * @instance Order results by specified key and direction
708
+ * @instance Order results by specified key and direction
709
709
  * @param key Key to order by
710
710
  * @param dir Direction: 'asc' | 'desc' (default: 'asc')
711
711
  *
@@ -1395,7 +1395,7 @@ var Locality = class Locality {
1395
1395
  /**
1396
1396
  * @instance Select records from a table.
1397
1397
  * @param table Table name.
1398
- * @returns
1398
+ * @returns Select query builder for the table.
1399
1399
  */
1400
1400
  from(table) {
1401
1401
  return new SelectQuery(table, () => this.#db, this.#readyPromise);
@@ -1575,7 +1575,7 @@ var Locality = class Locality {
1575
1575
  * }),
1576
1576
  * });
1577
1577
  *
1578
- * // Export all tables pretty-printed pretty-printed with default filename
1578
+ * // Export all tables pretty-printed with default filename
1579
1579
  * await db.export();
1580
1580
  *
1581
1581
  * // Export specific tables pretty-printed with custom filename
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/core.d.ts
2
- /** Symbol key for column column data type */
2
+ /** Symbol key for column data type */
3
3
  declare const ColumnType: unique symbol;
4
4
  /** Symbol key for primary key marker */
5
5
  declare const IsPrimaryKey: unique symbol;
@@ -162,7 +162,7 @@ declare class SelectQuery<T extends GenericObject, S extends Partial<Record<stri
162
162
  */
163
163
  where<IdxKey extends $InferPrimaryKey<Tbl['columns']> | $InferIndex<Tbl['columns']>>(indexName: IdxKey, query: IDBKeyRange | T[IdxKey]): this;
164
164
  /**
165
- * @instance Order results by specified key and direction
165
+ * @instance Order results by specified key and direction
166
166
  * @param key Key to order by
167
167
  * @param dir Direction: 'asc' | 'desc' (default: 'asc')
168
168
  *
@@ -300,9 +300,9 @@ type $Brand<B> = {
300
300
  /**
301
301
  * * Creates a branded version of a base type by intersecting it with a unique compile-time marker.
302
302
  *
303
- * @param T - Base type to brand.
304
- * @param B - Brand identifier used to distinguish this type from structurally similar types.
305
-
303
+ * @typeParam T - Base type to brand.
304
+ * @typeParam B - Brand identifier used to distinguish this type from structurally similar types.
305
+ *
306
306
  * @remarks Useful for preventing accidental mixing of structurally identical types, while keeping the runtime value unchanged.
307
307
  *
308
308
  * @example
@@ -313,7 +313,10 @@ type Branded<T, B> = T & $Brand<B>;
313
313
  /**
314
314
  * * Broadens a literal union (typically `string` or `number`) to also accept any other value of the base type, without losing IntelliSense autocomplete for the provided literals.
315
315
  *
316
- * *This is especially useful in API design where you want to provide suggestions for common options but still allow flexibility for custom user-defined values.*
316
+ * @remarks
317
+ * This is especially useful in API design where you want to provide suggestions for common options but still allow flexibility for custom user-defined values.
318
+ *
319
+ * Technically, this uses intersection with primitive base types (`string & {}` or `number & {}`) to retain IntelliSense while avoiding type narrowing.
317
320
  *
318
321
  * @example
319
322
  * // βœ… String literal usage
@@ -332,8 +335,6 @@ type Branded<T, B> = T & $Brand<B>;
332
335
  * const m2: Mixed = 2; // βœ…
333
336
  * const m3: Mixed = 'anything'; // βœ…
334
337
  * const m4: Mixed = 123; // βœ…
335
- *
336
- * @note Technically, this uses intersection with primitive base types (`string & {}` or `number & {}`) to retain IntelliSense while avoiding type narrowing.
337
338
  */
338
339
  type LooseLiteral<T extends string | number> = T | (T extends string ? string & {} : number & {});
339
340
  type ForcedAny = any;
@@ -365,7 +366,7 @@ type $UnionToTuple<T, L = $LastOf<T>> = [T] extends [never] ? [] : [...$UnionToT
365
366
  * - If `T` is a single type, it produces a one-element tuple `[T]`.
366
367
  * - If `T` is `never`, it produces an empty tuple `[]`.
367
368
  *
368
- * @param T - The type to convert into a tuple.
369
+ * @typeParam T - The type to convert into a tuple.
369
370
  * @returns A tuple type containing the elements of `T`.
370
371
  *
371
372
  * @example
@@ -383,7 +384,7 @@ type Tuple<T> = [T] extends [never] ? [] : $UnionToTuple<T>;
383
384
  * - Useful when you want to preserve all possible union members as a tuple literal instead of an array.
384
385
  * - For converting any type to tuple use {@link Tuple}.
385
386
  *
386
- * @param T - An array type whose element type is a union.
387
+ * @typeParam T - An array type whose element type is a union.
387
388
  * @returns A tuple type containing each member of the union in order.
388
389
  *
389
390
  * @example
@@ -435,7 +436,7 @@ type AdvancedTypes = Array<unknown> | File | FileList | Blob | Date | RegExp | C
435
436
  /**
436
437
  * * Extracts the parameters of the first overload of a function type `T`.
437
438
  *
438
- * @template T - The function type to extract parameters from.
439
+ * @typeParam T - The function type to extract parameters from.
439
440
  *
440
441
  * @returns A tuple type representing the parameters of the first overload of `T`.
441
442
  *
@@ -457,8 +458,8 @@ type FirstOverloadParams<T> = T extends ({
457
458
  /**
458
459
  * * Maps all values of object `T` to a fixed type `R`, keeping original keys.
459
460
  *
460
- * @template T - The source object type.
461
- * @template R - The replacement value type.
461
+ * @typeParam T - The source object type.
462
+ * @typeParam R - The replacement value type.
462
463
  *
463
464
  * @example
464
465
  * type T = { name: string; age: number };
@@ -488,14 +489,15 @@ type PageResult<T, Selection extends Partial<Record<keyof T, boolean>> | null> =
488
489
  /** Retrieved items for the current page */items: Selection extends null ? T[] : SelectFields<T, Extract<Selection, object>>[]; /** Cursor key for the next page, if more results are available */
489
490
  nextCursor: Maybe<IDBValidKey>;
490
491
  };
491
- /** - Extract only primitive keys from an object, including nested dot-notation keys. */
492
+ /** Extract only primitive keys from an object, including nested dot-notation keys. */
492
493
  type NestedPrimitiveKey<T> = T extends AdvancedTypes ? never : T extends GenericObject ? { [K in keyof T & string]: T[K] extends Function ? never : T[K] extends NormalPrimitive ? K : T[K] extends GenericObject ? `${K}.${NestedPrimitiveKey<T[K]>}` : never }[keyof T & string] : never;
493
- /** - Generic object but with `any` value */
494
+ /** Generic object but with `any` value */
494
495
  type GenericObject = Record<string, any>;
495
496
  /**
496
497
  * * Forces TypeScript to simplify a complex or inferred type into a more readable flat object.
497
498
  *
498
- * *Useful when working with utility types like `Merge`, `Omit`, etc., that produce deeply nested or unresolved intersections.*
499
+ * @remarks
500
+ * Useful when working with utility types like `Merge`, `Omit`, etc., that produce deeply nested or unresolved intersections.
499
501
  *
500
502
  * @example
501
503
  * type A = { a: number };
@@ -574,7 +576,7 @@ type $InferUUID<T extends ColumnDefinition> = { [K in keyof T]: T[K] extends Col
574
576
  /** Finds the field name with {@link Timestamp} type. */
575
577
  type $InferTimestamp<T extends ColumnDefinition> = { [K in keyof T]: T[K] extends Column<infer C, TypeName> ? C extends Timestamp ? K : never : never }[keyof T];
576
578
  /** Timestamp string type in ISO 8601 format */
577
- type Timestamp = Branded<string, 'Timestamp'>;
579
+ type Timestamp = `${number}-${number}-${number}T${number}:${number}:${number}.${number}${'Z' | `${'+' | '-'}${number}:${number}`}`;
578
580
  /** Sort direction type for ordering queries */
579
581
  type SortDirection = 'asc' | 'desc';
580
582
  /** Predicate function type for WHERE clauses in queries */
@@ -696,7 +698,7 @@ declare class Locality<DBName extends string = string, Version extends number =
696
698
  /**
697
699
  * @instance Select records from a table.
698
700
  * @param table Table name.
699
- * @returns
701
+ * @returns Select query builder for the table.
700
702
  */
701
703
  from<T extends TName, Row extends $InferRow<Schema[T]['columns']>>(table: T): SelectQuery<Row, null, Schema[T]>;
702
704
  /**
@@ -824,7 +826,7 @@ declare class Locality<DBName extends string = string, Version extends number =
824
826
  * }),
825
827
  * });
826
828
  *
827
- * // Export all tables pretty-printed pretty-printed with default filename
829
+ * // Export all tables pretty-printed with default filename
828
830
  * await db.export();
829
831
  *
830
832
  * // Export specific tables pretty-printed with custom filename
@@ -1162,7 +1164,7 @@ declare const column: {
1162
1164
  * - This column type is used for storing date and time information in ISO 8601 format.
1163
1165
  * - Automatically generates the current timestamp when no value is provided.
1164
1166
  */
1165
- timestamp: () => Column<Timestamp, "timestamp">;
1167
+ timestamp: () => Column<`${number}-${number}-${number}T${number}:${number}:${number}.${number}Z` | `${number}-${number}-${number}T${number}:${number}:${number}.${number}+${number}:${number}` | `${number}-${number}-${number}T${number}:${number}:${number}.${number}-${number}:${number}`, "timestamp">;
1166
1168
  /**
1167
1169
  * Creates an email column.
1168
1170
  * @returns A new {@link Column} instance for emails.
@@ -1372,7 +1374,7 @@ declare function uuidV4(uppercase?: boolean): UUID<'v4'>;
1372
1374
  * * Get current timestamp in ISO 8601 format
1373
1375
  * @param value Optional date input (string, number, or Date object). Defaults to {@link Date new Date()}
1374
1376
  * @remarks If the provided value is invalid, the current date and time will be used.
1375
- * @return Timestamp string in ISO 8601 format
1377
+ * @returns Timestamp string in ISO 8601 format
1376
1378
  */
1377
1379
  declare function getTimestamp(value?: string | number | Date): Timestamp;
1378
1380
  /**
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/core.d.ts
2
- /** Symbol key for column column data type */
2
+ /** Symbol key for column data type */
3
3
  declare const ColumnType: unique symbol;
4
4
  /** Symbol key for primary key marker */
5
5
  declare const IsPrimaryKey: unique symbol;
@@ -162,7 +162,7 @@ declare class SelectQuery<T extends GenericObject, S extends Partial<Record<stri
162
162
  */
163
163
  where<IdxKey extends $InferPrimaryKey<Tbl['columns']> | $InferIndex<Tbl['columns']>>(indexName: IdxKey, query: IDBKeyRange | T[IdxKey]): this;
164
164
  /**
165
- * @instance Order results by specified key and direction
165
+ * @instance Order results by specified key and direction
166
166
  * @param key Key to order by
167
167
  * @param dir Direction: 'asc' | 'desc' (default: 'asc')
168
168
  *
@@ -300,9 +300,9 @@ type $Brand<B> = {
300
300
  /**
301
301
  * * Creates a branded version of a base type by intersecting it with a unique compile-time marker.
302
302
  *
303
- * @param T - Base type to brand.
304
- * @param B - Brand identifier used to distinguish this type from structurally similar types.
305
-
303
+ * @typeParam T - Base type to brand.
304
+ * @typeParam B - Brand identifier used to distinguish this type from structurally similar types.
305
+ *
306
306
  * @remarks Useful for preventing accidental mixing of structurally identical types, while keeping the runtime value unchanged.
307
307
  *
308
308
  * @example
@@ -313,7 +313,10 @@ type Branded<T, B> = T & $Brand<B>;
313
313
  /**
314
314
  * * Broadens a literal union (typically `string` or `number`) to also accept any other value of the base type, without losing IntelliSense autocomplete for the provided literals.
315
315
  *
316
- * *This is especially useful in API design where you want to provide suggestions for common options but still allow flexibility for custom user-defined values.*
316
+ * @remarks
317
+ * This is especially useful in API design where you want to provide suggestions for common options but still allow flexibility for custom user-defined values.
318
+ *
319
+ * Technically, this uses intersection with primitive base types (`string & {}` or `number & {}`) to retain IntelliSense while avoiding type narrowing.
317
320
  *
318
321
  * @example
319
322
  * // βœ… String literal usage
@@ -332,8 +335,6 @@ type Branded<T, B> = T & $Brand<B>;
332
335
  * const m2: Mixed = 2; // βœ…
333
336
  * const m3: Mixed = 'anything'; // βœ…
334
337
  * const m4: Mixed = 123; // βœ…
335
- *
336
- * @note Technically, this uses intersection with primitive base types (`string & {}` or `number & {}`) to retain IntelliSense while avoiding type narrowing.
337
338
  */
338
339
  type LooseLiteral<T extends string | number> = T | (T extends string ? string & {} : number & {});
339
340
  type ForcedAny = any;
@@ -365,7 +366,7 @@ type $UnionToTuple<T, L = $LastOf<T>> = [T] extends [never] ? [] : [...$UnionToT
365
366
  * - If `T` is a single type, it produces a one-element tuple `[T]`.
366
367
  * - If `T` is `never`, it produces an empty tuple `[]`.
367
368
  *
368
- * @param T - The type to convert into a tuple.
369
+ * @typeParam T - The type to convert into a tuple.
369
370
  * @returns A tuple type containing the elements of `T`.
370
371
  *
371
372
  * @example
@@ -383,7 +384,7 @@ type Tuple<T> = [T] extends [never] ? [] : $UnionToTuple<T>;
383
384
  * - Useful when you want to preserve all possible union members as a tuple literal instead of an array.
384
385
  * - For converting any type to tuple use {@link Tuple}.
385
386
  *
386
- * @param T - An array type whose element type is a union.
387
+ * @typeParam T - An array type whose element type is a union.
387
388
  * @returns A tuple type containing each member of the union in order.
388
389
  *
389
390
  * @example
@@ -435,7 +436,7 @@ type AdvancedTypes = Array<unknown> | File | FileList | Blob | Date | RegExp | C
435
436
  /**
436
437
  * * Extracts the parameters of the first overload of a function type `T`.
437
438
  *
438
- * @template T - The function type to extract parameters from.
439
+ * @typeParam T - The function type to extract parameters from.
439
440
  *
440
441
  * @returns A tuple type representing the parameters of the first overload of `T`.
441
442
  *
@@ -457,8 +458,8 @@ type FirstOverloadParams<T> = T extends ({
457
458
  /**
458
459
  * * Maps all values of object `T` to a fixed type `R`, keeping original keys.
459
460
  *
460
- * @template T - The source object type.
461
- * @template R - The replacement value type.
461
+ * @typeParam T - The source object type.
462
+ * @typeParam R - The replacement value type.
462
463
  *
463
464
  * @example
464
465
  * type T = { name: string; age: number };
@@ -488,14 +489,15 @@ type PageResult<T, Selection extends Partial<Record<keyof T, boolean>> | null> =
488
489
  /** Retrieved items for the current page */items: Selection extends null ? T[] : SelectFields<T, Extract<Selection, object>>[]; /** Cursor key for the next page, if more results are available */
489
490
  nextCursor: Maybe<IDBValidKey>;
490
491
  };
491
- /** - Extract only primitive keys from an object, including nested dot-notation keys. */
492
+ /** Extract only primitive keys from an object, including nested dot-notation keys. */
492
493
  type NestedPrimitiveKey<T> = T extends AdvancedTypes ? never : T extends GenericObject ? { [K in keyof T & string]: T[K] extends Function ? never : T[K] extends NormalPrimitive ? K : T[K] extends GenericObject ? `${K}.${NestedPrimitiveKey<T[K]>}` : never }[keyof T & string] : never;
493
- /** - Generic object but with `any` value */
494
+ /** Generic object but with `any` value */
494
495
  type GenericObject = Record<string, any>;
495
496
  /**
496
497
  * * Forces TypeScript to simplify a complex or inferred type into a more readable flat object.
497
498
  *
498
- * *Useful when working with utility types like `Merge`, `Omit`, etc., that produce deeply nested or unresolved intersections.*
499
+ * @remarks
500
+ * Useful when working with utility types like `Merge`, `Omit`, etc., that produce deeply nested or unresolved intersections.
499
501
  *
500
502
  * @example
501
503
  * type A = { a: number };
@@ -574,7 +576,7 @@ type $InferUUID<T extends ColumnDefinition> = { [K in keyof T]: T[K] extends Col
574
576
  /** Finds the field name with {@link Timestamp} type. */
575
577
  type $InferTimestamp<T extends ColumnDefinition> = { [K in keyof T]: T[K] extends Column<infer C, TypeName> ? C extends Timestamp ? K : never : never }[keyof T];
576
578
  /** Timestamp string type in ISO 8601 format */
577
- type Timestamp = Branded<string, 'Timestamp'>;
579
+ type Timestamp = `${number}-${number}-${number}T${number}:${number}:${number}.${number}${'Z' | `${'+' | '-'}${number}:${number}`}`;
578
580
  /** Sort direction type for ordering queries */
579
581
  type SortDirection = 'asc' | 'desc';
580
582
  /** Predicate function type for WHERE clauses in queries */
@@ -696,7 +698,7 @@ declare class Locality<DBName extends string = string, Version extends number =
696
698
  /**
697
699
  * @instance Select records from a table.
698
700
  * @param table Table name.
699
- * @returns
701
+ * @returns Select query builder for the table.
700
702
  */
701
703
  from<T extends TName, Row extends $InferRow<Schema[T]['columns']>>(table: T): SelectQuery<Row, null, Schema[T]>;
702
704
  /**
@@ -824,7 +826,7 @@ declare class Locality<DBName extends string = string, Version extends number =
824
826
  * }),
825
827
  * });
826
828
  *
827
- * // Export all tables pretty-printed pretty-printed with default filename
829
+ * // Export all tables pretty-printed with default filename
828
830
  * await db.export();
829
831
  *
830
832
  * // Export specific tables pretty-printed with custom filename
@@ -1162,7 +1164,7 @@ declare const column: {
1162
1164
  * - This column type is used for storing date and time information in ISO 8601 format.
1163
1165
  * - Automatically generates the current timestamp when no value is provided.
1164
1166
  */
1165
- timestamp: () => Column<Timestamp, "timestamp">;
1167
+ timestamp: () => Column<`${number}-${number}-${number}T${number}:${number}:${number}.${number}Z` | `${number}-${number}-${number}T${number}:${number}:${number}.${number}+${number}:${number}` | `${number}-${number}-${number}T${number}:${number}:${number}.${number}-${number}:${number}`, "timestamp">;
1166
1168
  /**
1167
1169
  * Creates an email column.
1168
1170
  * @returns A new {@link Column} instance for emails.
@@ -1372,7 +1374,7 @@ declare function uuidV4(uppercase?: boolean): UUID<'v4'>;
1372
1374
  * * Get current timestamp in ISO 8601 format
1373
1375
  * @param value Optional date input (string, number, or Date object). Defaults to {@link Date new Date()}
1374
1376
  * @remarks If the provided value is invalid, the current date and time will be used.
1375
- * @return Timestamp string in ISO 8601 format
1377
+ * @returns Timestamp string in ISO 8601 format
1376
1378
  */
1377
1379
  declare function getTimestamp(value?: string | number | Date): Timestamp;
1378
1380
  /**
@@ -2,7 +2,7 @@ var LocalityIDB = (function(exports) {
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/primitives.js
5
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/primitives.js
6
6
  function isNumber(value) {
7
7
  return typeof value === "number" && Number.isFinite(value);
8
8
  }
@@ -26,7 +26,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
26
26
  }
27
27
 
28
28
  //#endregion
29
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/non-primitives.js
29
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/non-primitives.js
30
30
  function isArray(value) {
31
31
  return Array.isArray(value);
32
32
  }
@@ -56,13 +56,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
56
56
  }
57
57
 
58
58
  //#endregion
59
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/string/utilities.js
59
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/string/utilities.js
60
60
  const extractNumbersFromString = (input) => {
61
61
  return (input.match(/\d+/g) || [])?.map(Number);
62
62
  };
63
63
 
64
64
  //#endregion
65
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/specials.js
65
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/specials.js
66
66
  function isEmail$1(value) {
67
67
  return isString(value) && /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value);
68
68
  }
@@ -84,7 +84,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
84
84
  }
85
85
 
86
86
  //#endregion
87
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/array/sort.js
87
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/array/sort.js
88
88
  function naturalSort(a, b, options) {
89
89
  const { caseInsensitive = true, localeAware = false } = options || {};
90
90
  const _createChunks = (str) => {
@@ -153,7 +153,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
153
153
 
154
154
  //#endregion
155
155
  //#region src/core.ts
156
- /** Symbol key for column column data type */
156
+ /** Symbol key for column data type */
157
157
  const ColumnType = Symbol("ColumnType");
158
158
  /** Symbol key for primary key marker */
159
159
  const IsPrimaryKey = Symbol("IsPrimaryKey");
@@ -403,7 +403,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
403
403
  * * Get current timestamp in ISO 8601 format
404
404
  * @param value Optional date input (string, number, or Date object). Defaults to {@link Date new Date()}
405
405
  * @remarks If the provided value is invalid, the current date and time will be used.
406
- * @return Timestamp string in ISO 8601 format
406
+ * @returns Timestamp string in ISO 8601 format
407
407
  */
408
408
  function getTimestamp(value) {
409
409
  let date = value instanceof Date ? value : new Date(isNonEmptyString(value) ? value.replace(/['"]/g, "") : value ?? Date.now());
@@ -707,7 +707,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
707
707
  return this;
708
708
  }
709
709
  /**
710
- * @instance Order results by specified key and direction
710
+ * @instance Order results by specified key and direction
711
711
  * @param key Key to order by
712
712
  * @param dir Direction: 'asc' | 'desc' (default: 'asc')
713
713
  *
@@ -1397,7 +1397,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1397
1397
  /**
1398
1398
  * @instance Select records from a table.
1399
1399
  * @param table Table name.
1400
- * @returns
1400
+ * @returns Select query builder for the table.
1401
1401
  */
1402
1402
  from(table) {
1403
1403
  return new SelectQuery(table, () => this.#db, this.#readyPromise);
@@ -1577,7 +1577,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1577
1577
  * }),
1578
1578
  * });
1579
1579
  *
1580
- * // Export all tables pretty-printed pretty-printed with default filename
1580
+ * // Export all tables pretty-printed with default filename
1581
1581
  * await db.export();
1582
1582
  *
1583
1583
  * // Export specific tables pretty-printed with custom filename
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/primitives.js
1
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/primitives.js
2
2
  function isNumber(value) {
3
3
  return typeof value === "number" && Number.isFinite(value);
4
4
  }
@@ -22,7 +22,7 @@ function isNonEmptyString(value) {
22
22
  }
23
23
 
24
24
  //#endregion
25
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/non-primitives.js
25
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/non-primitives.js
26
26
  function isArray(value) {
27
27
  return Array.isArray(value);
28
28
  }
@@ -52,13 +52,13 @@ function isMap(value) {
52
52
  }
53
53
 
54
54
  //#endregion
55
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/string/utilities.js
55
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/string/utilities.js
56
56
  const extractNumbersFromString = (input) => {
57
57
  return (input.match(/\d+/g) || [])?.map(Number);
58
58
  };
59
59
 
60
60
  //#endregion
61
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/guards/specials.js
61
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/guards/specials.js
62
62
  function isEmail$1(value) {
63
63
  return isString(value) && /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value);
64
64
  }
@@ -80,7 +80,7 @@ function isNumericString(value) {
80
80
  }
81
81
 
82
82
  //#endregion
83
- //#region node_modules/.pnpm/nhb-toolbox@4.28.66/node_modules/nhb-toolbox/dist/esm/array/sort.js
83
+ //#region node_modules/.pnpm/nhb-toolbox@4.28.80/node_modules/nhb-toolbox/dist/esm/array/sort.js
84
84
  function naturalSort(a, b, options) {
85
85
  const { caseInsensitive = true, localeAware = false } = options || {};
86
86
  const _createChunks = (str) => {
@@ -149,7 +149,7 @@ function sortAnArray(array, options) {
149
149
 
150
150
  //#endregion
151
151
  //#region src/core.ts
152
- /** Symbol key for column column data type */
152
+ /** Symbol key for column data type */
153
153
  const ColumnType = Symbol("ColumnType");
154
154
  /** Symbol key for primary key marker */
155
155
  const IsPrimaryKey = Symbol("IsPrimaryKey");
@@ -399,7 +399,7 @@ function uuidV4(uppercase = false) {
399
399
  * * Get current timestamp in ISO 8601 format
400
400
  * @param value Optional date input (string, number, or Date object). Defaults to {@link Date new Date()}
401
401
  * @remarks If the provided value is invalid, the current date and time will be used.
402
- * @return Timestamp string in ISO 8601 format
402
+ * @returns Timestamp string in ISO 8601 format
403
403
  */
404
404
  function getTimestamp(value) {
405
405
  let date = value instanceof Date ? value : new Date(isNonEmptyString(value) ? value.replace(/['"]/g, "") : value ?? Date.now());
@@ -703,7 +703,7 @@ var SelectQuery = class {
703
703
  return this;
704
704
  }
705
705
  /**
706
- * @instance Order results by specified key and direction
706
+ * @instance Order results by specified key and direction
707
707
  * @param key Key to order by
708
708
  * @param dir Direction: 'asc' | 'desc' (default: 'asc')
709
709
  *
@@ -1393,7 +1393,7 @@ var Locality = class Locality {
1393
1393
  /**
1394
1394
  * @instance Select records from a table.
1395
1395
  * @param table Table name.
1396
- * @returns
1396
+ * @returns Select query builder for the table.
1397
1397
  */
1398
1398
  from(table) {
1399
1399
  return new SelectQuery(table, () => this.#db, this.#readyPromise);
@@ -1573,7 +1573,7 @@ var Locality = class Locality {
1573
1573
  * }),
1574
1574
  * });
1575
1575
  *
1576
- * // Export all tables pretty-printed pretty-printed with default filename
1576
+ * // Export all tables pretty-printed with default filename
1577
1577
  * await db.export();
1578
1578
  *
1579
1579
  * // Export specific tables pretty-printed with custom filename
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "locality-idb",
3
- "version": "1.5.4",
3
+ "version": "1.5.7",
4
4
  "description": "SQL-like query builder for IndexedDB with Drizzle-style API",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -47,16 +47,28 @@
47
47
  "package.json"
48
48
  ],
49
49
  "keywords": [
50
+ "indexeddb",
50
51
  "indexed-db",
52
+ "indexeddb-orm",
53
+ "indexed-db-orm",
51
54
  "sql",
52
- "drizzle",
53
55
  "db",
56
+ "orm",
57
+ "idb",
58
+ "idb-orm",
59
+ "typescript",
60
+ "typescript-orm",
61
+ "typescript-idb",
62
+ "typescript-indexeddb",
63
+ "typescript-indexed-db",
64
+ "locality-idb",
54
65
  "locality",
66
+ "drizzle",
55
67
  "database"
56
68
  ],
57
69
  "devDependencies": {
58
70
  "@eslint/js": "^9.39.2",
59
- "@types/node": "^25.2.0",
71
+ "@types/node": "^25.2.1",
60
72
  "@typescript-eslint/eslint-plugin": "^8.54.0",
61
73
  "@typescript-eslint/parser": "^8.54.0",
62
74
  "eslint": "^9.39.2",
@@ -64,7 +76,7 @@
64
76
  "eslint-plugin-prettier": "^5.5.5",
65
77
  "globals": "^17.3.0",
66
78
  "nhb-scripts": "^1.9.2",
67
- "nhb-toolbox": "^4.28.66",
79
+ "nhb-toolbox": "^4.28.80",
68
80
  "prettier": "^3.8.1",
69
81
  "tsdown": "^0.20.3",
70
82
  "typescript": "^5.9.3",
@@ -76,6 +88,7 @@
76
88
  "build": "tsdown",
77
89
  "dev:pkg": "tsdown --watch",
78
90
  "dev": "pnpm --dir demo run dev",
91
+ "install:demo": "pnpm --dir demo install",
79
92
  "build:demo": "pnpm --dir demo run build",
80
93
  "preview": "pnpm --dir demo run preview",
81
94
  "typecheck": "tsc --noEmit",