@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.
- package/dist/core-api/connected-accounts.d.ts +95 -4
- package/dist/core-api/connected-accounts.js +29 -6
- package/dist/core-api/control-plane.d.ts +1207 -1162
- package/dist/core-api/inference.d.ts +6 -1
- package/dist/core-api/inference.js +9 -2
- package/dist/core-api/profiles.d.ts +24 -0
- package/dist/core-api/system.d.ts +12 -0
- package/dist/core-api/system.js +6 -0
- package/dist/core-api/workspace-forward.d.ts +111 -6
- package/dist/core-api/workspace-forward.js +174 -2
- package/dist/core-api/workspaces.d.ts +8 -6
- package/dist/core-api/workspaces.js +8 -6
- package/package.json +2 -2
|
@@ -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
|
-
/**
|
|
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
|
-
/**
|
|
117
|
-
|
|
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.
|
package/dist/core-api/system.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
1035
|
-
* first; `/root` while the launch's own logins are at
|
|
1036
|
-
* owner), `home-unusable` (the home does not exist, is
|
|
1037
|
-
* symbolic link, or a login directory in it links outside
|
|
1038
|
-
* home, or too many into this workspace, is still
|
|
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
|
|
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
|
|
807
|
-
* first; `/root` while the launch's own logins are at
|
|
808
|
-
* owner), `home-unusable` (the home does not exist, is
|
|
809
|
-
* symbolic link, or a login directory in it links outside
|
|
810
|
-
* home, or too many into this workspace, is still
|
|
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.
|
|
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": "
|
|
39
|
+
"gitHead": "4d306e5cd66c40f162f7346370edd82930c1bc02",
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
42
42
|
}
|