@jxsuite/protocol 1.2.1 → 2.0.0
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/package.json +2 -2
- package/src/routes.ts +28 -1
- package/src/types.ts +55 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxsuite/protocol",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
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": "^1.
|
|
30
|
+
"@jxsuite/schema": "^1.9.0"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/src/routes.ts
CHANGED
|
@@ -112,7 +112,34 @@ export const STUDIO_ROUTES = {
|
|
|
112
112
|
fileRead: route("GET", "/__studio/file", "Read a file's text content"),
|
|
113
113
|
fileWrite: route("PUT", "/__studio/file", "Write a file's text content"),
|
|
114
114
|
fileDelete: route("DELETE", "/__studio/file", "Delete a file"),
|
|
115
|
-
fileUpload: route(
|
|
115
|
+
fileUpload: route(
|
|
116
|
+
"POST",
|
|
117
|
+
"/__studio/file/upload",
|
|
118
|
+
"Upload binary content to a path → UploadResult {path, size?}. `path` is the answer, not an " +
|
|
119
|
+
"echo: a store that de-duplicates, suffixes, or normalizes names reports what it really wrote",
|
|
120
|
+
),
|
|
121
|
+
/**
|
|
122
|
+
* A project file as its own BYTES, at its own URL.
|
|
123
|
+
*
|
|
124
|
+
* `fileRead` answers `{ path, content }`, which is right for the editor and useless to the
|
|
125
|
+
* renderer: `@jxsuite/runtime` resolves a component `$ref` with `fetch(url).then(r => r.json())`
|
|
126
|
+
* and expects the DOCUMENT, and an `<img src>` cannot be a JSON envelope at all. So a backend
|
|
127
|
+
* whose origin does not serve the site's own URL space serves this instead, declares `assetSpace:
|
|
128
|
+
* "repo"`, and Studio addresses every project file under it.
|
|
129
|
+
*
|
|
130
|
+
* The path is appended to the prefix, so this is the one route whose `path` is a PREFIX rather
|
|
131
|
+
* than a whole path. It was a textual assertion on both sides of the cloud seam before it was a
|
|
132
|
+
* route; naming it here is what makes that assertion a contract.
|
|
133
|
+
*/
|
|
134
|
+
documentRaw: route(
|
|
135
|
+
"GET",
|
|
136
|
+
"/__studio/raw/",
|
|
137
|
+
"A project file as its own bytes, at its own URL — the mount a canvas renders against when " +
|
|
138
|
+
"the editor origin does not serve the site's URL space. The project-relative path is " +
|
|
139
|
+
"appended to this prefix",
|
|
140
|
+
"The canvas cannot address project files by URL, so a host whose origin does not serve the " +
|
|
141
|
+
"site URL space renders no component $refs and no images.",
|
|
142
|
+
),
|
|
116
143
|
fileRename: route("POST", "/__studio/file/rename", "Rename/move (+ refactor report)"),
|
|
117
144
|
references: route(
|
|
118
145
|
"GET",
|
package/src/types.ts
CHANGED
|
@@ -68,6 +68,43 @@ export interface RenameResult {
|
|
|
68
68
|
error?: string;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* What an upload actually stored.
|
|
73
|
+
*
|
|
74
|
+
* `path` is the ANSWER, not an echo. A backend may store the bytes somewhere other than the path
|
|
75
|
+
* asked for — a store that de-duplicates by content hash, one that appends a collision suffix, one
|
|
76
|
+
* that normalizes a name — and the client has to write a reference to what was really written. The
|
|
77
|
+
* upload response used to be untyped (`Promise<unknown>`), and every caller ignored it and used the
|
|
78
|
+
* requested path, so any such backend produced a document pointing at a file that is not there.
|
|
79
|
+
*
|
|
80
|
+
* `size` is what the backend recorded, when it says: the client already knows the bytes it sent, so
|
|
81
|
+
* a differing value is the backend telling you it transformed them.
|
|
82
|
+
*/
|
|
83
|
+
export interface UploadResult {
|
|
84
|
+
/** Project-relative path the bytes were stored at. */
|
|
85
|
+
path: string;
|
|
86
|
+
/** Stored size in bytes, when the backend reports one. */
|
|
87
|
+
size?: number;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* What a backend will accept as an upload, when it says.
|
|
92
|
+
*
|
|
93
|
+
* Every field is optional and absence means "no declared limit" — a client must not invent one,
|
|
94
|
+
* because a limit it made up is a file the user cannot upload for no reason it can name. A DECLARED
|
|
95
|
+
* limit is different: it lets the client refuse before spending the round trip, and name the number
|
|
96
|
+
* in the refusal.
|
|
97
|
+
*/
|
|
98
|
+
export interface AssetCapabilities {
|
|
99
|
+
/** Largest single upload the backend accepts, in bytes. */
|
|
100
|
+
maxUploadBytes?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Media types and extensions the backend accepts, in `<input accept>` syntax (`"image/*,.pdf"`).
|
|
103
|
+
* Narrows the client's own default; it never widens it.
|
|
104
|
+
*/
|
|
105
|
+
accept?: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
71
108
|
/** One kind of reference in one file, with how many times it occurs there. */
|
|
72
109
|
export interface ReferenceHit {
|
|
73
110
|
/**
|
|
@@ -389,6 +426,24 @@ export interface SecretsSetResponse {
|
|
|
389
426
|
names: string[];
|
|
390
427
|
}
|
|
391
428
|
|
|
429
|
+
// ─── User settings (desktop launchers; specs/desktop.md §3.1) ───────────────
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* A set of changes to the user-level settings store.
|
|
433
|
+
*
|
|
434
|
+
* A patch rather than the whole map, and for the same reason {@link SecretsSetRequest} is one: a key
|
|
435
|
+
* named by neither `set` nor `remove` must be left exactly as it was found. Writing the whole map
|
|
436
|
+
* let any window overwrite the shared store with its own view of it — and on the chromium launcher
|
|
437
|
+
* every window is a separate process with a separate browser profile, so a window holding no
|
|
438
|
+
* settings could clear the credentials another had just stored.
|
|
439
|
+
*/
|
|
440
|
+
export interface SettingsPatch {
|
|
441
|
+
/** Keys to store, with their new values. */
|
|
442
|
+
set?: Record<string, string>;
|
|
443
|
+
/** Keys to forget. */
|
|
444
|
+
remove?: string[];
|
|
445
|
+
}
|
|
446
|
+
|
|
392
447
|
// ─── Packages ────────────────────────────────────────────────────────────────
|
|
393
448
|
|
|
394
449
|
export interface PackageInfo {
|