Skip to content

Commit

Permalink
feat: Add boilerplate for the file module
Browse files Browse the repository at this point in the history
  • Loading branch information
sradevski committed Apr 5, 2024
1 parent eb93e8f commit 58aa720
Show file tree
Hide file tree
Showing 35 changed files with 882 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/core-flows/src/file/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./steps"
export * from "./workflows"
17 changes: 17 additions & 0 deletions packages/core-flows/src/file/steps/delete-files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IFileModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"

export const deleteFilesStepId = "delete-files"
export const deleteFilesStep = createStep(
{ name: deleteFilesStepId, noCompensation: true },
async (ids: string[], { container }) => {
const service = container.resolve<IFileModuleService>(
ModuleRegistrationName.FILE
)

await service.delete(ids)
return new StepResponse(void 0)
},
async () => {}
)
2 changes: 2 additions & 0 deletions packages/core-flows/src/file/steps/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./upload-files"
export * from "./delete-files"
37 changes: 37 additions & 0 deletions packages/core-flows/src/file/steps/upload-files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IFileModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"

type UploadFilesStepInput = {
files: {
filename: string
mimeType: string
content: Blob
}[]
}

export const uploadFilesStepId = "upload-files"
export const uploadFilesStep = createStep(
uploadFilesStepId,
async (data: UploadFilesStepInput, { container }) => {
const service = container.resolve<IFileModuleService>(
ModuleRegistrationName.FILE
)
const created = await service.create(data.files)
return new StepResponse(
created,
created.map((file) => file.id)
)
},
async (createdIds, { container }) => {
if (!createdIds?.length) {
return
}

const service = container.resolve<IFileModuleService>(
ModuleRegistrationName.FILE
)

await service.delete(createdIds)
}
)
12 changes: 12 additions & 0 deletions packages/core-flows/src/file/workflows/delete-files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { deleteFilesStep } from "../steps"

type WorkflowInput = { ids: string[] }

export const deleteFilesWorkflowId = "delete-files"
export const deleteFilesWorkflow = createWorkflow(
deleteFilesWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
deleteFilesStep(input.ids)
}
)
2 changes: 2 additions & 0 deletions packages/core-flows/src/file/workflows/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./upload-files"
export * from "./delete-files"
19 changes: 19 additions & 0 deletions packages/core-flows/src/file/workflows/upload-files.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { FileDTO } from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { uploadFilesStep } from "../steps"

type WorkflowInput = {
files: {
filename: string
mimeType: string
content: Blob
}[]
}

export const uploadFilesWorkflowId = "upload-files"
export const uploadFilesWorkflow = createWorkflow(
uploadFilesWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<FileDTO[]> => {
return uploadFilesStep(input)
}
)
1 change: 1 addition & 0 deletions packages/core-flows/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ export * from "./stock-location"
export * from "./store"
export * from "./tax"
export * from "./user"
export * from "./file"
6 changes: 6 additions & 0 deletions packages/file/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/dist
node_modules
.DS_store
.env*
.env
*.sql
282 changes: 282 additions & 0 deletions packages/file/CHANGELOG.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/file/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# File Module
20 changes: 20 additions & 0 deletions packages/file/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
moduleNameMapper: {
"^@models": "<rootDir>/src/models",
"^@services": "<rootDir>/src/services",
"^@repositories": "<rootDir>/src/repositories",
"^@types": "<rootDir>/src/types",
},
transform: {
"^.+\\.[jt]s?$": [
"ts-jest",
{
tsconfig: "tsconfig.spec.json",
isolatedModules: true,
},
],
},
testEnvironment: `node`,
moduleFileExtensions: [`js`, `ts`],
modulePathIgnorePatterns: ["dist/"],
}
61 changes: 61 additions & 0 deletions packages/file/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@medusajs/file",
"version": "0.0.1",
"description": "Medusa File module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"engines": {
"node": ">=16"
},
"repository": {
"type": "git",
"url": "https://github.com/medusajs/medusa",
"directory": "packages/file"
},
"publishConfig": {
"access": "public"
},
"author": "Medusa",
"license": "MIT",
"scripts": {
"watch": "tsc --build --watch",
"watch:test": "tsc --build tsconfig.spec.json --watch",
"prepublishOnly": "cross-env NODE_ENV=production tsc --build && tsc-alias -p tsconfig.json",
"build": "rimraf dist && tsc --build && tsc-alias -p tsconfig.json",
"test": "jest --passWithNoTests --runInBand --bail --forceExit -- src/**/__tests__/**/*.ts",
"test:integration": "jest --passWithNoTests --forceExit -- integration-tests/**/__tests__/**/*.ts",
"migration:generate": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:generate",
"migration:initial": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create --initial",
"migration:create": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create",
"migration:up": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:up",
"orm:cache:clear": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm cache:clear"
},
"devDependencies": {
"@mikro-orm/cli": "5.9.7",
"cross-env": "^5.2.1",
"faker": "^6.6.6",
"jest": "^29.6.3",
"medusa-test-utils": "^1.1.43",
"pg-god": "^1.0.12",
"rimraf": "^3.0.2",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"tsc-alias": "^1.8.6",
"typescript": "^5.1.6"
},
"dependencies": {
"@medusajs/modules-sdk": "^1.12.10",
"@medusajs/types": "^1.11.15",
"@medusajs/utils": "^1.11.8",
"@mikro-orm/core": "5.9.7",
"@mikro-orm/migrations": "5.9.7",
"@mikro-orm/postgresql": "5.9.7",
"awilix": "^8.0.0",
"dotenv": "^16.4.5",
"knex": "2.4.2",
"lodash": "^4.17.21"
}
}
10 changes: 10 additions & 0 deletions packages/file/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {
moduleDefinition,
revertMigration,
runMigrations,
} from "./module-definition"

export default moduleDefinition
export { revertMigration, runMigrations }

export * from "./services"
22 changes: 22 additions & 0 deletions packages/file/src/joiner-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"
import { MapToConfig } from "@medusajs/utils"

export const LinkableKeys = {}

const entityLinkableKeysMap: MapToConfig = {}
export const entityNameToLinkableKeysMap: MapToConfig = entityLinkableKeysMap

export const joinerConfig: ModuleJoinerConfig = {
serviceName: Modules.FILE,
primaryKeys: ["id"],
linkableKeys: LinkableKeys,
alias: [
{
name: ["file", "files"],
args: {
entity: "File",
},
},
],
}
Empty file.
18 changes: 18 additions & 0 deletions packages/file/src/module-definition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ModuleExports } from "@medusajs/types"
import { FileModuleService } from "@services"
export const runMigrations = () => {
return Promise.resolve()
}
export const revertMigration = () => {
return Promise.resolve()
}

const service = FileModuleService
const loaders = [] as any

export const moduleDefinition: ModuleExports = {
service,
loaders,
runMigrations,
revertMigration,
}
3 changes: 3 additions & 0 deletions packages/file/src/services/__tests__/file.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
describe("File service", function () {
it("noop", async function () {})
})
42 changes: 42 additions & 0 deletions packages/file/src/services/file-module-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
Context,
CreateFileDTO,
FileDTO,
ModuleJoinerConfig,
} from "@medusajs/types"

import { joinerConfig } from "../joiner-config"

export default class FileModuleService {
constructor() {
// @ts-ignore
// eslint-disable-next-line prefer-rest-params
super(...arguments)
}

__joinerConfig(): ModuleJoinerConfig {
return joinerConfig
}

create(data: CreateFileDTO[], sharedContext?: Context): Promise<FileDTO[]>
create(data: CreateFileDTO, sharedContext?: Context): Promise<FileDTO>

async create(
data: CreateFileDTO[] | CreateFileDTO
): Promise<FileDTO[] | FileDTO> {
const input = Array.isArray(data) ? data : [data]
const files = []
return Array.isArray(data) ? files : files[0]
}

async delete(ids: string[], sharedContext?: Context): Promise<void>
async delete(id: string, sharedContext?: Context): Promise<void>
async delete(ids: string[] | string): Promise<void> {
return
}

async retrieve(id: string): Promise<FileDTO>
async retrieve(id: string): Promise<FileDTO> {
return {} as FileDTO
}
}
1 change: 1 addition & 0 deletions packages/file/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as FileModuleService } from "./file-module-service"
37 changes: 37 additions & 0 deletions packages/file/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"compilerOptions": {
"lib": ["es2020"],
"target": "es2020",
"outDir": "./dist",
"esModuleInterop": true,
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": false,
"noImplicitReturns": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"allowJs": true,
"skipLibCheck": true,
"downlevelIteration": true, // to use ES5 specific tooling
"baseUrl": ".",
"resolveJsonModule": true,
"paths": {
"@models": ["./src/models"],
"@services": ["./src/services"],
"@repositories": ["./src/repositories"],
"@types": ["./src/types"]
}
},
"include": ["src"],
"exclude": [
"dist",
"./src/**/__tests__",
"./src/**/__mocks__",
"./src/**/__fixtures__",
"node_modules"
]
}
8 changes: 8 additions & 0 deletions packages/file/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"include": ["src", "integration-tests"],
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"sourceMap": true
}
}
45 changes: 45 additions & 0 deletions packages/medusa/src/api-v2/admin/uploads/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../types/routing"
import { deleteFilesWorkflow } from "@medusajs/core-flows"
import { remoteQueryObjectFromString } from "@medusajs/utils"

export const GET = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const variables = { id: req.params.id }

const queryObject = remoteQueryObjectFromString({
entryPoint: "file",
variables,
fields: req.remoteQueryConfig.fields,
})

const [file] = await remoteQuery(queryObject)
res.status(200).json({ file })
}

export const DELETE = async (
req: AuthenticatedMedusaRequest,
res: MedusaResponse
) => {
const id = req.params.id

const { errors } = await deleteFilesWorkflow(req.scope).run({
input: { ids: [id] },
throwOnError: false,
})

if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}

res.status(200).json({
id,
object: "file",
deleted: true,
})
}
Loading

0 comments on commit 58aa720

Please sign in to comment.