@chipmobilesdk/rn-local-db 0.2.0 → 0.3.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/CHANGELOG.md +191 -102
- package/README.md +728 -728
- package/package.json +62 -62
- package/skills/sdk-rn-local-db/SKILL.md +0 -1
- package/src/adapter/budgets.ts +67 -67
- package/src/adapter/collection.ts +303 -298
- package/src/adapter/deletion.ts +252 -252
- package/src/adapter/index.ts +64 -68
- package/src/adapter/lifecycle.ts +517 -520
- package/src/adapter/transaction.ts +71 -71
- package/src/artifacts/availability.ts +67 -67
- package/src/artifacts/cascade.ts +114 -114
- package/src/artifacts/paths.ts +29 -29
- package/src/artifacts/reconcile.ts +63 -63
- package/src/artifacts/store.ts +334 -345
- package/src/contract/adapter.ts +76 -78
- package/src/contract/attachment.ts +75 -78
- package/src/contract/backup.ts +28 -28
- package/src/contract/config.ts +54 -54
- package/src/contract/encryption.ts +34 -34
- package/src/contract/errors.ts +76 -76
- package/src/contract/migration.ts +42 -42
- package/src/contract/query.ts +81 -81
- package/src/contract/record.ts +46 -51
- package/src/contract/schema.ts +36 -36
- package/src/contract/scope.ts +36 -36
- package/src/contract/transaction.ts +52 -54
- package/src/crypto/chunked-cipher.ts +153 -150
- package/src/crypto/derive.ts +64 -64
- package/src/crypto/key-provider.ts +78 -78
- package/src/crypto/provider.ts +75 -81
- package/src/diagnostics/dev-log.ts +132 -108
- package/src/diagnostics/errors.ts +63 -66
- package/src/diagnostics/faults.ts +58 -64
- package/src/diagnostics/map-native.ts +108 -106
- package/src/diagnostics/redact.ts +119 -141
- package/src/index.ts +80 -110
- package/src/migration/executor.ts +132 -136
- package/src/migration/ledger.ts +95 -97
- package/src/migration/validate-chain.ts +65 -65
- package/src/platform/backup-android-verify.ts +88 -88
- package/src/platform/backup-ios.ts +49 -48
- package/src/platform/bytes.ts +157 -144
- package/src/platform/fs.ts +90 -89
- package/src/platform/location.ts +135 -135
- package/src/query/budgets.ts +54 -54
- package/src/query/compare.ts +91 -91
- package/src/query/cursor.ts +100 -100
- package/src/query/filter.ts +82 -82
- package/src/query/paginate.ts +51 -51
- package/src/query/sort.ts +55 -56
- package/src/query/validate.ts +171 -171
- package/src/schema/declare.ts +42 -45
- package/src/schema/validate-config.ts +158 -158
- package/src/scope/hash.ts +131 -134
- package/src/scope/normalize.ts +83 -90
- package/src/scope/validate.ts +83 -83
- package/src/sqlite/adapter.ts +26 -26
- package/src/sqlite/batch.ts +242 -242
- package/src/sqlite/catalog.ts +105 -108
- package/src/sqlite/connection.ts +227 -227
- package/src/sqlite/index-coverage.ts +54 -56
- package/src/sqlite/native.ts +84 -83
- package/src/sqlite/row-codec.ts +217 -221
- package/src/sqlite/sql-builder.ts +244 -244
- package/src/sqlite/transaction-queue.ts +87 -87
- package/src/sqlite/transactions.ts +33 -33
- package/src/sqlite/values.ts +24 -24
- package/src/testing/conformance/attachments.ts +139 -136
- package/src/testing/conformance/encryption.ts +151 -150
- package/src/testing/conformance/index.ts +161 -161
- package/src/testing/conformance/lifecycle.ts +99 -99
- package/src/testing/conformance/migrations.ts +177 -177
- package/src/testing/conformance/queries.ts +204 -167
- package/src/testing/conformance/records.ts +169 -169
- package/src/testing/conformance/scopes.ts +86 -88
- package/src/testing/conformance/transactions.ts +149 -149
- package/src/testing/faults.ts +21 -21
- package/src/testing/index.ts +17 -21
- package/src/testing/memory-adapter/collection.ts +214 -219
- package/src/testing/memory-adapter/index.ts +511 -492
- package/src/testing/memory-adapter/migrations.ts +117 -119
- package/src/testing/memory-adapter/reset.ts +50 -50
- package/src/testing/memory-adapter/store.ts +128 -134
|
@@ -1,141 +1,119 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Redaction, applied at construction rather than at logging time.
|
|
3
|
-
*
|
|
4
|
-
* The distinction matters: an error object that never held a payload cannot
|
|
5
|
-
* leak one through a consumer's crash reporter, which is where these leaks
|
|
6
|
-
* actually happen in practice. Redacting on the way out of a logger would
|
|
7
|
-
* still leave the values sitting on the object for anything else to pick up
|
|
8
|
-
* (FR-079, FR-099).
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Reduce foreign text to an identifier, or to nothing.
|
|
44
|
-
*
|
|
45
|
-
* "Foreign" means text this package did not author: a SQLite message, a
|
|
46
|
-
* filesystem error, an `Error` a consumer's own migration threw. Any of them
|
|
47
|
-
* can contain anything — SQLite quotes bound parameters back, and a migration
|
|
48
|
-
* that fails on a constraint routinely names the value that violated it.
|
|
49
|
-
*
|
|
50
|
-
* An earlier version of this tried to keep the readable part: the text before
|
|
51
|
-
* the first colon, if it "looked like a class of failure". That heuristic
|
|
52
|
-
* fails on the case that matters. `Patient reported chest pain` looks exactly
|
|
53
|
-
* like a class of failure — short, no punctuation, no digits — and is a
|
|
54
|
-
* medical record. There is no shape test that separates prose describing a
|
|
55
|
-
* failure from prose describing a person, so there is no version of the
|
|
56
|
-
* heuristic worth keeping.
|
|
57
|
-
*
|
|
58
|
-
* What survives is a leading `SQLITE_*` / `ENOENT`-style identifier, which is
|
|
59
|
-
* a closed vocabulary of engine and libc constants and cannot be a value.
|
|
60
|
-
* Everything else becomes `[redacted]`. A developer who needs more can
|
|
61
|
-
* reproduce with the development logger; a crash report cannot.
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
*
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
typeof value === 'number' ||
|
|
121
|
-
typeof value === 'boolean'
|
|
122
|
-
) {
|
|
123
|
-
safe[key] = value;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return Object.keys(safe).length > 0 ? safe : undefined;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/** Reduce an unknown thrown value to a message-shaped string, redacted. */
|
|
130
|
-
export function redactCause(cause: unknown): string | undefined {
|
|
131
|
-
if (cause === undefined || cause === null) {
|
|
132
|
-
return undefined;
|
|
133
|
-
}
|
|
134
|
-
if (cause instanceof Error) {
|
|
135
|
-
return redactForeignText(cause.message);
|
|
136
|
-
}
|
|
137
|
-
if (typeof cause === 'string') {
|
|
138
|
-
return redactForeignText(cause);
|
|
139
|
-
}
|
|
140
|
-
return REDACTED;
|
|
141
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Redaction, applied at construction rather than at logging time.
|
|
3
|
+
*
|
|
4
|
+
* The distinction matters: an error object that never held a payload cannot
|
|
5
|
+
* leak one through a consumer's crash reporter, which is where these leaks
|
|
6
|
+
* actually happen in practice. Redacting on the way out of a logger would
|
|
7
|
+
* still leave the values sitting on the object for anything else to pick up
|
|
8
|
+
* (FR-079, FR-099).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { REDACTED, leadingIdentifier, pickAllowed } from '@chipmobilesdk/rn-core';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The allowlist IS the mechanism. Every key here has been reviewed as
|
|
15
|
+
* incapable of carrying user data: identifiers the app already knows, sizes,
|
|
16
|
+
* counts, and version numbers.
|
|
17
|
+
*
|
|
18
|
+
* A denylist was tried and removed. It rejected `recordId` because the name
|
|
19
|
+
* contains "record", which is the failure mode denylists always have — they
|
|
20
|
+
* guess from names. A closed allowlist cannot guess, and adding to it is a
|
|
21
|
+
* deliberate act with a reviewer attached.
|
|
22
|
+
*/
|
|
23
|
+
export const SAFE_DETAIL_KEYS = new Set([
|
|
24
|
+
'code',
|
|
25
|
+
'collection',
|
|
26
|
+
'recordId',
|
|
27
|
+
'attachmentId',
|
|
28
|
+
'scopeKey',
|
|
29
|
+
'version',
|
|
30
|
+
'recordedVersion',
|
|
31
|
+
'failingVersion',
|
|
32
|
+
'outcome',
|
|
33
|
+
'operation',
|
|
34
|
+
'adapter',
|
|
35
|
+
'platform',
|
|
36
|
+
'sizeBytes',
|
|
37
|
+
'limitBytes',
|
|
38
|
+
'count',
|
|
39
|
+
'limit',
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Reduce foreign text to an identifier, or to nothing.
|
|
44
|
+
*
|
|
45
|
+
* "Foreign" means text this package did not author: a SQLite message, a
|
|
46
|
+
* filesystem error, an `Error` a consumer's own migration threw. Any of them
|
|
47
|
+
* can contain anything — SQLite quotes bound parameters back, and a migration
|
|
48
|
+
* that fails on a constraint routinely names the value that violated it.
|
|
49
|
+
*
|
|
50
|
+
* An earlier version of this tried to keep the readable part: the text before
|
|
51
|
+
* the first colon, if it "looked like a class of failure". That heuristic
|
|
52
|
+
* fails on the case that matters. `Patient reported chest pain` looks exactly
|
|
53
|
+
* like a class of failure — short, no punctuation, no digits — and is a
|
|
54
|
+
* medical record. There is no shape test that separates prose describing a
|
|
55
|
+
* failure from prose describing a person, so there is no version of the
|
|
56
|
+
* heuristic worth keeping.
|
|
57
|
+
*
|
|
58
|
+
* What survives is a leading `SQLITE_*` / `ENOENT`-style identifier, which is
|
|
59
|
+
* a closed vocabulary of engine and libc constants and cannot be a value.
|
|
60
|
+
* Everything else becomes `[redacted]`. A developer who needs more can
|
|
61
|
+
* reproduce with the development logger; a crash report cannot.
|
|
62
|
+
*/
|
|
63
|
+
export function redactForeignText(text: string): string {
|
|
64
|
+
return leadingIdentifier(text);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const MAX_AUTHORED_MESSAGE = 160;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A message this package wrote itself.
|
|
71
|
+
*
|
|
72
|
+
* Every `raise()` call site passes a string literal, and the handful that
|
|
73
|
+
* interpolate do so with a value from a closed set — an operator name, a
|
|
74
|
+
* fault point, a sanitized identifier. `authored-messages.test.ts` enforces
|
|
75
|
+
* that mechanically against the source, so this is a checked property rather
|
|
76
|
+
* than a convention someone has to remember.
|
|
77
|
+
*
|
|
78
|
+
* So no filtering happens here: filtering a message the package wrote would
|
|
79
|
+
* destroy the only readable part of the error for no gain. Foreign text never
|
|
80
|
+
* reaches this function — it goes through `redactForeignText` above.
|
|
81
|
+
*/
|
|
82
|
+
export function sanitizeAuthoredMessage(message: string): string {
|
|
83
|
+
return message.split('\n')[0]!.trim().slice(0, MAX_AUTHORED_MESSAGE);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Reduce a consumer-supplied identifier to a bounded, punctuation-free token.
|
|
88
|
+
*
|
|
89
|
+
* A field name is worth naming — FR-034 exists so a typo is distinguishable
|
|
90
|
+
* from a deliberate choice, and "which field?" is the whole answer. But the
|
|
91
|
+
* name arrives from the consumer, so it is capped and stripped rather than
|
|
92
|
+
* trusted verbatim.
|
|
93
|
+
*/
|
|
94
|
+
export function sanitizeIdentifier(identifier: string): string {
|
|
95
|
+
const cleaned = identifier.replace(/\W/g, '').slice(0, 64);
|
|
96
|
+
return cleaned.length > 0 ? cleaned : REDACTED;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Keep only keys on the allowlist, and only primitive values. */
|
|
100
|
+
export function redactDetail(
|
|
101
|
+
detail: Record<string, unknown> | undefined,
|
|
102
|
+
): Record<string, string | number | boolean> | undefined {
|
|
103
|
+
const safe = pickAllowed(detail, SAFE_DETAIL_KEYS);
|
|
104
|
+
return safe && Object.keys(safe).length > 0 ? safe : undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Reduce an unknown thrown value to a message-shaped string, redacted. */
|
|
108
|
+
export function redactCause(cause: unknown): string | undefined {
|
|
109
|
+
if (cause === undefined || cause === null) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
if (cause instanceof Error) {
|
|
113
|
+
return redactForeignText(cause.message);
|
|
114
|
+
}
|
|
115
|
+
if (typeof cause === 'string') {
|
|
116
|
+
return redactForeignText(cause);
|
|
117
|
+
}
|
|
118
|
+
return REDACTED;
|
|
119
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,110 +1,80 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `@chipmobilesdk/rn-local-db`
|
|
3
|
-
*
|
|
4
|
-
* Offline-first, scope-isolated local storage for ChipMobileSdk apps.
|
|
5
|
-
*
|
|
6
|
-
* What is deliberately absent is part of the contract: there is no
|
|
7
|
-
* `switchScope`, and no read, write, or query operation accepts a scope
|
|
8
|
-
* argument. Scope is bound to a handle at open time and immutable, so a
|
|
9
|
-
* cross-scope leak is not expressible rather than merely prevented.
|
|
10
|
-
*
|
|
11
|
-
* The underlying engine, the physical layout, key material, and the query
|
|
12
|
-
* translation are private and unreachable by deep import.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
// Lifecycle
|
|
16
|
-
export {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
} from './contract/
|
|
60
|
-
export type {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
} from './contract/
|
|
78
|
-
export type {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
MigrationFailureDetail,
|
|
82
|
-
MigrationLedgerEntry,
|
|
83
|
-
MigrationOutcome,
|
|
84
|
-
} from './contract/migration';
|
|
85
|
-
export type {
|
|
86
|
-
AttachmentAvailability,
|
|
87
|
-
AttachmentAvailabilityState,
|
|
88
|
-
AttachmentInput,
|
|
89
|
-
AttachmentOwner,
|
|
90
|
-
AttachmentReference,
|
|
91
|
-
ByteRange,
|
|
92
|
-
DeletionOutcome,
|
|
93
|
-
ReconciliationReport,
|
|
94
|
-
} from './contract/attachment';
|
|
95
|
-
export type {
|
|
96
|
-
EncryptionConfig,
|
|
97
|
-
EncryptionPosture,
|
|
98
|
-
KeyProvider,
|
|
99
|
-
} from './contract/encryption';
|
|
100
|
-
export type {
|
|
101
|
-
BackupConfig,
|
|
102
|
-
BackupPostureValue,
|
|
103
|
-
EffectivePosture,
|
|
104
|
-
} from './contract/backup';
|
|
105
|
-
export type { DiagnosticCode } from './contract/errors';
|
|
106
|
-
export type {
|
|
107
|
-
Attachments,
|
|
108
|
-
DatabaseHandle,
|
|
109
|
-
StorageAdapter,
|
|
110
|
-
} from './contract/adapter';
|
|
1
|
+
/**
|
|
2
|
+
* `@chipmobilesdk/rn-local-db`
|
|
3
|
+
*
|
|
4
|
+
* Offline-first, scope-isolated local storage for ChipMobileSdk apps.
|
|
5
|
+
*
|
|
6
|
+
* What is deliberately absent is part of the contract: there is no
|
|
7
|
+
* `switchScope`, and no read, write, or query operation accepts a scope
|
|
8
|
+
* argument. Scope is bound to a handle at open time and immutable, so a
|
|
9
|
+
* cross-scope leak is not expressible rather than merely prevented.
|
|
10
|
+
*
|
|
11
|
+
* The underlying engine, the physical layout, key material, and the query
|
|
12
|
+
* translation are private and unreachable by deep import.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Lifecycle
|
|
16
|
+
export { deleteDatabase, deleteScopeData, openDatabase, resetScope } from './adapter';
|
|
17
|
+
|
|
18
|
+
// Diagnostics
|
|
19
|
+
export { DiagnosticCodes, StorageError, isCode, isStorageError } from './diagnostics/errors';
|
|
20
|
+
export { setDiagnosticLogger, type DiagnosticLogger } from './diagnostics/dev-log';
|
|
21
|
+
|
|
22
|
+
// Budgets, so a consumer can check before it writes rather than after
|
|
23
|
+
export { Budgets } from './contract/config';
|
|
24
|
+
|
|
25
|
+
// Contract types
|
|
26
|
+
export type { DatabaseConfig, DatabaseTargetConfig, ScopeTargetConfig } from './contract/config';
|
|
27
|
+
export type { ResolvedScope, ScopeDescriptor, ScopeKind } from './contract/scope';
|
|
28
|
+
export type {
|
|
29
|
+
CollectionSchema,
|
|
30
|
+
FieldDeclaration,
|
|
31
|
+
FieldType,
|
|
32
|
+
IndexDeclaration,
|
|
33
|
+
} from './contract/schema';
|
|
34
|
+
export type {
|
|
35
|
+
RecordInput,
|
|
36
|
+
StorableRecordData,
|
|
37
|
+
StorableValue,
|
|
38
|
+
StoredRecord,
|
|
39
|
+
WriteOperation,
|
|
40
|
+
WriteOutcome,
|
|
41
|
+
} from './contract/record';
|
|
42
|
+
export type {
|
|
43
|
+
ComparisonNode,
|
|
44
|
+
FilterNode,
|
|
45
|
+
FilterValue,
|
|
46
|
+
IndexCoverageReport,
|
|
47
|
+
LogicalNode,
|
|
48
|
+
PageRequest,
|
|
49
|
+
Query,
|
|
50
|
+
ResultPage,
|
|
51
|
+
SortDirection,
|
|
52
|
+
SortKey,
|
|
53
|
+
} from './contract/query';
|
|
54
|
+
export type {
|
|
55
|
+
BatchOperation,
|
|
56
|
+
BatchOutcome,
|
|
57
|
+
CollectionOps,
|
|
58
|
+
Transaction,
|
|
59
|
+
} from './contract/transaction';
|
|
60
|
+
export type {
|
|
61
|
+
Migration,
|
|
62
|
+
MigrationContext,
|
|
63
|
+
MigrationFailureDetail,
|
|
64
|
+
MigrationLedgerEntry,
|
|
65
|
+
MigrationOutcome,
|
|
66
|
+
} from './contract/migration';
|
|
67
|
+
export type {
|
|
68
|
+
AttachmentAvailability,
|
|
69
|
+
AttachmentAvailabilityState,
|
|
70
|
+
AttachmentInput,
|
|
71
|
+
AttachmentOwner,
|
|
72
|
+
AttachmentReference,
|
|
73
|
+
ByteRange,
|
|
74
|
+
DeletionOutcome,
|
|
75
|
+
ReconciliationReport,
|
|
76
|
+
} from './contract/attachment';
|
|
77
|
+
export type { EncryptionConfig, EncryptionPosture, KeyProvider } from './contract/encryption';
|
|
78
|
+
export type { BackupConfig, BackupPostureValue, EffectivePosture } from './contract/backup';
|
|
79
|
+
export type { DiagnosticCode } from './contract/errors';
|
|
80
|
+
export type { Attachments, DatabaseHandle, StorageAdapter } from './contract/adapter';
|