@gemmein/sdk 0.4.3 → 0.4.4

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/dist/index.cjs CHANGED
@@ -671,6 +671,12 @@ class CollectionClient {
671
671
  * Pass `{ name }` so the download carries a real filename, and
672
672
  * `{ contentType }` when the Blob has no type of its own.
673
673
  *
674
+ * W7.4 — `{ for: userId }` names ONE other person who may read this file
675
+ * (addressed and direct collections only — the rules where recipients
676
+ * exist). The attachment on a direct message: upload with
677
+ * `{ for: recipientId }`, store the ref in the record you send them, and
678
+ * their `g.files.link(ref)` works. Without `for`, only you can link it.
679
+ *
674
680
  * There is deliberately no `url` here. A URL that outlives a refund is the
675
681
  * bug this replaced.
676
682
  */
@@ -682,7 +688,7 @@ class CollectionClient {
682
688
  // Step 1: Get presigned upload URL
683
689
  const presign = await this.request("/upload", {
684
690
  method: "POST",
685
- body: JSON.stringify({ name, size: file.size, contentType }),
691
+ body: JSON.stringify({ name, size: file.size, contentType, ...(options?.for ? { for: options.for } : {}) }),
686
692
  });
687
693
  // Step 2: Upload directly to S3 via presigned POST
688
694
  const form = new FormData();
package/dist/index.d.cts CHANGED
@@ -500,12 +500,19 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
500
500
  * Pass `{ name }` so the download carries a real filename, and
501
501
  * `{ contentType }` when the Blob has no type of its own.
502
502
  *
503
+ * W7.4 — `{ for: userId }` names ONE other person who may read this file
504
+ * (addressed and direct collections only — the rules where recipients
505
+ * exist). The attachment on a direct message: upload with
506
+ * `{ for: recipientId }`, store the ref in the record you send them, and
507
+ * their `g.files.link(ref)` works. Without `for`, only you can link it.
508
+ *
503
509
  * There is deliberately no `url` here. A URL that outlives a refund is the
504
510
  * bug this replaced.
505
511
  */
506
512
  upload(file: Blob | File, options?: {
507
513
  name?: string;
508
514
  contentType?: string;
515
+ for?: string;
509
516
  }): Promise<{
510
517
  id: string;
511
518
  ref: FileRef;
package/dist/index.d.ts CHANGED
@@ -500,12 +500,19 @@ export declare class CollectionClient<T extends Record<string, unknown> = Record
500
500
  * Pass `{ name }` so the download carries a real filename, and
501
501
  * `{ contentType }` when the Blob has no type of its own.
502
502
  *
503
+ * W7.4 — `{ for: userId }` names ONE other person who may read this file
504
+ * (addressed and direct collections only — the rules where recipients
505
+ * exist). The attachment on a direct message: upload with
506
+ * `{ for: recipientId }`, store the ref in the record you send them, and
507
+ * their `g.files.link(ref)` works. Without `for`, only you can link it.
508
+ *
503
509
  * There is deliberately no `url` here. A URL that outlives a refund is the
504
510
  * bug this replaced.
505
511
  */
506
512
  upload(file: Blob | File, options?: {
507
513
  name?: string;
508
514
  contentType?: string;
515
+ for?: string;
509
516
  }): Promise<{
510
517
  id: string;
511
518
  ref: FileRef;
package/dist/index.js CHANGED
@@ -655,6 +655,12 @@ export class CollectionClient {
655
655
  * Pass `{ name }` so the download carries a real filename, and
656
656
  * `{ contentType }` when the Blob has no type of its own.
657
657
  *
658
+ * W7.4 — `{ for: userId }` names ONE other person who may read this file
659
+ * (addressed and direct collections only — the rules where recipients
660
+ * exist). The attachment on a direct message: upload with
661
+ * `{ for: recipientId }`, store the ref in the record you send them, and
662
+ * their `g.files.link(ref)` works. Without `for`, only you can link it.
663
+ *
658
664
  * There is deliberately no `url` here. A URL that outlives a refund is the
659
665
  * bug this replaced.
660
666
  */
@@ -666,7 +672,7 @@ export class CollectionClient {
666
672
  // Step 1: Get presigned upload URL
667
673
  const presign = await this.request("/upload", {
668
674
  method: "POST",
669
- body: JSON.stringify({ name, size: file.size, contentType }),
675
+ body: JSON.stringify({ name, size: file.size, contentType, ...(options?.for ? { for: options.for } : {}) }),
670
676
  });
671
677
  // Step 2: Upload directly to S3 via presigned POST
672
678
  const form = new FormData();
package/llms.txt CHANGED
@@ -291,7 +291,7 @@ go-live. Everything else is yours.
291
291
  - Images & files: NEVER base64 into record data and NEVER wire up your own
292
292
  storage bucket — uploads are built in:
293
293
  `const file = await g.collection("posts").upload(blob, { name })`
294
- → `{ id, ref, contentType, sizeBytes }`. Store `file.ref` (`"file:01K…"`)
294
+ → `{ id, ref, contentType, sizeBytes }`. Store `file.ref` (`"file:9f2c…"` — a UUID form)
295
295
  in a record field like any text — that's how a record "has" an image or
296
296
  a document.
297
297
  Store the REFERENCE, never a URL: a reference never expires and grants
@@ -318,14 +318,27 @@ go-live. Everything else is yours.
318
318
  the console shows by name).
319
319
  Honest bound: revoking access stops NEW links immediately; a link already
320
320
  issued works until it expires. Gemmein controls delivery, it can't take
321
- back a file someone already downloaded.
321
+ back a file someone already downloaded. A file can name ONE other reader:
322
+ `upload(blob, { for: userId })` (addressed/direct collections only) — the
323
+ direct message's attachment; the recipient's `files.link` works, everyone
324
+ else's still refuses. Without `for`, only the uploader can link it —
325
+ including in a client portal, where the OWNER hands a client a document
326
+ from the dashboard (attach it on the client's record there).
322
327
  - Shapes: collections your users write (community, shared, direct) have a
323
328
  SHAPE — the set of fields allowed. While your human builds, the server
324
329
  learns it from your writes automatically (nothing to do); when they go
325
- live it locks. A 400 invalid_shape means the field isn't in the locked
326
- shape. A live shape is sealed and cannot take new fields stop, tell
327
- your human which field you needed, and send only the fields the shape
328
- already has. Never rename fields to dodge it.
330
+ live it locks. Field kinds the shape learns: text, number, yes/no, list,
331
+ link (a stored record id), json, and FILE a field that held an
332
+ upload()'s ref learns as a file field and WHICH class (an image field
333
+ vs a document field, from what you actually uploaded). Once locked, the
334
+ field accepts only a reference to a real, confirmed file of this app
335
+ that the writer may read, of the right class — a ZIP into a profile
336
+ photo field is refused with the teach, as is a made-up or foreign ref
337
+ ("file not found"). A 400 invalid_shape means the field isn't in the locked
338
+ shape or the value doesn't fit its kind. A live shape is sealed and
339
+ cannot take new fields — stop, tell your human which field you needed,
340
+ and send only the fields the shape already has. Never rename fields to
341
+ dodge it.
329
342
  - Contention (bookings, slugs, stock, shared edits): when two users can race
330
343
  for the same thing, a permission model can't save you — preconditions do,
331
344
  and they're just arguments on calls you already make. A 409 `conflict` from
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gemmein/sdk",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "Gemmein SDK \u2014 passwordless auth, safe storage, and Stripe-driven record flips for AI-built apps. Small enough that one prompt teaches the whole API.",
5
5
  "license": "MIT",
6
6
  "type": "module",