@shaxpir/duiduidui-models 1.8.2 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { CompactDateTime } from "@shaxpir/shaxpir-common";
3
3
  import { ShareSync } from '../repo';
4
4
  import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
5
5
  import { ConditionFilters } from './Condition';
6
+ import { BuiltInDbState, DatabaseVersion } from '../util/Database';
6
7
  export interface LastSync {
7
8
  at_utc_time: CompactDateTime | null;
8
9
  }
@@ -34,6 +35,7 @@ export interface DevicePayload {
34
35
  conditions?: ConditionFilters;
35
36
  download_queue?: DownloadQueueItem[];
36
37
  upload_queue?: UploadQueueItem[];
38
+ builtin_db?: BuiltInDbState;
37
39
  }
38
40
  export interface DeviceBody extends ContentBody {
39
41
  meta: ContentMeta;
@@ -49,6 +51,17 @@ export declare class Device extends Content {
49
51
  setLastSyncAtUtcTime(value: CompactDateTime): void;
50
52
  get chineseFont(): string;
51
53
  setChineseFont(value: string): void;
54
+ getBuiltInDbState(): BuiltInDbState | undefined;
55
+ getBuiltInDbVersion(): DatabaseVersion;
56
+ getBuiltInDbPendingVersion(): DatabaseVersion;
57
+ getBuiltInDbDownloadStatus(): string;
58
+ getBuiltInDbLastCheck(): CompactDateTime;
59
+ getBuiltInDbLastError(): string;
60
+ setBuiltInDbVersion(version: DatabaseVersion | null): void;
61
+ setBuiltInDbPendingVersion(pending_version: DatabaseVersion | null): void;
62
+ setBuiltInDbDownloadStatus(download_status: 'none' | 'downloading' | 'ready' | 'failed'): void;
63
+ setBuiltInDbLastCheck(last_check: CompactDateTime | null): void;
64
+ setBuiltInDbLastError(last_error: string | null): void;
52
65
  get downloadQueue(): DownloadQueueItem[];
53
66
  get downloadQueueLength(): number;
54
67
  addToDownloadQueue(item: AudioDownloadQueueItem | ImageDownloadQueueItem): void;
@@ -22,7 +22,14 @@ class Device extends Content_1.Content {
22
22
  payload: {
23
23
  last_sync: { at_utc_time: null },
24
24
  download_queue: [],
25
- upload_queue: []
25
+ upload_queue: [],
26
+ builtin_db: {
27
+ version: null,
28
+ pending_version: null,
29
+ download_status: 'none',
30
+ last_check: null,
31
+ last_error: null
32
+ }
26
33
  }
27
34
  });
28
35
  }
@@ -59,6 +66,68 @@ class Device extends Content_1.Content {
59
66
  batch.commit();
60
67
  }
61
68
  }
69
+ // Built-in Database State Methods
70
+ getBuiltInDbState() {
71
+ this.checkDisposed("Device.getBuiltInDbState");
72
+ return shaxpir_common_1.Struct.clone(this.payload.builtin_db);
73
+ }
74
+ // Convenience getters for built-in DB state
75
+ getBuiltInDbVersion() {
76
+ return this.payload.builtin_db.version;
77
+ }
78
+ getBuiltInDbPendingVersion() {
79
+ return this.payload.builtin_db.pending_version;
80
+ }
81
+ getBuiltInDbDownloadStatus() {
82
+ return this.payload.builtin_db.download_status;
83
+ }
84
+ getBuiltInDbLastCheck() {
85
+ return this.payload.builtin_db.last_check;
86
+ }
87
+ getBuiltInDbLastError() {
88
+ return this.payload.builtin_db.last_error;
89
+ }
90
+ // Convenience setters for built-in DB state
91
+ setBuiltInDbVersion(version) {
92
+ this.checkDisposed("Device.setBuiltInDbVersion");
93
+ if (this.getBuiltInDbVersion() !== version) {
94
+ const batch = new Operation_1.BatchOperation(this);
95
+ batch.setPathValue(['payload', 'builtin_db', 'version'], version);
96
+ batch.commit();
97
+ }
98
+ }
99
+ setBuiltInDbPendingVersion(pending_version) {
100
+ this.checkDisposed("Device.setBuiltInDbPendingVersion");
101
+ if (this.getBuiltInDbPendingVersion() !== pending_version) {
102
+ const batch = new Operation_1.BatchOperation(this);
103
+ batch.setPathValue(['payload', 'builtin_db', 'pending_version'], pending_version);
104
+ batch.commit();
105
+ }
106
+ }
107
+ setBuiltInDbDownloadStatus(download_status) {
108
+ this.checkDisposed("Device.setBuiltInDbDownloadStatus");
109
+ if (this.getBuiltInDbDownloadStatus() !== download_status) {
110
+ const batch = new Operation_1.BatchOperation(this);
111
+ batch.setPathValue(['payload', 'builtin_db', 'download_status'], download_status);
112
+ batch.commit();
113
+ }
114
+ }
115
+ setBuiltInDbLastCheck(last_check) {
116
+ this.checkDisposed("Device.setBuiltInDbLastCheck");
117
+ if (this.getBuiltInDbLastCheck() !== last_check) {
118
+ const batch = new Operation_1.BatchOperation(this);
119
+ batch.setPathValue(['payload', 'builtin_db', 'last_check'], last_check);
120
+ batch.commit();
121
+ }
122
+ }
123
+ setBuiltInDbLastError(last_error) {
124
+ this.checkDisposed("Device.setBuiltInDbLastError");
125
+ if (this.getBuiltInDbLastError() !== last_error) {
126
+ const batch = new Operation_1.BatchOperation(this);
127
+ batch.setPathValue(['payload', 'builtin_db', 'last_error'], last_error);
128
+ batch.commit();
129
+ }
130
+ }
62
131
  // Download Queue Methods
63
132
  get downloadQueue() {
64
133
  this.checkDisposed("Device.downloadQueue");
@@ -0,0 +1,124 @@
1
+ import { CompactDateTime } from '@shaxpir/shaxpir-common';
2
+ declare enum DatabaseVersionBrand {
3
+ }
4
+ /**
5
+ * Branded type for database version strings (YYYYMMDDx format)
6
+ * Ensures only validated version strings are used
7
+ */
8
+ export type DatabaseVersion = string & DatabaseVersionBrand;
9
+ /**
10
+ * Describes a version of the built-in database available for download
11
+ */
12
+ export interface BuiltInDbMetadata {
13
+ version: DatabaseVersion;
14
+ url: string;
15
+ uncompressed_size: number;
16
+ compressed_size: number;
17
+ checksum: string;
18
+ published_at: string;
19
+ min_app_version: string;
20
+ }
21
+ /**
22
+ * Tracks the state of the built-in database on a device
23
+ * Stored in Device model's payload.builtin_db field
24
+ */
25
+ export interface BuiltInDbState {
26
+ version: DatabaseVersion | null;
27
+ pending_version: DatabaseVersion | null;
28
+ download_status: DownloadStatus;
29
+ last_check: CompactDateTime | null;
30
+ last_error: string | null;
31
+ }
32
+ /**
33
+ * General-purpose download status enum
34
+ * Used for built-in DB, images, or any other downloadable content
35
+ */
36
+ export type DownloadStatus = 'none' | 'downloading' | 'ready' | 'failed';
37
+ /**
38
+ * Checksum utilities for validating downloaded files
39
+ */
40
+ export declare class Checksum {
41
+ /**
42
+ * Parse a checksum string into algorithm and hash
43
+ * Format: "algorithm:hash" (e.g., "sha256:abc123...")
44
+ */
45
+ static parse(checksum: string): {
46
+ algorithm: string;
47
+ hash: string;
48
+ } | null;
49
+ /**
50
+ * Validate checksum format
51
+ */
52
+ static isValid(checksum: string): boolean;
53
+ /**
54
+ * Format a checksum (ensures consistent format)
55
+ */
56
+ static format(algorithm: string, hash: string): string;
57
+ }
58
+ /**
59
+ * Database version utilities
60
+ */
61
+ export declare class DatabaseVersionModel {
62
+ /**
63
+ * Validate and create a branded DatabaseVersion from a string
64
+ * Throws if the version format is invalid
65
+ */
66
+ static from(version: string): DatabaseVersion;
67
+ /**
68
+ * Validate YYYYMMDDx format (where x is a lowercase letter a-z)
69
+ * Examples: "20250118a", "20250118b", "20250125a"
70
+ */
71
+ static isValid(version: string): boolean;
72
+ /**
73
+ * Compare two version strings
74
+ * Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
75
+ */
76
+ static compare(v1: DatabaseVersion, v2: DatabaseVersion): number;
77
+ /**
78
+ * Check if v1 is newer than v2
79
+ */
80
+ static isNewer(v1: DatabaseVersion, v2: DatabaseVersion): boolean;
81
+ /**
82
+ * Generate next version in sequence for the same day
83
+ * Example: "20250118a" -> "20250118b"
84
+ * Returns null if already at 'z'
85
+ */
86
+ static nextInDay(version: DatabaseVersion): DatabaseVersion | null;
87
+ /**
88
+ * Extract CompactDate from version string (ignores letter suffix)
89
+ * Example: "20250118a" -> "20250118"
90
+ */
91
+ static toCompactDate(version: DatabaseVersion): string;
92
+ /**
93
+ * Get the letter suffix from a version string
94
+ * Example: "20250118a" -> "a"
95
+ */
96
+ static getLetterSuffix(version: DatabaseVersion): string;
97
+ }
98
+ /**
99
+ * Constants for built-in database management
100
+ */
101
+ export declare const BUILTIN_DB_CONSTANTS: {
102
+ readonly FILE_PREFIX: "duiduidui-";
103
+ readonly FILE_EXTENSION: ".sqlite";
104
+ readonly COMPRESSED_EXTENSION: ".sqlite.gz";
105
+ readonly VERSION_MANIFEST_FILENAME: "manifest.json";
106
+ readonly VERSION_FORMAT: "YYYYMMDDx";
107
+ readonly VERSION_REGEX: RegExp;
108
+ readonly DEFAULT_HASH_ALGORITHM: "sha256";
109
+ readonly SUPPORTED_HASH_ALGORITHMS: readonly ["sha256", "sha512"];
110
+ readonly MANIFEST_CACHE_TTL: 300;
111
+ readonly FILE_CACHE_TTL: 31536000;
112
+ readonly UPDATE_CHECK_INTERVAL_HOURS: 24;
113
+ readonly MAX_RETRIES: 5;
114
+ readonly RETRY_DELAYS_MS: readonly [1000, 2000, 4000, 8000, 16000];
115
+ readonly MIN_FREE_SPACE_MULTIPLIER: 2;
116
+ };
117
+ /**
118
+ * Helper to generate filename for a database version
119
+ * Examples:
120
+ * getBuiltInDbFilename("20250118a", true) -> "duiduidui-20250118a.sqlite.gz"
121
+ * getBuiltInDbFilename("20250118a", false) -> "duiduidui-20250118a.sqlite"
122
+ */
123
+ export declare function getBuiltInDbFilename(version: DatabaseVersion, compressed?: boolean): string;
124
+ export {};
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ // Database version and download management types
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.BUILTIN_DB_CONSTANTS = exports.DatabaseVersionModel = exports.Checksum = void 0;
5
+ exports.getBuiltInDbFilename = getBuiltInDbFilename;
6
+ var DatabaseVersionBrand;
7
+ (function (DatabaseVersionBrand) {
8
+ })(DatabaseVersionBrand || (DatabaseVersionBrand = {}));
9
+ /**
10
+ * Checksum utilities for validating downloaded files
11
+ */
12
+ class Checksum {
13
+ /**
14
+ * Parse a checksum string into algorithm and hash
15
+ * Format: "algorithm:hash" (e.g., "sha256:abc123...")
16
+ */
17
+ static parse(checksum) {
18
+ const match = checksum.match(/^(\w+):([a-f0-9]+)$/);
19
+ if (!match)
20
+ return null;
21
+ return { algorithm: match[1], hash: match[2] };
22
+ }
23
+ /**
24
+ * Validate checksum format
25
+ */
26
+ static isValid(checksum) {
27
+ return this.parse(checksum) !== null;
28
+ }
29
+ /**
30
+ * Format a checksum (ensures consistent format)
31
+ */
32
+ static format(algorithm, hash) {
33
+ return `${algorithm}:${hash}`;
34
+ }
35
+ }
36
+ exports.Checksum = Checksum;
37
+ /**
38
+ * Database version utilities
39
+ */
40
+ class DatabaseVersionModel {
41
+ /**
42
+ * Validate and create a branded DatabaseVersion from a string
43
+ * Throws if the version format is invalid
44
+ */
45
+ static from(version) {
46
+ if (!this.isValid(version)) {
47
+ throw new Error(`Invalid database version format: ${version}. Expected YYYYMMDDx (e.g., "20250118a")`);
48
+ }
49
+ return version;
50
+ }
51
+ /**
52
+ * Validate YYYYMMDDx format (where x is a lowercase letter a-z)
53
+ * Examples: "20250118a", "20250118b", "20250125a"
54
+ */
55
+ static isValid(version) {
56
+ return /^\d{8}[a-z]$/.test(version);
57
+ }
58
+ /**
59
+ * Compare two version strings
60
+ * Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
61
+ */
62
+ static compare(v1, v2) {
63
+ return v1.localeCompare(v2);
64
+ }
65
+ /**
66
+ * Check if v1 is newer than v2
67
+ */
68
+ static isNewer(v1, v2) {
69
+ return this.compare(v1, v2) > 0;
70
+ }
71
+ /**
72
+ * Generate next version in sequence for the same day
73
+ * Example: "20250118a" -> "20250118b"
74
+ * Returns null if already at 'z'
75
+ */
76
+ static nextInDay(version) {
77
+ const versionStr = version;
78
+ const letter = versionStr.charAt(8);
79
+ if (letter === 'z')
80
+ return null;
81
+ const nextLetter = String.fromCharCode(letter.charCodeAt(0) + 1);
82
+ return (versionStr.slice(0, 8) + nextLetter);
83
+ }
84
+ /**
85
+ * Extract CompactDate from version string (ignores letter suffix)
86
+ * Example: "20250118a" -> "20250118"
87
+ */
88
+ static toCompactDate(version) {
89
+ return version.slice(0, 8);
90
+ }
91
+ /**
92
+ * Get the letter suffix from a version string
93
+ * Example: "20250118a" -> "a"
94
+ */
95
+ static getLetterSuffix(version) {
96
+ return version.charAt(8);
97
+ }
98
+ }
99
+ exports.DatabaseVersionModel = DatabaseVersionModel;
100
+ /**
101
+ * Constants for built-in database management
102
+ */
103
+ exports.BUILTIN_DB_CONSTANTS = {
104
+ // File naming
105
+ FILE_PREFIX: 'duiduidui-',
106
+ FILE_EXTENSION: '.sqlite',
107
+ COMPRESSED_EXTENSION: '.sqlite.gz',
108
+ VERSION_MANIFEST_FILENAME: 'manifest.json',
109
+ // Version format
110
+ VERSION_FORMAT: 'YYYYMMDDx', // x is a lowercase letter a-z
111
+ VERSION_REGEX: /^\d{8}[a-z]$/,
112
+ // Checksums
113
+ DEFAULT_HASH_ALGORITHM: 'sha256',
114
+ SUPPORTED_HASH_ALGORITHMS: ['sha256', 'sha512'],
115
+ // Cache TTLs (seconds)
116
+ MANIFEST_CACHE_TTL: 300, // 5 minutes
117
+ FILE_CACHE_TTL: 31536000, // 1 year
118
+ // Update checking
119
+ UPDATE_CHECK_INTERVAL_HOURS: 24,
120
+ // Download retry
121
+ MAX_RETRIES: 5,
122
+ RETRY_DELAYS_MS: [1000, 2000, 4000, 8000, 16000],
123
+ // Storage
124
+ MIN_FREE_SPACE_MULTIPLIER: 2, // Need 2x compressed size free
125
+ };
126
+ /**
127
+ * Helper to generate filename for a database version
128
+ * Examples:
129
+ * getBuiltInDbFilename("20250118a", true) -> "duiduidui-20250118a.sqlite.gz"
130
+ * getBuiltInDbFilename("20250118a", false) -> "duiduidui-20250118a.sqlite"
131
+ */
132
+ function getBuiltInDbFilename(version, compressed = true) {
133
+ const base = `${exports.BUILTIN_DB_CONSTANTS.FILE_PREFIX}${version}${exports.BUILTIN_DB_CONSTANTS.FILE_EXTENSION}`;
134
+ return compressed ? `${base}.gz` : base;
135
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './AvatarUri';
2
+ export * from './Database';
2
3
  export * from './Encryption';
3
4
  export * from './Logging';
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  };
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  __exportStar(require("./AvatarUri"), exports);
19
+ __exportStar(require("./Database"), exports);
19
20
  __exportStar(require("./Encryption"), exports);
20
21
  __exportStar(require("./Logging"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaxpir/duiduidui-models",
3
- "version": "1.8.2",
3
+ "version": "1.9.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/shaxpir/duiduidui-models"