@volter/blender-engine 0.1.45 → 0.1.46

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.
@@ -225,6 +225,12 @@ export class BlenderRuntime {
225
225
  return this.#document;
226
226
  }
227
227
 
228
+ /** Blender's last lines of output (the worker's log, newest last): what a status read shows,
229
+ * including each document save's size and phase timings (`@@VOLTER-DOCUMENT`). */
230
+ get lastOutput(): readonly string[] {
231
+ return [...this.#lastLines];
232
+ }
233
+
228
234
  /** Idempotent: the first call boots Blender at `project`'s
229
235
  * absolute path; later calls await it (a different path is refused).
230
236
  *
package/browser/worker.ts CHANGED
@@ -198,9 +198,19 @@ function setDocumentDirty(dirty: boolean): void {
198
198
  async function saveDocument(): Promise<void> {
199
199
  if (!engine || documentPath === null) return;
200
200
  const relative = documentPath;
201
+ // Each phase's milliseconds, reported with the save: on a large document the save is the
202
+ // edit's cost, and where it goes differs by host (a tab-served project runs the server here).
203
+ const ms: Record<string, number> = {};
204
+ let mark = performance.now();
205
+ const lap = (phase: string) => {
206
+ const now = performance.now();
207
+ ms[phase] = Math.round(now - mark);
208
+ mark = now;
209
+ };
201
210
  let answer: { saved?: boolean; path?: string; size?: number };
202
211
  try {
203
212
  answer = (await engine.request({ op: 'save-document' })) as typeof answer;
213
+ lap('save');
204
214
  } catch (error) {
205
215
  // A document that cannot be written is the session's work at risk, so it
206
216
  // is a named condition in the editor's console, not a debug line.
@@ -211,6 +221,7 @@ async function saveDocument(): Promise<void> {
211
221
  let bytes: Uint8Array;
212
222
  try {
213
223
  bytes = await engine.files.readFile(answer.path);
224
+ lap('read');
214
225
  } catch (error) {
215
226
  throw new Error(`The Blender document ${relative} could not be read back out of the engine: ${describeThrown(error)}`);
216
227
  }
@@ -222,6 +233,7 @@ async function saveDocument(): Promise<void> {
222
233
  let sent = 0;
223
234
  try {
224
235
  const chunks = await documentChunks(bytes);
236
+ lap('chunk');
225
237
  const query = `path=${encodeURIComponent(relative)}`;
226
238
  const manifest = JSON.stringify({ chunks: chunks.map(({ hash, start, end }) => [hash, end - start]) });
227
239
  // The manifest asks for what the server lacks; after those are sent it commits. A second
@@ -232,9 +244,15 @@ async function saveDocument(): Promise<void> {
232
244
  headers: { 'content-type': 'application/json' },
233
245
  body: manifest,
234
246
  });
235
- const said = (await posted.json().catch(() => null)) as { ok?: boolean; missing?: string[]; error?: string } | null;
247
+ const said = (await posted.json().catch(() => null)) as
248
+ | { ok?: boolean; missing?: string[]; error?: string; ms?: Record<string, number> }
249
+ | null;
250
+ lap(`manifest${round}`);
236
251
  if (!posted.ok) throw new Error(`HTTP ${posted.status} ${said?.error ?? ''}`);
237
- if (said?.ok) break;
252
+ if (said?.ok) {
253
+ for (const [phase, value] of Object.entries(said.ms ?? {})) ms[`server.${phase}`] = value;
254
+ break;
255
+ }
238
256
  if (round === 2 || !Array.isArray(said?.missing)) throw new Error(`the server still lacks ${said?.missing?.length ?? '?'} chunks`);
239
257
  const wanted = new Set(said.missing);
240
258
  for (const chunk of chunks) {
@@ -247,12 +265,13 @@ async function saveDocument(): Promise<void> {
247
265
  if (!part.ok) throw new Error(`HTTP ${part.status} ${await part.text().catch(() => '')}`);
248
266
  sent += chunk.end - chunk.start;
249
267
  }
268
+ lap(`send${round}`);
250
269
  }
251
270
  } catch (error) {
252
271
  throw new Error(`The Blender document ${relative} was not written to the project: ${describeThrown(error)}`);
253
272
  }
254
273
  setDocumentDirty(false);
255
- log('log', `@@VOLTER-DOCUMENT ${JSON.stringify({ path: relative, bytes: bytes.length, sent })}`);
274
+ log('log', `@@VOLTER-DOCUMENT ${JSON.stringify({ path: relative, bytes: bytes.length, sent, ms })}`);
256
275
  }
257
276
 
258
277
  async function startBlender(project: string, document?: string): Promise<unknown> {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@volter/blender-engine",
3
3
  "author": "Volter AI, Inc.",
4
4
  "license": "GPL-3.0-or-later",
5
- "version": "0.1.45",
5
+ "version": "0.1.46",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },