@arden-hq/revisions 0.0.0-stage → 0.1.2

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 (87) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +84 -2
  3. package/dist/domain/change-set.d.ts +34 -0
  4. package/dist/domain/change-set.d.ts.map +1 -0
  5. package/dist/domain/change-set.js +206 -0
  6. package/dist/domain/change-set.js.map +1 -0
  7. package/dist/domain/codec.d.ts +17 -0
  8. package/dist/domain/codec.d.ts.map +1 -0
  9. package/dist/domain/codec.js +188 -0
  10. package/dist/domain/codec.js.map +1 -0
  11. package/dist/domain/errors.d.ts +61 -0
  12. package/dist/domain/errors.d.ts.map +1 -0
  13. package/dist/domain/errors.js +44 -0
  14. package/dist/domain/errors.js.map +1 -0
  15. package/dist/domain/format.d.ts +72 -0
  16. package/dist/domain/format.d.ts.map +1 -0
  17. package/dist/domain/format.js +93 -0
  18. package/dist/domain/format.js.map +1 -0
  19. package/dist/domain/integrity.d.ts +7 -0
  20. package/dist/domain/integrity.d.ts.map +1 -0
  21. package/dist/domain/integrity.js +100 -0
  22. package/dist/domain/integrity.js.map +1 -0
  23. package/dist/domain/model.d.ts +114 -0
  24. package/dist/domain/model.d.ts.map +1 -0
  25. package/dist/domain/model.js +145 -0
  26. package/dist/domain/model.js.map +1 -0
  27. package/dist/domain/query.d.ts +31 -0
  28. package/dist/domain/query.d.ts.map +1 -0
  29. package/dist/domain/query.js +168 -0
  30. package/dist/domain/query.js.map +1 -0
  31. package/dist/domain/transaction.d.ts +26 -0
  32. package/dist/domain/transaction.d.ts.map +1 -0
  33. package/dist/domain/transaction.js +93 -0
  34. package/dist/domain/transaction.js.map +1 -0
  35. package/dist/domain/tree.d.ts +6 -0
  36. package/dist/domain/tree.d.ts.map +1 -0
  37. package/dist/domain/tree.js +59 -0
  38. package/dist/domain/tree.js.map +1 -0
  39. package/dist/effect/index.d.ts +10 -0
  40. package/dist/effect/index.d.ts.map +1 -0
  41. package/dist/effect/index.js +4 -0
  42. package/dist/effect/index.js.map +1 -0
  43. package/dist/repository/commit.d.ts +12 -0
  44. package/dist/repository/commit.d.ts.map +1 -0
  45. package/dist/repository/commit.js +164 -0
  46. package/dist/repository/commit.js.map +1 -0
  47. package/dist/repository/history.d.ts +21 -0
  48. package/dist/repository/history.d.ts.map +1 -0
  49. package/dist/repository/history.js +152 -0
  50. package/dist/repository/history.js.map +1 -0
  51. package/dist/repository/service.d.ts +114 -0
  52. package/dist/repository/service.d.ts.map +1 -0
  53. package/dist/repository/service.js +374 -0
  54. package/dist/repository/service.js.map +1 -0
  55. package/dist/repository/state.d.ts +27 -0
  56. package/dist/repository/state.d.ts.map +1 -0
  57. package/dist/repository/state.js +72 -0
  58. package/dist/repository/state.js.map +1 -0
  59. package/dist/repository/transaction.d.ts +27 -0
  60. package/dist/repository/transaction.d.ts.map +1 -0
  61. package/dist/repository/transaction.js +372 -0
  62. package/dist/repository/transaction.js.map +1 -0
  63. package/dist/storage/files.d.ts +17 -0
  64. package/dist/storage/files.d.ts.map +1 -0
  65. package/dist/storage/files.js +179 -0
  66. package/dist/storage/files.js.map +1 -0
  67. package/dist/storage/maintenance-adapter.d.ts +5 -0
  68. package/dist/storage/maintenance-adapter.d.ts.map +1 -0
  69. package/dist/storage/maintenance-adapter.js +177 -0
  70. package/dist/storage/maintenance-adapter.js.map +1 -0
  71. package/dist/storage/maintenance-reader.d.ts +17 -0
  72. package/dist/storage/maintenance-reader.d.ts.map +1 -0
  73. package/dist/storage/maintenance-reader.js +82 -0
  74. package/dist/storage/maintenance-reader.js.map +1 -0
  75. package/dist/storage/maintenance.d.ts +113 -0
  76. package/dist/storage/maintenance.d.ts.map +1 -0
  77. package/dist/storage/maintenance.js +445 -0
  78. package/dist/storage/maintenance.js.map +1 -0
  79. package/dist/storage/node.d.ts +7 -0
  80. package/dist/storage/node.d.ts.map +1 -0
  81. package/dist/storage/node.js +53 -0
  82. package/dist/storage/node.js.map +1 -0
  83. package/dist/storage/service.d.ts +88 -0
  84. package/dist/storage/service.d.ts.map +1 -0
  85. package/dist/storage/service.js +506 -0
  86. package/dist/storage/service.js.map +1 -0
  87. package/package.json +63 -4
@@ -0,0 +1,59 @@
1
+ import { Effect } from "effect";
2
+ import { ResourceVersion } from "./model.js";
3
+ import { CorruptRepositoryError } from "./errors.js";
4
+ import {} from "./format.js";
5
+ import { validateActivePaths } from "./integrity.js";
6
+ import { compareCodePoints } from "@arden-hq/std/json";
7
+ const failCorrupt = (message) => Effect.fail(new CorruptRepositoryError({ message }));
8
+ export const materializeSnapshot = Effect.fn("Revision.materializeSnapshot")(function* (readTree, treeId, cache) {
9
+ const active = new Set();
10
+ const visit = function* (id, prefix, depth) {
11
+ if (depth > 64)
12
+ return yield* failCorrupt(`tree ${treeId} exceeds the maximum directory depth`);
13
+ if (active.has(id))
14
+ return yield* failCorrupt(`tree ${treeId} contains a cycle at ${id}`);
15
+ const key = `${prefix}\0${id}`;
16
+ const existing = cache?.get(key);
17
+ if (existing !== undefined)
18
+ return yield* existing;
19
+ const read = Effect.gen(function* () {
20
+ active.add(id);
21
+ const tree = yield* readTree(id);
22
+ const resources = new Map();
23
+ const activePaths = new Set();
24
+ for (const entry of tree.entries) {
25
+ const versions = entry.kind === "subtree"
26
+ ? (yield* visit(entry.tree_id, `${prefix}${entry.name}/`, depth + 1)).values()
27
+ : [
28
+ new ResourceVersion({
29
+ resourceId: entry.resource_id,
30
+ path: `${prefix}${entry.name}`,
31
+ blobId: entry.blob_id,
32
+ state: entry.state,
33
+ versionId: entry.version_id
34
+ }, { disableChecks: true })
35
+ ];
36
+ for (const version of versions) {
37
+ if (version.state === "active" && activePaths.has(version.path))
38
+ return yield* failCorrupt(`tree repeats active path ${version.path}`);
39
+ if (version.state === "active")
40
+ activePaths.add(version.path);
41
+ if (resources.has(version.resourceId))
42
+ return yield* failCorrupt(`tree repeats resource ${version.resourceId}`);
43
+ resources.set(version.resourceId, version);
44
+ }
45
+ }
46
+ active.delete(id);
47
+ return resources;
48
+ });
49
+ if (cache === undefined)
50
+ return yield* read;
51
+ const shared = yield* Effect.cached(read);
52
+ cache.set(key, shared);
53
+ return yield* shared;
54
+ };
55
+ const snapshot = yield* visit(treeId, "", 0);
56
+ yield* validateActivePaths(snapshot);
57
+ return new Map([...snapshot.entries()].sort(([left], [right]) => compareCodePoints(left, right)));
58
+ });
59
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/domain/tree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { ManagedFileRepository } from "../repository/service.js";
2
+ export type { AdoptWorkingChangesOptions, CommitInput, ManagedFileRepositoryOptions, ManagedFileRepositoryShape, RepositoryError, RepositoryOpenPhase, WorkingTreeChangesPreview } from "../repository/service.js";
3
+ export type { CommitResult } from "../repository/commit.js";
4
+ export { managedFileRepositoryNodeLayer } from "../storage/node.js";
5
+ export { CorruptRepositoryError, IdempotencyConflictError, InvalidRevisionInputError, NoChangesError, RepositoryClosedError, RevisionConflictError, RevisionContentLimitError, RevisionStorageError, UnsafePathError } from "../domain/errors.js";
6
+ export type { RevisionError } from "../domain/errors.js";
7
+ export type { Commit, ResourceChange, ResourceVersion, WorkingTreeChange } from "../domain/model.js";
8
+ export type { ResourceDiff, ResourceDiffPage } from "../domain/query.js";
9
+ export type { CollectionReport, IntegrityReport, StorageReport } from "../storage/maintenance.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAChE,YAAY,EACV,0BAA0B,EAC1B,WAAW,EACX,4BAA4B,EAC5B,0BAA0B,EAC1B,eAAe,EACf,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,0BAA0B,CAAA;AACjC,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAA;AACnE,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACpG,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACxE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { ManagedFileRepository } from "../repository/service.js";
2
+ export { managedFileRepositoryNodeLayer } from "../storage/node.js";
3
+ export { CorruptRepositoryError, IdempotencyConflictError, InvalidRevisionInputError, NoChangesError, RepositoryClosedError, RevisionConflictError, RevisionContentLimitError, RevisionStorageError, UnsafePathError } from "../domain/errors.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAWhE,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAA;AACnE,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,eAAe,EAChB,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,12 @@
1
+ import { Effect } from "effect";
2
+ import type { ChangeSet, Commit } from "../domain/model.js";
3
+ import { type RevisionError } from "../domain/errors.js";
4
+ import type { RevisionStorageShape } from "../storage/service.js";
5
+ export interface CommitResult {
6
+ readonly commit: Commit;
7
+ /** True when the idempotency key already named this exact request and its first commit was returned. */
8
+ readonly replayed: boolean;
9
+ }
10
+ /** One commit under the repository lock: prepare, materialize, publish. */
11
+ export declare const commit: (storage: RevisionStorageShape, head: Effect.Effect<string | null, RevisionError, never>, changeSet: ChangeSet, checkpoint?: ((stage: string) => Effect.Effect<void, RevisionError>) | undefined, adoptedPaths?: ReadonlyMap<string, string> | undefined) => Effect.Effect<CommitResult, RevisionError, never>;
12
+ //# sourceMappingURL=commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../src/repository/commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAA;AAStC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAA;AAO5B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAejE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,wGAAwG;IACxG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAC3B;AAKD,2EAA2E;AAC3E,eAAO,MAAM,MAAM,wIAII,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,2HAmLlE,CAAA"}
@@ -0,0 +1,164 @@
1
+ import { Clock, Effect } from "effect";
2
+ import { parseIdempotencyRecord, transactionRecord } from "../domain/transaction.js";
3
+ import { applyChangeSet, requestIdentity } from "../domain/change-set.js";
4
+ import { encodeCommitRecord, encodeTreeRecord, parseCommitObject } from "../domain/codec.js";
5
+ import { CorruptRepositoryError, IdempotencyConflictError, InvalidRevisionInputError, RevisionConflictError } from "../domain/errors.js";
6
+ import { buildTreeObjects, canonicalJsonl, commitRecord } from "../domain/format.js";
7
+ import { currentMap, timestamp } from "./state.js";
8
+ import { artifact, assertWorking, installRows, recoverTransactions, validateBeforePrepare, validateWorkingTree, workingHash, writeIdempotencyRecord, writePreparedMarker } from "./transaction.js";
9
+ import { sha256Hex } from "@arden-hq/std/hash";
10
+ const bytesEqual = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);
11
+ /** One commit under the repository lock: prepare, materialize, publish. */
12
+ export const commit = Effect.fn("RevisionRepository.commit")(function* (storage, head, changeSet, checkpoint, adoptedPaths) {
13
+ const critical = Effect.gen(function* () {
14
+ yield* recoverTransactions(storage);
15
+ const identity = yield* requestIdentity(changeSet);
16
+ const existing = yield* storage.readIdempotency(identity.keyHash);
17
+ if (existing !== null) {
18
+ const record = yield* parseIdempotencyRecord(existing, identity.keyHash);
19
+ if (record.requestHash !== identity.requestHash)
20
+ return yield* new IdempotencyConflictError({
21
+ message: `idempotency key was reused for a different request: ${changeSet.idempotencyKey}`
22
+ });
23
+ return {
24
+ commit: yield* storage
25
+ .readCommit(record.commitId)
26
+ .pipe(Effect.flatMap((bytes) => parseCommitObject(record.commitId, bytes))),
27
+ replayed: true
28
+ };
29
+ }
30
+ const oldHead = yield* head;
31
+ if ((changeSet.expectedHead !== null &&
32
+ changeSet.expectedHead !== undefined &&
33
+ changeSet.expectedHead !== oldHead) ||
34
+ (changeSet.enforceExpectedHead === true && (changeSet.expectedHead ?? null) !== oldHead)) {
35
+ return yield* new RevisionConflictError({
36
+ message: `expected head changed: expected ${changeSet.expectedHead ?? "null"}, found ${oldHead ?? "null"}`
37
+ });
38
+ }
39
+ const before = yield* currentMap(storage, oldHead);
40
+ const applied = yield* applyChangeSet(changeSet, before);
41
+ const adopted = adoptedPaths === undefined
42
+ ? null
43
+ : new Map();
44
+ if (adoptedPaths !== undefined && adopted !== null) {
45
+ for (const operation of changeSet.operations) {
46
+ if (operation._tag !== "Update") {
47
+ return yield* new InvalidRevisionInputError({
48
+ message: "working-tree adoption only supports active resource updates"
49
+ });
50
+ }
51
+ const path = adoptedPaths.get(operation.resourceId);
52
+ if (path === undefined) {
53
+ return yield* new InvalidRevisionInputError({
54
+ message: `working-tree adoption is missing resource: ${operation.resourceId}`
55
+ });
56
+ }
57
+ adopted.set(operation.resourceId, { path, content: new Uint8Array(operation.content) });
58
+ }
59
+ if (adopted.size !== adoptedPaths.size) {
60
+ return yield* new InvalidRevisionInputError({
61
+ message: "working-tree adoption contains an unknown resource"
62
+ });
63
+ }
64
+ }
65
+ for (const resource of before.values()) {
66
+ if (resource.state !== "active")
67
+ continue;
68
+ const change = adopted?.get(resource.resourceId);
69
+ if (change === undefined) {
70
+ yield* assertWorking(storage, resource.path, resource.blobId);
71
+ continue;
72
+ }
73
+ if (change.path !== resource.path) {
74
+ return yield* new RevisionConflictError({
75
+ message: `managed resource path changed: ${resource.resourceId}`
76
+ });
77
+ }
78
+ const content = yield* storage.readWorking(resource.path, true, true);
79
+ if (content === null || !bytesEqual(content, change.content)) {
80
+ return yield* new RevisionConflictError({
81
+ message: `working file changed after preview: ${resource.path}`
82
+ });
83
+ }
84
+ }
85
+ for (const [blobId, content] of applied.payloads)
86
+ if (sha256Hex(content) !== blobId)
87
+ return yield* new CorruptRepositoryError({ message: `payload hash mismatch: ${blobId}` });
88
+ for (const content of applied.payloads.values())
89
+ yield* storage.writeBlob(content);
90
+ const trees = buildTreeObjects([...applied.resulting.values()]);
91
+ for (const [treeId, tree] of trees.objects) {
92
+ if (sha256Hex(canonicalJsonl(tree)) !== treeId)
93
+ return yield* new CorruptRepositoryError({ message: `tree hash mismatch: ${treeId}` });
94
+ yield* storage.writeTree(encodeTreeRecord(tree));
95
+ }
96
+ const now = yield* Clock.currentTimeMillis;
97
+ const record = {
98
+ parentId: oldHead,
99
+ treeId: trees.rootId,
100
+ actor: changeSet.actor,
101
+ origin: changeSet.origin,
102
+ reason: changeSet.reason,
103
+ timestamp: timestamp(now),
104
+ changes: applied.changes
105
+ };
106
+ const commitBytes = encodeCommitRecord(commitRecord(record));
107
+ const newHead = yield* storage.writeCommit(commitBytes);
108
+ const rows = applied.rows;
109
+ const transactionWithoutId = {
110
+ oldHead,
111
+ newHead,
112
+ treeId: trees.rootId,
113
+ keyHash: identity.keyHash,
114
+ requestHash: identity.requestHash,
115
+ rows
116
+ };
117
+ const transactionId = sha256Hex(canonicalJsonl(transactionRecord(transactionWithoutId)));
118
+ const transaction = { transactionId, ...transactionWithoutId };
119
+ yield* storage.ensureMetadataDirectory(`transactions/${transactionId}`);
120
+ yield* storage.ensureMetadataDirectory(`transactions/${transactionId}/publish`);
121
+ yield* storage.ensureMetadataDirectory(`transactions/${transactionId}/backups`);
122
+ yield* storage.ensureMetadataDirectory(`transactions/${transactionId}/displaced`);
123
+ yield* storage.ensureMetadataDirectory(`transactions/${transactionId}/rejected`);
124
+ yield* storage.ensureMetadataDirectory(`transactions/${transactionId}/markers`);
125
+ for (const [index, row] of rows.entries()) {
126
+ if (row.newBlob !== null)
127
+ yield* storage.writeMetadata(artifact(transactionId, "publish", index), yield* storage.readBlob(row.newBlob), true);
128
+ if (row.oldBlob !== null)
129
+ yield* storage.writeMetadata(artifact(transactionId, "backups", index), yield* storage.readBlob(row.oldBlob), true);
130
+ }
131
+ yield* storage.writeMetadata(`transactions/${transactionId}/manifest.jsonl`, canonicalJsonl(transactionRecord(transactionWithoutId)), true);
132
+ if (adopted !== null) {
133
+ yield* storage.writeMetadata(`transactions/${transactionId}/markers/ADOPTING`, new Uint8Array(), true);
134
+ }
135
+ yield* writePreparedMarker(storage, yield* validateBeforePrepare(storage, transaction));
136
+ if (checkpoint !== undefined)
137
+ yield* checkpoint("after_prepared");
138
+ yield* storage.readRef.pipe(Effect.flatMap((current) => current === oldHead
139
+ ? Effect.succeed(undefined)
140
+ : new RevisionConflictError({ message: "current ref changed before materialization" })));
141
+ yield* installRows(storage, transaction, adopted !== null);
142
+ for (const row of rows) {
143
+ const actual = yield* workingHash(storage, row.path);
144
+ if (actual !== row.newBlob)
145
+ return yield* new RevisionConflictError({
146
+ message: `materialized path does not match new tree: ${row.path}`
147
+ });
148
+ }
149
+ yield* validateWorkingTree(storage, newHead);
150
+ if (checkpoint !== undefined)
151
+ yield* checkpoint("before_ref");
152
+ yield* storage.compareAndSwapRef(oldHead, newHead);
153
+ if (checkpoint !== undefined)
154
+ yield* checkpoint("after_ref");
155
+ yield* storage.writeMetadata(`transactions/${transactionId}/markers/DECIDED`, new Uint8Array(), true);
156
+ yield* storage.publish(newHead);
157
+ yield* writeIdempotencyRecord(storage, identity.keyHash, identity.requestHash, newHead);
158
+ yield* storage.writeMetadata(`transactions/${transactionId}/markers/COMMITTED`, new Uint8Array(), true);
159
+ yield* storage.removeMetadataTree(`transactions/${transactionId}`);
160
+ return { commit: yield* parseCommitObject(newHead, commitBytes), replayed: false };
161
+ });
162
+ return yield* storage.withLock(critical);
163
+ });
164
+ //# sourceMappingURL=commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/repository/commit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { Effect } from "effect";
2
+ import type { Commit } from "../domain/model.js";
3
+ import type { RevisionError } from "../domain/errors.js";
4
+ interface HistoryInput {
5
+ readonly head: string | null;
6
+ readonly resourceId?: string | null;
7
+ readonly start?: string | null;
8
+ readonly stopBefore?: string | null;
9
+ readonly limit?: number | null;
10
+ readonly validHash: (value: unknown) => boolean;
11
+ readonly requireReachable: (commitId: string) => Effect.Effect<void, RevisionError>;
12
+ readonly loadCommit: (commitId: string) => Effect.Effect<Commit, RevisionError>;
13
+ readonly validateCommitTransition: (commit: Commit) => Effect.Effect<unknown, RevisionError>;
14
+ }
15
+ /** Repository-local, derived metadata. Returned revisions are always read and validated afresh. */
16
+ export declare const makeHistoryQuery: () => {
17
+ readonly prepare: (input: Pick<HistoryInput, "head" | "loadCommit">) => Effect.Effect<void, RevisionError>;
18
+ readonly query: (input: HistoryInput) => Effect.Effect<readonly Commit[], RevisionError>;
19
+ };
20
+ export {};
21
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/repository/history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAExD,UAAU,YAAY;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IAC/C,QAAQ,CAAC,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACnF,QAAQ,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC/E,QAAQ,CAAC,wBAAwB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;CAC7F;AAoBD,mGAAmG;AACnG,eAAO,MAAM,gBAAgB,QAAO;IAClC,QAAQ,CAAC,OAAO,EAAE,CAChB,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAAC,KAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;IACvC,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,aAAa,CAAC,CAAA;CAyJzF,CAAA"}
@@ -0,0 +1,152 @@
1
+ import { Effect } from "effect";
2
+ import { CorruptRepositoryError, InvalidRevisionInputError } from "../domain/errors.js";
3
+ /** Repository-local, derived metadata. Returned revisions are always read and validated afresh. */
4
+ export const makeHistoryQuery = () => {
5
+ let index = { ids: [], positions: new Map(), resources: new Map() };
6
+ let unfinished;
7
+ const prepareIndex = Effect.fn("Revision.prepareHistoryIndex")(function* (input, start) {
8
+ const previous = index;
9
+ let walk = unfinished?.start === start && unfinished.base === previous
10
+ ? unfinished
11
+ : { start, base: previous, cursor: start, tail: undefined };
12
+ unfinished = walk;
13
+ const seen = new Set();
14
+ for (let node = walk.tail; node !== undefined; node = node.previous)
15
+ seen.add(node.commit.commitId);
16
+ while (walk.cursor !== null && !previous.positions.has(walk.cursor)) {
17
+ if (seen.has(walk.cursor))
18
+ return yield* new CorruptRepositoryError({
19
+ message: `commit history contains a cycle at ${walk.cursor}`
20
+ });
21
+ const commit = yield* input.loadCommit(walk.cursor);
22
+ seen.add(walk.cursor);
23
+ const next = {
24
+ start,
25
+ base: previous,
26
+ cursor: commit.parentId,
27
+ tail: { commit, previous: walk.tail }
28
+ };
29
+ if (unfinished === walk)
30
+ unfinished = next;
31
+ walk = next;
32
+ }
33
+ if (walk.tail !== undefined) {
34
+ const cursorPosition = walk.cursor === null ? undefined : previous.positions.get(walk.cursor);
35
+ const prefixLength = cursorPosition === undefined ? 0 : cursorPosition + 1;
36
+ const ids = previous.ids.slice(0, prefixLength);
37
+ const positions = new Map(ids.map((id, position) => [id, position]));
38
+ const resources = new Map();
39
+ for (const [resourceId, entries] of previous.resources) {
40
+ const retained = entries.filter((position) => position < prefixLength);
41
+ if (retained.length > 0)
42
+ resources.set(resourceId, retained);
43
+ }
44
+ for (let node = walk.tail; node !== undefined; node = node.previous) {
45
+ const commit = node.commit;
46
+ const position = ids.length;
47
+ ids.push(commit.commitId);
48
+ positions.set(commit.commitId, position);
49
+ const changed = new Set();
50
+ for (const change of commit.changes) {
51
+ const resource = change.after ?? change.before;
52
+ if (resource === null)
53
+ return yield* new CorruptRepositoryError({ message: "resource change has no identity" });
54
+ changed.add(resource.resourceId);
55
+ }
56
+ for (const resourceId of changed) {
57
+ const entries = resources.get(resourceId) ?? [];
58
+ entries.push(position);
59
+ resources.set(resourceId, entries);
60
+ }
61
+ }
62
+ const completed = { ids, positions, resources };
63
+ if (index === previous)
64
+ index = completed;
65
+ if (unfinished === walk)
66
+ unfinished = undefined;
67
+ return completed;
68
+ }
69
+ if (unfinished === walk)
70
+ unfinished = undefined;
71
+ return previous;
72
+ });
73
+ const query = Effect.fn("Revision.history")(function* (input) {
74
+ if (input.limit != null && (!Number.isInteger(input.limit) || input.limit < 1)) {
75
+ return yield* new InvalidRevisionInputError({ message: "history limit must be positive" });
76
+ }
77
+ if (input.stopBefore != null && !input.validHash(input.stopBefore)) {
78
+ return yield* new InvalidRevisionInputError({
79
+ message: `unknown history stop boundary: ${input.stopBefore}`
80
+ });
81
+ }
82
+ const start = input.start ?? input.head;
83
+ if (input.start != null)
84
+ yield* input.requireReachable(input.start);
85
+ if (start === input.stopBefore)
86
+ return [];
87
+ if (input.resourceId == null) {
88
+ const commits = [];
89
+ const seen = new Set();
90
+ let cursor = start;
91
+ while (cursor !== null) {
92
+ if (cursor === input.stopBefore)
93
+ return commits;
94
+ if (seen.has(cursor))
95
+ return yield* new CorruptRepositoryError({
96
+ message: `commit history contains a cycle at ${cursor}`
97
+ });
98
+ seen.add(cursor);
99
+ const commit = yield* input.loadCommit(cursor);
100
+ yield* input.validateCommitTransition(commit);
101
+ commits.push(commit);
102
+ if (input.stopBefore == null && input.limit != null && commits.length >= input.limit)
103
+ return commits;
104
+ cursor = commit.parentId;
105
+ }
106
+ if (input.stopBefore != null)
107
+ return yield* new InvalidRevisionInputError({
108
+ message: `history stop boundary is not reachable from the selected start: ${input.stopBefore}`
109
+ });
110
+ return commits;
111
+ }
112
+ const selected = yield* prepareIndex(input, start);
113
+ const startPosition = start === null ? -1 : selected.positions.get(start);
114
+ if (startPosition === undefined) {
115
+ return yield* new CorruptRepositoryError({
116
+ message: `commit history does not index its start ${start}`
117
+ });
118
+ }
119
+ const stopPosition = input.stopBefore == null ? -1 : selected.positions.get(input.stopBefore);
120
+ if (stopPosition === undefined || stopPosition > startPosition) {
121
+ return yield* new InvalidRevisionInputError({
122
+ message: `history stop boundary is not reachable from the selected start: ${input.stopBefore}`
123
+ });
124
+ }
125
+ const positions = selected.resources.get(input.resourceId) ?? [];
126
+ const ids = [];
127
+ for (const position of [...positions].reverse()) {
128
+ if (position > startPosition)
129
+ continue;
130
+ if (position <= stopPosition)
131
+ break;
132
+ const id = selected.ids[position];
133
+ if (id === undefined)
134
+ return yield* new CorruptRepositoryError({
135
+ message: `commit history has no commit at ${position}`
136
+ });
137
+ ids.push(id);
138
+ if (input.stopBefore == null && input.limit != null && ids.length >= input.limit)
139
+ break;
140
+ }
141
+ return yield* Effect.forEach(ids, Effect.fn("Revision.history.id")(function* (id) {
142
+ const commit = yield* input.loadCommit(id);
143
+ yield* input.validateCommitTransition(commit);
144
+ return commit;
145
+ }), { concurrency: 8 });
146
+ });
147
+ return {
148
+ query,
149
+ prepare: (input) => prepareIndex(input, input.head).pipe(Effect.asVoid)
150
+ };
151
+ };
152
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/repository/history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import { Context, Effect, Layer, type FileSystem, type Path } from "effect";
2
+ import { ChangeSet, Commit, ResourceVersion, WorkingTreeChange } from "../domain/model.js";
3
+ import type { RevisionError } from "../domain/errors.js";
4
+ import { type CommitResult } from "./commit.js";
5
+ import type { ResourceDiff, ResourceDiffPage } from "../domain/query.js";
6
+ import { type CollectionReport, type IntegrityReport, type StorageReport } from "../storage/maintenance.js";
7
+ import { type RevisionLockFactory, type RevisionStorageOptions } from "../storage/service.js";
8
+ export type RepositoryError = RevisionError;
9
+ export type RepositoryOpenPhase = "revision_storage_ready" | "revision_lock_acquired" | "revision_initialized" | "revision_recovered" | "revision_ref_checked";
10
+ export interface ManagedFileRepositoryOptions extends RevisionStorageOptions {
11
+ /** Unreachable objects newer than this are retained. Defaults to 30 days. */
12
+ readonly gcGracePeriodMs?: number;
13
+ /** Test/diagnostic hook. Production callers normally leave this unset. */
14
+ readonly checkpoint?: (stage: string) => Effect.Effect<void, RepositoryError>;
15
+ /** Startup diagnostics only; callback failures never block repository opening. */
16
+ readonly onOpenPhase?: (phase: RepositoryOpenPhase) => void;
17
+ }
18
+ /**
19
+ * One commit request. `expectedHead` is a repository-wide compare-and-swap:
20
+ * omit it for none; `null` with `enforceExpectedHead` asserts an empty repository.
21
+ * `idempotencyKey` is the durable write identity — a retry with the same key and
22
+ * request replays the first commit; omit it for a fresh identity.
23
+ */
24
+ export type CommitInput = Omit<typeof ChangeSet.Encoded, "idempotencyKey"> & {
25
+ readonly idempotencyKey?: string;
26
+ };
27
+ export interface WorkingTreeChangesPreview {
28
+ readonly revision: string | null;
29
+ readonly changes: readonly WorkingTreeChange[];
30
+ }
31
+ export interface AdoptWorkingChangesOptions {
32
+ readonly actor: string;
33
+ readonly origin: string;
34
+ readonly reason: string;
35
+ }
36
+ export interface ManagedFileRepositoryShape {
37
+ readonly head: Effect.Effect<string | null, RepositoryError>;
38
+ readonly currentRevision: Effect.Effect<string | null, RepositoryError>;
39
+ readonly isReachable: (commitId: string) => Effect.Effect<boolean, RepositoryError>;
40
+ readonly get: (resourceId: string, options?: {
41
+ readonly at?: string | null;
42
+ }) => Effect.Effect<ResourceVersion | null, RepositoryError>;
43
+ readonly findByPath: (path: string, options?: {
44
+ readonly at?: string | null;
45
+ readonly includeArchived?: boolean;
46
+ }) => Effect.Effect<ResourceVersion | null, RepositoryError>;
47
+ readonly listResources: (options?: {
48
+ readonly at?: string | null;
49
+ readonly includeArchived?: boolean;
50
+ }) => Effect.Effect<readonly ResourceVersion[], RepositoryError>;
51
+ readonly read: (resourceId: string, options?: {
52
+ readonly at?: string | null;
53
+ }) => Effect.Effect<Uint8Array, RepositoryError>;
54
+ readonly readVersion: (version: ResourceVersion) => Effect.Effect<Uint8Array, RepositoryError>;
55
+ readonly contentSize: (resource: ResourceVersion | string, options?: {
56
+ readonly at?: string | null;
57
+ }) => Effect.Effect<number, RepositoryError>;
58
+ readonly inspectCommit: (commitId: string) => Effect.Effect<Commit, RepositoryError>;
59
+ readonly commit: (request: CommitInput) => Effect.Effect<CommitResult, RepositoryError>;
60
+ readonly idempotencyReceipt: (idempotencyKey: string) => Effect.Effect<{
61
+ readonly requestHash: string;
62
+ readonly commitId: string;
63
+ } | null, RepositoryError>;
64
+ readonly finalizeIdempotencyReceipt: (idempotencyKey: string, requestIdentity: string) => Effect.Effect<{
65
+ readonly requestHash: string;
66
+ readonly commitId: string;
67
+ }, RepositoryError>;
68
+ readonly previewWorkingChanges: Effect.Effect<WorkingTreeChangesPreview, RepositoryError>;
69
+ readonly adoptWorkingChanges: (preview: WorkingTreeChangesPreview, options: AdoptWorkingChangesOptions) => Effect.Effect<CommitResult, RepositoryError>;
70
+ readonly history: (options?: {
71
+ readonly resourceId?: string | null;
72
+ readonly start?: string | null;
73
+ readonly stopBefore?: string | null;
74
+ readonly limit?: number | null;
75
+ }) => Effect.Effect<readonly Commit[], RepositoryError>;
76
+ /** Prepare derived history metadata; returned commits still receive full validation on read. */
77
+ readonly prepareHistory: () => Effect.Effect<void, RepositoryError>;
78
+ readonly diff: (base: string | null, target: string | null, options?: {
79
+ readonly resourceIds?: Iterable<string> | null;
80
+ }) => Effect.Effect<readonly ResourceDiff[], RepositoryError>;
81
+ readonly diffPage: (base: string | null, target: string | null, resourceId: string, options?: {
82
+ readonly offset?: number;
83
+ readonly limit?: number;
84
+ readonly tail?: boolean;
85
+ }) => Effect.Effect<ResourceDiffPage, RepositoryError>;
86
+ readonly diffVersionsPage: (before: ResourceVersion | null, after: ResourceVersion | null, options?: {
87
+ readonly offset?: number;
88
+ readonly limit?: number;
89
+ readonly tail?: boolean;
90
+ readonly sourceByteLimit?: number | null;
91
+ }) => Effect.Effect<ResourceDiffPage, RepositoryError>;
92
+ readonly restoreFromCommit: (resourceId: string, sourceCommit: string, options: {
93
+ readonly expectedVersion: string;
94
+ readonly expectedHead?: string | null;
95
+ readonly enforceExpectedHead?: boolean;
96
+ readonly actor: string;
97
+ readonly origin: string;
98
+ readonly reason: string;
99
+ readonly idempotencyKey?: string;
100
+ readonly path?: string;
101
+ }) => Effect.Effect<CommitResult, RepositoryError>;
102
+ readonly integrityReport: Effect.Effect<IntegrityReport, RepositoryError>;
103
+ readonly storageReport: Effect.Effect<StorageReport, RepositoryError>;
104
+ readonly collect: (options?: {
105
+ readonly nowMillis?: number;
106
+ readonly gracePeriodMs?: number;
107
+ }) => Effect.Effect<CollectionReport, RepositoryError>;
108
+ }
109
+ declare const ManagedFileRepository_base: Context.ServiceClass<ManagedFileRepository, "@arden-hq/revisions/ManagedFileRepository", ManagedFileRepositoryShape>;
110
+ export declare class ManagedFileRepository extends ManagedFileRepository_base {
111
+ }
112
+ export declare const managedFileRepositoryLayer: (options: ManagedFileRepositoryOptions) => Layer.Layer<ManagedFileRepository, RepositoryError, FileSystem.FileSystem | Path.Path | RevisionLockFactory>;
113
+ export {};
114
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/repository/service.ts"],"names":[],"mappings":"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"}