@sealant/api-contracts-next 0.40.0-next.761 → 0.40.0-next.764

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.
@@ -152,8 +152,13 @@ export declare class InferenceNotFoundError extends InferenceNotFoundError_base
152
152
  }
153
153
  declare const InferenceConflictError_base: Schema.Class<InferenceConflictError, Schema.TaggedStruct<"InferenceConflictError", {
154
154
  readonly message: Schema.String;
155
+ readonly code: Schema.optional<Schema.Literals<readonly ["connected-account-unsupported"]>>;
155
156
  }>, import("effect/Cause").YieldableError>;
156
- /** The selected account exists but is not usable (status "invalid") — reconnect it. */
157
+ /**
158
+ * The selected account exists but is not usable: its status is "invalid" (reconnect it), or, with
159
+ * `code` `connected-account-unsupported`, it is a login this control plane cannot run on yet (a
160
+ * Claude API key).
161
+ */
157
162
  export declare class InferenceConflictError extends InferenceConflictError_base {
158
163
  }
159
164
  declare const InferenceUnavailableError_base: Schema.Class<InferenceUnavailableError, Schema.TaggedStruct<"InferenceUnavailableError", {
@@ -113,8 +113,15 @@ export class InferenceBadRequestError extends Schema.TaggedError()("InferenceBad
113
113
  /** Unknown account/profile (uniform for foreign owners) or an expired/unknown inference session. */
114
114
  export class InferenceNotFoundError extends Schema.TaggedError()("InferenceNotFoundError", { message: Schema.String }, { httpApiStatus: 404 }) {
115
115
  }
116
- /** The selected account exists but is not usable (status "invalid") — reconnect it. */
117
- export class InferenceConflictError extends Schema.TaggedError()("InferenceConflictError", { message: Schema.String }, { httpApiStatus: 409 }) {
116
+ /**
117
+ * The selected account exists but is not usable: its status is "invalid" (reconnect it), or, with
118
+ * `code` `connected-account-unsupported`, it is a login this control plane cannot run on yet (a
119
+ * Claude API key).
120
+ */
121
+ export class InferenceConflictError extends Schema.TaggedError()("InferenceConflictError", {
122
+ message: Schema.String,
123
+ code: Schema.optional(Schema.Literals(["connected-account-unsupported"])),
124
+ }, { httpApiStatus: 409 }) {
118
125
  }
119
126
  export class InferenceUnavailableError extends Schema.TaggedError()("InferenceUnavailableError", { message: Schema.String }, { httpApiStatus: 503 }) {
120
127
  }
@@ -56,6 +56,12 @@ export declare const profileCredentialBindingWithAccountSchema: Schema.Struct<{
56
56
  }>;
57
57
  readonly isDefault: Schema.optional<Schema.Boolean>;
58
58
  readonly credentialRevision: Schema.optional<Schema.Int>;
59
+ readonly login: Schema.optional<Schema.Union<readonly [Schema.Struct<{
60
+ readonly kind: Schema.Literal<"subscription">;
61
+ }>, Schema.Struct<{
62
+ readonly kind: Schema.Literal<"api-key">;
63
+ readonly suffix: Schema.String;
64
+ }>]>>;
59
65
  }>;
60
66
  }>;
61
67
  export type ProfileCredentialBindingWithAccount = typeof profileCredentialBindingWithAccountSchema.Type;
@@ -84,6 +90,12 @@ export declare const listProfileCredentialBindingsResponseSchema: Schema.Struct<
84
90
  }>;
85
91
  readonly isDefault: Schema.optional<Schema.Boolean>;
86
92
  readonly credentialRevision: Schema.optional<Schema.Int>;
93
+ readonly login: Schema.optional<Schema.Union<readonly [Schema.Struct<{
94
+ readonly kind: Schema.Literal<"subscription">;
95
+ }>, Schema.Struct<{
96
+ readonly kind: Schema.Literal<"api-key">;
97
+ readonly suffix: Schema.String;
98
+ }>]>>;
87
99
  }>;
88
100
  }>>;
89
101
  }>;
@@ -148,6 +160,12 @@ export declare const ProfilesGroup: HttpApiGroup.HttpApiGroup<"profiles", HttpAp
148
160
  }>;
149
161
  readonly isDefault: Schema.optional<Schema.Boolean>;
150
162
  readonly credentialRevision: Schema.optional<Schema.Int>;
163
+ readonly login: Schema.optional<Schema.Union<readonly [Schema.Struct<{
164
+ readonly kind: Schema.Literal<"subscription">;
165
+ }>, Schema.Struct<{
166
+ readonly kind: Schema.Literal<"api-key">;
167
+ readonly suffix: Schema.String;
168
+ }>]>>;
151
169
  }>;
152
170
  }>>;
153
171
  }>>, Schema.toCodecJson<typeof ProfileNotFoundError | typeof ProfileInternalServerError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"listProfiles", "GET", "/", never, Schema.toCodecStringTree<Schema.Struct<{
@@ -200,6 +218,12 @@ export declare const ProfilesGroup: HttpApiGroup.HttpApiGroup<"profiles", HttpAp
200
218
  }>;
201
219
  readonly isDefault: Schema.optional<Schema.Boolean>;
202
220
  readonly credentialRevision: Schema.optional<Schema.Int>;
221
+ readonly login: Schema.optional<Schema.Union<readonly [Schema.Struct<{
222
+ readonly kind: Schema.Literal<"subscription">;
223
+ }>, Schema.Struct<{
224
+ readonly kind: Schema.Literal<"api-key">;
225
+ readonly suffix: Schema.String;
226
+ }>]>>;
203
227
  }>;
204
228
  }>>;
205
229
  }>>, Schema.toCodecJson<typeof ProfileBadRequestError | typeof ProfileNotFoundError | typeof ProfileConflictError | typeof ProfileInternalServerError>, never, never>, false>;
@@ -52,6 +52,12 @@ export declare const systemIndexResponseSchema: Schema.Struct<{
52
52
  * it, a connect takes `accountId` and `makeDefault`, and summaries carry `isDefault`.
53
53
  */
54
54
  readonly connectedAccountDefaults: Schema.optional<Schema.Boolean>;
55
+ /**
56
+ * A connect takes `login` and refuses a secret of the other login class, Claude and Codex
57
+ * API keys connect beside a subscription, summaries carry `login`, and the list carries
58
+ * `hasApiKeyHistory`. Without it, `login` on a connect is dropped unread.
59
+ */
60
+ readonly connectedAccountLoginClass: Schema.optional<Schema.Boolean>;
55
61
  /**
56
62
  * `ownerMap` on a capture source is taken on Kubernetes (runc): the Pod lets each person's
57
63
  * `sudo` work, and the Kubernetes image builder records the image probe the launch checks.
@@ -136,6 +142,12 @@ export declare const SystemGroup: HttpApiGroup.HttpApiGroup<"system", HttpApiEnd
136
142
  * it, a connect takes `accountId` and `makeDefault`, and summaries carry `isDefault`.
137
143
  */
138
144
  readonly connectedAccountDefaults: Schema.optional<Schema.Boolean>;
145
+ /**
146
+ * A connect takes `login` and refuses a secret of the other login class, Claude and Codex
147
+ * API keys connect beside a subscription, summaries carry `login`, and the list carries
148
+ * `hasApiKeyHistory`. Without it, `login` on a connect is dropped unread.
149
+ */
150
+ readonly connectedAccountLoginClass: Schema.optional<Schema.Boolean>;
139
151
  /**
140
152
  * `ownerMap` on a capture source is taken on Kubernetes (runc): the Pod lets each person's
141
153
  * `sudo` work, and the Kubernetes image builder records the image probe the launch checks.
@@ -53,6 +53,12 @@ export const systemIndexResponseSchema = Schema.Struct({
53
53
  * it, a connect takes `accountId` and `makeDefault`, and summaries carry `isDefault`.
54
54
  */
55
55
  connectedAccountDefaults: Schema.optional(Schema.Boolean),
56
+ /**
57
+ * A connect takes `login` and refuses a secret of the other login class, Claude and Codex
58
+ * API keys connect beside a subscription, summaries carry `login`, and the list carries
59
+ * `hasApiKeyHistory`. Without it, `login` on a connect is dropped unread.
60
+ */
61
+ connectedAccountLoginClass: Schema.optional(Schema.Boolean),
56
62
  /**
57
63
  * `ownerMap` on a capture source is taken on Kubernetes (runc): the Pod lets each person's
58
64
  * `sudo` work, and the Kubernetes image builder records the image probe the launch checks.
@@ -4,6 +4,14 @@
4
4
  * refused upgrade, so v2 accepts the upgrade first and answers with one text frame: `ready`, after
5
5
  * which binary frames carry payload both ways, or `refused`, after which the server closes with
6
6
  * {@link FORWARD_REFUSED_CLOSE_CODE}. A request without an upgrade gets 426 and is never dialled.
7
+ *
8
+ * After `ready`, each direction is bounded by {@link FORWARD_V2_WINDOW}. A receiver sends
9
+ * `progress` with the cumulative bytes and frames it has consumed; a sender keeps what it has sent
10
+ * within the last `progress` plus the window, and sends nothing before the first `progress`
11
+ * (`{0,0}`), which opens the receiver's window. A receiver resets a sender that goes past it.
12
+ * `fin` ends one direction with the totals sent; `reset` ends both at once. Core sends a `progress`
13
+ * naming exactly what reached the workspace before its `fin`, so a client can tell whether
14
+ * everything it wrote arrived. {@link ForwardFlow} keeps this ledger for either side.
7
15
  */
8
16
  import { Schema } from "effect";
9
17
  export declare const FORWARD_V2_SUBPROTOCOL = "sealant.forward.v2";
@@ -35,16 +43,26 @@ export declare const FORWARD_REFUSAL_STATUS: {
35
43
  readonly "binding-unverifiable": 409;
36
44
  readonly "binding-unsupported": 409;
37
45
  };
38
- export declare const forwardBindingSchema: Schema.Struct<{
46
+ /**
47
+ * What a forward reaches: whatever holds the port (`port`), or only a process of the session that
48
+ * `session` names (`session`), as the workspace runtime verified when it connected.
49
+ */
50
+ export declare const forwardBindingSchema: Schema.Union<readonly [Schema.Struct<{
39
51
  readonly kind: Schema.Literal<"port">;
40
- }>;
52
+ }>, Schema.Struct<{
53
+ readonly kind: Schema.Literal<"session">;
54
+ readonly session: Schema.String;
55
+ }>]>;
41
56
  export type ForwardBinding = typeof forwardBindingSchema.Type;
42
57
  export declare const forwardReadyFrameSchema: Schema.Struct<{
43
58
  readonly t: Schema.Literal<"ready">;
44
59
  readonly version: Schema.Literal<2>;
45
- readonly binding: Schema.Struct<{
60
+ readonly binding: Schema.Union<readonly [Schema.Struct<{
46
61
  readonly kind: Schema.Literal<"port">;
47
- }>;
62
+ }>, Schema.Struct<{
63
+ readonly kind: Schema.Literal<"session">;
64
+ readonly session: Schema.String;
65
+ }>]>;
48
66
  }>;
49
67
  export type ForwardReadyFrame = typeof forwardReadyFrameSchema.Type;
50
68
  /**
@@ -68,9 +86,12 @@ export declare const forwardRefusedFrame: (reason: "binding-unsupported" | "bind
68
86
  export declare const forwardOpenFrameSchema: Schema.Union<readonly [Schema.Struct<{
69
87
  readonly t: Schema.Literal<"ready">;
70
88
  readonly version: Schema.Literal<2>;
71
- readonly binding: Schema.Struct<{
89
+ readonly binding: Schema.Union<readonly [Schema.Struct<{
72
90
  readonly kind: Schema.Literal<"port">;
73
- }>;
91
+ }>, Schema.Struct<{
92
+ readonly kind: Schema.Literal<"session">;
93
+ readonly session: Schema.String;
94
+ }>]>;
74
95
  }>, Schema.Struct<{
75
96
  readonly t: Schema.Literal<"refused">;
76
97
  readonly reason: Schema.String;
@@ -78,3 +99,87 @@ export declare const forwardOpenFrameSchema: Schema.Union<readonly [Schema.Struc
78
99
  readonly status: Schema.Int;
79
100
  }>]>;
80
101
  export type ForwardOpenFrame = typeof forwardOpenFrameSchema.Type;
102
+ /** What each direction of a v2 forward may have in flight beyond what its receiver consumed. */
103
+ export declare const FORWARD_V2_WINDOW: {
104
+ readonly bytes: number;
105
+ readonly frames: 32;
106
+ };
107
+ export declare const forwardProgressFrameSchema: Schema.Struct<{
108
+ readonly t: Schema.Literal<"progress">;
109
+ readonly bytes: Schema.String;
110
+ readonly frames: Schema.String;
111
+ }>;
112
+ export type ForwardProgressFrame = typeof forwardProgressFrameSchema.Type;
113
+ export declare const forwardFinFrameSchema: Schema.Struct<{
114
+ readonly t: Schema.Literal<"fin">;
115
+ readonly bytes: Schema.String;
116
+ readonly frames: Schema.String;
117
+ }>;
118
+ export type ForwardFinFrame = typeof forwardFinFrameSchema.Type;
119
+ export declare const forwardResetReasonSchema: Schema.Literals<readonly ["window-exceeded", "protocol-violation", "aborted", "target-error", "runtime-lost", "owner-exited"]>;
120
+ export type ForwardResetReason = typeof forwardResetReasonSchema.Type;
121
+ /** Decoded with any `reason`, so a client keeps a reset from a Core newer than itself. */
122
+ export declare const forwardResetFrameSchema: Schema.Struct<{
123
+ readonly t: Schema.Literal<"reset">;
124
+ readonly reason: Schema.String;
125
+ }>;
126
+ export type ForwardResetFrame = typeof forwardResetFrameSchema.Type;
127
+ /** The text frames either side sends after `ready`. */
128
+ export declare const forwardFlowFrameSchema: Schema.Union<readonly [Schema.Struct<{
129
+ readonly t: Schema.Literal<"progress">;
130
+ readonly bytes: Schema.String;
131
+ readonly frames: Schema.String;
132
+ }>, Schema.Struct<{
133
+ readonly t: Schema.Literal<"fin">;
134
+ readonly bytes: Schema.String;
135
+ readonly frames: Schema.String;
136
+ }>, Schema.Struct<{
137
+ readonly t: Schema.Literal<"reset">;
138
+ readonly reason: Schema.String;
139
+ }>]>;
140
+ export type ForwardFlowFrame = typeof forwardFlowFrameSchema.Type;
141
+ /** What one frame from the peer meant, once the forward is open. */
142
+ export type ForwardInbound = {
143
+ readonly kind: "data";
144
+ readonly data: Uint8Array;
145
+ } | {
146
+ readonly kind: "progress";
147
+ } | {
148
+ readonly kind: "fin";
149
+ } | {
150
+ readonly kind: "reset";
151
+ readonly reason: string;
152
+ } | {
153
+ readonly kind: "violation";
154
+ readonly reason: "window-exceeded" | "protocol-violation";
155
+ };
156
+ /** A chunk as the binary frames it is sent in. */
157
+ export declare function forwardFrames(chunk: Uint8Array): Generator<Uint8Array>;
158
+ /**
159
+ * Both directions of an open v2 forward as one side sees them, with no I/O: what it sent against
160
+ * what its peer consumed, and what it received and consumed against what it granted. Core and the
161
+ * SDK each drive one from their socket.
162
+ *
163
+ * A grant is made when its `progress` is sent, so a side that holds a `progress` back while its
164
+ * socket is backed up also holds back its peer, and the next `progress` it sends names the latest
165
+ * count: acknowledgements never queue.
166
+ */
167
+ export declare class ForwardFlow {
168
+ #private;
169
+ /** The first `progress`, which lets the peer start sending. */
170
+ open(): ForwardProgressFrame;
171
+ receive(frame: string | Uint8Array): ForwardInbound;
172
+ /** Whether one frame of `bytes` fits in what the peer has granted. */
173
+ canSend(bytes: number): boolean;
174
+ sent(bytes: number): void;
175
+ /** Whether the peer has said it consumed everything this side sent. */
176
+ get delivered(): boolean;
177
+ fin(): ForwardFinFrame;
178
+ consumed(bytes: number): void;
179
+ /** Whether what was consumed since the last `progress` reaches half the window. */
180
+ get progressDue(): boolean;
181
+ /** The `progress` to send now, when one is due. Taking it makes the grant. */
182
+ takeProgress(): ForwardProgressFrame | undefined;
183
+ /** A `progress` naming exactly what was consumed, unless the last one already did. */
184
+ takeFinalProgress(): ForwardProgressFrame | undefined;
185
+ }
@@ -4,8 +4,16 @@
4
4
  * refused upgrade, so v2 accepts the upgrade first and answers with one text frame: `ready`, after
5
5
  * which binary frames carry payload both ways, or `refused`, after which the server closes with
6
6
  * {@link FORWARD_REFUSED_CLOSE_CODE}. A request without an upgrade gets 426 and is never dialled.
7
+ *
8
+ * After `ready`, each direction is bounded by {@link FORWARD_V2_WINDOW}. A receiver sends
9
+ * `progress` with the cumulative bytes and frames it has consumed; a sender keeps what it has sent
10
+ * within the last `progress` plus the window, and sends nothing before the first `progress`
11
+ * (`{0,0}`), which opens the receiver's window. A receiver resets a sender that goes past it.
12
+ * `fin` ends one direction with the totals sent; `reset` ends both at once. Core sends a `progress`
13
+ * naming exactly what reached the workspace before its `fin`, so a client can tell whether
14
+ * everything it wrote arrived. {@link ForwardFlow} keeps this ledger for either side.
7
15
  */
8
- import { Schema } from "effect";
16
+ import { Option, Schema } from "effect";
9
17
  export const FORWARD_V2_SUBPROTOCOL = "sealant.forward.v2";
10
18
  /** The largest binary frame either side may send. */
11
19
  export const FORWARD_V2_MAX_FRAME_BYTES = 64 * 1024;
@@ -54,7 +62,14 @@ export const FORWARD_REFUSAL_STATUS = {
54
62
  "binding-unverifiable": 409,
55
63
  "binding-unsupported": 409,
56
64
  };
57
- export const forwardBindingSchema = Schema.Struct({ kind: Schema.Literal("port") });
65
+ /**
66
+ * What a forward reaches: whatever holds the port (`port`), or only a process of the session that
67
+ * `session` names (`session`), as the workspace runtime verified when it connected.
68
+ */
69
+ export const forwardBindingSchema = Schema.Union([
70
+ Schema.Struct({ kind: Schema.Literal("port") }),
71
+ Schema.Struct({ kind: Schema.Literal("session"), session: Schema.String }),
72
+ ]);
58
73
  export const forwardReadyFrameSchema = Schema.Struct({
59
74
  t: Schema.Literal("ready"),
60
75
  version: Schema.Literal(2),
@@ -81,3 +96,160 @@ export const forwardOpenFrameSchema = Schema.Union([
81
96
  forwardReadyFrameSchema,
82
97
  forwardRefusedFrameSchema,
83
98
  ]);
99
+ /** What each direction of a v2 forward may have in flight beyond what its receiver consumed. */
100
+ export const FORWARD_V2_WINDOW = { bytes: 256 * 1024, frames: 32 };
101
+ const counterSchema = Schema.String.check(Schema.isPattern(/^(?:0|[1-9][0-9]{0,14})$/));
102
+ export const forwardProgressFrameSchema = Schema.Struct({
103
+ t: Schema.Literal("progress"),
104
+ bytes: counterSchema,
105
+ frames: counterSchema,
106
+ });
107
+ export const forwardFinFrameSchema = Schema.Struct({
108
+ t: Schema.Literal("fin"),
109
+ bytes: counterSchema,
110
+ frames: counterSchema,
111
+ });
112
+ export const forwardResetReasonSchema = Schema.Literals([
113
+ "window-exceeded",
114
+ "protocol-violation",
115
+ "aborted",
116
+ "target-error",
117
+ "runtime-lost",
118
+ "owner-exited",
119
+ ]);
120
+ /** Decoded with any `reason`, so a client keeps a reset from a Core newer than itself. */
121
+ export const forwardResetFrameSchema = Schema.Struct({
122
+ t: Schema.Literal("reset"),
123
+ reason: Schema.String,
124
+ });
125
+ /** The text frames either side sends after `ready`. */
126
+ export const forwardFlowFrameSchema = Schema.Union([
127
+ forwardProgressFrameSchema,
128
+ forwardFinFrameSchema,
129
+ forwardResetFrameSchema,
130
+ ]);
131
+ const NOTHING = { bytes: 0, frames: 0 };
132
+ const plusFrame = (count, bytes) => ({
133
+ bytes: count.bytes + bytes,
134
+ frames: count.frames + 1,
135
+ });
136
+ const countOf = (frame) => ({
137
+ bytes: Number(frame.bytes),
138
+ frames: Number(frame.frames),
139
+ });
140
+ const sameCount = (a, b) => a.bytes === b.bytes && a.frames === b.frames;
141
+ const withinWindow = (count, granted) => count.bytes <= granted.bytes + FORWARD_V2_WINDOW.bytes &&
142
+ count.frames <= granted.frames + FORWARD_V2_WINDOW.frames;
143
+ const counted = (t, count) => ({
144
+ t,
145
+ bytes: String(count.bytes),
146
+ frames: String(count.frames),
147
+ });
148
+ const decodeFlowFrame = Schema.decodeUnknownOption(Schema.fromJsonString(forwardFlowFrameSchema));
149
+ const violation = (reason) => ({
150
+ kind: "violation",
151
+ reason,
152
+ });
153
+ /** A chunk as the binary frames it is sent in. */
154
+ export function* forwardFrames(chunk) {
155
+ for (let offset = 0; offset < chunk.byteLength; offset += FORWARD_V2_MAX_FRAME_BYTES) {
156
+ yield chunk.subarray(offset, offset + FORWARD_V2_MAX_FRAME_BYTES);
157
+ }
158
+ }
159
+ /**
160
+ * Both directions of an open v2 forward as one side sees them, with no I/O: what it sent against
161
+ * what its peer consumed, and what it received and consumed against what it granted. Core and the
162
+ * SDK each drive one from their socket.
163
+ *
164
+ * A grant is made when its `progress` is sent, so a side that holds a `progress` back while its
165
+ * socket is backed up also holds back its peer, and the next `progress` it sends names the latest
166
+ * count: acknowledgements never queue.
167
+ */
168
+ export class ForwardFlow {
169
+ #sent = NOTHING;
170
+ #peerConsumed;
171
+ #received = NOTHING;
172
+ #consumed = NOTHING;
173
+ #granted;
174
+ #finReceived = false;
175
+ /** The first `progress`, which lets the peer start sending. */
176
+ open() {
177
+ this.#granted = this.#consumed;
178
+ return counted("progress", this.#consumed);
179
+ }
180
+ receive(frame) {
181
+ if (typeof frame !== "string") {
182
+ if (this.#finReceived)
183
+ return violation("protocol-violation");
184
+ this.#received = plusFrame(this.#received, frame.byteLength);
185
+ const granted = this.#granted;
186
+ return granted !== undefined && withinWindow(this.#received, granted)
187
+ ? { kind: "data", data: frame }
188
+ : violation("window-exceeded");
189
+ }
190
+ const decoded = decodeFlowFrame(frame);
191
+ if (Option.isNone(decoded))
192
+ return violation("protocol-violation");
193
+ switch (decoded.value.t) {
194
+ case "progress":
195
+ return this.#acceptPeerProgress(countOf(decoded.value))
196
+ ? { kind: "progress" }
197
+ : violation("protocol-violation");
198
+ case "fin":
199
+ if (this.#finReceived || !sameCount(countOf(decoded.value), this.#received)) {
200
+ return violation("protocol-violation");
201
+ }
202
+ this.#finReceived = true;
203
+ return { kind: "fin" };
204
+ case "reset":
205
+ return { kind: "reset", reason: decoded.value.reason };
206
+ }
207
+ }
208
+ #acceptPeerProgress(consumed) {
209
+ const previous = this.#peerConsumed ?? NOTHING;
210
+ if (consumed.bytes > this.#sent.bytes ||
211
+ consumed.frames > this.#sent.frames ||
212
+ consumed.bytes < previous.bytes ||
213
+ consumed.frames < previous.frames) {
214
+ return false;
215
+ }
216
+ this.#peerConsumed = consumed;
217
+ return true;
218
+ }
219
+ /** Whether one frame of `bytes` fits in what the peer has granted. */
220
+ canSend(bytes) {
221
+ const consumed = this.#peerConsumed;
222
+ return consumed !== undefined && withinWindow(plusFrame(this.#sent, bytes), consumed);
223
+ }
224
+ sent(bytes) {
225
+ this.#sent = plusFrame(this.#sent, bytes);
226
+ }
227
+ /** Whether the peer has said it consumed everything this side sent. */
228
+ get delivered() {
229
+ return this.#peerConsumed !== undefined && sameCount(this.#peerConsumed, this.#sent);
230
+ }
231
+ fin() {
232
+ return counted("fin", this.#sent);
233
+ }
234
+ consumed(bytes) {
235
+ this.#consumed = plusFrame(this.#consumed, bytes);
236
+ }
237
+ /** Whether what was consumed since the last `progress` reaches half the window. */
238
+ get progressDue() {
239
+ const granted = this.#granted ?? NOTHING;
240
+ return (this.#consumed.bytes - granted.bytes >= FORWARD_V2_WINDOW.bytes / 2 ||
241
+ this.#consumed.frames - granted.frames >= FORWARD_V2_WINDOW.frames / 2);
242
+ }
243
+ /** The `progress` to send now, when one is due. Taking it makes the grant. */
244
+ takeProgress() {
245
+ if (!this.progressDue)
246
+ return undefined;
247
+ return this.open();
248
+ }
249
+ /** A `progress` naming exactly what was consumed, unless the last one already did. */
250
+ takeFinalProgress() {
251
+ if (this.#granted !== undefined && sameCount(this.#granted, this.#consumed))
252
+ return undefined;
253
+ return this.open();
254
+ }
255
+ }
@@ -793,7 +793,8 @@ export type InspectWorkspaceImageResponse = typeof inspectWorkspaceImageResponse
793
793
  * else's) and `connected-account-invalid` (`WorkspaceConflictError`, 409: the account is marked
794
794
  * invalid, or holds an unusable credential; reconnect it) and `connected-account-unsupported`
795
795
  * (`WorkspaceConflictError`, 409: the account cannot serve what was asked, as a Codex API key cannot
796
- * be pi's or opencode's ChatGPT login). Nothing was written either way.
796
+ * be pi's or opencode's ChatGPT login, and a Claude API key cannot be placed yet). Nothing was
797
+ * written either way.
797
798
  */
798
799
  export declare const connectedAccountRefusalCodes: readonly ["connected-account-missing", "connected-account-invalid", "connected-account-unsupported"];
799
800
  export type ConnectedAccountRefusalCode = (typeof connectedAccountRefusalCodes)[number];
@@ -1031,11 +1032,12 @@ export type ListWorkspaceCredentialsResponse = typeof listWorkspaceCredentialsRe
1031
1032
  * `workspace-not-running` (no ready executor), `connected-account-invalid` (a named account is
1032
1033
  * marked invalid or unusable: reconnect it; `provider` names its provider),
1033
1034
  * `connected-account-unsupported` (a Codex account named for pi or opencode is not a ChatGPT
1034
- * login), `home-held` (the home holds another person's logins: release it
1035
- * first; `/root` while the launch's own logins are at `$HOME`, or for anyone but the workspace's
1036
- * owner), `home-unusable` (the home does not exist, is not a directory, is reached through a
1037
- * symbolic link, or a login directory in it links outside it), `home-busy` (another write into the
1038
- * home, or too many into this workspace, is still running: nothing was done, try again).
1035
+ * login, or a Claude account is an API key, which cannot be placed yet), `home-held` (the home
1036
+ * holds another person's logins: release it first; `/root` while the launch's own logins are at
1037
+ * `$HOME`, or for anyone but the workspace's owner), `home-unusable` (the home does not exist, is
1038
+ * not a directory, is reached through a symbolic link, or a login directory in it links outside
1039
+ * it), `home-busy` (another write into the home, or too many into this workspace, is still
1040
+ * running: nothing was done, try again).
1039
1041
  */
1040
1042
  export declare const workspaceCredentialsConflictCodes: readonly ["workspace-not-running", "connected-account-invalid", "connected-account-unsupported", "home-held", "home-unusable", "home-busy"];
1041
1043
  export type WorkspaceCredentialsConflictCode = (typeof workspaceCredentialsConflictCodes)[number];
@@ -663,7 +663,8 @@ export const inspectWorkspaceImageResponseSchema = Schema.Struct({
663
663
  * else's) and `connected-account-invalid` (`WorkspaceConflictError`, 409: the account is marked
664
664
  * invalid, or holds an unusable credential; reconnect it) and `connected-account-unsupported`
665
665
  * (`WorkspaceConflictError`, 409: the account cannot serve what was asked, as a Codex API key cannot
666
- * be pi's or opencode's ChatGPT login). Nothing was written either way.
666
+ * be pi's or opencode's ChatGPT login, and a Claude API key cannot be placed yet). Nothing was
667
+ * written either way.
667
668
  */
668
669
  export const connectedAccountRefusalCodes = [
669
670
  "connected-account-missing",
@@ -803,11 +804,12 @@ export const listWorkspaceCredentialsResponseSchema = Schema.Struct({
803
804
  * `workspace-not-running` (no ready executor), `connected-account-invalid` (a named account is
804
805
  * marked invalid or unusable: reconnect it; `provider` names its provider),
805
806
  * `connected-account-unsupported` (a Codex account named for pi or opencode is not a ChatGPT
806
- * login), `home-held` (the home holds another person's logins: release it
807
- * first; `/root` while the launch's own logins are at `$HOME`, or for anyone but the workspace's
808
- * owner), `home-unusable` (the home does not exist, is not a directory, is reached through a
809
- * symbolic link, or a login directory in it links outside it), `home-busy` (another write into the
810
- * home, or too many into this workspace, is still running: nothing was done, try again).
807
+ * login, or a Claude account is an API key, which cannot be placed yet), `home-held` (the home
808
+ * holds another person's logins: release it first; `/root` while the launch's own logins are at
809
+ * `$HOME`, or for anyone but the workspace's owner), `home-unusable` (the home does not exist, is
810
+ * not a directory, is reached through a symbolic link, or a login directory in it links outside
811
+ * it), `home-busy` (another write into the home, or too many into this workspace, is still
812
+ * running: nothing was done, try again).
811
813
  */
812
814
  export const workspaceCredentialsConflictCodes = [
813
815
  "workspace-not-running",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sealant/api-contracts-next",
3
- "version": "0.40.0-next.761",
3
+ "version": "0.40.0-next.764",
4
4
  "description": "Contract-first HTTP API definitions for Sealant services",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -36,7 +36,7 @@
36
36
  "peerDependencies": {
37
37
  "effect": "^4.0.5"
38
38
  },
39
- "gitHead": "3c4e8a0fe207247b1940197389924f330769ffb8",
39
+ "gitHead": "4d306e5cd66c40f162f7346370edd82930c1bc02",
40
40
  "publishConfig": {
41
41
  "access": "public"
42
42
  }