@braidlabs/data 0.1.1
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/package.json +41 -0
- package/src/index.d.ts +34 -0
- package/src/index.js +23 -0
- package/src/index.js.map +1 -0
- package/src/lib/adapters.d.ts +74 -0
- package/src/lib/adapters.js +10 -0
- package/src/lib/adapters.js.map +1 -0
- package/src/lib/events.d.ts +141 -0
- package/src/lib/events.js +337 -0
- package/src/lib/events.js.map +1 -0
- package/src/lib/flush.d.ts +49 -0
- package/src/lib/flush.js +60 -0
- package/src/lib/flush.js.map +1 -0
- package/src/lib/indexeddb-driver.d.ts +29 -0
- package/src/lib/indexeddb-driver.js +160 -0
- package/src/lib/indexeddb-driver.js.map +1 -0
- package/src/lib/intents.d.ts +83 -0
- package/src/lib/intents.js +136 -0
- package/src/lib/intents.js.map +1 -0
- package/src/lib/invalidation.d.ts +63 -0
- package/src/lib/invalidation.js +136 -0
- package/src/lib/invalidation.js.map +1 -0
- package/src/lib/locks.d.ts +43 -0
- package/src/lib/locks.js +78 -0
- package/src/lib/locks.js.map +1 -0
- package/src/lib/memory-driver.d.ts +10 -0
- package/src/lib/memory-driver.js +53 -0
- package/src/lib/memory-driver.js.map +1 -0
- package/src/lib/outbox.d.ts +146 -0
- package/src/lib/outbox.js +89 -0
- package/src/lib/outbox.js.map +1 -0
- package/src/lib/partitions.d.ts +70 -0
- package/src/lib/partitions.js +62 -0
- package/src/lib/partitions.js.map +1 -0
- package/src/lib/query.d.ts +235 -0
- package/src/lib/query.js +430 -0
- package/src/lib/query.js.map +1 -0
- package/src/lib/record-store.d.ts +125 -0
- package/src/lib/record-store.js +85 -0
- package/src/lib/record-store.js.map +1 -0
- package/src/lib/tenancy.d.ts +121 -0
- package/src/lib/tenancy.js +220 -0
- package/src/lib/tenancy.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../../../libs/data/src/lib/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { SkewResult, VersionedEnvelope, VersionedSchema } from '@braidlabs/skew';
|
|
2
|
+
/**
|
|
3
|
+
* A record-oriented store: many addressable records per collection, rather than one blob per key.
|
|
4
|
+
*
|
|
5
|
+
* This is the difference that matters, and it is not a preference. The existing `StorageDriver` is
|
|
6
|
+
* key→value, so a queue lives under one key and every append is a read-modify-write. Two contexts
|
|
7
|
+
* interleaving that lose a write — and **IndexedDB does not fix it**, because a KV shim makes `get`
|
|
8
|
+
* and `set` two separate transactions, so the race survives the driver swap.
|
|
9
|
+
*
|
|
10
|
+
* With addressable records the read disappears: append is `put`, remove is `delete`, and there is
|
|
11
|
+
* nothing to lose. That holds on any driver, at any number of realms or tabs.
|
|
12
|
+
*
|
|
13
|
+
* Every value is **enveloped** by `@braidlabs/skew` on the way in and projected on the way out.
|
|
14
|
+
* Persistence-first makes that non-negotiable rather than advisable: a record outlives the build
|
|
15
|
+
* that wrote it by arbitrary amounts, so the reader is routinely a different version from the
|
|
16
|
+
* writer, and there is no later moment at which envelopes can be added cheaply.
|
|
17
|
+
*/
|
|
18
|
+
/** A stored record, before projection. */
|
|
19
|
+
export interface StoredRecord {
|
|
20
|
+
/**
|
|
21
|
+
* Storage key: unique within the collection, and **partition-scoped**.
|
|
22
|
+
*
|
|
23
|
+
* Composed from the partition and the logical key rather than being the logical key itself.
|
|
24
|
+
* Without that, two tenants share one id space — `put` overwrites across the boundary and `get`
|
|
25
|
+
* reads across it, which quietly defeats the isolation partitions exist to provide. `list` was
|
|
26
|
+
* filtering correctly, which is exactly why the hole was easy to miss.
|
|
27
|
+
*/
|
|
28
|
+
id: string;
|
|
29
|
+
/** The caller's id, unique within its partition. */
|
|
30
|
+
key: string;
|
|
31
|
+
/** Tenant partition. Records never cross one — see `partition.ts`. */
|
|
32
|
+
partition: string;
|
|
33
|
+
/** Monotonic within a collection; gives FIFO order without a separate index. */
|
|
34
|
+
seq: number;
|
|
35
|
+
/** The `@braidlabs/skew` envelope. */
|
|
36
|
+
envelope: VersionedEnvelope;
|
|
37
|
+
/**
|
|
38
|
+
* Which fragment wrote it. Only that fragment may replay or reinterpret it — the reason a second
|
|
39
|
+
* app cannot drop the first's queued work.
|
|
40
|
+
*/
|
|
41
|
+
owner?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The storage primitive. Deliberately small, and deliberately *not* a transaction API: every
|
|
45
|
+
* operation here is a single-record write or a range read, which is what removes the need for
|
|
46
|
+
* transactions in the first place.
|
|
47
|
+
*/
|
|
48
|
+
export interface RecordDriver {
|
|
49
|
+
put(collection: string, record: StoredRecord): Promise<void>;
|
|
50
|
+
get(collection: string, id: string): Promise<StoredRecord | null>;
|
|
51
|
+
delete(collection: string, id: string): Promise<void>;
|
|
52
|
+
/** Records in a partition, ordered by `seq`. */
|
|
53
|
+
list(collection: string, partition: string): Promise<StoredRecord[]>;
|
|
54
|
+
/** Removes an entire partition. Used by sign-out; must be safe to re-run after interruption. */
|
|
55
|
+
clearPartition(collection: string, partition: string): Promise<void>;
|
|
56
|
+
/** Highest `seq` seen in a collection, so ordering survives a reload. */
|
|
57
|
+
highestSeq(collection: string): Promise<number>;
|
|
58
|
+
}
|
|
59
|
+
export interface RecordStoreOptions<T> {
|
|
60
|
+
driver: RecordDriver;
|
|
61
|
+
collection: string;
|
|
62
|
+
schema: VersionedSchema<T>;
|
|
63
|
+
/** Stamped onto envelopes so a bad record can be attributed to a deployment. */
|
|
64
|
+
buildId?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Called when a record cannot be projected to this reader's version. The default is silence —
|
|
67
|
+
* callers inspect the returned result — but wiring it to telemetry is how a wrong migration is
|
|
68
|
+
* discovered before users report it.
|
|
69
|
+
*/
|
|
70
|
+
onReadFailure?: (id: string, failure: Extract<SkewResult<never>, {
|
|
71
|
+
ok: false;
|
|
72
|
+
}>) => void;
|
|
73
|
+
}
|
|
74
|
+
/** A record as this reader sees it, with the provenance of getting it here. */
|
|
75
|
+
export interface ProjectedRecord<T> {
|
|
76
|
+
id: string;
|
|
77
|
+
partition: string;
|
|
78
|
+
seq: number;
|
|
79
|
+
owner?: string;
|
|
80
|
+
value: T;
|
|
81
|
+
/** Set when the record was older than this reader and was migrated up. */
|
|
82
|
+
migratedFrom: number | null;
|
|
83
|
+
/** Set when the record was newer and was projected down — `value` is honest but lossy. */
|
|
84
|
+
downgradedFrom: number | null;
|
|
85
|
+
/** Paths whose values are the migration's guesses rather than what the writer recorded. */
|
|
86
|
+
derivedPaths: readonly string[];
|
|
87
|
+
/** Paths a down-projection discarded. */
|
|
88
|
+
lossyPaths: readonly string[];
|
|
89
|
+
}
|
|
90
|
+
export interface RecordStore<T> {
|
|
91
|
+
put(input: {
|
|
92
|
+
id: string;
|
|
93
|
+
partition: string;
|
|
94
|
+
value: T;
|
|
95
|
+
owner?: string;
|
|
96
|
+
seq?: number;
|
|
97
|
+
}): Promise<number>;
|
|
98
|
+
/** Partition-scoped: an id alone does not identify a record. */
|
|
99
|
+
get(id: string, partition: string): Promise<ProjectedRecord<T> | null>;
|
|
100
|
+
/** Every readable record in a partition, in `seq` order. Unreadable ones are reported, not thrown. */
|
|
101
|
+
list(partition: string): Promise<ProjectedRecord<T>[]>;
|
|
102
|
+
delete(id: string, partition: string): Promise<void>;
|
|
103
|
+
clearPartition(partition: string): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* Records that could not be projected to this reader, with why.
|
|
106
|
+
*
|
|
107
|
+
* Separate from `list` on purpose: a caller iterating records should not have to filter failures
|
|
108
|
+
* out of the same array, and a failure that is merely absent from a list is a failure nobody
|
|
109
|
+
* notices.
|
|
110
|
+
*/
|
|
111
|
+
unreadable(partition: string): Promise<{
|
|
112
|
+
id: string;
|
|
113
|
+
failure: Extract<SkewResult<never>, {
|
|
114
|
+
ok: false;
|
|
115
|
+
}>;
|
|
116
|
+
}[]>;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Partition-scoped storage key. The separator cannot appear in either half by construction.
|
|
120
|
+
*
|
|
121
|
+
* Exported because moving a record between partitions means rewriting exactly this — and a second
|
|
122
|
+
* implementation of the composition rule is a silent way to lose records to a key nobody looks up.
|
|
123
|
+
*/
|
|
124
|
+
export declare function storageKey(partition: string, key: string): string;
|
|
125
|
+
export declare function createRecordStore<T>(options: RecordStoreOptions<T>): RecordStore<T>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Partition-scoped storage key. The separator cannot appear in either half by construction.
|
|
3
|
+
*
|
|
4
|
+
* Exported because moving a record between partitions means rewriting exactly this — and a second
|
|
5
|
+
* implementation of the composition rule is a silent way to lose records to a key nobody looks up.
|
|
6
|
+
*/
|
|
7
|
+
export function storageKey(partition, key) {
|
|
8
|
+
return `${partition}\u0000${key}`;
|
|
9
|
+
}
|
|
10
|
+
export function createRecordStore(options) {
|
|
11
|
+
const { driver, collection, schema, buildId, onReadFailure } = options;
|
|
12
|
+
// Cached rather than read per write: `highestSeq` is a full scan on some drivers, and ordering
|
|
13
|
+
// only needs to be monotonic within a process — gaps from a concurrent writer are harmless
|
|
14
|
+
// because nothing derives meaning from consecutive numbers.
|
|
15
|
+
let sequence = null;
|
|
16
|
+
/**
|
|
17
|
+
* Allocates the next sequence number.
|
|
18
|
+
*
|
|
19
|
+
* Chained rather than read-then-written, and the distinction is not cosmetic: an `await` between
|
|
20
|
+
* reading the counter and advancing it lets every concurrent caller observe the same value, so
|
|
21
|
+
* fifty parallel appends take fifty copies of one number. Verified against real IndexedDB — the
|
|
22
|
+
* in-memory tests resolved too fast to interleave and reported it as correct.
|
|
23
|
+
*
|
|
24
|
+
* Assigning the chain synchronously means the next caller extends *this* call's promise instead
|
|
25
|
+
* of racing it, so each gets a distinct number with no lock.
|
|
26
|
+
*/
|
|
27
|
+
function allocateSeq() {
|
|
28
|
+
sequence = (sequence ?? driver.highestSeq(collection)).then((last) => last + 1);
|
|
29
|
+
return sequence;
|
|
30
|
+
}
|
|
31
|
+
function project(record) {
|
|
32
|
+
const result = schema.read(record.envelope);
|
|
33
|
+
if (!result.ok) {
|
|
34
|
+
// The caller's id, not the storage key — a diagnostic naming an internal composite is a
|
|
35
|
+
// diagnostic the caller cannot act on.
|
|
36
|
+
onReadFailure?.(record.key, result);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
id: record.key,
|
|
41
|
+
partition: record.partition,
|
|
42
|
+
seq: record.seq,
|
|
43
|
+
...(record.owner === undefined ? {} : { owner: record.owner }),
|
|
44
|
+
value: result.value,
|
|
45
|
+
migratedFrom: result.migratedFrom,
|
|
46
|
+
downgradedFrom: result.downgradedFrom,
|
|
47
|
+
derivedPaths: result.derivedPaths,
|
|
48
|
+
lossyPaths: result.lossyPaths,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
async put({ id, partition, value, owner, seq }) {
|
|
53
|
+
const assigned = seq ?? (await allocateSeq());
|
|
54
|
+
await driver.put(collection, {
|
|
55
|
+
id: storageKey(partition, id),
|
|
56
|
+
key: id,
|
|
57
|
+
partition,
|
|
58
|
+
seq: assigned,
|
|
59
|
+
envelope: buildId ? schema.write(value, buildId) : schema.write(value),
|
|
60
|
+
...(owner === undefined ? {} : { owner }),
|
|
61
|
+
});
|
|
62
|
+
return assigned;
|
|
63
|
+
},
|
|
64
|
+
async get(id, partition) {
|
|
65
|
+
const record = await driver.get(collection, storageKey(partition, id));
|
|
66
|
+
return record ? project(record) : null;
|
|
67
|
+
},
|
|
68
|
+
async list(partition) {
|
|
69
|
+
const records = await driver.list(collection, partition);
|
|
70
|
+
return records.map(project).filter((record) => record !== null);
|
|
71
|
+
},
|
|
72
|
+
async unreadable(partition) {
|
|
73
|
+
const failures = [];
|
|
74
|
+
for (const record of await driver.list(collection, partition)) {
|
|
75
|
+
const result = schema.read(record.envelope);
|
|
76
|
+
if (!result.ok)
|
|
77
|
+
failures.push({ id: record.key, failure: result });
|
|
78
|
+
}
|
|
79
|
+
return failures;
|
|
80
|
+
},
|
|
81
|
+
delete: (id, partition) => driver.delete(collection, storageKey(partition, id)),
|
|
82
|
+
clearPartition: (partition) => driver.clearPartition(collection, partition),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=record-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-store.js","sourceRoot":"","sources":["../../../../../libs/data/src/lib/record-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { type CopyPartitionResult, type PartitionConflictPolicy } from './partitions.js';
|
|
2
|
+
import { type RecordDriver } from './record-store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Tenancy: which partition is live, and what sign-out actually destroys.
|
|
5
|
+
*
|
|
6
|
+
* Two identities change independently and both belong in the key:
|
|
7
|
+
*
|
|
8
|
+
* - the **authentication principal** — who is signed in; changing it is a login
|
|
9
|
+
* - the **acting-as tenant** — whose data is being viewed; changing it is a switch
|
|
10
|
+
*
|
|
11
|
+
* partition = hash(userId, actingAs)
|
|
12
|
+
*
|
|
13
|
+
* `actingAs` is part of the key rather than a dimension inside it. The cost is real — genuinely
|
|
14
|
+
* shared reference data is fetched once per tenant instead of once — and it buys the property that
|
|
15
|
+
* makes persistence-first defensible: a partition is **fully self-contained**. No read crosses a
|
|
16
|
+
* tenant boundary, so switching is a pointer move, purge is complete by construction, and there is
|
|
17
|
+
* no shared slice whose lifetime has to be reasoned about apart from the partitions referencing it.
|
|
18
|
+
*
|
|
19
|
+
* **Encryption at rest is deliberately not here.** A browser key has to live somewhere, and a
|
|
20
|
+
* non-extractable `CryptoKey` in IndexedDB defends against casual inspection but not against code
|
|
21
|
+
* running on the origin — which, on a page composing several fragments, is the realistic threat.
|
|
22
|
+
* Purge-on-sign-out is the honest control; encryption beside it would be theatre.
|
|
23
|
+
*/
|
|
24
|
+
export interface Principal {
|
|
25
|
+
/** Who is signed in. */
|
|
26
|
+
userId: string;
|
|
27
|
+
/** Whose data is being viewed. Defaults to the user acting as themselves. */
|
|
28
|
+
actingAs?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface TenancyOptions {
|
|
31
|
+
driver: RecordDriver;
|
|
32
|
+
/**
|
|
33
|
+
* Every collection a partition's records can live in.
|
|
34
|
+
*
|
|
35
|
+
* Enumerated rather than discovered, because a purge that quietly misses a collection is
|
|
36
|
+
* indistinguishable from a purge that worked — until the next user opens the page.
|
|
37
|
+
*/
|
|
38
|
+
collections: readonly string[];
|
|
39
|
+
/** Where tenancy's own bookkeeping lives. Never holds application data. */
|
|
40
|
+
metaCollection?: string;
|
|
41
|
+
buildId?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface Tenancy {
|
|
44
|
+
/**
|
|
45
|
+
* The live partition key.
|
|
46
|
+
*
|
|
47
|
+
* Throws when nobody is signed in, and throws when the active partition is poisoned. Both are
|
|
48
|
+
* refusals to serve rather than empty results: a read that silently returns nothing after
|
|
49
|
+
* sign-out looks exactly like a user with no data.
|
|
50
|
+
*/
|
|
51
|
+
partition(): string;
|
|
52
|
+
/** Who is signed in, and as whom. */
|
|
53
|
+
current(): Principal | null;
|
|
54
|
+
/** Activates a principal's partition, recovering any interrupted purge first. */
|
|
55
|
+
signIn(principal: Principal): Promise<string>;
|
|
56
|
+
/** Views another tenant's data. A pointer move — the previous partition stays warm on disk. */
|
|
57
|
+
switchTenant(actingAs: string): Promise<string>;
|
|
58
|
+
/**
|
|
59
|
+
* Purges every partition belonging to the signed-in user, then refuses reads.
|
|
60
|
+
*
|
|
61
|
+
* Session expiry calls this too: an expired session is not a reason to keep the data readable.
|
|
62
|
+
*/
|
|
63
|
+
signOut(): Promise<void>;
|
|
64
|
+
/** Re-runs any purge that was interrupted. Called by `signIn`; exposed for start-up. */
|
|
65
|
+
recover(): Promise<void>;
|
|
66
|
+
/** Notified with the new partition, or `null` when nobody is signed in. */
|
|
67
|
+
subscribe(listener: (partition: string | null) => void): () => void;
|
|
68
|
+
/**
|
|
69
|
+
* Brings another partition's records into the active one — the guest who just signed in.
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* const guest = await tenancy.signIn({ userId: `guest:${deviceId}` });
|
|
73
|
+
* // …they shop, then sign in…
|
|
74
|
+
* await tenancy.signIn({ userId: 'user:ana' });
|
|
75
|
+
* await tenancy.adopt(guest, { collections: ['cart'], mode: 'move' });
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* Deliberate rather than automatic. Whether a guest's basket should follow them into an account
|
|
79
|
+
* that may already have one is a question about *your* product — prices, stock reservations, and
|
|
80
|
+
* whose cart wins — and a data layer that answered it for you would be answering it wrong for
|
|
81
|
+
* somebody.
|
|
82
|
+
*/
|
|
83
|
+
adopt(from: string, options?: AdoptOptions): Promise<CopyPartitionResult>;
|
|
84
|
+
}
|
|
85
|
+
export interface AdoptOptions {
|
|
86
|
+
/** Which collections follow the person. Defaults to every collection this tenancy manages. */
|
|
87
|
+
collections?: readonly string[];
|
|
88
|
+
/** Defaults to `'skip'` — the signed-in account's own records win. */
|
|
89
|
+
onConflict?: PartitionConflictPolicy;
|
|
90
|
+
/** `'move'` clears the source afterwards. Defaults to `'copy'`. */
|
|
91
|
+
mode?: 'copy' | 'move';
|
|
92
|
+
}
|
|
93
|
+
interface TenancyRecordV1 {
|
|
94
|
+
/** `partition` records what exists; `purge` records what is mid-destruction. */
|
|
95
|
+
kind: 'partition' | 'purge';
|
|
96
|
+
userId: string;
|
|
97
|
+
actingAs?: string;
|
|
98
|
+
partition?: string;
|
|
99
|
+
partitions?: string[];
|
|
100
|
+
at: string;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Bookkeeping is enveloped like everything else.
|
|
104
|
+
*
|
|
105
|
+
* It outlives builds for the same reason application records do: a user signs out on a deploy that
|
|
106
|
+
* is not the one which wrote the marker, and an unversioned marker is precisely the record whose
|
|
107
|
+
* misreading would skip a purge.
|
|
108
|
+
*/
|
|
109
|
+
export declare const TenancyRecordSchema: import("@braidlabs/skew").VersionedSchema<TenancyRecordV1>;
|
|
110
|
+
export declare function createTenancy(options: TenancyOptions): Tenancy;
|
|
111
|
+
/**
|
|
112
|
+
* The partition key: `hash(userId, actingAs)`.
|
|
113
|
+
*
|
|
114
|
+
* FNV-1a rather than SHA-256 because this is a namespace, not a secret. It has to be synchronous —
|
|
115
|
+
* `partition()` is called on every read — and `crypto.subtle` is not. What hashing does buy is that
|
|
116
|
+
* user and tenant identifiers stay out of every storage key, which is what someone reading the
|
|
117
|
+
* IndexedDB pane sees; the one bookkeeping record that does hold them is itself destroyed at
|
|
118
|
+
* sign-out.
|
|
119
|
+
*/
|
|
120
|
+
export declare function partitionKey(userId: string, actingAs?: string): string;
|
|
121
|
+
export {};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { versioned } from '@braidlabs/skew';
|
|
2
|
+
import { withLock } from './locks.js';
|
|
3
|
+
import { copyPartition } from './partitions.js';
|
|
4
|
+
import { createRecordStore } from './record-store.js';
|
|
5
|
+
/**
|
|
6
|
+
* Bookkeeping is enveloped like everything else.
|
|
7
|
+
*
|
|
8
|
+
* It outlives builds for the same reason application records do: a user signs out on a deploy that
|
|
9
|
+
* is not the one which wrote the marker, and an unversioned marker is precisely the record whose
|
|
10
|
+
* misreading would skip a purge.
|
|
11
|
+
*/
|
|
12
|
+
export const TenancyRecordSchema = versioned('skew-tenancy-record');
|
|
13
|
+
const DEFAULT_META_COLLECTION = 'skew-tenancy';
|
|
14
|
+
/** Bookkeeping is not tenant data, so it lives in a partition of its own. */
|
|
15
|
+
const META_PARTITION = 'meta';
|
|
16
|
+
export function createTenancy(options) {
|
|
17
|
+
const store = createRecordStore({
|
|
18
|
+
driver: options.driver,
|
|
19
|
+
collection: options.metaCollection ?? DEFAULT_META_COLLECTION,
|
|
20
|
+
schema: TenancyRecordSchema,
|
|
21
|
+
...(options.buildId === undefined ? {} : { buildId: options.buildId }),
|
|
22
|
+
});
|
|
23
|
+
const listeners = new Set();
|
|
24
|
+
const poisoned = new Set();
|
|
25
|
+
let principal = null;
|
|
26
|
+
let active = null;
|
|
27
|
+
const notify = () => {
|
|
28
|
+
for (const listener of [...listeners])
|
|
29
|
+
listener(active);
|
|
30
|
+
};
|
|
31
|
+
async function markPartition(userId, actingAs, partition) {
|
|
32
|
+
await store.put({
|
|
33
|
+
id: `partition:${partition}`,
|
|
34
|
+
partition: META_PARTITION,
|
|
35
|
+
value: { kind: 'partition', userId, actingAs, partition, at: new Date().toISOString() },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Destroys the listed partitions across every collection, marker first.
|
|
40
|
+
*
|
|
41
|
+
* The marker is written **before** the first delete and removed after the last, so an interruption
|
|
42
|
+
* anywhere in between is discoverable. A purge that crashes halfway with no record of having
|
|
43
|
+
* started is the failure this exists to prevent: the partition would come back on the next open,
|
|
44
|
+
* half-emptied and served as if it were whole.
|
|
45
|
+
*/
|
|
46
|
+
async function purge(userId, partitions) {
|
|
47
|
+
if (partitions.length === 0)
|
|
48
|
+
return;
|
|
49
|
+
const markerId = `purge:${userId}`;
|
|
50
|
+
await store.put({
|
|
51
|
+
id: markerId,
|
|
52
|
+
partition: META_PARTITION,
|
|
53
|
+
value: { kind: 'purge', userId, partitions: [...partitions], at: new Date().toISOString() },
|
|
54
|
+
});
|
|
55
|
+
const cleared = [];
|
|
56
|
+
try {
|
|
57
|
+
for (const partition of partitions) {
|
|
58
|
+
for (const collection of options.collections) {
|
|
59
|
+
await options.driver.clearPartition(collection, partition);
|
|
60
|
+
}
|
|
61
|
+
await store.delete(`partition:${partition}`, META_PARTITION);
|
|
62
|
+
poisoned.delete(partition);
|
|
63
|
+
cleared.push(partition);
|
|
64
|
+
}
|
|
65
|
+
await store.delete(markerId, META_PARTITION);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
// The marker stays. Everything it names is unservable until a later `recover()` finishes the
|
|
69
|
+
// job — a partially purged partition must never be read, and the marker is the only durable
|
|
70
|
+
// evidence that it is partial.
|
|
71
|
+
for (const partition of partitions) {
|
|
72
|
+
if (!cleared.includes(partition))
|
|
73
|
+
poisoned.add(partition);
|
|
74
|
+
}
|
|
75
|
+
endSessionIfPurged(cleared);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
endSessionIfPurged(cleared);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A sign-out anywhere ends the session everywhere.
|
|
82
|
+
*
|
|
83
|
+
* The other tab that was reading this partition when it was destroyed holds a principal in memory
|
|
84
|
+
* and no reason to doubt it. Left alone it would keep serving a partition that no longer exists,
|
|
85
|
+
* which is a signed-out user still looking at their data — so the tab that discovers the purge
|
|
86
|
+
* ends its own session too. A partition that was *not* confirmed cleared is handled by `poisoned`
|
|
87
|
+
* instead: that one is refused rather than forgotten, because we cannot claim it is gone.
|
|
88
|
+
*/
|
|
89
|
+
function endSessionIfPurged(cleared) {
|
|
90
|
+
if (!active || !cleared.includes(active))
|
|
91
|
+
return;
|
|
92
|
+
principal = null;
|
|
93
|
+
active = null;
|
|
94
|
+
notify();
|
|
95
|
+
}
|
|
96
|
+
async function recover() {
|
|
97
|
+
const records = await store.list(META_PARTITION);
|
|
98
|
+
const markers = records.filter((record) => record.value.kind === 'purge');
|
|
99
|
+
// A sign-out that *succeeded* elsewhere leaves no marker — it leaves an absence. The partition
|
|
100
|
+
// record is what registration wrote, so its disappearance is how another tab learns its session
|
|
101
|
+
// is over. Checked before the markers, because a failed purge is the noisier case and would
|
|
102
|
+
// otherwise mask this quieter one.
|
|
103
|
+
if (active && !records.some((record) => record.value.kind === 'partition' && record.value.partition === active)) {
|
|
104
|
+
principal = null;
|
|
105
|
+
active = null;
|
|
106
|
+
notify();
|
|
107
|
+
}
|
|
108
|
+
for (const marker of markers) {
|
|
109
|
+
// Poisoned before the attempt, so a second failure leaves the partitions no more readable
|
|
110
|
+
// than the first did.
|
|
111
|
+
for (const partition of marker.value.partitions ?? [])
|
|
112
|
+
poisoned.add(partition);
|
|
113
|
+
await purge(marker.value.userId, marker.value.partitions ?? []);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function activate(next) {
|
|
117
|
+
const actingAs = next.actingAs ?? next.userId;
|
|
118
|
+
const partition = partitionKey(next.userId, actingAs);
|
|
119
|
+
await markPartition(next.userId, actingAs, partition);
|
|
120
|
+
principal = { userId: next.userId, actingAs };
|
|
121
|
+
active = partition;
|
|
122
|
+
notify();
|
|
123
|
+
return partition;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
partition() {
|
|
127
|
+
if (!active || !principal) {
|
|
128
|
+
throw new Error('[skew/data] no partition is active: sign in before reading. Reads are refused rather ' +
|
|
129
|
+
'than answered with nothing, because an empty result after sign-out is indistinguishable ' +
|
|
130
|
+
'from a user who has no data.');
|
|
131
|
+
}
|
|
132
|
+
if (poisoned.has(active)) {
|
|
133
|
+
throw new Error(`[skew/data] partition "${active}" was left half-purged by an interrupted sign-out and ` +
|
|
134
|
+
'cannot be served. Call recover() — it finishes the purge — then sign in again.');
|
|
135
|
+
}
|
|
136
|
+
return active;
|
|
137
|
+
},
|
|
138
|
+
current: () => (principal ? { ...principal } : null),
|
|
139
|
+
async signIn(next) {
|
|
140
|
+
// Before activation, not after: a partition still named by a marker must not be readable for
|
|
141
|
+
// the window between signing in and noticing.
|
|
142
|
+
await recover();
|
|
143
|
+
return activate(next);
|
|
144
|
+
},
|
|
145
|
+
async switchTenant(actingAs) {
|
|
146
|
+
if (!principal) {
|
|
147
|
+
throw new Error('[skew/data] cannot switch tenant before signing in');
|
|
148
|
+
}
|
|
149
|
+
// The previous partition is left exactly as it is. Warm on disk is the point: coming back to
|
|
150
|
+
// it should not re-fetch what was already fetched.
|
|
151
|
+
return activate({ userId: principal.userId, actingAs });
|
|
152
|
+
},
|
|
153
|
+
async signOut() {
|
|
154
|
+
const signedIn = principal;
|
|
155
|
+
// Cleared first, so nothing reads through the partition while it is being destroyed.
|
|
156
|
+
principal = null;
|
|
157
|
+
active = null;
|
|
158
|
+
notify();
|
|
159
|
+
if (!signedIn)
|
|
160
|
+
return;
|
|
161
|
+
// Held across tabs: a second tab that signs in mid-purge would otherwise re-register the
|
|
162
|
+
// partition being destroyed and serve what is left of it.
|
|
163
|
+
const outcome = await withLock(`skew:data:purge:${signedIn.userId}`, async () => {
|
|
164
|
+
const records = await store.list(META_PARTITION);
|
|
165
|
+
const partitions = records
|
|
166
|
+
.filter((record) => record.value.kind === 'partition' && record.value.userId === signedIn.userId)
|
|
167
|
+
.map((record) => record.value.partition)
|
|
168
|
+
.filter(Boolean);
|
|
169
|
+
await purge(signedIn.userId, partitions);
|
|
170
|
+
}, { ifAvailable: false });
|
|
171
|
+
// `ifAvailable: false` waits for the holder, so this only happens if the environment has no
|
|
172
|
+
// lock manager at all — in which case the purge has not run and must not be reported as done.
|
|
173
|
+
if (!outcome.acquired) {
|
|
174
|
+
throw new Error('[skew/data] sign-out could not take the purge lock; the data was not purged');
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
recover,
|
|
178
|
+
subscribe(listener) {
|
|
179
|
+
listeners.add(listener);
|
|
180
|
+
listener(active);
|
|
181
|
+
return () => void listeners.delete(listener);
|
|
182
|
+
},
|
|
183
|
+
async adopt(from, adoptOptions) {
|
|
184
|
+
if (!active || !principal) {
|
|
185
|
+
throw new Error('[skew/data] cannot adopt a partition before signing in: there is no destination to ' +
|
|
186
|
+
'copy into. Sign the user in first, then adopt what their guest session left behind.');
|
|
187
|
+
}
|
|
188
|
+
return copyPartition({
|
|
189
|
+
driver: options.driver,
|
|
190
|
+
from,
|
|
191
|
+
to: active,
|
|
192
|
+
collections: adoptOptions?.collections ?? options.collections,
|
|
193
|
+
...(adoptOptions?.onConflict === undefined ? {} : { onConflict: adoptOptions.onConflict }),
|
|
194
|
+
...(adoptOptions?.mode === undefined ? {} : { mode: adoptOptions.mode }),
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The partition key: `hash(userId, actingAs)`.
|
|
201
|
+
*
|
|
202
|
+
* FNV-1a rather than SHA-256 because this is a namespace, not a secret. It has to be synchronous —
|
|
203
|
+
* `partition()` is called on every read — and `crypto.subtle` is not. What hashing does buy is that
|
|
204
|
+
* user and tenant identifiers stay out of every storage key, which is what someone reading the
|
|
205
|
+
* IndexedDB pane sees; the one bookkeeping record that does hold them is itself destroyed at
|
|
206
|
+
* sign-out.
|
|
207
|
+
*/
|
|
208
|
+
export function partitionKey(userId, actingAs = userId) {
|
|
209
|
+
return `p_${fnv1a(userId)}_${fnv1a(actingAs)}`;
|
|
210
|
+
}
|
|
211
|
+
function fnv1a(value) {
|
|
212
|
+
let hash = 0x811c9dc5;
|
|
213
|
+
for (let i = 0; i < value.length; i++) {
|
|
214
|
+
hash ^= value.charCodeAt(i);
|
|
215
|
+
// The shifts are FNV's 32-bit prime multiply; `>>> 0` keeps it unsigned after each round.
|
|
216
|
+
hash = (hash + ((hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24))) >>> 0;
|
|
217
|
+
}
|
|
218
|
+
return hash.toString(16).padStart(8, '0');
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=tenancy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenancy.js","sourceRoot":"","sources":["../../../../../libs/data/src/lib/tenancy.ts"],"names":[],"mappings":"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"}
|