@stapel/cdn-react 0.1.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -1 +1,92 @@
1
1
  # @stapel/cdn-react
2
+
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 88a8be4: `<MediaGalleryField bag={…}>` — the prop the README documented and the package did not have
8
+
9
+ The field always built its own `useUploadQueue`, so a composer beside it had
10
+ two queues: its own, permanently empty, and the one on screen. `bag.settled` —
11
+ the publish gate — then talked about photos it could not see, and
12
+ `images_draft` went out empty while ten tiles sat there uploading. The
13
+ documented wiring (`<MediaGalleryField bag={gallery} />`, in this pair's README
14
+ and in `@stapel/listings-react`'s) simply did not compile.
15
+
16
+ Props are now a union: `{ bag }` **or** `{ max, target, initialRefs,
17
+ onRefsChange }`. Passing both is a type error rather than a runtime decision
18
+ about which queue wins.
19
+
20
+ ```tsx
21
+ const gallery = useUploadQueue({ max: 10 });
22
+ <ListingComposerPage images={gallery} gallerySlot={<MediaGalleryField bag={gallery} />} … />
23
+ ```
24
+
25
+ `test/galleryBag.test.tsx` proves the two halves see ONE queue — a pick through
26
+ the tiles reaches the caller's `refs` and moves the caller's `settled` — and
27
+ gates the README against the props declaration, because the defect was
28
+ documented for a whole release and nothing in the suite could tell.
29
+
30
+ ## 0.2.0
31
+
32
+ ### Minor Changes
33
+
34
+ - 234a091: New pair: `@stapel/cdn-react` — the React half of `stapel-cdn`, and the end of
35
+ `profiles-react/src/api/cdnAvatarApi.ts`'s stated reason to exist.
36
+
37
+ The storefront spec's verdict was that the three upload implementations in this
38
+ fleet are three DIFFERENT contracts, not three copies of one algorithm, and this
39
+ package holds to it: it implements cdn's contract (multipart POST to an
40
+ authenticated origin), while the two genuinely contract-free bones the OTHER two
41
+ share stayed in `@stapel/core` (`putToForeignOrigin`, `useObjectUrlPreview`).
42
+ Only the second appears here — there is no foreign origin in this contract to
43
+ PUT to, and inventing a use for the first would have been the fourth copy in a
44
+ different disguise.
45
+
46
+ What cdn's contract has that the others do not is a content-addressed store with
47
+ a public "do you already have these bytes?" question, so the flow leads with it:
48
+
49
+ ```
50
+ validate ─┬─ refuse (client-side mirror of the deployment's own ceilings)
51
+ └─ hash ── file/exists/ ─┬─ HIT → done, ZERO bytes sent
52
+ └─ MISS → multipart POST → wait for variants
53
+ ```
54
+
55
+ The hit leg is asserted by **counting requests**, which is the only assertion a
56
+ flow that merely looks right cannot pass. And a hit is checked three ways, not
57
+ one: `exists` alone answers about any object with those bytes, so the same file
58
+ stored earlier as a video — or as an avatar rather than a listing photo — is not
59
+ the row the POST would return, and short-circuiting on it would hand a composer
60
+ a reference to the wrong thing.
61
+
62
+ Surface:
63
+
64
+ - `useUploadQueue` / `<MediaUploader max={N}>` — the bag a listing composer
65
+ consumes. `refs` is the ordered `<type>/<hash>` list to store, `reorder` is the
66
+ only way that order moves, and `canAdd` / `settled` are `ActionAvailability`
67
+ so a switched-off Add and a switched-off Save each say which of the reasons
68
+ they are. Per-item cancel (including of an item still waiting for a
69
+ concurrency slot), retry, remove; a reopened draft starts from stored
70
+ references and makes no requests.
71
+ - `useUploadImage` / `<ImageUpload>` — the one-slot shape, built for
72
+ `profiles-react`'s `useSetAvatar` to sit on.
73
+ - `/default` — antd `<MediaGalleryField>` (grid, drag-reorder AND move buttons,
74
+ because drag reaches neither a keyboard nor a phone) and `<ImageUploadField>`.
75
+ - `toStapelImage` — the single place that knows stapel-cdn spells `tier` as an
76
+ int while `@stapel/image` spells it as a string.
77
+ - en inline, `./i18n/ru` and `./i18n/es` opt-in; the 11 error keys stapel-cdn
78
+ owns are authored here because upstream ships no `translations/` at all.
79
+
80
+ Two decisions recorded rather than papered over:
81
+
82
+ **No progress percentage.** `fetch` cannot observe request-body progress through
83
+ the injected client and `SubtleCrypto.digest` reports nothing mid-digest. A bar
84
+ would have meant forking onto `XMLHttpRequest` — a second transport with its own
85
+ auth, refresh and error handling — or animating a number nobody measured. The
86
+ bag names the PHASE instead.
87
+
88
+ **The pre-check is an optimisation and never fails the upload.** `file/exists/`
89
+ is `IsAuthenticated` while the upload endpoints take `IsNotAnonymousUser`, so a
90
+ guest reaches a 401 there and must still be able to post a photo; a page served
91
+ over plain `http://` has no `crypto.subtle` at all. Both fall through to the
92
+ POST and report `dedupSkipped` so a skin can explain it.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stapel contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/MODULE.md CHANGED
@@ -98,6 +98,24 @@ off has to be able to say WHICH of the two reasons it is. `bag.refs` contains
98
98
  only settled references, so it is never a promise about bytes that are not
99
99
  there.
100
100
 
101
+ ### …and the gallery has to be drawing the same bag
102
+
103
+ `<MediaGalleryField>` takes `bag` for exactly this reason. Its props are a
104
+ UNION — `{ bag }` or `{ max, target, initialRefs, onRefsChange }` — so a caller
105
+ cannot ask for both, and a composer's wiring is:
106
+
107
+ ```tsx
108
+ const gallery = useUploadQueue({ max: 10 });
109
+ <ListingComposerPage images={gallery} gallerySlot={<MediaGalleryField bag={gallery} />} … />
110
+ ```
111
+
112
+ Until 0.2.0 the field always built its own queue, and the two gates above were
113
+ then computed over a queue nobody was adding to: the composer's `settled` said
114
+ "wait for the photos" about photos it could not see, and `images_draft` went
115
+ out empty while ten tiles sat on screen. The prop was in this pair's README
116
+ before it was in the package — `test/galleryBag.test.tsx` now gates the README
117
+ against the props declaration so that cannot recur.
118
+
101
119
  ## Upstream notes (recorded, not worked around)
102
120
 
103
121
  - **No public read-by-reference.** `file/exists/` is owner-scoped, so nothing in
package/README.md CHANGED
@@ -48,6 +48,26 @@ The antd skin over the same bag is one import away:
48
48
  import { MediaGalleryField, ImageUploadField } from "@stapel/cdn-react/default";
49
49
  ```
50
50
 
51
+ ### Whose queue is it
52
+
53
+ `<MediaGalleryField>` either owns its queue or draws yours, and the two are
54
+ spelled as different prop sets so that "both" cannot be written:
55
+
56
+ ```tsx
57
+ // standalone: the field owns the queue
58
+ <MediaGalleryField max={10} onRefsChange={(refs) => form.set("images_draft", refs)} />
59
+
60
+ // beside a composer: the CALLER owns it, and both halves see one queue
61
+ const gallery = useUploadQueue({ max: 10 });
62
+ <ListingComposerPage images={gallery} gallerySlot={<MediaGalleryField bag={gallery} />} … />
63
+ ```
64
+
65
+ The second form is not a convenience. A composer reads `bag.refs` as
66
+ `images_draft` and `bag.settled` as its publish gate; a field that built its
67
+ own queue left the container with two — the composer's, permanently empty, and
68
+ the one on screen — so the publish gate talked about photos it could not see
69
+ and the listing was submitted with no images at all.
70
+
51
71
  ## One slot (avatar, cover)
52
72
 
53
73
  ```tsx
@@ -1,7 +1,29 @@
1
1
  import type { ReactElement } from "react";
2
+ import type { UploadQueueBag } from "../headless/useUploadQueue.js";
2
3
  import type { CdnRef } from "../api/types.js";
3
4
  import type { CdnUploadTarget } from "../model/upload.js";
4
- export interface MediaGalleryFieldProps {
5
+ /**
6
+ * The gallery over a queue the CALLER owns.
7
+ *
8
+ * This is the shape a composer needs and the one the field did not have. A
9
+ * listing composer takes `bag.refs` as `images_draft` and `bag.settled` as its
10
+ * publish gate, so the bag it was handed and the bag the gallery draws MUST be
11
+ * the same object. When the field built its own, the container had two queues:
12
+ * the composer's (empty, because nothing was ever added to it) and the one on
13
+ * screen — so the publish gate said "wait for the photos" about photos it
14
+ * could not see, and `images_draft` went out empty.
15
+ */
16
+ export interface MediaGalleryFieldBagProps {
17
+ /** The queue to draw. Hand it the same bag the composer got. */
18
+ bag: UploadQueueBag;
19
+ max?: undefined;
20
+ target?: undefined;
21
+ initialRefs?: undefined;
22
+ onRefsChange?: undefined;
23
+ }
24
+ /** The gallery that owns its own queue — a field standing alone. */
25
+ export interface MediaGalleryFieldOwnProps {
26
+ bag?: undefined;
5
27
  /** How many photos this gallery holds. The storefront's composer: 10. */
6
28
  max: number;
7
29
  target?: CdnUploadTarget;
@@ -10,5 +32,12 @@ export interface MediaGalleryFieldProps {
10
32
  /** The list to store, in display order, on every change. */
11
33
  onRefsChange?: (refs: readonly CdnRef[]) => void;
12
34
  }
35
+ /**
36
+ * Either the caller owns the queue (`bag`) or this field does (`max` and the
37
+ * options that configure one). Spelled as a union rather than as optional
38
+ * props so that passing both — two queues, one screen, the defect above — is a
39
+ * type error rather than a decision this component has to make at runtime.
40
+ */
41
+ export type MediaGalleryFieldProps = MediaGalleryFieldBagProps | MediaGalleryFieldOwnProps;
13
42
  export declare function MediaGalleryField(props: MediaGalleryFieldProps): ReactElement;
14
43
  //# sourceMappingURL=MediaGalleryField.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MediaGalleryField.d.ts","sourceRoot":"","sources":["../../src/default/MediaGalleryField.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,OAAO,CAAC;AAMvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAK1D,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,4DAA4D;IAC5D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CAClD;AAwLD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAa7E"}
1
+ {"version":3,"file":"MediaGalleryField.d.ts","sourceRoot":"","sources":["../../src/default/MediaGalleryField.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,OAAO,CAAC;AAIvD,OAAO,KAAK,EAAc,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEhF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAK1D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,yBAAyB;IACxC,gEAAgE;IAChE,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,oEAAoE;AACpE,MAAM,WAAW,yBAAyB;IACxC,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,4DAA4D;IAC5D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CAClD;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAC9B,yBAAyB,GACzB,yBAAyB,CAAC;AAwL9B,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAgB7E"}
@@ -12,6 +12,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
12
  * The first tile is labelled as the cover, because the order IS the meaning:
13
13
  * `Listing.images_draft` is stored in this order and the first reference is
14
14
  * what a search result card shows.
15
+ *
16
+ * ── Whose queue is it ──────────────────────────────────────────────────────
17
+ *
18
+ * Either the caller's (`bag`) or this field's (`max`). A composer consumes
19
+ * `bag.refs` as `images_draft` and `bag.settled` as its publish gate, so when
20
+ * a composer is on the page the bag it holds and the bag drawn here must be
21
+ * ONE object — see {@link MediaGalleryFieldBagProps}.
15
22
  */
16
23
  import { useRef, useState } from "react";
17
24
  import { Button, Space, Typography } from "antd";
@@ -58,6 +65,10 @@ function GalleryBody(props) {
58
65
  }) }), _jsx(Space, { wrap: true, align: "start", children: bag.items.length === 0 ? (_jsx(Typography.Text, { type: "secondary", "data-testid": "cdn-gallery-empty", children: t(CDN_I18N_KEYS.galleryEmpty) })) : (bag.items.map((item, index) => (_jsx(Tile, { item: item, index: index, bag: bag, onDragStart: setDragging, onDrop: onDrop }, item.id)))) }), _jsx("input", { ref: input, type: "file", multiple: true, accept: bag.accept.attribute, onChange: onPick, style: { display: "none" }, "data-testid": "cdn-gallery-input" }), _jsx(Button, { onClick: () => input.current?.click(), disabled: addGate.disabled, "data-testid": "cdn-gallery-add", "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", children: t(CDN_I18N_KEYS.pickImages) }), addGate.reason === undefined ? null : (_jsx(Typography.Text, { type: "secondary", "data-testid": "cdn-gallery-add-blocked", children: addGate.reason })), settledGate.reason === undefined ? null : (_jsx(Typography.Text, { type: "secondary", "data-testid": "cdn-gallery-unsettled", children: settledGate.reason }))] }));
59
66
  }
60
67
  export function MediaGalleryField(props) {
68
+ // A queue handed in is drawn directly: no `MediaUploader`, because mounting
69
+ // one would create the SECOND queue this prop exists to prevent.
70
+ if (props.bag !== undefined)
71
+ return _jsx(GalleryBody, { bag: props.bag });
61
72
  return (_jsx(MediaUploader, { max: props.max, ...(props.target !== undefined ? { target: props.target } : {}), ...(props.initialRefs !== undefined ? { initialRefs: props.initialRefs } : {}), ...(props.onRefsChange !== undefined
62
73
  ? { onRefsChange: props.onRefsChange }
63
74
  : {}), children: (bag) => _jsx(GalleryBody, { bag: bag }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"MediaGalleryField.js","sourceRoot":"","sources":["../../src/default/MediaGalleryField.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MediaGalleryField.js","sourceRoot":"","sources":["../../src/default/MediaGalleryField.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAGnE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4CrD,SAAS,IAAI,CAAC,KAMb;IACC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,YAAY,GAAG,eAAe,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACnC,MAAM,IAAI,GACR,IAAI,CAAC,KAAK,KAAK,SAAS;QACxB,IAAI,CAAC,KAAK,KAAK,UAAU;QACzB,IAAI,CAAC,KAAK,KAAK,WAAW;QAC1B,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC;IAE9B,OAAO,CACL,eACE,SAAS,QACT,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,EAC3C,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAC7C,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,iBACrB,kBAAkB,gBAClB,IAAI,CAAC,KAAK,EACtB,KAAK,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,aAElC,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CACtB,cAAK,KAAK,EAAE,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,GAAI,CACzD,CAAC,CAAC,CAAC,CACF,cAAK,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,WAAW,GAAI,CAC7E,EACD,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,gBAAgB,YAC3D,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GACV,EACjB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CACb,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,gBAAgB,YAC3D,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,GACX,CACnB,CAAC,CAAC,CAAC,IAAI,EACP,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CACd,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,kBAAkB,YAC7D,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,GACT,CACnB,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,UAAU,IAAC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,MAAM,EAAC,gBAAgB,GAAG,EACvE,MAAC,KAAK,IAAC,IAAI,EAAC,OAAO,EAAC,IAAI,mBACrB,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,MAAM,IACL,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,iBACtB,iBAAiB,oBACd,MAAM,2BACC,8DAAyD,YAE9E,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,GACrB,CACV,CAAC,CAAC,CAAC,IAAI,EACP,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,CACtD,KAAC,MAAM,IACL,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,iBACrB,gBAAgB,oBACb,MAAM,2BACC,8DAAyD,YAE9E,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,GACpB,CACV,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,MAAM,IACL,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,iBACtB,iBAAiB,oBACd,MAAM,2BACC,8DAAyD,YAE9E,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,GACrB,EACT,KAAC,MAAM,IACL,IAAI,EAAC,OAAO,EACZ,QAAQ,EAAE,KAAK,KAAK,CAAC,EACrB,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,iBAChC,kBAAkB,oBACf,MAAM,2BACC,8DAAyD,YAE9E,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,GAC1B,EACT,KAAC,MAAM,IACL,IAAI,EAAC,OAAO,EACZ,QAAQ,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EACxC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,iBAChC,gBAAgB,oBACb,MAAM,2BACC,8DAAyD,YAE9E,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,GACxB,IACH,IACJ,CACP,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAA8B;IACjD,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IACtB,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAE9D,MAAM,MAAM,GAAG,CAAC,KAAoC,EAAQ,EAAE;QAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;QACjC,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC;QACxB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACjD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7B,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,KAAa,EAAQ,EAAE;QACrC,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO;QAC9B,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7B,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,OAAO,CACL,MAAC,KAAK,IAAC,SAAS,EAAC,UAAU,iBAAa,aAAa,aACnD,KAAC,UAAU,CAAC,IAAI,mBAAa,mBAAmB,YAC7C,CAAC,CAAC,aAAa,CAAC,YAAY,EAAE;oBAC7B,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI;oBACvB,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG;iBACtB,CAAC,GACc,EAClB,KAAC,KAAK,IAAC,IAAI,QAAC,KAAK,EAAC,OAAO,YACtB,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACxB,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,mBAAmB,YAC9D,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,GACd,CACnB,CAAC,CAAC,CAAC,CACF,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC7B,KAAC,IAAI,IAEH,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,GAAG,EACR,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,IALT,IAAI,CAAC,EAAE,CAMZ,CACH,CAAC,CACH,GACK,EACR,gBACE,GAAG,EAAE,KAAK,EACV,IAAI,EAAC,MAAM,EACX,QAAQ,QACR,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,EAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,iBACd,mBAAmB,GAC/B,EACF,KAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,EACrC,QAAQ,EAAE,OAAO,CAAC,QAAQ,iBACd,iBAAiB,oBACd,MAAM,2BACC,8DAAyD,YAE9E,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,GACrB,EACR,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACrC,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,yBAAyB,YACpE,OAAO,CAAC,MAAM,GACC,CACnB,EACA,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzC,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,uBAAuB,YAClE,WAAW,CAAC,MAAM,GACH,CACnB,IACK,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,4EAA4E;IAC5E,iEAAiE;IACjE,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS;QAAE,OAAO,KAAC,WAAW,IAAC,GAAG,EAAE,KAAK,CAAC,GAAG,GAAI,CAAC;IACpE,OAAO,CACL,KAAC,aAAa,IACZ,GAAG,EAAE,KAAK,CAAC,GAAG,KACV,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC5D,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC3E,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS;YACnC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE;YACtC,CAAC,CAAC,EAAE,CAAC,YAEN,CAAC,GAAG,EAAE,EAAE,CAAC,KAAC,WAAW,IAAC,GAAG,EAAE,GAAG,GAAI,GACrB,CACjB,CAAC;AACJ,CAAC"}
@@ -11,5 +11,5 @@
11
11
  export { ImageUploadField } from "./ImageUploadField.js";
12
12
  export type { ImageUploadFieldProps } from "./ImageUploadField.js";
13
13
  export { MediaGalleryField } from "./MediaGalleryField.js";
14
- export type { MediaGalleryFieldProps } from "./MediaGalleryField.js";
14
+ export type { MediaGalleryFieldProps, MediaGalleryFieldBagProps, MediaGalleryFieldOwnProps, } from "./MediaGalleryField.js";
15
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EACV,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,wBAAwB,CAAC"}
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @stapel/cdn-react 0.1.0
1
+ # @stapel/cdn-react 0.3.0
2
2
 
3
3
  Headless React flow pair for stapel-cdn (contract >=0.12 <0.13) — business + state, zero visual opinion.
4
4
  Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$generated": "by scripts/gen-manifest.mjs — do not edit; drift-gated (pnpm gen:manifest:check)",
3
3
  "package": "@stapel/cdn-react",
4
- "version": "0.1.0",
4
+ "version": "0.3.0",
5
5
  "backend": {
6
6
  "module": "stapel-cdn",
7
7
  "contract": ">=0.12 <0.13"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stapel/cdn-react",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Headless React pair for stapel-cdn: a typed media-upload client whose flow is dedup-first — SHA-256 the bytes, ask file/exists/, and skip the POST entirely when the CDN already holds them. A phase-shaped upload bag (validate → hash → check → upload → variants), an ordered queue with per-item cancel/retry/remove and a max, object-URL previews with the revoke built in (@stapel/core's useObjectUrlPreview), and the opaque `<type>/<hash>` reference every consuming module actually stores. Client-side limits mirror the backend's own declared ceilings and never refuse what the server would accept. Zero visual opinion in the main entry; an opt-in /default subpath ships the antd skin.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -44,13 +44,6 @@
44
44
  "manifest.json",
45
45
  "llms.txt"
46
46
  ],
47
- "scripts": {
48
- "build": "tsc -p tsconfig.json",
49
- "test": "tsc -p tsconfig.demo.json && vitest run --exclude test/prodBundlePurity.test.ts",
50
- "test:pack": "vitest run test/prodBundlePurity.test.ts",
51
- "lint": "eslint .",
52
- "size": "size-limit"
53
- },
54
47
  "size-limit": [
55
48
  {
56
49
  "name": "index — headless pair (client + dedup-first upload flow + queue), no antd",
@@ -94,11 +87,6 @@
94
87
  },
95
88
  "devDependencies": {
96
89
  "@size-limit/preset-small-lib": "^11.2.0",
97
- "@stapel/core": "workspace:^",
98
- "@stapel/image": "workspace:^",
99
- "@stapel/showcase": "workspace:^",
100
- "@stapel/tokens": "workspace:^",
101
- "@stapel/tokens-antd": "workspace:^",
102
90
  "@tanstack/react-query": "^5.81.0",
103
91
  "@testing-library/react": "^16.3.0",
104
92
  "@types/react": "^19.1.0",
@@ -109,12 +97,24 @@
109
97
  "react-dom": "^19.1.0",
110
98
  "size-limit": "^11.2.0",
111
99
  "typescript": "^5.8.3",
112
- "vitest": "^3.2.4"
100
+ "vitest": "^3.2.4",
101
+ "@stapel/core": "^0.16.0",
102
+ "@stapel/image": "^0.2.0",
103
+ "@stapel/showcase": "^0.2.0",
104
+ "@stapel/tokens": "^0.5.0",
105
+ "@stapel/tokens-antd": "^0.5.0"
113
106
  },
114
107
  "engines": {
115
108
  "node": ">=22"
116
109
  },
117
110
  "publishConfig": {
118
111
  "access": "public"
112
+ },
113
+ "scripts": {
114
+ "build": "tsc -p tsconfig.json",
115
+ "test": "tsc -p tsconfig.demo.json && vitest run --exclude test/prodBundlePurity.test.ts",
116
+ "test:pack": "vitest run test/prodBundlePurity.test.ts",
117
+ "lint": "eslint .",
118
+ "size": "size-limit"
119
119
  }
120
- }
120
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$generated": "by scripts/gen-events.mjs — do not edit; drift-gated (pnpm gen:events:check)",
3
3
  "package": "@stapel/cdn-react",
4
- "version": "0.1.0",
4
+ "version": "0.3.0",
5
5
  "defined": [],
6
6
  "flows": []
7
7
  }
@@ -11,6 +11,13 @@
11
11
  * The first tile is labelled as the cover, because the order IS the meaning:
12
12
  * `Listing.images_draft` is stored in this order and the first reference is
13
13
  * what a search result card shows.
14
+ *
15
+ * ── Whose queue is it ──────────────────────────────────────────────────────
16
+ *
17
+ * Either the caller's (`bag`) or this field's (`max`). A composer consumes
18
+ * `bag.refs` as `images_draft` and `bag.settled` as its publish gate, so when
19
+ * a composer is on the page the bag it holds and the bag drawn here must be
20
+ * ONE object — see {@link MediaGalleryFieldBagProps}.
14
21
  */
15
22
  import { useRef, useState } from "react";
16
23
  import type { ChangeEvent, ReactElement } from "react";
@@ -25,7 +32,29 @@ import { CDN_I18N_KEYS } from "../i18n/keys.js";
25
32
  import { ErrorAlert } from "./ErrorAlert.js";
26
33
  import { PHASE_KEYS, PREVIEW_BOX } from "./phase.js";
27
34
 
28
- export interface MediaGalleryFieldProps {
35
+ /**
36
+ * The gallery over a queue the CALLER owns.
37
+ *
38
+ * This is the shape a composer needs and the one the field did not have. A
39
+ * listing composer takes `bag.refs` as `images_draft` and `bag.settled` as its
40
+ * publish gate, so the bag it was handed and the bag the gallery draws MUST be
41
+ * the same object. When the field built its own, the container had two queues:
42
+ * the composer's (empty, because nothing was ever added to it) and the one on
43
+ * screen — so the publish gate said "wait for the photos" about photos it
44
+ * could not see, and `images_draft` went out empty.
45
+ */
46
+ export interface MediaGalleryFieldBagProps {
47
+ /** The queue to draw. Hand it the same bag the composer got. */
48
+ bag: UploadQueueBag;
49
+ max?: undefined;
50
+ target?: undefined;
51
+ initialRefs?: undefined;
52
+ onRefsChange?: undefined;
53
+ }
54
+
55
+ /** The gallery that owns its own queue — a field standing alone. */
56
+ export interface MediaGalleryFieldOwnProps {
57
+ bag?: undefined;
29
58
  /** How many photos this gallery holds. The storefront's composer: 10. */
30
59
  max: number;
31
60
  target?: CdnUploadTarget;
@@ -35,6 +64,16 @@ export interface MediaGalleryFieldProps {
35
64
  onRefsChange?: (refs: readonly CdnRef[]) => void;
36
65
  }
37
66
 
67
+ /**
68
+ * Either the caller owns the queue (`bag`) or this field does (`max` and the
69
+ * options that configure one). Spelled as a union rather than as optional
70
+ * props so that passing both — two queues, one screen, the defect above — is a
71
+ * type error rather than a decision this component has to make at runtime.
72
+ */
73
+ export type MediaGalleryFieldProps =
74
+ | MediaGalleryFieldBagProps
75
+ | MediaGalleryFieldOwnProps;
76
+
38
77
  function Tile(props: {
39
78
  item: UploadItem;
40
79
  index: number;
@@ -218,6 +257,9 @@ function GalleryBody(props: { bag: UploadQueueBag }): ReactElement {
218
257
  }
219
258
 
220
259
  export function MediaGalleryField(props: MediaGalleryFieldProps): ReactElement {
260
+ // A queue handed in is drawn directly: no `MediaUploader`, because mounting
261
+ // one would create the SECOND queue this prop exists to prevent.
262
+ if (props.bag !== undefined) return <GalleryBody bag={props.bag} />;
221
263
  return (
222
264
  <MediaUploader
223
265
  max={props.max}
@@ -11,4 +11,8 @@
11
11
  export { ImageUploadField } from "./ImageUploadField.js";
12
12
  export type { ImageUploadFieldProps } from "./ImageUploadField.js";
13
13
  export { MediaGalleryField } from "./MediaGalleryField.js";
14
- export type { MediaGalleryFieldProps } from "./MediaGalleryField.js";
14
+ export type {
15
+ MediaGalleryFieldProps,
16
+ MediaGalleryFieldBagProps,
17
+ MediaGalleryFieldOwnProps,
18
+ } from "./MediaGalleryField.js";