@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.
Files changed (84) hide show
  1. package/CHANGELOG.md +191 -102
  2. package/README.md +728 -728
  3. package/package.json +62 -62
  4. package/skills/sdk-rn-local-db/SKILL.md +0 -1
  5. package/src/adapter/budgets.ts +67 -67
  6. package/src/adapter/collection.ts +303 -298
  7. package/src/adapter/deletion.ts +252 -252
  8. package/src/adapter/index.ts +64 -68
  9. package/src/adapter/lifecycle.ts +517 -520
  10. package/src/adapter/transaction.ts +71 -71
  11. package/src/artifacts/availability.ts +67 -67
  12. package/src/artifacts/cascade.ts +114 -114
  13. package/src/artifacts/paths.ts +29 -29
  14. package/src/artifacts/reconcile.ts +63 -63
  15. package/src/artifacts/store.ts +334 -345
  16. package/src/contract/adapter.ts +76 -78
  17. package/src/contract/attachment.ts +75 -78
  18. package/src/contract/backup.ts +28 -28
  19. package/src/contract/config.ts +54 -54
  20. package/src/contract/encryption.ts +34 -34
  21. package/src/contract/errors.ts +76 -76
  22. package/src/contract/migration.ts +42 -42
  23. package/src/contract/query.ts +81 -81
  24. package/src/contract/record.ts +46 -51
  25. package/src/contract/schema.ts +36 -36
  26. package/src/contract/scope.ts +36 -36
  27. package/src/contract/transaction.ts +52 -54
  28. package/src/crypto/chunked-cipher.ts +153 -150
  29. package/src/crypto/derive.ts +64 -64
  30. package/src/crypto/key-provider.ts +78 -78
  31. package/src/crypto/provider.ts +75 -81
  32. package/src/diagnostics/dev-log.ts +132 -108
  33. package/src/diagnostics/errors.ts +63 -66
  34. package/src/diagnostics/faults.ts +58 -64
  35. package/src/diagnostics/map-native.ts +108 -106
  36. package/src/diagnostics/redact.ts +119 -141
  37. package/src/index.ts +80 -110
  38. package/src/migration/executor.ts +132 -136
  39. package/src/migration/ledger.ts +95 -97
  40. package/src/migration/validate-chain.ts +65 -65
  41. package/src/platform/backup-android-verify.ts +88 -88
  42. package/src/platform/backup-ios.ts +49 -48
  43. package/src/platform/bytes.ts +157 -144
  44. package/src/platform/fs.ts +90 -89
  45. package/src/platform/location.ts +135 -135
  46. package/src/query/budgets.ts +54 -54
  47. package/src/query/compare.ts +91 -91
  48. package/src/query/cursor.ts +100 -100
  49. package/src/query/filter.ts +82 -82
  50. package/src/query/paginate.ts +51 -51
  51. package/src/query/sort.ts +55 -56
  52. package/src/query/validate.ts +171 -171
  53. package/src/schema/declare.ts +42 -45
  54. package/src/schema/validate-config.ts +158 -158
  55. package/src/scope/hash.ts +131 -134
  56. package/src/scope/normalize.ts +83 -90
  57. package/src/scope/validate.ts +83 -83
  58. package/src/sqlite/adapter.ts +26 -26
  59. package/src/sqlite/batch.ts +242 -242
  60. package/src/sqlite/catalog.ts +105 -108
  61. package/src/sqlite/connection.ts +227 -227
  62. package/src/sqlite/index-coverage.ts +54 -56
  63. package/src/sqlite/native.ts +84 -83
  64. package/src/sqlite/row-codec.ts +217 -221
  65. package/src/sqlite/sql-builder.ts +244 -244
  66. package/src/sqlite/transaction-queue.ts +87 -87
  67. package/src/sqlite/transactions.ts +33 -33
  68. package/src/sqlite/values.ts +24 -24
  69. package/src/testing/conformance/attachments.ts +139 -136
  70. package/src/testing/conformance/encryption.ts +151 -150
  71. package/src/testing/conformance/index.ts +161 -161
  72. package/src/testing/conformance/lifecycle.ts +99 -99
  73. package/src/testing/conformance/migrations.ts +177 -177
  74. package/src/testing/conformance/queries.ts +204 -167
  75. package/src/testing/conformance/records.ts +169 -169
  76. package/src/testing/conformance/scopes.ts +86 -88
  77. package/src/testing/conformance/transactions.ts +149 -149
  78. package/src/testing/faults.ts +21 -21
  79. package/src/testing/index.ts +17 -21
  80. package/src/testing/memory-adapter/collection.ts +214 -219
  81. package/src/testing/memory-adapter/index.ts +511 -492
  82. package/src/testing/memory-adapter/migrations.ts +117 -119
  83. package/src/testing/memory-adapter/reset.ts +50 -50
  84. package/src/testing/memory-adapter/store.ts +128 -134
@@ -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
- name: string,
45
- ): CollectionOps<T>;
46
- transaction<R>(fn: (tx: Transaction) => Promise<R>): Promise<R>;
47
- batch(operations: BatchOperation[]): Promise<BatchOutcome>;
48
- attachments(): Attachments;
49
- /** Development-mode index coverage answer (FR-037). */
50
- explain(collection: string, query?: Query): Promise<IndexCoverageReport>;
51
- close(): Promise<void>;
52
- };
53
-
54
- /**
55
- * What an implementation must provide. Deliberately lower-level than the
56
- * public surface: validation, budget checks, and error mapping happen once in
57
- * `adapter/`, above this line, so both implementations share them.
58
- */
59
- export type StorageAdapter = {
60
- readonly name: 'sqlite' | 'memory';
61
-
62
- open(config: DatabaseConfig): Promise<DatabaseHandle>;
63
- deleteScopeData(config: ScopeTargetConfig): Promise<DeletionOutcome>;
64
- deleteDatabase(config: DatabaseTargetConfig): Promise<DeletionOutcome>;
65
- /** The FR-057a recovery path. Never reachable from open(). */
66
- resetScope(config: ScopeTargetConfig): Promise<DeletionOutcome>;
67
- };
68
-
69
- export type {
70
- CollectionOps,
71
- FilterNode,
72
- Query,
73
- RecordInput,
74
- ResultPage,
75
- StoredRecord,
76
- Transaction,
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
- | 'available'
41
- | 'missing'
42
- | 'inaccessible'
43
- | 'undecryptable';
44
-
45
- export type AttachmentAvailability = {
46
- id: string;
47
- state: AttachmentAvailabilityState;
48
- size?: number;
49
- };
50
-
51
- export type ByteRange = {
52
- offset: number;
53
- length: number;
54
- };
55
-
56
- /**
57
- * Both directions of divergence between the database and the disk (FR-073d).
58
- */
59
- export type ReconciliationReport = {
60
- orphanedArtifacts: string[];
61
- danglingReferences: string[];
62
- removedArtifacts: string[];
63
- };
64
-
65
- /** Never a bare success (FR-065, FR-071). */
66
- export type DeletionOutcome = {
67
- scopeKey?: string;
68
- removedRecords: number;
69
- /**
70
- * True when the scope was deleted but its records could not be counted — an
71
- * encrypted scope whose key was unavailable, or a file that would not open.
72
- * `removedRecords` is then 0 and means "unknown". Added in 0.2.0.
73
- */
74
- recordCountUnavailable?: boolean;
75
- removedArtifacts: string[];
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
+ };
@@ -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
+ };
@@ -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
+ };