docs: added file module docs (#7278)
This commit is contained in:
@@ -12,8 +12,6 @@ An architectural module implements features and mechanisms related to the Medusa
|
||||
|
||||
Since modules are interchangeable, you have more control over Medusa’s architecture. For example, you can choose to use Memcached for event handling instead of Redis.
|
||||
|
||||
Medusa currently supports two types of architectural modules: Cache and event modules.
|
||||
|
||||
<Note>
|
||||
|
||||
Refer to the [Architectural Modules reference](!resources!/architectural-modules) for a list of Medusa’s architectural modules.
|
||||
@@ -26,4 +24,4 @@ Refer to the [Architectural Modules reference](!resources!/architectural-modules
|
||||
|
||||
You create an architectural module like you’ve been creating custom modules: create a module with a service and export that service in the module’s definition file. The module's service extends an abstract class or interface provided by Medusa with predefined method signatures.
|
||||
|
||||
The next chapters explain the different architectural module types and how to create an architectural module for each.
|
||||
The next chapters explain the different architectural module types and how to create an architectural module for each.
|
||||
|
||||
@@ -18,4 +18,16 @@ The underlying database, third-party service, or caching logic is flexible since
|
||||
|
||||
By default, Medusa uses the In-Memory Cache Module. This module uses a plain JavaScript Map object to store the cache data.
|
||||
|
||||
This is useful for development. However, for production, it's highly recommended to use other Cache Modules, such as the [Redis Cache Module](!resources!/architectural-modules/cache/redis).
|
||||
This is useful for development. However, for production, it's highly recommended to use other Cache Modules, such as the [Redis Cache Module](!resources!/architectural-modules/cache/redis).
|
||||
|
||||
---
|
||||
|
||||
## List of Cache Modules
|
||||
|
||||
Refer to the Medusa Learning Resources for a [list of available cache modules](!resources!/architectural-modules/cache).
|
||||
|
||||
---
|
||||
|
||||
## Create a Cache Module
|
||||
|
||||
To create a cache module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/cache/create).
|
||||
|
||||
@@ -12,7 +12,7 @@ In previous chapters, you learned that the Medusa application emits events, and
|
||||
|
||||
The Event Module implements the underlying publish/subscribe system that handles queueing events, emitting them, and executing their subscribers.
|
||||
|
||||
This makes the event architecture customizable, as you can either choose one of Medusa’s Event Modules or create your own.
|
||||
This makes the event architecture customizable, as you can either choose one of Medusa’s event modules or create your own.
|
||||
|
||||
---
|
||||
|
||||
@@ -21,3 +21,15 @@ This makes the event architecture customizable, as you can either choose one of
|
||||
By default, Medusa uses the Local Event Module. This module uses Node’s EventEmitter to implement the publish/subscribe system.
|
||||
|
||||
This is useful for development. However, for production, it’s highly recommended to use other Event Modules, such as the [Redis Event Module](!resources!/architectural-modules/event/redis).
|
||||
|
||||
---
|
||||
|
||||
## List of Event Modules
|
||||
|
||||
Refer to the Medusa Learning Resources for a [list of available event modules](!resources!/architectural-modules/event).
|
||||
|
||||
---
|
||||
|
||||
## Create a Event Module
|
||||
|
||||
To create an event module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/event/create).
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} File Module`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn about what the File Module is.
|
||||
|
||||
## What is the File Module?
|
||||
|
||||
The File Module exposes the functionalities to upload assets, such as product images, to the Medusa application.
|
||||
|
||||
---
|
||||
|
||||
## What is a File Provider Module?
|
||||
|
||||
A file provider module implements the logic of handling uploads and downloads. The File Module must have one file provider module configured.
|
||||
|
||||
By default, Medusa uses the Local File Module. This module uploads files to the `uploads` directory of your Medusa application.
|
||||
|
||||
{/* TODO add once s3 module is working/published? */}
|
||||
|
||||
{/* This is useful for development. However, for production, it’s highly recommended to use other File Modules, such as the [S3 Module](!resources!/architectural-modules/event/redis). */}
|
||||
|
||||
---
|
||||
|
||||
## List of File Provider Modules
|
||||
|
||||
Refer to the Medusa Learning Resources for a [list of available file provider modules](!resources!/architectural-modules/file).
|
||||
|
||||
---
|
||||
|
||||
## Create a File Provider Module
|
||||
|
||||
To create a file provider module, refer to [this guide in the Medusa Learning Resources](!resources!/architectural-modules/references/file-provider-module).
|
||||
@@ -9,5 +9,4 @@ In the next chapters, you’ll learn more about customizable aspects of Medusa
|
||||
By the end of these chapters, you’ll learn about:
|
||||
|
||||
- What an architectural module is.
|
||||
- The cache architectural module and how to create one.
|
||||
- The events architectural module and how to create one.
|
||||
- The different types of architectural modules, including cache and event modules.
|
||||
|
||||
@@ -253,22 +253,14 @@ export const sidebar = sidebarAttachHrefCommonOptions(
|
||||
{
|
||||
path: "/architectural-concepts/cache-module",
|
||||
title: "Cache Module",
|
||||
children: [
|
||||
{
|
||||
path: "/architectural-concepts/cache-module/create",
|
||||
title: "Create Cache Module",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/architectural-concepts/event-module",
|
||||
title: "Event Module",
|
||||
children: [
|
||||
{
|
||||
path: "/architectural-concepts/event-module/create",
|
||||
title: "Create Event Module",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/architectural-concepts/file-module",
|
||||
title: "File Module",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} How to Create a Cache Module`,
|
||||
title: `How to Create a Cache Module`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn how to create a Cache Module.
|
||||
In this guide, you’ll learn how to create a Cache Module.
|
||||
|
||||
## 1. Create Module Directory
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ChildDocs } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Cache Modules`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
Learn how to create a cache module in [this guide](./create/page.mdx).
|
||||
|
||||
<ChildDocs type="item" filters={["Guides"]} onlyTopLevel={true} />
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} How to Create an Event Module`,
|
||||
title: `How to Create an Event Module`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this chapter, you’ll learn how to create an Event Module.
|
||||
In this guide, you’ll learn how to create an Event Module.
|
||||
|
||||
## 1. Create Module Directory
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ChildDocs } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Event Modules`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
Learn how to create a event module in [this guide](./create/page.mdx).
|
||||
|
||||
<ChildDocs type="item" filters={["Guides"]} onlyTopLevel={true} />
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Table } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Local File Provider Module`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
The Local File Provider Module stores files uploaded to your Medusa application in the `/uploads` directory.
|
||||
|
||||
---
|
||||
|
||||
## Install the Local File Module
|
||||
|
||||
To install the Local File Provider Module, run the following command in the directory of your Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @medusajs/file-local-next
|
||||
```
|
||||
|
||||
Next, add the module into the `providers` array of the File Module:
|
||||
|
||||
<Note>
|
||||
|
||||
The File Module accepts one provider only.
|
||||
|
||||
</Note>
|
||||
|
||||
```js title="medusa-config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
modules: {
|
||||
// ...
|
||||
[Modules.FILE]: {
|
||||
resolve: "@medusajs/file",
|
||||
options: {
|
||||
providers: [
|
||||
{
|
||||
resolve: "@medusajs/file-local-next",
|
||||
options: {
|
||||
config: {
|
||||
local: {
|
||||
// provider options...
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Local File Module Options
|
||||
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Option</Table.HeaderCell>
|
||||
<Table.HeaderCell>Description</Table.HeaderCell>
|
||||
<Table.HeaderCell>Default</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
|
||||
`upload_dir`
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
The directory to upload files to.
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
`uploads`
|
||||
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
|
||||
`upload_dir`
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
The URL of the Medusa application.
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
`http://localhost:9000`
|
||||
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table>
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ChildDocs } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `File Provider Modules`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
Learn how to create a file provider module in [this guide](/references/file-provider-module).
|
||||
|
||||
<ChildDocs type="item" filters={["Guides"]} onlyTopLevel={true} />
|
||||
@@ -8,4 +8,4 @@ export const metadata = {
|
||||
|
||||
This section includes documentation for official Medusa architectural modules.
|
||||
|
||||
<ChildDocs />
|
||||
<ChildDocs filters={["Guides"]} />
|
||||
@@ -48,11 +48,15 @@ const modules = {
|
||||
{
|
||||
resolve: "@medusajs/payment-stripe",
|
||||
options: {
|
||||
credentials: {
|
||||
usd: {
|
||||
apiKey: process.env.STRIPE_USD_API_KEY,
|
||||
},
|
||||
},
|
||||
config: {
|
||||
stripe: {
|
||||
credentials: {
|
||||
usd: {
|
||||
apiKey: process.env.STRIPE_USD_API_KEY,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -3,22 +3,46 @@ export const filesMap = [
|
||||
"filePath": "/www/apps/resources/app/admin-widget-injection-zones/page.mdx",
|
||||
"pathname": "/admin-widget-injection-zones"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/cache/create/page.mdx",
|
||||
"pathname": "/architectural-modules/cache/create"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/cache/in-memory/page.mdx",
|
||||
"pathname": "/architectural-modules/cache/in-memory"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/cache/page.mdx",
|
||||
"pathname": "/architectural-modules/cache"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/cache/redis/page.mdx",
|
||||
"pathname": "/architectural-modules/cache/redis"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/event/create/page.mdx",
|
||||
"pathname": "/architectural-modules/event/create"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/event/local/page.mdx",
|
||||
"pathname": "/architectural-modules/event/local"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/event/page.mdx",
|
||||
"pathname": "/architectural-modules/event"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/event/redis/page.mdx",
|
||||
"pathname": "/architectural-modules/event/redis"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/file/local/page.mdx",
|
||||
"pathname": "/architectural-modules/file/local"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/file/page.mdx",
|
||||
"pathname": "/architectural-modules/file"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/app/architectural-modules/page.mdx",
|
||||
"pathname": "/architectural-modules"
|
||||
@@ -2004,12 +2028,8 @@ export const filesMap = [
|
||||
"pathname": "/references/customer_models/classes/customer_models.CustomerGroupCustomer"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/references/file/classes/file.AbstractFileService/page.mdx",
|
||||
"pathname": "/references/file/classes/file.AbstractFileService"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/references/file/interfaces/file.IFileService/page.mdx",
|
||||
"pathname": "/references/file/interfaces/file.IFileService"
|
||||
"filePath": "/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx",
|
||||
"pathname": "/references/file/classes/file.AbstractFileProviderService"
|
||||
},
|
||||
{
|
||||
"filePath": "/www/apps/resources/references/fulfillment/IFulfillmentModuleService/methods/fulfillment.IFulfillmentModuleService.cancelFulfillment/page.mdx",
|
||||
|
||||
@@ -6804,6 +6804,7 @@ export const generatedSidebar = [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/architectural-modules/cache",
|
||||
"title": "Cache Modules",
|
||||
"hasTitleStyling": true,
|
||||
"children": [
|
||||
@@ -6820,12 +6821,27 @@ export const generatedSidebar = [
|
||||
"path": "/architectural-modules/cache/redis",
|
||||
"title": "Redis",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"title": "Guides",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/architectural-modules/cache/create",
|
||||
"title": "Create Cache Module",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/architectural-modules/event",
|
||||
"title": "Event Modules",
|
||||
"hasTitleStyling": true,
|
||||
"children": [
|
||||
@@ -6842,6 +6858,50 @@ export const generatedSidebar = [
|
||||
"path": "/architectural-modules/event/redis",
|
||||
"title": "Redis",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"title": "Guides",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/architectural-modules/event/create",
|
||||
"title": "Create Event Module",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/architectural-modules/file",
|
||||
"title": "File Provider Modules",
|
||||
"hasTitleStyling": true,
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/architectural-modules/file/local",
|
||||
"title": "Local",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"title": "Guides",
|
||||
"children": [
|
||||
{
|
||||
"loaded": true,
|
||||
"isPathHref": true,
|
||||
"path": "/references/file-provider-module",
|
||||
"title": "Create File Module",
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -570,9 +570,9 @@ export const slugChanges = [
|
||||
"filePath": "/www/apps/resources/references/customer_models/classes/customer_models.CustomerGroupCustomer/page.mdx"
|
||||
},
|
||||
{
|
||||
"origSlug": "/references/file/classes/file.AbstractFileService",
|
||||
"newSlug": "/references/file-service",
|
||||
"filePath": "/www/apps/resources/references/file/classes/file.AbstractFileService/page.mdx"
|
||||
"origSlug": "/references/file/classes/file.AbstractFileProviderService",
|
||||
"newSlug": "/references/file-provider-module",
|
||||
"filePath": "/www/apps/resources/references/file/classes/file.AbstractFileProviderService/page.mdx"
|
||||
},
|
||||
{
|
||||
"origSlug": "/references/fulfillment/IFulfillmentModuleService/methods/fulfillment.IFulfillmentModuleService.cancelFulfillment",
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
slug: /references/file-provider-module
|
||||
---
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a File Provider Module
|
||||
|
||||
In this document, you’ll learn how to create a file provider module and the methods you must implement in it.
|
||||
|
||||
---
|
||||
|
||||
## 1. Create Module Directory
|
||||
|
||||
Start by creating a new directory for your module. For example, `src/modules/my-file`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Create the File Provider Service
|
||||
|
||||
Create the file `src/modules/my-file/service.ts` that holds the implementation of the file service.
|
||||
|
||||
The File Provider Module's main service must extend the `AbstractFileProviderService` class imported from `@medusajs/utils`:
|
||||
|
||||
```ts title="src/modules/my-file/service.ts"
|
||||
import { AbstractFileProviderService } from "@medusajs/utils"
|
||||
|
||||
class MyFileProviderService extends AbstractFileProviderService {
|
||||
// TODO implement methods
|
||||
}
|
||||
|
||||
export default MyFileProviderService
|
||||
```
|
||||
|
||||
### constructor
|
||||
|
||||
### getIdentifier
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"any","type":"`any`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]} sectionTitle="getIdentifier"/>
|
||||
|
||||
### upload
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"file","type":"`ProviderUploadFileDTO`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="upload"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<ProviderFileResultDTO>","optional":false,"defaultValue":"","description":"","expandable":false,"children":[{"name":"ProviderFileResultDTO","type":"`ProviderFileResultDTO`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="upload"/>
|
||||
|
||||
### delete
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"file","type":"`ProviderDeleteFileDTO`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="delete"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]} sectionTitle="delete"/>
|
||||
|
||||
### getPresignedDownloadUrl
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"`ProviderGetFileDTO`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="getPresignedDownloadUrl"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<string>","optional":false,"defaultValue":"","description":"","expandable":false,"children":[{"name":"string","type":"`string`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="getPresignedDownloadUrl"/>
|
||||
|
||||
---
|
||||
|
||||
## 3. Create Module Definition File
|
||||
|
||||
Create the file `src/modules/my-file/index.ts` with the following content:
|
||||
|
||||
```ts title="src/modules/my-file/index.ts"
|
||||
import MyFileProviderService from "./service"
|
||||
|
||||
export default {
|
||||
service: MyFileProviderService,
|
||||
}
|
||||
```
|
||||
|
||||
This exports the module's definition, indicating that the `MyFileProviderService` is the main service of the module.
|
||||
|
||||
---
|
||||
|
||||
## 4. Use Module
|
||||
|
||||
To use your File Provider Module, add it to the `providers` array of the File Module:
|
||||
|
||||
<Note>
|
||||
|
||||
The File Module accepts one provider only.
|
||||
|
||||
</Note>
|
||||
|
||||
```js title="medusa-config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
modules: {
|
||||
// ...
|
||||
[Modules.FILE]: {
|
||||
resolve: "@medusajs/file",
|
||||
options: {
|
||||
providers: [
|
||||
{
|
||||
resolve: "./dist/modules/my-file",
|
||||
options: {
|
||||
config: {
|
||||
"my-file": {
|
||||
// provider options...
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
@@ -1,379 +0,0 @@
|
||||
---
|
||||
slug: /references/file-service
|
||||
---
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# How to Create a File Service
|
||||
|
||||
In this document, you’ll learn how to create a file service in the Medusa backend and the methods you must implement in it.
|
||||
|
||||
## Overview
|
||||
|
||||
A file service class is defined in a TypeScript or JavaScript file that’s created in the `src/services` directory.
|
||||
The class must extend the `AbstractFileService` class imported from the `@medusajs/medusa` package.
|
||||
|
||||
Based on services’ naming conventions, the file’s name should be the slug version of the file service’s name
|
||||
without `service`, and the class’s name should be the pascal case of the file service’s name following by `Service`.
|
||||
|
||||
For example, create the file `src/services/local-file.ts` with the following content:
|
||||
|
||||
```ts title="src/services/local-file.ts"
|
||||
import { AbstractFileService } from "@medusajs/medusa"
|
||||
import {
|
||||
DeleteFileType,
|
||||
FileServiceGetUploadStreamResult,
|
||||
FileServiceUploadResult,
|
||||
GetUploadedFileType,
|
||||
UploadStreamDescriptorType,
|
||||
} from "@medusajs/types"
|
||||
|
||||
class LocalFileService extends AbstractFileService {
|
||||
async upload(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async uploadProtected(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async delete(fileData: DeleteFileType): Promise<void> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async getUploadStreamDescriptor(
|
||||
fileData: UploadStreamDescriptorType
|
||||
): Promise<FileServiceGetUploadStreamResult> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async getDownloadStream(
|
||||
fileData: GetUploadedFileType
|
||||
): Promise<NodeJS.ReadableStream> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async getPresignedDownloadUrl(
|
||||
fileData: GetUploadedFileType
|
||||
): Promise<string> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
export default LocalFileService
|
||||
```
|
||||
|
||||
:::note[Multer Typing]
|
||||
|
||||
The examples implement a file service supporting local uploads.
|
||||
|
||||
If you’re using TypeScript and you're following along with the implementation,
|
||||
you should install the Multer types package in the root of your Medusa backend to resolve errors within your file service types:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @types/multer
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## constructor
|
||||
|
||||
You can use the `constructor` of your file service to access the different services in Medusa through dependency injection.
|
||||
|
||||
You can also use the constructor to initialize your integration with the third-party provider. For example, if you use a client to connect to the third-party provider’s APIs,
|
||||
you can initialize it in the constructor and use it in other methods in the service.
|
||||
|
||||
Additionally, if you’re creating your file service as an external plugin to be installed on any Medusa backend and you want to access the options added for the plugin,
|
||||
you can access them in the constructor.
|
||||
|
||||
### Example
|
||||
|
||||
```ts
|
||||
// ...
|
||||
import { Logger } from "@medusajs/medusa"
|
||||
import * as fs from "fs"
|
||||
|
||||
class LocalFileService extends AbstractFileService {
|
||||
// can also be replaced by an environment variable
|
||||
// or a plugin option
|
||||
protected serverUrl = "http://localhost:9000"
|
||||
protected publicPath = "uploads"
|
||||
protected protectedPath = "protected-uploads"
|
||||
protected logger_: Logger
|
||||
|
||||
constructor({ logger }: InjectedDependencies) {
|
||||
// @ts-ignore
|
||||
super(...arguments)
|
||||
this.logger_ = logger
|
||||
|
||||
// for public uploads
|
||||
if (!fs.existsSync(this.publicPath)) {
|
||||
fs.mkdirSync(this.publicPath)
|
||||
}
|
||||
|
||||
// for protected uploads
|
||||
if (!fs.existsSync(this.protectedPath)) {
|
||||
fs.mkdirSync(this.protectedPath)
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
<TypeList types={[{"name":"container","type":"`Record<string, unknown>`","description":"An instance of `MedusaContainer` that allows you to access other resources, such as services, in your Medusa backend.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"config","type":"`Record<string, unknown>`","description":"If this file service is created in a plugin, the plugin's options are passed in this parameter.","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="new AbstractFileService"/>
|
||||
|
||||
___
|
||||
|
||||
## Methods
|
||||
|
||||
### upload
|
||||
|
||||
This method is used to upload a file to the Medusa backend.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
// ...
|
||||
async upload(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
const filePath =
|
||||
`${this.publicPath}/${fileData.originalname}`
|
||||
fs.copyFileSync(fileData.path, filePath)
|
||||
return {
|
||||
url: `${this.serverUrl}/${filePath}`,
|
||||
key: filePath,
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
This example does not account for duplicate names to maintain simplicity in this guide. So, an uploaded file can replace another existing file that has the same name.
|
||||
|
||||
:::
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"`File`","description":"A [multer file object](http://expressjs.com/en/resources/middleware/multer.html#file-information).\nThe file is uploaded to a temporary directory by default. Among the file’s details, you can access the file’s path in the `path` property of the file object.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="upload"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)>","optional":false,"defaultValue":"","description":"The details of the upload's result.","expandable":false,"children":[{"name":"FileServiceUploadResult","type":"[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)","optional":false,"defaultValue":"","description":"Details of a file upload's result.","expandable":false,"children":[{"name":"url","type":"`string`","description":"The file's URL.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"key","type":"`string`","description":"The file's key. This key is used in other operations,\nsuch as deleting a file.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="upload"/>
|
||||
|
||||
### uploadProtected
|
||||
|
||||
This method is used to upload a file to the Medusa backend, but to a protected storage. Typically, this would be used to store files that
|
||||
shouldn’t be accessible by using the file’s URL or should only be accessible by authenticated users. For example, exported or imported
|
||||
CSV files.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
// ...
|
||||
async uploadProtected(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
const filePath =
|
||||
`${this.protectedPath}/${fileData.originalname}`
|
||||
fs.copyFileSync(fileData.path, filePath)
|
||||
return {
|
||||
url: `${this.serverUrl}/${filePath}`,
|
||||
key: filePath
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
This example does not account for duplicate names to maintain simplicity in this guide. So, an uploaded file can replace another existing file that has the same name.
|
||||
|
||||
:::
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"`File`","description":"A [multer file object](http://expressjs.com/en/resources/middleware/multer.html#file-information).\nThe file is uploaded to a temporary directory by default. Among the file’s details, you can access the file’s path in the `path` property of the file object.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="uploadProtected"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)>","optional":false,"defaultValue":"","description":"The details of the upload's result.","expandable":false,"children":[{"name":"FileServiceUploadResult","type":"[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)","optional":false,"defaultValue":"","description":"Details of a file upload's result.","expandable":false,"children":[{"name":"url","type":"`string`","description":"The file's URL.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"key","type":"`string`","description":"The file's key. This key is used in other operations,\nsuch as deleting a file.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="uploadProtected"/>
|
||||
|
||||
### delete
|
||||
|
||||
This method is used to delete a file from storage.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
|
||||
async delete(
|
||||
fileData: DeleteFileType
|
||||
): Promise<void> {
|
||||
fs.rmSync(fileData.fileKey)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[DeleteFileType](../../../types/interfaces/types.DeleteFileType/page.mdx)","description":"The details of the file to remove.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key. When uploading a file, the\nreturned key is used here.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="delete"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"Resolves when the file is deleted successfully.","expandable":false,"children":[]}]} sectionTitle="delete"/>
|
||||
|
||||
### getUploadStreamDescriptor
|
||||
|
||||
This method is used to retrieve a write stream to be used to upload a file.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
// ...
|
||||
import { Stream } from "stream"
|
||||
|
||||
class LocalFileService extends AbstractFileService {
|
||||
// ...
|
||||
async getUploadStreamDescriptor({
|
||||
name,
|
||||
ext,
|
||||
isPrivate = true,
|
||||
}: UploadStreamDescriptorType
|
||||
): Promise<FileServiceGetUploadStreamResult> {
|
||||
const filePath = `${isPrivate ?
|
||||
this.publicPath : this.protectedPath
|
||||
}/${name}.${ext}`
|
||||
|
||||
const pass = new Stream.PassThrough()
|
||||
const writeStream = fs.createWriteStream(filePath)
|
||||
|
||||
pass.pipe(writeStream)
|
||||
|
||||
return {
|
||||
writeStream: pass,
|
||||
promise: Promise.resolve(),
|
||||
url: `${this.serverUrl}/${filePath}`,
|
||||
fileKey: filePath,
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[UploadStreamDescriptorType](../../../types/interfaces/types.UploadStreamDescriptorType/page.mdx)","description":"The details of the file being uploaded.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"name","type":"`string`","description":"The name of the file.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"ext","type":"`string`","description":"The extension of the file.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isPrivate","type":"`boolean`","description":"Whether the file should be uploaded to a private bucket or location. By convention, the default value of this property is `true`.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="getUploadStreamDescriptor"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<[FileServiceGetUploadStreamResult](../../../types/interfaces/types.FileServiceGetUploadStreamResult/page.mdx)>","optional":false,"defaultValue":"","description":"The result of the file-stream upload.","expandable":false,"children":[{"name":"FileServiceGetUploadStreamResult","type":"[FileServiceGetUploadStreamResult](../../../types/interfaces/types.FileServiceGetUploadStreamResult/page.mdx)","optional":false,"defaultValue":"","description":"The relevant details to upload a file through a stream.","expandable":false,"children":[{"name":"writeStream","type":"`PassThrough`","description":"A [PassThrough](https://nodejs.org/api/stream.html#class-streampassthrough) write stream object to be used to write the file.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"promise","type":"Promise<any>","description":"A promise that should resolved when the writing process is done to finish the upload.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"url","type":"`string`","description":"The URL of the file once it’s uploaded.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"fileKey","type":"`string`","description":"The identifier of the file in the storage. For example, for a local file service, this can be the file's name.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="getUploadStreamDescriptor"/>
|
||||
|
||||
### getDownloadStream
|
||||
|
||||
This method is used to retrieve a read stream for a file, which can then be used to download the file.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
|
||||
async getDownloadStream({
|
||||
fileKey,
|
||||
isPrivate = true,
|
||||
}: GetUploadedFileType
|
||||
): Promise<NodeJS.ReadableStream> {
|
||||
const filePath = `${isPrivate ?
|
||||
this.publicPath : this.protectedPath
|
||||
}/${fileKey}`
|
||||
const readStream = fs.createReadStream(filePath)
|
||||
|
||||
return readStream
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[GetUploadedFileType](../../../types/interfaces/types.GetUploadedFileType/page.mdx)","description":"The details of the file.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"isPrivate","type":"`boolean`","description":"Whether the file is private.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="getDownloadStream"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<ReadableStream>","optional":false,"defaultValue":"","description":"The [read stream](https://nodejs.org/api/webstreams.html#class-readablestream) to read and download the file.","expandable":false,"children":[{"name":"ReadableStream","type":"`ReadableStream`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="getDownloadStream"/>
|
||||
|
||||
### getPresignedDownloadUrl
|
||||
|
||||
This method is used to retrieve a download URL of the file. For some file services, such as S3, a presigned URL indicates a temporary URL to get access to a file.
|
||||
|
||||
If your file service doesn’t perform or offer a similar functionality, you can just return the URL to download the file.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
|
||||
async getPresignedDownloadUrl({
|
||||
fileKey,
|
||||
isPrivate = true,
|
||||
}: GetUploadedFileType
|
||||
): Promise<string> {
|
||||
// Local upload doesn't provide
|
||||
// support for presigned URLs,
|
||||
// so just return the file's URL.
|
||||
|
||||
const filePath = `${isPrivate ?
|
||||
this.publicPath : this.protectedPath
|
||||
}/${fileKey}`
|
||||
return `${this.serverUrl}/${filePath}`
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[GetUploadedFileType](../../../types/interfaces/types.GetUploadedFileType/page.mdx)","description":"The details of the file.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"isPrivate","type":"`boolean`","description":"Whether the file is private.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="getPresignedDownloadUrl"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<string>","optional":false,"defaultValue":"","description":"The presigned URL to download the file","expandable":false,"children":[{"name":"string","type":"`string`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="getPresignedDownloadUrl"/>
|
||||
|
||||
---
|
||||
|
||||
## Test Implementation
|
||||
|
||||
:::note
|
||||
|
||||
If you created your file service in a plugin, refer to [this guide on how to test plugins](https://docs.medusajs.com/development/plugins/create#test-your-plugin).
|
||||
|
||||
:::
|
||||
|
||||
After finishing your file service implementation:
|
||||
|
||||
1\. Run the `build` command in the root of your Medusa backend:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
```
|
||||
|
||||
2\. Start the backend with the `develop` command:
|
||||
|
||||
```bash
|
||||
npx medusa develop
|
||||
```
|
||||
|
||||
3\. Upload a file using the [Admin REST APIs](https://docs.medusajs.com/api/admin#uploads_postuploads) or using the Medusa admin, for example, to [upload a product's thumbnail](https://docs.medusajs.com/user-guide/products/manage#manage-thumbnails).
|
||||
@@ -1,355 +0,0 @@
|
||||
---
|
||||
displayed_sidebar: core
|
||||
---
|
||||
|
||||
import { TypeList } from "docs-ui"
|
||||
|
||||
# IFileService
|
||||
|
||||
## Overview
|
||||
|
||||
A file service class is defined in a TypeScript or JavaScript file that’s created in the `src/services` directory.
|
||||
The class must extend the `AbstractFileService` class imported from the `@medusajs/medusa` package.
|
||||
|
||||
Based on services’ naming conventions, the file’s name should be the slug version of the file service’s name
|
||||
without `service`, and the class’s name should be the pascal case of the file service’s name following by `Service`.
|
||||
|
||||
For example, create the file `src/services/local-file.ts` with the following content:
|
||||
|
||||
```ts title="src/services/local-file.ts"
|
||||
import { AbstractFileService } from "@medusajs/medusa"
|
||||
import {
|
||||
DeleteFileType,
|
||||
FileServiceGetUploadStreamResult,
|
||||
FileServiceUploadResult,
|
||||
GetUploadedFileType,
|
||||
UploadStreamDescriptorType,
|
||||
} from "@medusajs/types"
|
||||
|
||||
class LocalFileService extends AbstractFileService {
|
||||
async upload(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async uploadProtected(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async delete(fileData: DeleteFileType): Promise<void> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async getUploadStreamDescriptor(
|
||||
fileData: UploadStreamDescriptorType
|
||||
): Promise<FileServiceGetUploadStreamResult> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async getDownloadStream(
|
||||
fileData: GetUploadedFileType
|
||||
): Promise<NodeJS.ReadableStream> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
async getPresignedDownloadUrl(
|
||||
fileData: GetUploadedFileType
|
||||
): Promise<string> {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
export default LocalFileService
|
||||
```
|
||||
|
||||
:::note[Multer Typing]
|
||||
|
||||
The examples implement a file service supporting local uploads.
|
||||
|
||||
If you’re using TypeScript and you're following along with the implementation,
|
||||
you should install the Multer types package in the root of your Medusa backend to resolve errors within your file service types:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @types/multer
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Properties
|
||||
|
||||
<TypeList types={[{"name":"manager_","type":"`EntityManager`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"transactionManager_","type":"`undefined` \\| `EntityManager`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"__container__","type":"`any`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"__configModule__","type":"`Record<string, unknown>`","description":"","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"__moduleDeclaration__","type":"`Record<string, unknown>`","description":"","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="IFileService"/>
|
||||
|
||||
___
|
||||
|
||||
## Accessors
|
||||
|
||||
### activeManager\_
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"EntityManager","type":"`EntityManager`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]} sectionTitle="activeManager_"/>
|
||||
|
||||
___
|
||||
|
||||
## Methods
|
||||
|
||||
### upload
|
||||
|
||||
This method is used to upload a file to the Medusa backend.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
// ...
|
||||
async upload(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
const filePath =
|
||||
`${this.publicPath}/${fileData.originalname}`
|
||||
fs.copyFileSync(fileData.path, filePath)
|
||||
return {
|
||||
url: `${this.serverUrl}/${filePath}`,
|
||||
key: filePath,
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
This example does not account for duplicate names to maintain simplicity in this guide. So, an uploaded file can replace another existing file that has the same name.
|
||||
|
||||
:::
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"file","type":"`File`","description":"A [multer file object](http://expressjs.com/en/resources/middleware/multer.html#file-information).\nThe file is uploaded to a temporary directory by default. Among the file’s details, you can access the file’s path in the `path` property of the file object.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="upload"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)>","optional":false,"defaultValue":"","description":"The details of the upload's result.","expandable":false,"children":[{"name":"FileServiceUploadResult","type":"[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)","optional":false,"defaultValue":"","description":"Details of a file upload's result.","expandable":false,"children":[{"name":"url","type":"`string`","description":"The file's URL.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"key","type":"`string`","description":"The file's key. This key is used in other operations,\nsuch as deleting a file.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="upload"/>
|
||||
|
||||
### uploadProtected
|
||||
|
||||
This method is used to upload a file to the Medusa backend, but to a protected storage. Typically, this would be used to store files that
|
||||
shouldn’t be accessible by using the file’s URL or should only be accessible by authenticated users. For example, exported or imported
|
||||
CSV files.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
// ...
|
||||
async uploadProtected(
|
||||
fileData: Express.Multer.File
|
||||
): Promise<FileServiceUploadResult> {
|
||||
const filePath =
|
||||
`${this.protectedPath}/${fileData.originalname}`
|
||||
fs.copyFileSync(fileData.path, filePath)
|
||||
return {
|
||||
url: `${this.serverUrl}/${filePath}`,
|
||||
key: filePath
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
This example does not account for duplicate names to maintain simplicity in this guide. So, an uploaded file can replace another existing file that has the same name.
|
||||
|
||||
:::
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"file","type":"`File`","description":"A [multer file object](http://expressjs.com/en/resources/middleware/multer.html#file-information).\nThe file is uploaded to a temporary directory by default. Among the file’s details, you can access the file’s path in the `path` property of the file object.","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="uploadProtected"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)>","optional":false,"defaultValue":"","description":"The details of the upload's result.","expandable":false,"children":[{"name":"FileServiceUploadResult","type":"[FileServiceUploadResult](../../../medusa/interfaces/medusa.FileServiceUploadResult/page.mdx)","optional":false,"defaultValue":"","description":"Details of a file upload's result.","expandable":false,"children":[{"name":"url","type":"`string`","description":"The file's URL.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"key","type":"`string`","description":"The file's key. This key is used in other operations,\nsuch as deleting a file.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="uploadProtected"/>
|
||||
|
||||
### delete
|
||||
|
||||
This method is used to delete a file from storage.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
|
||||
async delete(
|
||||
fileData: DeleteFileType
|
||||
): Promise<void> {
|
||||
fs.rmSync(fileData.fileKey)
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[DeleteFileType](../../../types/interfaces/types.DeleteFileType/page.mdx)","description":"The details of the file to remove.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key. When uploading a file, the\nreturned key is used here.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="delete"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<void>","optional":false,"defaultValue":"","description":"Resolves when the file is deleted successfully.","expandable":false,"children":[]}]} sectionTitle="delete"/>
|
||||
|
||||
### getUploadStreamDescriptor
|
||||
|
||||
This method is used to retrieve a write stream to be used to upload a file.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
// ...
|
||||
import { Stream } from "stream"
|
||||
|
||||
class LocalFileService extends AbstractFileService {
|
||||
// ...
|
||||
async getUploadStreamDescriptor({
|
||||
name,
|
||||
ext,
|
||||
isPrivate = true,
|
||||
}: UploadStreamDescriptorType
|
||||
): Promise<FileServiceGetUploadStreamResult> {
|
||||
const filePath = `${isPrivate ?
|
||||
this.publicPath : this.protectedPath
|
||||
}/${name}.${ext}`
|
||||
|
||||
const pass = new Stream.PassThrough()
|
||||
const writeStream = fs.createWriteStream(filePath)
|
||||
|
||||
pass.pipe(writeStream)
|
||||
|
||||
return {
|
||||
writeStream: pass,
|
||||
promise: Promise.resolve(),
|
||||
url: `${this.serverUrl}/${filePath}`,
|
||||
fileKey: filePath,
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[UploadStreamDescriptorType](../../../types/interfaces/types.UploadStreamDescriptorType/page.mdx)","description":"The details of the file being uploaded.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"name","type":"`string`","description":"The name of the file.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"ext","type":"`string`","description":"The extension of the file.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"isPrivate","type":"`boolean`","description":"Whether the file should be uploaded to a private bucket or location. By convention, the default value of this property is `true`.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="getUploadStreamDescriptor"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<[FileServiceGetUploadStreamResult](../../../types/interfaces/types.FileServiceGetUploadStreamResult/page.mdx)>","optional":false,"defaultValue":"","description":"The result of the file-stream upload.","expandable":false,"children":[{"name":"FileServiceGetUploadStreamResult","type":"[FileServiceGetUploadStreamResult](../../../types/interfaces/types.FileServiceGetUploadStreamResult/page.mdx)","optional":false,"defaultValue":"","description":"The relevant details to upload a file through a stream.","expandable":false,"children":[{"name":"writeStream","type":"`PassThrough`","description":"A [PassThrough](https://nodejs.org/api/stream.html#class-streampassthrough) write stream object to be used to write the file.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"promise","type":"Promise<any>","description":"A promise that should resolved when the writing process is done to finish the upload.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"url","type":"`string`","description":"The URL of the file once it’s uploaded.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"fileKey","type":"`string`","description":"The identifier of the file in the storage. For example, for a local file service, this can be the file's name.","optional":false,"defaultValue":"","expandable":false,"children":[]}]}]}]} sectionTitle="getUploadStreamDescriptor"/>
|
||||
|
||||
### getDownloadStream
|
||||
|
||||
This method is used to retrieve a read stream for a file, which can then be used to download the file.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
|
||||
async getDownloadStream({
|
||||
fileKey,
|
||||
isPrivate = true,
|
||||
}: GetUploadedFileType
|
||||
): Promise<NodeJS.ReadableStream> {
|
||||
const filePath = `${isPrivate ?
|
||||
this.publicPath : this.protectedPath
|
||||
}/${fileKey}`
|
||||
const readStream = fs.createReadStream(filePath)
|
||||
|
||||
return readStream
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[GetUploadedFileType](../../../types/interfaces/types.GetUploadedFileType/page.mdx)","description":"The details of the file.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"isPrivate","type":"`boolean`","description":"Whether the file is private.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="getDownloadStream"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<ReadableStream>","optional":false,"defaultValue":"","description":"The [read stream](https://nodejs.org/api/webstreams.html#class-readablestream) to read and download the file.","expandable":false,"children":[{"name":"ReadableStream","type":"`ReadableStream`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="getDownloadStream"/>
|
||||
|
||||
### getPresignedDownloadUrl
|
||||
|
||||
This method is used to retrieve a download URL of the file. For some file services, such as S3, a presigned URL indicates a temporary URL to get access to a file.
|
||||
|
||||
If your file service doesn’t perform or offer a similar functionality, you can just return the URL to download the file.
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
class LocalFileService extends AbstractFileService {
|
||||
|
||||
async getPresignedDownloadUrl({
|
||||
fileKey,
|
||||
isPrivate = true,
|
||||
}: GetUploadedFileType
|
||||
): Promise<string> {
|
||||
// Local upload doesn't provide
|
||||
// support for presigned URLs,
|
||||
// so just return the file's URL.
|
||||
|
||||
const filePath = `${isPrivate ?
|
||||
this.publicPath : this.protectedPath
|
||||
}/${fileKey}`
|
||||
return `${this.serverUrl}/${filePath}`
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"fileData","type":"[GetUploadedFileType](../../../types/interfaces/types.GetUploadedFileType/page.mdx)","description":"The details of the file.","optional":false,"defaultValue":"","expandable":false,"children":[{"name":"fileKey","type":"`string`","description":"The file's key.","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"isPrivate","type":"`boolean`","description":"Whether the file is private.","optional":true,"defaultValue":"","expandable":false,"children":[]}]}]} sectionTitle="getPresignedDownloadUrl"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<string>","optional":false,"defaultValue":"","description":"The presigned URL to download the file","expandable":false,"children":[{"name":"string","type":"`string`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="getPresignedDownloadUrl"/>
|
||||
|
||||
### withTransaction
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"transactionManager","type":"`EntityManager`","description":"","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="withTransaction"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"this","type":"`this`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]} sectionTitle="withTransaction"/>
|
||||
|
||||
### shouldRetryTransaction\_
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"err","type":"`Record<string, unknown>` \\| `object`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="shouldRetryTransaction_"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"boolean","type":"`boolean`","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]} sectionTitle="shouldRetryTransaction_"/>
|
||||
|
||||
### atomicPhase\_
|
||||
|
||||
Wraps some work within a transactional block. If the service already has
|
||||
a transaction manager attached this will be reused, otherwise a new
|
||||
transaction manager is created.
|
||||
|
||||
#### Type Parameters
|
||||
|
||||
<TypeList types={[{"name":"TResult","type":"`object`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"TError","type":"`object`","description":"","optional":false,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="atomicPhase_"/>
|
||||
|
||||
#### Parameters
|
||||
|
||||
<TypeList types={[{"name":"work","type":"(`transactionManager`: `EntityManager`) => Promise<TResult>","description":"the transactional work to be done","optional":false,"defaultValue":"","expandable":false,"children":[]},{"name":"isolationOrErrorHandler","type":"`IsolationLevel` \\| (`error`: TError) => Promise<void \\| TResult>","description":"the isolation level to be used for the work.","optional":true,"defaultValue":"","expandable":false,"children":[]},{"name":"maybeErrorHandlerOrDontFail","type":"(`error`: TError) => Promise<void \\| TResult>","description":"Potential error handler","optional":true,"defaultValue":"","expandable":false,"children":[]}]} sectionTitle="atomicPhase_"/>
|
||||
|
||||
#### Returns
|
||||
|
||||
<TypeList types={[{"name":"Promise","type":"Promise<TResult>","optional":false,"defaultValue":"","description":"the result of the transactional work","expandable":false,"children":[{"name":"TResult","type":"TResult","optional":false,"defaultValue":"","description":"","expandable":false,"children":[]}]}]} sectionTitle="atomicPhase_"/>
|
||||
@@ -4,8 +4,4 @@ import { TypeList } from "docs-ui"
|
||||
|
||||
## Classes
|
||||
|
||||
- [AbstractFileService](../../file/classes/file.AbstractFileService/page.mdx)
|
||||
|
||||
## Interfaces
|
||||
|
||||
- [IFileService](../../file/interfaces/file.IFileService/page.mdx)
|
||||
- [AbstractFileProviderService](../../file/classes/file.AbstractFileProviderService/page.mdx)
|
||||
|
||||
@@ -1592,6 +1592,7 @@ export const sidebar = sidebarAttachHrefCommonOptions([
|
||||
hasTitleStyling: true,
|
||||
children: [
|
||||
{
|
||||
path: "/architectural-modules/cache",
|
||||
title: "Cache Modules",
|
||||
hasTitleStyling: true,
|
||||
children: [
|
||||
@@ -1603,9 +1604,19 @@ export const sidebar = sidebarAttachHrefCommonOptions([
|
||||
path: "/architectural-modules/cache/redis",
|
||||
title: "Redis",
|
||||
},
|
||||
{
|
||||
title: "Guides",
|
||||
children: [
|
||||
{
|
||||
path: "/architectural-modules/cache/create",
|
||||
title: "Create Cache Module",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/architectural-modules/event",
|
||||
title: "Event Modules",
|
||||
hasTitleStyling: true,
|
||||
children: [
|
||||
@@ -1617,6 +1628,35 @@ export const sidebar = sidebarAttachHrefCommonOptions([
|
||||
path: "/architectural-modules/event/redis",
|
||||
title: "Redis",
|
||||
},
|
||||
{
|
||||
title: "Guides",
|
||||
children: [
|
||||
{
|
||||
path: "/architectural-modules/event/create",
|
||||
title: "Create Event Module",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/architectural-modules/file",
|
||||
title: "File Provider Modules",
|
||||
hasTitleStyling: true,
|
||||
children: [
|
||||
{
|
||||
path: "/architectural-modules/file/local",
|
||||
title: "Local",
|
||||
},
|
||||
{
|
||||
title: "Guides",
|
||||
children: [
|
||||
{
|
||||
path: "/references/file-provider-module",
|
||||
title: "Create File Module",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,15 +1,59 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import React, { useMemo } from "react"
|
||||
import { Card, CardList, MDXComponents, useSidebar } from "../.."
|
||||
import { SidebarItemType } from "types"
|
||||
|
||||
type ChildDocsProps = {
|
||||
onlyTopLevel?: boolean
|
||||
type?: "sidebar" | "item"
|
||||
filters?: string[]
|
||||
}
|
||||
|
||||
export const ChildDocs = ({ onlyTopLevel = false }: ChildDocsProps) => {
|
||||
const { currentItems } = useSidebar()
|
||||
export const ChildDocs = ({
|
||||
onlyTopLevel = false,
|
||||
filters = [],
|
||||
type = "sidebar",
|
||||
}: ChildDocsProps) => {
|
||||
const { currentItems, getActiveItem } = useSidebar()
|
||||
|
||||
const filterItems = (items: SidebarItemType[]): SidebarItemType[] => {
|
||||
return items
|
||||
.filter(
|
||||
(item) =>
|
||||
(!item.path || !filters.includes(item.path)) &&
|
||||
!filters.includes(item.title)
|
||||
)
|
||||
.map((item) => Object.assign({}, item))
|
||||
.map((item) => {
|
||||
if (item.children) {
|
||||
item.children = filterItems(item.children)
|
||||
}
|
||||
|
||||
return item
|
||||
})
|
||||
}
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
const targetItems =
|
||||
type === "sidebar"
|
||||
? currentItems
|
||||
? Object.assign({}, currentItems)
|
||||
: undefined
|
||||
: {
|
||||
top: [...(getActiveItem()?.children || [])],
|
||||
bottom: [],
|
||||
}
|
||||
if (!filters.length || !targetItems) {
|
||||
return targetItems
|
||||
}
|
||||
|
||||
return {
|
||||
...targetItems,
|
||||
top: filterItems(targetItems.top),
|
||||
bottom: filterItems(targetItems.bottom),
|
||||
}
|
||||
}, [currentItems, type, getActiveItem])
|
||||
|
||||
const getTopLevelElms = (items?: SidebarItemType[]) => (
|
||||
<CardList
|
||||
@@ -58,8 +102,8 @@ export const ChildDocs = ({ onlyTopLevel = false }: ChildDocsProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{getElms(currentItems?.top)}
|
||||
{getElms(currentItems?.bottom)}
|
||||
{getElms(filteredItems?.top)}
|
||||
{getElms(filteredItems?.bottom)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,8 +16,8 @@ const customOptions: Record<string, Partial<TypeDocOptions>> = {
|
||||
name: "entities",
|
||||
}),
|
||||
file: getOptions({
|
||||
entryPointPath: "packages/medusa/src/interfaces/file-service.ts",
|
||||
tsConfigName: "medusa.json",
|
||||
entryPointPath: "packages/core/utils/src/file/abstract-file-provider.ts",
|
||||
tsConfigName: "utils.json",
|
||||
name: "file",
|
||||
parentIgnore: true,
|
||||
}),
|
||||
|
||||
+68
-21
@@ -6,42 +6,89 @@ const fileOptions: FormattingOptionsType = {
|
||||
displayed_sidebar: "core",
|
||||
},
|
||||
},
|
||||
"^file/.*AbstractFileService": {
|
||||
"^file/.*AbstractFileProviderService": {
|
||||
reflectionGroups: {
|
||||
Properties: false,
|
||||
},
|
||||
reflectionDescription: `In this document, you’ll learn how to create a file service in the Medusa backend and the methods you must implement in it.`,
|
||||
reflectionDescription: `In this document, you’ll learn how to create a file provider module and the methods you must implement in it.`,
|
||||
frontmatterData: {
|
||||
slug: "/references/file-service",
|
||||
slug: "/references/file-provider-module",
|
||||
},
|
||||
reflectionTitle: {
|
||||
fullReplacement: "How to Create a File Service",
|
||||
fullReplacement: "How to Create a File Provider Module",
|
||||
},
|
||||
shouldIncrementAfterStartSections: true,
|
||||
expandMembers: true,
|
||||
startSections: [
|
||||
`## 1. Create Module Directory
|
||||
|
||||
Start by creating a new directory for your module. For example, \`src/modules/my-file\`.`,
|
||||
`## 2. Create the File Provider Service
|
||||
|
||||
Create the file \`src/modules/my-file/service.ts\` that holds the implementation of the file service.
|
||||
|
||||
The File Provider Module's main service must extend the \`AbstractFileProviderService\` class imported from \`@medusajs/utils\`:
|
||||
|
||||
\`\`\`ts title="src/modules/my-file/service.ts"
|
||||
import { AbstractFileProviderService } from "@medusajs/utils"
|
||||
|
||||
class MyFileProviderService extends AbstractFileProviderService {
|
||||
// TODO implement methods
|
||||
}
|
||||
|
||||
export default MyFileProviderService
|
||||
\`\`\``,
|
||||
],
|
||||
endSections: [
|
||||
`## Test Implementation
|
||||
`## 3. Create Module Definition File
|
||||
|
||||
:::note
|
||||
Create the file \`src/modules/my-file/index.ts\` with the following content:
|
||||
|
||||
If you created your file service in a plugin, refer to [this guide on how to test plugins](https://docs.medusajs.com/development/plugins/create#test-your-plugin).
|
||||
\`\`\`ts title="src/modules/my-file/index.ts"
|
||||
import MyFileProviderService from "./service"
|
||||
|
||||
:::
|
||||
|
||||
After finishing your file service implementation:
|
||||
|
||||
1\\. Run the \`build\` command in the root of your Medusa backend:
|
||||
|
||||
\`\`\`bash npm2yarn
|
||||
npm run build
|
||||
export default {
|
||||
service: MyFileProviderService,
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
2\\. Start the backend with the \`develop\` command:
|
||||
This exports the module's definition, indicating that the \`MyFileProviderService\` is the main service of the module.`,
|
||||
`## 4. Use Module
|
||||
|
||||
\`\`\`bash
|
||||
npx medusa develop
|
||||
To use your File Provider Module, add it to the \`providers\` array of the File Module:
|
||||
|
||||
<Note>
|
||||
|
||||
The File Module accepts one provider only.
|
||||
|
||||
</Note>
|
||||
|
||||
\`\`\`js title="medusa-config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
modules: {
|
||||
// ...
|
||||
[Modules.FILE]: {
|
||||
resolve: "@medusajs/file",
|
||||
options: {
|
||||
providers: [
|
||||
{
|
||||
resolve: "./dist/modules/my-file",
|
||||
options: {
|
||||
config: {
|
||||
"my-file": {
|
||||
// provider options...
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
3\\. Upload a file using the [Admin REST APIs](https://docs.medusajs.com/api/admin#uploads_postuploads) or using the Medusa admin, for example, to [upload a product's thumbnail](https://docs.medusajs.com/user-guide/products/manage#manage-thumbnails).
|
||||
`,
|
||||
`,
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ import getDeclarationChildrenHelper from "./resources/helpers/get-declaration-ch
|
||||
import ifShowSeparatorForTitleLevelHelper from "./resources/helpers/if-show-separator-for-title-level"
|
||||
import shouldExpandPropertiesHelper from "./resources/helpers/should-expand-properties"
|
||||
import shouldExpandDeclarationChildrenHelper from "./resources/helpers/should-expand-declaration-children"
|
||||
import startSectionsHelper from "./resources/helpers/start-sections"
|
||||
import { MarkdownTheme } from "./theme"
|
||||
|
||||
const TEMPLATE_PATH = path.join(__dirname, "resources", "templates")
|
||||
@@ -154,4 +155,5 @@ export function registerHelpers(theme: MarkdownTheme) {
|
||||
ifShowSeparatorForTitleLevelHelper(theme)
|
||||
shouldExpandPropertiesHelper(theme)
|
||||
shouldExpandDeclarationChildrenHelper(theme)
|
||||
startSectionsHelper(theme)
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
import * as Handlebars from "handlebars"
|
||||
import { MarkdownTheme } from "../../theme"
|
||||
|
||||
export default function (theme: MarkdownTheme) {
|
||||
Handlebars.registerHelper("startSections", function () {
|
||||
const { startSections, shouldIncrementAfterStartSections } =
|
||||
theme.getFormattingOptionsForLocation()
|
||||
|
||||
if (!startSections?.length) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const lineBreaks = "\n\n"
|
||||
const separator = `---${lineBreaks}`
|
||||
|
||||
if (shouldIncrementAfterStartSections) {
|
||||
Handlebars.helpers.incrementCurrentTitleLevel()
|
||||
}
|
||||
|
||||
return `${separator}${startSections.join(`${lineBreaks}${separator}`)}`
|
||||
})
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
{{incrementCurrentTitleLevel}}
|
||||
|
||||
{{{ startSections }}}
|
||||
|
||||
{{#with model.readme}}
|
||||
|
||||
{{{comment this}}}
|
||||
|
||||
+2
@@ -4,6 +4,8 @@
|
||||
|
||||
{{incrementCurrentTitleLevel}}
|
||||
|
||||
{{{ startSections }}}
|
||||
|
||||
{{#with model}}
|
||||
|
||||
{{#if (sectionEnabled "reflection_comment")}}
|
||||
|
||||
+2
@@ -6,6 +6,8 @@
|
||||
|
||||
{{incrementCurrentTitleLevel}}
|
||||
|
||||
{{{ startSections }}}
|
||||
|
||||
{{> member showSources=false}}
|
||||
|
||||
{{decrementCurrentTitleLevel}}
|
||||
|
||||
+2
@@ -75,7 +75,9 @@ export type FormattingOptionType = {
|
||||
mdxImports?: string[]
|
||||
maxLevel?: number
|
||||
fileNameSeparator?: string
|
||||
startSections?: string[]
|
||||
endSections?: string[]
|
||||
shouldIncrementAfterStartSections?: boolean
|
||||
}
|
||||
|
||||
export declare module "typedoc" {
|
||||
|
||||
Reference in New Issue
Block a user