@jxsuite/protocol 1.2.0 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/protocol",
3
- "version": "1.2.0",
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.8.0"
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("POST", "/__studio/file/upload", "Upload binary content to a path"),
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 {