@push.rocks/smartsecret 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.smartconfig.json +1 -1
- package/dist_rust/smartsecret-kernel_linux_amd64 +0 -0
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +3 -1
- package/dist_ts/smartsecret.kernel.protocol.d.ts +2 -2
- package/dist_ts/smartsecret.kernel.protocol.js +3 -3
- package/dist_ts/smartsecret.kernelstore.js +17 -7
- package/dist_ts/smartsecret.sealedfile.d.ts +40 -0
- package/dist_ts/smartsecret.sealedfile.error.d.ts +17 -0
- package/dist_ts/smartsecret.sealedfile.error.js +44 -0
- package/dist_ts/smartsecret.sealedfile.js +989 -0
- package/package.json +6 -6
- package/readme.hints.md +12 -1
- package/readme.md +90 -3
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/index.ts +6 -0
- package/ts/smartsecret.kernel.protocol.ts +2 -2
- package/ts/smartsecret.kernelstore.ts +15 -6
- package/ts/smartsecret.sealedfile.error.ts +72 -0
- package/ts/smartsecret.sealedfile.ts +1195 -0
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartsecret",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "OS-backed secret storage plus strict Linux kernel-keyring and envelope APIs for Node.js.",
|
|
5
|
+
"description": "OS-backed secret storage plus strict Linux kernel-keyring, sealed-file, and envelope APIs for Node.js.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
7
7
|
"typings": "dist_ts/index.d.ts",
|
|
8
8
|
"type": "module",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@git.zone/tsbuild": "^4.4.2",
|
|
33
33
|
"@git.zone/tsrun": "^2.0.6",
|
|
34
|
-
"@git.zone/tsrust": "^1.
|
|
34
|
+
"@git.zone/tsrust": "^1.8.0",
|
|
35
35
|
"@git.zone/tstest": "^4.0.0",
|
|
36
|
-
"@types/node": "^26.
|
|
36
|
+
"@types/node": "^26.2.0"
|
|
37
37
|
},
|
|
38
38
|
"files": [
|
|
39
39
|
"ts/**/*",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@push.rocks/smartcrypto": "^2.2.0",
|
|
56
|
-
"@push.rocks/smartipc": "^2.4.
|
|
57
|
-
"@push.rocks/smartrust": "^1.
|
|
56
|
+
"@push.rocks/smartipc": "^2.4.2",
|
|
57
|
+
"@push.rocks/smartrust": "^1.7.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"test": "(tstest test/ --verbose)",
|
package/readme.hints.md
CHANGED
|
@@ -22,9 +22,20 @@
|
|
|
22
22
|
- Additive strict API; legacy SmartSecret backend selection remains unchanged
|
|
23
23
|
- Requires Node.js 24 or 25, Linux x64, Linux keyutils, and the exact package-owned static Rust worker
|
|
24
24
|
- No shell, PATH lookup, environment override, Secret Service, or filesystem secret fallback
|
|
25
|
-
- Generic values are framed and limited to 0..
|
|
25
|
+
- Generic values are framed and limited to 0..16384 bytes; service/account names are valid scalar UTF-8 strings of 1..1024 bytes
|
|
26
26
|
- Persistent-root service rings are revalidated on every operation; process keyring ownership is staging-only
|
|
27
27
|
- Service-wide SmartIPC NamedMutex plus a single monotonic 1..60000 ms deadline bounds cooperating cross-process access
|
|
28
28
|
- Any post-dispatch mutation ambiguity or worker integrity failure terminates and poisons the store
|
|
29
29
|
- DevIdP v1 migration is opaque, receipt-bound, keyutils-only, and requires a quiescent legacy writer
|
|
30
30
|
- Same-UID readability and kernel expiry/reboot behavior are part of the security model
|
|
31
|
+
|
|
32
|
+
## SmartSecret Sealed File Store
|
|
33
|
+
- Composes a caller-owned SmartSecretKernelStore; it never owns or closes the kernel worker
|
|
34
|
+
- Stores one 32-byte master key per service/store/directory identity in the kernel keyring
|
|
35
|
+
- Stores only strict AES-256-GCM envelopes in a caller-owned private directory
|
|
36
|
+
- A non-secret manifest fingerprints the master key; missing kernel material never creates a replacement silently
|
|
37
|
+
- Explicit reset is destructive and removes only store-owned manifest, entry, and temporary files
|
|
38
|
+
- All identities targeting the same directory share one mutex; reset verifies any manifest identity before deletion
|
|
39
|
+
- Directory traversal and store I/O are anchored to open descriptors; ancestors, final components, owners, modes, and O_NOFOLLOW are validated
|
|
40
|
+
- A 64-operation admission cap and one 60-second monotonic queue-plus-mutex deadline bound retained operation inputs
|
|
41
|
+
- Filesystem isolation assumes other processes under the same UID are trusted, matching the kernel-keyring boundary
|
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @push.rocks/smartsecret
|
|
2
2
|
|
|
3
|
-
OS-backed secret storage plus strict Linux kernel-keyring and envelope APIs for Node.js.
|
|
3
|
+
OS-backed secret storage plus strict Linux kernel-keyring, sealed-file, and envelope APIs for Node.js.
|
|
4
4
|
|
|
5
5
|
## Issue Reporting and Security
|
|
6
6
|
|
|
@@ -193,7 +193,7 @@ try {
|
|
|
193
193
|
}
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
Service and account strings must contain valid Unicode scalar values and encode to 1 through 1,024 UTF-8 bytes. Values may contain 0 through
|
|
196
|
+
Service and account strings must contain valid Unicode scalar values and encode to 1 through 1,024 UTF-8 bytes. Values may contain 0 through 16,384 bytes. The stored value is framed with a fixed version and exact length before publication. Existing service rings and entries are accepted only when their type, description, owner, and private permissions match the package contract. Kernel per-user quotas may still reject writes before this per-entry limit is reached; the store reports the kernel failure and never falls back to filesystem storage.
|
|
197
197
|
|
|
198
198
|
`setEntry()` copies its input before dispatch, and `getEntry()` returns a fresh byte array. The caller still owns its input and returned copies and should wipe them when no longer needed. JavaScript and operating-system buffers can retain additional copies, so this remains best-effort zeroization rather than guaranteed memory erasure.
|
|
199
199
|
|
|
@@ -205,6 +205,43 @@ Kernel keyring permissions are an isolation boundary between OS identities, not
|
|
|
205
205
|
|
|
206
206
|
Operation timeouts default to 5 seconds and may be set from 1 through 60,000 milliseconds. A timeout or abort covers queueing, mutex acquisition, and the worker request under one monotonic deadline. If a mutating request is interrupted after dispatch, or publication/release cannot be confirmed, the store rejects with a `SmartSecretKernelStoreError` whose code is `MUTATION_OUTCOME_UNKNOWN`, terminates the worker, and remains poisoned. Read-side worker integrity failures also poison and terminate the store. Always await `close()`; it waits for already-reserved operations and confirms worker termination.
|
|
207
207
|
|
|
208
|
+
### Sealed file store
|
|
209
|
+
|
|
210
|
+
`SmartSecretSealedFileStore` is a Linux-only API that composes a caller-owned `SmartSecretKernelStore` for data sets that exceed the kernel's per-user key quota. It stores one 32-byte master key in the kernel keyring and one authenticated AES-256-GCM envelope per account in a dedicated private directory supplied by the caller.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import {
|
|
214
|
+
SmartSecretKernelStore,
|
|
215
|
+
SmartSecretSealedFileStore,
|
|
216
|
+
} from '@push.rocks/smartsecret';
|
|
217
|
+
|
|
218
|
+
const kernelStore = await SmartSecretKernelStore.create({
|
|
219
|
+
service: 'example.application',
|
|
220
|
+
});
|
|
221
|
+
try {
|
|
222
|
+
const sealedStore = await SmartSecretSealedFileStore.create({
|
|
223
|
+
kernelStore,
|
|
224
|
+
storeId: 'oauth-credentials',
|
|
225
|
+
directoryPath: '/absolute/private/application/directory/credentials',
|
|
226
|
+
});
|
|
227
|
+
try {
|
|
228
|
+
await sealedStore.setEntry('account-a', new TextEncoder().encode('secret'));
|
|
229
|
+
const value = await sealedStore.getEntry('account-a');
|
|
230
|
+
value?.fill(0);
|
|
231
|
+
} finally {
|
|
232
|
+
await sealedStore.close();
|
|
233
|
+
}
|
|
234
|
+
} finally {
|
|
235
|
+
await kernelStore.close();
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The directory is required to be owned by the effective user and mode `0700`; envelope and manifest files are mode `0600`. Every directory component must be owned by root or the effective user and must not be group- or world-writable, except for root-owned sticky directories such as `/tmp`. Directory traversal, creation, and store I/O are anchored to open directory descriptors, and final components use `O_NOFOLLOW`. Writes use random exclusive temporary files, file and directory `fsync`, and atomic replacement. Reads reject unexpected owners or permissions, malformed envelopes, identity mismatches, oversized ciphertext, and authentication failures. The filesystem boundary, like the kernel keyring, trusts other processes running under the same UID.
|
|
240
|
+
|
|
241
|
+
The non-secret manifest binds the directory to the kernel master-key fingerprint. If the kernel key is lost or expires while any manifest, envelope, or temporary artifact remains, `create()` fails with `MASTER_KEY_UNAVAILABLE` and never silently generates a replacement. `SmartSecretSealedFileStore.reset()` is an explicit destructive recovery operation: after verifying any existing manifest belongs to the requested service and store ID, it removes only the store-owned manifest, envelope, and temporary files, removes the old kernel entry if present, and creates a new empty store.
|
|
242
|
+
|
|
243
|
+
Each store instance admits at most 64 operations at once. Each admitted operation has one 60-second monotonic deadline covering the local operation queue and cross-process mutex acquisition. The mutex is directory-wide, so different service or store identities targeting the same directory serialize with each other. Work already running after mutex acquisition is not interrupted by that admission deadline. `close()` rejects new operations, drains admitted operations, and then best-effort wipes the retained master-key copy.
|
|
244
|
+
|
|
208
245
|
### DevIdP v1 keyutils migration
|
|
209
246
|
|
|
210
247
|
The two `DevIdP` migration methods are intentionally narrow. They are available only on a store created with service `global.idp.devidp` and accept only accounts matching `v1:[a-f0-9]{64}`:
|
|
@@ -288,6 +325,56 @@ SmartSecretKernelStore.create(
|
|
|
288
325
|
|
|
289
326
|
Operation options contain optional `timeoutMs` and `signal: AbortSignal` properties. Failures are code-only `SmartSecretKernelStoreError` instances. Stable codes distinguish invalid input, unsupported runtime, unavailable kernel/worker/mutex resources, root conflicts, corrupt entries, changed migration sources, pre-dispatch aborts/timeouts, unknown mutation outcomes, poisoned/closed lifecycle state, and worker integrity failures. Secret values and underlying causes are never retained on these errors.
|
|
290
327
|
|
|
328
|
+
### `SmartSecretSealedFileStore`
|
|
329
|
+
|
|
330
|
+
Create a sealed store with a caller-owned kernel store and a dedicated absolute private directory:
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
SmartSecretSealedFileStore.create(
|
|
334
|
+
options: ISmartSecretSealedFileStoreOptions,
|
|
335
|
+
): Promise<SmartSecretSealedFileStore>
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
This API is available only on Linux. `directoryPath` must be an absolute normalized path. The exported options and kernel-store contract are:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
interface ISmartSecretSealedFileKernelStore {
|
|
342
|
+
readonly service: string;
|
|
343
|
+
getEntry(
|
|
344
|
+
account: string,
|
|
345
|
+
options?: ISmartSecretKernelOperationOptions,
|
|
346
|
+
): Promise<Uint8Array | null>;
|
|
347
|
+
setEntry(
|
|
348
|
+
account: string,
|
|
349
|
+
value: Uint8Array,
|
|
350
|
+
options?: ISmartSecretKernelOperationOptions,
|
|
351
|
+
): Promise<void>;
|
|
352
|
+
deleteEntry(
|
|
353
|
+
account: string,
|
|
354
|
+
options?: ISmartSecretKernelOperationOptions,
|
|
355
|
+
): Promise<boolean>;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
interface ISmartSecretSealedFileStoreOptions {
|
|
359
|
+
kernelStore: ISmartSecretSealedFileKernelStore;
|
|
360
|
+
storeId: string;
|
|
361
|
+
directoryPath: string;
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Instances expose readonly `service`, `storeId`, and `directoryPath` properties. The exported `smartSecretSealedFileMaximumEntryBytes` constant is `524288`.
|
|
366
|
+
|
|
367
|
+
| Method | Signature | Description |
|
|
368
|
+
| --- | --- | --- |
|
|
369
|
+
| `create` | `(options) => Promise<SmartSecretSealedFileStore>` | Open or initialize a store without replacing missing key material |
|
|
370
|
+
| `reset` | `(options) => Promise<SmartSecretSealedFileStore>` | Destructively discard store-owned ciphertext and create a new empty store |
|
|
371
|
+
| `getEntry` | `(account: string) => Promise<Uint8Array \| null>` | Authenticate and decrypt a copied value or return `null` when absent |
|
|
372
|
+
| `setEntry` | `(account: string, value: Uint8Array) => Promise<void>` | Atomically encrypt and replace an entry up to 524,288 bytes |
|
|
373
|
+
| `deleteEntry` | `(account: string) => Promise<boolean>` | Delete an encrypted entry and report whether it existed |
|
|
374
|
+
| `close` | `() => Promise<void>` | Drain admitted operations and best-effort wipe the retained master-key copy |
|
|
375
|
+
|
|
376
|
+
Failures are code-only `SmartSecretSealedFileStoreError` instances. `TSmartSecretSealedFileStoreErrorCode` is the exact union `AUTHENTICATION_FAILED | ENVELOPE_INVALID | FILESYSTEM_FAILED | INVALID_ARGUMENT | KERNEL_UNAVAILABLE | MASTER_KEY_CONFLICT | MASTER_KEY_UNAVAILABLE | MUTATION_OUTCOME_UNKNOWN | MUTEX_FAILED | OPERATION_LIMIT_REACHED | SIZE_LIMIT_EXCEEDED | STORE_CLOSED`. `ISmartSecretSealedFileStoreErrorJson` describes the stable `{ name, code, message }` JSON and inspection shape. The caller retains ownership of the kernel store and must close it separately.
|
|
377
|
+
|
|
291
378
|
### Types
|
|
292
379
|
|
|
293
380
|
```typescript
|
|
@@ -351,7 +438,7 @@ Both paths can be influenced by providing a custom `vaultPath` in the constructo
|
|
|
351
438
|
|
|
352
439
|
## License and Legal Information
|
|
353
440
|
|
|
354
|
-
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file.
|
|
441
|
+
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository [license file](./license).
|
|
355
442
|
|
|
356
443
|
The packaged Linux kernel worker contains statically linked third-party Rust components. Their copyright and license notices are reproduced in [third-party-notices.md](./third-party-notices.md).
|
|
357
444
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartsecret',
|
|
6
|
-
version: '1.
|
|
7
|
-
description: 'OS-backed secret storage plus strict Linux kernel-keyring and envelope APIs for Node.js.'
|
|
6
|
+
version: '1.5.0',
|
|
7
|
+
description: 'OS-backed secret storage plus strict Linux kernel-keyring, sealed-file, and envelope APIs for Node.js.'
|
|
8
8
|
}
|
package/ts/index.ts
CHANGED
|
@@ -19,3 +19,9 @@ export type {
|
|
|
19
19
|
ISmartSecretKernelStoreErrorJson,
|
|
20
20
|
TSmartSecretKernelStoreErrorCode,
|
|
21
21
|
} from './smartsecret.kernel.error.js';
|
|
22
|
+
export * from './smartsecret.sealedfile.js';
|
|
23
|
+
export { SmartSecretSealedFileStoreError } from './smartsecret.sealedfile.error.js';
|
|
24
|
+
export type {
|
|
25
|
+
ISmartSecretSealedFileStoreErrorJson,
|
|
26
|
+
TSmartSecretSealedFileStoreErrorCode,
|
|
27
|
+
} from './smartsecret.sealedfile.error.js';
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
|
|
7
7
|
export const smartSecretKernelDefaultTimeoutMs = 5_000;
|
|
8
8
|
export const smartSecretKernelMaximumTimeoutMs = 60_000;
|
|
9
|
-
export const smartSecretKernelMaximumEntryBytes = 1_024;
|
|
9
|
+
export const smartSecretKernelMaximumEntryBytes = 16 * 1_024;
|
|
10
10
|
export const smartSecretKernelMaximumLegacyBytes = 16 * 1_024;
|
|
11
|
-
export const smartSecretKernelMaximumMessageBytes =
|
|
11
|
+
export const smartSecretKernelMaximumMessageBytes = 32_767;
|
|
12
12
|
export const smartSecretKernelLegacyService = 'global.idp.devidp';
|
|
13
13
|
|
|
14
14
|
const serviceDomain = Buffer.from(
|
|
@@ -381,7 +381,7 @@ export class SmartSecretKernelStore {
|
|
|
381
381
|
if (this.closePromise) return this.closePromise;
|
|
382
382
|
this.lifecycleState = 'closing';
|
|
383
383
|
const operationTail = this.operationTail;
|
|
384
|
-
|
|
384
|
+
const closePromise = (async (): Promise<void> => {
|
|
385
385
|
await operationTail;
|
|
386
386
|
const terminated = await this.terminateBridgeConfirmed();
|
|
387
387
|
this.lifecycleState = 'closed';
|
|
@@ -390,7 +390,11 @@ export class SmartSecretKernelStore {
|
|
|
390
390
|
throw createSmartSecretKernelStoreError('WORKER_INTEGRITY_FAILED');
|
|
391
391
|
}
|
|
392
392
|
})();
|
|
393
|
-
|
|
393
|
+
this.closePromise = closePromise;
|
|
394
|
+
void closePromise.catch(() => {
|
|
395
|
+
if (this.closePromise === closePromise) this.closePromise = undefined;
|
|
396
|
+
});
|
|
397
|
+
return closePromise;
|
|
394
398
|
}
|
|
395
399
|
|
|
396
400
|
private assertCanReserve(): void {
|
|
@@ -643,14 +647,19 @@ export class SmartSecretKernelStore {
|
|
|
643
647
|
try {
|
|
644
648
|
termination = this.bridge.terminate({ gracePeriodMs: 0 });
|
|
645
649
|
} catch {
|
|
646
|
-
|
|
647
|
-
return this.terminationPromise;
|
|
650
|
+
return Promise.resolve(false);
|
|
648
651
|
}
|
|
649
|
-
|
|
652
|
+
const terminationAttempt = termination.then(
|
|
650
653
|
() => true,
|
|
651
654
|
() => false,
|
|
652
655
|
);
|
|
653
|
-
|
|
656
|
+
this.terminationPromise = terminationAttempt;
|
|
657
|
+
void terminationAttempt.then(() => {
|
|
658
|
+
if (this.terminationPromise === terminationAttempt) {
|
|
659
|
+
this.terminationPromise = undefined;
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
return terminationAttempt;
|
|
654
663
|
}
|
|
655
664
|
|
|
656
665
|
private async poisonAndTerminate(): Promise<void> {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type TSmartSecretSealedFileStoreErrorCode =
|
|
2
|
+
| 'AUTHENTICATION_FAILED'
|
|
3
|
+
| 'ENVELOPE_INVALID'
|
|
4
|
+
| 'FILESYSTEM_FAILED'
|
|
5
|
+
| 'INVALID_ARGUMENT'
|
|
6
|
+
| 'KERNEL_UNAVAILABLE'
|
|
7
|
+
| 'MASTER_KEY_CONFLICT'
|
|
8
|
+
| 'MASTER_KEY_UNAVAILABLE'
|
|
9
|
+
| 'MUTATION_OUTCOME_UNKNOWN'
|
|
10
|
+
| 'MUTEX_FAILED'
|
|
11
|
+
| 'OPERATION_LIMIT_REACHED'
|
|
12
|
+
| 'SIZE_LIMIT_EXCEEDED'
|
|
13
|
+
| 'STORE_CLOSED';
|
|
14
|
+
|
|
15
|
+
export interface ISmartSecretSealedFileStoreErrorJson {
|
|
16
|
+
name: 'SmartSecretSealedFileStoreError';
|
|
17
|
+
code: TSmartSecretSealedFileStoreErrorCode;
|
|
18
|
+
message: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const inspectSymbol = Symbol.for('nodejs.util.inspect.custom');
|
|
22
|
+
const errorCodes = new Set<TSmartSecretSealedFileStoreErrorCode>([
|
|
23
|
+
'AUTHENTICATION_FAILED',
|
|
24
|
+
'ENVELOPE_INVALID',
|
|
25
|
+
'FILESYSTEM_FAILED',
|
|
26
|
+
'INVALID_ARGUMENT',
|
|
27
|
+
'KERNEL_UNAVAILABLE',
|
|
28
|
+
'MASTER_KEY_CONFLICT',
|
|
29
|
+
'MASTER_KEY_UNAVAILABLE',
|
|
30
|
+
'MUTATION_OUTCOME_UNKNOWN',
|
|
31
|
+
'MUTEX_FAILED',
|
|
32
|
+
'OPERATION_LIMIT_REACHED',
|
|
33
|
+
'SIZE_LIMIT_EXCEEDED',
|
|
34
|
+
'STORE_CLOSED',
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
/** A code-only error that intentionally retains no secret values or causes. */
|
|
38
|
+
export class SmartSecretSealedFileStoreError extends Error {
|
|
39
|
+
public readonly code: TSmartSecretSealedFileStoreErrorCode;
|
|
40
|
+
public readonly cause: undefined;
|
|
41
|
+
|
|
42
|
+
constructor(codeArg: TSmartSecretSealedFileStoreErrorCode) {
|
|
43
|
+
const code = errorCodes.has(codeArg) ? codeArg : 'INVALID_ARGUMENT';
|
|
44
|
+
const message = `SmartSecret sealed file store operation failed (${code}).`;
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = 'SmartSecretSealedFileStoreError';
|
|
47
|
+
this.code = code;
|
|
48
|
+
this.stack = `${this.name}: ${message}`;
|
|
49
|
+
Object.defineProperty(this, 'cause', {
|
|
50
|
+
configurable: false,
|
|
51
|
+
enumerable: false,
|
|
52
|
+
value: undefined,
|
|
53
|
+
writable: false,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public toJSON(): ISmartSecretSealedFileStoreErrorJson {
|
|
58
|
+
return {
|
|
59
|
+
name: 'SmartSecretSealedFileStoreError',
|
|
60
|
+
code: this.code,
|
|
61
|
+
message: this.message,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public [inspectSymbol](): ISmartSecretSealedFileStoreErrorJson {
|
|
66
|
+
return this.toJSON();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const createSmartSecretSealedFileStoreError = (
|
|
71
|
+
codeArg: TSmartSecretSealedFileStoreErrorCode,
|
|
72
|
+
): SmartSecretSealedFileStoreError => new SmartSecretSealedFileStoreError(codeArg);
|