1/** Transport-independent input and scoped, opaque push transactions. */
2import * as Effect from "effect/Effect";
3import type * as Fiber from "effect/Fiber";
4import type * as Result from "effect/Result";
5import type { RuntimeContext } from "../RuntimeContext.ts";
6import type { ObjectType } from "./Protocol/ObjectCodec.ts";
7import { StoreError } from "./Protocol/Store.ts";
8import type {
9 CommitPushResult,
10 RefCommand,
11 RepoMetaData,
12} from "./RepoObject.ts";
13import type { StreamingFeeder } from "./Store/StreamingSource.ts";
14
15/** A proposed ref change. Zero old/new OIDs mean creation/deletion. */
16export type RefUpdate = RefCommand;
17
18/** Decoded commands and a streaming pack. Use the HTTP decoder or Push.fromStream to construct inputs. */
19export interface PushInput {
20 readonly updates: ReadonlyArray<RefUpdate>;
21 readonly atomic: boolean;
22}
23
24/** @internal The decoder and engine share this state; applications see PushInput. */
25export interface IncomingState {
26 readonly feeder: StreamingFeeder;
27 readonly receiving: Fiber.Fiber<
28 Result.Result<{ readonly total: number }, StoreError>
29 >;
30 readonly packStart: number;
31 readonly declaredBytes: number | undefined;
32 active: boolean;
33 claimed: boolean;
34}
35
36/** @internal */
37export const incomingStates = new WeakMap<PushInput, IncomingState>();
38
39/** A staged push, usable only within the scope that prepared it. */
40export interface PreparedPush {
41 readonly repo: RepoMetaData;
42 readonly updates: ReadonlyArray<RefUpdate>;
43 /** Read an incoming or existing object, bounded to 1 MiB by default. */
44 readonly readObject: (
45 oid: string,
46 maxBytes?: number,
47 ) => Effect.Effect<
48 { readonly type: ObjectType; readonly content: Uint8Array } | undefined,
49 StoreError,
50 RuntimeContext
51 >;
52}
53
54/** @internal */
55export const preparedStates = new WeakMap<
56 PreparedPush,
57 {
58 readonly owner: object;
59 readonly commit: Effect.Effect<
60 CommitPushResult,
61 StoreError,
62 RuntimeContext
63 >;
64 }
65>();
66
67/** A transaction/input was already consumed, escaped its scope, or belongs to another engine. */
68export const invalidPush = () =>
69 new StoreError({
70 reason: "push is no longer active or belongs to another engine",
71 });