@amalgm/live 0.2.81-main.41026618671 → 0.2.81-main.41264653147

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.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The History SDK: the rule bound to one cloud authority's store.
3
+ *
4
+ * Event-driven: the authority calls `accepted` once per accepted record,
5
+ * which schedules the one release that acceptance fixes, and arms one timer
6
+ * at `nextDueAt`. `cleanup` runs when that timer fires. Nothing polls.
7
+ */
8
+ import type { Cleanup, HistoryPorts, HistoryVersion, JudgedVersion, Release } from './types.js';
9
+ interface History {
10
+ /** The versions of one entity that can still be got back, oldest first. */
11
+ versions(entityId: string): Promise<JudgedVersion[]>;
12
+ /** The authority accepted `version`: schedule the release it fixes. */
13
+ accepted(version: HistoryVersion): Promise<Release | null>;
14
+ /** Release every version now due, then drop every artifact nothing holds. */
15
+ cleanup(): Promise<Cleanup>;
16
+ }
17
+ declare function createHistory({ store, now }: HistoryPorts): History;
18
+ export { createHistory };
19
+ export type { History };
20
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/history/history.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAKhG,UAAU,OAAO;IACf,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACrD,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC3D,6EAA6E;IAC7E,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7B;AAED,iBAAS,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,YAAY,GAAG,OAAO,CAqC5D;AAED,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,YAAY,EAAE,OAAO,EAAE,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The History SDK: the rule bound to one cloud authority's store.
3
+ *
4
+ * Event-driven: the authority calls `accepted` once per accepted record,
5
+ * which schedules the one release that acceptance fixes, and arms one timer
6
+ * at `nextDueAt`. `cleanup` runs when that timer fires. Nothing polls.
7
+ */
8
+ import { judge, releaseFixedBy } from './rule.js';
9
+ /** Releases or artifacts read in one store call. */
10
+ const BATCH = 256;
11
+ function createHistory({ store, now }) {
12
+ return {
13
+ async versions(entityId) {
14
+ return judge(await store.versions(entityId), now()).filter(version => version.state !== 'gone');
15
+ },
16
+ async accepted(version) {
17
+ const release = await releaseFixedBy(version, async (sequence) => {
18
+ const earlier = await store.version(version.entityId, sequence);
19
+ if (earlier === null)
20
+ throw new Error(`version ${sequence} of ${version.entityId} was never accepted`);
21
+ return earlier;
22
+ });
23
+ if (release !== null)
24
+ await store.schedule(release);
25
+ return release;
26
+ },
27
+ async cleanup() {
28
+ const at = now();
29
+ let released = 0;
30
+ for (let due = await store.due(at, BATCH); due.length > 0; due = await store.due(at, BATCH)) {
31
+ for (const release of due)
32
+ await store.release(release.entityId, release.through);
33
+ released += due.length;
34
+ }
35
+ let dropped = 0;
36
+ let bytes = 0;
37
+ for (let queued = await store.queued(BATCH); queued.length > 0; queued = await store.queued(BATCH)) {
38
+ for (const artifact of queued) {
39
+ const result = await store.drop(artifact);
40
+ if (result.dropped) {
41
+ dropped += 1;
42
+ bytes += result.bytes;
43
+ }
44
+ }
45
+ }
46
+ return { released, dropped, bytes, nextDueAt: await store.nextDueAt() };
47
+ },
48
+ };
49
+ }
50
+ export { createHistory };
51
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/history/history.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGlD,oDAAoD;AACpD,MAAM,KAAK,GAAG,GAAG,CAAC;AAWlB,SAAS,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,EAAgB;IACjD,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,QAAQ;YACrB,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;QAClG,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,OAAO;YACpB,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;gBAC7D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBAChE,IAAI,OAAO,KAAK,IAAI;oBAAE,MAAM,IAAI,KAAK,CAAC,WAAW,QAAQ,OAAO,OAAO,CAAC,QAAQ,qBAAqB,CAAC,CAAC;gBACvG,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC,CAAC;YACH,IAAI,OAAO,KAAK,IAAI;gBAAE,MAAM,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACpD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,KAAK,CAAC,OAAO;YACX,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC;YACjB,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,KAAK,IAAI,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC5F,KAAK,MAAM,OAAO,IAAI,GAAG;oBAAE,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;gBAClF,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC;YACzB,CAAC;YACD,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnG,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;oBAC9B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC1C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;wBACnB,OAAO,IAAI,CAAC,CAAC;wBACb,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;oBACxB,CAAC;gBACH,CAAC;YACH,CAAC;YACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;QAC1E,CAAC;KACF,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Version history: the newest ten versions of every entity stay, so does
3
+ * every version replaced in the last thirty days, and each version neither
4
+ * keeps waits thirty days in version Trash before its bytes go. One rule for
5
+ * every type, one cleanup run, one timer.
6
+ */
7
+ export { createHistory } from './history.js';
8
+ export type { History } from './history.js';
9
+ export { KEEP_NEWEST, KEEP_REPLACED_MS, VERSION_TRASH_MS, judge, releaseFixedBy } from './rule.js';
10
+ export { versionOf } from './version.js';
11
+ export type { ArtifactRef, Cleanup, Dropped, HistoryPorts, HistoryStore, HistoryVersion, JudgedVersion, Release, VersionState, } from './types.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,YAAY,EACV,WAAW,EACX,OAAO,EACP,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,aAAa,EACb,OAAO,EACP,YAAY,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Version history: the newest ten versions of every entity stay, so does
3
+ * every version replaced in the last thirty days, and each version neither
4
+ * keeps waits thirty days in version Trash before its bytes go. One rule for
5
+ * every type, one cleanup run, one timer.
6
+ */
7
+ export { createHistory } from './history.js';
8
+ export { KEEP_NEWEST, KEEP_REPLACED_MS, VERSION_TRASH_MS, judge, releaseFixedBy } from './rule.js';
9
+ export { versionOf } from './version.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The version history rule, the same for every entity type:
3
+ *
4
+ * 1. the newest ten versions are kept, however old;
5
+ * 2. a version replaced in the last thirty days is kept;
6
+ * 3. a version neither rule keeps waits thirty days in version Trash, then
7
+ * goes.
8
+ *
9
+ * The current version is always kept. A permanent deletion keeps no history:
10
+ * every version before it goes when it is accepted.
11
+ *
12
+ * Time is the authority's acceptance time, never a device clock. Because a
13
+ * version's end depends only on the versions after it, accepting version `k`
14
+ * fixes exactly one end: that of version `k - 10`, the one it pushes out of
15
+ * the newest ten. Versions go oldest first.
16
+ */
17
+ import type { HistoryVersion, JudgedVersion, Release } from './types.js';
18
+ /** Rule 1: this many newest versions stay, however old. */
19
+ export declare const KEEP_NEWEST = 10;
20
+ /** Rule 2: a replaced version stays this long after it was replaced. */
21
+ export declare const KEEP_REPLACED_MS: number;
22
+ /** Rule 3: a version no rule keeps waits this long in version Trash. */
23
+ export declare const VERSION_TRASH_MS: number;
24
+ /**
25
+ * The one release accepting `version` fixes, or null when it fixes none yet.
26
+ * `versionAt` reads an earlier version of the same entity; only the one that
27
+ * replaced the version leaving the newest ten is read.
28
+ */
29
+ export declare function releaseFixedBy(version: HistoryVersion, versionAt: (sequence: number) => Promise<HistoryVersion>): Promise<Release | null>;
30
+ /**
31
+ * Every version of one entity as the rule stands at `now`: current, kept,
32
+ * trashed, or gone. `versions` runs in sequence order from any version to the
33
+ * newest; a version's end depends only on the versions after it, so released
34
+ * ones before need not be read.
35
+ */
36
+ export declare function judge(versions: readonly HistoryVersion[], now: number): JudgedVersion[];
37
+ //# sourceMappingURL=rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../src/history/rule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAIzE,2DAA2D;AAC3D,eAAO,MAAM,WAAW,KAAK,CAAC;AAE9B,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,QAAc,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,QAAc,CAAC;AAW5C;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,GACvD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CASzB;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,CAmBvF"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The version history rule, the same for every entity type:
3
+ *
4
+ * 1. the newest ten versions are kept, however old;
5
+ * 2. a version replaced in the last thirty days is kept;
6
+ * 3. a version neither rule keeps waits thirty days in version Trash, then
7
+ * goes.
8
+ *
9
+ * The current version is always kept. A permanent deletion keeps no history:
10
+ * every version before it goes when it is accepted.
11
+ *
12
+ * Time is the authority's acceptance time, never a device clock. Because a
13
+ * version's end depends only on the versions after it, accepting version `k`
14
+ * fixes exactly one end: that of version `k - 10`, the one it pushes out of
15
+ * the newest ten. Versions go oldest first.
16
+ */
17
+ const DAY_MS = 24 * 60 * 60 * 1000;
18
+ /** Rule 1: this many newest versions stay, however old. */
19
+ export const KEEP_NEWEST = 10;
20
+ /** Rule 2: a replaced version stays this long after it was replaced. */
21
+ export const KEEP_REPLACED_MS = 30 * DAY_MS;
22
+ /** Rule 3: a version no rule keeps waits this long in version Trash. */
23
+ export const VERSION_TRASH_MS = 30 * DAY_MS;
24
+ /**
25
+ * When a version leaves both keeping rules: thirty days after `next`
26
+ * replaced it, or when `tenth` pushed it out of the newest ten, whichever is
27
+ * later. It then waits in version Trash.
28
+ */
29
+ function keptUntil(next, tenth) {
30
+ return Math.max(next.acceptedAt + KEEP_REPLACED_MS, tenth.acceptedAt);
31
+ }
32
+ /**
33
+ * The one release accepting `version` fixes, or null when it fixes none yet.
34
+ * `versionAt` reads an earlier version of the same entity; only the one that
35
+ * replaced the version leaving the newest ten is read.
36
+ */
37
+ export async function releaseFixedBy(version, versionAt) {
38
+ const { entityId, sequence, acceptedAt } = version;
39
+ if (version.deleted) {
40
+ return sequence > 1 ? { entityId, through: sequence - 1, dueAt: acceptedAt } : null;
41
+ }
42
+ const leaving = sequence - KEEP_NEWEST;
43
+ if (leaving < 1)
44
+ return null;
45
+ const end = keptUntil(await versionAt(leaving + 1), version);
46
+ return { entityId, through: leaving, dueAt: end + VERSION_TRASH_MS };
47
+ }
48
+ /**
49
+ * Every version of one entity as the rule stands at `now`: current, kept,
50
+ * trashed, or gone. `versions` runs in sequence order from any version to the
51
+ * newest; a version's end depends only on the versions after it, so released
52
+ * ones before need not be read.
53
+ */
54
+ export function judge(versions, now) {
55
+ const count = versions.length;
56
+ const last = versions[count - 1];
57
+ const deletedAt = last?.deleted === true ? last.acceptedAt : null;
58
+ return versions.map((version, index) => {
59
+ if (index === count - 1)
60
+ return { ...version, state: 'current', trashedAt: null, goneAt: null };
61
+ if (deletedAt !== null) {
62
+ return { ...version, state: 'gone', trashedAt: deletedAt, goneAt: deletedAt };
63
+ }
64
+ const next = versions[index + 1];
65
+ const tenth = versions[index + KEEP_NEWEST];
66
+ if (tenth === undefined) {
67
+ return { ...version, state: 'kept', trashedAt: null, goneAt: null };
68
+ }
69
+ const trashedAt = keptUntil(next, tenth);
70
+ const goneAt = trashedAt + VERSION_TRASH_MS;
71
+ const state = now < trashedAt ? 'kept' : now < goneAt ? 'trashed' : 'gone';
72
+ return { ...version, state, trashedAt, goneAt };
73
+ });
74
+ }
75
+ //# sourceMappingURL=rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.js","sourceRoot":"","sources":["../../src/history/rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Version history: how long the cloud keeps each entity's earlier versions.
3
+ * A version is one accepted record on the entity's channel; its bytes are the
4
+ * one artifact that record names. History never writes records and never
5
+ * changes Watch, Detect, Record, Send, Receive, Apply or Verify. It reads
6
+ * what the authority accepted and lets go of bytes the rule no longer keeps.
7
+ */
8
+ import type { EntityType } from '../entities/types.js';
9
+ /** One accepted record, as history sees it. */
10
+ interface HistoryVersion {
11
+ readonly entityId: string;
12
+ /** The authority whose storage holds this version's bytes. */
13
+ readonly authorityId: string;
14
+ /** The record's dense sequence on its entity's channel, from 1. */
15
+ readonly sequence: number;
16
+ /** Authority acceptance time, never a device clock. */
17
+ readonly acceptedAt: number;
18
+ /** The artifact holding this version's bytes: a content hash, or null for
19
+ * a folder, workspace, reference, or permanent deletion. */
20
+ readonly content: string | null;
21
+ /** The entity's type at this version; a `repo.git` artifact is a link in
22
+ * its repository's chain. */
23
+ readonly type: EntityType;
24
+ /** A permanent deletion. Nothing follows it on its channel. */
25
+ readonly deleted: boolean;
26
+ }
27
+ /** One stored artifact: its content hash within its authority's storage. */
28
+ interface ArtifactRef {
29
+ readonly authorityId: string;
30
+ readonly contentHash: string;
31
+ }
32
+ type VersionState = 'current' | 'kept' | 'trashed' | 'gone';
33
+ /** A version and where the rule stands on it. `trashedAt` and `goneAt` are
34
+ * null until a later version fixes them. */
35
+ interface JudgedVersion extends HistoryVersion {
36
+ readonly state: VersionState;
37
+ readonly trashedAt: number | null;
38
+ readonly goneAt: number | null;
39
+ }
40
+ /** Versions 1 through `through` of one entity go at `dueAt`. */
41
+ interface Release {
42
+ readonly entityId: string;
43
+ readonly through: number;
44
+ readonly dueAt: number;
45
+ }
46
+ /** What one holding check did with one artifact: kept it, or deleted it
47
+ * and freed `bytes` of storage no remaining artifact uses. */
48
+ type Dropped = {
49
+ readonly dropped: false;
50
+ } | {
51
+ readonly dropped: true;
52
+ readonly bytes: number;
53
+ };
54
+ /**
55
+ * The cloud authority's side of history. Records and artifacts are the ones
56
+ * the authority already keeps; history adds a release schedule, a released
57
+ * mark on versions, and a queue of artifacts to check.
58
+ */
59
+ interface HistoryStore {
60
+ /** The versions of one entity not yet released, in sequence order. */
61
+ versions(entityId: string): Promise<HistoryVersion[]>;
62
+ /** One version, or null when the authority has not accepted it. */
63
+ version(entityId: string, sequence: number): Promise<HistoryVersion | null>;
64
+ /** Keep this release until it is due. Saving the same release again changes nothing. */
65
+ schedule(release: Release): Promise<void>;
66
+ /** Scheduled releases due by `now`, earliest first, at most `limit`. */
67
+ due(now: number, limit: number): Promise<Release[]>;
68
+ /** The earliest scheduled due time, or null when nothing is scheduled. */
69
+ nextDueAt(): Promise<number | null>;
70
+ /**
71
+ * In one transaction: mark versions 1 through `through` released, remove
72
+ * the releases this one covers, and queue every artifact a newly released
73
+ * version names. When the entity's newest version is a permanent deletion,
74
+ * also queue every Git artifact any of its versions named, which its chain
75
+ * held until then.
76
+ */
77
+ release(entityId: string, through: number): Promise<void>;
78
+ /** Queued artifacts, at most `limit`. */
79
+ queued(limit: number): Promise<ArtifactRef[]>;
80
+ /**
81
+ * In one transaction, atomic against acceptance and against sealing the
82
+ * same bytes again: unqueue `artifact`, and delete it when nothing holds
83
+ * it. It is held while
84
+ *
85
+ * - a version not yet released, of any entity, names it; or
86
+ * - it is a Git artifact of an entity not permanently deleted, since each
87
+ * later Git artifact is built on the one before it.
88
+ *
89
+ * Deleting it frees each of its blocks no remaining artifact uses. Nothing
90
+ * deleted can be sealed again until its bytes are gone from storage.
91
+ */
92
+ drop(artifact: ArtifactRef): Promise<Dropped>;
93
+ }
94
+ interface HistoryPorts {
95
+ readonly store: HistoryStore;
96
+ /** The authority's clock. */
97
+ now(): number;
98
+ }
99
+ /** What one cleanup run let go of, and when the next one is due. */
100
+ interface Cleanup {
101
+ readonly released: number;
102
+ readonly dropped: number;
103
+ readonly bytes: number;
104
+ readonly nextDueAt: number | null;
105
+ }
106
+ export type { ArtifactRef, Cleanup, Dropped, HistoryPorts, HistoryStore, HistoryVersion, JudgedVersion, Release, VersionState, };
107
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Version history: how long the cloud keeps each entity's earlier versions.
3
+ * A version is one accepted record on the entity's channel; its bytes are the
4
+ * one artifact that record names. History never writes records and never
5
+ * changes Watch, Detect, Record, Send, Receive, Apply or Verify. It reads
6
+ * what the authority accepted and lets go of bytes the rule no longer keeps.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,5 @@
1
+ /** One accepted record as a version: its place, its time, and its bytes. */
2
+ import type { AcceptedEntityRecord } from '../records/contracts.js';
3
+ import type { HistoryVersion } from './types.js';
4
+ export declare function versionOf(record: AcceptedEntityRecord): HistoryVersion;
5
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/history/version.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAE5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,SAAS,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc,CAWtE"}
@@ -0,0 +1,15 @@
1
+ /** One accepted record as a version: its place, its time, and its bytes. */
2
+ import { artifactForRecord } from '../transfer/artifacts.js';
3
+ export function versionOf(record) {
4
+ const result = record.change.result;
5
+ return {
6
+ entityId: record.entityId,
7
+ authorityId: record.authorityId,
8
+ sequence: record.globalSequence,
9
+ acceptedAt: record.acceptedAt,
10
+ content: artifactForRecord(result)?.contentHash ?? null,
11
+ type: result.type,
12
+ deleted: result.status === 'deleted',
13
+ };
14
+ }
15
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/history/version.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAG5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,MAAM,UAAU,SAAS,CAAC,MAA4B;IACpD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,MAAM,CAAC,cAAc;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,WAAW,IAAI,IAAI;QACvD,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,SAAS;KACrC,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -24,5 +24,6 @@ export * from './transfer/index.js';
24
24
  export * from './merge/index.js';
25
25
  export * from './workspace/index.js';
26
26
  export * from './sharing/index.js';
27
+ export * from './history/index.js';
27
28
  export * from './git/index.js';
28
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -24,5 +24,6 @@ export * from './transfer/index.js';
24
24
  export * from './merge/index.js';
25
25
  export * from './workspace/index.js';
26
26
  export * from './sharing/index.js';
27
+ export * from './history/index.js';
27
28
  export * from './git/index.js';
28
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * The History SDK: the rule bound to one cloud authority's store.
4
+ *
5
+ * Event-driven: the authority calls `accepted` once per accepted record,
6
+ * which schedules the one release that acceptance fixes, and arms one timer
7
+ * at `nextDueAt`. `cleanup` runs when that timer fires. Nothing polls.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.createHistory = createHistory;
11
+ const rule_js_1 = require("./rule.js");
12
+ /** Releases or artifacts read in one store call. */
13
+ const BATCH = 256;
14
+ function createHistory({ store, now }) {
15
+ return {
16
+ async versions(entityId) {
17
+ return (0, rule_js_1.judge)(await store.versions(entityId), now()).filter(version => version.state !== 'gone');
18
+ },
19
+ async accepted(version) {
20
+ const release = await (0, rule_js_1.releaseFixedBy)(version, async (sequence) => {
21
+ const earlier = await store.version(version.entityId, sequence);
22
+ if (earlier === null)
23
+ throw new Error(`version ${sequence} of ${version.entityId} was never accepted`);
24
+ return earlier;
25
+ });
26
+ if (release !== null)
27
+ await store.schedule(release);
28
+ return release;
29
+ },
30
+ async cleanup() {
31
+ const at = now();
32
+ let released = 0;
33
+ for (let due = await store.due(at, BATCH); due.length > 0; due = await store.due(at, BATCH)) {
34
+ for (const release of due)
35
+ await store.release(release.entityId, release.through);
36
+ released += due.length;
37
+ }
38
+ let dropped = 0;
39
+ let bytes = 0;
40
+ for (let queued = await store.queued(BATCH); queued.length > 0; queued = await store.queued(BATCH)) {
41
+ for (const artifact of queued) {
42
+ const result = await store.drop(artifact);
43
+ if (result.dropped) {
44
+ dropped += 1;
45
+ bytes += result.bytes;
46
+ }
47
+ }
48
+ }
49
+ return { released, dropped, bytes, nextDueAt: await store.nextDueAt() };
50
+ },
51
+ };
52
+ }
53
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/history/history.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAwDM,sCAAa;AAtDtB,uCAAkD;AAGlD,oDAAoD;AACpD,MAAM,KAAK,GAAG,GAAG,CAAC;AAWlB,SAAS,aAAa,CAAC,EAAE,KAAK,EAAE,GAAG,EAAgB;IACjD,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,QAAQ;YACrB,OAAO,IAAA,eAAK,EAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;QAClG,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,OAAO;YACpB,MAAM,OAAO,GAAG,MAAM,IAAA,wBAAc,EAAC,OAAO,EAAE,KAAK,EAAC,QAAQ,EAAC,EAAE;gBAC7D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBAChE,IAAI,OAAO,KAAK,IAAI;oBAAE,MAAM,IAAI,KAAK,CAAC,WAAW,QAAQ,OAAO,OAAO,CAAC,QAAQ,qBAAqB,CAAC,CAAC;gBACvG,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC,CAAC;YACH,IAAI,OAAO,KAAK,IAAI;gBAAE,MAAM,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACpD,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,KAAK,CAAC,OAAO;YACX,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC;YACjB,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,KAAK,IAAI,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC5F,KAAK,MAAM,OAAO,IAAI,GAAG;oBAAE,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;gBAClF,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC;YACzB,CAAC;YACD,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnG,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;oBAC9B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC1C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;wBACnB,OAAO,IAAI,CAAC,CAAC;wBACb,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;oBACxB,CAAC;gBACH,CAAC;YACH,CAAC;YACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;QAC1E,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ /**
3
+ * Version history: the newest ten versions of every entity stay, so does
4
+ * every version replaced in the last thirty days, and each version neither
5
+ * keeps waits thirty days in version Trash before its bytes go. One rule for
6
+ * every type, one cleanup run, one timer.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.versionOf = exports.releaseFixedBy = exports.judge = exports.VERSION_TRASH_MS = exports.KEEP_REPLACED_MS = exports.KEEP_NEWEST = exports.createHistory = void 0;
10
+ var history_js_1 = require("./history.js");
11
+ Object.defineProperty(exports, "createHistory", { enumerable: true, get: function () { return history_js_1.createHistory; } });
12
+ var rule_js_1 = require("./rule.js");
13
+ Object.defineProperty(exports, "KEEP_NEWEST", { enumerable: true, get: function () { return rule_js_1.KEEP_NEWEST; } });
14
+ Object.defineProperty(exports, "KEEP_REPLACED_MS", { enumerable: true, get: function () { return rule_js_1.KEEP_REPLACED_MS; } });
15
+ Object.defineProperty(exports, "VERSION_TRASH_MS", { enumerable: true, get: function () { return rule_js_1.VERSION_TRASH_MS; } });
16
+ Object.defineProperty(exports, "judge", { enumerable: true, get: function () { return rule_js_1.judge; } });
17
+ Object.defineProperty(exports, "releaseFixedBy", { enumerable: true, get: function () { return rule_js_1.releaseFixedBy; } });
18
+ var version_js_1 = require("./version.js");
19
+ Object.defineProperty(exports, "versionOf", { enumerable: true, get: function () { return version_js_1.versionOf; } });
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/history/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,2CAA6C;AAApC,2GAAA,aAAa,OAAA;AAEtB,qCAAmG;AAA1F,sGAAA,WAAW,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAAE,2GAAA,gBAAgB,OAAA;AAAE,gGAAA,KAAK,OAAA;AAAE,yGAAA,cAAc,OAAA;AAC/E,2CAAyC;AAAhC,uGAAA,SAAS,OAAA"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * The version history rule, the same for every entity type:
4
+ *
5
+ * 1. the newest ten versions are kept, however old;
6
+ * 2. a version replaced in the last thirty days is kept;
7
+ * 3. a version neither rule keeps waits thirty days in version Trash, then
8
+ * goes.
9
+ *
10
+ * The current version is always kept. A permanent deletion keeps no history:
11
+ * every version before it goes when it is accepted.
12
+ *
13
+ * Time is the authority's acceptance time, never a device clock. Because a
14
+ * version's end depends only on the versions after it, accepting version `k`
15
+ * fixes exactly one end: that of version `k - 10`, the one it pushes out of
16
+ * the newest ten. Versions go oldest first.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.VERSION_TRASH_MS = exports.KEEP_REPLACED_MS = exports.KEEP_NEWEST = void 0;
20
+ exports.releaseFixedBy = releaseFixedBy;
21
+ exports.judge = judge;
22
+ const DAY_MS = 24 * 60 * 60 * 1000;
23
+ /** Rule 1: this many newest versions stay, however old. */
24
+ exports.KEEP_NEWEST = 10;
25
+ /** Rule 2: a replaced version stays this long after it was replaced. */
26
+ exports.KEEP_REPLACED_MS = 30 * DAY_MS;
27
+ /** Rule 3: a version no rule keeps waits this long in version Trash. */
28
+ exports.VERSION_TRASH_MS = 30 * DAY_MS;
29
+ /**
30
+ * When a version leaves both keeping rules: thirty days after `next`
31
+ * replaced it, or when `tenth` pushed it out of the newest ten, whichever is
32
+ * later. It then waits in version Trash.
33
+ */
34
+ function keptUntil(next, tenth) {
35
+ return Math.max(next.acceptedAt + exports.KEEP_REPLACED_MS, tenth.acceptedAt);
36
+ }
37
+ /**
38
+ * The one release accepting `version` fixes, or null when it fixes none yet.
39
+ * `versionAt` reads an earlier version of the same entity; only the one that
40
+ * replaced the version leaving the newest ten is read.
41
+ */
42
+ async function releaseFixedBy(version, versionAt) {
43
+ const { entityId, sequence, acceptedAt } = version;
44
+ if (version.deleted) {
45
+ return sequence > 1 ? { entityId, through: sequence - 1, dueAt: acceptedAt } : null;
46
+ }
47
+ const leaving = sequence - exports.KEEP_NEWEST;
48
+ if (leaving < 1)
49
+ return null;
50
+ const end = keptUntil(await versionAt(leaving + 1), version);
51
+ return { entityId, through: leaving, dueAt: end + exports.VERSION_TRASH_MS };
52
+ }
53
+ /**
54
+ * Every version of one entity as the rule stands at `now`: current, kept,
55
+ * trashed, or gone. `versions` runs in sequence order from any version to the
56
+ * newest; a version's end depends only on the versions after it, so released
57
+ * ones before need not be read.
58
+ */
59
+ function judge(versions, now) {
60
+ const count = versions.length;
61
+ const last = versions[count - 1];
62
+ const deletedAt = last?.deleted === true ? last.acceptedAt : null;
63
+ return versions.map((version, index) => {
64
+ if (index === count - 1)
65
+ return { ...version, state: 'current', trashedAt: null, goneAt: null };
66
+ if (deletedAt !== null) {
67
+ return { ...version, state: 'gone', trashedAt: deletedAt, goneAt: deletedAt };
68
+ }
69
+ const next = versions[index + 1];
70
+ const tenth = versions[index + exports.KEEP_NEWEST];
71
+ if (tenth === undefined) {
72
+ return { ...version, state: 'kept', trashedAt: null, goneAt: null };
73
+ }
74
+ const trashedAt = keptUntil(next, tenth);
75
+ const goneAt = trashedAt + exports.VERSION_TRASH_MS;
76
+ const state = now < trashedAt ? 'kept' : now < goneAt ? 'trashed' : 'gone';
77
+ return { ...version, state, trashedAt, goneAt };
78
+ });
79
+ }
80
+ //# sourceMappingURL=rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule.js","sourceRoot":"","sources":["../../src/history/rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /**
3
+ * Version history: how long the cloud keeps each entity's earlier versions.
4
+ * A version is one accepted record on the entity's channel; its bytes are the
5
+ * one artifact that record names. History never writes records and never
6
+ * changes Watch, Detect, Record, Send, Receive, Apply or Verify. It reads
7
+ * what the authority accepted and lets go of bytes the rule no longer keeps.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/history/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /** One accepted record as a version: its place, its time, and its bytes. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.versionOf = versionOf;
5
+ const artifacts_js_1 = require("../transfer/artifacts.js");
6
+ function versionOf(record) {
7
+ const result = record.change.result;
8
+ return {
9
+ entityId: record.entityId,
10
+ authorityId: record.authorityId,
11
+ sequence: record.globalSequence,
12
+ acceptedAt: record.acceptedAt,
13
+ content: (0, artifacts_js_1.artifactForRecord)(result)?.contentHash ?? null,
14
+ type: result.type,
15
+ deleted: result.status === 'deleted',
16
+ };
17
+ }
18
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/history/version.ts"],"names":[],"mappings":";AAAA,4EAA4E;;AAM5E,8BAWC;AAdD,2DAA6D;AAG7D,SAAgB,SAAS,CAAC,MAA4B;IACpD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,QAAQ,EAAE,MAAM,CAAC,cAAc;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,OAAO,EAAE,IAAA,gCAAiB,EAAC,MAAM,CAAC,EAAE,WAAW,IAAI,IAAI;QACvD,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,SAAS;KACrC,CAAC;AACJ,CAAC"}
package/dist-cjs/index.js CHANGED
@@ -40,5 +40,6 @@ __exportStar(require("./transfer/index.js"), exports);
40
40
  __exportStar(require("./merge/index.js"), exports);
41
41
  __exportStar(require("./workspace/index.js"), exports);
42
42
  __exportStar(require("./sharing/index.js"), exports);
43
+ __exportStar(require("./history/index.js"), exports);
43
44
  __exportStar(require("./git/index.js"), exports);
44
45
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;AAEH,6CAA2B;AAC3B,uDAAqC;AACrC,sDAAoC;AACpC,sDAAoC;AACpC,sDAAoC;AACpC,uDAAqC;AACrC,qDAAmC;AACnC,mDAAiC;AACjC,0DAAwC;AACxC,mDAAiC;AACjC,sDAAoC;AACpC,mDAAiC;AACjC,uDAAqC;AACrC,qDAAmC;AACnC,iDAA+B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;AAEH,6CAA2B;AAC3B,uDAAqC;AACrC,sDAAoC;AACpC,sDAAoC;AACpC,sDAAoC;AACpC,uDAAqC;AACrC,qDAAmC;AACnC,mDAAiC;AACjC,0DAAwC;AACxC,mDAAiC;AACjC,sDAAoC;AACpC,mDAAiC;AACjC,uDAAqC;AACrC,qDAAmC;AACnC,qDAAmC;AACnC,iDAA+B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/live",
3
- "version": "0.2.81-main.41026618671",
3
+ "version": "0.2.81-main.41264653147",
4
4
  "description": "Portable realtime SDK for Amalgm — wire contracts, mutation discipline, and delivery state machines behind host-injected adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist-cjs/index.js",
@@ -32,6 +32,12 @@
32
32
  "require": "./dist-cjs/machines/index.js",
33
33
  "default": "./dist/machines/index.js"
34
34
  },
35
+ "./history": {
36
+ "types": "./dist/history/index.d.ts",
37
+ "import": "./dist/history/index.js",
38
+ "require": "./dist-cjs/history/index.js",
39
+ "default": "./dist/history/index.js"
40
+ },
35
41
  "./sharing": {
36
42
  "types": "./dist/sharing/index.d.ts",
37
43
  "import": "./dist/sharing/index.js",
@@ -129,13 +135,13 @@
129
135
  ]
130
136
  },
131
137
  "dependencies": {
132
- "@amalgm/core": "0.5.1-main.39177162099"
138
+ "@amalgm/core": "0.5.1-main.41264319540"
133
139
  },
134
- "gitHead": "240d07d978a7ebad74f7623a18ac9ad39aa662a3",
140
+ "gitHead": "b75cb97bd7dcce3e0c4a15f7f43102c4d12abe3d",
135
141
  "amalgmSource": {
136
142
  "repository": "amalgm-inc/amalgm-live",
137
143
  "branch": "main",
138
- "commit": "240d07d978a7ebad74f7623a18ac9ad39aa662a3",
139
- "occurrence": "41026618671"
144
+ "commit": "b75cb97bd7dcce3e0c4a15f7f43102c4d12abe3d",
145
+ "occurrence": "41264653147"
140
146
  }
141
147
  }