@fgv/ts-web-extras 5.0.2 → 5.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 (208) hide show
  1. package/.rush/temp/81e0881271ff236956b2f52e8ca99da6574c6e1e.tar.log +223 -0
  2. package/.rush/temp/chunked-rush-logs/ts-web-extras.build.chunks.jsonl +35 -25
  3. package/.rush/temp/operation/build/all.log +35 -25
  4. package/.rush/temp/operation/build/log-chunks.jsonl +35 -25
  5. package/.rush/temp/operation/build/state.json +1 -1
  6. package/.rush/temp/shrinkwrap-deps.json +175 -163
  7. package/config/jest.config.json +4 -1
  8. package/config/typedoc.json +6 -0
  9. package/dist/index.js +2 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/packlets/crypto-utils/browserCryptoProvider.js +254 -0
  12. package/dist/packlets/crypto-utils/browserCryptoProvider.js.map +1 -0
  13. package/dist/packlets/crypto-utils/browserHashProvider.js.map +1 -0
  14. package/dist/packlets/{crypto → crypto-utils}/index.js +1 -0
  15. package/dist/packlets/crypto-utils/index.js.map +1 -0
  16. package/dist/packlets/file-api-types/index.js +27 -3
  17. package/dist/packlets/file-api-types/index.js.map +1 -1
  18. package/dist/packlets/file-tree/directoryHandleStore.js +124 -0
  19. package/dist/packlets/file-tree/directoryHandleStore.js.map +1 -0
  20. package/dist/packlets/file-tree/fileApiTreeAccessors.js +76 -0
  21. package/dist/packlets/file-tree/fileApiTreeAccessors.js.map +1 -1
  22. package/dist/packlets/file-tree/fileSystemAccessTreeAccessors.js +345 -0
  23. package/dist/packlets/file-tree/fileSystemAccessTreeAccessors.js.map +1 -0
  24. package/dist/packlets/file-tree/index.js +3 -0
  25. package/dist/packlets/file-tree/index.js.map +1 -1
  26. package/dist/packlets/file-tree/localStorageTreeAccessors.js +308 -0
  27. package/dist/packlets/file-tree/localStorageTreeAccessors.js.map +1 -0
  28. package/dist/test/mocks/idb-keyval.js +6 -0
  29. package/dist/test/mocks/idb-keyval.js.map +1 -0
  30. package/dist/test/unit/browserHashProvider.test.js +1 -1
  31. package/dist/test/unit/browserHashProvider.test.js.map +1 -1
  32. package/dist/test/unit/directoryHandleStore.test.js +190 -0
  33. package/dist/test/unit/directoryHandleStore.test.js.map +1 -0
  34. package/dist/test/unit/fileApiTypes.test.js +30 -0
  35. package/dist/test/unit/fileApiTypes.test.js.map +1 -1
  36. package/dist/test/unit/fileSystemAccessTreeAccessors.test.js +517 -0
  37. package/dist/test/unit/fileSystemAccessTreeAccessors.test.js.map +1 -0
  38. package/dist/test/unit/localStorageTreeAccessors.test.js +595 -0
  39. package/dist/test/unit/localStorageTreeAccessors.test.js.map +1 -0
  40. package/dist/test/utils/fileSystemAccessMocks.js +271 -0
  41. package/dist/test/utils/fileSystemAccessMocks.js.map +1 -0
  42. package/dist/ts-web-extras.d.ts +460 -1
  43. package/dist/tsdoc-metadata.json +1 -1
  44. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider._constructor_.md +50 -0
  45. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.decrypt.md +104 -0
  46. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.derivekey.md +88 -0
  47. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.encrypt.md +72 -0
  48. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.frombase64.md +56 -0
  49. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.generatekey.md +19 -0
  50. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.generaterandombytes.md +56 -0
  51. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.md +169 -0
  52. package/docs/ts-web-extras.cryptoutils.browsercryptoprovider.tobase64.md +56 -0
  53. package/docs/{ts-web-extras.browserhashprovider.hashparts.md → ts-web-extras.cryptoutils.browserhashprovider.hashparts.md} +2 -2
  54. package/docs/{ts-web-extras.browserhashprovider.hashstring.md → ts-web-extras.cryptoutils.browserhashprovider.hashstring.md} +2 -2
  55. package/docs/{ts-web-extras.browserhashprovider.md → ts-web-extras.cryptoutils.browserhashprovider.md} +4 -4
  56. package/docs/ts-web-extras.cryptoutils.createbrowsercryptoprovider.md +19 -0
  57. package/docs/ts-web-extras.cryptoutils.md +71 -0
  58. package/docs/ts-web-extras.fileapitreeaccessors.createfromlocalstorage.md +74 -0
  59. package/docs/ts-web-extras.fileapitreeaccessors.createpersistent.md +76 -0
  60. package/docs/ts-web-extras.fileapitreeaccessors.md +32 -0
  61. package/docs/ts-web-extras.filesystemaccesstreeaccessors._constructor_.md +114 -0
  62. package/docs/ts-web-extras.filesystemaccesstreeaccessors.fileismutable.md +52 -0
  63. package/docs/ts-web-extras.filesystemaccesstreeaccessors.fromdirectoryhandle.md +72 -0
  64. package/docs/ts-web-extras.filesystemaccesstreeaccessors.getdirtypaths.md +17 -0
  65. package/docs/ts-web-extras.filesystemaccesstreeaccessors.isdirty.md +17 -0
  66. package/docs/ts-web-extras.filesystemaccesstreeaccessors.md +159 -0
  67. package/docs/ts-web-extras.filesystemaccesstreeaccessors.savefilecontents.md +66 -0
  68. package/docs/ts-web-extras.filesystemaccesstreeaccessors.synctodisk.md +17 -0
  69. package/docs/ts-web-extras.ifilesystemaccesstreeparams.autosync.md +13 -0
  70. package/docs/ts-web-extras.ifilesystemaccesstreeparams.md +78 -0
  71. package/docs/ts-web-extras.ifilesystemaccesstreeparams.requirewritepermission.md +13 -0
  72. package/docs/ts-web-extras.ilocalstoragetreeparams.autosync.md +13 -0
  73. package/docs/ts-web-extras.ilocalstoragetreeparams.md +97 -0
  74. package/docs/ts-web-extras.ilocalstoragetreeparams.pathtokeymap.md +13 -0
  75. package/docs/ts-web-extras.ilocalstoragetreeparams.storage.md +13 -0
  76. package/docs/ts-web-extras.localstoragetreeaccessors.fileismutable.md +56 -0
  77. package/docs/ts-web-extras.localstoragetreeaccessors.fromstorage.md +56 -0
  78. package/docs/ts-web-extras.localstoragetreeaccessors.getdirtypaths.md +19 -0
  79. package/docs/ts-web-extras.localstoragetreeaccessors.isdirty.md +19 -0
  80. package/docs/ts-web-extras.localstoragetreeaccessors.md +131 -0
  81. package/docs/ts-web-extras.localstoragetreeaccessors.savefilecontents.md +72 -0
  82. package/docs/ts-web-extras.localstoragetreeaccessors.synctodisk.md +19 -0
  83. package/docs/ts-web-extras.md +50 -4
  84. package/etc/ts-web-extras.api.md +91 -1
  85. package/lib/index.d.ts +2 -1
  86. package/lib/index.d.ts.map +1 -1
  87. package/lib/index.js +25 -2
  88. package/lib/index.js.map +1 -1
  89. package/lib/packlets/crypto-utils/browserCryptoProvider.d.ts +77 -0
  90. package/lib/packlets/crypto-utils/browserCryptoProvider.d.ts.map +1 -0
  91. package/lib/packlets/crypto-utils/browserCryptoProvider.js +259 -0
  92. package/lib/packlets/crypto-utils/browserCryptoProvider.js.map +1 -0
  93. package/lib/packlets/crypto-utils/browserHashProvider.d.ts.map +1 -0
  94. package/lib/packlets/crypto-utils/browserHashProvider.js.map +1 -0
  95. package/lib/packlets/{crypto → crypto-utils}/index.d.ts +1 -0
  96. package/lib/packlets/crypto-utils/index.d.ts.map +1 -0
  97. package/lib/packlets/{crypto → crypto-utils}/index.js +1 -0
  98. package/lib/packlets/crypto-utils/index.js.map +1 -0
  99. package/lib/packlets/file-api-types/index.d.ts.map +1 -1
  100. package/lib/packlets/file-api-types/index.js +27 -3
  101. package/lib/packlets/file-api-types/index.js.map +1 -1
  102. package/lib/packlets/file-tree/directoryHandleStore.d.ts +59 -0
  103. package/lib/packlets/file-tree/directoryHandleStore.d.ts.map +1 -0
  104. package/lib/packlets/file-tree/directoryHandleStore.js +128 -0
  105. package/lib/packlets/file-tree/directoryHandleStore.js.map +1 -0
  106. package/lib/packlets/file-tree/fileApiTreeAccessors.d.ts +57 -0
  107. package/lib/packlets/file-tree/fileApiTreeAccessors.d.ts.map +1 -1
  108. package/lib/packlets/file-tree/fileApiTreeAccessors.js +76 -0
  109. package/lib/packlets/file-tree/fileApiTreeAccessors.js.map +1 -1
  110. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.d.ts +136 -0
  111. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.d.ts.map +1 -0
  112. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.js +349 -0
  113. package/lib/packlets/file-tree/fileSystemAccessTreeAccessors.js.map +1 -0
  114. package/lib/packlets/file-tree/index.d.ts +3 -0
  115. package/lib/packlets/file-tree/index.d.ts.map +1 -1
  116. package/lib/packlets/file-tree/index.js +3 -0
  117. package/lib/packlets/file-tree/index.js.map +1 -1
  118. package/lib/packlets/file-tree/localStorageTreeAccessors.d.ts +129 -0
  119. package/lib/packlets/file-tree/localStorageTreeAccessors.d.ts.map +1 -0
  120. package/lib/packlets/file-tree/localStorageTreeAccessors.js +312 -0
  121. package/lib/packlets/file-tree/localStorageTreeAccessors.js.map +1 -0
  122. package/lib/test/mocks/idb-keyval.d.ts +6 -0
  123. package/lib/test/mocks/idb-keyval.d.ts.map +1 -0
  124. package/lib/test/mocks/idb-keyval.js +9 -0
  125. package/lib/test/mocks/idb-keyval.js.map +1 -0
  126. package/lib/test/unit/browserHashProvider.test.js +21 -21
  127. package/lib/test/unit/browserHashProvider.test.js.map +1 -1
  128. package/lib/test/unit/directoryHandleStore.test.d.ts +2 -0
  129. package/lib/test/unit/directoryHandleStore.test.d.ts.map +1 -0
  130. package/lib/test/unit/directoryHandleStore.test.js +192 -0
  131. package/lib/test/unit/directoryHandleStore.test.js.map +1 -0
  132. package/lib/test/unit/fileApiTypes.test.js +30 -0
  133. package/lib/test/unit/fileApiTypes.test.js.map +1 -1
  134. package/lib/test/unit/fileSystemAccessTreeAccessors.test.d.ts +2 -0
  135. package/lib/test/unit/fileSystemAccessTreeAccessors.test.d.ts.map +1 -0
  136. package/lib/test/unit/fileSystemAccessTreeAccessors.test.js +519 -0
  137. package/lib/test/unit/fileSystemAccessTreeAccessors.test.js.map +1 -0
  138. package/lib/test/unit/localStorageTreeAccessors.test.d.ts +2 -0
  139. package/lib/test/unit/localStorageTreeAccessors.test.d.ts.map +1 -0
  140. package/lib/test/unit/localStorageTreeAccessors.test.js +597 -0
  141. package/lib/test/unit/localStorageTreeAccessors.test.js.map +1 -0
  142. package/lib/test/utils/fileSystemAccessMocks.d.ts +53 -0
  143. package/lib/test/utils/fileSystemAccessMocks.d.ts.map +1 -0
  144. package/lib/test/utils/fileSystemAccessMocks.js +277 -0
  145. package/lib/test/utils/fileSystemAccessMocks.js.map +1 -0
  146. package/package.json +27 -20
  147. package/rush-logs/ts-web-extras.build.cache.log +3 -1
  148. package/rush-logs/ts-web-extras.build.log +35 -25
  149. package/src/index.ts +2 -2
  150. package/src/packlets/crypto-utils/browserCryptoProvider.ts +311 -0
  151. package/src/packlets/{crypto → crypto-utils}/index.ts +1 -0
  152. package/src/packlets/file-api-types/index.ts +24 -3
  153. package/src/packlets/file-tree/directoryHandleStore.ts +136 -0
  154. package/src/packlets/file-tree/fileApiTreeAccessors.ts +90 -0
  155. package/src/packlets/file-tree/fileSystemAccessTreeAccessors.ts +427 -0
  156. package/src/packlets/file-tree/index.ts +3 -0
  157. package/src/packlets/file-tree/localStorageTreeAccessors.ts +377 -0
  158. package/src/test/mocks/idb-keyval.ts +5 -0
  159. package/src/test/unit/browserHashProvider.test.ts +1 -1
  160. package/src/test/unit/directoryHandleStore.test.ts +251 -0
  161. package/src/test/unit/fileApiTypes.test.ts +36 -0
  162. package/src/test/unit/fileSystemAccessTreeAccessors.test.ts +732 -0
  163. package/src/test/unit/localStorageTreeAccessors.test.ts +746 -0
  164. package/src/test/utils/fileSystemAccessMocks.ts +353 -0
  165. package/temp/build/typescript/ts_8nwakTlr.json +1 -0
  166. package/temp/coverage/crypto-utils/browserCryptoProvider.ts.html +1018 -0
  167. package/temp/coverage/{crypto → crypto-utils}/browserHashProvider.ts.html +3 -3
  168. package/temp/coverage/{lcov-report/crypto → crypto-utils}/index.html +21 -6
  169. package/temp/coverage/file-tree/directoryHandleStore.ts.html +493 -0
  170. package/temp/coverage/file-tree/fileApiTreeAccessors.ts.html +276 -6
  171. package/temp/coverage/file-tree/fileSystemAccessTreeAccessors.ts.html +1366 -0
  172. package/temp/coverage/file-tree/index.html +55 -10
  173. package/temp/coverage/file-tree/localStorageTreeAccessors.ts.html +1216 -0
  174. package/temp/coverage/helpers/fileTreeHelpers.ts.html +1 -1
  175. package/temp/coverage/helpers/index.html +1 -1
  176. package/temp/coverage/index.html +15 -15
  177. package/temp/coverage/lcov-report/crypto-utils/browserCryptoProvider.ts.html +1018 -0
  178. package/temp/coverage/lcov-report/{crypto → crypto-utils}/browserHashProvider.ts.html +3 -3
  179. package/temp/coverage/{crypto → lcov-report/crypto-utils}/index.html +21 -6
  180. package/temp/coverage/lcov-report/file-tree/directoryHandleStore.ts.html +493 -0
  181. package/temp/coverage/lcov-report/file-tree/fileApiTreeAccessors.ts.html +276 -6
  182. package/temp/coverage/lcov-report/file-tree/fileSystemAccessTreeAccessors.ts.html +1366 -0
  183. package/temp/coverage/lcov-report/file-tree/index.html +55 -10
  184. package/temp/coverage/lcov-report/file-tree/localStorageTreeAccessors.ts.html +1216 -0
  185. package/temp/coverage/lcov-report/helpers/fileTreeHelpers.ts.html +1 -1
  186. package/temp/coverage/lcov-report/helpers/index.html +1 -1
  187. package/temp/coverage/lcov-report/index.html +15 -15
  188. package/temp/coverage/lcov-report/url-utils/index.html +1 -1
  189. package/temp/coverage/lcov-report/url-utils/urlParams.ts.html +1 -1
  190. package/temp/coverage/lcov.info +2128 -451
  191. package/temp/coverage/url-utils/index.html +1 -1
  192. package/temp/coverage/url-utils/urlParams.ts.html +1 -1
  193. package/temp/test/jest/haste-map-7492f1b44480e0cdd1f220078fb3afd8-c8dd6c3430605adeb2f1cadf4f75e791-8c9336785555d572065b28c111982ba4 +0 -0
  194. package/temp/test/jest/perf-cache-7492f1b44480e0cdd1f220078fb3afd8-da39a3ee5e6b4b0d3255bfef95601890 +1 -1
  195. package/temp/ts-web-extras.api.json +3236 -385
  196. package/temp/ts-web-extras.api.md +91 -1
  197. package/dist/packlets/crypto/browserHashProvider.js.map +0 -1
  198. package/dist/packlets/crypto/index.js.map +0 -1
  199. package/lib/packlets/crypto/browserHashProvider.d.ts.map +0 -1
  200. package/lib/packlets/crypto/browserHashProvider.js.map +0 -1
  201. package/lib/packlets/crypto/index.d.ts.map +0 -1
  202. package/lib/packlets/crypto/index.js.map +0 -1
  203. package/temp/build/typescript/ts_vnCx6LlY.json +0 -1
  204. /package/dist/packlets/{crypto → crypto-utils}/browserHashProvider.js +0 -0
  205. /package/lib/packlets/{crypto → crypto-utils}/browserHashProvider.d.ts +0 -0
  206. /package/lib/packlets/{crypto → crypto-utils}/browserHashProvider.js +0 -0
  207. /package/src/packlets/{crypto → crypto-utils}/browserHashProvider.ts +0 -0
  208. /package/temp/test/jest/jest-transform-cache-7492f1b44480e0cdd1f220078fb3afd8-79ef2876fae7ca75eedb2aa53dc48338/{0e/package_0eb6535f5987849d93ea51ef33a14cf6 → 8d/package_8dcbedef69e4299f0f51fcda8f4f1c8e} +0 -0
@@ -9,15 +9,82 @@
9
9
  * @packageDocumentation
10
10
  */
11
11
 
12
+ import { CryptoUtils as CryptoUtils_2 } from '@fgv/ts-extras';
13
+ import { DetailedResult } from '@fgv/ts-utils';
12
14
  import { FileTree } from '@fgv/ts-json-base';
13
15
  import { Result } from '@fgv/ts-utils';
14
16
 
17
+ /**
18
+ * Browser implementation of `ICryptoProvider` using the Web Crypto API.
19
+ * Uses AES-256-GCM for authenticated encryption.
20
+ *
21
+ * Note: This provider requires a browser environment with Web Crypto API support.
22
+ * In Node.js 15+, Web Crypto is available via globalThis.crypto or require('crypto').webcrypto.
23
+ *
24
+ * @public
25
+ */
26
+ declare class BrowserCryptoProvider implements ICryptoProvider {
27
+ private readonly _crypto;
28
+ /**
29
+ * Creates a new {@link CryptoUtils.BrowserCryptoProvider | BrowserCryptoProvider}.
30
+ * @param cryptoApi - Optional Crypto instance (defaults to globalThis.crypto)
31
+ */
32
+ constructor(cryptoApi?: Crypto);
33
+ /**
34
+ * Encrypts plaintext using AES-256-GCM.
35
+ * @param plaintext - UTF-8 string to encrypt
36
+ * @param key - 32-byte encryption key
37
+ * @returns `Success` with encryption result, or `Failure` with an error.
38
+ */
39
+ encrypt(plaintext: string, key: Uint8Array): Promise<Result<IEncryptionResult>>;
40
+ /**
41
+ * Decrypts ciphertext using AES-256-GCM.
42
+ * @param encryptedData - Encrypted bytes
43
+ * @param key - 32-byte decryption key
44
+ * @param iv - Initialization vector (12 bytes)
45
+ * @param authTag - GCM authentication tag (16 bytes)
46
+ * @returns `Success` with decrypted UTF-8 string, or `Failure` with an error.
47
+ */
48
+ decrypt(encryptedData: Uint8Array, key: Uint8Array, iv: Uint8Array, authTag: Uint8Array): Promise<Result<string>>;
49
+ /**
50
+ * Generates a random 32-byte key suitable for AES-256.
51
+ * @returns Success with generated key, or Failure with error
52
+ */
53
+ generateKey(): Promise<Result<Uint8Array>>;
54
+ /**
55
+ * Derives a key from a password using PBKDF2.
56
+ * @param password - Password string
57
+ * @param salt - Salt bytes (should be at least 16 bytes)
58
+ * @param iterations - Number of iterations (recommend 100000+)
59
+ * @returns Success with derived 32-byte key, or Failure with error
60
+ */
61
+ deriveKey(password: string, salt: Uint8Array, iterations: number): Promise<Result<Uint8Array>>;
62
+ /**
63
+ * Generates cryptographically secure random bytes.
64
+ * @param length - Number of bytes to generate
65
+ * @returns Success with random bytes, or Failure with error
66
+ */
67
+ generateRandomBytes(length: number): Result<Uint8Array>;
68
+ /**
69
+ * Encodes binary data to base64 string.
70
+ * @param data - Binary data to encode
71
+ * @returns Base64-encoded string
72
+ */
73
+ toBase64(data: Uint8Array): string;
74
+ /**
75
+ * Decodes base64 string to binary data.
76
+ * @param base64 - Base64-encoded string
77
+ * @returns Success with decoded bytes, or Failure if invalid base64
78
+ */
79
+ fromBase64(base64: string): Result<Uint8Array>;
80
+ }
81
+
15
82
  /**
16
83
  * Browser-compatible hash provider using the Web Crypto API.
17
84
  * Supports common hash algorithms available in browsers.
18
85
  * @public
19
86
  */
20
- export declare class BrowserHashProvider {
87
+ declare class BrowserHashProvider {
21
88
  /**
22
89
  * Hash a string using the specified algorithm.
23
90
  * @param data - The string to hash
@@ -35,12 +102,83 @@ export declare class BrowserHashProvider {
35
102
  static hashParts(parts: string[], algorithm?: string, separator?: string): Promise<Result<string>>;
36
103
  }
37
104
 
105
+ /**
106
+ * Creates a {@link CryptoUtils.BrowserCryptoProvider | BrowserCryptoProvider} if Web
107
+ * Crypto API is available.
108
+ * @returns `Success` with provider, or `Failure` if not available
109
+ * @public
110
+ */
111
+ declare function createBrowserCryptoProvider(): Result<BrowserCryptoProvider>;
112
+
113
+ declare namespace CryptoUtils {
114
+ export {
115
+ BrowserHashProvider,
116
+ createBrowserCryptoProvider,
117
+ BrowserCryptoProvider
118
+ }
119
+ }
120
+ export { CryptoUtils }
121
+
122
+ /**
123
+ * Default IndexedDB database name for directory handles.
124
+ * @public
125
+ */
126
+ export declare const DEFAULT_DIRECTORY_HANDLE_DB = "chocolate-lab-storage";
127
+
128
+ /**
129
+ * Default IndexedDB store name for directory handles.
130
+ * @public
131
+ */
132
+ export declare const DEFAULT_DIRECTORY_HANDLE_STORE = "directory-handles";
133
+
38
134
  /**
39
135
  * Default initialization parameters for a `FileTree` using {@link FileApiTreeAccessors}.
40
136
  * @public
41
137
  */
42
138
  declare const defaultFileApiTreeInitParams: FileTree.IFileTreeInitParams<string>;
43
139
 
140
+ /**
141
+ * Manages persistence of {@link FileSystemDirectoryHandle} objects in IndexedDB.
142
+ * Keyed by a label (typically the directory name).
143
+ * @public
144
+ */
145
+ export declare class DirectoryHandleStore {
146
+ private readonly _store;
147
+ constructor(dbName?: string, storeName?: string);
148
+ /**
149
+ * Saves a directory handle to IndexedDB under the given label.
150
+ * @param label - Key to store the handle under (typically dirHandle.name)
151
+ * @param handle - The FileSystemDirectoryHandle to persist
152
+ * @returns Success or Failure
153
+ */
154
+ save(label: string, handle: FileSystemDirectoryHandle_2): Promise<Result<void>>;
155
+ /**
156
+ * Retrieves a directory handle by label.
157
+ * @param label - Key to look up
158
+ * @returns Success with handle (or undefined if not found), or Failure on error
159
+ */
160
+ load(label: string): Promise<Result<FileSystemDirectoryHandle_2 | undefined>>;
161
+ /**
162
+ * Removes a directory handle from IndexedDB.
163
+ * @param label - Key to remove
164
+ * @returns Success or Failure
165
+ */
166
+ remove(label: string): Promise<Result<void>>;
167
+ /**
168
+ * Returns all stored labels (keys).
169
+ * @returns Success with array of labels, or Failure
170
+ */
171
+ getAllLabels(): Promise<Result<string[]>>;
172
+ /**
173
+ * Returns all stored handles as label/handle pairs.
174
+ * @returns Success with array of entries, or Failure
175
+ */
176
+ getAll(): Promise<Result<Array<{
177
+ label: string;
178
+ handle: FileSystemDirectoryHandle_2;
179
+ }>>>;
180
+ }
181
+
44
182
  /**
45
183
  * Export data as JSON file using legacy blob download method.
46
184
  * Creates a temporary download link and triggers file download.
@@ -91,6 +229,61 @@ declare function extractFileListMetadata(fileList: FileList): Array<IFileMetadat
91
229
  * @public
92
230
  */
93
231
  export declare class FileApiTreeAccessors<TCT extends string = string> {
232
+ /**
233
+ * Create a persistent FileTree from a File System Access API directory handle.
234
+ * Changes to files can be synced back to disk.
235
+ *
236
+ * @param dirHandle - FileSystemDirectoryHandle to load files from
237
+ * @param params - Optional parameters including autoSync and permission settings
238
+ * @returns Promise resolving to a FileTree with persistence capability
239
+ *
240
+ * @remarks
241
+ * - Only works in browsers supporting File System Access API (Chrome, Edge, Opera)
242
+ * - Requires 'readwrite' permission on the directory handle
243
+ * - Falls back to read-only mode if permissions unavailable (unless requireWritePermission is true)
244
+ *
245
+ * @public
246
+ */
247
+ static createPersistent<TCT extends string = string>(dirHandle: FileSystemDirectoryHandle_2, params?: IFileSystemAccessTreeParams<TCT>): Promise<Result<FileTree.FileTree<TCT>>>;
248
+ /**
249
+ * Create a persistent FileTree from a single File System Access API file handle.
250
+ * The tree contains exactly one file at `/<filename>`.
251
+ * Changes can be synced back to the original file via `syncToDisk()`.
252
+ *
253
+ * @param fileHandle - FileSystemFileHandle to load
254
+ * @param params - Optional parameters including autoSync and permission settings
255
+ * @returns Promise resolving to a FileTree with persistence capability
256
+ * @public
257
+ */
258
+ static createPersistentFromFile<TCT extends string = string>(fileHandle: FileSystemFileHandle_2, params?: IFileSystemAccessTreeParams<TCT>): Promise<Result<FileTree.FileTree<TCT>>>;
259
+ /**
260
+ * Create a persistent FileTree from browser localStorage.
261
+ * Changes to files can be synced back to localStorage.
262
+ *
263
+ * @param params - Configuration including path-to-key mappings and optional autoSync
264
+ * @returns Result containing a FileTree with persistence capability
265
+ *
266
+ * @remarks
267
+ * - Works in all browsers with localStorage support
268
+ * - Maps directory paths to localStorage keys
269
+ * - Each key stores multiple collections as JSON
270
+ * - Files are automatically discovered from storage
271
+ *
272
+ * @example
273
+ * ```typescript
274
+ * const tree = FileApiTreeAccessors.createFromLocalStorage({
275
+ * pathToKeyMap: {
276
+ * '/data/ingredients': 'myapp:ingredients:v1',
277
+ * '/data/fillings': 'myapp:fillings:v1'
278
+ * },
279
+ * mutable: true,
280
+ * autoSync: false
281
+ * });
282
+ * ```
283
+ *
284
+ * @public
285
+ */
286
+ static createFromLocalStorage<TCT extends string = string>(params: ILocalStorageTreeParams<TCT>): Result<FileTree.FileTree<TCT>>;
94
287
  /**
95
288
  * Create FileTree from various file sources using TreeInitializer array.
96
289
  * @param initializers - Array of TreeInitializer objects specifying file sources
@@ -180,6 +373,114 @@ declare function extractFileListMetadata(fileList: FileList): Array<IFileMetadat
180
373
  accept: Record<string, string | string[]>;
181
374
  }
182
375
 
376
+ /**
377
+ * Implementation of `FileTree.IPersistentFileTreeAccessors` that uses the File System Access API
378
+ * to provide persistent file editing in browsers.
379
+ * @public
380
+ */
381
+ export declare class FileSystemAccessTreeAccessors<TCT extends string = string> extends FileTree.InMemoryTreeAccessors<TCT> implements FileTree.IPersistentFileTreeAccessors<TCT> {
382
+ private readonly _handles;
383
+ private readonly _rootDir;
384
+ private readonly _dirtyFiles;
385
+ private readonly _autoSync;
386
+ private readonly _hasWritePermission;
387
+ /**
388
+ * Protected constructor for FileSystemAccessTreeAccessors.
389
+ * @param files - An array of in-memory files to include in the tree.
390
+ * @param rootDir - The root directory handle.
391
+ * @param handles - Map of file paths to their handles.
392
+ * @param params - Optional params for the tree.
393
+ * @param hasWritePermission - Whether write permission was granted.
394
+ */
395
+ protected constructor(files: FileTree.IInMemoryFile<TCT>[], rootDir: FileSystemDirectoryHandle_2, handles: Map<string, FileSystemFileHandle_2>, params: IFileSystemAccessTreeParams<TCT> | undefined, hasWritePermission: boolean);
396
+ /**
397
+ * Creates a new FileSystemAccessTreeAccessors instance from a directory handle.
398
+ * @param dirHandle - The FileSystemDirectoryHandle to load files from.
399
+ * @param params - Optional parameters including autoSync and permission settings.
400
+ * @returns Promise resolving to a FileSystemAccessTreeAccessors instance.
401
+ * @public
402
+ */
403
+ static fromDirectoryHandle<TCT extends string = string>(dirHandle: FileSystemDirectoryHandle_2, params?: IFileSystemAccessTreeParams<TCT>): Promise<Result<FileSystemAccessTreeAccessors<TCT>>>;
404
+ /**
405
+ * Creates a new FileSystemAccessTreeAccessors instance from a single file handle.
406
+ *
407
+ * The resulting tree contains exactly one file at `/<filename>`.
408
+ * `syncToDisk()` writes changes back to the original file via the File System Access API.
409
+ * New file creation is not supported on this tree (no parent directory handle).
410
+ *
411
+ * @param fileHandle - The FileSystemFileHandle to load.
412
+ * @param params - Optional parameters including autoSync and permission settings.
413
+ * @returns Promise resolving to a FileSystemAccessTreeAccessors instance.
414
+ * @public
415
+ */
416
+ static fromFileHandle<TCT extends string = string>(fileHandle: FileSystemFileHandle_2, params?: IFileSystemAccessTreeParams<TCT>): Promise<Result<FileSystemAccessTreeAccessors<TCT>>>;
417
+ /**
418
+ * Check if the directory handle has write permission.
419
+ * @param handle - The directory handle to check.
420
+ * @returns Promise resolving to true if write permission is granted.
421
+ * @internal
422
+ */
423
+ private static _checkWritePermission;
424
+ /**
425
+ * Check if the file handle has write permission.
426
+ * @param handle - The file handle to check.
427
+ * @returns Promise resolving to true if write permission is granted.
428
+ * @internal
429
+ */
430
+ private static _checkFileWritePermission;
431
+ /**
432
+ * Load all files from a directory handle recursively.
433
+ * @param dirHandle - The directory handle to load from.
434
+ * @param basePath - The base path for files.
435
+ * @param params - Optional parameters.
436
+ * @returns Promise resolving to files and handles.
437
+ * @internal
438
+ */
439
+ private static _loadDirectory;
440
+ /**
441
+ * Join path segments.
442
+ * @param base - The base path.
443
+ * @param name - The name to append.
444
+ * @returns The joined path.
445
+ * @internal
446
+ */
447
+ private static _joinPath;
448
+ /**
449
+ * Implements `FileTree.IPersistentFileTreeAccessors.syncToDisk`
450
+ */
451
+ syncToDisk(): Promise<Result<void>>;
452
+ /**
453
+ * Implements `FileTree.IPersistentFileTreeAccessors.isDirty`
454
+ */
455
+ isDirty(): boolean;
456
+ /**
457
+ * Implements `FileTree.IPersistentFileTreeAccessors.getDirtyPaths`
458
+ */
459
+ getDirtyPaths(): string[];
460
+ /**
461
+ * Implements `FileTree.IMutableFileTreeAccessors.saveFileContents`
462
+ */
463
+ saveFileContents(path: string, contents: string): Result<string>;
464
+ /**
465
+ * Implements `FileTree.IMutableFileTreeAccessors.fileIsMutable`
466
+ */
467
+ fileIsMutable(path: string): DetailedResult<boolean, FileTree.SaveDetail>;
468
+ /**
469
+ * Sync a single file to disk.
470
+ * @param path - The path of the file to sync.
471
+ * @returns Promise resolving to success or failure.
472
+ * @internal
473
+ */
474
+ private _syncFile;
475
+ /**
476
+ * Create a new file and write its contents.
477
+ * @param path - The path of the file to create.
478
+ * @returns Promise resolving to success or failure.
479
+ * @internal
480
+ */
481
+ private _createAndWriteFile;
482
+ }
483
+
183
484
  /**
184
485
  * Options for creating writable file streams
185
486
  * @public
@@ -327,6 +628,8 @@ declare function extractFileListMetadata(fileList: FileList): Array<IFileMetadat
327
628
  */
328
629
  declare function getOriginalFile(fileList: FileList, path: string): Result<File>;
329
630
 
631
+ declare type ICryptoProvider = CryptoUtils_2.ICryptoProvider;
632
+
330
633
  /**
331
634
  * Tree initializer for File System Access API directory handles.
332
635
  * @public
@@ -337,6 +640,8 @@ declare function extractFileListMetadata(fileList: FileList): Array<IFileMetadat
337
640
  readonly nonRecursive?: boolean;
338
641
  }
339
642
 
643
+ declare type IEncryptionResult = CryptoUtils_2.IEncryptionResult;
644
+
340
645
  /**
341
646
  * Tree initializer for File System Access API file handles.
342
647
  * @public
@@ -366,6 +671,32 @@ declare function extractFileListMetadata(fileList: FileList): Array<IFileMetadat
366
671
  lastModified: number;
367
672
  }
368
673
 
674
+ /**
675
+ * Options for creating persistent file trees.
676
+ * @public
677
+ */
678
+ export declare interface IFileSystemAccessTreeParams<TCT extends string = string> extends FileTree.IFileTreeInitParams<TCT> {
679
+ /**
680
+ * Automatically sync changes to disk immediately after each save.
681
+ * If false, changes are batched and written on explicit syncToDisk() call.
682
+ * @defaultValue false
683
+ */
684
+ autoSync?: boolean;
685
+ /**
686
+ * Require write permission on the directory handle.
687
+ * If true, fails if write permission cannot be obtained.
688
+ * If false, falls back to read-only mode.
689
+ * @defaultValue true
690
+ */
691
+ requireWritePermission?: boolean;
692
+ /**
693
+ * Override the path at which the file is stored in the tree (for fromFileHandle).
694
+ * Must be an absolute path (e.g., '/data/confections/common.yaml').
695
+ * If omitted, defaults to `/<filename>`.
696
+ */
697
+ filePath?: string;
698
+ }
699
+
369
700
  /**
370
701
  * File System Access API methods available on Window
371
702
  * @public
@@ -376,6 +707,29 @@ declare function extractFileListMetadata(fileList: FileList): Array<IFileMetadat
376
707
  showSaveFilePicker(options?: ShowSaveFilePickerOptions): Promise<FileSystemFileHandle_2>;
377
708
  }
378
709
 
710
+ /**
711
+ * Configuration for LocalStorageTreeAccessors.
712
+ * @public
713
+ */
714
+ export declare interface ILocalStorageTreeParams<TCT extends string = string> extends FileTree.IFileTreeInitParams<TCT> {
715
+ /**
716
+ * Map of directory path prefixes to localStorage keys.
717
+ * Files under each prefix are stored in the corresponding localStorage key.
718
+ * Example: \{ '/data/ingredients': 'myapp:ingredients:v1' \}
719
+ */
720
+ pathToKeyMap: Record<string, string>;
721
+ /**
722
+ * Storage instance to use. Defaults to window.localStorage.
723
+ * Can be overridden for testing with mock storage.
724
+ */
725
+ storage?: Storage;
726
+ /**
727
+ * If true, automatically sync changes to localStorage on every modification.
728
+ * If false (default), changes are only synced when syncToDisk() is called.
729
+ */
730
+ autoSync?: boolean;
731
+ }
732
+
379
733
  /**
380
734
  * Type guard to check if a FileSystemHandle is a directory handle
381
735
  * @param handle - The handle to check
@@ -457,6 +811,111 @@ declare function extractFileListMetadata(fileList: FileList): Array<IFileMetadat
457
811
  zipFile?: string;
458
812
  }
459
813
 
814
+ /**
815
+ * Browser localStorage-backed file tree accessors with persistence support.
816
+ *
817
+ * Maps filesystem-like directory paths to localStorage keys, where each key stores
818
+ * multiple collections as a JSON object. This provides a general-purpose implementation
819
+ * for browser-based file tree persistence without requiring File System Access API.
820
+ *
821
+ * Storage format per key: `{ "collection-id": "<raw file content>" }`
822
+ * File paths map as: `/data/ingredients/collection-id.yaml` → stored in key for `/data/ingredients`
823
+ *
824
+ * Legacy format (v1): `{ "collection-id": { ...parsedJsonObject } }` is auto-migrated on load.
825
+ *
826
+ * @public
827
+ */
828
+ export declare class LocalStorageTreeAccessors<TCT extends string = string> extends FileTree.InMemoryTreeAccessors<TCT> implements FileTree.IPersistentFileTreeAccessors<TCT> {
829
+ private readonly _storage;
830
+ private readonly _pathToKeyMap;
831
+ private readonly _keyToPathMap;
832
+ private readonly _dirtyFiles;
833
+ private readonly _autoSync;
834
+ /**
835
+ * Private constructor. Use fromStorage() factory method instead.
836
+ * @internal
837
+ */
838
+ private constructor();
839
+ /**
840
+ * Create LocalStorageTreeAccessors from browser localStorage.
841
+ * Loads all collections from the configured storage keys.
842
+ *
843
+ * @param params - Configuration including path-to-key mappings
844
+ * @returns Result containing the accessors or an error
845
+ * @public
846
+ */
847
+ static fromStorage<TCT extends string = string>(params: ILocalStorageTreeParams<TCT>): Result<LocalStorageTreeAccessors<TCT>>;
848
+ /**
849
+ * Load all files from localStorage based on path-to-key mappings.
850
+ * @internal
851
+ */
852
+ private static _loadFromStorage;
853
+ /**
854
+ * Heuristic check: does the content look like JSON?
855
+ * @internal
856
+ */
857
+ private static _looksLikeJson;
858
+ /**
859
+ * Join path components, handling leading/trailing slashes.
860
+ * @internal
861
+ */
862
+ private static _joinPath;
863
+ /**
864
+ * Get the storage key for a given file path.
865
+ * @internal
866
+ */
867
+ private _getStorageKeyForPath;
868
+ /**
869
+ * Get the data path prefix for a given file path.
870
+ * @internal
871
+ */
872
+ private _getDataPathForPath;
873
+ /**
874
+ * Extract collection ID from a file path.
875
+ * Example: '/data/ingredients/my-collection.yaml' → 'my-collection'
876
+ * @internal
877
+ */
878
+ private _getCollectionIdFromPath;
879
+ /**
880
+ * Sync a single dirty file to localStorage.
881
+ * @internal
882
+ */
883
+ private _syncFile;
884
+ /**
885
+ * Sync all dirty files to localStorage.
886
+ * @returns Result indicating success or failure
887
+ * @public
888
+ */
889
+ syncToDisk(): Promise<Result<void>>;
890
+ /**
891
+ * Check if there are unsaved changes.
892
+ * @returns True if there are dirty files
893
+ * @public
894
+ */
895
+ isDirty(): boolean;
896
+ /**
897
+ * Get list of file paths with unsaved changes.
898
+ * @returns Array of dirty file paths
899
+ * @public
900
+ */
901
+ getDirtyPaths(): string[];
902
+ /**
903
+ * Save file contents. Marks file as dirty and optionally auto-syncs.
904
+ * @param path - File path
905
+ * @param contents - New file contents
906
+ * @returns Result with the saved contents or error
907
+ * @public
908
+ */
909
+ saveFileContents(path: string, contents: string): Result<string>;
910
+ /**
911
+ * Check if a file is mutable and return persistence detail.
912
+ * @param path - File path to check
913
+ * @returns DetailedResult with mutability status and 'persistent' detail if mutable
914
+ * @public
915
+ */
916
+ fileIsMutable(path: string): DetailedResult<boolean, FileTree.SaveDetail>;
917
+ }
918
+
460
919
  /**
461
920
  * Converts context filter token to context object
462
921
  * Example: "language=en-US|territory=US" -\> \{ language: "en-US", territory: "US" \}
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.54.0"
8
+ "packageVersion": "7.57.6"
9
9
  }
10
10
  ]
11
11
  }
@@ -0,0 +1,50 @@
1
+ <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
+
3
+ [Home](./index.md) &gt; [@fgv/ts-web-extras](./ts-web-extras.md) &gt; [CryptoUtils](./ts-web-extras.cryptoutils.md) &gt; [BrowserCryptoProvider](./ts-web-extras.cryptoutils.browsercryptoprovider.md) &gt; [(constructor)](./ts-web-extras.cryptoutils.browsercryptoprovider._constructor_.md)
4
+
5
+ ## CryptoUtils.BrowserCryptoProvider.(constructor)
6
+
7
+ Creates a new [BrowserCryptoProvider](./ts-web-extras.cryptoutils.browsercryptoprovider.md)<!-- -->.
8
+
9
+ **Signature:**
10
+
11
+ ```typescript
12
+ constructor(cryptoApi?: Crypto);
13
+ ```
14
+
15
+ ## Parameters
16
+
17
+ <table><thead><tr><th>
18
+
19
+ Parameter
20
+
21
+
22
+ </th><th>
23
+
24
+ Type
25
+
26
+
27
+ </th><th>
28
+
29
+ Description
30
+
31
+
32
+ </th></tr></thead>
33
+ <tbody><tr><td>
34
+
35
+ cryptoApi
36
+
37
+
38
+ </td><td>
39
+
40
+ Crypto
41
+
42
+
43
+ </td><td>
44
+
45
+ _(Optional)_ Optional Crypto instance (defaults to globalThis.crypto)
46
+
47
+
48
+ </td></tr>
49
+ </tbody></table>
50
+
@@ -0,0 +1,104 @@
1
+ <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
+
3
+ [Home](./index.md) &gt; [@fgv/ts-web-extras](./ts-web-extras.md) &gt; [CryptoUtils](./ts-web-extras.cryptoutils.md) &gt; [BrowserCryptoProvider](./ts-web-extras.cryptoutils.browsercryptoprovider.md) &gt; [decrypt](./ts-web-extras.cryptoutils.browsercryptoprovider.decrypt.md)
4
+
5
+ ## CryptoUtils.BrowserCryptoProvider.decrypt() method
6
+
7
+ Decrypts ciphertext using AES-256-GCM.
8
+
9
+ **Signature:**
10
+
11
+ ```typescript
12
+ decrypt(encryptedData: Uint8Array, key: Uint8Array, iv: Uint8Array, authTag: Uint8Array): Promise<Result<string>>;
13
+ ```
14
+
15
+ ## Parameters
16
+
17
+ <table><thead><tr><th>
18
+
19
+ Parameter
20
+
21
+
22
+ </th><th>
23
+
24
+ Type
25
+
26
+
27
+ </th><th>
28
+
29
+ Description
30
+
31
+
32
+ </th></tr></thead>
33
+ <tbody><tr><td>
34
+
35
+ encryptedData
36
+
37
+
38
+ </td><td>
39
+
40
+ Uint8Array
41
+
42
+
43
+ </td><td>
44
+
45
+ Encrypted bytes
46
+
47
+
48
+ </td></tr>
49
+ <tr><td>
50
+
51
+ key
52
+
53
+
54
+ </td><td>
55
+
56
+ Uint8Array
57
+
58
+
59
+ </td><td>
60
+
61
+ 32-byte decryption key
62
+
63
+
64
+ </td></tr>
65
+ <tr><td>
66
+
67
+ iv
68
+
69
+
70
+ </td><td>
71
+
72
+ Uint8Array
73
+
74
+
75
+ </td><td>
76
+
77
+ Initialization vector (12 bytes)
78
+
79
+
80
+ </td></tr>
81
+ <tr><td>
82
+
83
+ authTag
84
+
85
+
86
+ </td><td>
87
+
88
+ Uint8Array
89
+
90
+
91
+ </td><td>
92
+
93
+ GCM authentication tag (16 bytes)
94
+
95
+
96
+ </td></tr>
97
+ </tbody></table>
98
+
99
+ **Returns:**
100
+
101
+ Promise&lt;Result&lt;string&gt;&gt;
102
+
103
+ `Success` with decrypted UTF-8 string, or `Failure` with an error.
104
+