@kumwe/studio-media 0.1.0-beta.3 → 0.1.0-beta.5
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/README.md +23 -1
- package/dist/upload-controller.d.ts.map +1 -1
- package/dist/upload-controller.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
# `@kumwe/studio-media`
|
|
2
2
|
|
|
3
|
+
[![npm beta][version-badge]][package]
|
|
4
|
+
[![Build][build-badge]][build]
|
|
5
|
+
[![License][license-badge]][license]
|
|
6
|
+
|
|
7
|
+
For build-time beta evaluation, install an exact resolved version:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install --save-exact @kumwe/studio-media@beta
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Keep all Studio packages on the same coordinated release. Hosts deploy prebuilt browser assets;
|
|
14
|
+
Node.js and npm are contributor and build tools. [Integration guidance][integration] describes
|
|
15
|
+
host authority, the release pin and qualification requirements.
|
|
16
|
+
|
|
3
17
|
Status: governed beta development, still pre-Gate-A and not production-supported. The exact coordinated
|
|
4
|
-
version is in the
|
|
18
|
+
version is in the [coordinated release record](https://github.com/kumwe/studio/blob/main/studio-release.json); this package supplies orchestration primitives, not a
|
|
5
19
|
production media backend.
|
|
6
20
|
|
|
7
21
|
Host-neutral media orchestration. Hosts provide authentication, storage, upload, processing, and
|
|
@@ -31,3 +45,11 @@ conforms to the protocol's `media-upload-session` schema. A file larger than the
|
|
|
31
45
|
transport rejections surface as a generic `studio.media/upload-failed` diagnostic and never leak
|
|
32
46
|
raw error text. `cancel()` aborts in-flight work and requests best-effort server-side
|
|
33
47
|
cancellation, and `retry()` restarts a failed session from authorization under a fresh session id.
|
|
48
|
+
|
|
49
|
+
[version-badge]: https://img.shields.io/npm/v/@kumwe/studio-media/beta
|
|
50
|
+
[package]: https://www.npmjs.com/package/@kumwe/studio-media
|
|
51
|
+
[build-badge]: https://github.com/kumwe/studio/actions/workflows/ci.yml/badge.svg?branch=main
|
|
52
|
+
[build]: https://github.com/kumwe/studio/actions/workflows/ci.yml?query=branch%3Amain
|
|
53
|
+
[license-badge]: https://img.shields.io/github/license/kumwe/studio
|
|
54
|
+
[license]: https://github.com/kumwe/studio/blob/main/LICENSE
|
|
55
|
+
[integration]: https://github.com/kumwe/studio/blob/main/docs/integration/README.md
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-controller.d.ts","sourceRoot":"","sources":["../src/upload-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,gBAAgB,CAG1D,CAAC;AAEH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,gBAAgB,CAG5D,CAAC;AAEH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,EAAE,4BAA4B,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjG,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACrF,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,4BAA4B,KAAK,MAAM,CAAC;CAC/D;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;AASxE,qBAAa,qBAAqB;;gBAQb,SAAS,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,4BAA4B;IAK1F,IAAW,OAAO,IAAI,kBAAkB,CAKvC;IAEM,MAAM,IAAI,IAAI;IAUR,KAAK,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAS1C,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,IAAI;IAU9C,MAAM,CACjB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,IAAI,CAAC,4BAA4B,EAAE,UAAU,CAAC,GACtD,OAAO,CAAC,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"upload-controller.d.ts","sourceRoot":"","sources":["../src/upload-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EACtB,MAAM,wBAAwB,CAAC;AAEhC,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,gBAAgB,CAG1D,CAAC;AAEH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,gBAAgB,CAG5D,CAAC;AAEH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,EAAE,4BAA4B,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjG,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACrF,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,4BAA4B,KAAK,MAAM,CAAC;CAC/D;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;AASxE,qBAAa,qBAAqB;;gBAQb,SAAS,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,4BAA4B;IAK1F,IAAW,OAAO,IAAI,kBAAkB,CAKvC;IAEM,MAAM,IAAI,IAAI;IAUR,KAAK,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAS1C,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,IAAI;IAU9C,MAAM,CACjB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,IAAI,CAAC,4BAA4B,EAAE,UAAU,CAAC,GACtD,OAAO,CAAC,kBAAkB,CAAC;CAkJ/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{STUDIO_CONTRACT_VERSION as e}from"@kumwe/studio-protocol";export const MEDIA_UPLOAD_FAILURE=Object.freeze({defaultMessage:`The upload could not be completed.`,key:`studio.media/upload-failed`});export const MEDIA_UPLOAD_TOO_LARGE=Object.freeze({defaultMessage:`The file is larger than the host allows for this upload.`,key:`studio.media/upload-too-large`});const r=new Set([`authorized`,`requested`,`transferring`,`verifying`]);export class MediaUploadController{#listeners=new Set;#sessionId;#transport;#abortController;#file;#session;constructor(e,t){this.#transport=e,this.#sessionId=t?.sessionId??(()=>crypto.randomUUID())}get session(){if(this.#session===void 0)throw Error(`No upload session has been started.`);return structuredClone(this.#session)}cancel(){let e=this.#session;e===void 0||!r.has(e.state)||(this.#abortController?.abort(),this.#setSession({...structuredClone(e),state:`cancelled`}),this.#transport.abort(e.id).catch(()=>void 0))}async retry(){let e=this.#session,t=this.#file;if(e?.state!==`failed`||t===void 0)throw Error(`Only a failed upload session can be retried.`);return this.#run(t,structuredClone(e.request))}subscribe(e){return this.#listeners.add(e),this.#session!==void 0&&e(this.session),()=>{this.#listeners.delete(e)}}async upload(e,t){if(this.#session!==void 0&&r.has(this.#session.state))throw Error(`An upload session is already in progress.`);if(e.size<1)throw Error(`Cannot upload an empty file.`);let n={byteSize:e.size,filename:t.filename,mediaType:t.mediaType,purpose:t.purpose};return t.checksum!==void 0&&(n.checksum=t.checksum),this.#file=e,this.#run(e,n)}#fail(){let e=this.#session;if(e===void 0)return;let n={contractVersion:e.contractVersion,failure:{code:`studio.media/upload-failed`,message:{...MEDIA_UPLOAD_FAILURE},severity:`error`},id:e.id,kind:`media-upload-session`,progress:{...e.progress},request:{...e.request},state:`failed`};e.plan!==void 0&&(n.plan={...e.plan}),this.#setSession(n)}async#run(t,r){let i=new AbortController;this.#abortController=i;let
|
|
1
|
+
import{STUDIO_CONTRACT_VERSION as e}from"@kumwe/studio-protocol";export const MEDIA_UPLOAD_FAILURE=Object.freeze({defaultMessage:`The upload could not be completed.`,key:`studio.media/upload-failed`});export const MEDIA_UPLOAD_TOO_LARGE=Object.freeze({defaultMessage:`The file is larger than the host allows for this upload.`,key:`studio.media/upload-too-large`});const r=new Set([`authorized`,`requested`,`transferring`,`verifying`]);export class MediaUploadController{#listeners=new Set;#sessionId;#transport;#abortController;#file;#session;constructor(e,t){this.#transport=e,this.#sessionId=t?.sessionId??(()=>crypto.randomUUID())}get session(){if(this.#session===void 0)throw Error(`No upload session has been started.`);return structuredClone(this.#session)}cancel(){let e=this.#session;e===void 0||!r.has(e.state)||(this.#abortController?.abort(),this.#setSession({...structuredClone(e),state:`cancelled`}),this.#transport.abort(e.id).catch(()=>void 0))}async retry(){let e=this.#session,t=this.#file;if(e?.state!==`failed`||t===void 0)throw Error(`Only a failed upload session can be retried.`);return this.#run(t,structuredClone(e.request))}subscribe(e){return this.#listeners.add(e),this.#session!==void 0&&e(this.session),()=>{this.#listeners.delete(e)}}async upload(e,t){if(this.#session!==void 0&&r.has(this.#session.state))throw Error(`An upload session is already in progress.`);if(e.size<1)throw Error(`Cannot upload an empty file.`);let n={byteSize:e.size,filename:t.filename,mediaType:t.mediaType,purpose:t.purpose};return t.checksum!==void 0&&(n.checksum=t.checksum),this.#file=e,this.#run(e,n)}#fail(){let e=this.#session;if(e===void 0)return;let n={contractVersion:e.contractVersion,failure:{code:`studio.media/upload-failed`,message:{...MEDIA_UPLOAD_FAILURE},severity:`error`},id:e.id,kind:`media-upload-session`,progress:{...e.progress},request:{...e.request},state:`failed`};e.plan!==void 0&&(n.plan={...e.plan}),this.#setSession(n)}async#run(t,r){let i=new AbortController;this.#abortController=i;let o=r.byteSize,s={contractVersion:e,id:this.#sessionId(r),kind:`media-upload-session`,request:r};this.#setSession({...s,progress:{totalBytes:o,transferredBytes:0},state:`requested`});try{let e=await this.#transport.authorize(r,i.signal);if(i.signal.aborted)return this.session;let c=a(e);if(o>c.maximumBytes)return this.#setSession({...s,failure:{code:`studio.media/upload-too-large`,message:{...MEDIA_UPLOAD_TOO_LARGE},parameters:{byteSize:o,maximumBytes:c.maximumBytes},severity:`error`},plan:c,progress:{totalBytes:o,transferredBytes:0},state:`failed`}),this.session;this.#setSession({...s,plan:c,progress:{totalBytes:o,transferredBytes:0},state:`authorized`}),this.#setSession({...s,plan:c,progress:{totalBytes:o,transferredBytes:0},state:`transferring`});let l=c.chunkBytes??o,u=0;for(;u<o;){let e=t.slice(u,Math.min(u+l,o));if(await this.#transport.transfer({data:e,offset:u,sessionId:s.id},i.signal),i.signal.aborted)return this.session;u=Math.min(u+e.size,o),this.#setSession({...s,plan:c,progress:{totalBytes:o,transferredBytes:u},state:`transferring`})}this.#setSession({...s,plan:c,progress:{totalBytes:o,transferredBytes:o},state:`verifying`});let d=await this.#transport.finalize(s.id,i.signal);if(i.signal.aborted)return this.session;this.#setSession({...s,asset:d,plan:c,progress:{totalBytes:o,transferredBytes:o},state:`complete`})}catch{i.signal.aborted||this.#fail()}return this.session}#setSession(e){this.#session=e;for(let e of this.#listeners)e(this.session)}}function a(e){if(typeof e!=`object`||!e||Array.isArray(e))throw TypeError(`The host returned an invalid bounded upload plan.`);let t=Object.getPrototypeOf(e);if(t!==Object.prototype&&t!==null||Object.getOwnPropertySymbols(e).length!==0)throw TypeError(`The host returned an invalid bounded upload plan.`);let n=Object.getOwnPropertyDescriptors(e);if(!Object.hasOwn(n,`maximumBytes`)||!Object.hasOwn(n,`resumable`)||Object.keys(n).some(e=>![`chunkBytes`,`maximumBytes`,`resumable`].includes(e))||Object.values(n).some(e=>!(`value`in e)||!e.enumerable))throw TypeError(`The host returned an invalid bounded upload plan.`);let r=n.maximumBytes?.value,i=n.resumable?.value,a=Object.hasOwn(n,`chunkBytes`)?n.chunkBytes?.value:void 0;if(typeof r!=`number`||!Number.isInteger(r)||r<1||r>1099511627776||typeof i!=`boolean`||Object.hasOwn(n,`chunkBytes`)&&(typeof a!=`number`||!Number.isInteger(a)||a<1024||a>1073741824))throw TypeError(`The host returned an invalid bounded upload plan.`);return{maximumBytes:r,resumable:i,...typeof a==`number`?{chunkBytes:a}:{}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kumwe/studio-media",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.5",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/kumwe/studio.git",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"build": "tsc -b && node ../../scripts/minify-package-dist.mjs --package packages/media"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@kumwe/studio-protocol": "0.1.0-beta.
|
|
31
|
+
"@kumwe/studio-protocol": "0.1.0-beta.5"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public",
|