@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
package/src/contract/adapter.ts
CHANGED
|
@@ -1,78 +1,76 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The interface every storage implementation satisfies.
|
|
3
|
-
*
|
|
4
|
-
* Two implementations exist: op-sqlite on device, and a pure-TypeScript
|
|
5
|
-
* in-memory one for tests. The second is not a convenience — op-sqlite is
|
|
6
|
-
* native and unreachable from Jest, so without it the package's own
|
|
7
|
-
* guarantees would be untestable in CI (research.md R8).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
AttachmentAvailability,
|
|
12
|
-
AttachmentInput,
|
|
13
|
-
AttachmentReference,
|
|
14
|
-
AttachmentOwner,
|
|
15
|
-
ByteRange,
|
|
16
|
-
DeletionOutcome,
|
|
17
|
-
ReconciliationReport,
|
|
18
|
-
} from './attachment';
|
|
19
|
-
import type { EffectivePosture } from './backup';
|
|
20
|
-
import type { DatabaseConfig, DatabaseTargetConfig, ScopeTargetConfig } from './config';
|
|
21
|
-
import type { FilterNode, IndexCoverageReport, Query, ResultPage } from './query';
|
|
22
|
-
import type { RecordInput, StorableRecordData, StoredRecord, WriteOutcome } from './record';
|
|
23
|
-
import type { BatchOperation, BatchOutcome, CollectionOps, Transaction } from './transaction';
|
|
24
|
-
|
|
25
|
-
export type Attachments = {
|
|
26
|
-
write(input: AttachmentInput): Promise<AttachmentReference>;
|
|
27
|
-
read(id: string, range?: ByteRange): Promise<string>;
|
|
28
|
-
/** Never opens or decrypts the artifact (FR-073e, FR-107b). */
|
|
29
|
-
availability(id: string): Promise<AttachmentAvailability>;
|
|
30
|
-
remove(id: string): Promise<DeletionOutcome>;
|
|
31
|
-
listFor(owner: AttachmentOwner): Promise<AttachmentReference[]>;
|
|
32
|
-
/** App-triggered only; the package runs no background sweep. */
|
|
33
|
-
reconcile(options?: { removeOrphans?: boolean }): Promise<ReconciliationReport>;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export type DatabaseHandle = {
|
|
37
|
-
/** The scope hash. Never the components (FR-014). */
|
|
38
|
-
readonly scopeKey: string;
|
|
39
|
-
readonly schemaVersion: number;
|
|
40
|
-
readonly backupPosture: EffectivePosture;
|
|
41
|
-
readonly isEncrypted: boolean;
|
|
42
|
-
|
|
43
|
-
collection<T extends StorableRecordData = StorableRecordData>(
|
|
44
|
-
|
|
45
|
-
):
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
*
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
WriteOutcome,
|
|
78
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* The interface every storage implementation satisfies.
|
|
3
|
+
*
|
|
4
|
+
* Two implementations exist: op-sqlite on device, and a pure-TypeScript
|
|
5
|
+
* in-memory one for tests. The second is not a convenience — op-sqlite is
|
|
6
|
+
* native and unreachable from Jest, so without it the package's own
|
|
7
|
+
* guarantees would be untestable in CI (research.md R8).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
AttachmentAvailability,
|
|
12
|
+
AttachmentInput,
|
|
13
|
+
AttachmentReference,
|
|
14
|
+
AttachmentOwner,
|
|
15
|
+
ByteRange,
|
|
16
|
+
DeletionOutcome,
|
|
17
|
+
ReconciliationReport,
|
|
18
|
+
} from './attachment';
|
|
19
|
+
import type { EffectivePosture } from './backup';
|
|
20
|
+
import type { DatabaseConfig, DatabaseTargetConfig, ScopeTargetConfig } from './config';
|
|
21
|
+
import type { FilterNode, IndexCoverageReport, Query, ResultPage } from './query';
|
|
22
|
+
import type { RecordInput, StorableRecordData, StoredRecord, WriteOutcome } from './record';
|
|
23
|
+
import type { BatchOperation, BatchOutcome, CollectionOps, Transaction } from './transaction';
|
|
24
|
+
|
|
25
|
+
export type Attachments = {
|
|
26
|
+
write(input: AttachmentInput): Promise<AttachmentReference>;
|
|
27
|
+
read(id: string, range?: ByteRange): Promise<string>;
|
|
28
|
+
/** Never opens or decrypts the artifact (FR-073e, FR-107b). */
|
|
29
|
+
availability(id: string): Promise<AttachmentAvailability>;
|
|
30
|
+
remove(id: string): Promise<DeletionOutcome>;
|
|
31
|
+
listFor(owner: AttachmentOwner): Promise<AttachmentReference[]>;
|
|
32
|
+
/** App-triggered only; the package runs no background sweep. */
|
|
33
|
+
reconcile(options?: { removeOrphans?: boolean }): Promise<ReconciliationReport>;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type DatabaseHandle = {
|
|
37
|
+
/** The scope hash. Never the components (FR-014). */
|
|
38
|
+
readonly scopeKey: string;
|
|
39
|
+
readonly schemaVersion: number;
|
|
40
|
+
readonly backupPosture: EffectivePosture;
|
|
41
|
+
readonly isEncrypted: boolean;
|
|
42
|
+
|
|
43
|
+
collection<T extends StorableRecordData = StorableRecordData>(name: string): CollectionOps<T>;
|
|
44
|
+
transaction<R>(fn: (tx: Transaction) => Promise<R>): Promise<R>;
|
|
45
|
+
batch(operations: BatchOperation[]): Promise<BatchOutcome>;
|
|
46
|
+
attachments(): Attachments;
|
|
47
|
+
/** Development-mode index coverage answer (FR-037). */
|
|
48
|
+
explain(collection: string, query?: Query): Promise<IndexCoverageReport>;
|
|
49
|
+
close(): Promise<void>;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* What an implementation must provide. Deliberately lower-level than the
|
|
54
|
+
* public surface: validation, budget checks, and error mapping happen once in
|
|
55
|
+
* `adapter/`, above this line, so both implementations share them.
|
|
56
|
+
*/
|
|
57
|
+
export type StorageAdapter = {
|
|
58
|
+
readonly name: 'sqlite' | 'memory';
|
|
59
|
+
|
|
60
|
+
open(config: DatabaseConfig): Promise<DatabaseHandle>;
|
|
61
|
+
deleteScopeData(config: ScopeTargetConfig): Promise<DeletionOutcome>;
|
|
62
|
+
deleteDatabase(config: DatabaseTargetConfig): Promise<DeletionOutcome>;
|
|
63
|
+
/** The FR-057a recovery path. Never reachable from open(). */
|
|
64
|
+
resetScope(config: ScopeTargetConfig): Promise<DeletionOutcome>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type {
|
|
68
|
+
CollectionOps,
|
|
69
|
+
FilterNode,
|
|
70
|
+
Query,
|
|
71
|
+
RecordInput,
|
|
72
|
+
ResultPage,
|
|
73
|
+
StoredRecord,
|
|
74
|
+
Transaction,
|
|
75
|
+
WriteOutcome,
|
|
76
|
+
};
|
|
@@ -1,78 +1,75 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Attachment references and the artifacts behind them.
|
|
3
|
-
*
|
|
4
|
-
* This package owns both halves. The consequence is that a filesystem write
|
|
5
|
-
* cannot be rolled back by a database transaction, which is why
|
|
6
|
-
* reconciliation exists (FR-073d) rather than being a nicety.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
export type AttachmentOwner = {
|
|
10
|
-
collection: string;
|
|
11
|
-
id: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export type AttachmentInput = {
|
|
15
|
-
id: string;
|
|
16
|
-
/** Absent means the attachment belongs to the scope rather than a record. */
|
|
17
|
-
owner?: AttachmentOwner;
|
|
18
|
-
contentType: string;
|
|
19
|
-
/** Base64 content. Written incrementally; never held whole when encrypted. */
|
|
20
|
-
content: string;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export type AttachmentReference = {
|
|
24
|
-
id: string;
|
|
25
|
-
owner?: AttachmentOwner;
|
|
26
|
-
contentType: string;
|
|
27
|
-
/** Plaintext byte length, <= 100 MB (FR-088). */
|
|
28
|
-
size: number;
|
|
29
|
-
createdAt: number;
|
|
30
|
-
/** Present only for encrypted artifacts (research.md R4). */
|
|
31
|
-
chunkSize?: number;
|
|
32
|
-
chunkCount?: number;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* `undecryptable` is deliberately distinct from `missing`: one is data loss
|
|
37
|
-
* for that artifact, the other is a wrong key or a tampered file (FR-107c).
|
|
38
|
-
*/
|
|
39
|
-
export type AttachmentAvailabilityState =
|
|
40
|
-
| '
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
orphanedReferences: string[];
|
|
77
|
-
failedRemovals: string[];
|
|
78
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Attachment references and the artifacts behind them.
|
|
3
|
+
*
|
|
4
|
+
* This package owns both halves. The consequence is that a filesystem write
|
|
5
|
+
* cannot be rolled back by a database transaction, which is why
|
|
6
|
+
* reconciliation exists (FR-073d) rather than being a nicety.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type AttachmentOwner = {
|
|
10
|
+
collection: string;
|
|
11
|
+
id: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type AttachmentInput = {
|
|
15
|
+
id: string;
|
|
16
|
+
/** Absent means the attachment belongs to the scope rather than a record. */
|
|
17
|
+
owner?: AttachmentOwner | undefined;
|
|
18
|
+
contentType: string;
|
|
19
|
+
/** Base64 content. Written incrementally; never held whole when encrypted. */
|
|
20
|
+
content: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type AttachmentReference = {
|
|
24
|
+
id: string;
|
|
25
|
+
owner?: AttachmentOwner | undefined;
|
|
26
|
+
contentType: string;
|
|
27
|
+
/** Plaintext byte length, <= 100 MB (FR-088). */
|
|
28
|
+
size: number;
|
|
29
|
+
createdAt: number;
|
|
30
|
+
/** Present only for encrypted artifacts (research.md R4). */
|
|
31
|
+
chunkSize?: number;
|
|
32
|
+
chunkCount?: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* `undecryptable` is deliberately distinct from `missing`: one is data loss
|
|
37
|
+
* for that artifact, the other is a wrong key or a tampered file (FR-107c).
|
|
38
|
+
*/
|
|
39
|
+
export type AttachmentAvailabilityState =
|
|
40
|
+
'available' | 'missing' | 'inaccessible' | 'undecryptable';
|
|
41
|
+
|
|
42
|
+
export type AttachmentAvailability = {
|
|
43
|
+
id: string;
|
|
44
|
+
state: AttachmentAvailabilityState;
|
|
45
|
+
size?: number;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type ByteRange = {
|
|
49
|
+
offset: number;
|
|
50
|
+
length: number;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Both directions of divergence between the database and the disk (FR-073d).
|
|
55
|
+
*/
|
|
56
|
+
export type ReconciliationReport = {
|
|
57
|
+
orphanedArtifacts: string[];
|
|
58
|
+
danglingReferences: string[];
|
|
59
|
+
removedArtifacts: string[];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/** Never a bare success (FR-065, FR-071). */
|
|
63
|
+
export type DeletionOutcome = {
|
|
64
|
+
scopeKey?: string;
|
|
65
|
+
removedRecords: number;
|
|
66
|
+
/**
|
|
67
|
+
* True when the scope was deleted but its records could not be counted — an
|
|
68
|
+
* encrypted scope whose key was unavailable, or a file that would not open.
|
|
69
|
+
* `removedRecords` is then 0 and means "unknown". Added in 0.2.0.
|
|
70
|
+
*/
|
|
71
|
+
recordCountUnavailable?: boolean;
|
|
72
|
+
removedArtifacts: string[];
|
|
73
|
+
orphanedReferences: string[];
|
|
74
|
+
failedRemovals: string[];
|
|
75
|
+
};
|
package/src/contract/backup.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Platform backup posture.
|
|
3
|
-
*
|
|
4
|
-
* The platforms are not symmetric, and this contract is where that becomes
|
|
5
|
-
* visible to the consumer rather than hidden. On iOS the package sets the
|
|
6
|
-
* exclusion attribute itself. On Android backup participation is declared in
|
|
7
|
-
* the app's manifest — build-time, app-owned, and unreachable from a library
|
|
8
|
-
* that authors no native code — so the package verifies and reports instead.
|
|
9
|
-
* See research.md R5.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export type BackupConfig = {
|
|
13
|
-
/** Default false: excluded unless the app asks otherwise (FR-109). */
|
|
14
|
-
includeInPlatformBackup: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export type BackupPostureValue = 'excluded' | 'included' | 'unknown';
|
|
18
|
-
|
|
19
|
-
export type EffectivePosture = {
|
|
20
|
-
/** What the app asked for. */
|
|
21
|
-
requested: Exclude<BackupPostureValue, 'unknown'>;
|
|
22
|
-
/** What the package can actually confirm on this platform. */
|
|
23
|
-
observed: BackupPostureValue;
|
|
24
|
-
/** iOS: the package. Android: the app's manifest. */
|
|
25
|
-
enforcedBy: 'package' | 'app-manifest';
|
|
26
|
-
/** Present when requested and observed disagree — the case that matters. */
|
|
27
|
-
warning?: string;
|
|
28
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Platform backup posture.
|
|
3
|
+
*
|
|
4
|
+
* The platforms are not symmetric, and this contract is where that becomes
|
|
5
|
+
* visible to the consumer rather than hidden. On iOS the package sets the
|
|
6
|
+
* exclusion attribute itself. On Android backup participation is declared in
|
|
7
|
+
* the app's manifest — build-time, app-owned, and unreachable from a library
|
|
8
|
+
* that authors no native code — so the package verifies and reports instead.
|
|
9
|
+
* See research.md R5.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type BackupConfig = {
|
|
13
|
+
/** Default false: excluded unless the app asks otherwise (FR-109). */
|
|
14
|
+
includeInPlatformBackup: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type BackupPostureValue = 'excluded' | 'included' | 'unknown';
|
|
18
|
+
|
|
19
|
+
export type EffectivePosture = {
|
|
20
|
+
/** What the app asked for. */
|
|
21
|
+
requested: Exclude<BackupPostureValue, 'unknown'>;
|
|
22
|
+
/** What the package can actually confirm on this platform. */
|
|
23
|
+
observed: BackupPostureValue;
|
|
24
|
+
/** iOS: the package. Android: the app's manifest. */
|
|
25
|
+
enforcedBy: 'package' | 'app-manifest';
|
|
26
|
+
/** Present when requested and observed disagree — the case that matters. */
|
|
27
|
+
warning?: string;
|
|
28
|
+
};
|
package/src/contract/config.ts
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database configuration: everything an app supplies at open time.
|
|
3
|
-
*
|
|
4
|
-
* Immutable for the handle's lifetime. Scope in particular is bound here and
|
|
5
|
-
* never changes (FR-008a) — there is no switchScope, and no operation takes a
|
|
6
|
-
* scope argument, which is what makes cross-scope leakage inexpressible
|
|
7
|
-
* rather than merely prevented.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { BackupConfig } from './backup';
|
|
11
|
-
import type { EncryptionConfig } from './encryption';
|
|
12
|
-
import type { Migration } from './migration';
|
|
13
|
-
import type { CollectionSchema } from './schema';
|
|
14
|
-
import type { ScopeDescriptor } from './scope';
|
|
15
|
-
|
|
16
|
-
/** Phase-one budgets (FR-088). Confirmed against the harness during validation. */
|
|
17
|
-
export const Budgets = {
|
|
18
|
-
MAX_RECORDS_PER_COLLECTION: 100_000,
|
|
19
|
-
MAX_RECORD_BYTES: 256 * 1024,
|
|
20
|
-
MAX_BATCH_OPERATIONS: 1_000,
|
|
21
|
-
MAX_PAGE_SIZE: 500,
|
|
22
|
-
MAX_COLLECTIONS_PER_DATABASE: 50,
|
|
23
|
-
MAX_ATTACHMENT_REFERENCES_PER_SCOPE: 50_000,
|
|
24
|
-
MAX_ARTIFACT_BYTES: 100 * 1024 * 1024,
|
|
25
|
-
MAX_OPEN_HANDLES: 8,
|
|
26
|
-
/** Plaintext chunk size for encrypted artifacts (research.md R4). */
|
|
27
|
-
ARTIFACT_CHUNK_BYTES: 256 * 1024,
|
|
28
|
-
} as const;
|
|
29
|
-
|
|
30
|
-
export type DatabaseConfig = {
|
|
31
|
-
name: string;
|
|
32
|
-
scope: ScopeDescriptor;
|
|
33
|
-
/** Must equal the highest version in `migrations` (FR-053). */
|
|
34
|
-
schemaVersion: number;
|
|
35
|
-
collections: CollectionSchema[];
|
|
36
|
-
migrations?: Migration[];
|
|
37
|
-
/** Absent means unencrypted (FR-097). */
|
|
38
|
-
encryption?: EncryptionConfig;
|
|
39
|
-
/** Absent means excluded from platform backup (FR-109). */
|
|
40
|
-
backup?: BackupConfig;
|
|
41
|
-
/** Governs whether deleting a record removes its artifacts (FR-070). */
|
|
42
|
-
cascadeAttachments?: boolean;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/** Names a scope for the operations that legitimately need to (FR-059). */
|
|
46
|
-
export type ScopeTargetConfig = {
|
|
47
|
-
name: string;
|
|
48
|
-
scope: ScopeDescriptor;
|
|
49
|
-
encryption?: EncryptionConfig;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export type DatabaseTargetConfig = {
|
|
53
|
-
name: string;
|
|
54
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Database configuration: everything an app supplies at open time.
|
|
3
|
+
*
|
|
4
|
+
* Immutable for the handle's lifetime. Scope in particular is bound here and
|
|
5
|
+
* never changes (FR-008a) — there is no switchScope, and no operation takes a
|
|
6
|
+
* scope argument, which is what makes cross-scope leakage inexpressible
|
|
7
|
+
* rather than merely prevented.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { BackupConfig } from './backup';
|
|
11
|
+
import type { EncryptionConfig } from './encryption';
|
|
12
|
+
import type { Migration } from './migration';
|
|
13
|
+
import type { CollectionSchema } from './schema';
|
|
14
|
+
import type { ScopeDescriptor } from './scope';
|
|
15
|
+
|
|
16
|
+
/** Phase-one budgets (FR-088). Confirmed against the harness during validation. */
|
|
17
|
+
export const Budgets = {
|
|
18
|
+
MAX_RECORDS_PER_COLLECTION: 100_000,
|
|
19
|
+
MAX_RECORD_BYTES: 256 * 1024,
|
|
20
|
+
MAX_BATCH_OPERATIONS: 1_000,
|
|
21
|
+
MAX_PAGE_SIZE: 500,
|
|
22
|
+
MAX_COLLECTIONS_PER_DATABASE: 50,
|
|
23
|
+
MAX_ATTACHMENT_REFERENCES_PER_SCOPE: 50_000,
|
|
24
|
+
MAX_ARTIFACT_BYTES: 100 * 1024 * 1024,
|
|
25
|
+
MAX_OPEN_HANDLES: 8,
|
|
26
|
+
/** Plaintext chunk size for encrypted artifacts (research.md R4). */
|
|
27
|
+
ARTIFACT_CHUNK_BYTES: 256 * 1024,
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
export type DatabaseConfig = {
|
|
31
|
+
name: string;
|
|
32
|
+
scope: ScopeDescriptor;
|
|
33
|
+
/** Must equal the highest version in `migrations` (FR-053). */
|
|
34
|
+
schemaVersion: number;
|
|
35
|
+
collections: CollectionSchema[];
|
|
36
|
+
migrations?: Migration[];
|
|
37
|
+
/** Absent means unencrypted (FR-097). */
|
|
38
|
+
encryption?: EncryptionConfig | undefined;
|
|
39
|
+
/** Absent means excluded from platform backup (FR-109). */
|
|
40
|
+
backup?: BackupConfig;
|
|
41
|
+
/** Governs whether deleting a record removes its artifacts (FR-070). */
|
|
42
|
+
cascadeAttachments?: boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** Names a scope for the operations that legitimately need to (FR-059). */
|
|
46
|
+
export type ScopeTargetConfig = {
|
|
47
|
+
name: string;
|
|
48
|
+
scope: ScopeDescriptor;
|
|
49
|
+
encryption?: EncryptionConfig | undefined;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type DatabaseTargetConfig = {
|
|
53
|
+
name: string;
|
|
54
|
+
};
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Opt-in encryption at rest under an app-supplied key.
|
|
3
|
-
*
|
|
4
|
-
* The package never generates, derives from its own material, persists,
|
|
5
|
-
* caches beyond the handle's lifetime, transmits, or returns a key (FR-098).
|
|
6
|
-
* Keeping key acquisition on the app side is also what keeps a keychain
|
|
7
|
-
* dependency out of this package entirely (LIB-004).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { ResolvedScope } from './scope';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Implemented by the consuming app. Receives the scope so an app can key per
|
|
14
|
-
* identity — which is what makes destroying one identity's key meaningful
|
|
15
|
-
* (FR-104).
|
|
16
|
-
*/
|
|
17
|
-
export type KeyProvider = {
|
|
18
|
-
getKey(scope: ResolvedScope): Promise<string>;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type EncryptionConfig = {
|
|
22
|
-
enabled: true;
|
|
23
|
-
keyProvider: KeyProvider;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* What the package will say about its own at-rest posture. Reported so a
|
|
28
|
-
* consumer can make an accurate privacy disclosure rather than assume one.
|
|
29
|
-
*/
|
|
30
|
-
export type EncryptionPosture = {
|
|
31
|
-
enabled: boolean;
|
|
32
|
-
/** Whether SQLCipher is actually compiled into the app (research.md R1a). */
|
|
33
|
-
available: boolean;
|
|
34
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in encryption at rest under an app-supplied key.
|
|
3
|
+
*
|
|
4
|
+
* The package never generates, derives from its own material, persists,
|
|
5
|
+
* caches beyond the handle's lifetime, transmits, or returns a key (FR-098).
|
|
6
|
+
* Keeping key acquisition on the app side is also what keeps a keychain
|
|
7
|
+
* dependency out of this package entirely (LIB-004).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ResolvedScope } from './scope';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Implemented by the consuming app. Receives the scope so an app can key per
|
|
14
|
+
* identity — which is what makes destroying one identity's key meaningful
|
|
15
|
+
* (FR-104).
|
|
16
|
+
*/
|
|
17
|
+
export type KeyProvider = {
|
|
18
|
+
getKey(scope: ResolvedScope): Promise<string>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type EncryptionConfig = {
|
|
22
|
+
enabled: true;
|
|
23
|
+
keyProvider: KeyProvider;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* What the package will say about its own at-rest posture. Reported so a
|
|
28
|
+
* consumer can make an accurate privacy disclosure rather than assume one.
|
|
29
|
+
*/
|
|
30
|
+
export type EncryptionPosture = {
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
/** Whether SQLCipher is actually compiled into the app (research.md R1a). */
|
|
33
|
+
available: boolean;
|
|
34
|
+
};
|