@jxsuite/protocol 2.5.0 → 2.6.1
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/LICENSE +1 -1
- package/package.json +2 -2
- package/src/problems.ts +13 -2
- package/src/routes.ts +2 -2
- package/src/types.ts +45 -1
package/LICENSE
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxsuite/protocol",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "The Studio Backend Protocol — wire types and the canonical route table every Jx Studio backend implements",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,6 +27,6 @@
|
|
|
27
27
|
"test:coverage": "bun test --isolate --coverage"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@jxsuite/schema": "^
|
|
30
|
+
"@jxsuite/schema": "^3.0.0"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/src/problems.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* declared once, exported as data, rendered into the docs by the same generator, and checked by the
|
|
7
7
|
* same drift machinery.
|
|
8
8
|
*
|
|
9
|
-
* **What belongs here.** A type is a
|
|
9
|
+
* **What belongs here.** A type is a _class_ of failure a client might handle differently — not a
|
|
10
10
|
* message. "The project root was refused" is a type; "root /x/y was refused" is a `detail`. If two
|
|
11
11
|
* entries would only ever differ in their wording, they are one type.
|
|
12
12
|
*
|
|
@@ -78,7 +78,18 @@ export const PROBLEM_TYPES = {
|
|
|
78
78
|
403,
|
|
79
79
|
"The path resolves outside the active project",
|
|
80
80
|
),
|
|
81
|
-
|
|
81
|
+
/*
|
|
82
|
+
* Refused for a reason the user can act on (desktop.md §10.4): a role, a policy, a plan, a quota.
|
|
83
|
+
* Its own type rather than a `forbidden` with a code, by the same test as
|
|
84
|
+
* `needsInstallationAccess`: the client does something different with it — it offers the
|
|
85
|
+
* `actions` the backend listed, under the backend's `heading`, and follows `retry` once one is
|
|
86
|
+
* done. Nothing here says WHY; that is the backend's, and so is every word the user reads.
|
|
87
|
+
*/
|
|
88
|
+
actionRequired: problem("action-required", 403, "An action is required first", [
|
|
89
|
+
"actions",
|
|
90
|
+
"heading",
|
|
91
|
+
"retry",
|
|
92
|
+
]),
|
|
82
93
|
// ─── Backend state ────────────────────────────────────────────────────────
|
|
83
94
|
noActiveProject: problem("no-active-project", 409, "No project is active on this backend"),
|
|
84
95
|
capabilityUnavailable: problem(
|
package/src/routes.ts
CHANGED
|
@@ -110,8 +110,8 @@ export const STUDIO_ROUTES = {
|
|
|
110
110
|
files: route(
|
|
111
111
|
"GET",
|
|
112
112
|
"/__studio/files",
|
|
113
|
-
"List a directory (DirEntry[]) in stable path order;
|
|
114
|
-
"files project-wide",
|
|
113
|
+
"List a directory (DirEntry[]) in stable path order; an entry may carry an opaque content " +
|
|
114
|
+
"`version` the backend vouches for; with ?glob=<pattern>, search matching files project-wide",
|
|
115
115
|
),
|
|
116
116
|
fileRead: route("GET", "/__studio/file", "Read a file's text content"),
|
|
117
117
|
/**
|
package/src/types.ts
CHANGED
|
@@ -41,6 +41,13 @@ export interface DirEntry {
|
|
|
41
41
|
type: "file" | "directory";
|
|
42
42
|
size?: number;
|
|
43
43
|
modified?: string;
|
|
44
|
+
/**
|
|
45
|
+
* An opaque version of the file's bytes: two equal versions mean identical bytes. ABSENT whenever
|
|
46
|
+
* the backend cannot vouch for the bytes — an uncommitted, dirty or just-uploaded file, and every
|
|
47
|
+
* directory. A client may append it to the file's URL (`?v=<version>`) so a host that recognizes
|
|
48
|
+
* it can answer with an immutable cache lifetime; a backend with no such notion never sets it.
|
|
49
|
+
*/
|
|
50
|
+
version?: string;
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
/** A filesystem change pushed from the backend (project-relative, forward-slashed path). */
|
|
@@ -812,10 +819,47 @@ export interface AiModelsResponse {
|
|
|
812
819
|
* true`: Cloudflare being briefly unreachable is not a reason to send someone round an OAuth flow
|
|
813
820
|
* that fixes nothing. `cf_account_required` is a live grant with no account chosen (ai.md §2.1):
|
|
814
821
|
* re-authorizing lands back in the same state, so it calls for the account picker instead.
|
|
822
|
+
*
|
|
823
|
+
* `action_required` is the fourth, and no connection fixes it: the backend requires something of
|
|
824
|
+
* the user before the assistant will run (desktop.md §10.4, ai.md §2.1). It arrives with
|
|
825
|
+
* {@link detail} and {@link actions}, the same members the `action-required` problem carries, so
|
|
826
|
+
* the gate can offer what the backend offers in the backend's own words.
|
|
815
827
|
*/
|
|
816
|
-
code?:
|
|
828
|
+
code?:
|
|
829
|
+
| "cf_not_connected"
|
|
830
|
+
| "cf_reconnect_required"
|
|
831
|
+
| "cf_account_required"
|
|
832
|
+
| "cf_upstream_error"
|
|
833
|
+
| "action_required";
|
|
834
|
+
/** Why the backend refuses, in its own words. Sent with `action_required`. */
|
|
835
|
+
detail?: string;
|
|
836
|
+
/** What the user can do about it. Sent with `action_required`. */
|
|
837
|
+
actions?: OfferedAction[];
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// ─── Backend-directed access (desktop.md §10.4) ──────────────────────────────
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Something the user can do, offered by the backend: on an `action-required` refusal, a notice, or
|
|
844
|
+
* an account row. The backend decides what it means; the platform adapter performs it.
|
|
845
|
+
*/
|
|
846
|
+
export interface OfferedAction {
|
|
847
|
+
/** Stable within the offer — for the backend's bookkeeping and a test's selector. */
|
|
848
|
+
id: string;
|
|
849
|
+
/** The button's words. */
|
|
850
|
+
label: string;
|
|
851
|
+
/** A page the platform opens for the user. Absent: the platform performs it by `id`. */
|
|
852
|
+
href?: string;
|
|
853
|
+
/** The one action a surface leads with. */
|
|
854
|
+
primary?: boolean;
|
|
817
855
|
}
|
|
818
856
|
|
|
857
|
+
/**
|
|
858
|
+
* What the client does once an offered action is done: `reload` the page (the refusal broke the
|
|
859
|
+
* session), `repeat` (the user runs what was refused again), or `none`.
|
|
860
|
+
*/
|
|
861
|
+
export type RetryHint = "reload" | "repeat" | "none";
|
|
862
|
+
|
|
819
863
|
// ─── Cloudflare publish surface ──────────────────────────────────────────────
|
|
820
864
|
|
|
821
865
|
/**
|