@justai/cuts 0.127.0 → 0.128.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": "@justai/cuts",
3
- "version": "0.127.0",
3
+ "version": "0.128.0",
4
4
  "description": "A persona's named parts — the page shell that holds them, and the cuts themselves.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -420,11 +420,72 @@ const { id, title = "Choose a file", src = "/files" } = Astro.props;
420
420
  };
421
421
  }
422
422
 
423
+ // queries: write a file without asking · FilePicker write · a persona's own cached asset ·
424
+ // keep a dependency a project points at · write vs save · save asks and I do not want
425
+ // to ask · store a file the person did not make · project dependency from outside files
426
+ //
427
+ // THE SECOND VERB THAT ASKS NOBODY, AND THE ONE THAT WAS MISSING.
428
+ //
429
+ // `save` is deliberately not a friendlier `write`. The kernel's own corpus states the split and
430
+ // it is not about permission — both write the same origin under the same policy:
431
+ //
432
+ // `write` is arithmetic and keeps the PERSONA's things — a cached asset, a draft it will
433
+ // reopen itself. `save` is an interaction and hands a person THEIRS, because the two questions
434
+ // that make a saved document a document — what is it called, where does it go — are the
435
+ // person's to answer.
436
+ //
437
+ // The service has had `write` since the beginning. This door did not expose it, and for fifteen
438
+ // personas that was invisible, because the only project dependency anybody had was `qr`'s logo —
439
+ // which arrives through `pick`, so it is already in files and already has an id.
440
+ //
441
+ // `3dviewer` is the first persona whose dependency comes from OUTSIDE: a model dragged off a
442
+ // desktop. Its project file must point at that model, so the model needs a home — and it is not
443
+ // a document the person made here, it is the asset this persona will reopen itself. Exactly the
444
+ // case the paragraph above describes, with no verb to express it. The persona was left choosing
445
+ // between a doctrine it could not follow and a second Save sheet asking somebody to name a file
446
+ // they did not create.
447
+ //
448
+ // ADDITIVE, and that matters: nothing that exists behaves differently. The policy still answers
449
+ // "who is asking" — same-origin only, exactly as `read` does — so this widens no door.
450
+ //
451
+ // It returns the NODE, because a caller writing a project dependency needs the `id`: a path is
452
+ // what a person renames and an id is what a thing IS.
453
+ async function write(
454
+ path: string,
455
+ bytes: ArrayBuffer | Uint8Array,
456
+ opts: { mime?: string; keepVersions?: number } = {},
457
+ ): Promise<{ id: string; name: string; path: string } | null> {
458
+ const bus = await router();
459
+ ensureFrame();
460
+ const body = bytes instanceof Uint8Array
461
+ ? (bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength
462
+ ? bytes.buffer
463
+ : bytes.slice().buffer)
464
+ : bytes;
465
+ const node = await arrived!
466
+ .then(() => bus.proxy({
467
+ service: "files",
468
+ method: "write",
469
+ args: { path, bytes: body, mime: opts.mime, keepVersions: opts.keepVersions },
470
+ // The same 30s ceiling `read` uses. A model is tens of megabytes and a phone's storage is
471
+ // not fast; the default would time out on exactly the files this verb exists for.
472
+ options: { timeout: 30000 },
473
+ }))
474
+ .catch(() => null);
475
+ // A quota that is full, or a path the kernel refused. `null` rather than a throw, for the same
476
+ // reason `read` returns null: a caller must be able to carry on and say so.
477
+ if (!node) return null;
478
+ const n = node as { id: string; name: string };
479
+ return { id: n.id, name: n.name, path };
480
+ }
481
+
423
482
  (host as any).pick = pick;
424
483
  (sheet as any).pick = pick;
425
484
  (host as any).save = save;
426
485
  (sheet as any).save = save;
427
486
  (host as any).read = read;
428
487
  (sheet as any).read = read;
488
+ (host as any).write = write;
489
+ (sheet as any).write = write;
429
490
  }
430
491
  </script>