@testerpaykit/storage-browser 0.0.0-stage → 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/README.md +2 -2
- package/dist/index.d.mts +287 -0
- package/dist/index.d.ts +287 -0
- package/dist/index.js +233 -0
- package/dist/index.mjs +195 -0
- package/package.json +46 -3
package/README.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @testerpaykit/storage-browser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
IndexedDB storage (Dexie) for the TesterPayKit web SDK, so queued reports survive reloads. Used with [`@testerpaykit/react`](https://www.npmjs.com/package/@testerpaykit/react) — start there.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { IStorage, Where } from '@testerpaykit/core';
|
|
2
|
+
import Dexie, { Table } from 'dexie';
|
|
3
|
+
|
|
4
|
+
interface SessionRecord {
|
|
5
|
+
id: string;
|
|
6
|
+
started_at: number;
|
|
7
|
+
ended_at: number | null;
|
|
8
|
+
duration_seconds: number | null;
|
|
9
|
+
screen_view_count: number;
|
|
10
|
+
tap_count: number;
|
|
11
|
+
end_reason: string | null;
|
|
12
|
+
foreground_seconds: number | null;
|
|
13
|
+
metadata?: string;
|
|
14
|
+
}
|
|
15
|
+
interface EventRecord {
|
|
16
|
+
id: string;
|
|
17
|
+
session_id: string;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
event_type: string;
|
|
20
|
+
screen_name: string | null;
|
|
21
|
+
element_id: string | null;
|
|
22
|
+
metadata: string | null;
|
|
23
|
+
}
|
|
24
|
+
interface OutboxRecord {
|
|
25
|
+
local_id: string;
|
|
26
|
+
type: string;
|
|
27
|
+
payload: string;
|
|
28
|
+
state: string;
|
|
29
|
+
attempts: number;
|
|
30
|
+
last_error: string | null;
|
|
31
|
+
created_at: string;
|
|
32
|
+
}
|
|
33
|
+
interface SdkMetaRecord {
|
|
34
|
+
key: string;
|
|
35
|
+
value: string;
|
|
36
|
+
}
|
|
37
|
+
interface BugReportRecord {
|
|
38
|
+
id: string;
|
|
39
|
+
session_id: string;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
message: string;
|
|
42
|
+
stack: string | null;
|
|
43
|
+
severity: string;
|
|
44
|
+
}
|
|
45
|
+
interface FeedbackRecord {
|
|
46
|
+
id: string;
|
|
47
|
+
session_id: string;
|
|
48
|
+
content: string;
|
|
49
|
+
rating: number | null;
|
|
50
|
+
created_at: number;
|
|
51
|
+
}
|
|
52
|
+
interface TaskRecord {
|
|
53
|
+
id: string;
|
|
54
|
+
task_preset_id: string;
|
|
55
|
+
title: string;
|
|
56
|
+
started_at: number | null;
|
|
57
|
+
completed_at: number | null;
|
|
58
|
+
is_completed: number;
|
|
59
|
+
created_at: number;
|
|
60
|
+
}
|
|
61
|
+
interface WeeklySummaryRecord {
|
|
62
|
+
id: string;
|
|
63
|
+
data: string;
|
|
64
|
+
status: string;
|
|
65
|
+
created_at: number;
|
|
66
|
+
}
|
|
67
|
+
interface Event {
|
|
68
|
+
id?: string;
|
|
69
|
+
sessionId: string;
|
|
70
|
+
type: string;
|
|
71
|
+
timestamp: Date;
|
|
72
|
+
screenRoute?: string;
|
|
73
|
+
metadata?: string;
|
|
74
|
+
}
|
|
75
|
+
interface Session {
|
|
76
|
+
id?: string;
|
|
77
|
+
startedAt: Date;
|
|
78
|
+
endedAt?: Date;
|
|
79
|
+
durationSeconds?: number;
|
|
80
|
+
screenViewCount?: number;
|
|
81
|
+
tapCount?: number;
|
|
82
|
+
endReason?: string;
|
|
83
|
+
foregroundSeconds?: number;
|
|
84
|
+
metadata?: string;
|
|
85
|
+
}
|
|
86
|
+
interface Task {
|
|
87
|
+
id?: string;
|
|
88
|
+
taskPresetId: string;
|
|
89
|
+
title: string;
|
|
90
|
+
description?: string;
|
|
91
|
+
startedAt?: Date;
|
|
92
|
+
completedAt?: Date;
|
|
93
|
+
isCompleted?: boolean;
|
|
94
|
+
createdAt: Date;
|
|
95
|
+
}
|
|
96
|
+
interface Feedback {
|
|
97
|
+
id?: string;
|
|
98
|
+
sessionId?: string;
|
|
99
|
+
content: string;
|
|
100
|
+
rating?: number;
|
|
101
|
+
createdAt: Date;
|
|
102
|
+
metadata?: string;
|
|
103
|
+
}
|
|
104
|
+
interface Submission {
|
|
105
|
+
id?: string;
|
|
106
|
+
projectId: string;
|
|
107
|
+
testerId: string;
|
|
108
|
+
deviceId: string;
|
|
109
|
+
periodStart: Date;
|
|
110
|
+
periodEnd: Date;
|
|
111
|
+
metrics: string;
|
|
112
|
+
integrityHash: string;
|
|
113
|
+
deviceMetadata: string;
|
|
114
|
+
appMetadata: string;
|
|
115
|
+
status: string;
|
|
116
|
+
rejectionReason?: string;
|
|
117
|
+
estimatedPayout?: number;
|
|
118
|
+
actualPayout?: number;
|
|
119
|
+
createdAt: Date;
|
|
120
|
+
updatedAt: Date;
|
|
121
|
+
submittedAt?: Date;
|
|
122
|
+
}
|
|
123
|
+
interface BugReport {
|
|
124
|
+
id?: string;
|
|
125
|
+
sessionId: string;
|
|
126
|
+
testerId?: string;
|
|
127
|
+
type: string;
|
|
128
|
+
severity: string;
|
|
129
|
+
category: string;
|
|
130
|
+
title: string;
|
|
131
|
+
description: string;
|
|
132
|
+
affectedFeature?: string;
|
|
133
|
+
frequency?: string;
|
|
134
|
+
reproductionSteps?: string;
|
|
135
|
+
expectedBehavior?: string;
|
|
136
|
+
actualBehavior?: string;
|
|
137
|
+
currentScreen: string;
|
|
138
|
+
breadcrumbs?: string;
|
|
139
|
+
deviceSnapshot: string;
|
|
140
|
+
appSnapshot: string;
|
|
141
|
+
screenshotPath?: string;
|
|
142
|
+
annotatedScreenshotPath?: string;
|
|
143
|
+
screenRecordingPath?: string;
|
|
144
|
+
attachments?: string;
|
|
145
|
+
createdAt: Date;
|
|
146
|
+
submittedAt?: Date;
|
|
147
|
+
status?: string;
|
|
148
|
+
assignedTo?: string;
|
|
149
|
+
coordinatorNotes?: string;
|
|
150
|
+
severityConfidence?: number;
|
|
151
|
+
suggestedCategory?: string;
|
|
152
|
+
duplicateOf?: string;
|
|
153
|
+
}
|
|
154
|
+
interface Breadcrumb {
|
|
155
|
+
id?: string;
|
|
156
|
+
sessionId: string;
|
|
157
|
+
type: string;
|
|
158
|
+
timestamp: Date;
|
|
159
|
+
screen?: string;
|
|
160
|
+
action?: string;
|
|
161
|
+
data?: string;
|
|
162
|
+
message?: string;
|
|
163
|
+
}
|
|
164
|
+
interface CrashContext {
|
|
165
|
+
id?: string;
|
|
166
|
+
sessionId?: string;
|
|
167
|
+
error: string;
|
|
168
|
+
stackTrace: string;
|
|
169
|
+
breadcrumbs?: string;
|
|
170
|
+
deviceSnapshot: string;
|
|
171
|
+
appSnapshot: string;
|
|
172
|
+
crashTime: Date;
|
|
173
|
+
reported?: boolean;
|
|
174
|
+
}
|
|
175
|
+
interface SessionEndFeedback {
|
|
176
|
+
id?: string;
|
|
177
|
+
sessionId: string;
|
|
178
|
+
rating: number;
|
|
179
|
+
comment?: string;
|
|
180
|
+
categories?: string;
|
|
181
|
+
wouldRecommend?: boolean;
|
|
182
|
+
createdAt: Date;
|
|
183
|
+
}
|
|
184
|
+
interface DeviceIdMetadata {
|
|
185
|
+
id?: string;
|
|
186
|
+
deviceId: string;
|
|
187
|
+
isActive: boolean;
|
|
188
|
+
createdAt: Date;
|
|
189
|
+
expiresAt: Date;
|
|
190
|
+
}
|
|
191
|
+
interface TaskTracking {
|
|
192
|
+
id?: string;
|
|
193
|
+
taskId: string;
|
|
194
|
+
sessionId: string;
|
|
195
|
+
startedAt: Date;
|
|
196
|
+
completedAt?: Date;
|
|
197
|
+
abandonedAt?: Date;
|
|
198
|
+
durationSeconds?: number;
|
|
199
|
+
status: string;
|
|
200
|
+
metadata?: string;
|
|
201
|
+
}
|
|
202
|
+
interface WidgetAnnotation {
|
|
203
|
+
id?: string;
|
|
204
|
+
taskId: string;
|
|
205
|
+
widgetKey: string;
|
|
206
|
+
annotationType: string;
|
|
207
|
+
message: string;
|
|
208
|
+
priority: string;
|
|
209
|
+
elementBounds?: string;
|
|
210
|
+
metadata?: string;
|
|
211
|
+
createdAt: Date;
|
|
212
|
+
}
|
|
213
|
+
interface AnnotationInteraction {
|
|
214
|
+
id?: string;
|
|
215
|
+
sessionId: string;
|
|
216
|
+
annotationId: string;
|
|
217
|
+
taskId: string;
|
|
218
|
+
interactionType: string;
|
|
219
|
+
timestamp: Date;
|
|
220
|
+
elementBounds?: string;
|
|
221
|
+
metadata?: string;
|
|
222
|
+
inputValue?: string;
|
|
223
|
+
durationMs?: number;
|
|
224
|
+
triggeredCompletion?: boolean;
|
|
225
|
+
}
|
|
226
|
+
declare class TesterPayKitDB extends Dexie {
|
|
227
|
+
events: Table<Event, string>;
|
|
228
|
+
sessions: Table<Session, string>;
|
|
229
|
+
tasks: Table<Task, string>;
|
|
230
|
+
feedbacks: Table<Feedback, string>;
|
|
231
|
+
submissions: Table<Submission, string>;
|
|
232
|
+
bugReports: Table<BugReport, string>;
|
|
233
|
+
breadcrumbs: Table<Breadcrumb, string>;
|
|
234
|
+
crashContexts: Table<CrashContext, string>;
|
|
235
|
+
sessionEndFeedbacks: Table<SessionEndFeedback, string>;
|
|
236
|
+
deviceIdMetadata: Table<DeviceIdMetadata, string>;
|
|
237
|
+
taskTracking: Table<TaskTracking, string>;
|
|
238
|
+
widgetAnnotations: Table<WidgetAnnotation, string>;
|
|
239
|
+
annotationInteractions: Table<AnnotationInteraction, string>;
|
|
240
|
+
sdk_sessions: Table<SessionRecord, string>;
|
|
241
|
+
sdk_events: Table<EventRecord, string>;
|
|
242
|
+
outbox: Table<OutboxRecord, string>;
|
|
243
|
+
sdk_meta: Table<SdkMetaRecord, string>;
|
|
244
|
+
bug_reports: Table<BugReportRecord, string>;
|
|
245
|
+
sdk_feedbacks: Table<FeedbackRecord, string>;
|
|
246
|
+
sdk_tasks: Table<TaskRecord, string>;
|
|
247
|
+
weekly_summaries: Table<WeeklySummaryRecord, string>;
|
|
248
|
+
constructor();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* IndexedDB storage adapter for browser environments.
|
|
253
|
+
*
|
|
254
|
+
* Implements IStorage using Dexie.js. All operations go through the typed
|
|
255
|
+
* document/collection API (insert/find/findOne/update/delete/count) — no SQL.
|
|
256
|
+
*
|
|
257
|
+
* Collection names follow COLLECTIONS constants; each maps to a dedicated
|
|
258
|
+
* Dexie object store declared in schema version 2.
|
|
259
|
+
*
|
|
260
|
+
* The legacy getDB() / transaction() methods are kept so existing direct-Dexie
|
|
261
|
+
* tests continue to work.
|
|
262
|
+
*/
|
|
263
|
+
declare class IndexedDBAdapter implements IStorage {
|
|
264
|
+
private db;
|
|
265
|
+
constructor();
|
|
266
|
+
init(): Promise<void>;
|
|
267
|
+
close(): Promise<void>;
|
|
268
|
+
insert<T extends Record<string, unknown>>(collection: string, record: T): Promise<void>;
|
|
269
|
+
find<T>(collection: string, where?: Where): Promise<T[]>;
|
|
270
|
+
findOne<T>(collection: string, where: Where): Promise<T | null>;
|
|
271
|
+
update(collection: string, where: Where, patch: Record<string, unknown>): Promise<number>;
|
|
272
|
+
delete(collection: string, where: Where): Promise<number>;
|
|
273
|
+
count(collection: string, where?: Where): Promise<number>;
|
|
274
|
+
transaction<T>(fn: () => Promise<T>): Promise<T>;
|
|
275
|
+
getDB(): TesterPayKitDB;
|
|
276
|
+
getVersion(): Promise<number>;
|
|
277
|
+
migrate(_targetVersion: number): Promise<void>;
|
|
278
|
+
private _table;
|
|
279
|
+
/**
|
|
280
|
+
* Return the primary key field name for a given collection.
|
|
281
|
+
* Used by delete() to retrieve the PK value from each matched record.
|
|
282
|
+
*/
|
|
283
|
+
private _primaryKey;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export { IndexedDBAdapter, TesterPayKitDB };
|
|
287
|
+
export type { AnnotationInteraction, Breadcrumb, BugReport, BugReportRecord, CrashContext, DeviceIdMetadata, Event, EventRecord, Feedback, FeedbackRecord, OutboxRecord, SdkMetaRecord, Session, SessionEndFeedback, SessionRecord, Submission, Task, TaskRecord, TaskTracking, WeeklySummaryRecord, WidgetAnnotation };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { IStorage, Where } from '@testerpaykit/core';
|
|
2
|
+
import Dexie, { Table } from 'dexie';
|
|
3
|
+
|
|
4
|
+
interface SessionRecord {
|
|
5
|
+
id: string;
|
|
6
|
+
started_at: number;
|
|
7
|
+
ended_at: number | null;
|
|
8
|
+
duration_seconds: number | null;
|
|
9
|
+
screen_view_count: number;
|
|
10
|
+
tap_count: number;
|
|
11
|
+
end_reason: string | null;
|
|
12
|
+
foreground_seconds: number | null;
|
|
13
|
+
metadata?: string;
|
|
14
|
+
}
|
|
15
|
+
interface EventRecord {
|
|
16
|
+
id: string;
|
|
17
|
+
session_id: string;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
event_type: string;
|
|
20
|
+
screen_name: string | null;
|
|
21
|
+
element_id: string | null;
|
|
22
|
+
metadata: string | null;
|
|
23
|
+
}
|
|
24
|
+
interface OutboxRecord {
|
|
25
|
+
local_id: string;
|
|
26
|
+
type: string;
|
|
27
|
+
payload: string;
|
|
28
|
+
state: string;
|
|
29
|
+
attempts: number;
|
|
30
|
+
last_error: string | null;
|
|
31
|
+
created_at: string;
|
|
32
|
+
}
|
|
33
|
+
interface SdkMetaRecord {
|
|
34
|
+
key: string;
|
|
35
|
+
value: string;
|
|
36
|
+
}
|
|
37
|
+
interface BugReportRecord {
|
|
38
|
+
id: string;
|
|
39
|
+
session_id: string;
|
|
40
|
+
timestamp: number;
|
|
41
|
+
message: string;
|
|
42
|
+
stack: string | null;
|
|
43
|
+
severity: string;
|
|
44
|
+
}
|
|
45
|
+
interface FeedbackRecord {
|
|
46
|
+
id: string;
|
|
47
|
+
session_id: string;
|
|
48
|
+
content: string;
|
|
49
|
+
rating: number | null;
|
|
50
|
+
created_at: number;
|
|
51
|
+
}
|
|
52
|
+
interface TaskRecord {
|
|
53
|
+
id: string;
|
|
54
|
+
task_preset_id: string;
|
|
55
|
+
title: string;
|
|
56
|
+
started_at: number | null;
|
|
57
|
+
completed_at: number | null;
|
|
58
|
+
is_completed: number;
|
|
59
|
+
created_at: number;
|
|
60
|
+
}
|
|
61
|
+
interface WeeklySummaryRecord {
|
|
62
|
+
id: string;
|
|
63
|
+
data: string;
|
|
64
|
+
status: string;
|
|
65
|
+
created_at: number;
|
|
66
|
+
}
|
|
67
|
+
interface Event {
|
|
68
|
+
id?: string;
|
|
69
|
+
sessionId: string;
|
|
70
|
+
type: string;
|
|
71
|
+
timestamp: Date;
|
|
72
|
+
screenRoute?: string;
|
|
73
|
+
metadata?: string;
|
|
74
|
+
}
|
|
75
|
+
interface Session {
|
|
76
|
+
id?: string;
|
|
77
|
+
startedAt: Date;
|
|
78
|
+
endedAt?: Date;
|
|
79
|
+
durationSeconds?: number;
|
|
80
|
+
screenViewCount?: number;
|
|
81
|
+
tapCount?: number;
|
|
82
|
+
endReason?: string;
|
|
83
|
+
foregroundSeconds?: number;
|
|
84
|
+
metadata?: string;
|
|
85
|
+
}
|
|
86
|
+
interface Task {
|
|
87
|
+
id?: string;
|
|
88
|
+
taskPresetId: string;
|
|
89
|
+
title: string;
|
|
90
|
+
description?: string;
|
|
91
|
+
startedAt?: Date;
|
|
92
|
+
completedAt?: Date;
|
|
93
|
+
isCompleted?: boolean;
|
|
94
|
+
createdAt: Date;
|
|
95
|
+
}
|
|
96
|
+
interface Feedback {
|
|
97
|
+
id?: string;
|
|
98
|
+
sessionId?: string;
|
|
99
|
+
content: string;
|
|
100
|
+
rating?: number;
|
|
101
|
+
createdAt: Date;
|
|
102
|
+
metadata?: string;
|
|
103
|
+
}
|
|
104
|
+
interface Submission {
|
|
105
|
+
id?: string;
|
|
106
|
+
projectId: string;
|
|
107
|
+
testerId: string;
|
|
108
|
+
deviceId: string;
|
|
109
|
+
periodStart: Date;
|
|
110
|
+
periodEnd: Date;
|
|
111
|
+
metrics: string;
|
|
112
|
+
integrityHash: string;
|
|
113
|
+
deviceMetadata: string;
|
|
114
|
+
appMetadata: string;
|
|
115
|
+
status: string;
|
|
116
|
+
rejectionReason?: string;
|
|
117
|
+
estimatedPayout?: number;
|
|
118
|
+
actualPayout?: number;
|
|
119
|
+
createdAt: Date;
|
|
120
|
+
updatedAt: Date;
|
|
121
|
+
submittedAt?: Date;
|
|
122
|
+
}
|
|
123
|
+
interface BugReport {
|
|
124
|
+
id?: string;
|
|
125
|
+
sessionId: string;
|
|
126
|
+
testerId?: string;
|
|
127
|
+
type: string;
|
|
128
|
+
severity: string;
|
|
129
|
+
category: string;
|
|
130
|
+
title: string;
|
|
131
|
+
description: string;
|
|
132
|
+
affectedFeature?: string;
|
|
133
|
+
frequency?: string;
|
|
134
|
+
reproductionSteps?: string;
|
|
135
|
+
expectedBehavior?: string;
|
|
136
|
+
actualBehavior?: string;
|
|
137
|
+
currentScreen: string;
|
|
138
|
+
breadcrumbs?: string;
|
|
139
|
+
deviceSnapshot: string;
|
|
140
|
+
appSnapshot: string;
|
|
141
|
+
screenshotPath?: string;
|
|
142
|
+
annotatedScreenshotPath?: string;
|
|
143
|
+
screenRecordingPath?: string;
|
|
144
|
+
attachments?: string;
|
|
145
|
+
createdAt: Date;
|
|
146
|
+
submittedAt?: Date;
|
|
147
|
+
status?: string;
|
|
148
|
+
assignedTo?: string;
|
|
149
|
+
coordinatorNotes?: string;
|
|
150
|
+
severityConfidence?: number;
|
|
151
|
+
suggestedCategory?: string;
|
|
152
|
+
duplicateOf?: string;
|
|
153
|
+
}
|
|
154
|
+
interface Breadcrumb {
|
|
155
|
+
id?: string;
|
|
156
|
+
sessionId: string;
|
|
157
|
+
type: string;
|
|
158
|
+
timestamp: Date;
|
|
159
|
+
screen?: string;
|
|
160
|
+
action?: string;
|
|
161
|
+
data?: string;
|
|
162
|
+
message?: string;
|
|
163
|
+
}
|
|
164
|
+
interface CrashContext {
|
|
165
|
+
id?: string;
|
|
166
|
+
sessionId?: string;
|
|
167
|
+
error: string;
|
|
168
|
+
stackTrace: string;
|
|
169
|
+
breadcrumbs?: string;
|
|
170
|
+
deviceSnapshot: string;
|
|
171
|
+
appSnapshot: string;
|
|
172
|
+
crashTime: Date;
|
|
173
|
+
reported?: boolean;
|
|
174
|
+
}
|
|
175
|
+
interface SessionEndFeedback {
|
|
176
|
+
id?: string;
|
|
177
|
+
sessionId: string;
|
|
178
|
+
rating: number;
|
|
179
|
+
comment?: string;
|
|
180
|
+
categories?: string;
|
|
181
|
+
wouldRecommend?: boolean;
|
|
182
|
+
createdAt: Date;
|
|
183
|
+
}
|
|
184
|
+
interface DeviceIdMetadata {
|
|
185
|
+
id?: string;
|
|
186
|
+
deviceId: string;
|
|
187
|
+
isActive: boolean;
|
|
188
|
+
createdAt: Date;
|
|
189
|
+
expiresAt: Date;
|
|
190
|
+
}
|
|
191
|
+
interface TaskTracking {
|
|
192
|
+
id?: string;
|
|
193
|
+
taskId: string;
|
|
194
|
+
sessionId: string;
|
|
195
|
+
startedAt: Date;
|
|
196
|
+
completedAt?: Date;
|
|
197
|
+
abandonedAt?: Date;
|
|
198
|
+
durationSeconds?: number;
|
|
199
|
+
status: string;
|
|
200
|
+
metadata?: string;
|
|
201
|
+
}
|
|
202
|
+
interface WidgetAnnotation {
|
|
203
|
+
id?: string;
|
|
204
|
+
taskId: string;
|
|
205
|
+
widgetKey: string;
|
|
206
|
+
annotationType: string;
|
|
207
|
+
message: string;
|
|
208
|
+
priority: string;
|
|
209
|
+
elementBounds?: string;
|
|
210
|
+
metadata?: string;
|
|
211
|
+
createdAt: Date;
|
|
212
|
+
}
|
|
213
|
+
interface AnnotationInteraction {
|
|
214
|
+
id?: string;
|
|
215
|
+
sessionId: string;
|
|
216
|
+
annotationId: string;
|
|
217
|
+
taskId: string;
|
|
218
|
+
interactionType: string;
|
|
219
|
+
timestamp: Date;
|
|
220
|
+
elementBounds?: string;
|
|
221
|
+
metadata?: string;
|
|
222
|
+
inputValue?: string;
|
|
223
|
+
durationMs?: number;
|
|
224
|
+
triggeredCompletion?: boolean;
|
|
225
|
+
}
|
|
226
|
+
declare class TesterPayKitDB extends Dexie {
|
|
227
|
+
events: Table<Event, string>;
|
|
228
|
+
sessions: Table<Session, string>;
|
|
229
|
+
tasks: Table<Task, string>;
|
|
230
|
+
feedbacks: Table<Feedback, string>;
|
|
231
|
+
submissions: Table<Submission, string>;
|
|
232
|
+
bugReports: Table<BugReport, string>;
|
|
233
|
+
breadcrumbs: Table<Breadcrumb, string>;
|
|
234
|
+
crashContexts: Table<CrashContext, string>;
|
|
235
|
+
sessionEndFeedbacks: Table<SessionEndFeedback, string>;
|
|
236
|
+
deviceIdMetadata: Table<DeviceIdMetadata, string>;
|
|
237
|
+
taskTracking: Table<TaskTracking, string>;
|
|
238
|
+
widgetAnnotations: Table<WidgetAnnotation, string>;
|
|
239
|
+
annotationInteractions: Table<AnnotationInteraction, string>;
|
|
240
|
+
sdk_sessions: Table<SessionRecord, string>;
|
|
241
|
+
sdk_events: Table<EventRecord, string>;
|
|
242
|
+
outbox: Table<OutboxRecord, string>;
|
|
243
|
+
sdk_meta: Table<SdkMetaRecord, string>;
|
|
244
|
+
bug_reports: Table<BugReportRecord, string>;
|
|
245
|
+
sdk_feedbacks: Table<FeedbackRecord, string>;
|
|
246
|
+
sdk_tasks: Table<TaskRecord, string>;
|
|
247
|
+
weekly_summaries: Table<WeeklySummaryRecord, string>;
|
|
248
|
+
constructor();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* IndexedDB storage adapter for browser environments.
|
|
253
|
+
*
|
|
254
|
+
* Implements IStorage using Dexie.js. All operations go through the typed
|
|
255
|
+
* document/collection API (insert/find/findOne/update/delete/count) — no SQL.
|
|
256
|
+
*
|
|
257
|
+
* Collection names follow COLLECTIONS constants; each maps to a dedicated
|
|
258
|
+
* Dexie object store declared in schema version 2.
|
|
259
|
+
*
|
|
260
|
+
* The legacy getDB() / transaction() methods are kept so existing direct-Dexie
|
|
261
|
+
* tests continue to work.
|
|
262
|
+
*/
|
|
263
|
+
declare class IndexedDBAdapter implements IStorage {
|
|
264
|
+
private db;
|
|
265
|
+
constructor();
|
|
266
|
+
init(): Promise<void>;
|
|
267
|
+
close(): Promise<void>;
|
|
268
|
+
insert<T extends Record<string, unknown>>(collection: string, record: T): Promise<void>;
|
|
269
|
+
find<T>(collection: string, where?: Where): Promise<T[]>;
|
|
270
|
+
findOne<T>(collection: string, where: Where): Promise<T | null>;
|
|
271
|
+
update(collection: string, where: Where, patch: Record<string, unknown>): Promise<number>;
|
|
272
|
+
delete(collection: string, where: Where): Promise<number>;
|
|
273
|
+
count(collection: string, where?: Where): Promise<number>;
|
|
274
|
+
transaction<T>(fn: () => Promise<T>): Promise<T>;
|
|
275
|
+
getDB(): TesterPayKitDB;
|
|
276
|
+
getVersion(): Promise<number>;
|
|
277
|
+
migrate(_targetVersion: number): Promise<void>;
|
|
278
|
+
private _table;
|
|
279
|
+
/**
|
|
280
|
+
* Return the primary key field name for a given collection.
|
|
281
|
+
* Used by delete() to retrieve the PK value from each matched record.
|
|
282
|
+
*/
|
|
283
|
+
private _primaryKey;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export { IndexedDBAdapter, TesterPayKitDB };
|
|
287
|
+
export type { AnnotationInteraction, Breadcrumb, BugReport, BugReportRecord, CrashContext, DeviceIdMetadata, Event, EventRecord, Feedback, FeedbackRecord, OutboxRecord, SdkMetaRecord, Session, SessionEndFeedback, SessionRecord, Submission, Task, TaskRecord, TaskTracking, WeeklySummaryRecord, WidgetAnnotation };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
IndexedDBAdapter: () => IndexedDBAdapter,
|
|
34
|
+
TesterPayKitDB: () => TesterPayKitDB
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/IndexedDBAdapter.ts
|
|
39
|
+
var import_core = require("@testerpaykit/core");
|
|
40
|
+
|
|
41
|
+
// src/schema.ts
|
|
42
|
+
var import_dexie = __toESM(require("dexie"));
|
|
43
|
+
var TesterPayKitDB = class extends import_dexie.default {
|
|
44
|
+
constructor() {
|
|
45
|
+
super("TesterPayKitDB");
|
|
46
|
+
this.version(1).stores({
|
|
47
|
+
events: "++id, sessionId, timestamp, type",
|
|
48
|
+
sessions: "++id, startedAt",
|
|
49
|
+
tasks: "++id, taskPresetId, isCompleted, createdAt",
|
|
50
|
+
feedbacks: "++id, sessionId, createdAt",
|
|
51
|
+
submissions: "++id, projectId, testerId, deviceId, status, createdAt",
|
|
52
|
+
bugReports: "++id, sessionId, testerId, type, severity, status, createdAt",
|
|
53
|
+
breadcrumbs: "++id, sessionId, timestamp, type",
|
|
54
|
+
crashContexts: "++id, sessionId, crashTime, reported",
|
|
55
|
+
sessionEndFeedbacks: "++id, sessionId, createdAt",
|
|
56
|
+
deviceIdMetadata: "++id, deviceId, isActive, expiresAt",
|
|
57
|
+
taskTracking: "++id, taskId, sessionId, status, startedAt",
|
|
58
|
+
widgetAnnotations: "++id, taskId, widgetKey, createdAt",
|
|
59
|
+
annotationInteractions: "++id, sessionId, annotationId, taskId, timestamp"
|
|
60
|
+
});
|
|
61
|
+
this.version(2).stores({
|
|
62
|
+
events: "++id, sessionId, timestamp, type",
|
|
63
|
+
sessions: "++id, startedAt",
|
|
64
|
+
tasks: "++id, taskPresetId, isCompleted, createdAt",
|
|
65
|
+
feedbacks: "++id, sessionId, createdAt",
|
|
66
|
+
submissions: "++id, projectId, testerId, deviceId, status, createdAt",
|
|
67
|
+
bugReports: "++id, sessionId, testerId, type, severity, status, createdAt",
|
|
68
|
+
breadcrumbs: "++id, sessionId, timestamp, type",
|
|
69
|
+
crashContexts: "++id, sessionId, crashTime, reported",
|
|
70
|
+
sessionEndFeedbacks: "++id, sessionId, createdAt",
|
|
71
|
+
deviceIdMetadata: "++id, deviceId, isActive, expiresAt",
|
|
72
|
+
taskTracking: "++id, taskId, sessionId, status, startedAt",
|
|
73
|
+
widgetAnnotations: "++id, taskId, widgetKey, createdAt",
|
|
74
|
+
annotationInteractions: "++id, sessionId, annotationId, taskId, timestamp",
|
|
75
|
+
// SDK-core flat stores
|
|
76
|
+
sdk_sessions: "id, started_at, ended_at",
|
|
77
|
+
sdk_events: "id, session_id, timestamp, event_type",
|
|
78
|
+
outbox: "local_id, state",
|
|
79
|
+
sdk_meta: "key",
|
|
80
|
+
bug_reports: "id, session_id, timestamp, severity",
|
|
81
|
+
sdk_feedbacks: "id, session_id, created_at",
|
|
82
|
+
sdk_tasks: "id, task_preset_id, is_completed, created_at",
|
|
83
|
+
weekly_summaries: "id, status, created_at"
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/IndexedDBAdapter.ts
|
|
89
|
+
var COLLECTION_TO_TABLE = {
|
|
90
|
+
[import_core.COLLECTIONS.sessions]: "sdk_sessions",
|
|
91
|
+
[import_core.COLLECTIONS.events]: "sdk_events",
|
|
92
|
+
[import_core.COLLECTIONS.outbox]: "outbox",
|
|
93
|
+
[import_core.COLLECTIONS.sdkMeta]: "sdk_meta",
|
|
94
|
+
[import_core.COLLECTIONS.bugReports]: "bug_reports",
|
|
95
|
+
[import_core.COLLECTIONS.feedbacks]: "sdk_feedbacks",
|
|
96
|
+
[import_core.COLLECTIONS.tasks]: "sdk_tasks",
|
|
97
|
+
[import_core.COLLECTIONS.weeklySummaries]: "weekly_summaries"
|
|
98
|
+
};
|
|
99
|
+
function matchesWhere(record, where) {
|
|
100
|
+
for (const [field, condition] of Object.entries(where)) {
|
|
101
|
+
const val = record[field];
|
|
102
|
+
if (condition === null) {
|
|
103
|
+
if (val !== null && val !== void 0) return false;
|
|
104
|
+
} else if (typeof condition === "object" && !Array.isArray(condition)) {
|
|
105
|
+
const cond = condition;
|
|
106
|
+
if (cond.ne !== void 0) {
|
|
107
|
+
if (cond.ne === null) {
|
|
108
|
+
if (val === null || val === void 0) return false;
|
|
109
|
+
} else {
|
|
110
|
+
if (val === cond.ne) return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (cond.in !== void 0) {
|
|
114
|
+
if (!cond.in.includes(val)) return false;
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
if (val !== condition) return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
var IndexedDBAdapter = class {
|
|
123
|
+
constructor() {
|
|
124
|
+
this.db = new TesterPayKitDB();
|
|
125
|
+
}
|
|
126
|
+
// ── IStorage.init ──────────────────────────────────────────────────────────
|
|
127
|
+
async init() {
|
|
128
|
+
await this.db.open();
|
|
129
|
+
}
|
|
130
|
+
// ── IStorage.close ─────────────────────────────────────────────────────────
|
|
131
|
+
async close() {
|
|
132
|
+
this.db.close();
|
|
133
|
+
}
|
|
134
|
+
// ── IStorage.insert ────────────────────────────────────────────────────────
|
|
135
|
+
async insert(collection, record) {
|
|
136
|
+
const table = this._table(collection);
|
|
137
|
+
await table.put(record);
|
|
138
|
+
}
|
|
139
|
+
// ── IStorage.find ──────────────────────────────────────────────────────────
|
|
140
|
+
async find(collection, where) {
|
|
141
|
+
const table = this._table(collection);
|
|
142
|
+
if (!where || Object.keys(where).length === 0) {
|
|
143
|
+
return table.toArray();
|
|
144
|
+
}
|
|
145
|
+
const all = await table.toArray();
|
|
146
|
+
return all.filter(
|
|
147
|
+
(r) => matchesWhere(r, where)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
// ── IStorage.findOne ───────────────────────────────────────────────────────
|
|
151
|
+
async findOne(collection, where) {
|
|
152
|
+
const table = this._table(collection);
|
|
153
|
+
const all = await table.toArray();
|
|
154
|
+
const match = all.find(
|
|
155
|
+
(r) => matchesWhere(r, where)
|
|
156
|
+
);
|
|
157
|
+
return match ?? null;
|
|
158
|
+
}
|
|
159
|
+
// ── IStorage.update ────────────────────────────────────────────────────────
|
|
160
|
+
async update(collection, where, patch) {
|
|
161
|
+
const table = this._table(collection);
|
|
162
|
+
const all = await table.toArray();
|
|
163
|
+
const matches = all.filter(
|
|
164
|
+
(r) => matchesWhere(r, where)
|
|
165
|
+
);
|
|
166
|
+
for (const record of matches) {
|
|
167
|
+
const updated = { ...record, ...patch };
|
|
168
|
+
await table.put(updated);
|
|
169
|
+
}
|
|
170
|
+
return matches.length;
|
|
171
|
+
}
|
|
172
|
+
// ── IStorage.delete ────────────────────────────────────────────────────────
|
|
173
|
+
async delete(collection, where) {
|
|
174
|
+
const table = this._table(collection);
|
|
175
|
+
const pk = this._primaryKey(collection);
|
|
176
|
+
const all = await table.toArray();
|
|
177
|
+
const matches = all.filter(
|
|
178
|
+
(r) => matchesWhere(r, where)
|
|
179
|
+
);
|
|
180
|
+
for (const record of matches) {
|
|
181
|
+
const key = record[pk];
|
|
182
|
+
await table.delete(key);
|
|
183
|
+
}
|
|
184
|
+
return matches.length;
|
|
185
|
+
}
|
|
186
|
+
// ── IStorage.count ─────────────────────────────────────────────────────────
|
|
187
|
+
async count(collection, where) {
|
|
188
|
+
if (!where || Object.keys(where).length === 0) {
|
|
189
|
+
return this._table(collection).count();
|
|
190
|
+
}
|
|
191
|
+
const rows = await this.find(collection, where);
|
|
192
|
+
return rows.length;
|
|
193
|
+
}
|
|
194
|
+
// ── Legacy helpers (kept for existing direct-Dexie tests) ──────────────────
|
|
195
|
+
async transaction(fn) {
|
|
196
|
+
return this.db.transaction("rw", this.db.tables, fn);
|
|
197
|
+
}
|
|
198
|
+
getDB() {
|
|
199
|
+
return this.db;
|
|
200
|
+
}
|
|
201
|
+
async getVersion() {
|
|
202
|
+
return this.db.verno;
|
|
203
|
+
}
|
|
204
|
+
async migrate(_targetVersion) {
|
|
205
|
+
}
|
|
206
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
207
|
+
_table(collection) {
|
|
208
|
+
const prop = COLLECTION_TO_TABLE[collection];
|
|
209
|
+
if (!prop) {
|
|
210
|
+
throw new Error(`Unknown collection: ${collection}`);
|
|
211
|
+
}
|
|
212
|
+
return this.db[prop];
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Return the primary key field name for a given collection.
|
|
216
|
+
* Used by delete() to retrieve the PK value from each matched record.
|
|
217
|
+
*/
|
|
218
|
+
_primaryKey(collection) {
|
|
219
|
+
switch (collection) {
|
|
220
|
+
case import_core.COLLECTIONS.outbox:
|
|
221
|
+
return "local_id";
|
|
222
|
+
case import_core.COLLECTIONS.sdkMeta:
|
|
223
|
+
return "key";
|
|
224
|
+
default:
|
|
225
|
+
return "id";
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
230
|
+
0 && (module.exports = {
|
|
231
|
+
IndexedDBAdapter,
|
|
232
|
+
TesterPayKitDB
|
|
233
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// src/IndexedDBAdapter.ts
|
|
2
|
+
import { COLLECTIONS } from "@testerpaykit/core";
|
|
3
|
+
|
|
4
|
+
// src/schema.ts
|
|
5
|
+
import Dexie from "dexie";
|
|
6
|
+
var TesterPayKitDB = class extends Dexie {
|
|
7
|
+
constructor() {
|
|
8
|
+
super("TesterPayKitDB");
|
|
9
|
+
this.version(1).stores({
|
|
10
|
+
events: "++id, sessionId, timestamp, type",
|
|
11
|
+
sessions: "++id, startedAt",
|
|
12
|
+
tasks: "++id, taskPresetId, isCompleted, createdAt",
|
|
13
|
+
feedbacks: "++id, sessionId, createdAt",
|
|
14
|
+
submissions: "++id, projectId, testerId, deviceId, status, createdAt",
|
|
15
|
+
bugReports: "++id, sessionId, testerId, type, severity, status, createdAt",
|
|
16
|
+
breadcrumbs: "++id, sessionId, timestamp, type",
|
|
17
|
+
crashContexts: "++id, sessionId, crashTime, reported",
|
|
18
|
+
sessionEndFeedbacks: "++id, sessionId, createdAt",
|
|
19
|
+
deviceIdMetadata: "++id, deviceId, isActive, expiresAt",
|
|
20
|
+
taskTracking: "++id, taskId, sessionId, status, startedAt",
|
|
21
|
+
widgetAnnotations: "++id, taskId, widgetKey, createdAt",
|
|
22
|
+
annotationInteractions: "++id, sessionId, annotationId, taskId, timestamp"
|
|
23
|
+
});
|
|
24
|
+
this.version(2).stores({
|
|
25
|
+
events: "++id, sessionId, timestamp, type",
|
|
26
|
+
sessions: "++id, startedAt",
|
|
27
|
+
tasks: "++id, taskPresetId, isCompleted, createdAt",
|
|
28
|
+
feedbacks: "++id, sessionId, createdAt",
|
|
29
|
+
submissions: "++id, projectId, testerId, deviceId, status, createdAt",
|
|
30
|
+
bugReports: "++id, sessionId, testerId, type, severity, status, createdAt",
|
|
31
|
+
breadcrumbs: "++id, sessionId, timestamp, type",
|
|
32
|
+
crashContexts: "++id, sessionId, crashTime, reported",
|
|
33
|
+
sessionEndFeedbacks: "++id, sessionId, createdAt",
|
|
34
|
+
deviceIdMetadata: "++id, deviceId, isActive, expiresAt",
|
|
35
|
+
taskTracking: "++id, taskId, sessionId, status, startedAt",
|
|
36
|
+
widgetAnnotations: "++id, taskId, widgetKey, createdAt",
|
|
37
|
+
annotationInteractions: "++id, sessionId, annotationId, taskId, timestamp",
|
|
38
|
+
// SDK-core flat stores
|
|
39
|
+
sdk_sessions: "id, started_at, ended_at",
|
|
40
|
+
sdk_events: "id, session_id, timestamp, event_type",
|
|
41
|
+
outbox: "local_id, state",
|
|
42
|
+
sdk_meta: "key",
|
|
43
|
+
bug_reports: "id, session_id, timestamp, severity",
|
|
44
|
+
sdk_feedbacks: "id, session_id, created_at",
|
|
45
|
+
sdk_tasks: "id, task_preset_id, is_completed, created_at",
|
|
46
|
+
weekly_summaries: "id, status, created_at"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/IndexedDBAdapter.ts
|
|
52
|
+
var COLLECTION_TO_TABLE = {
|
|
53
|
+
[COLLECTIONS.sessions]: "sdk_sessions",
|
|
54
|
+
[COLLECTIONS.events]: "sdk_events",
|
|
55
|
+
[COLLECTIONS.outbox]: "outbox",
|
|
56
|
+
[COLLECTIONS.sdkMeta]: "sdk_meta",
|
|
57
|
+
[COLLECTIONS.bugReports]: "bug_reports",
|
|
58
|
+
[COLLECTIONS.feedbacks]: "sdk_feedbacks",
|
|
59
|
+
[COLLECTIONS.tasks]: "sdk_tasks",
|
|
60
|
+
[COLLECTIONS.weeklySummaries]: "weekly_summaries"
|
|
61
|
+
};
|
|
62
|
+
function matchesWhere(record, where) {
|
|
63
|
+
for (const [field, condition] of Object.entries(where)) {
|
|
64
|
+
const val = record[field];
|
|
65
|
+
if (condition === null) {
|
|
66
|
+
if (val !== null && val !== void 0) return false;
|
|
67
|
+
} else if (typeof condition === "object" && !Array.isArray(condition)) {
|
|
68
|
+
const cond = condition;
|
|
69
|
+
if (cond.ne !== void 0) {
|
|
70
|
+
if (cond.ne === null) {
|
|
71
|
+
if (val === null || val === void 0) return false;
|
|
72
|
+
} else {
|
|
73
|
+
if (val === cond.ne) return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (cond.in !== void 0) {
|
|
77
|
+
if (!cond.in.includes(val)) return false;
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
if (val !== condition) return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
var IndexedDBAdapter = class {
|
|
86
|
+
constructor() {
|
|
87
|
+
this.db = new TesterPayKitDB();
|
|
88
|
+
}
|
|
89
|
+
// ── IStorage.init ──────────────────────────────────────────────────────────
|
|
90
|
+
async init() {
|
|
91
|
+
await this.db.open();
|
|
92
|
+
}
|
|
93
|
+
// ── IStorage.close ─────────────────────────────────────────────────────────
|
|
94
|
+
async close() {
|
|
95
|
+
this.db.close();
|
|
96
|
+
}
|
|
97
|
+
// ── IStorage.insert ────────────────────────────────────────────────────────
|
|
98
|
+
async insert(collection, record) {
|
|
99
|
+
const table = this._table(collection);
|
|
100
|
+
await table.put(record);
|
|
101
|
+
}
|
|
102
|
+
// ── IStorage.find ──────────────────────────────────────────────────────────
|
|
103
|
+
async find(collection, where) {
|
|
104
|
+
const table = this._table(collection);
|
|
105
|
+
if (!where || Object.keys(where).length === 0) {
|
|
106
|
+
return table.toArray();
|
|
107
|
+
}
|
|
108
|
+
const all = await table.toArray();
|
|
109
|
+
return all.filter(
|
|
110
|
+
(r) => matchesWhere(r, where)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
// ── IStorage.findOne ───────────────────────────────────────────────────────
|
|
114
|
+
async findOne(collection, where) {
|
|
115
|
+
const table = this._table(collection);
|
|
116
|
+
const all = await table.toArray();
|
|
117
|
+
const match = all.find(
|
|
118
|
+
(r) => matchesWhere(r, where)
|
|
119
|
+
);
|
|
120
|
+
return match ?? null;
|
|
121
|
+
}
|
|
122
|
+
// ── IStorage.update ────────────────────────────────────────────────────────
|
|
123
|
+
async update(collection, where, patch) {
|
|
124
|
+
const table = this._table(collection);
|
|
125
|
+
const all = await table.toArray();
|
|
126
|
+
const matches = all.filter(
|
|
127
|
+
(r) => matchesWhere(r, where)
|
|
128
|
+
);
|
|
129
|
+
for (const record of matches) {
|
|
130
|
+
const updated = { ...record, ...patch };
|
|
131
|
+
await table.put(updated);
|
|
132
|
+
}
|
|
133
|
+
return matches.length;
|
|
134
|
+
}
|
|
135
|
+
// ── IStorage.delete ────────────────────────────────────────────────────────
|
|
136
|
+
async delete(collection, where) {
|
|
137
|
+
const table = this._table(collection);
|
|
138
|
+
const pk = this._primaryKey(collection);
|
|
139
|
+
const all = await table.toArray();
|
|
140
|
+
const matches = all.filter(
|
|
141
|
+
(r) => matchesWhere(r, where)
|
|
142
|
+
);
|
|
143
|
+
for (const record of matches) {
|
|
144
|
+
const key = record[pk];
|
|
145
|
+
await table.delete(key);
|
|
146
|
+
}
|
|
147
|
+
return matches.length;
|
|
148
|
+
}
|
|
149
|
+
// ── IStorage.count ─────────────────────────────────────────────────────────
|
|
150
|
+
async count(collection, where) {
|
|
151
|
+
if (!where || Object.keys(where).length === 0) {
|
|
152
|
+
return this._table(collection).count();
|
|
153
|
+
}
|
|
154
|
+
const rows = await this.find(collection, where);
|
|
155
|
+
return rows.length;
|
|
156
|
+
}
|
|
157
|
+
// ── Legacy helpers (kept for existing direct-Dexie tests) ──────────────────
|
|
158
|
+
async transaction(fn) {
|
|
159
|
+
return this.db.transaction("rw", this.db.tables, fn);
|
|
160
|
+
}
|
|
161
|
+
getDB() {
|
|
162
|
+
return this.db;
|
|
163
|
+
}
|
|
164
|
+
async getVersion() {
|
|
165
|
+
return this.db.verno;
|
|
166
|
+
}
|
|
167
|
+
async migrate(_targetVersion) {
|
|
168
|
+
}
|
|
169
|
+
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
170
|
+
_table(collection) {
|
|
171
|
+
const prop = COLLECTION_TO_TABLE[collection];
|
|
172
|
+
if (!prop) {
|
|
173
|
+
throw new Error(`Unknown collection: ${collection}`);
|
|
174
|
+
}
|
|
175
|
+
return this.db[prop];
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Return the primary key field name for a given collection.
|
|
179
|
+
* Used by delete() to retrieve the PK value from each matched record.
|
|
180
|
+
*/
|
|
181
|
+
_primaryKey(collection) {
|
|
182
|
+
switch (collection) {
|
|
183
|
+
case COLLECTIONS.outbox:
|
|
184
|
+
return "local_id";
|
|
185
|
+
case COLLECTIONS.sdkMeta:
|
|
186
|
+
return "key";
|
|
187
|
+
default:
|
|
188
|
+
return "id";
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
export {
|
|
193
|
+
IndexedDBAdapter,
|
|
194
|
+
TesterPayKitDB
|
|
195
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testerpaykit/storage-browser",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "IndexedDB storage adapter for TesterPayKit SDK",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"README.md"
|
|
8
|
+
],
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"module": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.mjs",
|
|
18
|
+
"require": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"dexie": "^4.4.6",
|
|
24
|
+
"@testerpaykit/core": "1.3.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^26.6.5",
|
|
28
|
+
"fake-indexeddb": "^6.2.6",
|
|
29
|
+
"jsdom": "^30.1.3",
|
|
30
|
+
"tsup": "^9.0.0",
|
|
31
|
+
"typescript": "^6.0.3",
|
|
32
|
+
"vitest": "^5.0.5"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"testerpaykit",
|
|
36
|
+
"storage",
|
|
37
|
+
"indexeddb",
|
|
38
|
+
"browser",
|
|
39
|
+
"typescript"
|
|
40
|
+
],
|
|
41
|
+
"author": "TesterPayKit Team",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
45
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
46
|
+
"test": "vitest",
|
|
47
|
+
"lint": "eslint src --ext .ts"
|
|
48
|
+
}
|
|
6
49
|
}
|