@bagelink/vue 1.17.2 → 1.18.3
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/assetTransport.d.ts +9 -31
- package/dist/assetTransport.d.ts.map +1 -1
- package/dist/assets.d.ts +39 -20
- package/dist/assets.d.ts.map +1 -1
- package/dist/components/AddressSearch.vue.d.ts +40 -36
- package/dist/components/AddressSearch.vue.d.ts.map +1 -1
- package/dist/components/ContextMenu.vue.d.ts +518 -0
- package/dist/components/ContextMenu.vue.d.ts.map +1 -0
- package/dist/components/Dropdown.types.d.ts +25 -0
- package/dist/components/Dropdown.types.d.ts.map +1 -0
- package/dist/components/Dropdown.vue.d.ts +20 -15
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/FilterQuery.vue.d.ts +1 -1
- package/dist/components/FilterQuery.vue.d.ts.map +1 -1
- package/dist/components/Icon/Icon.vue.d.ts +0 -1
- package/dist/components/Icon/Icon.vue.d.ts.map +1 -1
- package/dist/components/Icon/constants.d.ts +0 -1
- package/dist/components/Icon/constants.d.ts.map +1 -1
- package/dist/components/Icon/types.d.ts +2 -3
- package/dist/components/Icon/types.d.ts.map +1 -1
- package/dist/components/Swiper.vue.d.ts +1 -1
- package/dist/components/draggable/useDraggable.d.ts.map +1 -1
- package/dist/components/form/inputs/IconPickerInput.vue.d.ts +48 -37
- package/dist/components/form/inputs/IconPickerInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/components/EditorToolbar.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useCommands.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts +3 -0
- package/dist/components/form/inputs/RichText/composables/useEditor.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts +1 -1
- package/dist/components/form/inputs/RichText/composables/useEditorKeyboard.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/commands.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/selection.d.ts +2 -0
- package/dist/components/form/inputs/RichText/utils/selection.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/utils/table.d.ts +34 -8
- package/dist/components/form/inputs/RichText/utils/table.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts +74 -65
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts +2 -2
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/composables/index.d.ts +1 -1
- package/dist/composables/index.d.ts.map +1 -1
- package/dist/composables/useBoundedRectDrag.d.ts.map +1 -1
- package/dist/composables/usePointerSession.d.ts +14 -3
- package/dist/composables/usePointerSession.d.ts.map +1 -1
- package/dist/core.css +3 -3
- package/dist/directives/vResize.d.ts.map +1 -1
- package/dist/form-flow/FormFlow.vue.d.ts.map +1 -1
- package/dist/form-flow/form-flow.d.ts +4 -2
- package/dist/form-flow/form-flow.d.ts.map +1 -1
- package/dist/form-flow/schema-fields.d.ts +4 -1
- package/dist/form-flow/schema-fields.d.ts.map +1 -1
- package/dist/index.cjs +240 -153
- package/dist/index.css +1 -1
- package/dist/index.mjs +18461 -18283
- package/dist/style.css +3 -3
- package/dist/types/BagelForm.d.ts +2 -0
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/assetTransport.test.ts +33 -83
- package/src/assetTransport.ts +24 -90
- package/src/assets.test.ts +58 -99
- package/src/assets.ts +78 -161
- package/src/components/ContextMenu.vue +113 -0
- package/src/components/Dropdown.types.ts +27 -0
- package/src/components/Dropdown.vue +129 -64
- package/src/components/FilterQuery.vue +1 -1
- package/src/components/Icon/Icon.vue +8 -30
- package/src/components/Icon/constants.ts +0 -166
- package/src/components/Icon/types.ts +2 -3
- package/src/components/draggable/useDraggable.ts +67 -100
- package/src/components/form/inputs/IconPickerInput.vue +14 -9
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +43 -111
- package/src/components/form/inputs/RichText/composables/useCommands.ts +32 -54
- package/src/components/form/inputs/RichText/composables/useEditor.ts +45 -171
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +90 -14
- package/src/components/form/inputs/RichText/index.vue +1195 -1210
- package/src/components/form/inputs/RichText/utils/commands.ts +689 -1028
- package/src/components/form/inputs/RichText/utils/selection.ts +66 -41
- package/src/components/form/inputs/RichText/utils/table.ts +798 -136
- package/src/components/form/inputs/SelectInput.vue +6 -4
- package/src/components/form/inputs/Upload/AssetUploadInput.vue +2 -2
- package/src/components/index.ts +3 -1
- package/src/composables/index.ts +1 -1
- package/src/composables/useBoundedRectDrag.ts +9 -12
- package/src/composables/usePointerSession.ts +57 -12
- package/src/directives/vResize.ts +6 -7
- package/src/form-flow/FormFlow.vue +4 -0
- package/src/form-flow/form-flow.ts +8 -3
- package/src/form-flow/schema-fields.ts +9 -4
- package/src/styles/core.css +1 -18
- package/src/types/BagelForm.ts +2 -0
- package/dist/components/form/inputs/RichText/utils/formatting.d.ts +0 -10
- package/dist/components/form/inputs/RichText/utils/formatting.d.ts.map +0 -1
- package/src/components/form/inputs/RichText/components/gridBox.vue +0 -58
- package/src/components/form/inputs/RichText/utils/formatting.ts +0 -331
|
@@ -100,6 +100,8 @@ export interface UploadInputValueObject {
|
|
|
100
100
|
export interface UploadInputProps extends BagelInputShellProps {
|
|
101
101
|
/** Opt-in stable reference output; defaults to legacy path-key behavior. */
|
|
102
102
|
assetMode?: boolean;
|
|
103
|
+
/** Asset delivery policy. Defaults to protected; website/media fields use public. */
|
|
104
|
+
assetVisibility?: import('../assets').AssetVisibility;
|
|
103
105
|
id?: string;
|
|
104
106
|
name?: string;
|
|
105
107
|
label?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BagelForm.d.ts","sourceRoot":"","sources":["../../src/types/BagelForm.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC/E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,CAAA;AAIhC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAA;AAErF,UAAU,MAAM;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE;AAI9C,MAAM,MAAM,KAAK,CAChB,CAAC,EACD,EAAE,SAAS,YAAY,GAAG,mBAAmB,IAC1C,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAG9C,KAAK,mBAAmB,CAAC,CAAC,IAAI;KAC5B,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAChD,GAAG,CAAC,GAAG,MAAM,IAAI,MAAM,EAAE,GACzB,KAAK;CACR,CAAC,MAAM,CAAC,CAAC,CAAA;AAGV,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,EAAE,SAAS,YAAY,GAAG,mBAAmB,IAC9D,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,GAC3C,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAChC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,MAAM,cAAc,MAAM,EAAE,CAAA;AAErF,uFAAuF;AACvF,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IACtC,OAAO,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAElD,sEAAsE;AACtE,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAC3C,CAAC,SAAS,MAAM,GACf,CAAC,SAAS,MAAM,CAAC,GAChB,CAAC,CAAC,CAAC,CAAC,GACJ,GAAG,GACJ,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAIlB,MAAM,MAAM,cAAc,GACrB,MAAM,GACP,MAAM,GACN,OAAO,GACP,SAAS,GACT;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAA;AAE1B,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,CAC/C,KAAK,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1B,GAAG,CAAC,EAAE,CAAC,KACH,cAAc,CAAA;AAEnB,MAAM,WAAW,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CACjD;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IACxC,MAAM,GACP,CACC;IACD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CACtB,GACC,MAAM,GACN,MAAM,GACN,OAAO,GACP;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CACxB,EAAE,GACD,CAAC,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAC/F,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;AAElF,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IACnC,MAAM,GACP,OAAO,GACP,CAAC,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,CAAA;AAEzD,MAAM,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,CAChD,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EACzB,OAAO,CAAC,EAAE,CAAC,KACP,MAAM,GAAG,SAAS,CAAA;AAEvB,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,CAC/C,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EACzB,OAAO,CAAC,EAAE,CAAC,KACP,GAAG,CAAA;AAER,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,CAC5C,GAAG,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EACzB,OAAO,CAAC,EAAE,CAAC,KACP,OAAO,CAAA;AAIZ,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE;IACnD,GAAG,CAAC,EAAE,CAAC,CAAA;IACP,KAAK,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAC3B,KAAK,KAAK,CAAA;AAEX,MAAM,WAAW,YAAY,CAC5B,CAAC,EACD,EAAE,SAAS,YAAY,GAAG,mBAAmB;IAE7C,GAAG,EAAE,GAAG,CAAA;IACR,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAA;IACzB,KAAK,CAAC,EAAE,GAAG,CAAA;IACX,GAAG,CAAC,EAAE,GAAG,CAAA;IACT,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3B,OAAO,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;IAC1C,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,GAAG,CAAA;IAC3C,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAA;CAChC;AAGD,KAAK,mBAAmB,CAAC,CAAC,EAAE,EAAE,SAAS,YAAY,GAAG,mBAAmB,IAAI;KAC3E,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;CAC5C,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAEd,MAAM,MAAM,WAAW,CACtB,CAAC,EACD,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,EACrB,EAAE,SAAS,YAAY,GAAG,mBAAmB,IAC1C,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,GAAG,mBAAmB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAEpG,MAAM,WAAW,cAAc,CAC9B,CAAC,EACD,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,EACrB,EAAE,SAAS,YAAY,GAAG,mBAAmB;IAE7C,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,CAAA;IACpB,IAAI,CAAC,EAAE,CAAC,CAAA;IACR,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,cAAc,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC5C,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9B,UAAU,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAA;IAC9C,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAA;KAAE,CAAA;IAC9D,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACtB,WAAW,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC/B,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3B,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAC/B;AAED,MAAM,MAAM,KAAK,CAChB,CAAC,EACD,EAAE,SAAS,YAAY,GAAG,mBAAmB,IAC1C,mBAAmB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAE9B,MAAM,MAAM,WAAW,CACtB,CAAC,EACD,EAAE,SAAS,YAAY,GAAG,mBAAmB,IAC1C,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAEtC,MAAM,MAAM,cAAc,CACzB,CAAC,EACD,EAAE,SAAS,YAAY,GAAG,mBAAmB,IAC1C,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAA;AAI/D,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,EAAE,YAAY,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,EAAE,MAAM,CAAC,CAAA;IAC3D,WAAW,CAAC,EAAE,MAAM,GAAG,CAAA;CACvB;AAED,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC7D,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,sBAAsB,GAAG,OAAO,WAAW,EAAE,cAAc,GAAG,CAAC,MAAM,GAAG,sBAAsB,GAAG,OAAO,WAAW,EAAE,cAAc,CAAC,EAAE,CAAA;IACvK,uFAAuF;IACvF,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,CAAA;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0FAA0F;IAC1F,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAChC"}
|
|
1
|
+
{"version":3,"file":"BagelForm.d.ts","sourceRoot":"","sources":["../../src/types/BagelForm.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,56 +4,16 @@ import { createAssetClient } from './assets'
|
|
|
4
4
|
import type { ApiTransport } from '@bagelink/sdk'
|
|
5
5
|
import { createApp, ref } from 'vue'
|
|
6
6
|
|
|
7
|
-
const session = { asset_id: 'a',
|
|
7
|
+
const session = { asset_id: 'a', upload_id: 'u', status: 'ready' }
|
|
8
8
|
const json = (value: unknown, status = 200) => new Response(JSON.stringify(value), { status })
|
|
9
9
|
const signal = () => new AbortController().signal
|
|
10
10
|
|
|
11
11
|
describe('asset REST transport', () => {
|
|
12
|
-
it('
|
|
13
|
-
const request = vi.fn().mockImplementation(() => new Promise(() => {}))
|
|
14
|
-
const transport = { axios: { defaults: { baseURL: 'https://api.example/api' }, request } } as unknown as ApiTransport
|
|
15
|
-
const sessionKey = ref('account:tenant-a')
|
|
16
|
-
const assets = configureAssetClient({ transport, sessionKey })
|
|
17
|
-
createApp({}).use(assets)
|
|
18
|
-
const result = assets.client.resolve({ asset_id: 'a', representation: 'website' })
|
|
19
|
-
const rejected = expect(result).rejects.toMatchObject({ name: 'AbortError' })
|
|
20
|
-
await Promise.resolve()
|
|
21
|
-
expect(request.mock.calls[0]![0].url).toBe('assets/resolve')
|
|
22
|
-
expect(JSON.parse(request.mock.calls[0]![0].data).references[0].representation).toBe('website')
|
|
23
|
-
sessionKey.value = 'account:tenant-b'
|
|
24
|
-
await rejected
|
|
25
|
-
expect(request.mock.calls[0]![0].signal.aborted).toBe(true)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('publishes only explicit image purposes with stable version-pinned URLs', async () => {
|
|
29
|
-
const fetcher = vi.fn<AssetFetch>().mockResolvedValue(json({
|
|
30
|
-
asset_id: 'a', version_id: 'v', published: true, name: 'photo',
|
|
31
|
-
representations: ['website', 'social'].map(representation => ({
|
|
32
|
-
representation, url: `/assets/a/public/v/${representation}`, media_type: 'image/jpeg', size: 42,
|
|
33
|
-
})),
|
|
34
|
-
}))
|
|
35
|
-
const transport = createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
|
|
36
|
-
const result = await transport.publish({ asset_id: 'a', version_id: 'v' })
|
|
37
|
-
expect(JSON.parse(String(fetcher.mock.calls[0]![1]?.body))).toEqual({
|
|
38
|
-
published: true, version_id: 'v', representations: ['website', 'social'],
|
|
39
|
-
})
|
|
40
|
-
expect(result.representations[1]?.url).toBe('https://api.example/assets/a/public/v/social')
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('rejects private grant URLs returned by publication', async () => {
|
|
44
|
-
const fetcher = vi.fn<AssetFetch>().mockResolvedValue(json({
|
|
45
|
-
asset_id: 'a', version_id: 'v', published: true,
|
|
46
|
-
representations: [{ representation: 'website', url: '/assets/a/content?token=secret' }],
|
|
47
|
-
}))
|
|
48
|
-
await expect(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
|
|
49
|
-
.publish({ asset_id: 'a', version_id: 'v' })).rejects.toThrow('Invalid public')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('starts a session and sends unchanged raw bytes, returning pinned references', async () => {
|
|
12
|
+
it('starts a session and sends unchanged raw bytes, returning the public id', async () => {
|
|
53
13
|
const fetcher = vi.fn<AssetFetch>().mockResolvedValueOnce(json(session)).mockResolvedValueOnce(json(session))
|
|
54
14
|
const transport = createAssetHttpTransport({ baseURL: 'https://api.example/api', fetch: fetcher })
|
|
55
15
|
const file = new File(['original'], 'test.heic')
|
|
56
|
-
expect(await transport.upload(file, signal())).toEqual({ asset_id: 'a'
|
|
16
|
+
expect(await transport.upload(file, signal())).toEqual({ asset_id: 'a' })
|
|
57
17
|
expect(String(fetcher.mock.calls[0]![0])).toBe('https://api.example/api/assets/uploads')
|
|
58
18
|
expect(fetcher.mock.calls[0]![1]?.body).toBe('{"name":"test.heic"}')
|
|
59
19
|
expect(fetcher.mock.calls[1]![1]?.body).toBe(file)
|
|
@@ -65,30 +25,7 @@ describe('asset REST transport', () => {
|
|
|
65
25
|
.mockResolvedValueOnce(json({ ...session, status: 'rejected' })).mockResolvedValueOnce(json({}, 403))
|
|
66
26
|
const transport = createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
|
|
67
27
|
await expect(transport.upload(new File(['x'], 'x'), signal())).rejects.toThrow('not ready')
|
|
68
|
-
await expect(transport.
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('chunks 101 references and resolves relative URLs against the API origin', async () => {
|
|
72
|
-
const fetcher = vi.fn<AssetFetch>(async (_url, init) => {
|
|
73
|
-
const { references } = JSON.parse(String(init?.body)) as { references: { asset_id: string }[] }
|
|
74
|
-
return json({ items: references.map(reference => ({
|
|
75
|
-
...reference, version_id: 'v', representation: 'original',
|
|
76
|
-
url: '/assets/content?token=secret', expires_at: new Date(Date.now() + 60000).toISOString(),
|
|
77
|
-
})) })
|
|
78
|
-
})
|
|
79
|
-
const transport = createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
|
|
80
|
-
const items = await transport.resolve(Array.from({ length: 101 }, (_, i) => ({ asset_id: String(i) })), signal())
|
|
81
|
-
expect(fetcher.mock.calls.map(call => JSON.parse(String(call[1]?.body)).references.length)).toEqual([50, 50, 1])
|
|
82
|
-
expect(items).toHaveLength(101)
|
|
83
|
-
expect(items[0]?.url).toBe('https://api.example/assets/content?token=secret')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('rejects untrusted delivery origins', async () => {
|
|
87
|
-
const fetcher = vi.fn<AssetFetch>().mockResolvedValue(json({ items: [{
|
|
88
|
-
asset_id: 'a', version_id: 'v', representation: 'original', url: '//evil.example/file',
|
|
89
|
-
}] }))
|
|
90
|
-
await expect(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher })
|
|
91
|
-
.resolve([{ asset_id: 'a' }], signal())).rejects.toThrow('Untrusted')
|
|
28
|
+
await expect(transport.upload(new File(['x'], 'x'), signal())).rejects.toThrow('(403)')
|
|
92
29
|
})
|
|
93
30
|
|
|
94
31
|
it('does not PUT if session creation fails', async () => {
|
|
@@ -98,28 +35,41 @@ describe('asset REST transport', () => {
|
|
|
98
35
|
expect(fetcher).toHaveBeenCalledTimes(1)
|
|
99
36
|
})
|
|
100
37
|
|
|
101
|
-
it('
|
|
38
|
+
it('configureAssetClient provides a client that builds public URLs', () => {
|
|
39
|
+
const transport = { axios: { defaults: { baseURL: 'https://api.example/api' }, request: vi.fn() } } as unknown as ApiTransport
|
|
40
|
+
const assets = configureAssetClient({ transport, deliveryBaseUrl: 'https://cdn.bgl.dev/auctentic' })
|
|
41
|
+
expect(assets.client.assetUrl({ asset_id: 'a' })).toBe('https://cdn.bgl.dev/auctentic/a')
|
|
42
|
+
expect(assets.client.assetUrl({ asset_id: 'a' }, 'website')).toBe('https://cdn.bgl.dev/auctentic/a?fmt=webp')
|
|
43
|
+
expect(assets.client.assetUrl({ asset_id: 'a' }, 'social')).toBe('https://cdn.bgl.dev/auctentic/a?w=1200&h=630&fmt=jpeg&fit=cover')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('clears in-flight uploads on session change', async () => {
|
|
47
|
+
let requestSignal: AbortSignal | null | undefined
|
|
48
|
+
const fetcher = vi.fn<AssetFetch>((config: any) => {
|
|
49
|
+
requestSignal = config?.signal
|
|
50
|
+
return new Promise((_resolve, reject) => requestSignal?.addEventListener('abort', () => reject(requestSignal?.reason))
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
const transport = { axios: { defaults: { baseURL: 'https://api.example' }, request: fetcher } } as unknown as ApiTransport
|
|
54
|
+
const sessionKey = ref('a')
|
|
55
|
+
const assets = configureAssetClient({ transport, deliveryBaseUrl: 'https://cdn.bgl.dev/auctentic', sessionKey })
|
|
56
|
+
createApp({}).use(assets)
|
|
57
|
+
const promise = assets.client.upload(new File(['x'], 'x'))
|
|
58
|
+
sessionKey.value = 'b'
|
|
59
|
+
await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
|
|
60
|
+
expect(requestSignal?.aborted).toBe(true)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('asset client upload cancellation', () => {
|
|
65
|
+
it('does not complete after clearSession', async () => {
|
|
102
66
|
let finish!: (response: Response) => void
|
|
103
67
|
const fetcher = vi.fn<AssetFetch>().mockImplementationOnce(() => new Promise(resolve => { finish = resolve }))
|
|
104
|
-
const client = createAssetClient(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher }))
|
|
68
|
+
const client = createAssetClient(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher }), 'https://cdn.bgl.dev/auctentic')
|
|
105
69
|
const promise = client.upload(new File(['x'], 'x'))
|
|
106
70
|
client.clearSession()
|
|
107
71
|
finish(json(session))
|
|
108
72
|
await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
|
|
109
73
|
expect(fetcher).toHaveBeenCalledTimes(1)
|
|
110
74
|
})
|
|
111
|
-
|
|
112
|
-
it('session cleanup aborts the HTTP request', async () => {
|
|
113
|
-
let requestSignal: AbortSignal | null | undefined
|
|
114
|
-
const fetcher = vi.fn<AssetFetch>((_url, init) => {
|
|
115
|
-
requestSignal = init?.signal
|
|
116
|
-
return new Promise((_resolve, reject) => requestSignal?.addEventListener('abort', () => reject(requestSignal?.reason)))
|
|
117
|
-
})
|
|
118
|
-
const client = createAssetClient(createAssetHttpTransport({ baseURL: 'https://api.example', fetch: fetcher }))
|
|
119
|
-
const promise = client.resolve({ asset_id: 'a' })
|
|
120
|
-
await Promise.resolve()
|
|
121
|
-
client.clearSession()
|
|
122
|
-
await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
|
|
123
|
-
expect(requestSignal?.aborted).toBe(true)
|
|
124
|
-
})
|
|
125
75
|
})
|
package/src/assetTransport.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAssetClient, ASSET_CLIENT_KEY, type
|
|
1
|
+
import { createAssetClient, ASSET_CLIENT_KEY, type AssetTransport } from './assets'
|
|
2
2
|
import type { ApiTransport } from '@bagelink/sdk'
|
|
3
3
|
import { watch, toValue, type App, type MaybeRefOrGetter } from 'vue'
|
|
4
4
|
|
|
@@ -10,30 +10,20 @@ export interface AssetHttpOptions {
|
|
|
10
10
|
headers?: () => HeadersInit
|
|
11
11
|
fetch?: AssetFetch
|
|
12
12
|
credentials?: RequestCredentials
|
|
13
|
-
/** Explicitly trusted delivery origins besides the API origin. */
|
|
14
|
-
deliveryOrigins?: string[]
|
|
15
13
|
/** Reuse the app's authenticated axios instance, including tenant interceptors. */
|
|
16
14
|
apiTransport?: ApiTransport
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
interface UploadResponse {
|
|
20
18
|
asset_id: string
|
|
21
|
-
version_id: string
|
|
22
19
|
upload_id: string
|
|
23
20
|
status: string
|
|
24
21
|
}
|
|
25
|
-
interface DeliveryResponse extends AssetDelivery {
|
|
26
|
-
asset_id: string
|
|
27
|
-
representation: string
|
|
28
|
-
}
|
|
29
22
|
|
|
30
|
-
/** Concrete REST adapter
|
|
31
|
-
export function createAssetHttpTransport(options: AssetHttpOptions): AssetTransport
|
|
32
|
-
publish(reference: Required<AssetReference>, signal?: AbortSignal): Promise<AssetPublication>
|
|
33
|
-
} {
|
|
23
|
+
/** Concrete REST adapter. Public-by-default: upload only; display is a client-built URL. */
|
|
24
|
+
export function createAssetHttpTransport(options: AssetHttpOptions): AssetTransport {
|
|
34
25
|
const base = new URL(options.baseURL.endsWith('/') ? options.baseURL : `${options.baseURL}/`)
|
|
35
26
|
if (!['http:', 'https:'].includes(base.protocol) || base.username || base.password) throw new Error('Invalid API base')
|
|
36
|
-
const trusted = new Set([base.origin, ...(options.deliveryOrigins ?? []).map(origin => new URL(origin).origin)])
|
|
37
27
|
const request = options.fetch ?? globalThis.fetch
|
|
38
28
|
async function send<T>(path: string, init: RequestInit, signal: AbortSignal): Promise<T> {
|
|
39
29
|
signal.throwIfAborted()
|
|
@@ -57,108 +47,52 @@ export function createAssetHttpTransport(options: AssetHttpOptions): AssetTransp
|
|
|
57
47
|
return await response.json() as T
|
|
58
48
|
}
|
|
59
49
|
return {
|
|
60
|
-
async
|
|
61
|
-
const result = await send<AssetPublication>(`${encodeURIComponent(reference.asset_id)}/publication`, {
|
|
62
|
-
method: 'PUT', headers: { 'Content-Type': 'application/json' },
|
|
63
|
-
body: JSON.stringify({ published: true, version_id: reference.version_id, representations: ['website', 'social'] }),
|
|
64
|
-
}, signal)
|
|
65
|
-
if (result.asset_id !== reference.asset_id || result.version_id !== reference.version_id || !result.published) {
|
|
66
|
-
throw new Error('Mismatched asset publication')
|
|
67
|
-
}
|
|
68
|
-
for (const purpose of ['website', 'social'] as const) {
|
|
69
|
-
const item = result.representations.find(item => item.representation === purpose)
|
|
70
|
-
if (!item) throw new Error('Incomplete asset publication')
|
|
71
|
-
const url = new URL(item.url, base)
|
|
72
|
-
const suffix = `/assets/${encodeURIComponent(reference.asset_id)}/public/${encodeURIComponent(reference.version_id)}/${purpose}`
|
|
73
|
-
if (!trusted.has(url.origin) || !['http:', 'https:'].includes(url.protocol)
|
|
74
|
-
|| url.username || url.password || url.search || url.hash || !url.pathname.endsWith(suffix)) {
|
|
75
|
-
throw new Error('Invalid public asset URL')
|
|
76
|
-
}
|
|
77
|
-
item.url = url.href
|
|
78
|
-
}
|
|
79
|
-
return result
|
|
80
|
-
},
|
|
81
|
-
async upload(file, signal) {
|
|
50
|
+
async upload(file, signal, uploadOptions) {
|
|
82
51
|
const started = await send<UploadResponse>('uploads', {
|
|
83
|
-
method: 'POST',
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: { 'Content-Type': 'application/json' },
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
name: file.name,
|
|
56
|
+
visibility: uploadOptions?.visibility ?? 'protected',
|
|
57
|
+
}),
|
|
84
58
|
}, signal)
|
|
85
|
-
if (!started.upload_id || !started.asset_id
|
|
59
|
+
if (!started.upload_id || !started.asset_id) throw new Error('Invalid upload session')
|
|
86
60
|
const completed = await send<UploadResponse>(`uploads/${encodeURIComponent(started.upload_id)}`, {
|
|
87
61
|
method: 'PUT', headers: { 'Content-Type': 'application/octet-stream' }, body: file,
|
|
88
62
|
}, signal)
|
|
89
|
-
if (completed.status !== 'ready' || completed.asset_id !== started.asset_id
|
|
90
|
-
|| completed.version_id !== started.version_id || completed.upload_id !== started.upload_id) {
|
|
63
|
+
if (completed.status !== 'ready' || completed.asset_id !== started.asset_id) {
|
|
91
64
|
throw new Error('Asset upload is not ready')
|
|
92
65
|
}
|
|
93
|
-
return { asset_id: completed.asset_id
|
|
94
|
-
},
|
|
95
|
-
async resolve(references, signal) {
|
|
96
|
-
const result: AssetDelivery[] = []
|
|
97
|
-
for (let offset = 0; offset < references.length; offset += 50) {
|
|
98
|
-
const chunk = references.slice(offset, offset + 50)
|
|
99
|
-
const response = await send<{ items: DeliveryResponse[] }>('resolve', {
|
|
100
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ references: chunk }),
|
|
101
|
-
}, signal)
|
|
102
|
-
if (!Array.isArray(response.items) || response.items.length !== chunk.length) throw new Error('Incomplete delivery response')
|
|
103
|
-
for (const reference of chunk) {
|
|
104
|
-
const item = response.items.find(candidate => candidate.asset_id === reference.asset_id
|
|
105
|
-
&& (!reference.version_id || candidate.version_id === reference.version_id)
|
|
106
|
-
&& candidate.representation === (reference.representation ?? 'original'))
|
|
107
|
-
if (!item) throw new Error('Mismatched delivery response')
|
|
108
|
-
const url = new URL(item.url, base)
|
|
109
|
-
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password
|
|
110
|
-
|| !trusted.has(url.origin)) throw new Error('Untrusted asset delivery URL')
|
|
111
|
-
result.push({ url: url.href, version_id: item.version_id, expires_at: item.expires_at })
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return result
|
|
66
|
+
return { asset_id: completed.asset_id }
|
|
115
67
|
},
|
|
116
68
|
}
|
|
117
69
|
}
|
|
118
70
|
|
|
119
|
-
/** Public URLs are deliberately separate from expiring private deliveries. */
|
|
120
|
-
export interface AssetPublication {
|
|
121
|
-
asset_id: string
|
|
122
|
-
name: string
|
|
123
|
-
version_id: string
|
|
124
|
-
published: boolean
|
|
125
|
-
representations: { representation: AssetPurpose; url: string; media_type: string; size: number }[]
|
|
126
|
-
}
|
|
127
|
-
|
|
128
71
|
export interface ConfigureAssetClientOptions {
|
|
129
72
|
transport: ApiTransport
|
|
130
|
-
/**
|
|
131
|
-
|
|
132
|
-
|
|
73
|
+
/** Public CDN base, e.g. `https://cdn.bgl.dev/auctentic`. Used to build asset URLs. */
|
|
74
|
+
deliveryBaseUrl: string
|
|
75
|
+
/** Identity + tenant key; must change on logout and account/tenant switch. */
|
|
76
|
+
sessionKey?: MaybeRefOrGetter<string | undefined>
|
|
133
77
|
}
|
|
134
78
|
|
|
135
|
-
/** Vue plugin;
|
|
79
|
+
/** Vue plugin; provides the asset client and clears uploads on session change. */
|
|
136
80
|
export function configureAssetClient(options: ConfigureAssetClientOptions) {
|
|
137
81
|
const baseURL = options.transport.axios.defaults.baseURL
|
|
138
82
|
if (!baseURL) throw new Error('Asset transport needs an API baseURL')
|
|
139
83
|
const transport = createAssetHttpTransport({
|
|
140
84
|
baseURL: new URL(baseURL, typeof location === 'undefined' ? undefined : location.origin).href,
|
|
141
|
-
apiTransport: options.transport,
|
|
85
|
+
apiTransport: options.transport,
|
|
142
86
|
})
|
|
143
|
-
const client = createAssetClient(transport)
|
|
144
|
-
const publications = new Set<AbortController>()
|
|
145
|
-
const clearSession = () => {
|
|
146
|
-
client.clearSession()
|
|
147
|
-
for (const controller of publications) controller.abort()
|
|
148
|
-
publications.clear()
|
|
149
|
-
}
|
|
87
|
+
const client = createAssetClient(transport, options.deliveryBaseUrl)
|
|
150
88
|
return {
|
|
151
89
|
client,
|
|
152
|
-
async publish(reference: Required<AssetReference>) {
|
|
153
|
-
const controller = new AbortController()
|
|
154
|
-
publications.add(controller)
|
|
155
|
-
try { return await transport.publish(reference, controller.signal) }
|
|
156
|
-
finally { publications.delete(controller) }
|
|
157
|
-
},
|
|
158
90
|
install(app: App) {
|
|
159
91
|
app.provide(ASSET_CLIENT_KEY, client)
|
|
160
|
-
const stop =
|
|
161
|
-
|
|
92
|
+
const stop = options.sessionKey
|
|
93
|
+
? watch(() => toValue(options.sessionKey), () => client.clearSession(), { flush: 'sync' })
|
|
94
|
+
: undefined
|
|
95
|
+
app.onUnmount(() => { stop?.(); client.clearSession() })
|
|
162
96
|
},
|
|
163
97
|
}
|
|
164
98
|
}
|
package/src/assets.test.ts
CHANGED
|
@@ -1,123 +1,82 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
-
import { createAssetClient, ASSET_CLIENT_KEY, useAssetDelivery,
|
|
3
|
+
import { createAssetClient, ASSET_CLIENT_KEY, useAssetDelivery, useAssetUpload, type AssetTransport } from './assets'
|
|
4
4
|
import { mount } from '@vue/test-utils'
|
|
5
5
|
import { defineComponent, nextTick } from 'vue'
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
url: 'https://delivery.example/private',
|
|
9
|
-
expires_at: new Date(Date.now() + 60_000).toISOString(),
|
|
10
|
-
version_id,
|
|
11
|
-
})
|
|
7
|
+
const BASE = 'https://cdn.bgl.dev/auctentic'
|
|
12
8
|
|
|
13
|
-
function
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
return { resolve, upload, client: createAssetClient({ resolve, upload }) }
|
|
9
|
+
function makeClient(upload?: AssetTransport['upload']) {
|
|
10
|
+
const transport = { upload: upload ?? (async () => ({ asset_id: 'a' })) }
|
|
11
|
+
return createAssetClient(transport, BASE)
|
|
17
12
|
}
|
|
18
13
|
|
|
19
14
|
describe('asset client', () => {
|
|
20
|
-
it('
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
setup() { state = useAssetDelivery(() => ({ asset_id: 'a' })); return () => null },
|
|
27
|
-
}), { global: { provide: { [ASSET_CLIENT_KEY as symbol]: client } } })
|
|
28
|
-
try {
|
|
29
|
-
await vi.advanceTimersByTimeAsync(0)
|
|
30
|
-
expect(state.url.value).toBe(delivery().url)
|
|
31
|
-
resolve.mockImplementationOnce(() => new Promise(done => { finish = done }))
|
|
32
|
-
await vi.advanceTimersByTimeAsync(48_000)
|
|
33
|
-
expect(resolve).toHaveBeenCalledTimes(2)
|
|
34
|
-
expect(state.url.value).toBe(delivery().url)
|
|
35
|
-
client.clearSession()
|
|
36
|
-
expect(state.url.value).toBeUndefined()
|
|
37
|
-
finish([delivery()])
|
|
38
|
-
await nextTick()
|
|
39
|
-
expect(state.url.value).toBeUndefined()
|
|
40
|
-
} finally {
|
|
41
|
-
component.unmount()
|
|
42
|
-
vi.useRealTimers()
|
|
43
|
-
}
|
|
15
|
+
it('builds deterministic public URLs per purpose', () => {
|
|
16
|
+
const client = makeClient()
|
|
17
|
+
expect(client.assetUrl({ asset_id: 'a' })).toBe(`${BASE}/a`)
|
|
18
|
+
expect(client.assetUrl({ asset_id: 'a' }, 'original')).toBe(`${BASE}/a`)
|
|
19
|
+
expect(client.assetUrl({ asset_id: 'a' }, 'website')).toBe(`${BASE}/a?fmt=webp`)
|
|
20
|
+
expect(client.assetUrl({ asset_id: 'a' }, 'social')).toBe(`${BASE}/a?w=1200&h=630&fmt=jpeg&fit=cover`)
|
|
44
21
|
})
|
|
45
22
|
|
|
46
|
-
it('
|
|
47
|
-
const {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const controller = new AbortController()
|
|
51
|
-
const first = client.resolve({ asset_id: 'a' }, controller.signal)
|
|
52
|
-
const rejected = expect(first).rejects.toMatchObject({ name: 'AbortError' })
|
|
53
|
-
await Promise.resolve()
|
|
54
|
-
const second = client.resolve({ asset_id: 'a', representation: 'original' })
|
|
55
|
-
controller.abort()
|
|
56
|
-
await rejected
|
|
57
|
-
expect(resolve.mock.calls[0]![1].aborted).toBe(false)
|
|
58
|
-
finish([delivery()])
|
|
59
|
-
await expect(second).resolves.toMatchObject({ version_id: 'v1' })
|
|
60
|
-
expect(resolve).toHaveBeenCalledTimes(1)
|
|
23
|
+
it('upload returns only the public id (version is ignored)', async () => {
|
|
24
|
+
const upload = vi.fn<AssetTransport['upload']>(async () => ({ asset_id: 'a', version_id: 'v1' }))
|
|
25
|
+
const client = makeClient(upload)
|
|
26
|
+
await expect(client.upload(new File(['x'], 'x'))).resolves.toEqual({ asset_id: 'a' })
|
|
61
27
|
})
|
|
62
28
|
|
|
63
|
-
it('aborts
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
29
|
+
it('clearSession aborts in-flight uploads and bumps revision', async () => {
|
|
30
|
+
const upload = vi.fn<AssetTransport['upload']>((_f, signal) => new Promise((_resolve, reject) => {
|
|
31
|
+
signal.addEventListener('abort', () => reject(new DOMException('x', 'AbortError')))
|
|
32
|
+
}))
|
|
33
|
+
const client = makeClient(upload)
|
|
34
|
+
const before = client.revision
|
|
35
|
+
const promise = client.upload(new File(['x'], 'x'))
|
|
69
36
|
client.clearSession()
|
|
70
|
-
await
|
|
71
|
-
expect(
|
|
72
|
-
await expect(client.resolve({ asset_id: 'a' })).resolves.toMatchObject({ version_id: 'v1' })
|
|
73
|
-
expect(resolve).toHaveBeenCalledTimes(2)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('batches same-turn resolutions and preserves pins', async () => {
|
|
77
|
-
const { client, resolve } = setup()
|
|
78
|
-
await Promise.all([client.resolve({ asset_id: 'a', version_id: 'v1' }), client.resolve({ asset_id: 'b' })])
|
|
79
|
-
expect(resolve).toHaveBeenCalledTimes(1)
|
|
80
|
-
expect(resolve.mock.calls[0]![0][0]).toEqual({ asset_id: 'a', version_id: 'v1' })
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('does not cache grants between calls', async () => {
|
|
84
|
-
const { client, resolve } = setup()
|
|
85
|
-
await client.resolve({ asset_id: 'a' })
|
|
86
|
-
await client.resolve({ asset_id: 'a' })
|
|
87
|
-
expect(resolve).toHaveBeenCalledTimes(2)
|
|
37
|
+
await expect(promise).rejects.toMatchObject({ name: 'AbortError' })
|
|
38
|
+
expect(client.revision).toBe(before + 1)
|
|
88
39
|
})
|
|
40
|
+
})
|
|
89
41
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
42
|
+
describe('useAssetDelivery (public URL resolution)', () => {
|
|
43
|
+
it('resolves an asset reference to its public URL without a network call', async () => {
|
|
44
|
+
const client = makeClient()
|
|
45
|
+
let state!: ReturnType<typeof useAssetDelivery>
|
|
46
|
+
mount(defineComponent({
|
|
47
|
+
setup() { state = useAssetDelivery(() => ({ asset_id: 'a', representation: 'preview' })); return () => null },
|
|
48
|
+
}), { global: { provide: { [ASSET_CLIENT_KEY as symbol]: client } } })
|
|
49
|
+
await nextTick()
|
|
50
|
+
expect(state.url.value).toBe(`${BASE}/a?fmt=webp`)
|
|
51
|
+
expect(state.error.value).toBe(false)
|
|
95
52
|
})
|
|
96
53
|
|
|
97
|
-
it('
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
54
|
+
it('sets error when no client is provided', async () => {
|
|
55
|
+
let state!: ReturnType<typeof useAssetDelivery>
|
|
56
|
+
mount(defineComponent({
|
|
57
|
+
setup() { state = useAssetDelivery(() => ({ asset_id: 'a' })); return () => null },
|
|
58
|
+
}))
|
|
59
|
+
await nextTick()
|
|
60
|
+
expect(state.url.value).toBeUndefined()
|
|
61
|
+
expect(state.error.value).toBe(true)
|
|
103
62
|
})
|
|
63
|
+
})
|
|
104
64
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
let
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
finish([delivery()])
|
|
113
|
-
await expect(request).rejects.toMatchObject({ name: 'AbortError' })
|
|
65
|
+
describe('useAssetUpload', () => {
|
|
66
|
+
it('rejects when no client is injected', async () => {
|
|
67
|
+
let upload!: ReturnType<typeof useAssetUpload>['upload']
|
|
68
|
+
mount(defineComponent({
|
|
69
|
+
setup() { upload = useAssetUpload().upload; return () => null },
|
|
70
|
+
}))
|
|
71
|
+
await expect(upload(new File(['x'], 'x'))).rejects.toThrow('Asset client is not configured')
|
|
114
72
|
})
|
|
115
73
|
|
|
116
|
-
it('
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
74
|
+
it('uploads and returns the public reference', async () => {
|
|
75
|
+
const client = makeClient()
|
|
76
|
+
let upload!: ReturnType<typeof useAssetUpload>['upload']
|
|
77
|
+
mount(defineComponent({
|
|
78
|
+
setup() { upload = useAssetUpload().upload; return () => null },
|
|
79
|
+
}), { global: { provide: { [ASSET_CLIENT_KEY as symbol]: client } } })
|
|
80
|
+
await expect(upload(new File(['x'], 'x'))).resolves.toEqual({ asset_id: 'a' })
|
|
122
81
|
})
|
|
123
82
|
})
|