web-idb-client 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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +230 -0
  3. package/dist/client/index.d.ts +7 -0
  4. package/dist/client/index.js +12 -0
  5. package/dist/client/index.js.map +1 -0
  6. package/dist/client/indexed-db-client.d.ts +40 -0
  7. package/dist/client/indexed-db-client.js +211 -0
  8. package/dist/client/indexed-db-client.js.map +1 -0
  9. package/dist/client/mutations.d.ts +12 -0
  10. package/dist/client/mutations.js +3 -0
  11. package/dist/client/mutations.js.map +1 -0
  12. package/dist/client/store.d.ts +42 -0
  13. package/dist/client/store.js +356 -0
  14. package/dist/client/store.js.map +1 -0
  15. package/dist/client/transaction.d.ts +14 -0
  16. package/dist/client/transaction.js +37 -0
  17. package/dist/client/transaction.js.map +1 -0
  18. package/dist/errors/index.d.ts +15 -0
  19. package/dist/errors/index.js +35 -0
  20. package/dist/errors/index.js.map +1 -0
  21. package/dist/index.d.ts +10 -0
  22. package/dist/index.js +33 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/liveQuery/index.d.ts +31 -0
  25. package/dist/liveQuery/index.js +216 -0
  26. package/dist/liveQuery/index.js.map +1 -0
  27. package/dist/migrate/diff.d.ts +28 -0
  28. package/dist/migrate/diff.js +89 -0
  29. package/dist/migrate/diff.js.map +1 -0
  30. package/dist/migrate/helpers.d.ts +29 -0
  31. package/dist/migrate/helpers.js +89 -0
  32. package/dist/migrate/helpers.js.map +1 -0
  33. package/dist/migrate/index.d.ts +6 -0
  34. package/dist/migrate/index.js +14 -0
  35. package/dist/migrate/index.js.map +1 -0
  36. package/dist/migrate/upgrade.d.ts +19 -0
  37. package/dist/migrate/upgrade.js +123 -0
  38. package/dist/migrate/upgrade.js.map +1 -0
  39. package/dist/query/order.d.ts +8 -0
  40. package/dist/query/order.js +30 -0
  41. package/dist/query/order.js.map +1 -0
  42. package/dist/query/where.d.ts +17 -0
  43. package/dist/query/where.js +106 -0
  44. package/dist/query/where.js.map +1 -0
  45. package/dist/relation/define-relation.d.ts +49 -0
  46. package/dist/relation/define-relation.js +101 -0
  47. package/dist/relation/define-relation.js.map +1 -0
  48. package/dist/relation/index.d.ts +3 -0
  49. package/dist/relation/index.js +14 -0
  50. package/dist/relation/index.js.map +1 -0
  51. package/dist/relation/load-related.d.ts +21 -0
  52. package/dist/relation/load-related.js +54 -0
  53. package/dist/relation/load-related.js.map +1 -0
  54. package/dist/schema/define-db.d.ts +5 -0
  55. package/dist/schema/define-db.js +41 -0
  56. package/dist/schema/define-db.js.map +1 -0
  57. package/dist/schema/define-store.d.ts +17 -0
  58. package/dist/schema/define-store.js +95 -0
  59. package/dist/schema/define-store.js.map +1 -0
  60. package/dist/schema/fields.d.ts +75 -0
  61. package/dist/schema/fields.js +90 -0
  62. package/dist/schema/fields.js.map +1 -0
  63. package/dist/schema/index.d.ts +5 -0
  64. package/dist/schema/index.js +22 -0
  65. package/dist/schema/index.js.map +1 -0
  66. package/dist/schema/infer.d.ts +131 -0
  67. package/dist/schema/infer.js +3 -0
  68. package/dist/schema/infer.js.map +1 -0
  69. package/dist/schema/infer.test-types.d.ts +11 -0
  70. package/dist/schema/infer.test-types.js +80 -0
  71. package/dist/schema/infer.test-types.js.map +1 -0
  72. package/dist/schema/types.d.ts +55 -0
  73. package/dist/schema/types.js +3 -0
  74. package/dist/schema/types.js.map +1 -0
  75. package/dist/utils/assert-keys.d.ts +3 -0
  76. package/dist/utils/assert-keys.js +15 -0
  77. package/dist/utils/assert-keys.js.map +1 -0
  78. package/dist/utils/boolean-codec.d.ts +23 -0
  79. package/dist/utils/boolean-codec.js +149 -0
  80. package/dist/utils/boolean-codec.js.map +1 -0
  81. package/dist/utils/index.d.ts +5 -0
  82. package/dist/utils/index.js +16 -0
  83. package/dist/utils/index.js.map +1 -0
  84. package/dist/utils/key-range.d.ts +14 -0
  85. package/dist/utils/key-range.js +157 -0
  86. package/dist/utils/key-range.js.map +1 -0
  87. package/dist/utils/promisify.d.ts +2 -0
  88. package/dist/utils/promisify.js +29 -0
  89. package/dist/utils/promisify.js.map +1 -0
  90. package/dist/utils/type-utils.d.ts +2 -0
  91. package/dist/utils/type-utils.js +3 -0
  92. package/dist/utils/type-utils.js.map +1 -0
  93. package/package.json +71 -0
@@ -0,0 +1,75 @@
1
+ import type { StoreFieldsInterface, StoreInterface } from './types';
2
+ /** Runtime options / snapshot for a field builder. */
3
+ export type FieldKind = 'string' | 'number' | 'boolean' | 'date' | 'array' | 'json';
4
+ export interface FieldIndexInterface {
5
+ name: string;
6
+ keyPath: string;
7
+ unique?: boolean;
8
+ multiEntry?: boolean;
9
+ }
10
+ /** Declares that this field is a foreign key to another store's primary key. */
11
+ export interface FieldRefInterface {
12
+ /** Target object store name */
13
+ store: string;
14
+ /** Target PK field name (documentation / validation; defaults to target store PK) */
15
+ field?: string;
16
+ }
17
+ export interface FieldInterface {
18
+ kind: FieldKind;
19
+ optional: boolean;
20
+ primaryKey: boolean;
21
+ autoIncrement: boolean;
22
+ /** Simple index on this field (if set) */
23
+ index?: FieldIndexInterface;
24
+ /** Optional FK metadata (does not create an IDB index by itself) */
25
+ ref?: FieldRefInterface;
26
+ }
27
+ /**
28
+ * Immutable field builder. Chain methods return a new instance;
29
+ * type parameters drive InferSelect / InferInsert / typed where.
30
+ */
31
+ export declare class Field<T = unknown, TOptional extends boolean = false, TPrimary extends boolean = false, TAuto extends boolean = false, TIndexed extends boolean = false, TUnique extends boolean = false> {
32
+ readonly meta: Readonly<FieldInterface>;
33
+ /** Phantom: value type for InferSelect / InferInsert */
34
+ readonly _type: T;
35
+ readonly _optional: TOptional;
36
+ readonly _primary: TPrimary;
37
+ readonly _autoIncrement: TAuto;
38
+ readonly _indexed: TIndexed;
39
+ readonly _unique: TUnique;
40
+ constructor(options?: Partial<FieldInterface>);
41
+ cloneWith(options?: Partial<FieldInterface>): Field<T, TOptional, TPrimary, TAuto, TIndexed, TUnique>;
42
+ private cloneAs;
43
+ optional(): Field<T, true, TPrimary, TAuto, TIndexed, TUnique>;
44
+ primaryKey(options: {
45
+ autoIncrement: true;
46
+ }): Field<T, TOptional, true, true, TIndexed, TUnique>;
47
+ primaryKey(options?: {
48
+ autoIncrement?: false;
49
+ }): Field<T, TOptional, true, false, TIndexed, TUnique>;
50
+ /**
51
+ * Mark this field as a foreign key to another store.
52
+ * Does **not** create an IndexedDB index — chain `.index()` / `.uniqueIndex()`.
53
+ *
54
+ * Prefer passing the store object to avoid typos: `.ref(users)` / `.ref(users, 'id')`.
55
+ * String form `.ref('users')` remains supported.
56
+ */
57
+ ref(store: string, field?: string): Field<T, TOptional, TPrimary, TAuto, TIndexed, TUnique>;
58
+ ref<TFields extends StoreFieldsInterface>(store: StoreInterface<TFields>, field?: keyof TFields & string): Field<T, TOptional, TPrimary, TAuto, TIndexed, TUnique>;
59
+ index(name: string): Field<T, TOptional, TPrimary, TAuto, true, false>;
60
+ uniqueIndex(name: string): Field<T, TOptional, TPrimary, TAuto, true, true>;
61
+ multiEntry(name: string): Field<T, TOptional, TPrimary, TAuto, true, false>;
62
+ }
63
+ export type AnyField = Field<unknown, boolean, boolean, boolean, boolean, boolean>;
64
+ /** Field builders for schema definitions. */
65
+ export declare const field: {
66
+ string: () => Field<string, false, false, false, false, false>;
67
+ number: () => Field<number, false, false, false, false, false>;
68
+ boolean: () => Field<boolean, false, false, false, false, false>;
69
+ date: () => Field<Date, false, false, false, false, false>;
70
+ /** Opaque structured-cloneable value (objects, ArrayBuffer, etc.). */
71
+ json: <T = unknown>() => Field<T, false, false, false, false, false>;
72
+ array: <T_1>(_item?: Field<T_1, boolean, boolean, boolean, boolean, boolean> | undefined) => Field<T_1[], false, false, false, false, false>;
73
+ };
74
+ export declare function isField(value: unknown): value is AnyField;
75
+ export declare function fieldIndexSpec(fieldName: string, fieldDef: AnyField): FieldIndexInterface | null;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fieldIndexSpec = exports.isField = exports.field = exports.Field = void 0;
4
+ const DEFAULT_FIELD = {
5
+ kind: 'string',
6
+ optional: false,
7
+ primaryKey: false,
8
+ autoIncrement: false,
9
+ };
10
+ /**
11
+ * Immutable field builder. Chain methods return a new instance;
12
+ * type parameters drive InferSelect / InferInsert / typed where.
13
+ */
14
+ class Field {
15
+ constructor(options) {
16
+ this.meta = Object.assign(Object.assign({}, DEFAULT_FIELD), options);
17
+ }
18
+ cloneWith(options) {
19
+ return new Field(Object.assign(Object.assign({}, this.meta), options));
20
+ }
21
+ cloneAs(options) {
22
+ return new Field(Object.assign(Object.assign({}, this.meta), options));
23
+ }
24
+ optional() {
25
+ return this.cloneAs({
26
+ optional: true,
27
+ });
28
+ }
29
+ primaryKey(options) {
30
+ if (options === null || options === void 0 ? void 0 : options.autoIncrement) {
31
+ return this.cloneAs({
32
+ primaryKey: true,
33
+ autoIncrement: true,
34
+ });
35
+ }
36
+ return this.cloneAs({
37
+ primaryKey: true,
38
+ autoIncrement: false,
39
+ });
40
+ }
41
+ ref(store, field) {
42
+ const storeName = typeof store === 'string' ? store : store.name;
43
+ return this.cloneWith({
44
+ ref: field ? { store: storeName, field } : { store: storeName },
45
+ });
46
+ }
47
+ index(name) {
48
+ return this.cloneAs({
49
+ index: { name, keyPath: '', unique: false, multiEntry: false },
50
+ });
51
+ }
52
+ uniqueIndex(name) {
53
+ return this.cloneAs({
54
+ index: { name, keyPath: '', unique: true, multiEntry: false },
55
+ });
56
+ }
57
+ multiEntry(name) {
58
+ return this.cloneAs({
59
+ index: { name, keyPath: '', unique: false, multiEntry: true },
60
+ });
61
+ }
62
+ }
63
+ exports.Field = Field;
64
+ /** Field builders for schema definitions. */
65
+ exports.field = {
66
+ string: () => new Field({ kind: 'string' }),
67
+ number: () => new Field({ kind: 'number' }),
68
+ boolean: () => new Field({ kind: 'boolean' }),
69
+ date: () => new Field({ kind: 'date' }),
70
+ /** Opaque structured-cloneable value (objects, ArrayBuffer, etc.). */
71
+ json: () => new Field({ kind: 'json' }),
72
+ array: (_item) => new Field({ kind: 'array' }),
73
+ };
74
+ function isField(value) {
75
+ return value instanceof Field;
76
+ }
77
+ exports.isField = isField;
78
+ function fieldIndexSpec(fieldName, fieldDef) {
79
+ if (!fieldDef.meta.index) {
80
+ return null;
81
+ }
82
+ return {
83
+ name: fieldDef.meta.index.name,
84
+ keyPath: fieldName,
85
+ unique: fieldDef.meta.index.unique,
86
+ multiEntry: fieldDef.meta.index.multiEntry,
87
+ };
88
+ }
89
+ exports.fieldIndexSpec = fieldIndexSpec;
90
+ //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/schema/fields.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from './types';
2
+ export * from './fields';
3
+ export * from './define-store';
4
+ export * from './define-db';
5
+ export * from './infer';
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./fields"), exports);
19
+ __exportStar(require("./define-store"), exports);
20
+ __exportStar(require("./define-db"), exports);
21
+ __exportStar(require("./infer"), exports);
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,2CAAyB;AACzB,iDAA+B;AAC/B,8CAA4B;AAC5B,0CAAwB"}
@@ -0,0 +1,131 @@
1
+ import type { Field } from './fields';
2
+ import type { CompoundIndexType, StoreInterface } from './types';
3
+ type FieldOutput<F> = F extends {
4
+ readonly _type: infer T;
5
+ } ? T : never;
6
+ type SelectValue<F> = F extends Field<infer T, infer O, boolean, boolean, boolean, boolean> ? O extends true ? T | undefined : T : never;
7
+ type IsInsertOptional<F> = F extends Field<unknown, infer O, infer P, infer A, boolean, boolean> ? O extends true ? true : P extends true ? A extends true ? true : false : false : false;
8
+ type RequiredInsertKeys<TFields extends Record<string, Field<unknown, boolean, boolean, boolean, boolean, boolean>>> = {
9
+ [K in keyof TFields]: IsInsertOptional<TFields[K]> extends true ? never : K;
10
+ }[keyof TFields];
11
+ type OptionalInsertKeys<TFields extends Record<string, Field<unknown, boolean, boolean, boolean, boolean, boolean>>> = Exclude<keyof TFields, RequiredInsertKeys<TFields>>;
12
+ type StoreShape = {
13
+ fields: Record<string, Field<unknown, boolean, boolean, boolean, boolean, boolean>>;
14
+ primaryKey: {
15
+ keyPath: string;
16
+ };
17
+ };
18
+ /** Row type returned from queries. */
19
+ export type InferSelect<TStore extends StoreShape> = {
20
+ [K in keyof TStore['fields']]: SelectValue<TStore['fields'][K]>;
21
+ };
22
+ /** Payload accepted by insert (autoIncrement PK optional). */
23
+ export type InferInsert<TStore extends StoreShape> = {
24
+ [K in RequiredInsertKeys<TStore['fields']>]: FieldOutput<TStore['fields'][K]>;
25
+ } & {
26
+ [K in OptionalInsertKeys<TStore['fields']>]?: FieldOutput<TStore['fields'][K]>;
27
+ };
28
+ export type InferUpdate<TStore extends StoreShape> = Partial<InferSelect<TStore>>;
29
+ export type InferClientStores<TStores extends Record<string, StoreShape>> = {
30
+ [K in keyof TStores]: InferSelect<TStores[K]>;
31
+ };
32
+ export interface RangeFilterInterface<T> {
33
+ equals?: T;
34
+ gt?: T;
35
+ gte?: T;
36
+ lt?: T;
37
+ lte?: T;
38
+ /** Aliases for gt / gte / lt / lte */
39
+ above?: T;
40
+ aboveOrEqual?: T;
41
+ below?: T;
42
+ belowOrEqual?: T;
43
+ /**
44
+ * String prefix → IDBKeyRange (lower = prefix, upper = prefix + '\\uffff').
45
+ * Only valid for string keys.
46
+ */
47
+ startsWith?: string;
48
+ /**
49
+ * Bound range. Default inclusive on both sides.
50
+ * `[lower, upper]` or `[lower, upper, lowerOpen, upperOpen]`.
51
+ */
52
+ between?: readonly [T, T] | readonly [T, T, boolean, boolean];
53
+ }
54
+ export type WhereValueInterface<T = unknown> = T | RangeFilterInterface<T> | IDBKeyRange;
55
+ export type OrderDirection = 'asc' | 'desc';
56
+ /** Runtime / internal where (not tied to a store schema). */
57
+ export type LooseWhereInputInterface = Record<string, WhereValueInterface>;
58
+ /** Runtime / internal orderBy. */
59
+ export type LooseOrderByInputInterface = Record<string, OrderDirection>;
60
+ type IsQueryableField<F> = F extends Field<unknown, boolean, infer P, boolean, infer I, boolean> ? P extends true ? true : I extends true ? true : false : false;
61
+ type IsUniqueField<F> = F extends Field<unknown, boolean, infer P, boolean, boolean, infer U> ? P extends true ? true : U extends true ? true : false : false;
62
+ /** PK ∪ simple/unique/multiEntry indexed field names. */
63
+ export type QueryableKeys<TFields> = {
64
+ [K in keyof TFields]-?: IsQueryableField<TFields[K]> extends true ? K & string : never;
65
+ }[keyof TFields];
66
+ /** PK ∪ uniqueIndex field names (for findUnique). */
67
+ export type UniqueKeys<TFields> = {
68
+ [K in keyof TFields]-?: IsUniqueField<TFields[K]> extends true ? K & string : never;
69
+ }[keyof TFields];
70
+ type FieldWhereValue<TFields, K extends keyof TFields> = WhereValueInterface<FieldOutput<TFields[K]>>;
71
+ type SimpleWhereInput<TFields> = {
72
+ [K in QueryableKeys<TFields>]?: FieldWhereValue<TFields, K>;
73
+ };
74
+ type CompoundsOf<TStore> = TStore extends StoreInterface<infer _F, infer C extends readonly CompoundIndexType[]> ? C : readonly [];
75
+ type FieldsOf<TStore> = TStore extends StoreInterface<infer F, infer _C> ? F : TStore extends {
76
+ fields: infer F;
77
+ } ? F : never;
78
+ type CompoundWhereFromItem<TFields, Item extends CompoundIndexType> = Item['fields'][number] extends infer K ? [K] extends [keyof TFields] ? {
79
+ [P in Item['fields'][number] & keyof TFields]: FieldWhereValue<TFields, P>;
80
+ } : never : never;
81
+ type CompoundWhereUnion<TFields, TCompounds extends readonly CompoundIndexType[]> = TCompounds[number] extends infer Item ? Item extends CompoundIndexType ? CompoundWhereFromItem<TFields, Item> : never : never;
82
+ type NamedCompoundWhere<TFields, TCompounds extends readonly CompoundIndexType[]> = {
83
+ [C in TCompounds[number] as C['name']]?: {
84
+ [I in keyof C['fields']]: C['fields'][I] extends keyof TFields ? FieldWhereValue<TFields, C['fields'][I] & keyof TFields> : IDBValidKey;
85
+ };
86
+ };
87
+ /**
88
+ * Where clause typed from store schema: only PK / indexed fields,
89
+ * a full compound index key object, or `{ compoundIndexName: […values] }`.
90
+ */
91
+ export type WhereInputInterface<TStore extends StoreInterface = StoreInterface> = SimpleWhereInput<FieldsOf<TStore>> | CompoundWhereUnion<FieldsOf<TStore>, CompoundsOf<TStore>> | NamedCompoundWhere<FieldsOf<TStore>, CompoundsOf<TStore>>;
92
+ /** orderBy: only queryable (PK / indexed) fields. */
93
+ export type OrderByInputInterface<TStore extends StoreInterface = StoreInterface> = {
94
+ [K in QueryableKeys<FieldsOf<TStore>>]?: OrderDirection;
95
+ };
96
+ /**
97
+ * findUnique where: exactly one PK or uniqueIndex field.
98
+ */
99
+ export type UniqueWhereInputInterface<TStore extends StoreInterface = StoreInterface> = {
100
+ [K in UniqueKeys<FieldsOf<TStore>>]: {
101
+ [P in K]: FieldWhereValue<FieldsOf<TStore>, P & keyof FieldsOf<TStore>>;
102
+ };
103
+ }[UniqueKeys<FieldsOf<TStore>>];
104
+ export type FindManyParamsInterface<TStore extends StoreInterface = StoreInterface> = {
105
+ where?: WhereInputInterface<TStore>;
106
+ orderBy?: OrderByInputInterface<TStore>;
107
+ take?: number;
108
+ skip?: number;
109
+ /**
110
+ * When `where` and `orderBy` use different indexes, fetch by `where` then
111
+ * sort in memory. Can be expensive on large result sets.
112
+ */
113
+ sortInMemory?: boolean;
114
+ };
115
+ export type FindParamsInterface<TStore extends StoreInterface = StoreInterface> = {
116
+ where: WhereInputInterface<TStore>;
117
+ orderBy?: OrderByInputInterface<TStore>;
118
+ /** See FindManyParamsInterface.sortInMemory */
119
+ sortInMemory?: boolean;
120
+ };
121
+ export type UpdateParamsInterface<TStore extends StoreInterface = StoreInterface> = {
122
+ where: WhereInputInterface<TStore>;
123
+ data: Partial<InferSelect<TStore>>;
124
+ };
125
+ export type DeleteParamsInterface<TStore extends StoreInterface = StoreInterface> = {
126
+ where: WhereInputInterface<TStore>;
127
+ };
128
+ export type CountParamsInterface<TStore extends StoreInterface = StoreInterface> = {
129
+ where?: WhereInputInterface<TStore>;
130
+ };
131
+ export {};
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=infer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.js","sourceRoot":"","sources":["../../src/schema/infer.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ export declare function getTasksSchemaSnapshot(): {
2
+ name: string;
3
+ primaryKey: import("./types").PrimaryKeyInterface;
4
+ indexes: {
5
+ name: string;
6
+ keyPath: string | string[];
7
+ unique?: boolean | undefined;
8
+ multiEntry?: boolean | undefined;
9
+ }[];
10
+ };
11
+ export declare function getDbSchemaSnapshot(): import("./types").DeclaredDbInterface;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getDbSchemaSnapshot = exports.getTasksSchemaSnapshot = void 0;
4
+ /**
5
+ * Compile-time / snapshot checks for schema inference.
6
+ * Included in `tsc` build; does not require a test runner.
7
+ */
8
+ const fields_1 = require("./fields");
9
+ const define_store_1 = require("./define-store");
10
+ const define_db_1 = require("./define-db");
11
+ const tasks = (0, define_store_1.defineStore)('tasks', {
12
+ id: fields_1.field.number().primaryKey({ autoIncrement: true }),
13
+ title: fields_1.field.string(),
14
+ status: fields_1.field.string().index('byStatus'),
15
+ tags: fields_1.field.array(fields_1.field.string()).multiEntry('byTags'),
16
+ userId: fields_1.field.string(),
17
+ dueAt: fields_1.field.date().optional(),
18
+ email: fields_1.field.string().uniqueIndex('byEmail'),
19
+ }, () => [(0, define_store_1.compoundIndex)('byUserDue', ['userId', 'dueAt'])]);
20
+ /** Ensures Task has expected shape (assignability). */
21
+ const _taskCheck = {
22
+ id: 1,
23
+ title: 't',
24
+ status: 'todo',
25
+ tags: [],
26
+ userId: 'u1',
27
+ dueAt: undefined,
28
+ email: 'a@b.c',
29
+ };
30
+ /** Ensures autoIncrement id is optional on insert. */
31
+ const _insertCheck = {
32
+ title: 't',
33
+ status: 'todo',
34
+ tags: [],
35
+ userId: 'u1',
36
+ email: 'a@b.c',
37
+ };
38
+ const _whereOk = { status: 'todo' };
39
+ const _wherePk = { id: 1 };
40
+ const _whereCompound = { userId: 'u1', dueAt: new Date() };
41
+ const _orderOk = { id: 'desc' };
42
+ const _orderStatus = { status: 'asc' };
43
+ const _uniqueOk = { id: 1 };
44
+ const _uniqueEmail = { email: 'a@b.c' };
45
+ // @ts-expect-error title is not indexed
46
+ const _whereBad = { title: 'nope' };
47
+ // @ts-expect-error status is not unique
48
+ const _uniqueBad = { status: 'todo' };
49
+ // @ts-expect-error title is not queryable for orderBy
50
+ const _orderBad = { title: 'asc' };
51
+ function getTasksSchemaSnapshot() {
52
+ return {
53
+ name: tasks.name,
54
+ primaryKey: tasks.primaryKey,
55
+ indexes: tasks.indexes.map((i) => (Object.assign({}, i))),
56
+ };
57
+ }
58
+ exports.getTasksSchemaSnapshot = getTasksSchemaSnapshot;
59
+ function getDbSchemaSnapshot() {
60
+ return (0, define_db_1.toDeclaredDbSchema)({
61
+ name: 'app',
62
+ version: 1,
63
+ stores: { tasks },
64
+ });
65
+ }
66
+ exports.getDbSchemaSnapshot = getDbSchemaSnapshot;
67
+ void _taskCheck;
68
+ void _insertCheck;
69
+ void _whereOk;
70
+ void _wherePk;
71
+ void _whereCompound;
72
+ void _orderOk;
73
+ void _orderStatus;
74
+ void _uniqueOk;
75
+ void _uniqueEmail;
76
+ void _whereBad;
77
+ void _uniqueBad;
78
+ void _orderBad;
79
+ void null;
80
+ //# sourceMappingURL=infer.test-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.test-types.js","sourceRoot":"","sources":["../../src/schema/infer.test-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { AnyField } from './fields';
2
+ export type { FieldKind } from './fields';
3
+ export interface IndexInterface {
4
+ name: string;
5
+ /** Property name or path; array = compound index keyPath */
6
+ keyPath: string | string[];
7
+ unique?: boolean;
8
+ multiEntry?: boolean;
9
+ }
10
+ export interface PrimaryKeyInterface {
11
+ keyPath: string;
12
+ autoIncrement: boolean;
13
+ }
14
+ export type StoreFieldsInterface = Record<string, AnyField>;
15
+ export type CompoundIndexType = {
16
+ name: string;
17
+ fields: readonly string[];
18
+ unique?: boolean;
19
+ };
20
+ export interface StoreInterface<TFields extends StoreFieldsInterface = StoreFieldsInterface, TCompounds extends readonly CompoundIndexType[] = readonly CompoundIndexType[]> {
21
+ readonly name: string;
22
+ readonly fields: TFields;
23
+ readonly primaryKey: PrimaryKeyInterface;
24
+ readonly indexes: IndexInterface[];
25
+ /** Phantom: compound indexes from defineStore (for typed where). */
26
+ readonly __compounds?: TCompounds;
27
+ }
28
+ export type DbStoresInterface = Record<string, StoreInterface>;
29
+ export interface UpgradeContextInterface {
30
+ oldVersion: number;
31
+ newVersion: number;
32
+ }
33
+ export type UpgradeFn = (tx: IDBTransaction, ctx: UpgradeContextInterface) => void | Promise<void>;
34
+ export interface DbConfigInterface<TStores extends DbStoresInterface = DbStoresInterface> {
35
+ name: string;
36
+ version: number;
37
+ stores: TStores;
38
+ /** Hooks keyed by target version; run when oldVersion < version */
39
+ upgrade?: Record<number, UpgradeFn>;
40
+ /**
41
+ * When true, `insert` / `insertMany` throw if the payload has keys
42
+ * that are not declared on the store schema.
43
+ */
44
+ strictInsert?: boolean;
45
+ }
46
+ export interface DeclaredStoreInterface {
47
+ name: string;
48
+ primaryKey: PrimaryKeyInterface;
49
+ indexes: IndexInterface[];
50
+ }
51
+ export interface DeclaredDbInterface {
52
+ name: string;
53
+ version: number;
54
+ stores: DeclaredStoreInterface[];
55
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { StoreInterface } from '../schema/types';
2
+ /** Throw if `data` has keys that are not declared on the store schema. */
3
+ export declare function assertKnownInsertKeys(store: StoreInterface, data: Record<string, unknown>): void;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertKnownInsertKeys = void 0;
4
+ const errors_1 = require("../errors");
5
+ /** Throw if `data` has keys that are not declared on the store schema. */
6
+ function assertKnownInsertKeys(store, data) {
7
+ const allowed = new Set(Object.keys(store.fields));
8
+ const unknown = Object.keys(data).filter((key) => !allowed.has(key));
9
+ if (unknown.length === 0) {
10
+ return;
11
+ }
12
+ throw new errors_1.IndexedDbError('QUERY_INVALID', `Unknown key(s) on insert: ${unknown.map((k) => `"${k}"`).join(', ')}. Declared fields: ${[...allowed].join(', ')}.`, { store: store.name, field: unknown[0] });
13
+ }
14
+ exports.assertKnownInsertKeys = assertKnownInsertKeys;
15
+ //# sourceMappingURL=assert-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assert-keys.js","sourceRoot":"","sources":["../../src/utils/assert-keys.ts"],"names":[],"mappings":";;;AACA,sCAA2C;AAE3C,0EAA0E;AAC1E,SAAgB,qBAAqB,CACnC,KAAqB,EACrB,IAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACrE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;QACxB,OAAO;KACR;IACD,MAAM,IAAI,uBAAc,CACtB,eAAe,EACf,6BAA6B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EACpH,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CACzC,CAAC;AACJ,CAAC;AAdD,sDAcC"}
@@ -0,0 +1,23 @@
1
+ import type { StoreInterface } from '../schema/types';
2
+ import type { LooseWhereInputInterface } from '../schema/infer';
3
+ /** IndexedDB keys cannot be boolean — store 0 | 1 instead. */
4
+ export type StoredBoolean = 0 | 1;
5
+ /** App boolean → IDB key (0 | 1). Passes through 0/1; leaves other values alone. */
6
+ export declare function encodeBooleanForStorage(value: unknown): unknown;
7
+ /**
8
+ * IDB value → app boolean.
9
+ * Accepts 0/1 and legacy true/false so old rows still decode.
10
+ */
11
+ export declare function decodeBooleanFromStorage(value: unknown): boolean;
12
+ /**
13
+ * Encode boolean fields in a row before writing to IndexedDB.
14
+ * App API stays `boolean`; storage / index keys are `0 | 1`.
15
+ */
16
+ export declare function encodeRowForStorage<T extends Record<string, unknown>>(store: StoreInterface, row: T): T;
17
+ /**
18
+ * Decode boolean fields after reading from IndexedDB.
19
+ * Treats both `0|1` and legacy `true|false` as boolean.
20
+ */
21
+ export declare function decodeRowFromStorage<T extends Record<string, unknown>>(store: StoreInterface, row: T): T;
22
+ /** Encode boolean parts of a where clause before resolving to IDBKeyRange. */
23
+ export declare function encodeWhereForStorage(store: StoreInterface, where?: LooseWhereInputInterface): LooseWhereInputInterface | undefined;