feat: add needed methods to the file module and providers (#12325)
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import { Readable } from "stream"
|
||||||
import { FileAccessPermission } from "./common"
|
import { FileAccessPermission } from "./common"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,4 +145,14 @@ export interface IFileProvider {
|
|||||||
getPresignedUploadUrl?(
|
getPresignedUploadUrl?(
|
||||||
fileData: ProviderGetPresignedUploadUrlDTO
|
fileData: ProviderGetPresignedUploadUrlDTO
|
||||||
): Promise<ProviderFileResultDTO>
|
): Promise<ProviderFileResultDTO>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a readable stream.
|
||||||
|
*/
|
||||||
|
getAsStream(fileData: ProviderGetFileDTO): Promise<Readable>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a Node.js Buffer
|
||||||
|
*/
|
||||||
|
getAsBuffer(fileData: ProviderGetFileDTO): Promise<Buffer>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
|
import { Readable } from "stream"
|
||||||
import { IModuleService } from "../modules-sdk"
|
import { IModuleService } from "../modules-sdk"
|
||||||
import { FileDTO, FilterableFileProps, UploadFileUrlDTO } from "./common"
|
import { FileDTO, FilterableFileProps, UploadFileUrlDTO } from "./common"
|
||||||
import { FindConfig } from "../common"
|
import { FindConfig } from "../common"
|
||||||
import { Context } from "../shared-context"
|
import { Context } from "../shared-context"
|
||||||
|
import { IFileProvider } from "./provider"
|
||||||
import { CreateFileDTO, GetUploadFileUrlDTO } from "./mutations"
|
import { CreateFileDTO, GetUploadFileUrlDTO } from "./mutations"
|
||||||
|
|
||||||
export interface IFileModuleService extends IModuleService {
|
export interface IFileModuleService extends IModuleService {
|
||||||
|
/**
|
||||||
|
* Returns a reference to the file provider in use
|
||||||
|
*/
|
||||||
|
getProvider(): IFileProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method uploads files to the designated file storage system.
|
* This method uploads files to the designated file storage system.
|
||||||
*
|
*
|
||||||
@@ -157,4 +164,22 @@ export interface IFileModuleService extends IModuleService {
|
|||||||
config?: FindConfig<FileDTO>,
|
config?: FindConfig<FileDTO>,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<[FileDTO[], number]>
|
): Promise<[FileDTO[], number]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a readable stream.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const stream = await fileModuleService.getAsStream("file_123")
|
||||||
|
* writeable.pipe(stream)
|
||||||
|
*/
|
||||||
|
getAsStream(id: string, sharedContext?: Context): Promise<Readable>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a Node.js Buffer
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const contents = await fileModuleService.getAsBuffer("file_123")
|
||||||
|
* contents.toString('utf-8')
|
||||||
|
*/
|
||||||
|
getAsBuffer(id: string, sharedContext?: Context): Promise<Buffer>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Readable } from "stream"
|
||||||
import { FileTypes, IFileProvider } from "@medusajs/types"
|
import { FileTypes, IFileProvider } from "@medusajs/types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,4 +175,34 @@ export class AbstractFileProviderService implements IFileProvider {
|
|||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
throw Error("getPresignedDownloadUrl must be overridden by the child class")
|
throw Error("getPresignedDownloadUrl must be overridden by the child class")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a readable stream.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* class MyFileProviderService extends AbstractFileProviderService {
|
||||||
|
* // ...
|
||||||
|
* async getAsStream(file: ProviderDeleteFileDTO): Promise<Readable> {
|
||||||
|
* this.client.getAsStream(file.fileKey)
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
getAsStream(fileData: FileTypes.ProviderGetFileDTO): Promise<Readable> {
|
||||||
|
throw Error("getAsStream must be overridden by the child class")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a Node.js Buffer
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* class MyFileProviderService extends AbstractFileProviderService {
|
||||||
|
* // ...
|
||||||
|
* async getAsBuffer(file: ProviderDeleteFileDTO): Promise<Buffer> {
|
||||||
|
* this.client.getAsBuffer(file.fileKey)
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
getAsBuffer(fileData: FileTypes.ProviderGetFileDTO): Promise<Buffer> {
|
||||||
|
throw Error("getAsBuffer must be overridden by the child class")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Readable } from "stream"
|
||||||
import {
|
import {
|
||||||
Context,
|
Context,
|
||||||
CreateFileDTO,
|
CreateFileDTO,
|
||||||
@@ -28,6 +29,10 @@ export default class FileModuleService implements FileTypes.IFileModuleService {
|
|||||||
return joinerConfig
|
return joinerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProvider() {
|
||||||
|
return this.fileProviderService_
|
||||||
|
}
|
||||||
|
|
||||||
createFiles(
|
createFiles(
|
||||||
data: CreateFileDTO[],
|
data: CreateFileDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
@@ -154,4 +159,26 @@ export default class FileModuleService implements FileTypes.IFileModuleService {
|
|||||||
1,
|
1,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a readable stream.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const stream = await fileModuleService.getAsStream("file_123")
|
||||||
|
* writeable.pipe(stream)
|
||||||
|
*/
|
||||||
|
getAsStream(id: string): Promise<Readable> {
|
||||||
|
return this.fileProviderService_.getAsStream({ fileKey: id })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the file contents as a Node.js Buffer
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const contents = await fileModuleService.getAsBuffer("file_123")
|
||||||
|
* contents.toString('utf-8')
|
||||||
|
*/
|
||||||
|
getAsBuffer(id: string): Promise<Buffer> {
|
||||||
|
return this.fileProviderService_.getAsBuffer({ fileKey: id })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Readable } from "stream"
|
||||||
import { Constructor, FileTypes } from "@medusajs/framework/types"
|
import { Constructor, FileTypes } from "@medusajs/framework/types"
|
||||||
import { MedusaError } from "@medusajs/framework/utils"
|
import { MedusaError } from "@medusajs/framework/utils"
|
||||||
import { FileProviderRegistrationPrefix } from "@types"
|
import { FileProviderRegistrationPrefix } from "@types"
|
||||||
@@ -68,4 +69,12 @@ export default class FileProviderService {
|
|||||||
|
|
||||||
return this.fileProvider_.getPresignedUploadUrl(fileData)
|
return this.fileProvider_.getPresignedUploadUrl(fileData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAsStream(fileData: FileTypes.ProviderGetFileDTO): Promise<Readable> {
|
||||||
|
return this.fileProvider_.getAsStream(fileData)
|
||||||
|
}
|
||||||
|
|
||||||
|
getAsBuffer(fileData: FileTypes.ProviderGetFileDTO): Promise<Buffer> {
|
||||||
|
return this.fileProvider_.getAsBuffer(fileData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ModuleProvider, Modules } from "@medusajs/framework/utils"
|
import { ModuleProvider, Modules } from "@medusajs/framework/utils"
|
||||||
import { LocalFileService } from "./services/local-file"
|
import { LocalFileService } from "./services/local-file"
|
||||||
|
export { LocalFileService }
|
||||||
|
|
||||||
const services = [LocalFileService]
|
const services = [LocalFileService]
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import {
|
|||||||
AbstractFileProviderService,
|
AbstractFileProviderService,
|
||||||
MedusaError,
|
MedusaError,
|
||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
|
import { createReadStream } from "fs"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
import type { Readable } from "stream"
|
||||||
|
|
||||||
export class LocalFileService extends AbstractFileProviderService {
|
export class LocalFileService extends AbstractFileProviderService {
|
||||||
static identifier = "localfs"
|
static identifier = "localfs"
|
||||||
@@ -83,6 +85,24 @@ export class LocalFileService extends AbstractFileProviderService {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAsStream(file: FileTypes.ProviderGetFileDTO): Promise<Readable> {
|
||||||
|
const baseDir = file.fileKey.startsWith("private-")
|
||||||
|
? this.privateUploadDir_
|
||||||
|
: this.uploadDir_
|
||||||
|
|
||||||
|
const filePath = this.getUploadFilePath(baseDir, file.fileKey)
|
||||||
|
return createReadStream(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAsBuffer(file: FileTypes.ProviderGetFileDTO): Promise<Buffer> {
|
||||||
|
const baseDir = file.fileKey.startsWith("private-")
|
||||||
|
? this.privateUploadDir_
|
||||||
|
: this.uploadDir_
|
||||||
|
|
||||||
|
const filePath = this.getUploadFilePath(baseDir, file.fileKey)
|
||||||
|
return fs.readFile(filePath)
|
||||||
|
}
|
||||||
|
|
||||||
// The local file provider doesn't support presigned URLs for private files (i.e files not placed in /static).
|
// The local file provider doesn't support presigned URLs for private files (i.e files not placed in /static).
|
||||||
async getPresignedDownloadUrl(
|
async getPresignedDownloadUrl(
|
||||||
file: FileTypes.ProviderGetFileDTO
|
file: FileTypes.ProviderGetFileDTO
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
MedusaError,
|
MedusaError,
|
||||||
} from "@medusajs/framework/utils"
|
} from "@medusajs/framework/utils"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
import { Readable } from "stream"
|
||||||
import { ulid } from "ulid"
|
import { ulid } from "ulid"
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
@@ -215,4 +216,42 @@ export class S3FileService extends AbstractFileProviderService {
|
|||||||
key: fileKey,
|
key: fileKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAsStream(file: FileTypes.ProviderGetFileDTO): Promise<Readable> {
|
||||||
|
if (!file?.filename) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`No filename provided`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileKey = `${this.config_.prefix}${file.filename}`
|
||||||
|
const response = await this.client_.send(
|
||||||
|
new GetObjectCommand({
|
||||||
|
Key: fileKey,
|
||||||
|
Bucket: this.config_.bucket,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.Body! as Readable
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAsBuffer(file: FileTypes.ProviderGetFileDTO): Promise<Buffer> {
|
||||||
|
if (!file?.filename) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`No filename provided`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileKey = `${this.config_.prefix}${file.filename}`
|
||||||
|
const response = await this.client_.send(
|
||||||
|
new GetObjectCommand({
|
||||||
|
Key: fileKey,
|
||||||
|
Bucket: this.config_.bucket,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return Buffer.from(await response.Body!.transformToByteArray())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user