@vived/host 5.3.1 → 5.4.1
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/cjs/Assets/UCs/NewAppAssetUC.js +5 -1
- package/dist/cjs/Assets/UCs/NewAppAssetUC.js.map +1 -1
- package/dist/cjs/VivedAPI/UCs/FileUploadUC.js +11 -3
- package/dist/cjs/VivedAPI/UCs/FileUploadUC.js.map +1 -1
- package/dist/cjs/VivedAPI/UCs/PostNewAssetUC.js +8 -2
- package/dist/cjs/VivedAPI/UCs/PostNewAssetUC.js.map +1 -1
- package/dist/esm/Assets/UCs/NewAppAssetUC.js +5 -1
- package/dist/esm/Assets/UCs/NewAppAssetUC.js.map +1 -1
- package/dist/esm/VivedAPI/UCs/FileUploadUC.js +11 -3
- package/dist/esm/VivedAPI/UCs/FileUploadUC.js.map +1 -1
- package/dist/esm/VivedAPI/UCs/PostNewAssetUC.js +8 -2
- package/dist/esm/VivedAPI/UCs/PostNewAssetUC.js.map +1 -1
- package/dist/types/VivedAPI/UCs/PostNewAssetUC.d.ts +7 -0
- package/dist/types/VivedAPI/UCs/PostNewAssetUC.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -76,7 +76,11 @@ class NewAppAssetUCImp extends NewAppAssetUC {
|
|
|
76
76
|
description,
|
|
77
77
|
name,
|
|
78
78
|
file,
|
|
79
|
-
ownerID: sandbox.appID
|
|
79
|
+
ownerID: sandbox.appID,
|
|
80
|
+
// App-owned create: the backend authorizes this via the `app` branch
|
|
81
|
+
// only when the row carries ownerType "app" (it does not infer it).
|
|
82
|
+
// See vivedlearning/vived-api-legacy#133.
|
|
83
|
+
ownerType: "app"
|
|
80
84
|
};
|
|
81
85
|
const spinnerDialog = this.spinnerFactory?.make({
|
|
82
86
|
title: "New App Asset",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NewAppAssetUC.js","sourceRoot":"","sources":["../../../../src/Assets/UCs/NewAppAssetUC.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA+DH,8CAEC;AA/DD,sCAKqB;AACrB,wDAA2E;AAC3E,yCAIsB;AACtB,4CAAoE;AACpE,0CAAyD;AAczD;;;;GAIG;AACH,MAAsB,aAAc,SAAQ,kBAAW;IAYrD;;;;;OAKG;IACH,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,IAAA,4BAAqB,EAAC,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC/D,CAAC;;AApBH,sCAqBC;AApBC,wDAAwD;AACjD,kBAAI,GAAG,eAAe,CAAC;AAqBhC;;;;;GAKG;AACH,SAAgB,iBAAiB,CAAC,SAAoB;IACpD,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,gBAAiB,SAAQ,aAAa;IAG1C,IAAY,YAAY;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAiB,oBAAc,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9E,CAAC;IAED,IAAY,SAAS;QACnB,OAAO,IAAI,CAAC,kBAAkB,CAAY,oBAAS,CAAC,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED,IAAY,OAAO;QACjB,OAAO,IAAI,CAAC,kBAAkB,CAAmB,2BAAgB,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED,IAAY,cAAc;QACxB,OAAO,IAAI,CAAC,kBAAkB,CAC5B,4BAAmB,CAAC,IAAI,CACzB,CAAC;IACJ,CAAC;IAED,IAAY,YAAY;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAoB,0BAAiB,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;
|
|
1
|
+
{"version":3,"file":"NewAppAssetUC.js","sourceRoot":"","sources":["../../../../src/Assets/UCs/NewAppAssetUC.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * NewAppAssetUC.ts\r\n *\r\n * This use case handles creation of new assets within application contexts,\r\n * managing the complete workflow from file upload to UI state transitions.\r\n */\r\n\r\nimport {\r\n getSingletonComponent,\r\n AppObject,\r\n AppObjectRepo,\r\n AppObjectUC\r\n} from \"@vived/core\";\r\nimport { AppSandboxEntity, SandboxState } from \"../../AppSandbox/Entities\";\r\nimport {\r\n DialogAlertDTO,\r\n MakeAlertDialogUC,\r\n MakeSpinnerDialogUC\r\n} from \"../../Dialog\";\r\nimport { NewAssetApiDto, PostNewAssetUC } from \"../../VivedAPI/UCs\";\r\nimport { AppAssetsEntity, AssetRepo } from \"../Entities\";\r\n\r\n/**\r\n * Data transfer object for new application asset creation requests.\r\n */\r\nexport interface NewAppAssetDTO {\r\n /** The file object to be uploaded and stored as the asset */\r\n file: File;\r\n /** Display name for the asset */\r\n name: string;\r\n /** Detailed description of the asset's purpose or content */\r\n description: string;\r\n}\r\n\r\n/**\r\n * NewAppAssetUC handles creation of new assets within application contexts.\r\n *\r\n * This singleton use case manages asset creation with UI feedback and state transitions.\r\n */\r\nexport abstract class NewAppAssetUC extends AppObjectUC {\r\n /** Static type identifier for component registration */\r\n static type = \"NewAppAssetUC\";\r\n\r\n /**\r\n * Creates a new asset with the provided data.\r\n *\r\n * @param data - Complete asset information including file and metadata\r\n * @returns Promise that resolves when the asset is successfully created\r\n */\r\n abstract create(data: NewAppAssetDTO): Promise<void>;\r\n\r\n /**\r\n * Retrieves the singleton NewAppAssetUC instance.\r\n *\r\n * @param appObjects - Repository for accessing the singleton component\r\n * @returns NewAppAssetUC instance or undefined if not found\r\n */\r\n static get(appObjects: AppObjectRepo): NewAppAssetUC | undefined {\r\n return getSingletonComponent(NewAppAssetUC.type, appObjects);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create a new NewAppAssetUC instance.\r\n *\r\n * @param appObject - The AppObject that will host this singleton use case\r\n * @returns A new NewAppAssetUC implementation instance\r\n */\r\nexport function makeNewAppAssetUC(appObject: AppObject): NewAppAssetUC {\r\n return new NewAppAssetUCImp(appObject);\r\n}\r\n\r\n/**\r\n * Private implementation of NewAppAssetUC with app context and state management.\r\n */\r\nclass NewAppAssetUCImp extends NewAppAssetUC {\r\n private appAssets?: AppAssetsEntity;\r\n\r\n private get postNewAsset() {\r\n return this.getCachedSingleton<PostNewAssetUC>(PostNewAssetUC.type)?.doPost;\r\n }\r\n\r\n private get assetRepo() {\r\n return this.getCachedSingleton<AssetRepo>(AssetRepo.type);\r\n }\r\n\r\n private get sandbox() {\r\n return this.getCachedSingleton<AppSandboxEntity>(AppSandboxEntity.type);\r\n }\r\n\r\n private get spinnerFactory() {\r\n return this.getCachedSingleton<MakeSpinnerDialogUC>(\r\n MakeSpinnerDialogUC.type\r\n );\r\n }\r\n\r\n private get alertFactory() {\r\n return this.getCachedSingleton<MakeAlertDialogUC>(MakeAlertDialogUC.type);\r\n }\r\n\r\n create = (data: NewAppAssetDTO): Promise<void> => {\r\n const appAssets = this.appAssets;\r\n const postNewAsset = this.postNewAsset;\r\n const sandbox = this.sandbox;\r\n const assetRepo = this.assetRepo;\r\n\r\n if (!appAssets || !postNewAsset || !sandbox || !assetRepo) {\r\n return Promise.reject();\r\n }\r\n\r\n return new Promise<void>((resolve) => {\r\n const { description, file, name } = data;\r\n\r\n const newAssetData: NewAssetApiDto = {\r\n description,\r\n name,\r\n file,\r\n ownerID: sandbox.appID,\r\n // App-owned create: the backend authorizes this via the `app` branch\r\n // only when the row carries ownerType \"app\" (it does not infer it).\r\n // See vivedlearning/vived-api-legacy#133.\r\n ownerType: \"app\"\r\n };\r\n\r\n const spinnerDialog = this.spinnerFactory?.make({\r\n title: \"New App Asset\",\r\n message: \"Posting new app asset...\"\r\n });\r\n\r\n postNewAsset(newAssetData)\r\n .then((resp) => {\r\n appAssets.add(resp.id);\r\n\r\n const newAsset = assetRepo.assetFactory(resp.id);\r\n newAsset.setFile(file);\r\n newAsset.description = description;\r\n newAsset.name = name;\r\n newAsset.filename = resp.filename;\r\n\r\n assetRepo.add(newAsset);\r\n this.sandbox!.state = SandboxState.MOUNTED;\r\n\r\n spinnerDialog?.close();\r\n resolve();\r\n })\r\n .catch((e: Error) => {\r\n this.error(\"create new asset error: \" + e.message);\r\n spinnerDialog?.close();\r\n\r\n const dialogDTO: DialogAlertDTO = {\r\n buttonLabel: \"OK\",\r\n message: `Something went wrong when creating a new app asset. Check the console. ${e.message}`,\r\n title: \"New App Asset Error\"\r\n };\r\n this.alertFactory?.make(dialogDTO);\r\n\r\n resolve();\r\n });\r\n });\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, NewAppAssetUC.type);\r\n this.appObjects.registerSingleton(this);\r\n\r\n this.appAssets = appObject.getComponent<AppAssetsEntity>(\r\n AppAssetsEntity.type\r\n );\r\n if (!this.appAssets) {\r\n this.error(\r\n \"UC added to an App Object that does not have AppAssetsEntity\"\r\n );\r\n return;\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -76,13 +76,21 @@ class FileUploadUCImp extends FileUploadUC {
|
|
|
76
76
|
return Promise.reject();
|
|
77
77
|
}
|
|
78
78
|
return new Promise((resolve, reject) => {
|
|
79
|
-
const getUploadURL = vivedAPI.getEndpointURL(`upload/large/DataVariants/${file.name}`);
|
|
79
|
+
const getUploadURL = vivedAPI.getEndpointURL(`upload/large/DataVariants/${file.name}?function_version=2`);
|
|
80
80
|
requestJSON(getUploadURL)
|
|
81
|
-
.then((
|
|
81
|
+
.then((result) => {
|
|
82
|
+
// v2 returns an object { url, contentType }, not a bare URL string.
|
|
83
|
+
const { url: uploadURL, contentType } = result;
|
|
82
84
|
const url = new URL(uploadURL);
|
|
83
85
|
const options = {
|
|
84
86
|
method: "PUT",
|
|
85
|
-
body: file
|
|
87
|
+
body: file,
|
|
88
|
+
// The SigV2 presigned PUT is signed with this exact Content-Type;
|
|
89
|
+
// echoing v2's own value guarantees the signature matches and S3
|
|
90
|
+
// stores the correct type instead of binary/octet-stream.
|
|
91
|
+
headers: {
|
|
92
|
+
"Content-Type": contentType
|
|
93
|
+
}
|
|
86
94
|
};
|
|
87
95
|
return basicFetch(url, options);
|
|
88
96
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileUploadUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/FileUploadUC.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AA0CH,4CAEC;AA1CD,sCAKqB;AACrB,+DAA4D;AAC5D,iDAAiE;AACjE,mDAAgD;AAEhD;;;GAGG;AACH,MAAsB,YAAa,SAAQ,kBAAW;IAWpD;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,IAAA,4BAAqB,EAAC,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;;AAlBH,oCAmBC;AAlBC,gDAAgD;AACzC,iBAAI,GAAG,cAAc,CAAC;AAmB/B;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,SAAoB;IACnD,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,eAAgB,SAAQ,YAAY;IACxC,IAAY,QAAQ;QAClB,OAAO,IAAI,CAAC,kBAAkB,CAAiB,+BAAc,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,kBAAkB,CAAgB,6BAAa,CAAC,IAAI,CAAC;YAC/D,EAAE,SAAS,CAAC;IAChB,CAAC;IAED,IAAY,UAAU;QACpB,OAAO,IAAI,CAAC,kBAAkB,CAAe,2BAAY,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC7E,CAAC;
|
|
1
|
+
{"version":3,"file":"FileUploadUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/FileUploadUC.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AA0CH,4CAEC;AA1CD,sCAKqB;AACrB,+DAA4D;AAC5D,iDAAiE;AACjE,mDAAgD;AAEhD;;;GAGG;AACH,MAAsB,YAAa,SAAQ,kBAAW;IAWpD;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,IAAA,4BAAqB,EAAC,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;;AAlBH,oCAmBC;AAlBC,gDAAgD;AACzC,iBAAI,GAAG,cAAc,CAAC;AAmB/B;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,SAAoB;IACnD,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,eAAgB,SAAQ,YAAY;IACxC,IAAY,QAAQ;QAClB,OAAO,IAAI,CAAC,kBAAkB,CAAiB,+BAAc,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,kBAAkB,CAAgB,6BAAa,CAAC,IAAI,CAAC;YAC/D,EAAE,SAAS,CAAC;IAChB,CAAC;IAED,IAAY,UAAU;QACpB,OAAO,IAAI,CAAC,kBAAkB,CAAe,2BAAY,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC7E,CAAC;IA8CD,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;QA7CtC,aAAQ,GAAG,CAAC,IAAU,EAAiB,EAAE;YACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;YACrC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;YAEnC,IAAI,CAAC,QAAQ,IAAI,CAAC,WAAW,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC7C,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1B,CAAC;YACD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC3C,MAAM,YAAY,GAAG,QAAQ,CAAC,cAAc,CAC1C,6BAA6B,IAAI,CAAC,IAAI,qBAAqB,CAC5D,CAAC;gBAEF,WAAW,CAAC,YAAY,CAAC;qBACtB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;oBACf,oEAAoE;oBACpE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAGvC,CAAC;oBACF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;oBAC/B,MAAM,OAAO,GAAsB;wBACjC,MAAM,EAAE,KAAK;wBACb,IAAI,EAAE,IAAI;wBACV,kEAAkE;wBAClE,iEAAiE;wBACjE,0DAA0D;wBAC1D,OAAO,EAAE;4BACP,cAAc,EAAE,WAAW;yBAC5B;qBACF,CAAC;oBAEF,OAAO,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;gBAClC,CAAC,CAAC;qBACD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;oBACV,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;oBAClB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;oBACrB,MAAM,CAAC,CAAC,CAAC,CAAC;gBACZ,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["/**\r\n * FileUploadUC.ts\r\n *\r\n * This file defines the Use Case for uploading files to the VIVED API.\r\n * FileUploadUC handles the process of uploading file data to storage endpoints,\r\n * managing multipart form data and upload progress.\r\n *\r\n * Key concepts:\r\n * - Abstract UC defining the interface for file upload operations\r\n * - Handles file upload workflows with progress tracking\r\n * - Coordinates with BasicFetchUC for HTTP transport\r\n * - Manages multipart form data encoding and transmission\r\n * - Provides error handling for upload failures\r\n *\r\n * Usage pattern:\r\n * 1. Get a UC instance using FileUploadUC.get(appObjects) or makeFileUploadUC\r\n * 2. Call doUpload with File object to upload\r\n * 3. Handle the returned Promise for upload completion\r\n * 4. UC manages the HTTP upload mechanics and error handling\r\n */\r\n\r\nimport {\r\n getSingletonComponent,\r\n AppObject,\r\n AppObjectRepo,\r\n AppObjectUC\r\n} from \"@vived/core\";\r\nimport { VivedAPIEntity } from \"../Entities/VivedAPIEntity\";\r\nimport { BasicFetchOptions, BasicFetchUC } from \"./BasicFetchUC\";\r\nimport { JsonRequestUC } from \"./JsonRequestUC\";\r\n\r\n/**\r\n * FileUploadUC provides functionality for uploading files to APIs.\r\n * Abstract class that defines the interface for file upload operations.\r\n */\r\nexport abstract class FileUploadUC extends AppObjectUC {\r\n /** Unique type identifier for this component */\r\n static type = \"FileUploadUC\";\r\n\r\n /**\r\n * Uploads a file to the configured API endpoint\r\n * @param file The File object to upload\r\n * @returns Promise that resolves when upload is complete\r\n */\r\n abstract doUpload(file: File): Promise<void>;\r\n\r\n /**\r\n * Retrieves a FileUploadUC component from an AppObject\r\n * @param appObjects The AppObjectRepo to get the component from\r\n * @returns The FileUploadUC component or undefined if not found\r\n */\r\n static get(appObjects: AppObjectRepo): FileUploadUC | undefined {\r\n return getSingletonComponent(FileUploadUC.type, appObjects);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create a new FileUploadUC instance\r\n * @param appObject The AppObject to attach the UC to\r\n * @returns A new FileUploadUC instance\r\n */\r\nexport function makeFileUploadUC(appObject: AppObject): FileUploadUC {\r\n return new FileUploadUCImp(appObject);\r\n}\r\n\r\n/**\r\n * Concrete implementation of FileUploadUC\r\n * This private class handles the actual file upload mechanics\r\n */\r\nclass FileUploadUCImp extends FileUploadUC {\r\n private get vivedAPI(): VivedAPIEntity | undefined {\r\n return this.getCachedSingleton<VivedAPIEntity>(VivedAPIEntity.type);\r\n }\r\n\r\n private get requestJSON() {\r\n return this.getCachedSingleton<JsonRequestUC>(JsonRequestUC.type)\r\n ?.doRequest;\r\n }\r\n\r\n private get basicFetch() {\r\n return this.getCachedSingleton<BasicFetchUC>(BasicFetchUC.type)?.doRequest;\r\n }\r\n\r\n doUpload = (file: File): Promise<void> => {\r\n const vivedAPI = this.vivedAPI;\r\n const requestJSON = this.requestJSON;\r\n const basicFetch = this.basicFetch;\r\n\r\n if (!vivedAPI || !requestJSON || !basicFetch) {\r\n return Promise.reject();\r\n }\r\n return new Promise<void>((resolve, reject) => {\r\n const getUploadURL = vivedAPI.getEndpointURL(\r\n `upload/large/DataVariants/${file.name}?function_version=2`\r\n );\r\n\r\n requestJSON(getUploadURL)\r\n .then((result) => {\r\n // v2 returns an object { url, contentType }, not a bare URL string.\r\n const { url: uploadURL, contentType } = result as {\r\n url: string;\r\n contentType: string;\r\n };\r\n const url = new URL(uploadURL);\r\n const options: BasicFetchOptions = {\r\n method: \"PUT\",\r\n body: file,\r\n // The SigV2 presigned PUT is signed with this exact Content-Type;\r\n // echoing v2's own value guarantees the signature matches and S3\r\n // stores the correct type instead of binary/octet-stream.\r\n headers: {\r\n \"Content-Type\": contentType\r\n }\r\n };\r\n\r\n return basicFetch(url, options);\r\n })\r\n .then((_) => {\r\n resolve();\r\n })\r\n .catch((e: Error) => {\r\n this.warn(e.message);\r\n reject(e);\r\n });\r\n });\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, FileUploadUC.type);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
|
|
@@ -82,12 +82,13 @@ class PostNewAssetUCImp extends PostNewAssetUC {
|
|
|
82
82
|
return Promise.reject();
|
|
83
83
|
}
|
|
84
84
|
return new Promise((resolve, reject) => {
|
|
85
|
-
const { description, file, name, ownerID } = data;
|
|
85
|
+
const { description, file, name, ownerID, ownerType } = data;
|
|
86
86
|
let assetId;
|
|
87
87
|
const nameSplits = file.name.split(".");
|
|
88
88
|
const extension = nameSplits[nameSplits.length - 1];
|
|
89
89
|
const filename = `${(0, core_1.generateUniqueID)()}.${extension}`;
|
|
90
90
|
const assetFile = new File([file], filename, {
|
|
91
|
+
type: file.type,
|
|
91
92
|
lastModified: Date.now()
|
|
92
93
|
});
|
|
93
94
|
fileUploader(assetFile)
|
|
@@ -96,11 +97,16 @@ class PostNewAssetUCImp extends PostNewAssetUC {
|
|
|
96
97
|
})
|
|
97
98
|
.then((token) => {
|
|
98
99
|
const postURL = vivedAPI.getEndpointURL("assets");
|
|
100
|
+
// Forward ownerType only when the caller declared it. Omitting the
|
|
101
|
+
// key (conditional spread → nothing when unset) preserves the
|
|
102
|
+
// backend's channel default for non-app creates; the server never
|
|
103
|
+
// infers owner type. See vived-api-legacy#133.
|
|
99
104
|
const body = {
|
|
100
105
|
ownerId: ownerID,
|
|
101
106
|
name,
|
|
102
107
|
description,
|
|
103
|
-
filename
|
|
108
|
+
filename,
|
|
109
|
+
...(ownerType !== undefined && { ownerType })
|
|
104
110
|
};
|
|
105
111
|
const options = {
|
|
106
112
|
method: "POST",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostNewAssetUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/PostNewAssetUC.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;
|
|
1
|
+
{"version":3,"file":"PostNewAssetUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/PostNewAssetUC.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AA2EH,gDAEC;AA3ED,sCAMqB;AACrB,+DAA4D;AAC5D,iDAA8C;AAC9C,mDAAoE;AACpE,2DAAwD;AAiCxD;;;GAGG;AACH,MAAsB,cAAe,SAAQ,kBAAW;IAWtD;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,IAAA,4BAAqB,EAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAChE,CAAC;;AAlBH,wCAmBC;AAlBC,gDAAgD;AACzC,mBAAI,GAAG,gBAAgB,CAAC;AAmBjC;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,SAAoB;IACrD,OAAO,IAAI,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,iBAAkB,SAAQ,cAAc;IAC5C,IAAY,aAAa;QACvB,OAAO,IAAI,CAAC,kBAAkB,CAAgB,6BAAa,CAAC,IAAI,CAAC;YAC/D,EAAE,SAAS,CAAC;IAChB,CAAC;IAED,IAAY,kBAAkB;QAC5B,OAAO,IAAI,CAAC,kBAAkB,CAAoB,qCAAiB,CAAC,IAAI,CAAC;YACvE,EAAE,YAAY,CAAC;IACnB,CAAC;IAED,IAAY,YAAY;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAe,2BAAY,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAC5E,CAAC;IAED,IAAY,QAAQ;QAClB,OAAO,IAAI,CAAC,kBAAkB,CAAiB,+BAAc,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAmED,YAAY,SAAoB;QAC9B,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;QAlExC,WAAM,GAAG,CAAC,IAAoB,EAAgC,EAAE;YAC9D,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;YACvC,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,CAAC;YACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;YAEzC,IAAI,CAAC,YAAY,IAAI,CAAC,kBAAkB,IAAI,CAAC,QAAQ,IAAI,CAAC,aAAa,EAAE,CAAC;gBACxE,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1B,CAAC;YAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;gBAC7D,IAAI,OAAe,CAAC;gBAEpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACxC,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACpD,MAAM,QAAQ,GAAG,GAAG,IAAA,uBAAgB,GAAE,IAAI,SAAS,EAAE,CAAC;gBACtD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE;oBAC3C,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;iBACzB,CAAC,CAAC;gBAEH,YAAY,CAAC,SAAS,CAAC;qBACpB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;oBACV,OAAO,kBAAkB,EAAE,CAAC;gBAC9B,CAAC,CAAC;qBACD,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;oBACd,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;oBAElD,mEAAmE;oBACnE,8DAA8D;oBAC9D,kEAAkE;oBAClE,+CAA+C;oBAC/C,MAAM,IAAI,GAAG;wBACX,OAAO,EAAE,OAAO;wBAChB,IAAI;wBACJ,WAAW;wBACX,QAAQ;wBACR,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;qBAC9C,CAAC;oBAEF,MAAM,OAAO,GAAuB;wBAClC,MAAM,EAAE,MAAM;wBACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;wBAC1B,OAAO,EAAE;4BACP,aAAa,EAAE,SAAS,GAAG,KAAK;yBACjC;qBACF,CAAC;oBAEF,OAAO,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACzC,CAAC,CAAC;qBACD,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;oBACf,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;oBACzB,OAAO,CAAC;wBACN,EAAE,EAAE,OAAO;wBACX,QAAQ;qBACT,CAAC,CAAC;gBACL,CAAC,CAAC;qBACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;oBACX,MAAM,CAAC,CAAC,CAAC,CAAC;oBACV,OAAO;gBACT,CAAC,CAAC,CAAC;YACP,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["/**\r\n * PostNewAssetUC.ts\r\n *\r\n * This file defines the Use Case for creating new assets via the VIVED API.\r\n * PostNewAssetUC handles the complete workflow of uploading asset files and\r\n * creating asset metadata records through API requests.\r\n *\r\n * Key concepts:\r\n * - Orchestrates file upload and metadata creation for new assets\r\n * - Handles multipart file uploads with asset information\r\n * - Manages authentication tokens and API endpoints\r\n * - Coordinates between multiple UCs (JsonRequest, FileUpload, SignedAuthToken)\r\n * - Returns asset creation response with generated IDs\r\n *\r\n * Usage pattern:\r\n * 1. Get a UC instance using PostNewAssetUC.get(appObjects) or makePostNewAssetUC\r\n * 2. Call doPost with asset data including file and metadata\r\n * 3. Handle the returned Promise with asset creation response\r\n * 4. UC will coordinate authentication, file upload, and API requests\r\n */\r\n\r\nimport {\r\n AppObject,\r\n AppObjectRepo,\r\n AppObjectUC,\r\n generateUniqueID,\r\n getSingletonComponent\r\n} from \"@vived/core\";\r\nimport { VivedAPIEntity } from \"../Entities/VivedAPIEntity\";\r\nimport { FileUploadUC } from \"./FileUploadUC\";\r\nimport { JsonRequestUC, RequestJSONOptions } from \"./JsonRequestUC\";\r\nimport { SignedAuthTokenUC } from \"./SignedAuthTokenUC\";\r\n\r\n/**\r\n * Data transfer object for new asset creation requests\r\n */\r\nexport interface NewAssetApiDto {\r\n /** Display name for the new asset */\r\n name: string;\r\n /** Description text for the asset */\r\n description: string;\r\n /** ID of the user who will own this asset */\r\n ownerID: string;\r\n /**\r\n * Owner type for the asset. The backend authorizes app-owned assets via the\r\n * `app` branch only when this is `\"app\"`; an absent value is treated as the\r\n * `channel` default (the backend does not — and must not — infer it). See\r\n * vivedlearning/vived-api-legacy#133.\r\n */\r\n ownerType?: \"channel\" | \"activity\" | \"app\";\r\n /** File object containing the asset data */\r\n file: File;\r\n}\r\n\r\n/**\r\n * Response data transfer object for successful asset creation\r\n */\r\nexport interface NewAssetResponseDTO {\r\n /** Unique identifier assigned to the new asset */\r\n id: string;\r\n /** Final filename used for the stored asset file */\r\n filename: string;\r\n}\r\n\r\n/**\r\n * PostNewAssetUC provides functionality for creating new assets via API.\r\n * Abstract class that defines the interface for asset creation operations.\r\n */\r\nexport abstract class PostNewAssetUC extends AppObjectUC {\r\n /** Unique type identifier for this component */\r\n static type = \"PostNewAssetUC\";\r\n\r\n /**\r\n * Creates a new asset by uploading file and metadata to the API\r\n * @param data The asset creation data including file and metadata\r\n * @returns Promise resolving to the new asset response with ID and filename\r\n */\r\n abstract doPost(data: NewAssetApiDto): Promise<NewAssetResponseDTO>;\r\n\r\n /**\r\n * Retrieves a PostNewAssetUC component from an AppObject\r\n * @param appObjects The AppObjectRepo to get the component from\r\n * @returns The PostNewAssetUC component or undefined if not found\r\n */\r\n static get(appObjects: AppObjectRepo): PostNewAssetUC | undefined {\r\n return getSingletonComponent(PostNewAssetUC.type, appObjects);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create a new PostNewAssetUC instance\r\n * @param appObject The AppObject to attach the UC to\r\n * @returns A new PostNewAssetUC instance\r\n */\r\nexport function makePostNewAssetUC(appObject: AppObject): PostNewAssetUC {\r\n return new PostNewAssetUCImp(appObject);\r\n}\r\n\r\n/**\r\n * Concrete implementation of PostNewAssetUC\r\n * This private class handles the actual asset creation workflow\r\n */\r\nclass PostNewAssetUCImp extends PostNewAssetUC {\r\n private get jsonRequester() {\r\n return this.getCachedSingleton<JsonRequestUC>(JsonRequestUC.type)\r\n ?.doRequest;\r\n }\r\n\r\n private get getPlayerAuthToken() {\r\n return this.getCachedSingleton<SignedAuthTokenUC>(SignedAuthTokenUC.type)\r\n ?.getAuthToken;\r\n }\r\n\r\n private get fileUploader() {\r\n return this.getCachedSingleton<FileUploadUC>(FileUploadUC.type)?.doUpload;\r\n }\r\n\r\n private get vivedAPI() {\r\n return this.getCachedSingleton<VivedAPIEntity>(VivedAPIEntity.type);\r\n }\r\n\r\n doPost = (data: NewAssetApiDto): Promise<NewAssetResponseDTO> => {\r\n const fileUploader = this.fileUploader;\r\n const getPlayerAuthToken = this.getPlayerAuthToken;\r\n const vivedAPI = this.vivedAPI;\r\n const jsonRequester = this.jsonRequester;\r\n\r\n if (!fileUploader || !getPlayerAuthToken || !vivedAPI || !jsonRequester) {\r\n return Promise.reject();\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const { description, file, name, ownerID, ownerType } = data;\r\n let assetId: string;\r\n\r\n const nameSplits = file.name.split(\".\");\r\n const extension = nameSplits[nameSplits.length - 1];\r\n const filename = `${generateUniqueID()}.${extension}`;\r\n const assetFile = new File([file], filename, {\r\n type: file.type,\r\n lastModified: Date.now()\r\n });\r\n\r\n fileUploader(assetFile)\r\n .then((_) => {\r\n return getPlayerAuthToken();\r\n })\r\n .then((token) => {\r\n const postURL = vivedAPI.getEndpointURL(\"assets\");\r\n\r\n // Forward ownerType only when the caller declared it. Omitting the\r\n // key (conditional spread → nothing when unset) preserves the\r\n // backend's channel default for non-app creates; the server never\r\n // infers owner type. See vived-api-legacy#133.\r\n const body = {\r\n ownerId: ownerID,\r\n name,\r\n description,\r\n filename,\r\n ...(ownerType !== undefined && { ownerType })\r\n };\r\n\r\n const options: RequestJSONOptions = {\r\n method: \"POST\",\r\n body: JSON.stringify(body),\r\n headers: {\r\n Authorization: \"Bearer \" + token\r\n }\r\n };\r\n\r\n return jsonRequester(postURL, options);\r\n })\r\n .then((result) => {\r\n assetId = result.assetId;\r\n resolve({\r\n id: assetId,\r\n filename\r\n });\r\n })\r\n .catch((e) => {\r\n reject(e);\r\n return;\r\n });\r\n });\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, PostNewAssetUC.type);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
|
|
@@ -71,7 +71,11 @@ class NewAppAssetUCImp extends NewAppAssetUC {
|
|
|
71
71
|
description,
|
|
72
72
|
name,
|
|
73
73
|
file,
|
|
74
|
-
ownerID: sandbox.appID
|
|
74
|
+
ownerID: sandbox.appID,
|
|
75
|
+
// App-owned create: the backend authorizes this via the `app` branch
|
|
76
|
+
// only when the row carries ownerType "app" (it does not infer it).
|
|
77
|
+
// See vivedlearning/vived-api-legacy#133.
|
|
78
|
+
ownerType: "app"
|
|
75
79
|
};
|
|
76
80
|
const spinnerDialog = this.spinnerFactory?.make({
|
|
77
81
|
title: "New App Asset",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NewAppAssetUC.js","sourceRoot":"","sources":["../../../../src/Assets/UCs/NewAppAssetUC.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,qBAAqB,EAGrB,WAAW,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAEL,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAkB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAczD;;;;GAIG;AACH,MAAM,OAAgB,aAAc,SAAQ,WAAW;IAYrD;;;;;OAKG;IACH,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC/D,CAAC;;AAnBD,wDAAwD;AACjD,kBAAI,GAAG,eAAe,CAAC;AAqBhC;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAoB;IACpD,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,gBAAiB,SAAQ,aAAa;IAG1C,IAAY,YAAY;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAiB,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9E,CAAC;IAED,IAAY,SAAS;QACnB,OAAO,IAAI,CAAC,kBAAkB,CAAY,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED,IAAY,OAAO;QACjB,OAAO,IAAI,CAAC,kBAAkB,CAAmB,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED,IAAY,cAAc;QACxB,OAAO,IAAI,CAAC,kBAAkB,CAC5B,mBAAmB,CAAC,IAAI,CACzB,CAAC;IACJ,CAAC;IAED,IAAY,YAAY;QACtB,OAAO,IAAI,CAAC,kBAAkB,CAAoB,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;
|
|
1
|
+
{"version":3,"file":"NewAppAssetUC.js","sourceRoot":"","sources":["../../../../src/Assets/UCs/NewAppAssetUC.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * NewAppAssetUC.ts\r\n *\r\n * This use case handles creation of new assets within application contexts,\r\n * managing the complete workflow from file upload to UI state transitions.\r\n */\r\n\r\nimport {\r\n getSingletonComponent,\r\n AppObject,\r\n AppObjectRepo,\r\n AppObjectUC\r\n} from \"@vived/core\";\r\nimport { AppSandboxEntity, SandboxState } from \"../../AppSandbox/Entities\";\r\nimport {\r\n DialogAlertDTO,\r\n MakeAlertDialogUC,\r\n MakeSpinnerDialogUC\r\n} from \"../../Dialog\";\r\nimport { NewAssetApiDto, PostNewAssetUC } from \"../../VivedAPI/UCs\";\r\nimport { AppAssetsEntity, AssetRepo } from \"../Entities\";\r\n\r\n/**\r\n * Data transfer object for new application asset creation requests.\r\n */\r\nexport interface NewAppAssetDTO {\r\n /** The file object to be uploaded and stored as the asset */\r\n file: File;\r\n /** Display name for the asset */\r\n name: string;\r\n /** Detailed description of the asset's purpose or content */\r\n description: string;\r\n}\r\n\r\n/**\r\n * NewAppAssetUC handles creation of new assets within application contexts.\r\n *\r\n * This singleton use case manages asset creation with UI feedback and state transitions.\r\n */\r\nexport abstract class NewAppAssetUC extends AppObjectUC {\r\n /** Static type identifier for component registration */\r\n static type = \"NewAppAssetUC\";\r\n\r\n /**\r\n * Creates a new asset with the provided data.\r\n *\r\n * @param data - Complete asset information including file and metadata\r\n * @returns Promise that resolves when the asset is successfully created\r\n */\r\n abstract create(data: NewAppAssetDTO): Promise<void>;\r\n\r\n /**\r\n * Retrieves the singleton NewAppAssetUC instance.\r\n *\r\n * @param appObjects - Repository for accessing the singleton component\r\n * @returns NewAppAssetUC instance or undefined if not found\r\n */\r\n static get(appObjects: AppObjectRepo): NewAppAssetUC | undefined {\r\n return getSingletonComponent(NewAppAssetUC.type, appObjects);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create a new NewAppAssetUC instance.\r\n *\r\n * @param appObject - The AppObject that will host this singleton use case\r\n * @returns A new NewAppAssetUC implementation instance\r\n */\r\nexport function makeNewAppAssetUC(appObject: AppObject): NewAppAssetUC {\r\n return new NewAppAssetUCImp(appObject);\r\n}\r\n\r\n/**\r\n * Private implementation of NewAppAssetUC with app context and state management.\r\n */\r\nclass NewAppAssetUCImp extends NewAppAssetUC {\r\n private appAssets?: AppAssetsEntity;\r\n\r\n private get postNewAsset() {\r\n return this.getCachedSingleton<PostNewAssetUC>(PostNewAssetUC.type)?.doPost;\r\n }\r\n\r\n private get assetRepo() {\r\n return this.getCachedSingleton<AssetRepo>(AssetRepo.type);\r\n }\r\n\r\n private get sandbox() {\r\n return this.getCachedSingleton<AppSandboxEntity>(AppSandboxEntity.type);\r\n }\r\n\r\n private get spinnerFactory() {\r\n return this.getCachedSingleton<MakeSpinnerDialogUC>(\r\n MakeSpinnerDialogUC.type\r\n );\r\n }\r\n\r\n private get alertFactory() {\r\n return this.getCachedSingleton<MakeAlertDialogUC>(MakeAlertDialogUC.type);\r\n }\r\n\r\n create = (data: NewAppAssetDTO): Promise<void> => {\r\n const appAssets = this.appAssets;\r\n const postNewAsset = this.postNewAsset;\r\n const sandbox = this.sandbox;\r\n const assetRepo = this.assetRepo;\r\n\r\n if (!appAssets || !postNewAsset || !sandbox || !assetRepo) {\r\n return Promise.reject();\r\n }\r\n\r\n return new Promise<void>((resolve) => {\r\n const { description, file, name } = data;\r\n\r\n const newAssetData: NewAssetApiDto = {\r\n description,\r\n name,\r\n file,\r\n ownerID: sandbox.appID,\r\n // App-owned create: the backend authorizes this via the `app` branch\r\n // only when the row carries ownerType \"app\" (it does not infer it).\r\n // See vivedlearning/vived-api-legacy#133.\r\n ownerType: \"app\"\r\n };\r\n\r\n const spinnerDialog = this.spinnerFactory?.make({\r\n title: \"New App Asset\",\r\n message: \"Posting new app asset...\"\r\n });\r\n\r\n postNewAsset(newAssetData)\r\n .then((resp) => {\r\n appAssets.add(resp.id);\r\n\r\n const newAsset = assetRepo.assetFactory(resp.id);\r\n newAsset.setFile(file);\r\n newAsset.description = description;\r\n newAsset.name = name;\r\n newAsset.filename = resp.filename;\r\n\r\n assetRepo.add(newAsset);\r\n this.sandbox!.state = SandboxState.MOUNTED;\r\n\r\n spinnerDialog?.close();\r\n resolve();\r\n })\r\n .catch((e: Error) => {\r\n this.error(\"create new asset error: \" + e.message);\r\n spinnerDialog?.close();\r\n\r\n const dialogDTO: DialogAlertDTO = {\r\n buttonLabel: \"OK\",\r\n message: `Something went wrong when creating a new app asset. Check the console. ${e.message}`,\r\n title: \"New App Asset Error\"\r\n };\r\n this.alertFactory?.make(dialogDTO);\r\n\r\n resolve();\r\n });\r\n });\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, NewAppAssetUC.type);\r\n this.appObjects.registerSingleton(this);\r\n\r\n this.appAssets = appObject.getComponent<AppAssetsEntity>(\r\n AppAssetsEntity.type\r\n );\r\n if (!this.appAssets) {\r\n this.error(\r\n \"UC added to an App Object that does not have AppAssetsEntity\"\r\n );\r\n return;\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -71,13 +71,21 @@ class FileUploadUCImp extends FileUploadUC {
|
|
|
71
71
|
return Promise.reject();
|
|
72
72
|
}
|
|
73
73
|
return new Promise((resolve, reject) => {
|
|
74
|
-
const getUploadURL = vivedAPI.getEndpointURL(`upload/large/DataVariants/${file.name}`);
|
|
74
|
+
const getUploadURL = vivedAPI.getEndpointURL(`upload/large/DataVariants/${file.name}?function_version=2`);
|
|
75
75
|
requestJSON(getUploadURL)
|
|
76
|
-
.then((
|
|
76
|
+
.then((result) => {
|
|
77
|
+
// v2 returns an object { url, contentType }, not a bare URL string.
|
|
78
|
+
const { url: uploadURL, contentType } = result;
|
|
77
79
|
const url = new URL(uploadURL);
|
|
78
80
|
const options = {
|
|
79
81
|
method: "PUT",
|
|
80
|
-
body: file
|
|
82
|
+
body: file,
|
|
83
|
+
// The SigV2 presigned PUT is signed with this exact Content-Type;
|
|
84
|
+
// echoing v2's own value guarantees the signature matches and S3
|
|
85
|
+
// stores the correct type instead of binary/octet-stream.
|
|
86
|
+
headers: {
|
|
87
|
+
"Content-Type": contentType
|
|
88
|
+
}
|
|
81
89
|
};
|
|
82
90
|
return basicFetch(url, options);
|
|
83
91
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileUploadUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/FileUploadUC.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,qBAAqB,EAGrB,WAAW,EACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAqB,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,MAAM,OAAgB,YAAa,SAAQ,WAAW;IAWpD;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,UAAyB;QAClC,OAAO,qBAAqB,CAAC,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9D,CAAC;;AAjBD,gDAAgD;AACzC,iBAAI,GAAG,cAAc,CAAC;AAmB/B;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAoB;IACnD,OAAO,IAAI,eAAe,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,eAAgB,SAAQ,YAAY;IACxC,IAAY,QAAQ;QAClB,OAAO,IAAI,CAAC,kBAAkB,CAAiB,cAAc,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,kBAAkB,CAAgB,aAAa,CAAC,IAAI,CAAC;YAC/D,EAAE,SAAS,CAAC;IAChB,CAAC;IAED,IAAY,UAAU;QACpB,OAAO,IAAI,CAAC,kBAAkB,CAAe,YAAY,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC7E,CAAC;
|
|
1
|
+
{"version":3,"file":"FileUploadUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/FileUploadUC.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * FileUploadUC.ts\r\n *\r\n * This file defines the Use Case for uploading files to the VIVED API.\r\n * FileUploadUC handles the process of uploading file data to storage endpoints,\r\n * managing multipart form data and upload progress.\r\n *\r\n * Key concepts:\r\n * - Abstract UC defining the interface for file upload operations\r\n * - Handles file upload workflows with progress tracking\r\n * - Coordinates with BasicFetchUC for HTTP transport\r\n * - Manages multipart form data encoding and transmission\r\n * - Provides error handling for upload failures\r\n *\r\n * Usage pattern:\r\n * 1. Get a UC instance using FileUploadUC.get(appObjects) or makeFileUploadUC\r\n * 2. Call doUpload with File object to upload\r\n * 3. Handle the returned Promise for upload completion\r\n * 4. UC manages the HTTP upload mechanics and error handling\r\n */\r\n\r\nimport {\r\n getSingletonComponent,\r\n AppObject,\r\n AppObjectRepo,\r\n AppObjectUC\r\n} from \"@vived/core\";\r\nimport { VivedAPIEntity } from \"../Entities/VivedAPIEntity\";\r\nimport { BasicFetchOptions, BasicFetchUC } from \"./BasicFetchUC\";\r\nimport { JsonRequestUC } from \"./JsonRequestUC\";\r\n\r\n/**\r\n * FileUploadUC provides functionality for uploading files to APIs.\r\n * Abstract class that defines the interface for file upload operations.\r\n */\r\nexport abstract class FileUploadUC extends AppObjectUC {\r\n /** Unique type identifier for this component */\r\n static type = \"FileUploadUC\";\r\n\r\n /**\r\n * Uploads a file to the configured API endpoint\r\n * @param file The File object to upload\r\n * @returns Promise that resolves when upload is complete\r\n */\r\n abstract doUpload(file: File): Promise<void>;\r\n\r\n /**\r\n * Retrieves a FileUploadUC component from an AppObject\r\n * @param appObjects The AppObjectRepo to get the component from\r\n * @returns The FileUploadUC component or undefined if not found\r\n */\r\n static get(appObjects: AppObjectRepo): FileUploadUC | undefined {\r\n return getSingletonComponent(FileUploadUC.type, appObjects);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create a new FileUploadUC instance\r\n * @param appObject The AppObject to attach the UC to\r\n * @returns A new FileUploadUC instance\r\n */\r\nexport function makeFileUploadUC(appObject: AppObject): FileUploadUC {\r\n return new FileUploadUCImp(appObject);\r\n}\r\n\r\n/**\r\n * Concrete implementation of FileUploadUC\r\n * This private class handles the actual file upload mechanics\r\n */\r\nclass FileUploadUCImp extends FileUploadUC {\r\n private get vivedAPI(): VivedAPIEntity | undefined {\r\n return this.getCachedSingleton<VivedAPIEntity>(VivedAPIEntity.type);\r\n }\r\n\r\n private get requestJSON() {\r\n return this.getCachedSingleton<JsonRequestUC>(JsonRequestUC.type)\r\n ?.doRequest;\r\n }\r\n\r\n private get basicFetch() {\r\n return this.getCachedSingleton<BasicFetchUC>(BasicFetchUC.type)?.doRequest;\r\n }\r\n\r\n doUpload = (file: File): Promise<void> => {\r\n const vivedAPI = this.vivedAPI;\r\n const requestJSON = this.requestJSON;\r\n const basicFetch = this.basicFetch;\r\n\r\n if (!vivedAPI || !requestJSON || !basicFetch) {\r\n return Promise.reject();\r\n }\r\n return new Promise<void>((resolve, reject) => {\r\n const getUploadURL = vivedAPI.getEndpointURL(\r\n `upload/large/DataVariants/${file.name}?function_version=2`\r\n );\r\n\r\n requestJSON(getUploadURL)\r\n .then((result) => {\r\n // v2 returns an object { url, contentType }, not a bare URL string.\r\n const { url: uploadURL, contentType } = result as {\r\n url: string;\r\n contentType: string;\r\n };\r\n const url = new URL(uploadURL);\r\n const options: BasicFetchOptions = {\r\n method: \"PUT\",\r\n body: file,\r\n // The SigV2 presigned PUT is signed with this exact Content-Type;\r\n // echoing v2's own value guarantees the signature matches and S3\r\n // stores the correct type instead of binary/octet-stream.\r\n headers: {\r\n \"Content-Type\": contentType\r\n }\r\n };\r\n\r\n return basicFetch(url, options);\r\n })\r\n .then((_) => {\r\n resolve();\r\n })\r\n .catch((e: Error) => {\r\n this.warn(e.message);\r\n reject(e);\r\n });\r\n });\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, FileUploadUC.type);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
|
|
@@ -77,12 +77,13 @@ class PostNewAssetUCImp extends PostNewAssetUC {
|
|
|
77
77
|
return Promise.reject();
|
|
78
78
|
}
|
|
79
79
|
return new Promise((resolve, reject) => {
|
|
80
|
-
const { description, file, name, ownerID } = data;
|
|
80
|
+
const { description, file, name, ownerID, ownerType } = data;
|
|
81
81
|
let assetId;
|
|
82
82
|
const nameSplits = file.name.split(".");
|
|
83
83
|
const extension = nameSplits[nameSplits.length - 1];
|
|
84
84
|
const filename = `${generateUniqueID()}.${extension}`;
|
|
85
85
|
const assetFile = new File([file], filename, {
|
|
86
|
+
type: file.type,
|
|
86
87
|
lastModified: Date.now()
|
|
87
88
|
});
|
|
88
89
|
fileUploader(assetFile)
|
|
@@ -91,11 +92,16 @@ class PostNewAssetUCImp extends PostNewAssetUC {
|
|
|
91
92
|
})
|
|
92
93
|
.then((token) => {
|
|
93
94
|
const postURL = vivedAPI.getEndpointURL("assets");
|
|
95
|
+
// Forward ownerType only when the caller declared it. Omitting the
|
|
96
|
+
// key (conditional spread → nothing when unset) preserves the
|
|
97
|
+
// backend's channel default for non-app creates; the server never
|
|
98
|
+
// infers owner type. See vived-api-legacy#133.
|
|
94
99
|
const body = {
|
|
95
100
|
ownerId: ownerID,
|
|
96
101
|
name,
|
|
97
102
|
description,
|
|
98
|
-
filename
|
|
103
|
+
filename,
|
|
104
|
+
...(ownerType !== undefined && { ownerType })
|
|
99
105
|
};
|
|
100
106
|
const options = {
|
|
101
107
|
method: "POST",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostNewAssetUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/PostNewAssetUC.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAGL,WAAW,EACX,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAsB,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"PostNewAssetUC.js","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/PostNewAssetUC.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * PostNewAssetUC.ts\r\n *\r\n * This file defines the Use Case for creating new assets via the VIVED API.\r\n * PostNewAssetUC handles the complete workflow of uploading asset files and\r\n * creating asset metadata records through API requests.\r\n *\r\n * Key concepts:\r\n * - Orchestrates file upload and metadata creation for new assets\r\n * - Handles multipart file uploads with asset information\r\n * - Manages authentication tokens and API endpoints\r\n * - Coordinates between multiple UCs (JsonRequest, FileUpload, SignedAuthToken)\r\n * - Returns asset creation response with generated IDs\r\n *\r\n * Usage pattern:\r\n * 1. Get a UC instance using PostNewAssetUC.get(appObjects) or makePostNewAssetUC\r\n * 2. Call doPost with asset data including file and metadata\r\n * 3. Handle the returned Promise with asset creation response\r\n * 4. UC will coordinate authentication, file upload, and API requests\r\n */\r\n\r\nimport {\r\n AppObject,\r\n AppObjectRepo,\r\n AppObjectUC,\r\n generateUniqueID,\r\n getSingletonComponent\r\n} from \"@vived/core\";\r\nimport { VivedAPIEntity } from \"../Entities/VivedAPIEntity\";\r\nimport { FileUploadUC } from \"./FileUploadUC\";\r\nimport { JsonRequestUC, RequestJSONOptions } from \"./JsonRequestUC\";\r\nimport { SignedAuthTokenUC } from \"./SignedAuthTokenUC\";\r\n\r\n/**\r\n * Data transfer object for new asset creation requests\r\n */\r\nexport interface NewAssetApiDto {\r\n /** Display name for the new asset */\r\n name: string;\r\n /** Description text for the asset */\r\n description: string;\r\n /** ID of the user who will own this asset */\r\n ownerID: string;\r\n /**\r\n * Owner type for the asset. The backend authorizes app-owned assets via the\r\n * `app` branch only when this is `\"app\"`; an absent value is treated as the\r\n * `channel` default (the backend does not — and must not — infer it). See\r\n * vivedlearning/vived-api-legacy#133.\r\n */\r\n ownerType?: \"channel\" | \"activity\" | \"app\";\r\n /** File object containing the asset data */\r\n file: File;\r\n}\r\n\r\n/**\r\n * Response data transfer object for successful asset creation\r\n */\r\nexport interface NewAssetResponseDTO {\r\n /** Unique identifier assigned to the new asset */\r\n id: string;\r\n /** Final filename used for the stored asset file */\r\n filename: string;\r\n}\r\n\r\n/**\r\n * PostNewAssetUC provides functionality for creating new assets via API.\r\n * Abstract class that defines the interface for asset creation operations.\r\n */\r\nexport abstract class PostNewAssetUC extends AppObjectUC {\r\n /** Unique type identifier for this component */\r\n static type = \"PostNewAssetUC\";\r\n\r\n /**\r\n * Creates a new asset by uploading file and metadata to the API\r\n * @param data The asset creation data including file and metadata\r\n * @returns Promise resolving to the new asset response with ID and filename\r\n */\r\n abstract doPost(data: NewAssetApiDto): Promise<NewAssetResponseDTO>;\r\n\r\n /**\r\n * Retrieves a PostNewAssetUC component from an AppObject\r\n * @param appObjects The AppObjectRepo to get the component from\r\n * @returns The PostNewAssetUC component or undefined if not found\r\n */\r\n static get(appObjects: AppObjectRepo): PostNewAssetUC | undefined {\r\n return getSingletonComponent(PostNewAssetUC.type, appObjects);\r\n }\r\n}\r\n\r\n/**\r\n * Factory function to create a new PostNewAssetUC instance\r\n * @param appObject The AppObject to attach the UC to\r\n * @returns A new PostNewAssetUC instance\r\n */\r\nexport function makePostNewAssetUC(appObject: AppObject): PostNewAssetUC {\r\n return new PostNewAssetUCImp(appObject);\r\n}\r\n\r\n/**\r\n * Concrete implementation of PostNewAssetUC\r\n * This private class handles the actual asset creation workflow\r\n */\r\nclass PostNewAssetUCImp extends PostNewAssetUC {\r\n private get jsonRequester() {\r\n return this.getCachedSingleton<JsonRequestUC>(JsonRequestUC.type)\r\n ?.doRequest;\r\n }\r\n\r\n private get getPlayerAuthToken() {\r\n return this.getCachedSingleton<SignedAuthTokenUC>(SignedAuthTokenUC.type)\r\n ?.getAuthToken;\r\n }\r\n\r\n private get fileUploader() {\r\n return this.getCachedSingleton<FileUploadUC>(FileUploadUC.type)?.doUpload;\r\n }\r\n\r\n private get vivedAPI() {\r\n return this.getCachedSingleton<VivedAPIEntity>(VivedAPIEntity.type);\r\n }\r\n\r\n doPost = (data: NewAssetApiDto): Promise<NewAssetResponseDTO> => {\r\n const fileUploader = this.fileUploader;\r\n const getPlayerAuthToken = this.getPlayerAuthToken;\r\n const vivedAPI = this.vivedAPI;\r\n const jsonRequester = this.jsonRequester;\r\n\r\n if (!fileUploader || !getPlayerAuthToken || !vivedAPI || !jsonRequester) {\r\n return Promise.reject();\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const { description, file, name, ownerID, ownerType } = data;\r\n let assetId: string;\r\n\r\n const nameSplits = file.name.split(\".\");\r\n const extension = nameSplits[nameSplits.length - 1];\r\n const filename = `${generateUniqueID()}.${extension}`;\r\n const assetFile = new File([file], filename, {\r\n type: file.type,\r\n lastModified: Date.now()\r\n });\r\n\r\n fileUploader(assetFile)\r\n .then((_) => {\r\n return getPlayerAuthToken();\r\n })\r\n .then((token) => {\r\n const postURL = vivedAPI.getEndpointURL(\"assets\");\r\n\r\n // Forward ownerType only when the caller declared it. Omitting the\r\n // key (conditional spread → nothing when unset) preserves the\r\n // backend's channel default for non-app creates; the server never\r\n // infers owner type. See vived-api-legacy#133.\r\n const body = {\r\n ownerId: ownerID,\r\n name,\r\n description,\r\n filename,\r\n ...(ownerType !== undefined && { ownerType })\r\n };\r\n\r\n const options: RequestJSONOptions = {\r\n method: \"POST\",\r\n body: JSON.stringify(body),\r\n headers: {\r\n Authorization: \"Bearer \" + token\r\n }\r\n };\r\n\r\n return jsonRequester(postURL, options);\r\n })\r\n .then((result) => {\r\n assetId = result.assetId;\r\n resolve({\r\n id: assetId,\r\n filename\r\n });\r\n })\r\n .catch((e) => {\r\n reject(e);\r\n return;\r\n });\r\n });\r\n };\r\n\r\n constructor(appObject: AppObject) {\r\n super(appObject, PostNewAssetUC.type);\r\n this.appObjects.registerSingleton(this);\r\n }\r\n}\r\n"]}
|
|
@@ -29,6 +29,13 @@ export interface NewAssetApiDto {
|
|
|
29
29
|
description: string;
|
|
30
30
|
/** ID of the user who will own this asset */
|
|
31
31
|
ownerID: string;
|
|
32
|
+
/**
|
|
33
|
+
* Owner type for the asset. The backend authorizes app-owned assets via the
|
|
34
|
+
* `app` branch only when this is `"app"`; an absent value is treated as the
|
|
35
|
+
* `channel` default (the backend does not — and must not — infer it). See
|
|
36
|
+
* vivedlearning/vived-api-legacy#133.
|
|
37
|
+
*/
|
|
38
|
+
ownerType?: "channel" | "activity" | "app";
|
|
32
39
|
/** File object containing the asset data */
|
|
33
40
|
file: File;
|
|
34
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostNewAssetUC.d.ts","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/PostNewAssetUC.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,SAAS,EACT,aAAa,EACb,WAAW,EAGZ,MAAM,aAAa,CAAC;AAMrB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,8BAAsB,cAAe,SAAQ,WAAW;IACtD,gDAAgD;IAChD,MAAM,CAAC,IAAI,SAAoB;IAE/B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAEnE;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,GAAG,cAAc,GAAG,SAAS;CAGlE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,CAEvE"}
|
|
1
|
+
{"version":3,"file":"PostNewAssetUC.d.ts","sourceRoot":"","sources":["../../../../src/VivedAPI/UCs/PostNewAssetUC.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,SAAS,EACT,aAAa,EACb,WAAW,EAGZ,MAAM,aAAa,CAAC;AAMrB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;IAC3C,4CAA4C;IAC5C,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,8BAAsB,cAAe,SAAQ,WAAW;IACtD,gDAAgD;IAChD,MAAM,CAAC,IAAI,SAAoB;IAE/B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAEnE;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,GAAG,cAAc,GAAG,SAAS;CAGlE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,CAEvE"}
|