@delta-comic/db 3.0.0-next.11 → 3.0.0-next.12
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/dist/index.d.mts +529 -68
- package/dist/index.mjs +308 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
import { isTauri } from "@tauri-apps/api/core";
|
|
2
|
-
import { InsertObject, JSONColumnType, Kysely, Kysely as Kysely$1, SelectQueryBuilder, Selectable } from "kysely";
|
|
2
|
+
import { InsertObject, JSONColumnType, Kysely, Kysely as Kysely$1, KyselyPlugin, PluginTransformQueryArgs, PluginTransformResultArgs, QueryResult, RootOperationNode, SelectQueryBuilder, Selectable, UnknownRow } from "kysely";
|
|
3
3
|
import { EntryKey } from "@pinia/colada";
|
|
4
|
-
import { FormResult, FormSingleConfigure, PluginManifest, SourcedKeyType, SourcedValue, UniEpRaw, UniItem, UniItemAuthor, UniItemRaw } from "@delta-comic/model";
|
|
5
4
|
import { MaybeRefOrGetter, Ref } from "vue";
|
|
5
|
+
import { FormResult, FormSingleConfigure, PluginManifest, SourcedKeyType, SourcedValue, UniEpRaw, UniItem, UniItemAuthor, UniItemRaw } from "@delta-comic/model";
|
|
6
|
+
import { TSchema } from "typebox";
|
|
7
|
+
//#region lib/generated/favourite_card.table.d.ts
|
|
8
|
+
interface FavouriteCardTable {
|
|
9
|
+
createAt: number;
|
|
10
|
+
title: string;
|
|
11
|
+
private: boolean;
|
|
12
|
+
description: string;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region lib/generated/favourite_item.table.d.ts
|
|
16
|
+
interface FavouriteItemTable {
|
|
17
|
+
addTime: number;
|
|
18
|
+
belongTo: number;
|
|
19
|
+
itemKey: string;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region lib/generated/item_store.table.d.ts
|
|
23
|
+
interface ItemStoreTable {
|
|
24
|
+
key: string;
|
|
25
|
+
item: JSONColumnType<UniItemRaw>;
|
|
26
|
+
}
|
|
6
27
|
declare namespace utils_d_exports {
|
|
7
28
|
export { CommonQueryKey, countDb, withTransition };
|
|
8
29
|
}
|
|
@@ -14,11 +35,7 @@ declare enum CommonQueryKey {
|
|
|
14
35
|
declare namespace itemStore_d_exports {
|
|
15
36
|
export { QueryKey$5 as QueryKey, StorableItem, StoredItem, Table$6 as Table, itemKey, useUpsert$4 as useUpsert };
|
|
16
37
|
}
|
|
17
|
-
|
|
18
|
-
/** @description primary key */
|
|
19
|
-
key: string;
|
|
20
|
-
item: JSONColumnType<UniItemRaw>;
|
|
21
|
-
}
|
|
38
|
+
type Table$6 = ItemStoreTable;
|
|
22
39
|
type StorableItem = UniItem | UniItemRaw;
|
|
23
40
|
type StoredItem = Selectable<Table$6>;
|
|
24
41
|
declare const itemKey: SourcedValue<[string, string]>;
|
|
@@ -50,20 +67,9 @@ declare const useUpsert$4: () => {
|
|
|
50
67
|
declare namespace favourite_d_exports {
|
|
51
68
|
export { Card, CardTable, Item$3 as Item, ItemTable, QueryKey$4 as QueryKey, useCreateCard, useMoveItem, useQueryCard, useQueryItem, useUpsertItem };
|
|
52
69
|
}
|
|
53
|
-
|
|
54
|
-
title: string;
|
|
55
|
-
private: boolean;
|
|
56
|
-
description: string;
|
|
57
|
-
/** @description primary key */
|
|
58
|
-
createAt: number;
|
|
59
|
-
}
|
|
70
|
+
type CardTable = FavouriteCardTable;
|
|
60
71
|
type Card = Selectable<CardTable>;
|
|
61
|
-
|
|
62
|
-
itemKey: string;
|
|
63
|
-
/** @description foreign key */
|
|
64
|
-
belongTo: CardTable['createAt'];
|
|
65
|
-
addTime: number;
|
|
66
|
-
}
|
|
72
|
+
type ItemTable = FavouriteItemTable;
|
|
67
73
|
type Item$3 = Selectable<ItemTable>;
|
|
68
74
|
declare enum QueryKey$4 {
|
|
69
75
|
item = "db:favouriteItem:",
|
|
@@ -75,7 +81,7 @@ declare const useUpsertItem: () => {
|
|
|
75
81
|
belongTos: Item$3["belongTo"][];
|
|
76
82
|
trx?: Kysely$1<DB>;
|
|
77
83
|
}) => Promise<void>;
|
|
78
|
-
key: (CommonQueryKey | QueryKey$
|
|
84
|
+
key: (CommonQueryKey | QueryKey$5 | QueryKey$4)[];
|
|
79
85
|
state: import("vue").ComputedRef<import("@pinia/colada").DataState<void, Error, undefined>>;
|
|
80
86
|
status: import("vue").ShallowRef<import("@pinia/colada").DataStateStatus>;
|
|
81
87
|
asyncStatus: import("vue").ShallowRef<import("@pinia/colada").AsyncStatus>;
|
|
@@ -144,23 +150,27 @@ declare const useCreateCard: () => {
|
|
|
144
150
|
}) => void;
|
|
145
151
|
reset: () => void;
|
|
146
152
|
};
|
|
147
|
-
declare const useQueryItem: <T>(query: (db: SelectQueryBuilder<DB, "favouriteItem", {}>) => Promise<T>, otherKeys?:
|
|
148
|
-
declare const useQueryCard: <T>(query: (db: SelectQueryBuilder<DB, "favouriteCard", {}>) => Promise<T>, otherKeys?:
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
type Meta = PluginManifest;
|
|
153
|
-
interface Table$5 {
|
|
153
|
+
declare const useQueryItem: <T>(query: (db: SelectQueryBuilder<DB, "favouriteItem", {}>) => Promise<T>, otherKeys?: MaybeRefOrGetter<EntryKey>, initialData?: () => T) => import("@pinia/colada").UseQueryReturn<T, Error, T>;
|
|
154
|
+
declare const useQueryCard: <T>(query: (db: SelectQueryBuilder<DB, "favouriteCard", {}>) => Promise<T>, otherKeys?: MaybeRefOrGetter<EntryKey>, initialData?: () => T) => import("@pinia/colada").UseQueryReturn<T, Error, T>;
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region lib/generated/plugin.table.d.ts
|
|
157
|
+
interface PluginTable {
|
|
154
158
|
installerName: string;
|
|
155
159
|
loaderName: string;
|
|
156
|
-
/** @description primary key */
|
|
157
160
|
pluginName: string;
|
|
158
|
-
meta: JSONColumnType<
|
|
161
|
+
meta: JSONColumnType<PluginManifest>;
|
|
159
162
|
enable: boolean;
|
|
160
163
|
installInput: string;
|
|
161
|
-
displayName: string;
|
|
164
|
+
displayName: string | null;
|
|
162
165
|
}
|
|
163
|
-
|
|
166
|
+
declare namespace plugin_d_exports {
|
|
167
|
+
export { Archive, Meta, QueryKey$3 as QueryKey, Table$5 as Table, removeByNames, useQuery$4 as useQuery, useRemove$3 as useRemove, useToggleEnable, useUpsert$3 as useUpsert };
|
|
168
|
+
}
|
|
169
|
+
type Meta = PluginManifest;
|
|
170
|
+
type Table$5 = Omit<PluginTable, 'meta' | 'enable'> & {
|
|
171
|
+
meta: Selectable<PluginTable>['meta'];
|
|
172
|
+
enable: boolean;
|
|
173
|
+
};
|
|
164
174
|
type Archive = Selectable<Table$5>;
|
|
165
175
|
declare enum QueryKey$3 {
|
|
166
176
|
item = "db:plugin:"
|
|
@@ -233,15 +243,17 @@ declare const useToggleEnable: () => {
|
|
|
233
243
|
reset: () => void;
|
|
234
244
|
};
|
|
235
245
|
declare const useQuery$4: <T>(query: (db: SelectQueryBuilder<DB, "plugin", {}>) => Promise<T>, otherKeys?: readonly EntryKey[], initialData?: () => T) => import("@pinia/colada").UseQueryReturn<T, Error, T>;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
/** @description primary key */
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region lib/generated/history.table.d.ts
|
|
248
|
+
interface HistoryTable {
|
|
249
|
+
ep: JSONColumnType<UniEpRaw>;
|
|
241
250
|
timestamp: number;
|
|
242
251
|
itemKey: string;
|
|
243
|
-
ep: JSONColumnType<UniEpRaw>;
|
|
244
252
|
}
|
|
253
|
+
declare namespace history_d_exports {
|
|
254
|
+
export { Item$2 as Item, QueryKey$2 as QueryKey, Table$4 as Table, useQuery$3 as useQuery, useRemove$2 as useRemove, useUpsert$2 as useUpsert };
|
|
255
|
+
}
|
|
256
|
+
type Table$4 = HistoryTable;
|
|
245
257
|
type Item$2 = Selectable<Table$4>;
|
|
246
258
|
declare enum QueryKey$2 {
|
|
247
259
|
item = "db:history:"
|
|
@@ -291,39 +303,44 @@ declare const useRemove$2: () => {
|
|
|
291
303
|
reset: () => void;
|
|
292
304
|
};
|
|
293
305
|
declare const useQuery$3: <T>(query: (db: SelectQueryBuilder<DB, "history", {}>) => Promise<T>, otherKeys?: readonly EntryKey[], initialData?: () => T) => import("@pinia/colada").UseQueryReturn<T, Error, T>;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
interface Table$3 {
|
|
298
|
-
/** @description config owner, usually plugin name */
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region lib/generated/config.table.d.ts
|
|
308
|
+
interface ConfigTable {
|
|
299
309
|
belongTo: string;
|
|
300
|
-
/** @description serialized form structure */
|
|
301
310
|
form: string;
|
|
302
|
-
/** @description serialized config data */
|
|
303
311
|
data: string;
|
|
304
312
|
}
|
|
313
|
+
declare namespace config_d_exports {
|
|
314
|
+
export { ConfigDescription, ConfigRef, Table$3 as Table, useConfig };
|
|
315
|
+
}
|
|
316
|
+
type Table$3 = ConfigTable;
|
|
305
317
|
type ConfigRef<T> = Ref<T> & {
|
|
306
318
|
readonly ready: Promise<void>;
|
|
307
319
|
};
|
|
308
320
|
type ConfigDescription = Record<string, Required<Pick<FormSingleConfigure, 'defaultValue'>> & FormSingleConfigure>;
|
|
309
321
|
declare const useConfig: <T extends ConfigDescription>(belongTo: string, form: T) => ConfigRef<FormResult<T>>;
|
|
310
322
|
//#endregion
|
|
311
|
-
//#region lib/
|
|
312
|
-
interface
|
|
323
|
+
//#region lib/generated/native_store.table.d.ts
|
|
324
|
+
interface NativeStoreTable {
|
|
313
325
|
namespace: string;
|
|
314
326
|
key: string;
|
|
315
327
|
value: string;
|
|
316
328
|
}
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region lib/nativeStore/index.d.ts
|
|
331
|
+
type Table = NativeStoreTable;
|
|
317
332
|
declare const useNativeStore: <T extends object>(namespace: string, key: MaybeRefOrGetter<string>, defaultValue: MaybeRefOrGetter<T>) => Ref<T, T>;
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
interface Table$2 {
|
|
322
|
-
/** @description primary key */
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region lib/generated/recent_view.table.d.ts
|
|
335
|
+
interface RecentViewTable {
|
|
323
336
|
timestamp: number;
|
|
324
337
|
itemKey: string;
|
|
325
338
|
isViewed: boolean;
|
|
326
339
|
}
|
|
340
|
+
declare namespace recentView_d_exports {
|
|
341
|
+
export { Item$1 as Item, QueryKey$1 as QueryKey, Table$2 as Table, useQuery$2 as useQuery, useRemove$1 as useRemove, useUpsert$1 as useUpsert };
|
|
342
|
+
}
|
|
343
|
+
type Table$2 = RecentViewTable;
|
|
327
344
|
type Item$1 = Selectable<Table$2>;
|
|
328
345
|
declare enum QueryKey$1 {
|
|
329
346
|
item = "db:recentView:"
|
|
@@ -373,31 +390,34 @@ declare const useRemove$1: () => {
|
|
|
373
390
|
reset: () => void;
|
|
374
391
|
};
|
|
375
392
|
declare const useQuery$2: <T>(query: (db: SelectQueryBuilder<DB, "recentView", {}>) => Promise<T>, otherKeys?: readonly EntryKey[], initialData?: () => T) => import("@pinia/colada").UseQueryReturn<T, Error, T>;
|
|
393
|
+
//#endregion
|
|
394
|
+
//#region lib/generated/subscribe.table.d.ts
|
|
395
|
+
interface SubscribeTable {
|
|
396
|
+
itemKey: string | null;
|
|
397
|
+
author: JSONColumnType<UniItemAuthor> | null;
|
|
398
|
+
type: string;
|
|
399
|
+
key: string;
|
|
400
|
+
plugin: string;
|
|
401
|
+
}
|
|
376
402
|
declare namespace subscribe_d_exports {
|
|
377
403
|
export { AuthorItem, AuthorTable, EpItem, EpTable, Item, Key, Key_, QueryKey, Table$1 as Table, key, useQuery$1 as useQuery, useRemove, useUpsert };
|
|
378
404
|
}
|
|
379
405
|
declare const key: SourcedValue<[plugin: string, label: string]>;
|
|
380
406
|
type Key_ = SourcedKeyType<typeof key>;
|
|
381
407
|
type Key = Exclude<Key_, string>;
|
|
382
|
-
|
|
383
|
-
author:
|
|
408
|
+
type AuthorTable = Omit<SubscribeTable, 'itemKey' | 'author' | 'type'> & {
|
|
409
|
+
author: Selectable<SubscribeTable>['author'];
|
|
384
410
|
itemKey: null;
|
|
385
411
|
type: 'author';
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
type AuthorItem = Selectable<AuthorTable>;
|
|
391
|
-
interface EpTable {
|
|
412
|
+
};
|
|
413
|
+
type AuthorItem = AuthorTable;
|
|
414
|
+
type EpTable = Omit<SubscribeTable, 'itemKey' | 'author' | 'type'> & {
|
|
392
415
|
author: null;
|
|
393
416
|
itemKey: string;
|
|
394
417
|
type: 'ep';
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
type EpItem = Selectable<EpTable>;
|
|
400
|
-
type Table$1 = AuthorTable | EpTable;
|
|
418
|
+
};
|
|
419
|
+
type EpItem = EpTable;
|
|
420
|
+
type Table$1 = SubscribeTable;
|
|
401
421
|
type Item = AuthorItem | EpItem;
|
|
402
422
|
declare enum QueryKey {
|
|
403
423
|
item = "db:subscribe:"
|
|
@@ -448,6 +468,447 @@ declare const useRemove: () => {
|
|
|
448
468
|
};
|
|
449
469
|
declare const useQuery$1: <T>(query: (db: SelectQueryBuilder<DB, "subscribe", {}>) => Promise<T>, otherKeys?: readonly EntryKey[], initialData?: () => T) => import("@pinia/colada").UseQueryReturn<T, Error, T>;
|
|
450
470
|
//#endregion
|
|
471
|
+
//#region lib/writeValidation.d.ts
|
|
472
|
+
/**
|
|
473
|
+
* Centralized write gate: validates every insert/replace/update against the
|
|
474
|
+
* generated camelCase row schema before it reaches the dialect. Registered
|
|
475
|
+
* before CamelCasePlugin, so it observes camelCase identifiers and raw values.
|
|
476
|
+
*/
|
|
477
|
+
declare class WriteValidationPlugin implements KyselyPlugin {
|
|
478
|
+
transformQuery({ node }: PluginTransformQueryArgs): RootOperationNode;
|
|
479
|
+
transformResult({ result }: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>>;
|
|
480
|
+
}
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region lib/generated/schemas.d.ts
|
|
483
|
+
declare const clientCamelRowSchemas: {
|
|
484
|
+
itemStore: {
|
|
485
|
+
readonly type: "object";
|
|
486
|
+
readonly properties: {
|
|
487
|
+
readonly key: {
|
|
488
|
+
readonly type: "string";
|
|
489
|
+
};
|
|
490
|
+
readonly item: {
|
|
491
|
+
readonly anyOf: readonly [{
|
|
492
|
+
readonly type: "object";
|
|
493
|
+
}, {
|
|
494
|
+
readonly type: "string";
|
|
495
|
+
}];
|
|
496
|
+
};
|
|
497
|
+
};
|
|
498
|
+
readonly required: readonly ["key", "item"];
|
|
499
|
+
readonly additionalProperties: false;
|
|
500
|
+
};
|
|
501
|
+
favouriteCard: {
|
|
502
|
+
readonly type: "object";
|
|
503
|
+
readonly properties: {
|
|
504
|
+
readonly createAt: {
|
|
505
|
+
readonly type: "integer";
|
|
506
|
+
};
|
|
507
|
+
readonly title: {
|
|
508
|
+
readonly type: "string";
|
|
509
|
+
};
|
|
510
|
+
readonly private: {
|
|
511
|
+
readonly anyOf: readonly [{
|
|
512
|
+
readonly type: "boolean";
|
|
513
|
+
}, {
|
|
514
|
+
readonly const: 0;
|
|
515
|
+
}, {
|
|
516
|
+
readonly const: 1;
|
|
517
|
+
}];
|
|
518
|
+
};
|
|
519
|
+
readonly description: {
|
|
520
|
+
readonly type: "string";
|
|
521
|
+
};
|
|
522
|
+
};
|
|
523
|
+
readonly required: readonly ["createAt", "title", "private", "description"];
|
|
524
|
+
readonly additionalProperties: false;
|
|
525
|
+
};
|
|
526
|
+
favouriteItem: {
|
|
527
|
+
readonly type: "object";
|
|
528
|
+
readonly properties: {
|
|
529
|
+
readonly addTime: {
|
|
530
|
+
readonly type: "integer";
|
|
531
|
+
};
|
|
532
|
+
readonly belongTo: {
|
|
533
|
+
readonly type: "integer";
|
|
534
|
+
};
|
|
535
|
+
readonly itemKey: {
|
|
536
|
+
readonly type: "string";
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
readonly required: readonly ["addTime", "belongTo", "itemKey"];
|
|
540
|
+
readonly additionalProperties: false;
|
|
541
|
+
};
|
|
542
|
+
history: {
|
|
543
|
+
readonly type: "object";
|
|
544
|
+
readonly properties: {
|
|
545
|
+
readonly ep: {
|
|
546
|
+
readonly anyOf: readonly [{
|
|
547
|
+
readonly type: "object";
|
|
548
|
+
}, {
|
|
549
|
+
readonly type: "string";
|
|
550
|
+
}];
|
|
551
|
+
};
|
|
552
|
+
readonly timestamp: {
|
|
553
|
+
readonly type: "integer";
|
|
554
|
+
};
|
|
555
|
+
readonly itemKey: {
|
|
556
|
+
readonly type: "string";
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
readonly required: readonly ["ep", "timestamp", "itemKey"];
|
|
560
|
+
readonly additionalProperties: false;
|
|
561
|
+
};
|
|
562
|
+
recentView: {
|
|
563
|
+
readonly type: "object";
|
|
564
|
+
readonly properties: {
|
|
565
|
+
readonly timestamp: {
|
|
566
|
+
readonly type: "integer";
|
|
567
|
+
};
|
|
568
|
+
readonly itemKey: {
|
|
569
|
+
readonly type: "string";
|
|
570
|
+
};
|
|
571
|
+
readonly isViewed: {
|
|
572
|
+
readonly anyOf: readonly [{
|
|
573
|
+
readonly type: "boolean";
|
|
574
|
+
}, {
|
|
575
|
+
readonly const: 0;
|
|
576
|
+
}, {
|
|
577
|
+
readonly const: 1;
|
|
578
|
+
}];
|
|
579
|
+
};
|
|
580
|
+
};
|
|
581
|
+
readonly required: readonly ["timestamp", "itemKey", "isViewed"];
|
|
582
|
+
readonly additionalProperties: false;
|
|
583
|
+
};
|
|
584
|
+
subscribe: {
|
|
585
|
+
readonly type: "object";
|
|
586
|
+
readonly properties: {
|
|
587
|
+
readonly itemKey: {
|
|
588
|
+
readonly anyOf: readonly [{
|
|
589
|
+
readonly type: "string";
|
|
590
|
+
}, {
|
|
591
|
+
readonly type: "null";
|
|
592
|
+
}];
|
|
593
|
+
};
|
|
594
|
+
readonly author: {
|
|
595
|
+
readonly anyOf: readonly [{
|
|
596
|
+
readonly type: "object";
|
|
597
|
+
}, {
|
|
598
|
+
readonly type: "string";
|
|
599
|
+
}, {
|
|
600
|
+
readonly type: "null";
|
|
601
|
+
}];
|
|
602
|
+
};
|
|
603
|
+
readonly type: {
|
|
604
|
+
readonly type: "string";
|
|
605
|
+
};
|
|
606
|
+
readonly key: {
|
|
607
|
+
readonly type: "string";
|
|
608
|
+
};
|
|
609
|
+
readonly plugin: {
|
|
610
|
+
readonly type: "string";
|
|
611
|
+
};
|
|
612
|
+
};
|
|
613
|
+
readonly required: readonly ["itemKey", "author", "type", "key", "plugin"];
|
|
614
|
+
readonly additionalProperties: false;
|
|
615
|
+
};
|
|
616
|
+
plugin: {
|
|
617
|
+
readonly type: "object";
|
|
618
|
+
readonly properties: {
|
|
619
|
+
readonly installerName: {
|
|
620
|
+
readonly type: "string";
|
|
621
|
+
};
|
|
622
|
+
readonly loaderName: {
|
|
623
|
+
readonly type: "string";
|
|
624
|
+
};
|
|
625
|
+
readonly pluginName: {
|
|
626
|
+
readonly type: "string";
|
|
627
|
+
};
|
|
628
|
+
readonly meta: {
|
|
629
|
+
readonly anyOf: readonly [{
|
|
630
|
+
readonly type: "object";
|
|
631
|
+
}, {
|
|
632
|
+
readonly type: "string";
|
|
633
|
+
}];
|
|
634
|
+
};
|
|
635
|
+
readonly enable: {
|
|
636
|
+
readonly anyOf: readonly [{
|
|
637
|
+
readonly type: "boolean";
|
|
638
|
+
}, {
|
|
639
|
+
readonly const: 0;
|
|
640
|
+
}, {
|
|
641
|
+
readonly const: 1;
|
|
642
|
+
}];
|
|
643
|
+
};
|
|
644
|
+
readonly installInput: {
|
|
645
|
+
readonly type: "string";
|
|
646
|
+
};
|
|
647
|
+
readonly displayName: {
|
|
648
|
+
readonly anyOf: readonly [{
|
|
649
|
+
readonly type: "string";
|
|
650
|
+
}, {
|
|
651
|
+
readonly type: "null";
|
|
652
|
+
}];
|
|
653
|
+
};
|
|
654
|
+
};
|
|
655
|
+
readonly required: readonly ["installerName", "loaderName", "pluginName", "meta", "enable", "installInput", "displayName"];
|
|
656
|
+
readonly additionalProperties: false;
|
|
657
|
+
};
|
|
658
|
+
nativeStore: {
|
|
659
|
+
readonly type: "object";
|
|
660
|
+
readonly properties: {
|
|
661
|
+
readonly namespace: {
|
|
662
|
+
readonly type: "string";
|
|
663
|
+
};
|
|
664
|
+
readonly key: {
|
|
665
|
+
readonly type: "string";
|
|
666
|
+
};
|
|
667
|
+
readonly value: {
|
|
668
|
+
readonly type: "string";
|
|
669
|
+
};
|
|
670
|
+
};
|
|
671
|
+
readonly required: readonly ["namespace", "key", "value"];
|
|
672
|
+
readonly additionalProperties: false;
|
|
673
|
+
};
|
|
674
|
+
config: {
|
|
675
|
+
readonly type: "object";
|
|
676
|
+
readonly properties: {
|
|
677
|
+
readonly belongTo: {
|
|
678
|
+
readonly type: "string";
|
|
679
|
+
};
|
|
680
|
+
readonly form: {
|
|
681
|
+
readonly type: "string";
|
|
682
|
+
};
|
|
683
|
+
readonly data: {
|
|
684
|
+
readonly type: "string";
|
|
685
|
+
};
|
|
686
|
+
};
|
|
687
|
+
readonly required: readonly ["belongTo", "form", "data"];
|
|
688
|
+
readonly additionalProperties: false;
|
|
689
|
+
};
|
|
690
|
+
};
|
|
691
|
+
//#endregion
|
|
692
|
+
//#region lib/validation.d.ts
|
|
693
|
+
type ClientTableName = keyof typeof clientCamelRowSchemas;
|
|
694
|
+
declare const tableSchema: <K extends ClientTableName>(table: K) => {
|
|
695
|
+
itemStore: {
|
|
696
|
+
readonly type: "object";
|
|
697
|
+
readonly properties: {
|
|
698
|
+
readonly key: {
|
|
699
|
+
readonly type: "string";
|
|
700
|
+
};
|
|
701
|
+
readonly item: {
|
|
702
|
+
readonly anyOf: readonly [{
|
|
703
|
+
readonly type: "object";
|
|
704
|
+
}, {
|
|
705
|
+
readonly type: "string";
|
|
706
|
+
}];
|
|
707
|
+
};
|
|
708
|
+
};
|
|
709
|
+
readonly required: readonly ["key", "item"];
|
|
710
|
+
readonly additionalProperties: false;
|
|
711
|
+
};
|
|
712
|
+
favouriteCard: {
|
|
713
|
+
readonly type: "object";
|
|
714
|
+
readonly properties: {
|
|
715
|
+
readonly createAt: {
|
|
716
|
+
readonly type: "integer";
|
|
717
|
+
};
|
|
718
|
+
readonly title: {
|
|
719
|
+
readonly type: "string";
|
|
720
|
+
};
|
|
721
|
+
readonly private: {
|
|
722
|
+
readonly anyOf: readonly [{
|
|
723
|
+
readonly type: "boolean";
|
|
724
|
+
}, {
|
|
725
|
+
readonly const: 0;
|
|
726
|
+
}, {
|
|
727
|
+
readonly const: 1;
|
|
728
|
+
}];
|
|
729
|
+
};
|
|
730
|
+
readonly description: {
|
|
731
|
+
readonly type: "string";
|
|
732
|
+
};
|
|
733
|
+
};
|
|
734
|
+
readonly required: readonly ["createAt", "title", "private", "description"];
|
|
735
|
+
readonly additionalProperties: false;
|
|
736
|
+
};
|
|
737
|
+
favouriteItem: {
|
|
738
|
+
readonly type: "object";
|
|
739
|
+
readonly properties: {
|
|
740
|
+
readonly addTime: {
|
|
741
|
+
readonly type: "integer";
|
|
742
|
+
};
|
|
743
|
+
readonly belongTo: {
|
|
744
|
+
readonly type: "integer";
|
|
745
|
+
};
|
|
746
|
+
readonly itemKey: {
|
|
747
|
+
readonly type: "string";
|
|
748
|
+
};
|
|
749
|
+
};
|
|
750
|
+
readonly required: readonly ["addTime", "belongTo", "itemKey"];
|
|
751
|
+
readonly additionalProperties: false;
|
|
752
|
+
};
|
|
753
|
+
history: {
|
|
754
|
+
readonly type: "object";
|
|
755
|
+
readonly properties: {
|
|
756
|
+
readonly ep: {
|
|
757
|
+
readonly anyOf: readonly [{
|
|
758
|
+
readonly type: "object";
|
|
759
|
+
}, {
|
|
760
|
+
readonly type: "string";
|
|
761
|
+
}];
|
|
762
|
+
};
|
|
763
|
+
readonly timestamp: {
|
|
764
|
+
readonly type: "integer";
|
|
765
|
+
};
|
|
766
|
+
readonly itemKey: {
|
|
767
|
+
readonly type: "string";
|
|
768
|
+
};
|
|
769
|
+
};
|
|
770
|
+
readonly required: readonly ["ep", "timestamp", "itemKey"];
|
|
771
|
+
readonly additionalProperties: false;
|
|
772
|
+
};
|
|
773
|
+
recentView: {
|
|
774
|
+
readonly type: "object";
|
|
775
|
+
readonly properties: {
|
|
776
|
+
readonly timestamp: {
|
|
777
|
+
readonly type: "integer";
|
|
778
|
+
};
|
|
779
|
+
readonly itemKey: {
|
|
780
|
+
readonly type: "string";
|
|
781
|
+
};
|
|
782
|
+
readonly isViewed: {
|
|
783
|
+
readonly anyOf: readonly [{
|
|
784
|
+
readonly type: "boolean";
|
|
785
|
+
}, {
|
|
786
|
+
readonly const: 0;
|
|
787
|
+
}, {
|
|
788
|
+
readonly const: 1;
|
|
789
|
+
}];
|
|
790
|
+
};
|
|
791
|
+
};
|
|
792
|
+
readonly required: readonly ["timestamp", "itemKey", "isViewed"];
|
|
793
|
+
readonly additionalProperties: false;
|
|
794
|
+
};
|
|
795
|
+
subscribe: {
|
|
796
|
+
readonly type: "object";
|
|
797
|
+
readonly properties: {
|
|
798
|
+
readonly itemKey: {
|
|
799
|
+
readonly anyOf: readonly [{
|
|
800
|
+
readonly type: "string";
|
|
801
|
+
}, {
|
|
802
|
+
readonly type: "null";
|
|
803
|
+
}];
|
|
804
|
+
};
|
|
805
|
+
readonly author: {
|
|
806
|
+
readonly anyOf: readonly [{
|
|
807
|
+
readonly type: "object";
|
|
808
|
+
}, {
|
|
809
|
+
readonly type: "string";
|
|
810
|
+
}, {
|
|
811
|
+
readonly type: "null";
|
|
812
|
+
}];
|
|
813
|
+
};
|
|
814
|
+
readonly type: {
|
|
815
|
+
readonly type: "string";
|
|
816
|
+
};
|
|
817
|
+
readonly key: {
|
|
818
|
+
readonly type: "string";
|
|
819
|
+
};
|
|
820
|
+
readonly plugin: {
|
|
821
|
+
readonly type: "string";
|
|
822
|
+
};
|
|
823
|
+
};
|
|
824
|
+
readonly required: readonly ["itemKey", "author", "type", "key", "plugin"];
|
|
825
|
+
readonly additionalProperties: false;
|
|
826
|
+
};
|
|
827
|
+
plugin: {
|
|
828
|
+
readonly type: "object";
|
|
829
|
+
readonly properties: {
|
|
830
|
+
readonly installerName: {
|
|
831
|
+
readonly type: "string";
|
|
832
|
+
};
|
|
833
|
+
readonly loaderName: {
|
|
834
|
+
readonly type: "string";
|
|
835
|
+
};
|
|
836
|
+
readonly pluginName: {
|
|
837
|
+
readonly type: "string";
|
|
838
|
+
};
|
|
839
|
+
readonly meta: {
|
|
840
|
+
readonly anyOf: readonly [{
|
|
841
|
+
readonly type: "object";
|
|
842
|
+
}, {
|
|
843
|
+
readonly type: "string";
|
|
844
|
+
}];
|
|
845
|
+
};
|
|
846
|
+
readonly enable: {
|
|
847
|
+
readonly anyOf: readonly [{
|
|
848
|
+
readonly type: "boolean";
|
|
849
|
+
}, {
|
|
850
|
+
readonly const: 0;
|
|
851
|
+
}, {
|
|
852
|
+
readonly const: 1;
|
|
853
|
+
}];
|
|
854
|
+
};
|
|
855
|
+
readonly installInput: {
|
|
856
|
+
readonly type: "string";
|
|
857
|
+
};
|
|
858
|
+
readonly displayName: {
|
|
859
|
+
readonly anyOf: readonly [{
|
|
860
|
+
readonly type: "string";
|
|
861
|
+
}, {
|
|
862
|
+
readonly type: "null";
|
|
863
|
+
}];
|
|
864
|
+
};
|
|
865
|
+
};
|
|
866
|
+
readonly required: readonly ["installerName", "loaderName", "pluginName", "meta", "enable", "installInput", "displayName"];
|
|
867
|
+
readonly additionalProperties: false;
|
|
868
|
+
};
|
|
869
|
+
nativeStore: {
|
|
870
|
+
readonly type: "object";
|
|
871
|
+
readonly properties: {
|
|
872
|
+
readonly namespace: {
|
|
873
|
+
readonly type: "string";
|
|
874
|
+
};
|
|
875
|
+
readonly key: {
|
|
876
|
+
readonly type: "string";
|
|
877
|
+
};
|
|
878
|
+
readonly value: {
|
|
879
|
+
readonly type: "string";
|
|
880
|
+
};
|
|
881
|
+
};
|
|
882
|
+
readonly required: readonly ["namespace", "key", "value"];
|
|
883
|
+
readonly additionalProperties: false;
|
|
884
|
+
};
|
|
885
|
+
config: {
|
|
886
|
+
readonly type: "object";
|
|
887
|
+
readonly properties: {
|
|
888
|
+
readonly belongTo: {
|
|
889
|
+
readonly type: "string";
|
|
890
|
+
};
|
|
891
|
+
readonly form: {
|
|
892
|
+
readonly type: "string";
|
|
893
|
+
};
|
|
894
|
+
readonly data: {
|
|
895
|
+
readonly type: "string";
|
|
896
|
+
};
|
|
897
|
+
};
|
|
898
|
+
readonly required: readonly ["belongTo", "form", "data"];
|
|
899
|
+
readonly additionalProperties: false;
|
|
900
|
+
};
|
|
901
|
+
}[K];
|
|
902
|
+
/** Validates a row before writing; throws to block invalid data from persisting. */
|
|
903
|
+
declare const assertWrite: <T>(schema: TSchema, table: string, value: T) => T;
|
|
904
|
+
declare const assertWriteRow: <K extends ClientTableName, T>(table: K, value: T) => T;
|
|
905
|
+
/** Validates a row on read; failures are non-intrusive: logged and the value returned as-is. */
|
|
906
|
+
declare const validateRead: <T>(schema: TSchema, table: string, value: T) => T;
|
|
907
|
+
declare const validateReadRow: <K extends ClientTableName, T>(table: K, value: T) => T;
|
|
908
|
+
/** Filters invalid rows on read; failures are non-intrusive: logged and the row dropped. */
|
|
909
|
+
declare const filterValidRows: <T>(schema: TSchema, table: string, rows: readonly T[]) => T[];
|
|
910
|
+
declare const filterValidRowsFor: <K extends ClientTableName, T>(table: K, rows: readonly T[]) => T[];
|
|
911
|
+
//#endregion
|
|
451
912
|
//#region lib/index.d.ts
|
|
452
913
|
interface DB {
|
|
453
914
|
itemStore: Table$6;
|
|
@@ -456,12 +917,12 @@ interface DB {
|
|
|
456
917
|
history: Table$4;
|
|
457
918
|
recentView: Table$2;
|
|
458
919
|
subscribe: Table$1;
|
|
459
|
-
plugin:
|
|
920
|
+
plugin: PluginTable;
|
|
460
921
|
nativeStore: Table;
|
|
461
922
|
config: Table$3;
|
|
462
923
|
}
|
|
463
924
|
declare const isTauriRuntime: typeof isTauri;
|
|
464
925
|
declare const db: Kysely$1<DB>;
|
|
465
926
|
//#endregion
|
|
466
|
-
export { config_d_exports as ConfigDB, DB, utils_d_exports as DBUtils, favourite_d_exports as FavouriteDB, history_d_exports as HistoryDB, type InsertObject, itemStore_d_exports as ItemStoreDB, type Kysely, plugin_d_exports as PluginArchiveDB, recentView_d_exports as RecentDB, subscribe_d_exports as SubscribeDB, Table, db, isTauriRuntime, useConfig, useNativeStore };
|
|
927
|
+
export { ClientTableName, config_d_exports as ConfigDB, DB, utils_d_exports as DBUtils, favourite_d_exports as FavouriteDB, history_d_exports as HistoryDB, type InsertObject, itemStore_d_exports as ItemStoreDB, type Kysely, plugin_d_exports as PluginArchiveDB, type PluginTable, recentView_d_exports as RecentDB, subscribe_d_exports as SubscribeDB, Table, WriteValidationPlugin, assertWrite, assertWriteRow, db, filterValidRows, filterValidRowsFor, isTauriRuntime, tableSchema, useConfig, useNativeStore, validateRead, validateReadRow };
|
|
467
928
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -4,9 +4,11 @@ import { isTauri } from "@tauri-apps/api/core";
|
|
|
4
4
|
import { CamelCasePlugin, Kysely } from "kysely";
|
|
5
5
|
import { SerializePlugin } from "kysely-plugin-serialize";
|
|
6
6
|
import { defineMutation, useMutation, useQuery, useQueryCache } from "@pinia/colada";
|
|
7
|
+
import { ref, toValue, watch } from "vue";
|
|
7
8
|
import { SourcedValue, Struct, UniContentPage } from "@delta-comic/model";
|
|
8
9
|
import { fromPairs } from "es-toolkit/compat";
|
|
9
|
-
import {
|
|
10
|
+
import { Compile } from "typebox/compile";
|
|
11
|
+
import { Value } from "typebox/value";
|
|
10
12
|
//#region lib/utils.ts
|
|
11
13
|
var utils_exports = /* @__PURE__ */ __exportAll({
|
|
12
14
|
CommonQueryKey: () => CommonQueryKey,
|
|
@@ -261,7 +263,7 @@ const useQueryItem = (query, otherKeys = [], initialData) => useQuery({
|
|
|
261
263
|
"db:favouriteItem:",
|
|
262
264
|
"db:favouriteCard:",
|
|
263
265
|
query,
|
|
264
|
-
...otherKeys
|
|
266
|
+
...toValue(otherKeys)
|
|
265
267
|
],
|
|
266
268
|
staleTime: 15e3,
|
|
267
269
|
initialData,
|
|
@@ -275,7 +277,7 @@ const useQueryCard = (query, otherKeys = [], initialData) => useQuery({
|
|
|
275
277
|
key: () => [
|
|
276
278
|
"db:favouriteCard:",
|
|
277
279
|
query,
|
|
278
|
-
...otherKeys
|
|
280
|
+
...toValue(otherKeys)
|
|
279
281
|
],
|
|
280
282
|
staleTime: 15e3,
|
|
281
283
|
refetchOnMount: "always",
|
|
@@ -311,7 +313,7 @@ const useUpsert$2 = defineMutation(() => {
|
|
|
311
313
|
await trx.replaceInto("history").values({
|
|
312
314
|
itemKey,
|
|
313
315
|
timestamp: Date.now(),
|
|
314
|
-
ep: Struct.toRaw(item)
|
|
316
|
+
ep: Struct.toRaw(item.thisEp)
|
|
315
317
|
}).execute();
|
|
316
318
|
}, trx),
|
|
317
319
|
onSettled: () => {
|
|
@@ -573,6 +575,302 @@ const useConfig = (belongTo, form) => {
|
|
|
573
575
|
});
|
|
574
576
|
return Object.assign(data, { ready });
|
|
575
577
|
};
|
|
578
|
+
const clientCamelRowSchemas = {
|
|
579
|
+
itemStore: {
|
|
580
|
+
type: "object",
|
|
581
|
+
properties: {
|
|
582
|
+
key: { type: "string" },
|
|
583
|
+
item: { anyOf: [{ type: "object" }, { type: "string" }] }
|
|
584
|
+
},
|
|
585
|
+
required: ["key", "item"],
|
|
586
|
+
additionalProperties: false
|
|
587
|
+
},
|
|
588
|
+
favouriteCard: {
|
|
589
|
+
type: "object",
|
|
590
|
+
properties: {
|
|
591
|
+
createAt: { type: "integer" },
|
|
592
|
+
title: { type: "string" },
|
|
593
|
+
private: { anyOf: [
|
|
594
|
+
{ type: "boolean" },
|
|
595
|
+
{ const: 0 },
|
|
596
|
+
{ const: 1 }
|
|
597
|
+
] },
|
|
598
|
+
description: { type: "string" }
|
|
599
|
+
},
|
|
600
|
+
required: [
|
|
601
|
+
"createAt",
|
|
602
|
+
"title",
|
|
603
|
+
"private",
|
|
604
|
+
"description"
|
|
605
|
+
],
|
|
606
|
+
additionalProperties: false
|
|
607
|
+
},
|
|
608
|
+
favouriteItem: {
|
|
609
|
+
type: "object",
|
|
610
|
+
properties: {
|
|
611
|
+
addTime: { type: "integer" },
|
|
612
|
+
belongTo: { type: "integer" },
|
|
613
|
+
itemKey: { type: "string" }
|
|
614
|
+
},
|
|
615
|
+
required: [
|
|
616
|
+
"addTime",
|
|
617
|
+
"belongTo",
|
|
618
|
+
"itemKey"
|
|
619
|
+
],
|
|
620
|
+
additionalProperties: false
|
|
621
|
+
},
|
|
622
|
+
history: {
|
|
623
|
+
type: "object",
|
|
624
|
+
properties: {
|
|
625
|
+
ep: { anyOf: [{ type: "object" }, { type: "string" }] },
|
|
626
|
+
timestamp: { type: "integer" },
|
|
627
|
+
itemKey: { type: "string" }
|
|
628
|
+
},
|
|
629
|
+
required: [
|
|
630
|
+
"ep",
|
|
631
|
+
"timestamp",
|
|
632
|
+
"itemKey"
|
|
633
|
+
],
|
|
634
|
+
additionalProperties: false
|
|
635
|
+
},
|
|
636
|
+
recentView: {
|
|
637
|
+
type: "object",
|
|
638
|
+
properties: {
|
|
639
|
+
timestamp: { type: "integer" },
|
|
640
|
+
itemKey: { type: "string" },
|
|
641
|
+
isViewed: { anyOf: [
|
|
642
|
+
{ type: "boolean" },
|
|
643
|
+
{ const: 0 },
|
|
644
|
+
{ const: 1 }
|
|
645
|
+
] }
|
|
646
|
+
},
|
|
647
|
+
required: [
|
|
648
|
+
"timestamp",
|
|
649
|
+
"itemKey",
|
|
650
|
+
"isViewed"
|
|
651
|
+
],
|
|
652
|
+
additionalProperties: false
|
|
653
|
+
},
|
|
654
|
+
subscribe: {
|
|
655
|
+
type: "object",
|
|
656
|
+
properties: {
|
|
657
|
+
itemKey: { anyOf: [{ type: "string" }, { type: "null" }] },
|
|
658
|
+
author: { anyOf: [
|
|
659
|
+
{ type: "object" },
|
|
660
|
+
{ type: "string" },
|
|
661
|
+
{ type: "null" }
|
|
662
|
+
] },
|
|
663
|
+
type: { type: "string" },
|
|
664
|
+
key: { type: "string" },
|
|
665
|
+
plugin: { type: "string" }
|
|
666
|
+
},
|
|
667
|
+
required: [
|
|
668
|
+
"itemKey",
|
|
669
|
+
"author",
|
|
670
|
+
"type",
|
|
671
|
+
"key",
|
|
672
|
+
"plugin"
|
|
673
|
+
],
|
|
674
|
+
additionalProperties: false
|
|
675
|
+
},
|
|
676
|
+
plugin: {
|
|
677
|
+
type: "object",
|
|
678
|
+
properties: {
|
|
679
|
+
installerName: { type: "string" },
|
|
680
|
+
loaderName: { type: "string" },
|
|
681
|
+
pluginName: { type: "string" },
|
|
682
|
+
meta: { anyOf: [{ type: "object" }, { type: "string" }] },
|
|
683
|
+
enable: { anyOf: [
|
|
684
|
+
{ type: "boolean" },
|
|
685
|
+
{ const: 0 },
|
|
686
|
+
{ const: 1 }
|
|
687
|
+
] },
|
|
688
|
+
installInput: { type: "string" },
|
|
689
|
+
displayName: { anyOf: [{ type: "string" }, { type: "null" }] }
|
|
690
|
+
},
|
|
691
|
+
required: [
|
|
692
|
+
"installerName",
|
|
693
|
+
"loaderName",
|
|
694
|
+
"pluginName",
|
|
695
|
+
"meta",
|
|
696
|
+
"enable",
|
|
697
|
+
"installInput",
|
|
698
|
+
"displayName"
|
|
699
|
+
],
|
|
700
|
+
additionalProperties: false
|
|
701
|
+
},
|
|
702
|
+
nativeStore: {
|
|
703
|
+
type: "object",
|
|
704
|
+
properties: {
|
|
705
|
+
namespace: { type: "string" },
|
|
706
|
+
key: { type: "string" },
|
|
707
|
+
value: { type: "string" }
|
|
708
|
+
},
|
|
709
|
+
required: [
|
|
710
|
+
"namespace",
|
|
711
|
+
"key",
|
|
712
|
+
"value"
|
|
713
|
+
],
|
|
714
|
+
additionalProperties: false
|
|
715
|
+
},
|
|
716
|
+
config: {
|
|
717
|
+
type: "object",
|
|
718
|
+
properties: {
|
|
719
|
+
belongTo: { type: "string" },
|
|
720
|
+
form: { type: "string" },
|
|
721
|
+
data: { type: "string" }
|
|
722
|
+
},
|
|
723
|
+
required: [
|
|
724
|
+
"belongTo",
|
|
725
|
+
"form",
|
|
726
|
+
"data"
|
|
727
|
+
],
|
|
728
|
+
additionalProperties: false
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
//#endregion
|
|
732
|
+
//#region lib/validation.ts
|
|
733
|
+
const validationLogger = logger.scoped("db:validation");
|
|
734
|
+
const validators = /* @__PURE__ */ new WeakMap();
|
|
735
|
+
const validatorFor = (schema) => {
|
|
736
|
+
const cached = validators.get(schema);
|
|
737
|
+
if (cached) return cached;
|
|
738
|
+
const validator = Compile(schema);
|
|
739
|
+
validators.set(schema, validator);
|
|
740
|
+
return validator;
|
|
741
|
+
};
|
|
742
|
+
const validationDetails = (schema, value) => [...Value.Errors(schema, value)].slice(0, 5).map((error) => ({
|
|
743
|
+
instancePath: error.instancePath,
|
|
744
|
+
message: error.message
|
|
745
|
+
}));
|
|
746
|
+
const tableSchema = (table) => clientCamelRowSchemas[table];
|
|
747
|
+
/** Validates a row before writing; throws to block invalid data from persisting. */
|
|
748
|
+
const assertWrite = (schema, table, value) => {
|
|
749
|
+
if (!validatorFor(schema).Check(value)) {
|
|
750
|
+
validationLogger.error("database write validation failed", {
|
|
751
|
+
table,
|
|
752
|
+
errors: validationDetails(schema, value)
|
|
753
|
+
});
|
|
754
|
+
throw new Error(`database write validation failed for ${table}: ${JSON.stringify(validationDetails(schema, value))}`);
|
|
755
|
+
}
|
|
756
|
+
return value;
|
|
757
|
+
};
|
|
758
|
+
const assertWriteRow = (table, value) => assertWrite(tableSchema(table), table, value);
|
|
759
|
+
/** Validates a row on read; failures are non-intrusive: logged and the value returned as-is. */
|
|
760
|
+
const validateRead = (schema, table, value) => {
|
|
761
|
+
if (!validatorFor(schema).Check(value)) validationLogger.warn("database read validation failed", {
|
|
762
|
+
table,
|
|
763
|
+
errors: validationDetails(schema, value)
|
|
764
|
+
});
|
|
765
|
+
return value;
|
|
766
|
+
};
|
|
767
|
+
const validateReadRow = (table, value) => validateRead(tableSchema(table), table, value);
|
|
768
|
+
/** Filters invalid rows on read; failures are non-intrusive: logged and the row dropped. */
|
|
769
|
+
const filterValidRows = (schema, table, rows) => {
|
|
770
|
+
const valid = [];
|
|
771
|
+
for (const row of rows) {
|
|
772
|
+
if (validatorFor(schema).Check(row)) {
|
|
773
|
+
valid.push(row);
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
validationLogger.warn("database read validation failed, row dropped", {
|
|
777
|
+
table,
|
|
778
|
+
errors: validationDetails(schema, row)
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
return valid;
|
|
782
|
+
};
|
|
783
|
+
const filterValidRowsFor = (table, rows) => filterValidRows(tableSchema(table), table, rows);
|
|
784
|
+
//#endregion
|
|
785
|
+
//#region lib/writeValidation.ts
|
|
786
|
+
const isTableNode = (node) => node?.kind === "TableNode";
|
|
787
|
+
const isValuesNode = (node) => node?.kind === "ValuesNode";
|
|
788
|
+
const isValueNode = (node) => node.kind === "ValueNode";
|
|
789
|
+
const isColumnNode = (node) => node.kind === "ColumnNode";
|
|
790
|
+
const tableNameOf = (node) => {
|
|
791
|
+
if (!isTableNode(node)) return null;
|
|
792
|
+
return node.table.identifier.name;
|
|
793
|
+
};
|
|
794
|
+
const rowObjectsOf = (node) => {
|
|
795
|
+
const columns = node.columns;
|
|
796
|
+
if (!columns || columns.length === 0) return null;
|
|
797
|
+
const names = columns.map((column) => column.column.name);
|
|
798
|
+
const values = node.values;
|
|
799
|
+
if (!isValuesNode(values)) return null;
|
|
800
|
+
const rows = [];
|
|
801
|
+
for (const list of values.values) {
|
|
802
|
+
let entries;
|
|
803
|
+
if (list.kind === "PrimitiveValueListNode") entries = [...list.values];
|
|
804
|
+
else if (list.kind === "ValueListNode") {
|
|
805
|
+
const wrapped = [];
|
|
806
|
+
for (const entry of list.values) {
|
|
807
|
+
if (!isValueNode(entry)) return null;
|
|
808
|
+
wrapped.push(entry.value);
|
|
809
|
+
}
|
|
810
|
+
entries = wrapped;
|
|
811
|
+
} else return null;
|
|
812
|
+
if (entries.length !== names.length) return null;
|
|
813
|
+
rows.push(Object.fromEntries(names.map((name, index) => [name, entries[index]])));
|
|
814
|
+
}
|
|
815
|
+
return rows;
|
|
816
|
+
};
|
|
817
|
+
const updatePatchOf = (node) => {
|
|
818
|
+
if (!node.updates || node.updates.length === 0) return null;
|
|
819
|
+
const patch = {};
|
|
820
|
+
for (const update of node.updates) {
|
|
821
|
+
if (!isColumnNode(update.column)) return null;
|
|
822
|
+
const value = update.value;
|
|
823
|
+
if (!isValueNode(value)) return null;
|
|
824
|
+
patch[update.column.column.name] = value.value;
|
|
825
|
+
}
|
|
826
|
+
return patch;
|
|
827
|
+
};
|
|
828
|
+
const partialSchemas = /* @__PURE__ */ new WeakMap();
|
|
829
|
+
const partialOf = (schema) => {
|
|
830
|
+
const cached = partialSchemas.get(schema);
|
|
831
|
+
if (cached) return cached;
|
|
832
|
+
const partial = {
|
|
833
|
+
...schema,
|
|
834
|
+
required: void 0
|
|
835
|
+
};
|
|
836
|
+
partialSchemas.set(schema, partial);
|
|
837
|
+
return partial;
|
|
838
|
+
};
|
|
839
|
+
const validateWriteNode = (node) => {
|
|
840
|
+
let tableName = null;
|
|
841
|
+
let rows = null;
|
|
842
|
+
let patch = null;
|
|
843
|
+
if (node.kind === "InsertQueryNode") {
|
|
844
|
+
tableName = tableNameOf(node.into);
|
|
845
|
+
rows = rowObjectsOf(node);
|
|
846
|
+
} else if (node.kind === "UpdateQueryNode") {
|
|
847
|
+
tableName = tableNameOf(node.table);
|
|
848
|
+
patch = updatePatchOf(node);
|
|
849
|
+
} else return;
|
|
850
|
+
if (tableName === null) return;
|
|
851
|
+
const schema = clientCamelRowSchemas[tableName];
|
|
852
|
+
if (!schema) return;
|
|
853
|
+
if (rows !== null) {
|
|
854
|
+
if (rows.length === 0) return;
|
|
855
|
+
for (const row of rows) assertWrite(schema, tableName, row);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (patch !== null) assertWrite(partialOf(schema), tableName, patch);
|
|
859
|
+
};
|
|
860
|
+
/**
|
|
861
|
+
* Centralized write gate: validates every insert/replace/update against the
|
|
862
|
+
* generated camelCase row schema before it reaches the dialect. Registered
|
|
863
|
+
* before CamelCasePlugin, so it observes camelCase identifiers and raw values.
|
|
864
|
+
*/
|
|
865
|
+
var WriteValidationPlugin = class {
|
|
866
|
+
transformQuery({ node }) {
|
|
867
|
+
validateWriteNode(node);
|
|
868
|
+
return node;
|
|
869
|
+
}
|
|
870
|
+
async transformResult({ result }) {
|
|
871
|
+
return result;
|
|
872
|
+
}
|
|
873
|
+
};
|
|
576
874
|
//#endregion
|
|
577
875
|
//#region lib/nativeStore/index.ts
|
|
578
876
|
const nativeStoreLogger = logger.scoped("db:native-store");
|
|
@@ -682,9 +980,13 @@ const createDialect = async () => {
|
|
|
682
980
|
};
|
|
683
981
|
const db = new Kysely({
|
|
684
982
|
dialect: await createDialect(),
|
|
685
|
-
plugins: [
|
|
983
|
+
plugins: [
|
|
984
|
+
new WriteValidationPlugin(),
|
|
985
|
+
new CamelCasePlugin(),
|
|
986
|
+
new SerializePlugin()
|
|
987
|
+
]
|
|
686
988
|
});
|
|
687
989
|
//#endregion
|
|
688
|
-
export { config_exports as ConfigDB, utils_exports as DBUtils, favourite_exports as FavouriteDB, history_exports as HistoryDB, itemStore_exports as ItemStoreDB, plugin_exports as PluginArchiveDB, recentView_exports as RecentDB, subscribe_exports as SubscribeDB, db, isTauriRuntime, useConfig, useNativeStore };
|
|
990
|
+
export { config_exports as ConfigDB, utils_exports as DBUtils, favourite_exports as FavouriteDB, history_exports as HistoryDB, itemStore_exports as ItemStoreDB, plugin_exports as PluginArchiveDB, recentView_exports as RecentDB, subscribe_exports as SubscribeDB, WriteValidationPlugin, assertWrite, assertWriteRow, db, filterValidRows, filterValidRowsFor, isTauriRuntime, tableSchema, useConfig, useNativeStore, validateRead, validateReadRow };
|
|
689
991
|
|
|
690
992
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["QueryKey","useUpsert","useRemove","useQuery","useColadaQuery","QueryKey","useUpsert","QueryKey","ItemStoreDB.useUpsert","useColadaQuery","QueryKey","useUpsert","ItemStoreDB.useUpsert","useRemove","useQuery","useColadaQuery","QueryKey","useUpsert","useRemove","useQuery","useColadaQuery","ItemStoreDB.useUpsert","useQuery","useColadaQuery"],"sources":["../lib/utils.ts","../lib/plugin.ts","../lib/itemStore.ts","../lib/favourite.ts","../lib/history.ts","../lib/subscribe.ts","../lib/recentView.ts","../lib/config.ts","../lib/nativeStore/index.ts","../lib/index.ts"],"sourcesContent":["import { logger } from '@delta-comic/logger'\nimport type { Kysely, SelectQueryBuilder } from 'kysely'\n\nimport type { DB } from '.'\n\nconst transactionLogger = logger.scoped('db:transaction')\n\nexport const withTransition = async <T>(\n handler: (trx: Kysely<DB>) => Promise<T>,\n trx?: Kysely<DB>,\n) => {\n if (trx) return await handler(trx)\n else {\n const { db } = await import('.')\n transactionLogger.trace('database transaction started')\n try {\n const result = await db\n .transaction()\n .setAccessMode('read write')\n .setIsolationLevel('read committed')\n .execute(handler)\n transactionLogger.trace('database transaction committed')\n return result\n } catch (error) {\n transactionLogger.error('database transaction failed', error)\n throw error\n }\n }\n}\n\nexport async function countDb<TB extends keyof DB, O extends object>(\n sql: SelectQueryBuilder<DB, TB, O>,\n) {\n const v = await sql.select(db => db.fn.countAll<number>().as('count')).executeTakeFirstOrThrow()\n return v.count\n}\n\nexport enum CommonQueryKey {\n common = 'db',\n}","import type { PluginManifest } from '@delta-comic/model'\nimport {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { JSONColumnType, Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport type Meta = PluginManifest\n\nexport interface Table {\n installerName: string\n loaderName: string\n /** @description primary key */\n pluginName: string\n meta: JSONColumnType<Meta>\n enable: boolean\n installInput: string\n displayName: string\n}\n\n/** @description Not Blue */\nexport type Archive = Selectable<Table>\n\nexport enum QueryKey {\n item = 'db:plugin:',\n}\n\nexport const removeByNames = async (keys: Archive['pluginName'][], trx: Kysely<DB>) => {\n if (keys.length === 0) return\n await trx.deleteFrom('plugin').where('plugin.pluginName', 'in', keys).execute()\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ archives, trx }: { archives: Archive[]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx\n .replaceInto('plugin')\n .values(archives.map(a => ({ ...a, meta: JSON.stringify(a.meta) })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ keys, trx }: { keys: Archive['pluginName'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await removeByNames(keys, trx)\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useToggleEnable = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ keys, trx }: { keys: Archive['pluginName'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n for (const key of keys) {\n const isEnable = await trx\n .selectFrom('plugin')\n .where('pluginName', '=', key)\n .select('enable')\n .executeTakeFirstOrThrow()\n return trx\n .updateTable('plugin')\n .where('pluginName', '=', key)\n .set({ enable: !isEnable.enable })\n .execute()\n }\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, toggle: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'plugin', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('plugin'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import {\n SourcedValue,\n Struct,\n UniContentPage,\n type UniItem,\n type UniItemRaw,\n} from '@delta-comic/model'\nimport { defineMutation, useMutation, useQueryCache } from '@pinia/colada'\nimport type { JSONColumnType, Kysely, Selectable } from 'kysely'\n\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport interface Table {\n /** @description primary key */\n key: string\n item: JSONColumnType<UniItemRaw>\n}\nexport type StorableItem = UniItem | UniItemRaw\nexport type StoredItem = Selectable<Table>\nexport const itemKey = new SourcedValue('*')\n\nexport enum QueryKey {\n item = 'db:itemStore:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ item, trx }: { item: StorableItem; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n const k = itemKey.toString([\n UniContentPage.contentPages.key.toString(item.contentType),\n item.id,\n ])\n await trx\n .replaceInto('itemStore')\n .values({ item: Struct.toRaw(item), key: k })\n .execute()\n return k\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})","import {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport * as ItemStoreDB from './itemStore'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport interface CardTable {\n title: string\n private: boolean\n description: string\n /** @description primary key */\n createAt: number\n}\n\nexport type Card = Selectable<CardTable>\n\nexport interface ItemTable {\n itemKey: string\n /** @description foreign key */\n belongTo: CardTable['createAt']\n addTime: number\n}\n\nexport type Item = Selectable<ItemTable>\n\nexport enum QueryKey {\n item = 'db:favouriteItem:',\n card = 'db:favouriteCard:',\n}\n\nexport const useUpsertItem = defineMutation(() => {\n const queryCache = useQueryCache()\n const { key: iKey, upsert } = ItemStoreDB.useUpsert()\n const key = [CommonQueryKey.common, QueryKey.item, ...iKey]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({\n item,\n belongTos,\n trx,\n }: {\n item: ItemStoreDB.StorableItem\n belongTos: Item['belongTo'][]\n trx?: Kysely<DB>\n }) =>\n withTransition(async trx => {\n const itemKey = await upsert({ item, trx })\n await trx\n .replaceInto('favouriteItem')\n .values(belongTos.map(belongTo => ({ addTime: Date.now(), itemKey, belongTo })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useMoveItem = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({\n item,\n from,\n aims,\n trx,\n }: {\n item: ItemStoreDB.StorableItem\n from: Item['belongTo']\n aims: Item['belongTo'][]\n trx?: Kysely<DB>\n }) =>\n withTransition(async trx => {\n await trx\n .deleteFrom('favouriteItem')\n .where('itemKey', '=', item.id)\n .where('belongTo', '=', from)\n .execute()\n await trx\n .replaceInto('favouriteItem')\n .values(aims.map(to => ({ addTime: Date.now(), itemKey: item.id, belongTo: to })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, move: mutateAsync, key }\n})\n\nexport const useCreateCard = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [QueryKey.card, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ card, trx }: { card: Card; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.replaceInto('favouriteCard').values(card).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, createCard: mutateAsync, key }\n})\n\nexport const useQueryItem = <T>(\n query: (db: SelectQueryBuilder<DB, 'favouriteItem', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('favouriteItem'))\n },\n key: () => [QueryKey.item, QueryKey.card, query, ...otherKeys],\n staleTime: 15000,\n initialData,\n initialDataUpdatedAt: 0,\n })\n\nexport const useQueryCard = <T>(\n query: (db: SelectQueryBuilder<DB, 'favouriteCard', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('favouriteCard'))\n },\n key: () => [QueryKey.card, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import { Struct, type UniEpRaw } from '@delta-comic/model'\nimport {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { JSONColumnType, Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport * as ItemStoreDB from './itemStore'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport interface Table {\n /** @description primary key */\n timestamp: number\n itemKey: string\n ep: JSONColumnType<UniEpRaw>\n}\n\nexport type Item = Selectable<Table>\n\nexport enum QueryKey {\n item = 'db:history:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const { key: iKey, upsert } = ItemStoreDB.useUpsert()\n const key = [CommonQueryKey.common, QueryKey.item, ...iKey]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ item, trx }: { item: ItemStoreDB.StorableItem; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n const itemKey = await upsert({ item, trx })\n await trx\n .replaceInto('history')\n .values({ itemKey, timestamp: Date.now(), ep: Struct.toRaw(item) })\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: ({ keys, trx }: { keys: Item['timestamp'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.deleteFrom('history').where('history.timestamp', 'is', keys).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'history', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('history'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import { SourcedValue, type SourcedKeyType, type UniItemAuthor } from '@delta-comic/model'\nimport {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { JSONColumnType, Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport const key = new SourcedValue<[plugin: string, label: string]>()\nexport type Key_ = SourcedKeyType<typeof key>\nexport type Key = Exclude<Key_, string>\n\nexport interface AuthorTable {\n author: JSONColumnType<UniItemAuthor>\n itemKey: null\n type: 'author'\n /** @description primary key */\n key: string\n plugin: string\n}\nexport type AuthorItem = Selectable<AuthorTable>\n\nexport interface EpTable {\n author: null\n itemKey: string // not f key\n type: 'ep'\n /** @description primary key */\n key: string\n plugin: string\n}\nexport type EpItem = Selectable<EpTable>\n\nexport type Table = AuthorTable | EpTable\nexport type Item = AuthorItem | EpItem\n\nexport enum QueryKey {\n item = 'db:subscribe:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ items, trx }: { items: Item[]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx\n .replaceInto('subscribe')\n .values(items.map(item => ({ ...item, author: JSON.stringify(item.author) })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ keys, trx }: { keys: Item['key'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.deleteFrom('subscribe').where('subscribe.key', 'is', keys).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'subscribe', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('subscribe'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport * as ItemStoreDB from './itemStore'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport interface Table {\n /** @description primary key */\n timestamp: number\n itemKey: string\n isViewed: boolean\n}\nexport type Item = Selectable<Table>\n\nexport enum QueryKey {\n item = 'db:recentView:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const { key: iKey, upsert } = ItemStoreDB.useUpsert()\n const key = [CommonQueryKey.common, QueryKey.item, ...iKey]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ item, trx }: { item: ItemStoreDB.StorableItem; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n const itemKey = await upsert({ item, trx })\n await trx\n .replaceInto('recentView')\n .values({ isViewed: false, itemKey, timestamp: Date.now() })\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ items, trx }: { items: Item['timestamp'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.deleteFrom('recentView').where('recentView.timestamp', 'is', items).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'recentView', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('recentView'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import { logger } from '@delta-comic/logger'\nimport type { FormResult, FormSingleConfigure } from '@delta-comic/model'\nimport { fromPairs } from 'es-toolkit/compat'\nimport { ref, watch, type Ref } from 'vue'\n\nconst configLogger = logger.scoped('db:config')\n\nexport interface Table {\n /** @description config owner, usually plugin name */\n belongTo: string\n /** @description serialized form structure */\n form: string\n /** @description serialized config data */\n data: string\n}\n\nexport type ConfigRef<T> = Ref<T> & { readonly ready: Promise<void> }\n\nexport type ConfigDescription = Record<\n string,\n Required<Pick<FormSingleConfigure, 'defaultValue'>> & FormSingleConfigure\n>\n\nconst cloneValue = <T>(value: T): T => {\n if (typeof structuredClone === 'function') return structuredClone(value)\n return JSON.parse(JSON.stringify(value)) as T\n}\n\nconst createDefaultData = <T extends ConfigDescription>(config: T): FormResult<T> =>\n fromPairs(\n Object.entries(config).map(([name, desc]) => [name, desc.defaultValue]),\n ) as FormResult<T>\n\nconst parseJson = <T>(value: unknown, fallback: T): T => {\n if (!value) return cloneValue(fallback)\n if (typeof value !== 'string') return cloneValue(value as T)\n try {\n return JSON.parse(value) as T\n } catch (error) {\n configLogger.warn('failed to parse config value', error)\n return cloneValue(fallback)\n }\n}\n\nconst upsertConfig = async (belongTo: string, form: ConfigDescription, data: unknown) => {\n const { db } = await import('.')\n await db\n .replaceInto('config')\n .values({ belongTo, form: JSON.stringify(form), data: JSON.stringify(data) })\n .execute()\n configLogger.debug('config persisted', { belongTo })\n}\n\nexport const useConfig = <T extends ConfigDescription>(\n belongTo: string,\n form: T,\n): ConfigRef<FormResult<T>> => {\n const defaultData = createDefaultData(form)\n const data = ref(cloneValue(defaultData)) as Ref<FormResult<T>>\n let hydrated = false\n let saveTimer: ReturnType<typeof setTimeout> | undefined\n\n const persist = () => {\n if (saveTimer) clearTimeout(saveTimer)\n saveTimer = setTimeout(() => {\n void upsertConfig(belongTo, form, data.value).catch(error => {\n configLogger.warn('failed to persist config value', { belongTo }, error)\n })\n }, 100)\n }\n\n const ready = (async () => {\n try {\n const { db } = await import('.')\n const stored = await db\n .selectFrom('config')\n .select(['form', 'data'])\n .where('belongTo', '=', belongTo)\n .executeTakeFirst()\n data.value = parseJson(stored?.data, defaultData)\n configLogger.debug('config hydrated', { belongTo, found: Boolean(stored) })\n hydrated = true\n const storedForm =\n typeof stored?.form === 'string' ? stored.form : JSON.stringify(stored?.form)\n if (!stored || storedForm !== JSON.stringify(form)) persist()\n } catch (error) {\n configLogger.warn('failed to load config value', { belongTo }, error)\n data.value = cloneValue(defaultData)\n hydrated = true\n }\n })()\n\n watch(\n data,\n () => {\n if (!hydrated) return\n persist()\n },\n { deep: true, flush: 'sync' },\n )\n\n return Object.assign(data, { ready })\n}","import { logger } from '@delta-comic/logger'\nimport { SourcedValue } from '@delta-comic/model'\nimport { ref, toValue, watch, type MaybeRefOrGetter, type Ref } from 'vue'\n\nconst nativeStoreLogger = logger.scoped('db:native-store')\n\nexport interface Table {\n namespace: string\n key: string\n value: string\n}\n\nconst saveKey = new SourcedValue<[namespace: string, key: string]>()\n\nconst cloneDefault = <T extends object>(defaultValue: MaybeRefOrGetter<T>): T => {\n const value = toValue(defaultValue)\n if (typeof structuredClone === 'function') return structuredClone(value)\n return JSON.parse(JSON.stringify(value)) as T\n}\n\nconst legacyValue = (namespace: string, key: string) => {\n try {\n return globalThis.localStorage?.getItem(saveKey.toString([namespace, key])) ?? null\n } catch {\n return null\n }\n}\n\nconst parseValue = <T extends object>(value: unknown, defaultValue: MaybeRefOrGetter<T>): T => {\n if (value === null || value === '') return cloneDefault(defaultValue)\n if (typeof value !== 'string') {\n if (typeof structuredClone === 'function') return structuredClone(value as T)\n return JSON.parse(JSON.stringify(value)) as T\n }\n try {\n return JSON.parse(value) as T\n } catch (error) {\n nativeStoreLogger.warn('failed to parse native store value', error)\n return cloneDefault(defaultValue)\n }\n}\n\nconst getStoreValue = async (namespace: string, key: string) => {\n const { db } = await import('../index')\n return (\n (\n await db\n .selectFrom('nativeStore')\n .select('value')\n .where('namespace', '=', namespace)\n .where('key', '=', key)\n .executeTakeFirst()\n )?.value ?? null\n )\n}\n\nconst setStoreValue = async (namespace: string, key: string, value: string) => {\n const { db } = await import('../index')\n await db.replaceInto('nativeStore').values({ namespace, key, value }).execute()\n}\n\nexport const useNativeStore = <T extends object>(\n namespace: string,\n key: MaybeRefOrGetter<string>,\n defaultValue: MaybeRefOrGetter<T>,\n) => {\n const state = ref(cloneDefault(defaultValue)) as Ref<T>\n let version = 0\n let hydrated = false\n let saveTimer: ReturnType<typeof setTimeout> | undefined\n\n const persist = (resolvedKey: string, value: T) => {\n if (saveTimer) clearTimeout(saveTimer)\n const encoded = JSON.stringify(value)\n saveTimer = setTimeout(() => {\n void setStoreValue(namespace, resolvedKey, encoded).catch(error => {\n nativeStoreLogger.warn(\n 'failed to persist native store value',\n { key: resolvedKey, namespace },\n error,\n )\n })\n }, 100)\n }\n\n const load = async () => {\n const current = ++version\n const resolvedKey = toValue(key)\n hydrated = false\n try {\n const storeValue = await getStoreValue(namespace, resolvedKey)\n const storedValue = storeValue ?? legacyValue(namespace, resolvedKey)\n if (current !== version) return\n state.value = parseValue(storedValue, defaultValue)\n nativeStoreLogger.debug('native store value hydrated', {\n key: resolvedKey,\n namespace,\n source: storeValue === null ? 'legacy-or-default' : 'database',\n })\n hydrated = true\n if (storeValue === null) persist(resolvedKey, state.value)\n } catch (error) {\n nativeStoreLogger.warn(\n 'failed to load native store value',\n { key: resolvedKey, namespace },\n error,\n )\n if (current !== version) return\n state.value = cloneDefault(defaultValue)\n hydrated = true\n }\n }\n\n watch(\n () => toValue(key),\n () => void load(),\n { immediate: true },\n )\n watch(\n state,\n value => {\n if (!hydrated) return\n persist(toValue(key), value)\n },\n { deep: true },\n )\n\n return state\n}","import { logger } from '@delta-comic/logger'\nimport { isTauri } from '@tauri-apps/api/core'\nimport { CamelCasePlugin, type Dialect, Kysely } from 'kysely'\nimport { SerializePlugin } from 'kysely-plugin-serialize'\n\nimport type * as FavouriteDB from './favourite'\nexport * as PluginArchiveDB from './plugin'\nimport type * as HistoryDB from './history'\nexport * as FavouriteDB from './favourite'\nimport type * as ConfigDB from './config'\nimport type * as ItemStoreDB from './itemStore'\nimport type * as NativeStoreDB from './nativeStore'\nexport * as HistoryDB from './history'\nimport type * as PluginArchiveDB from './plugin'\nexport * as ItemStoreDB from './itemStore'\nimport type * as RecentDB from './recentView'\nexport * as SubscribeDB from './subscribe'\nimport type * as SubscribeDB from './subscribe'\nexport * as RecentDB from './recentView'\nexport * as ConfigDB from './config'\n\nexport interface DB {\n itemStore: ItemStoreDB.Table\n favouriteCard: FavouriteDB.CardTable\n favouriteItem: FavouriteDB.ItemTable\n history: HistoryDB.Table\n recentView: RecentDB.Table\n subscribe: SubscribeDB.Table\n plugin: PluginArchiveDB.Table\n nativeStore: NativeStoreDB.Table\n config: ConfigDB.Table\n}\n\nconst databaseLogger = logger.scoped('db:lifecycle')\n\ndatabaseLogger.info('database initialization started')\n\nexport const isTauriRuntime = isTauri\n\nconst createDialect = async (): Promise<Dialect> => {\n if (isTauriRuntime()) {\n const [{ default: Database }, { TauriSqliteDialect }] = await Promise.all([\n import('@tauri-apps/plugin-sql'),\n import('kysely-dialect-tauri'),\n ])\n const database = await Database.load('sqlite:app.db')\n databaseLogger.info('native sqlite dialect initialized')\n return new TauriSqliteDialect({ database })\n }\n\n const { createWebDialect } = await import('./web')\n databaseLogger.info('web sqlite dialect initialized')\n return createWebDialect()\n}\n\nexport const db = new Kysely<DB>({\n dialect: await createDialect(),\n plugins: [new CamelCasePlugin(), new SerializePlugin()],\n})\n\nexport * as DBUtils from './utils'\n\nexport type { InsertObject, Kysely } from 'kysely'\n\nexport * from './nativeStore'\nexport { useConfig } from './config'"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["QueryKey","useUpsert","useRemove","useQuery","useColadaQuery","QueryKey","useUpsert","QueryKey","ItemStoreDB.useUpsert","useColadaQuery","QueryKey","useUpsert","ItemStoreDB.useUpsert","useRemove","useQuery","useColadaQuery","QueryKey","useUpsert","useRemove","useQuery","useColadaQuery","ItemStoreDB.useUpsert","useQuery","useColadaQuery"],"sources":["../lib/utils.ts","../lib/plugin.ts","../lib/itemStore.ts","../lib/favourite.ts","../lib/history.ts","../lib/subscribe.ts","../lib/recentView.ts","../lib/config.ts","../lib/generated/schemas.ts","../lib/validation.ts","../lib/writeValidation.ts","../lib/nativeStore/index.ts","../lib/index.ts"],"sourcesContent":["import { logger } from '@delta-comic/logger'\nimport type { Kysely, SelectQueryBuilder } from 'kysely'\n\nimport type { DB } from '.'\n\nconst transactionLogger = logger.scoped('db:transaction')\n\nexport const withTransition = async <T>(\n handler: (trx: Kysely<DB>) => Promise<T>,\n trx?: Kysely<DB>,\n) => {\n if (trx) return await handler(trx)\n else {\n const { db } = await import('.')\n transactionLogger.trace('database transaction started')\n try {\n const result = await db\n .transaction()\n .setAccessMode('read write')\n .setIsolationLevel('read committed')\n .execute(handler)\n transactionLogger.trace('database transaction committed')\n return result\n } catch (error) {\n transactionLogger.error('database transaction failed', error)\n throw error\n }\n }\n}\n\nexport async function countDb<TB extends keyof DB, O extends object>(\n sql: SelectQueryBuilder<DB, TB, O>,\n) {\n const v = await sql.select(db => db.fn.countAll<number>().as('count')).executeTakeFirstOrThrow()\n return v.count\n}\n\nexport enum CommonQueryKey {\n common = 'db',\n}","import type { PluginManifest } from '@delta-comic/model'\nimport {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport type { PluginTable } from './generated/plugin.table'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport type Meta = PluginManifest\n\nexport type Table = Omit<PluginTable, 'meta' | 'enable'> & {\n meta: Selectable<PluginTable>['meta']\n enable: boolean\n}\n\nexport type Archive = Selectable<Table>\n\nexport enum QueryKey {\n item = 'db:plugin:',\n}\n\nexport const removeByNames = async (keys: Archive['pluginName'][], trx: Kysely<DB>) => {\n if (keys.length === 0) return\n await trx.deleteFrom('plugin').where('plugin.pluginName', 'in', keys).execute()\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ archives, trx }: { archives: Archive[]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx\n .replaceInto('plugin')\n .values(archives.map(a => ({ ...a, meta: JSON.stringify(a.meta) })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ keys, trx }: { keys: Archive['pluginName'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await removeByNames(keys, trx)\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useToggleEnable = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ keys, trx }: { keys: Archive['pluginName'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n for (const key of keys) {\n const isEnable = await trx\n .selectFrom('plugin')\n .where('pluginName', '=', key)\n .select('enable')\n .executeTakeFirstOrThrow()\n return trx\n .updateTable('plugin')\n .where('pluginName', '=', key)\n .set({ enable: !isEnable.enable })\n .execute()\n }\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, toggle: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'plugin', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('plugin'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import {\n SourcedValue,\n Struct,\n UniContentPage,\n type UniItem,\n type UniItemRaw,\n} from '@delta-comic/model'\nimport { defineMutation, useMutation, useQueryCache } from '@pinia/colada'\nimport type { Kysely, Selectable } from 'kysely'\n\nimport type { ItemStoreTable } from './generated/item_store.table'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport type Table = ItemStoreTable\nexport type StorableItem = UniItem | UniItemRaw\nexport type StoredItem = Selectable<Table>\nexport const itemKey = new SourcedValue('*')\n\nexport enum QueryKey {\n item = 'db:itemStore:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ item, trx }: { item: StorableItem; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n const k = itemKey.toString([\n UniContentPage.contentPages.key.toString(item.contentType),\n item.id,\n ])\n await trx\n .replaceInto('itemStore')\n .values({ item: Struct.toRaw(item), key: k })\n .execute()\n return k\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})","import {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { Kysely, Selectable, SelectQueryBuilder } from 'kysely'\nimport type { MaybeRefOrGetter } from 'vue'\nimport { toValue } from 'vue'\n\nimport type { FavouriteCardTable } from './generated/favourite_card.table'\nimport type { FavouriteItemTable as GeneratedFavouriteItemTable } from './generated/favourite_item.table'\nimport * as ItemStoreDB from './itemStore'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport type CardTable = FavouriteCardTable\n\nexport type Card = Selectable<CardTable>\n\nexport type ItemTable = GeneratedFavouriteItemTable\n\nexport type Item = Selectable<ItemTable>\n\nexport enum QueryKey {\n item = 'db:favouriteItem:',\n card = 'db:favouriteCard:',\n}\n\nexport const useUpsertItem = defineMutation(() => {\n const queryCache = useQueryCache()\n const { key: iKey, upsert } = ItemStoreDB.useUpsert()\n const key = [CommonQueryKey.common, QueryKey.item, ...iKey]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({\n item,\n belongTos,\n trx,\n }: {\n item: ItemStoreDB.StorableItem\n belongTos: Item['belongTo'][]\n trx?: Kysely<DB>\n }) =>\n withTransition(async trx => {\n const itemKey = await upsert({ item, trx })\n await trx\n .replaceInto('favouriteItem')\n .values(belongTos.map(belongTo => ({ addTime: Date.now(), itemKey, belongTo })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useMoveItem = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({\n item,\n from,\n aims,\n trx,\n }: {\n item: ItemStoreDB.StorableItem\n from: Item['belongTo']\n aims: Item['belongTo'][]\n trx?: Kysely<DB>\n }) =>\n withTransition(async trx => {\n await trx\n .deleteFrom('favouriteItem')\n .where('itemKey', '=', item.id)\n .where('belongTo', '=', from)\n .execute()\n await trx\n .replaceInto('favouriteItem')\n .values(aims.map(to => ({ addTime: Date.now(), itemKey: item.id, belongTo: to })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, move: mutateAsync, key }\n})\n\nexport const useCreateCard = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [QueryKey.card, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ card, trx }: { card: Card; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.replaceInto('favouriteCard').values(card).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, createCard: mutateAsync, key }\n})\n\nexport const useQueryItem = <T>(\n query: (db: SelectQueryBuilder<DB, 'favouriteItem', {}>) => Promise<T>,\n otherKeys: MaybeRefOrGetter<EntryKey> = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('favouriteItem'))\n },\n key: () => [QueryKey.item, QueryKey.card, query, ...toValue(otherKeys)],\n staleTime: 15000,\n initialData,\n initialDataUpdatedAt: 0,\n })\n\nexport const useQueryCard = <T>(\n query: (db: SelectQueryBuilder<DB, 'favouriteCard', {}>) => Promise<T>,\n otherKeys: MaybeRefOrGetter<EntryKey> = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('favouriteCard'))\n },\n key: () => [QueryKey.card, query, ...toValue(otherKeys)],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import { Struct } from '@delta-comic/model'\nimport {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport type { HistoryTable } from './generated/history.table'\nimport * as ItemStoreDB from './itemStore'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport type Table = HistoryTable\n\nexport type Item = Selectable<Table>\n\nexport enum QueryKey {\n item = 'db:history:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const { key: iKey, upsert } = ItemStoreDB.useUpsert()\n const key = [CommonQueryKey.common, QueryKey.item, ...iKey]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ item, trx }: { item: ItemStoreDB.StorableItem; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n const itemKey = await upsert({ item, trx })\n await trx\n .replaceInto('history')\n .values({ itemKey, timestamp: Date.now(), ep: Struct.toRaw(item.thisEp) })\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: ({ keys, trx }: { keys: Item['timestamp'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.deleteFrom('history').where('history.timestamp', 'is', keys).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'history', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('history'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import { SourcedValue, type SourcedKeyType } from '@delta-comic/model'\nimport {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport type { SubscribeTable } from './generated/subscribe.table'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport const key = new SourcedValue<[plugin: string, label: string]>()\nexport type Key_ = SourcedKeyType<typeof key>\nexport type Key = Exclude<Key_, string>\n\nexport type AuthorTable = Omit<SubscribeTable, 'itemKey' | 'author' | 'type'> & {\n author: Selectable<SubscribeTable>['author']\n itemKey: null\n type: 'author'\n}\nexport type AuthorItem = AuthorTable\n\nexport type EpTable = Omit<SubscribeTable, 'itemKey' | 'author' | 'type'> & {\n author: null\n itemKey: string // not f key\n type: 'ep'\n}\nexport type EpItem = EpTable\n\nexport type Table = SubscribeTable\nexport type Item = AuthorItem | EpItem\n\nexport enum QueryKey {\n item = 'db:subscribe:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ items, trx }: { items: Item[]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx\n .replaceInto('subscribe')\n .values(items.map(item => ({ ...item, author: JSON.stringify(item.author) })))\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ keys, trx }: { keys: Item['key'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.deleteFrom('subscribe').where('subscribe.key', 'is', keys).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'subscribe', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('subscribe'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import {\n defineMutation,\n useMutation,\n useQueryCache,\n useQuery as useColadaQuery,\n type EntryKey,\n} from '@pinia/colada'\nimport type { Kysely, Selectable, SelectQueryBuilder } from 'kysely'\n\nimport type { RecentViewTable } from './generated/recent_view.table'\nimport * as ItemStoreDB from './itemStore'\nimport { CommonQueryKey, withTransition } from './utils'\n\nimport type { DB } from '.'\n\nexport type Table = RecentViewTable\nexport type Item = Selectable<Table>\n\nexport enum QueryKey {\n item = 'db:recentView:',\n}\n\nexport const useUpsert = defineMutation(() => {\n const queryCache = useQueryCache()\n const { key: iKey, upsert } = ItemStoreDB.useUpsert()\n const key = [CommonQueryKey.common, QueryKey.item, ...iKey]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ item, trx }: { item: ItemStoreDB.StorableItem; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n const itemKey = await upsert({ item, trx })\n await trx\n .replaceInto('recentView')\n .values({ isViewed: false, itemKey, timestamp: Date.now() })\n .execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, upsert: mutateAsync, key }\n})\n\nexport const useRemove = defineMutation(() => {\n const queryCache = useQueryCache()\n const key = [CommonQueryKey.common, QueryKey.item]\n const { mutateAsync, ...mutation } = useMutation({\n mutation: async ({ items, trx }: { items: Item['timestamp'][]; trx?: Kysely<DB> }) =>\n withTransition(async trx => {\n await trx.deleteFrom('recentView').where('recentView.timestamp', 'is', items).execute()\n }, trx),\n onSettled: () => {\n void queryCache.invalidateQueries({ key })\n },\n key,\n })\n return { ...mutation, remove: mutateAsync, key }\n})\n\nexport const useQuery = <T>(\n query: (db: SelectQueryBuilder<DB, 'recentView', {}>) => Promise<T>,\n otherKeys: readonly EntryKey[] = [],\n initialData?: () => T,\n) =>\n useColadaQuery({\n query: async () => {\n const { db } = await import('.')\n return await query(db.selectFrom('recentView'))\n },\n key: () => [CommonQueryKey.common, QueryKey.item, query, ...otherKeys],\n staleTime: 15000,\n refetchOnMount: 'always',\n initialData,\n initialDataUpdatedAt: 0,\n })","import { logger } from '@delta-comic/logger'\nimport type { FormResult, FormSingleConfigure } from '@delta-comic/model'\nimport { fromPairs } from 'es-toolkit/compat'\nimport { ref, watch, type Ref } from 'vue'\n\nimport type { ConfigTable } from './generated/config.table'\nconst configLogger = logger.scoped('db:config')\n\nexport type Table = ConfigTable\n\nexport type ConfigRef<T> = Ref<T> & { readonly ready: Promise<void> }\n\nexport type ConfigDescription = Record<\n string,\n Required<Pick<FormSingleConfigure, 'defaultValue'>> & FormSingleConfigure\n>\n\nconst cloneValue = <T>(value: T): T => {\n if (typeof structuredClone === 'function') return structuredClone(value)\n return JSON.parse(JSON.stringify(value)) as T\n}\n\nconst createDefaultData = <T extends ConfigDescription>(config: T): FormResult<T> =>\n fromPairs(\n Object.entries(config).map(([name, desc]) => [name, desc.defaultValue]),\n ) as FormResult<T>\n\nconst parseJson = <T>(value: unknown, fallback: T): T => {\n if (!value) return cloneValue(fallback)\n if (typeof value !== 'string') return cloneValue(value as T)\n try {\n return JSON.parse(value) as T\n } catch (error) {\n configLogger.warn('failed to parse config value', error)\n return cloneValue(fallback)\n }\n}\n\nconst upsertConfig = async (belongTo: string, form: ConfigDescription, data: unknown) => {\n const { db } = await import('.')\n await db\n .replaceInto('config')\n .values({ belongTo, form: JSON.stringify(form), data: JSON.stringify(data) })\n .execute()\n configLogger.debug('config persisted', { belongTo })\n}\n\nexport const useConfig = <T extends ConfigDescription>(\n belongTo: string,\n form: T,\n): ConfigRef<FormResult<T>> => {\n const defaultData = createDefaultData(form)\n const data = ref(cloneValue(defaultData)) as Ref<FormResult<T>>\n let hydrated = false\n let saveTimer: ReturnType<typeof setTimeout> | undefined\n\n const persist = () => {\n if (saveTimer) clearTimeout(saveTimer)\n saveTimer = setTimeout(() => {\n void upsertConfig(belongTo, form, data.value).catch(error => {\n configLogger.warn('failed to persist config value', { belongTo }, error)\n })\n }, 100)\n }\n\n const ready = (async () => {\n try {\n const { db } = await import('.')\n const stored = await db\n .selectFrom('config')\n .select(['form', 'data'])\n .where('belongTo', '=', belongTo)\n .executeTakeFirst()\n data.value = parseJson(stored?.data, defaultData)\n configLogger.debug('config hydrated', { belongTo, found: Boolean(stored) })\n hydrated = true\n const storedForm =\n typeof stored?.form === 'string' ? stored.form : JSON.stringify(stored?.form)\n if (!stored || storedForm !== JSON.stringify(form)) persist()\n } catch (error) {\n configLogger.warn('failed to load config value', { belongTo }, error)\n data.value = cloneValue(defaultData)\n hydrated = true\n }\n })()\n\n watch(\n data,\n () => {\n if (!hydrated) return\n persist()\n },\n { deep: true, flush: 'sync' },\n )\n\n return Object.assign(data, { ready })\n}","import type { TSchema } from 'typebox'\n\n/** Runtime SQLite row schema for item_store. */\nexport const itemStoreRowSchema = {\n type: 'object',\n properties: { key: { type: 'string' }, item: { type: 'string' } },\n required: ['key', 'item'],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for favourite_card. */\nexport const favouriteCardRowSchema = {\n type: 'object',\n properties: {\n create_at: { type: 'integer' },\n title: { type: 'string' },\n private: { type: 'integer' },\n description: { type: 'string' },\n },\n required: ['create_at', 'title', 'private', 'description'],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for favourite_item. */\nexport const favouriteItemRowSchema = {\n type: 'object',\n properties: {\n add_time: { type: 'integer' },\n belong_to: { type: 'integer' },\n item_key: { type: 'string' },\n },\n required: ['add_time', 'belong_to', 'item_key'],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for history. */\nexport const historyRowSchema = {\n type: 'object',\n properties: {\n ep: { type: 'string' },\n timestamp: { type: 'integer' },\n item_key: { type: 'string' },\n },\n required: ['ep', 'timestamp', 'item_key'],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for recent_view. */\nexport const recentViewRowSchema = {\n type: 'object',\n properties: {\n timestamp: { type: 'integer' },\n item_key: { type: 'string' },\n is_viewed: { type: 'integer' },\n },\n required: ['timestamp', 'item_key', 'is_viewed'],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for subscribe. */\nexport const subscribeRowSchema = {\n type: 'object',\n properties: {\n item_key: { anyOf: [{ type: 'string' }, { type: 'null' }] },\n author: { anyOf: [{ type: 'string' }, { type: 'null' }] },\n type: { type: 'string' },\n key: { type: 'string' },\n plugin: { type: 'string' },\n },\n required: ['item_key', 'author', 'type', 'key', 'plugin'],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for plugin. */\nexport const pluginRowSchema = {\n type: 'object',\n properties: {\n installer_name: { type: 'string' },\n loader_name: { type: 'string' },\n plugin_name: { type: 'string' },\n meta: { type: 'string' },\n enable: { type: 'integer' },\n install_input: { type: 'string' },\n display_name: { anyOf: [{ type: 'string' }, { type: 'null' }] },\n },\n required: [\n 'installer_name',\n 'loader_name',\n 'plugin_name',\n 'meta',\n 'enable',\n 'install_input',\n 'display_name',\n ],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for native_store. */\nexport const nativeStoreRowSchema = {\n type: 'object',\n properties: { namespace: { type: 'string' }, key: { type: 'string' }, value: { type: 'string' } },\n required: ['namespace', 'key', 'value'],\n additionalProperties: false,\n} as const\n\n/** Runtime SQLite row schema for config. */\nexport const configRowSchema = {\n type: 'object',\n properties: { belong_to: { type: 'string' }, form: { type: 'string' }, data: { type: 'string' } },\n required: ['belong_to', 'form', 'data'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for item_store (camelCase keys). */\nexport const itemStoreCamelRowSchema = {\n type: 'object',\n properties: {\n key: { type: 'string' },\n item: { anyOf: [{ type: 'object' }, { type: 'string' }] },\n },\n required: ['key', 'item'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for favourite_card (camelCase keys). */\nexport const favouriteCardCamelRowSchema = {\n type: 'object',\n properties: {\n createAt: { type: 'integer' },\n title: { type: 'string' },\n private: { anyOf: [{ type: 'boolean' }, { const: 0 }, { const: 1 }] },\n description: { type: 'string' },\n },\n required: ['createAt', 'title', 'private', 'description'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for favourite_item (camelCase keys). */\nexport const favouriteItemCamelRowSchema = {\n type: 'object',\n properties: {\n addTime: { type: 'integer' },\n belongTo: { type: 'integer' },\n itemKey: { type: 'string' },\n },\n required: ['addTime', 'belongTo', 'itemKey'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for history (camelCase keys). */\nexport const historyCamelRowSchema = {\n type: 'object',\n properties: {\n ep: { anyOf: [{ type: 'object' }, { type: 'string' }] },\n timestamp: { type: 'integer' },\n itemKey: { type: 'string' },\n },\n required: ['ep', 'timestamp', 'itemKey'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for recent_view (camelCase keys). */\nexport const recentViewCamelRowSchema = {\n type: 'object',\n properties: {\n timestamp: { type: 'integer' },\n itemKey: { type: 'string' },\n isViewed: { anyOf: [{ type: 'boolean' }, { const: 0 }, { const: 1 }] },\n },\n required: ['timestamp', 'itemKey', 'isViewed'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for subscribe (camelCase keys). */\nexport const subscribeCamelRowSchema = {\n type: 'object',\n properties: {\n itemKey: { anyOf: [{ type: 'string' }, { type: 'null' }] },\n author: { anyOf: [{ type: 'object' }, { type: 'string' }, { type: 'null' }] },\n type: { type: 'string' },\n key: { type: 'string' },\n plugin: { type: 'string' },\n },\n required: ['itemKey', 'author', 'type', 'key', 'plugin'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for plugin (camelCase keys). */\nexport const pluginCamelRowSchema = {\n type: 'object',\n properties: {\n installerName: { type: 'string' },\n loaderName: { type: 'string' },\n pluginName: { type: 'string' },\n meta: { anyOf: [{ type: 'object' }, { type: 'string' }] },\n enable: { anyOf: [{ type: 'boolean' }, { const: 0 }, { const: 1 }] },\n installInput: { type: 'string' },\n displayName: { anyOf: [{ type: 'string' }, { type: 'null' }] },\n },\n required: [\n 'installerName',\n 'loaderName',\n 'pluginName',\n 'meta',\n 'enable',\n 'installInput',\n 'displayName',\n ],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for native_store (camelCase keys). */\nexport const nativeStoreCamelRowSchema = {\n type: 'object',\n properties: { namespace: { type: 'string' }, key: { type: 'string' }, value: { type: 'string' } },\n required: ['namespace', 'key', 'value'],\n additionalProperties: false,\n} as const\n\n/** Runtime TS-level row schema for config (camelCase keys). */\nexport const configCamelRowSchema = {\n type: 'object',\n properties: { belongTo: { type: 'string' }, form: { type: 'string' }, data: { type: 'string' } },\n required: ['belongTo', 'form', 'data'],\n additionalProperties: false,\n} as const\n\nexport const clientRowSchemas = {\n item_store: itemStoreRowSchema,\n favourite_card: favouriteCardRowSchema,\n favourite_item: favouriteItemRowSchema,\n history: historyRowSchema,\n recent_view: recentViewRowSchema,\n subscribe: subscribeRowSchema,\n plugin: pluginRowSchema,\n native_store: nativeStoreRowSchema,\n config: configRowSchema,\n} satisfies Record<string, TSchema>\nexport const clientCamelRowSchemas = {\n itemStore: itemStoreCamelRowSchema,\n favouriteCard: favouriteCardCamelRowSchema,\n favouriteItem: favouriteItemCamelRowSchema,\n history: historyCamelRowSchema,\n recentView: recentViewCamelRowSchema,\n subscribe: subscribeCamelRowSchema,\n plugin: pluginCamelRowSchema,\n nativeStore: nativeStoreCamelRowSchema,\n config: configCamelRowSchema,\n} satisfies Record<string, TSchema>","import { logger } from '@delta-comic/logger'\nimport type { TSchema } from 'typebox'\nimport { Compile } from 'typebox/compile'\nimport { Value } from 'typebox/value'\n\nimport { clientCamelRowSchemas } from './generated/schemas'\n\nconst validationLogger = logger.scoped('db:validation')\n\nexport type ClientTableName = keyof typeof clientCamelRowSchemas\n\nconst validators = new WeakMap<object, ReturnType<typeof Compile>>()\n\nconst validatorFor = (schema: TSchema): ReturnType<typeof Compile> => {\n const cached = validators.get(schema)\n if (cached) return cached\n const validator = Compile(schema)\n validators.set(schema, validator)\n return validator\n}\n\nconst validationDetails = (schema: TSchema, value: unknown) =>\n [...Value.Errors(schema, value)]\n .slice(0, 5)\n .map(error => ({ instancePath: error.instancePath, message: error.message }))\n\nexport const tableSchema = <K extends ClientTableName>(table: K) => clientCamelRowSchemas[table]\n\n/** Validates a row before writing; throws to block invalid data from persisting. */\nexport const assertWrite = <T>(schema: TSchema, table: string, value: T): T => {\n if (!validatorFor(schema).Check(value)) {\n validationLogger.error('database write validation failed', {\n table,\n errors: validationDetails(schema, value),\n })\n throw new Error(\n `database write validation failed for ${table}: ${JSON.stringify(\n validationDetails(schema, value),\n )}`,\n )\n }\n return value\n}\n\nexport const assertWriteRow = <K extends ClientTableName, T>(table: K, value: T): T =>\n assertWrite(tableSchema(table), table, value)\n\n/** Validates a row on read; failures are non-intrusive: logged and the value returned as-is. */\nexport const validateRead = <T>(schema: TSchema, table: string, value: T): T => {\n if (!validatorFor(schema).Check(value)) {\n validationLogger.warn('database read validation failed', {\n table,\n errors: validationDetails(schema, value),\n })\n }\n return value\n}\n\nexport const validateReadRow = <K extends ClientTableName, T>(table: K, value: T): T =>\n validateRead(tableSchema(table), table, value)\n\n/** Filters invalid rows on read; failures are non-intrusive: logged and the row dropped. */\nexport const filterValidRows = <T>(schema: TSchema, table: string, rows: readonly T[]): T[] => {\n const valid: T[] = []\n for (const row of rows) {\n if (validatorFor(schema).Check(row)) {\n valid.push(row)\n continue\n }\n validationLogger.warn('database read validation failed, row dropped', {\n table,\n errors: validationDetails(schema, row),\n })\n }\n return valid\n}\n\nexport const filterValidRowsFor = <K extends ClientTableName, T>(\n table: K,\n rows: readonly T[],\n): T[] => filterValidRows(tableSchema(table), table, rows)","import type {\n ColumnNode,\n InsertQueryNode,\n KyselyPlugin,\n OperationNode,\n PluginTransformQueryArgs,\n PluginTransformResultArgs,\n QueryResult,\n RootOperationNode,\n TableNode,\n UpdateQueryNode,\n UnknownRow,\n ValueNode,\n ValuesNode,\n} from 'kysely'\nimport type { TSchema } from 'typebox'\n\nimport { clientCamelRowSchemas } from './generated/schemas'\nimport { assertWrite } from './validation'\n\nconst isTableNode = (node: OperationNode | undefined): node is TableNode =>\n node?.kind === 'TableNode'\n\nconst isValuesNode = (node: OperationNode | undefined): node is ValuesNode =>\n node?.kind === 'ValuesNode'\n\nconst isValueNode = (node: OperationNode): node is ValueNode => node.kind === 'ValueNode'\n\nconst isColumnNode = (node: OperationNode): node is ColumnNode => node.kind === 'ColumnNode'\n\nconst tableNameOf = (node: OperationNode | undefined): string | null => {\n if (!isTableNode(node)) return null\n return node.table.identifier.name\n}\n\nconst rowObjectsOf = (node: InsertQueryNode): readonly unknown[] | null => {\n const columns = node.columns\n if (!columns || columns.length === 0) return null\n const names = columns.map(column => column.column.name)\n const values = node.values\n if (!isValuesNode(values)) return null\n const rows: unknown[] = []\n for (const list of values.values) {\n let entries: unknown[]\n if (list.kind === 'PrimitiveValueListNode') {\n entries = [...list.values]\n } else if (list.kind === 'ValueListNode') {\n const wrapped: unknown[] = []\n for (const entry of list.values) {\n if (!isValueNode(entry)) return null\n wrapped.push(entry.value)\n }\n entries = wrapped\n } else {\n return null\n }\n if (entries.length !== names.length) return null\n rows.push(Object.fromEntries(names.map((name, index) => [name, entries[index]])))\n }\n return rows\n}\n\nconst updatePatchOf = (node: UpdateQueryNode): Record<string, unknown> | null => {\n if (!node.updates || node.updates.length === 0) return null\n const patch: Record<string, unknown> = {}\n for (const update of node.updates) {\n if (!isColumnNode(update.column)) return null\n const value = update.value\n if (!isValueNode(value)) return null\n patch[update.column.column.name] = value.value\n }\n return patch\n}\n\nconst partialSchemas = new WeakMap<object, TSchema>()\n\nconst partialOf = (schema: TSchema): TSchema => {\n const cached = partialSchemas.get(schema)\n if (cached) return cached\n const partial = { ...schema, required: undefined }\n partialSchemas.set(schema, partial)\n return partial\n}\n\nexport const validateWriteNode = (node: RootOperationNode): void => {\n let tableName: string | null = null\n let rows: readonly unknown[] | null = null\n let patch: Record<string, unknown> | null = null\n if (node.kind === 'InsertQueryNode') {\n tableName = tableNameOf(node.into)\n rows = rowObjectsOf(node)\n } else if (node.kind === 'UpdateQueryNode') {\n tableName = tableNameOf(node.table)\n patch = updatePatchOf(node)\n } else {\n return\n }\n if (tableName === null) return\n const schema = (clientCamelRowSchemas as Record<string, TSchema>)[tableName]\n if (!schema) return\n if (rows !== null) {\n if (rows.length === 0) return\n for (const row of rows) assertWrite(schema, tableName, row)\n return\n }\n if (patch !== null) {\n assertWrite(partialOf(schema), tableName, patch)\n }\n}\n\n/**\n * Centralized write gate: validates every insert/replace/update against the\n * generated camelCase row schema before it reaches the dialect. Registered\n * before CamelCasePlugin, so it observes camelCase identifiers and raw values.\n */\nexport class WriteValidationPlugin implements KyselyPlugin {\n transformQuery({ node }: PluginTransformQueryArgs): RootOperationNode {\n validateWriteNode(node)\n return node\n }\n\n async transformResult({ result }: PluginTransformResultArgs): Promise<QueryResult<UnknownRow>> {\n return result\n }\n}","import { logger } from '@delta-comic/logger'\nimport { SourcedValue } from '@delta-comic/model'\nimport { ref, toValue, watch, type MaybeRefOrGetter, type Ref } from 'vue'\n\nimport type { NativeStoreTable } from '../generated/native_store.table'\n\nconst nativeStoreLogger = logger.scoped('db:native-store')\n\nexport type Table = NativeStoreTable\n\nconst saveKey = new SourcedValue<[namespace: string, key: string]>()\n\nconst cloneDefault = <T extends object>(defaultValue: MaybeRefOrGetter<T>): T => {\n const value = toValue(defaultValue)\n if (typeof structuredClone === 'function') return structuredClone(value)\n return JSON.parse(JSON.stringify(value)) as T\n}\n\nconst legacyValue = (namespace: string, key: string) => {\n try {\n return globalThis.localStorage?.getItem(saveKey.toString([namespace, key])) ?? null\n } catch {\n return null\n }\n}\n\nconst parseValue = <T extends object>(value: unknown, defaultValue: MaybeRefOrGetter<T>): T => {\n if (value === null || value === '') return cloneDefault(defaultValue)\n if (typeof value !== 'string') {\n if (typeof structuredClone === 'function') return structuredClone(value as T)\n return JSON.parse(JSON.stringify(value)) as T\n }\n try {\n return JSON.parse(value) as T\n } catch (error) {\n nativeStoreLogger.warn('failed to parse native store value', error)\n return cloneDefault(defaultValue)\n }\n}\n\nconst getStoreValue = async (namespace: string, key: string) => {\n const { db } = await import('../index')\n return (\n (\n await db\n .selectFrom('nativeStore')\n .select('value')\n .where('namespace', '=', namespace)\n .where('key', '=', key)\n .executeTakeFirst()\n )?.value ?? null\n )\n}\n\nconst setStoreValue = async (namespace: string, key: string, value: string) => {\n const { db } = await import('../index')\n await db.replaceInto('nativeStore').values({ namespace, key, value }).execute()\n}\n\nexport const useNativeStore = <T extends object>(\n namespace: string,\n key: MaybeRefOrGetter<string>,\n defaultValue: MaybeRefOrGetter<T>,\n) => {\n const state = ref(cloneDefault(defaultValue)) as Ref<T>\n let version = 0\n let hydrated = false\n let saveTimer: ReturnType<typeof setTimeout> | undefined\n\n const persist = (resolvedKey: string, value: T) => {\n if (saveTimer) clearTimeout(saveTimer)\n const encoded = JSON.stringify(value)\n saveTimer = setTimeout(() => {\n void setStoreValue(namespace, resolvedKey, encoded).catch(error => {\n nativeStoreLogger.warn(\n 'failed to persist native store value',\n { key: resolvedKey, namespace },\n error,\n )\n })\n }, 100)\n }\n\n const load = async () => {\n const current = ++version\n const resolvedKey = toValue(key)\n hydrated = false\n try {\n const storeValue = await getStoreValue(namespace, resolvedKey)\n const storedValue = storeValue ?? legacyValue(namespace, resolvedKey)\n if (current !== version) return\n state.value = parseValue(storedValue, defaultValue)\n nativeStoreLogger.debug('native store value hydrated', {\n key: resolvedKey,\n namespace,\n source: storeValue === null ? 'legacy-or-default' : 'database',\n })\n hydrated = true\n if (storeValue === null) persist(resolvedKey, state.value)\n } catch (error) {\n nativeStoreLogger.warn(\n 'failed to load native store value',\n { key: resolvedKey, namespace },\n error,\n )\n if (current !== version) return\n state.value = cloneDefault(defaultValue)\n hydrated = true\n }\n }\n\n watch(\n () => toValue(key),\n () => void load(),\n { immediate: true },\n )\n watch(\n state,\n value => {\n if (!hydrated) return\n persist(toValue(key), value)\n },\n { deep: true },\n )\n\n return state\n}","import { logger } from '@delta-comic/logger'\nimport { isTauri } from '@tauri-apps/api/core'\nimport { CamelCasePlugin, type Dialect, Kysely } from 'kysely'\nimport { SerializePlugin } from 'kysely-plugin-serialize'\n\nimport type * as FavouriteDB from './favourite'\nexport * as PluginArchiveDB from './plugin'\nimport type * as HistoryDB from './history'\nexport * as FavouriteDB from './favourite'\nimport type * as ConfigDB from './config'\nimport type { PluginTable } from './generated/plugin.table'\nimport type * as ItemStoreDB from './itemStore'\nimport type * as NativeStoreDB from './nativeStore'\nexport type { PluginTable } from './generated/plugin.table'\nexport * as HistoryDB from './history'\nexport * as ItemStoreDB from './itemStore'\nimport type * as RecentDB from './recentView'\nexport * as SubscribeDB from './subscribe'\nimport type * as SubscribeDB from './subscribe'\nexport * as RecentDB from './recentView'\nexport * as ConfigDB from './config'\nimport { WriteValidationPlugin } from './writeValidation'\nexport { WriteValidationPlugin } from './writeValidation'\nexport * from './validation'\n\nexport interface DB {\n itemStore: ItemStoreDB.Table\n favouriteCard: FavouriteDB.CardTable\n favouriteItem: FavouriteDB.ItemTable\n history: HistoryDB.Table\n recentView: RecentDB.Table\n subscribe: SubscribeDB.Table\n plugin: PluginTable\n nativeStore: NativeStoreDB.Table\n config: ConfigDB.Table\n}\n\nconst databaseLogger = logger.scoped('db:lifecycle')\n\ndatabaseLogger.info('database initialization started')\n\nexport const isTauriRuntime = isTauri\n\nconst createDialect = async (): Promise<Dialect> => {\n if (isTauriRuntime()) {\n const [{ default: Database }, { TauriSqliteDialect }] = await Promise.all([\n import('@tauri-apps/plugin-sql'),\n import('kysely-dialect-tauri'),\n ])\n const database = await Database.load('sqlite:app.db')\n databaseLogger.info('native sqlite dialect initialized')\n return new TauriSqliteDialect({ database })\n }\n\n const { createWebDialect } = await import('./web')\n databaseLogger.info('web sqlite dialect initialized')\n return createWebDialect()\n}\n\nexport const db = new Kysely<DB>({\n dialect: await createDialect(),\n plugins: [new WriteValidationPlugin(), new CamelCasePlugin(), new SerializePlugin()],\n})\n\nexport * as DBUtils from './utils'\n\nexport type { InsertObject, Kysely } from 'kysely'\n\nexport * from './nativeStore'\nexport { useConfig } from './config'"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@delta-comic/db",
|
|
3
|
-
"version": "3.0.0-next.
|
|
3
|
+
"version": "3.0.0-next.12",
|
|
4
4
|
"description": "空阙虱楼",
|
|
5
5
|
"homepage": "https://github.com/delta-comic/delta-comic",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@delta-comic/logger": "3.0.0-next.
|
|
32
|
+
"@delta-comic/logger": "3.0.0-next.12",
|
|
33
33
|
"@subframe7536/sqlite-wasm": "^1.3.1",
|
|
34
34
|
"@tauri-apps/api": "^2.11.1",
|
|
35
35
|
"@tauri-apps/plugin-sql": "^2.4.0",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"kysely-dialect-tauri": "^2.0.1",
|
|
39
39
|
"kysely-plugin-serialize": "^0.8.2",
|
|
40
40
|
"kysely-wasqlite-worker": "^2.0.1",
|
|
41
|
-
"mitt": "^3.0.1"
|
|
41
|
+
"mitt": "^3.0.1",
|
|
42
|
+
"typebox": "^1.3.14"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"typescript": "npm:typescript-native-bridge@6.0.3-bridge.8.tsgo.7.0.2",
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"vite-plus": "^0.2.9"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
|
-
"@delta-comic/model": "3.0.0-next.
|
|
50
|
+
"@delta-comic/model": "3.0.0-next.12",
|
|
50
51
|
"@pinia/colada": "^1.4.2",
|
|
51
52
|
"vue": "^3.6.0-rc.4"
|
|
52
53
|
}
|