strata-storage 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/Readme.md +113 -0
  2. package/android/src/main/java/com/strata/storage/EncryptedStorage.java +65 -0
  3. package/android/src/main/java/com/strata/storage/SQLiteStorage.java +147 -0
  4. package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +74 -0
  5. package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +256 -0
  6. package/dist/adapters/capacitor/FilesystemAdapter.d.ts +46 -0
  7. package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +1 -0
  8. package/dist/adapters/capacitor/FilesystemAdapter.js +162 -0
  9. package/dist/adapters/capacitor/PreferencesAdapter.d.ts +46 -0
  10. package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +1 -0
  11. package/dist/adapters/capacitor/PreferencesAdapter.js +162 -0
  12. package/dist/adapters/capacitor/SecureAdapter.d.ts +69 -0
  13. package/dist/adapters/capacitor/SecureAdapter.d.ts.map +1 -0
  14. package/dist/adapters/capacitor/SecureAdapter.js +214 -0
  15. package/dist/adapters/capacitor/SqliteAdapter.d.ts +68 -0
  16. package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +1 -0
  17. package/dist/adapters/capacitor/SqliteAdapter.js +277 -0
  18. package/dist/adapters/capacitor/index.d.ts +9 -0
  19. package/dist/adapters/capacitor/index.d.ts.map +1 -0
  20. package/dist/adapters/capacitor/index.js +8 -0
  21. package/dist/adapters/web/CacheAdapter.d.ts +91 -0
  22. package/dist/adapters/web/CacheAdapter.d.ts.map +1 -0
  23. package/dist/adapters/web/CacheAdapter.js +291 -0
  24. package/dist/adapters/web/CookieAdapter.d.ts +77 -0
  25. package/dist/adapters/web/CookieAdapter.d.ts.map +1 -0
  26. package/dist/adapters/web/CookieAdapter.js +260 -0
  27. package/dist/adapters/web/IndexedDBAdapter.d.ts +78 -0
  28. package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -0
  29. package/dist/adapters/web/IndexedDBAdapter.js +371 -0
  30. package/dist/adapters/web/LocalStorageAdapter.d.ts +63 -0
  31. package/dist/adapters/web/LocalStorageAdapter.d.ts.map +1 -0
  32. package/dist/adapters/web/LocalStorageAdapter.js +238 -0
  33. package/dist/adapters/web/MemoryAdapter.d.ts +69 -0
  34. package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -0
  35. package/dist/adapters/web/MemoryAdapter.js +165 -0
  36. package/dist/adapters/web/SessionStorageAdapter.d.ts +53 -0
  37. package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -0
  38. package/dist/adapters/web/SessionStorageAdapter.js +180 -0
  39. package/dist/adapters/web/index.d.ts +10 -0
  40. package/dist/adapters/web/index.d.ts.map +1 -0
  41. package/dist/adapters/web/index.js +9 -0
  42. package/dist/core/AdapterRegistry.d.ts +52 -0
  43. package/dist/core/AdapterRegistry.d.ts.map +1 -0
  44. package/dist/core/AdapterRegistry.js +102 -0
  45. package/dist/core/BaseAdapter.d.ts +79 -0
  46. package/dist/core/BaseAdapter.d.ts.map +1 -0
  47. package/dist/core/BaseAdapter.js +197 -0
  48. package/dist/core/StorageStrategy.d.ts +55 -0
  49. package/dist/core/StorageStrategy.d.ts.map +1 -0
  50. package/dist/core/StorageStrategy.js +199 -0
  51. package/dist/core/Strata.d.ts +122 -0
  52. package/dist/core/Strata.d.ts.map +1 -0
  53. package/dist/core/Strata.js +568 -0
  54. package/dist/features/compression.d.ts +65 -0
  55. package/dist/features/compression.d.ts.map +1 -0
  56. package/dist/features/compression.js +205 -0
  57. package/dist/features/encryption.d.ts +68 -0
  58. package/dist/features/encryption.d.ts.map +1 -0
  59. package/dist/features/encryption.js +172 -0
  60. package/dist/features/migration.d.ts +17 -0
  61. package/dist/features/migration.d.ts.map +1 -0
  62. package/dist/features/migration.js +43 -0
  63. package/dist/features/query.d.ts +75 -0
  64. package/dist/features/query.d.ts.map +1 -0
  65. package/dist/features/query.js +305 -0
  66. package/dist/features/sync.d.ts +87 -0
  67. package/dist/features/sync.d.ts.map +1 -0
  68. package/dist/features/sync.js +233 -0
  69. package/dist/features/ttl.d.ts +124 -0
  70. package/dist/features/ttl.d.ts.map +1 -0
  71. package/dist/features/ttl.js +236 -0
  72. package/dist/index.d.ts +44 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +46 -0
  75. package/dist/package.json +60 -0
  76. package/dist/plugin/definitions.d.ts +219 -0
  77. package/dist/plugin/definitions.d.ts.map +1 -0
  78. package/dist/plugin/definitions.js +5 -0
  79. package/dist/plugin/index.d.ts +8 -0
  80. package/dist/plugin/index.d.ts.map +1 -0
  81. package/dist/plugin/index.js +27 -0
  82. package/dist/plugin/web.d.ts +24 -0
  83. package/dist/plugin/web.d.ts.map +1 -0
  84. package/dist/plugin/web.js +35 -0
  85. package/dist/types/index.d.ts +558 -0
  86. package/dist/types/index.d.ts.map +1 -0
  87. package/dist/types/index.js +14 -0
  88. package/dist/utils/errors.d.ts +92 -0
  89. package/dist/utils/errors.d.ts.map +1 -0
  90. package/dist/utils/errors.js +153 -0
  91. package/dist/utils/index.d.ts +105 -0
  92. package/dist/utils/index.d.ts.map +1 -0
  93. package/dist/utils/index.js +329 -0
  94. package/ios/Plugin/KeychainStorage.swift +87 -0
  95. package/ios/Plugin/SQLiteStorage.swift +167 -0
  96. package/ios/Plugin/StrataStoragePlugin.swift +204 -0
  97. package/ios/Plugin/UserDefaultsStorage.swift +44 -0
  98. package/package.json +126 -0
  99. package/scripts/build.js +52 -0
  100. package/scripts/cli.js +60 -0
  101. package/scripts/configure.js +444 -0
  102. package/scripts/postinstall.js +33 -0
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Compression Feature - Pure JavaScript LZ-string implementation
3
+ * Zero-dependency compression/decompression for storage values
4
+ */
5
+ import { CompressionError } from '@/utils/errors';
6
+ /**
7
+ * Compression manager using pure JavaScript LZ-string algorithm
8
+ */
9
+ export class CompressionManager {
10
+ config;
11
+ constructor(config = {}) {
12
+ this.config = {
13
+ algorithm: config.algorithm || 'lz',
14
+ threshold: config.threshold || 1024, // 1KB default threshold
15
+ level: config.level || 6,
16
+ };
17
+ }
18
+ /**
19
+ * Compress data using LZ-string algorithm
20
+ */
21
+ async compress(data) {
22
+ try {
23
+ const jsonStr = JSON.stringify(data);
24
+ const originalSize = new Blob([jsonStr]).size;
25
+ // Skip compression if below threshold
26
+ if (originalSize < this.config.threshold) {
27
+ return data;
28
+ }
29
+ // Compress using LZ algorithm
30
+ const compressed = this.lzCompress(jsonStr);
31
+ const compressedSize = new Blob([compressed]).size;
32
+ // Only use compression if it reduces size
33
+ if (compressedSize >= originalSize) {
34
+ return data;
35
+ }
36
+ return {
37
+ data: compressed,
38
+ algorithm: this.config.algorithm,
39
+ originalSize,
40
+ compressedSize,
41
+ };
42
+ }
43
+ catch (error) {
44
+ throw new CompressionError(`Compression failed: ${error}`);
45
+ }
46
+ }
47
+ /**
48
+ * Decompress data
49
+ */
50
+ async decompress(compressedData) {
51
+ try {
52
+ if (!this.isCompressedData(compressedData)) {
53
+ return compressedData;
54
+ }
55
+ const decompressed = this.lzDecompress(compressedData.data);
56
+ return JSON.parse(decompressed);
57
+ }
58
+ catch (error) {
59
+ throw new CompressionError(`Decompression failed: ${error}`);
60
+ }
61
+ }
62
+ /**
63
+ * Check if data is compressed
64
+ */
65
+ isCompressedData(data) {
66
+ return (typeof data === 'object' &&
67
+ data !== null &&
68
+ 'data' in data &&
69
+ 'algorithm' in data &&
70
+ 'originalSize' in data &&
71
+ 'compressedSize' in data);
72
+ }
73
+ /**
74
+ * LZ-string compression implementation
75
+ */
76
+ lzCompress(uncompressed) {
77
+ if (uncompressed == null)
78
+ return '';
79
+ const context = new Map();
80
+ const out = [];
81
+ let currentChar;
82
+ let phrase = uncompressed.charAt(0);
83
+ let code = 256;
84
+ for (let i = 1; i < uncompressed.length; i++) {
85
+ currentChar = uncompressed.charAt(i);
86
+ if (context.has(phrase + currentChar)) {
87
+ phrase += currentChar;
88
+ }
89
+ else {
90
+ if (phrase.length > 1) {
91
+ out.push(String.fromCharCode(context.get(phrase)));
92
+ }
93
+ else {
94
+ out.push(phrase);
95
+ }
96
+ context.set(phrase + currentChar, code);
97
+ code++;
98
+ phrase = currentChar;
99
+ }
100
+ }
101
+ if (phrase.length > 1) {
102
+ out.push(String.fromCharCode(context.get(phrase)));
103
+ }
104
+ else {
105
+ out.push(phrase);
106
+ }
107
+ return this.encodeToBase64(out.join(''));
108
+ }
109
+ /**
110
+ * LZ-string decompression implementation
111
+ */
112
+ lzDecompress(compressed) {
113
+ if (compressed == null)
114
+ return '';
115
+ if (compressed === '')
116
+ return '';
117
+ const decoded = this.decodeFromBase64(compressed);
118
+ const dictionary = new Map();
119
+ let currentChar = decoded.charAt(0);
120
+ let oldPhrase = currentChar;
121
+ const out = [currentChar];
122
+ let code = 256;
123
+ let phrase;
124
+ for (let i = 1; i < decoded.length; i++) {
125
+ const currentCode = decoded.charCodeAt(i);
126
+ if (currentCode < 256) {
127
+ phrase = decoded.charAt(i);
128
+ }
129
+ else {
130
+ phrase = dictionary.get(currentCode) || oldPhrase + currentChar;
131
+ }
132
+ out.push(phrase);
133
+ currentChar = phrase.charAt(0);
134
+ dictionary.set(code, oldPhrase + currentChar);
135
+ code++;
136
+ oldPhrase = phrase;
137
+ }
138
+ return out.join('');
139
+ }
140
+ /**
141
+ * Base64 encoding for compressed data
142
+ */
143
+ encodeToBase64(input) {
144
+ if (typeof btoa !== 'undefined') {
145
+ // Browser environment
146
+ return btoa(unescape(encodeURIComponent(input)));
147
+ }
148
+ // Pure JS implementation for Node.js or other environments
149
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
150
+ let result = '';
151
+ let i = 0;
152
+ while (i < input.length) {
153
+ const a = input.charCodeAt(i++);
154
+ const b = i < input.length ? input.charCodeAt(i++) : 0;
155
+ const c = i < input.length ? input.charCodeAt(i++) : 0;
156
+ const bitmap = (a << 16) | (b << 8) | c;
157
+ result += chars.charAt((bitmap >> 18) & 63);
158
+ result += chars.charAt((bitmap >> 12) & 63);
159
+ result += i - 2 < input.length ? chars.charAt((bitmap >> 6) & 63) : '=';
160
+ result += i - 1 < input.length ? chars.charAt(bitmap & 63) : '=';
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * Base64 decoding for compressed data
166
+ */
167
+ decodeFromBase64(input) {
168
+ if (typeof atob !== 'undefined') {
169
+ // Browser environment
170
+ return decodeURIComponent(escape(atob(input)));
171
+ }
172
+ // Pure JS implementation
173
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
174
+ let result = '';
175
+ let i = 0;
176
+ input = input.replace(/[^A-Za-z0-9+/]/g, '');
177
+ while (i < input.length) {
178
+ const encoded1 = chars.indexOf(input.charAt(i++));
179
+ const encoded2 = chars.indexOf(input.charAt(i++));
180
+ const encoded3 = chars.indexOf(input.charAt(i++));
181
+ const encoded4 = chars.indexOf(input.charAt(i++));
182
+ const bitmap = (encoded1 << 18) | (encoded2 << 12) | (encoded3 << 6) | encoded4;
183
+ result += String.fromCharCode((bitmap >> 16) & 255);
184
+ if (encoded3 !== 64)
185
+ result += String.fromCharCode((bitmap >> 8) & 255);
186
+ if (encoded4 !== 64)
187
+ result += String.fromCharCode(bitmap & 255);
188
+ }
189
+ return result;
190
+ }
191
+ /**
192
+ * Get compression ratio
193
+ */
194
+ getCompressionRatio(compressedData) {
195
+ return compressedData.compressedSize / compressedData.originalSize;
196
+ }
197
+ /**
198
+ * Get savings percentage
199
+ */
200
+ getSavingsPercentage(compressedData) {
201
+ return (((compressedData.originalSize - compressedData.compressedSize) /
202
+ compressedData.originalSize) *
203
+ 100);
204
+ }
205
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Encryption Feature - Web Crypto API implementation
3
+ * Zero-dependency encryption/decryption for storage values
4
+ */
5
+ /**
6
+ * Encryption configuration
7
+ */
8
+ export interface EncryptionConfig {
9
+ algorithm?: 'AES-GCM' | 'AES-CBC';
10
+ keyLength?: 128 | 192 | 256;
11
+ iterations?: number;
12
+ saltLength?: number;
13
+ }
14
+ /**
15
+ * Encrypted data structure
16
+ */
17
+ export interface EncryptedData {
18
+ data: string;
19
+ salt: string;
20
+ iv: string;
21
+ algorithm: string;
22
+ iterations: number;
23
+ }
24
+ /**
25
+ * Encryption manager using Web Crypto API
26
+ */
27
+ export declare class EncryptionManager {
28
+ private config;
29
+ private keyCache;
30
+ constructor(config?: EncryptionConfig);
31
+ /**
32
+ * Check if encryption is available
33
+ */
34
+ isAvailable(): boolean;
35
+ /**
36
+ * Encrypt data
37
+ */
38
+ encrypt(data: unknown, password: string): Promise<EncryptedData>;
39
+ /**
40
+ * Decrypt data
41
+ */
42
+ decrypt<T = unknown>(encryptedData: EncryptedData, password: string): Promise<T>;
43
+ /**
44
+ * Derive encryption key from password
45
+ */
46
+ private deriveKey;
47
+ /**
48
+ * Convert ArrayBuffer to base64
49
+ */
50
+ private bufferToBase64;
51
+ /**
52
+ * Convert base64 to ArrayBuffer
53
+ */
54
+ private base64ToBuffer;
55
+ /**
56
+ * Clear key cache
57
+ */
58
+ clearCache(): void;
59
+ /**
60
+ * Generate a secure random password
61
+ */
62
+ generatePassword(length?: number): string;
63
+ /**
64
+ * Hash data using SHA-256
65
+ */
66
+ hash(data: string): Promise<string>;
67
+ }
68
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../src/features/encryption.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,QAAQ,CAAqC;gBAEzC,MAAM,GAAE,gBAAqB;IASzC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAyCtE;;OAEG;IACG,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAiCtF;;OAEG;YACW,SAAS;IA0CvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,gBAAgB,CAAC,MAAM,GAAE,MAAW,GAAG,MAAM;IAc7C;;OAEG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAU1C"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Encryption Feature - Web Crypto API implementation
3
+ * Zero-dependency encryption/decryption for storage values
4
+ */
5
+ import { EncryptionError } from '@/utils/errors';
6
+ /**
7
+ * Encryption manager using Web Crypto API
8
+ */
9
+ export class EncryptionManager {
10
+ config;
11
+ keyCache = new Map();
12
+ constructor(config = {}) {
13
+ this.config = {
14
+ algorithm: config.algorithm || 'AES-GCM',
15
+ keyLength: config.keyLength || 256,
16
+ iterations: config.iterations || 100000,
17
+ saltLength: config.saltLength || 16,
18
+ };
19
+ }
20
+ /**
21
+ * Check if encryption is available
22
+ */
23
+ isAvailable() {
24
+ return typeof window !== 'undefined' && window.crypto && window.crypto.subtle !== undefined;
25
+ }
26
+ /**
27
+ * Encrypt data
28
+ */
29
+ async encrypt(data, password) {
30
+ if (!this.isAvailable()) {
31
+ throw new EncryptionError('Web Crypto API not available');
32
+ }
33
+ try {
34
+ // Convert data to string
35
+ const dataStr = JSON.stringify(data);
36
+ const encoder = new TextEncoder();
37
+ const dataBuffer = encoder.encode(dataStr);
38
+ // Generate salt and IV
39
+ const salt = crypto.getRandomValues(new Uint8Array(this.config.saltLength));
40
+ const iv = crypto.getRandomValues(new Uint8Array(12)); // 12 bytes for GCM
41
+ // Derive key from password
42
+ const key = await this.deriveKey(password, salt);
43
+ // Encrypt data
44
+ const encryptedBuffer = await crypto.subtle.encrypt({
45
+ name: this.config.algorithm,
46
+ iv: iv,
47
+ }, key, dataBuffer);
48
+ // Convert to base64 for storage
49
+ return {
50
+ data: this.bufferToBase64(encryptedBuffer),
51
+ salt: this.bufferToBase64(salt),
52
+ iv: this.bufferToBase64(iv),
53
+ algorithm: this.config.algorithm,
54
+ iterations: this.config.iterations,
55
+ };
56
+ }
57
+ catch (error) {
58
+ throw new EncryptionError(`Encryption failed: ${error}`);
59
+ }
60
+ }
61
+ /**
62
+ * Decrypt data
63
+ */
64
+ async decrypt(encryptedData, password) {
65
+ if (!this.isAvailable()) {
66
+ throw new EncryptionError('Web Crypto API not available');
67
+ }
68
+ try {
69
+ // Convert from base64
70
+ const dataBuffer = this.base64ToBuffer(encryptedData.data);
71
+ const salt = this.base64ToBuffer(encryptedData.salt);
72
+ const iv = this.base64ToBuffer(encryptedData.iv);
73
+ // Derive key from password
74
+ const key = await this.deriveKey(password, new Uint8Array(salt), encryptedData.iterations);
75
+ // Decrypt data
76
+ const decryptedBuffer = await crypto.subtle.decrypt({
77
+ name: encryptedData.algorithm,
78
+ iv: iv,
79
+ }, key, dataBuffer);
80
+ // Convert back to original data
81
+ const decoder = new TextDecoder();
82
+ const decryptedStr = decoder.decode(decryptedBuffer);
83
+ return JSON.parse(decryptedStr);
84
+ }
85
+ catch (error) {
86
+ throw new EncryptionError(`Decryption failed: ${error}`);
87
+ }
88
+ }
89
+ /**
90
+ * Derive encryption key from password
91
+ */
92
+ async deriveKey(password, salt, iterations = this.config.iterations) {
93
+ // Check cache
94
+ const cacheKey = `${password}-${this.bufferToBase64(salt)}-${iterations}`;
95
+ if (this.keyCache.has(cacheKey)) {
96
+ return this.keyCache.get(cacheKey);
97
+ }
98
+ // Import password as key material
99
+ const encoder = new TextEncoder();
100
+ const passwordBuffer = encoder.encode(password);
101
+ const keyMaterial = await crypto.subtle.importKey('raw', passwordBuffer, 'PBKDF2', false, [
102
+ 'deriveBits',
103
+ 'deriveKey',
104
+ ]);
105
+ // Derive key using PBKDF2
106
+ const key = await crypto.subtle.deriveKey({
107
+ name: 'PBKDF2',
108
+ salt: salt,
109
+ iterations: iterations,
110
+ hash: 'SHA-256',
111
+ }, keyMaterial, {
112
+ name: this.config.algorithm,
113
+ length: this.config.keyLength,
114
+ }, false, ['encrypt', 'decrypt']);
115
+ // Cache the key
116
+ this.keyCache.set(cacheKey, key);
117
+ return key;
118
+ }
119
+ /**
120
+ * Convert ArrayBuffer to base64
121
+ */
122
+ bufferToBase64(buffer) {
123
+ const bytes = new Uint8Array(buffer);
124
+ let binary = '';
125
+ for (let i = 0; i < bytes.byteLength; i++) {
126
+ binary += String.fromCharCode(bytes[i]);
127
+ }
128
+ return btoa(binary);
129
+ }
130
+ /**
131
+ * Convert base64 to ArrayBuffer
132
+ */
133
+ base64ToBuffer(base64) {
134
+ const binary = atob(base64);
135
+ const bytes = new Uint8Array(binary.length);
136
+ for (let i = 0; i < binary.length; i++) {
137
+ bytes[i] = binary.charCodeAt(i);
138
+ }
139
+ return bytes.buffer;
140
+ }
141
+ /**
142
+ * Clear key cache
143
+ */
144
+ clearCache() {
145
+ this.keyCache.clear();
146
+ }
147
+ /**
148
+ * Generate a secure random password
149
+ */
150
+ generatePassword(length = 32) {
151
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?';
152
+ const array = new Uint8Array(length);
153
+ crypto.getRandomValues(array);
154
+ let password = '';
155
+ for (let i = 0; i < length; i++) {
156
+ password += chars[array[i] % chars.length];
157
+ }
158
+ return password;
159
+ }
160
+ /**
161
+ * Hash data using SHA-256
162
+ */
163
+ async hash(data) {
164
+ if (!this.isAvailable()) {
165
+ throw new EncryptionError('Web Crypto API not available');
166
+ }
167
+ const encoder = new TextEncoder();
168
+ const dataBuffer = encoder.encode(data);
169
+ const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
170
+ return this.bufferToBase64(hashBuffer);
171
+ }
172
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Migration utilities for storage upgrades
3
+ */
4
+ import type { StorageAdapter } from '@/types';
5
+ export interface Migration {
6
+ version: number;
7
+ up: (adapter: StorageAdapter) => Promise<void>;
8
+ down?: (adapter: StorageAdapter) => Promise<void>;
9
+ }
10
+ export declare class MigrationManager {
11
+ private migrations;
12
+ register(migration: Migration): void;
13
+ migrate(adapter: StorageAdapter, targetVersion: number): Promise<void>;
14
+ private getCurrentVersion;
15
+ private setVersion;
16
+ }
17
+ //# sourceMappingURL=migration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/features/migration.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAmB;IAErC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAK9B,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YA0B9D,iBAAiB;YAKjB,UAAU;CAOzB"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Migration utilities for storage upgrades
3
+ */
4
+ export class MigrationManager {
5
+ migrations = [];
6
+ register(migration) {
7
+ this.migrations.push(migration);
8
+ this.migrations.sort((a, b) => a.version - b.version);
9
+ }
10
+ async migrate(adapter, targetVersion) {
11
+ const currentVersion = await this.getCurrentVersion(adapter);
12
+ if (currentVersion === targetVersion)
13
+ return;
14
+ const migrationsToRun = this.migrations.filter((m) => currentVersion < targetVersion
15
+ ? m.version > currentVersion && m.version <= targetVersion
16
+ : m.version <= currentVersion && m.version > targetVersion);
17
+ if (currentVersion < targetVersion) {
18
+ for (const migration of migrationsToRun) {
19
+ await migration.up(adapter);
20
+ await this.setVersion(adapter, migration.version);
21
+ }
22
+ }
23
+ else {
24
+ for (const migration of migrationsToRun.reverse()) {
25
+ if (migration.down) {
26
+ await migration.down(adapter);
27
+ }
28
+ await this.setVersion(adapter, migration.version - 1);
29
+ }
30
+ }
31
+ }
32
+ async getCurrentVersion(adapter) {
33
+ const versionData = await adapter.get('__strata_version__');
34
+ return versionData?.value || 0;
35
+ }
36
+ async setVersion(adapter, version) {
37
+ await adapter.set('__strata_version__', {
38
+ value: version,
39
+ created: Date.now(),
40
+ updated: Date.now(),
41
+ });
42
+ }
43
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Query Engine Feature
3
+ * Zero-dependency implementation of MongoDB-like query operators
4
+ */
5
+ import type { QueryCondition } from '@/types';
6
+ /**
7
+ * Query engine for advanced data filtering
8
+ */
9
+ export declare class QueryEngine {
10
+ /**
11
+ * Check if a value matches a query condition
12
+ */
13
+ matches(value: unknown, condition: QueryCondition): boolean;
14
+ /**
15
+ * Check if object has query operators
16
+ */
17
+ private hasOperators;
18
+ /**
19
+ * Match value against operators
20
+ */
21
+ private matchesOperators;
22
+ /**
23
+ * Match single operator
24
+ */
25
+ private matchesOperator;
26
+ /**
27
+ * Match object against condition
28
+ */
29
+ private matchesObject;
30
+ /**
31
+ * Get nested value from object using dot notation
32
+ */
33
+ private getNestedValue;
34
+ /**
35
+ * Check equality with proper type handling
36
+ */
37
+ private equals;
38
+ /**
39
+ * Compare values
40
+ */
41
+ private compare;
42
+ /**
43
+ * Match regex pattern
44
+ */
45
+ private matchesRegex;
46
+ /**
47
+ * Get JavaScript type of value
48
+ */
49
+ private getType;
50
+ /**
51
+ * Handle null/undefined matching
52
+ */
53
+ private matchesNull;
54
+ /**
55
+ * Sort array of items by multiple fields
56
+ */
57
+ sort<T>(items: T[], sortBy: Record<string, 1 | -1>): T[];
58
+ /**
59
+ * Project/transform objects based on projection spec
60
+ */
61
+ project<T>(item: T, projection: Record<string, 0 | 1 | boolean>): Partial<T>;
62
+ /**
63
+ * Set nested value in object using dot notation
64
+ */
65
+ private setNestedValue;
66
+ /**
67
+ * Delete nested value from object using dot notation
68
+ */
69
+ private deleteNestedValue;
70
+ }
71
+ /**
72
+ * Create a query engine instance
73
+ */
74
+ export declare function createQueryEngine(): QueryEngine;
75
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/features/query.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,SAAS,CAAC;AAE9D;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO;IAwB3D;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAqDvB;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAmBtB;;OAEG;IACH,OAAO,CAAC,MAAM;IA+Bd;;OAEG;IACH,OAAO,CAAC,OAAO;IAyBf;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,OAAO,CAAC,OAAO;IASf;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;IAoBxD;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA2B5E;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAc1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,CAE/C"}