breaking: move shared HTTP utils to the framework (#9402)
Fixes: FRMW-2728, FRMW-2729 After this PR gets merged the following middleware will be exported from the `@medusajs/framework/http` import path. - applyParamsAsFilters - clearFiltersByKey - applyDefaultFilters - setContext - getQueryConfig - httpCompression - maybeApplyLinkFilter - refetchEntities - unlessPath - validateBody - validateQuery Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import {
|
||||
AuthenticationInput,
|
||||
AuthenticationResponse,
|
||||
AuthIdentityProviderService,
|
||||
IAuthProvider
|
||||
IAuthProvider,
|
||||
} from "@medusajs/types"
|
||||
|
||||
/**
|
||||
@@ -118,7 +118,7 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
*
|
||||
* The authentication happens either by directly authenticating or returning a redirect URL to continue
|
||||
* the authentication with a third party provider.
|
||||
*
|
||||
*
|
||||
* Related Read: [Learn about the different authentication flows in Medusa](https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route).
|
||||
*
|
||||
* @param {AuthenticationInput} data - The details of the authentication request.
|
||||
@@ -217,22 +217,22 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
/**
|
||||
* This method receives credentails to create a new auth identity. It performs any validation necessary
|
||||
* before creating the auth identity.
|
||||
*
|
||||
*
|
||||
* For example, in the `emailpass` provider, this method ensures that the provided email doesn't exist
|
||||
* before creating the auth identity.
|
||||
*
|
||||
*
|
||||
* This method is only used in a basic authentication flow, such as when using an email and password
|
||||
* to register and authenticate a user.
|
||||
*
|
||||
*
|
||||
* Related Read: [Learn about the different authentication flows in Medusa](https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route).
|
||||
*
|
||||
* @param {AuthenticationInput} data - The details of the authentication request.
|
||||
*
|
||||
* @param {AuthenticationInput} data - The details of the authentication request.
|
||||
* @param {AuthIdentityProviderService} authIdentityProviderService - The service used to retrieve or
|
||||
* create an auth identity. It has two methods: `create` to create an auth identity,
|
||||
* and `retrieve` to retrieve an auth identity. When you authenticate the user, you can create an auth identity
|
||||
* using this service.
|
||||
* @returns The created authentication identity if no errors occur.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* import {
|
||||
* AuthIdentityProviderService,
|
||||
@@ -252,7 +252,7 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
* await authIdentityService.retrieve({
|
||||
* entity_id: data.body.email, // email or some ID
|
||||
* })
|
||||
*
|
||||
*
|
||||
* return {
|
||||
* success: false,
|
||||
* error: "Identity with email already exists",
|
||||
@@ -266,13 +266,13 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
* // can include password or any other relevant information
|
||||
* }
|
||||
* })
|
||||
*
|
||||
*
|
||||
* return {
|
||||
* success: true,
|
||||
* authIdentity: createdAuthIdentity,
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* return { success: false, error: error.message }
|
||||
* }
|
||||
* }
|
||||
@@ -289,9 +289,9 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
|
||||
/**
|
||||
* This method is used to update an auth identity's details.
|
||||
*
|
||||
*
|
||||
* For example, the `emailpass` provider's implementation of this method updates a user's password.
|
||||
*
|
||||
*
|
||||
* @param data - Data relevant to identify the auth identity and what to update in it. For example,
|
||||
* the `emailpass` provider expects in this object an `email` and `password` properties.
|
||||
* @param authIdentityProviderService - The service used to retrieve or
|
||||
@@ -299,7 +299,7 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
* and `retrieve` to retrieve an auth identity. When you authenticate the user, you can create an auth identity
|
||||
* using this service.
|
||||
* @returns The updated authentication identity if no errors occur.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* import {
|
||||
* AuthIdentityProviderService,
|
||||
@@ -322,7 +322,7 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
* user: data.user // example
|
||||
* }
|
||||
* )
|
||||
*
|
||||
*
|
||||
* return { success: true, authIdentity }
|
||||
* } catch (error) {
|
||||
* return { success: false, error: error.message }
|
||||
@@ -348,15 +348,15 @@ export abstract class AbstractAuthModuleProvider implements IAuthProvider {
|
||||
* Then, the third-party service redirects to a frontend URL passing it a `code` query parameter.
|
||||
* The frontend should then send a request to the Medusa application's validate callback API route, passing it the code.
|
||||
* That route uses this method to verify the callback's code.
|
||||
*
|
||||
*
|
||||
* If the callback is verified successfully, the provider creates an auth identity for the user, or updates the auth identity's user information.
|
||||
*
|
||||
*
|
||||
* In the auth identity, use the following properties to store additional data:
|
||||
*
|
||||
*
|
||||
* - `provider_metadata`: Store metadata useful for the provider, such as a password hash.
|
||||
* - `user_metadata`: Store metadata of the user's details. For example, if the third-party service returns the user's information such as email
|
||||
* or name, you store this data in this property.
|
||||
*
|
||||
*
|
||||
* Related Guide: [Learn about the different authentication flows in Medusa](https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route).
|
||||
*
|
||||
* @param {AuthenticationInput} data - The details of the authentication request.
|
||||
|
||||
59
packages/core/utils/src/common/__tests__/omit-deep.spec.ts
Normal file
59
packages/core/utils/src/common/__tests__/omit-deep.spec.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { omitDeep } from "../omit-deep"
|
||||
|
||||
describe("omitDeep", () => {
|
||||
it("should omit properties in a nested object", () => {
|
||||
const input = {
|
||||
id: 1,
|
||||
__typename: "123",
|
||||
createdAt: "1020209",
|
||||
address: {
|
||||
id: 1,
|
||||
__typename: "123",
|
||||
},
|
||||
variants: [
|
||||
20,
|
||||
{
|
||||
id: 22,
|
||||
title: "hello world",
|
||||
__typename: "123",
|
||||
createdAt: "1020209",
|
||||
variantOption: {
|
||||
id: 1,
|
||||
__typename: "123",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 32,
|
||||
test: null,
|
||||
__typename: "123",
|
||||
createdAt: "1020209",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const output = {
|
||||
id: 1,
|
||||
address: {
|
||||
id: 1,
|
||||
},
|
||||
variants: [
|
||||
20,
|
||||
{
|
||||
id: 22,
|
||||
title: "hello world",
|
||||
variantOption: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 32,
|
||||
test: null,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
expect(omitDeep(input, ["createdAt", "updatedAt", "__typename"])).toEqual(
|
||||
output
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,47 @@
|
||||
import { removeUndefinedProperties } from "../remove-undefined-properties"
|
||||
|
||||
describe("removeUndefinedProperties", () => {
|
||||
it("should remove all undefined properties from an input object", () => {
|
||||
const inputObj = {
|
||||
test: undefined,
|
||||
test1: "test1",
|
||||
test2: null,
|
||||
test3: {
|
||||
test3_1: undefined,
|
||||
test3_2: "test3_2",
|
||||
test3_3: null,
|
||||
},
|
||||
test4: [
|
||||
undefined,
|
||||
null,
|
||||
"null",
|
||||
[1, 2, undefined],
|
||||
{
|
||||
test4_1: undefined,
|
||||
test4_2: "test4_2",
|
||||
test4_3: null,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const cleanObject = removeUndefinedProperties(inputObj)
|
||||
|
||||
expect(cleanObject).toEqual({
|
||||
test1: "test1",
|
||||
test2: null,
|
||||
test3: {
|
||||
test3_2: "test3_2",
|
||||
test3_3: null,
|
||||
},
|
||||
test4: [
|
||||
null,
|
||||
null,
|
||||
[1, 2],
|
||||
{
|
||||
test4_2: "test4_2",
|
||||
test4_3: null,
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,7 +1,7 @@
|
||||
export function getNodeVersion(): number {
|
||||
const [major] = process.versions.node.split('.').map(Number)
|
||||
const [major] = process.versions.node.split(".").map(Number)
|
||||
|
||||
return major
|
||||
}
|
||||
|
||||
export const MIN_SUPPORTED_NODE_VERSION = 20
|
||||
export const MIN_SUPPORTED_NODE_VERSION = 20
|
||||
|
||||
@@ -2,6 +2,7 @@ export * from "./alter-columns-helper"
|
||||
export * from "./array-difference"
|
||||
export * from "./array-intersection"
|
||||
export * from "./build-query"
|
||||
export * from "./remove-undefined-properties"
|
||||
export * from "./build-regexp-if-valid"
|
||||
export * from "./camel-to-snake-case"
|
||||
export * from "./container"
|
||||
@@ -73,3 +74,4 @@ export * from "./validate-handle"
|
||||
export * from "./wrap-handler"
|
||||
export * from "./resolve-exports"
|
||||
export * from "./dynamic-import"
|
||||
export * from "./omit-deep"
|
||||
|
||||
34
packages/core/utils/src/common/omit-deep.ts
Normal file
34
packages/core/utils/src/common/omit-deep.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { isObject } from "./is-object"
|
||||
|
||||
export function omitDeep<T extends object = object>(
|
||||
input: object,
|
||||
excludes: Array<number | string>
|
||||
): T {
|
||||
if (!input) {
|
||||
return input
|
||||
}
|
||||
|
||||
return Object.entries(input).reduce((nextInput, [key, value]) => {
|
||||
const shouldExclude = excludes.includes(key)
|
||||
if (shouldExclude) {
|
||||
return nextInput
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
nextInput[key] = value.map((arrItem) => {
|
||||
if (isObject(arrItem)) {
|
||||
return omitDeep(arrItem, excludes)
|
||||
}
|
||||
return arrItem
|
||||
})
|
||||
return nextInput
|
||||
} else if (isObject(value)) {
|
||||
nextInput[key] = omitDeep(value, excludes)
|
||||
return nextInput
|
||||
}
|
||||
|
||||
nextInput[key] = value
|
||||
|
||||
return nextInput
|
||||
}, {} as T)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { isDefined } from "./is-defined"
|
||||
|
||||
export function removeUndefinedProperties<T extends object>(inputObj: T): T {
|
||||
const removeProperties = (obj: T) => {
|
||||
const res = {} as T
|
||||
|
||||
Object.keys(obj).reduce((acc: T, key: string) => {
|
||||
if (typeof obj[key] === "undefined") {
|
||||
return acc
|
||||
}
|
||||
acc[key] = removeUndefinedDeeply(obj[key])
|
||||
return acc
|
||||
}, res)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return removeProperties(inputObj)
|
||||
}
|
||||
|
||||
function removeUndefinedDeeply(input: unknown): any {
|
||||
if (isDefined(input)) {
|
||||
if (input === null || input === "null") {
|
||||
return null
|
||||
} else if (Array.isArray(input)) {
|
||||
return input
|
||||
.map((item) => {
|
||||
return removeUndefinedDeeply(item)
|
||||
})
|
||||
.filter((v) => isDefined(v))
|
||||
} else if (Object.prototype.toString.call(input) === "[object Date]") {
|
||||
return input
|
||||
} else if (typeof input === "object") {
|
||||
return Object.keys(input).reduce(
|
||||
(acc: Record<string, unknown>, key: string) => {
|
||||
if (typeof input[key] === "undefined") {
|
||||
return acc
|
||||
}
|
||||
acc[key] = removeUndefinedDeeply(input[key])
|
||||
return acc
|
||||
},
|
||||
{}
|
||||
)
|
||||
} else {
|
||||
return input
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -354,7 +354,7 @@ export class EntityBuilder {
|
||||
*
|
||||
* @example
|
||||
* import { model } from "@medusajs/framework/utils"
|
||||
*
|
||||
*
|
||||
* const Product = model.define("product", {
|
||||
* id: model.id(),
|
||||
* store: model.belongsTo(() => Store, {
|
||||
|
||||
@@ -31,17 +31,17 @@ export abstract class BaseProperty<T> implements PropertyType<T> {
|
||||
|
||||
/**
|
||||
* This method indicates that a property's value can be `null`.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* import { model } from "@medusajs/framework/utils"
|
||||
*
|
||||
*
|
||||
* const MyCustom = model.define("my_custom", {
|
||||
* price: model.bigNumber().nullable(),
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
*
|
||||
* export default MyCustom
|
||||
*
|
||||
*
|
||||
* @customNamespace Property Configuration Methods
|
||||
*/
|
||||
nullable() {
|
||||
@@ -50,22 +50,22 @@ export abstract class BaseProperty<T> implements PropertyType<T> {
|
||||
|
||||
/**
|
||||
* This method defines an index on a property.
|
||||
*
|
||||
*
|
||||
* @param {string} name - The index's name. If not provided,
|
||||
* Medusa generates the name.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* import { model } from "@medusajs/framework/utils"
|
||||
*
|
||||
*
|
||||
* const MyCustom = model.define("my_custom", {
|
||||
* id: model.id(),
|
||||
* name: model.text().index(
|
||||
* "IDX_MY_CUSTOM_NAME"
|
||||
* ),
|
||||
* })
|
||||
*
|
||||
*
|
||||
* export default MyCustom
|
||||
*
|
||||
*
|
||||
* @customNamespace Property Configuration Methods
|
||||
*/
|
||||
index(name?: string) {
|
||||
@@ -76,20 +76,20 @@ export abstract class BaseProperty<T> implements PropertyType<T> {
|
||||
/**
|
||||
* This method indicates that a property's value must be unique in the database.
|
||||
* A unique index is created on the property.
|
||||
*
|
||||
*
|
||||
* @param {string} name - The unique index's name. If not provided,
|
||||
* Medusa generates the name.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* import { model } from "@medusajs/framework/utils"
|
||||
*
|
||||
*
|
||||
* const User = model.define("user", {
|
||||
* email: model.text().unique(),
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
*
|
||||
* export default User
|
||||
*
|
||||
*
|
||||
* @customNamespace Property Configuration Methods
|
||||
*/
|
||||
unique(name?: string) {
|
||||
@@ -99,12 +99,12 @@ export abstract class BaseProperty<T> implements PropertyType<T> {
|
||||
|
||||
/**
|
||||
* This method defines the default value of a property.
|
||||
*
|
||||
*
|
||||
* @param {T} value - The default value.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* import { model } from "@medusajs/framework/utils"
|
||||
*
|
||||
*
|
||||
* const MyCustom = model.define("my_custom", {
|
||||
* color: model
|
||||
* .enum(["black", "white"])
|
||||
@@ -114,9 +114,9 @@ export abstract class BaseProperty<T> implements PropertyType<T> {
|
||||
* .default(0),
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
*
|
||||
* export default MyCustom
|
||||
*
|
||||
*
|
||||
* @customNamespace Property Configuration Methods
|
||||
*/
|
||||
default(value: T) {
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import {
|
||||
IFulfillmentProvider,
|
||||
FulfillmentOption
|
||||
} from "@medusajs/types"
|
||||
import { FulfillmentOption, IFulfillmentProvider } from "@medusajs/types"
|
||||
|
||||
/**
|
||||
* ### constructor
|
||||
*
|
||||
* The constructor allows you to access resources from the module's container using the first parameter,
|
||||
* and the module's options using the second parameter.
|
||||
*
|
||||
*
|
||||
* :::note
|
||||
*
|
||||
*
|
||||
* A module's options are passed when you register it in the Medusa application.
|
||||
*
|
||||
*
|
||||
* :::
|
||||
*
|
||||
* If you're creating a client or establishing a connection with a third-party service, do it in the constructor.
|
||||
@@ -22,32 +19,32 @@ import {
|
||||
* ```ts
|
||||
* import { AbstractFulfillmentProviderService } from "@medusajs/framework/utils"
|
||||
* import { Logger } from "@medusajs/framework/types"
|
||||
*
|
||||
*
|
||||
* type InjectedDependencies = {
|
||||
* logger: Logger
|
||||
* }
|
||||
*
|
||||
*
|
||||
* type Options = {
|
||||
* apiKey: string
|
||||
* }
|
||||
*
|
||||
*
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* protected logger_: Logger
|
||||
* protected options_: Options
|
||||
* // assuming you're initializing a client
|
||||
* protected client
|
||||
*
|
||||
*
|
||||
* constructor(
|
||||
* { logger }: InjectedDependencies,
|
||||
* options: Options
|
||||
* ) {
|
||||
* super()
|
||||
*
|
||||
*
|
||||
* this.logger_ = logger
|
||||
* this.options_ = options
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* export default MyFulfillmentProviderService
|
||||
* ```
|
||||
*/
|
||||
@@ -56,15 +53,15 @@ export class AbstractFulfillmentProviderService
|
||||
{
|
||||
/**
|
||||
* The `identifier` property holds a unique identifier of the fulfillment module provider.
|
||||
*
|
||||
*
|
||||
* You can use the kebab-case name of the provider as its value.
|
||||
*
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* static identifier = "my-fulfillment"
|
||||
*
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
*/
|
||||
@@ -84,7 +81,7 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*
|
||||
*
|
||||
* @privateRemarks
|
||||
* This method is ignored as {@link validateOption} is the one used by the Fulfillment Module.
|
||||
*/
|
||||
@@ -99,13 +96,13 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* This method retrieves the shipping options this fulfillment provider supports.
|
||||
*
|
||||
*
|
||||
* @returns The list of fulfillment options.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* // other imports...
|
||||
* import { FulfillmentOption } from "@medusajs/framework/types"
|
||||
*
|
||||
*
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
* async getFulfillmentOptions(): Promise<FulfillmentOption[]> {
|
||||
@@ -128,28 +125,28 @@ export class AbstractFulfillmentProviderService
|
||||
/**
|
||||
* This method validates the `data` property of a shipping method and returns it. The returned data
|
||||
* is stored in the shipping method's `data` property.
|
||||
*
|
||||
*
|
||||
* Your fulfillment provider can use the `data` property to store additional information useful for
|
||||
* handling the fulfillment later. For example, you may store an ID from the third-party fulfillment
|
||||
* system.
|
||||
*
|
||||
*
|
||||
* @param optionData - The `data` property of the shipping option.
|
||||
* @param data - The `data` property of the shipping method.
|
||||
* @param context - Context details, such as context of the cart or customer.
|
||||
* @returns the data to store in the `data` property of the shipping method.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
* async validateFulfillmentData(
|
||||
* optionData: any,
|
||||
* data: any,
|
||||
* optionData: any,
|
||||
* data: any,
|
||||
* context: any
|
||||
* ): Promise<any> {
|
||||
* // assuming your client retrieves an ID from the
|
||||
* // third-party service
|
||||
* const externalId = await this.client.getId()
|
||||
*
|
||||
*
|
||||
* return {
|
||||
* ...data,
|
||||
* externalId
|
||||
@@ -163,13 +160,13 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* This method validates the `data` property of a shipping option when it's created.
|
||||
*
|
||||
*
|
||||
* The `data` property can hold useful information that's later added to the `data` attribute
|
||||
* of shipping methods created from this option.
|
||||
*
|
||||
*
|
||||
* @param data - The data to validate.
|
||||
* @return Whether the data is valid.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -183,12 +180,12 @@ export class AbstractFulfillmentProviderService
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether a shippin option's price is calculated during
|
||||
* This method indicates whether a shippin option's price is calculated during
|
||||
* checkout or is fixed.
|
||||
*
|
||||
*
|
||||
* @param data - The `data` property of the shipping option.
|
||||
* @returns Whether the price is calculated for the shipping option.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -203,15 +200,15 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* This method calculates the price of a shipping option, or a shipping method when it's created.
|
||||
*
|
||||
*
|
||||
* The Medusa application uses the {@link canCalculate} method first to check whether the shipping option's price is calculated.
|
||||
* If it returns `true`, Medusa uses this method to retrieve the calculated price.
|
||||
*
|
||||
*
|
||||
* @param optionData - The `data` property of a shipping option.
|
||||
* @param data - If the price is calculated for a shipping option, it's the `data` of the shipping option. Otherwise, it's the `data of the shipping method.
|
||||
* @param cart - The cart details.
|
||||
* @returns The calculated price
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -219,7 +216,7 @@ export class AbstractFulfillmentProviderService
|
||||
* // assuming the client can calculate the price using
|
||||
* // the third-party service
|
||||
* const price = await this.client.calculate(data)
|
||||
*
|
||||
*
|
||||
* return price
|
||||
* }
|
||||
* }
|
||||
@@ -229,27 +226,27 @@ export class AbstractFulfillmentProviderService
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used when a fulfillment is created. If the method returns in the object a
|
||||
* This method is used when a fulfillment is created. If the method returns in the object a
|
||||
* `data` property, it's stored in the fulfillment's `data` property.
|
||||
*
|
||||
*
|
||||
* The `data` property is useful when handling the fulfillment later,
|
||||
* as you can access information useful for your integration.
|
||||
*
|
||||
*
|
||||
* You can also use this method to perform an action with the third-party fulfillment service.
|
||||
*
|
||||
*
|
||||
* @param data - The `data` property of the shipping method this fulfillment is created for.
|
||||
* @param items - The items in the fulfillment.
|
||||
* @param order - The order this fulfillment is created for.
|
||||
* @param fulfillment - The fulfillment's details.
|
||||
* @returns The data to store in the fulfillment's `data` property.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
* async createFulfillment(
|
||||
* data: any,
|
||||
* items: any,
|
||||
* order: any,
|
||||
* data: any,
|
||||
* items: any,
|
||||
* order: any,
|
||||
* fulfillment: any
|
||||
* ): Promise<any> {
|
||||
* // assuming the client creates a fulfillment
|
||||
@@ -258,7 +255,7 @@ export class AbstractFulfillmentProviderService
|
||||
* fulfillment,
|
||||
* items
|
||||
* )
|
||||
*
|
||||
*
|
||||
* return {
|
||||
* data: {
|
||||
* ...data,
|
||||
@@ -275,9 +272,9 @@ export class AbstractFulfillmentProviderService
|
||||
/**
|
||||
* This method is used when a fulfillment is canceled. Use it to perform operations
|
||||
* with the third-party fulfillment service.
|
||||
*
|
||||
*
|
||||
* @param fulfillment - The fulfillment's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -294,10 +291,10 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* This method retrieves the documents of a fulfillment.
|
||||
*
|
||||
*
|
||||
* @param data - The `data` property of the fulfillment.
|
||||
* @returns The fulfillment's documents.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -313,17 +310,17 @@ export class AbstractFulfillmentProviderService
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used when a fulfillment is created for a return. If the method returns in the object a
|
||||
* This method is used when a fulfillment is created for a return. If the method returns in the object a
|
||||
* `data` property, it's stored in the fulfillment's `data` property.
|
||||
*
|
||||
*
|
||||
* The `data` property is useful when handling the fulfillment later,
|
||||
* as you can access information useful for your integration.
|
||||
*
|
||||
*
|
||||
* Use this method to perform actions necessary in the third-party fulfillment service.
|
||||
*
|
||||
*
|
||||
* @param fulfillment - The fulfillment's details.
|
||||
* @returns The data to store in the fulfillment's `data` property.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -333,7 +330,7 @@ export class AbstractFulfillmentProviderService
|
||||
* const externalData = await this.client.createReturn(
|
||||
* fulfillment
|
||||
* )
|
||||
*
|
||||
*
|
||||
* return {
|
||||
* data: {
|
||||
* ...fulfillment.data,
|
||||
@@ -349,10 +346,10 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* This method retrieves documents for a return's fulfillment.
|
||||
*
|
||||
*
|
||||
* @param data - The `data` property of the fulfillment.
|
||||
* @returns The fulfillment's documents.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -369,10 +366,10 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* This method retrieves the documents for a shipment.
|
||||
*
|
||||
*
|
||||
* @param data - The `data` property of the shipmnet.
|
||||
* @returns The shipment's documents.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
@@ -382,7 +379,7 @@ export class AbstractFulfillmentProviderService
|
||||
* return await this.client.documents(data)
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
*/
|
||||
async getShipmentDocuments(data) {
|
||||
return []
|
||||
@@ -390,16 +387,16 @@ export class AbstractFulfillmentProviderService
|
||||
|
||||
/**
|
||||
* This method retrieves the documents of a fulfillment of a certain type.
|
||||
*
|
||||
*
|
||||
* @param fulfillmentData - The `data` property of the fulfillment.
|
||||
* @param documentType - The document's type. For example, `invoice`.
|
||||
* @returns The fulfillment's documents.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MyFulfillmentProviderService extends AbstractFulfillmentProviderService {
|
||||
* // ...
|
||||
* async retrieveDocuments(
|
||||
* fulfillmentData: any,
|
||||
* fulfillmentData: any,
|
||||
* documentType: any
|
||||
* ): Promise<void> {
|
||||
* // assuming the client retrieves documents
|
||||
|
||||
@@ -2,21 +2,21 @@ import { SearchTypes } from "@medusajs/types"
|
||||
|
||||
/**
|
||||
* ## Overview
|
||||
*
|
||||
*
|
||||
* A search service class is in a TypeScript or JavaScript file created in the `src/services` directory. The class must extend the `AbstractSearchService` class imported
|
||||
* from the `@medusajs/utils` package.
|
||||
*
|
||||
* Based on services’ naming conventions, the file’s name should be the slug version of the search service’s name without `service`, and the class’s name should be the
|
||||
*
|
||||
* Based on services’ naming conventions, the file’s name should be the slug version of the search service’s name without `service`, and the class’s name should be the
|
||||
* pascal case of the search service’s name following by `Service`.
|
||||
*
|
||||
*
|
||||
* For example, create the `MySearchService` class in the file `src/services/my-search.ts`:
|
||||
*
|
||||
*
|
||||
* ```ts title="src/services/my-search.ts"
|
||||
* import { AbstractSearchService } from "@medusajs/utils"
|
||||
*
|
||||
*
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* isDefault = false
|
||||
*
|
||||
*
|
||||
* createIndex(indexName: string, options: Record<string, any>) {
|
||||
* throw new Error("Method not implemented.")
|
||||
* }
|
||||
@@ -48,7 +48,7 @@ import { SearchTypes } from "@medusajs/types"
|
||||
* }
|
||||
* search(
|
||||
* indexName: string,
|
||||
* query: string,
|
||||
* query: string,
|
||||
* options: Record<string, any>
|
||||
* ) {
|
||||
* return {
|
||||
@@ -56,24 +56,24 @@ import { SearchTypes } from "@medusajs/types"
|
||||
* }
|
||||
* }
|
||||
* updateSettings(
|
||||
* indexName: string,
|
||||
* indexName: string,
|
||||
* settings: Record<string, any>
|
||||
* ) {
|
||||
* throw new Error("Method not implemented.")
|
||||
* }
|
||||
*
|
||||
*
|
||||
* }
|
||||
*
|
||||
*
|
||||
* export default MySearchService
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ---
|
||||
*
|
||||
*
|
||||
* ## Notes About Class Methods
|
||||
*
|
||||
* Although there are several helper methods in this class, the main methods used by the Medusa backend are `addDocuments`, `deleteDocument`, and `search`.
|
||||
*
|
||||
* Although there are several helper methods in this class, the main methods used by the Medusa backend are `addDocuments`, `deleteDocument`, and `search`.
|
||||
* The rest of the methods are provided in case you need them for custom use cases.
|
||||
*
|
||||
*
|
||||
* ---
|
||||
*/
|
||||
export abstract class AbstractSearchService
|
||||
@@ -122,15 +122,15 @@ export abstract class AbstractSearchService
|
||||
* @example
|
||||
* // ...
|
||||
* import { ProductService } from "@medusajs/medusa"
|
||||
*
|
||||
*
|
||||
* type InjectedDependencies = {
|
||||
* productService: ProductService
|
||||
* }
|
||||
*
|
||||
*
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
* protected readonly productService_: ProductService
|
||||
*
|
||||
*
|
||||
* constructor({ productService }: InjectedDependencies) {
|
||||
* // @ts-expect-error prefer-rest-params
|
||||
* super(...arguments)
|
||||
@@ -140,7 +140,7 @@ export abstract class AbstractSearchService
|
||||
* // communicates with a third-party service.
|
||||
* this.client = new Client(options)
|
||||
* }
|
||||
*
|
||||
*
|
||||
* // ...
|
||||
* }
|
||||
*/
|
||||
@@ -150,15 +150,15 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to create an index in the search engine.
|
||||
*
|
||||
*
|
||||
* @param {string} indexName - The name of the index to create.
|
||||
* @param {unknown} options - Any options that may be relevant to your search service. This parameter doesn't have
|
||||
* @param {unknown} options - Any options that may be relevant to your search service. This parameter doesn't have
|
||||
* any defined format as it depends on your custom implementation.
|
||||
* @returns {unknown} No required format of returned data, as it depends on your custom implementation.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* An example implementation, assuming `client` would interact with a third-party service:
|
||||
*
|
||||
*
|
||||
* ```ts title="src/services/my-search.ts"
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
@@ -168,10 +168,10 @@ export abstract class AbstractSearchService
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* Another example of how the [MeiliSearch plugin](https://docs.medusajs.com/plugins/search/meilisearch) uses the
|
||||
* `options` parameter:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* class MeiliSearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
@@ -189,14 +189,14 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to retrieve an index’s results from the search engine.
|
||||
*
|
||||
*
|
||||
* @param {string} indexName - The name of the index
|
||||
* @returns {unknown} No required format of returned data, as it depends on your custom implementation.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
*
|
||||
*
|
||||
* getIndex(indexName: string) {
|
||||
* return this.client_.getIndex(indexName)
|
||||
* }
|
||||
@@ -206,19 +206,19 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to add a document to an index in the search engine.
|
||||
*
|
||||
*
|
||||
* When the Medusa backend loads, it triggers indexing for all products available in the Medusa backend, which uses this method to add or update documents.
|
||||
* It’s also used whenever a new product is added or a product is updated.
|
||||
*
|
||||
*
|
||||
* @param {string} indexName - The name of the index to add the documents to.
|
||||
* @param {unknown} documents - The list of documents to add. For example, an array of {@link entities!Product | products}.
|
||||
* @param {string} type - The type of documents being indexed. For example, `products`.
|
||||
* @returns {unknown} The response of saving the documents in the search engine, but there’s no required format of the response.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
*
|
||||
*
|
||||
* async addDocuments(
|
||||
* indexName: string,
|
||||
* documents: Record<string, any>[],
|
||||
@@ -237,17 +237,17 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to replace existing documents in the search engine of an index with new documents.
|
||||
*
|
||||
*
|
||||
* @param {string} indexName - The name of the index that the documents belong to.
|
||||
* @param {unknown} documents - The list of documents to index. For example, it can be an array of {@link entities!Product | products}.
|
||||
* Based on your search engine implementation, the documents should include an identification key that allows replacing the existing documents.
|
||||
* @param {string} type - The type of documents being replaced. For example, `products`.
|
||||
* @returns {unknown} The response of replacing the documents in the search engine, but there’s no required format of the response.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
*
|
||||
*
|
||||
* async replaceDocuments(
|
||||
* indexName: string,
|
||||
* documents: Record<string, any>[],
|
||||
@@ -268,18 +268,18 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to delete a document from an index.
|
||||
*
|
||||
*
|
||||
* When a product is deleted in the Medusa backend, this method is used to delete the product from the search engine’s index.
|
||||
*
|
||||
*
|
||||
* @param {string} indexName - The name of the index that the document belongs to.
|
||||
* @param {string | number} document_id - The ID of the item indexed. For example, if the deleted item is a product, then this is
|
||||
* the ID of the product.
|
||||
* @returns {unknown} The response of deleting the document in the search engine, but there’s no required format of the response.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
*
|
||||
*
|
||||
* async deleteDocument(
|
||||
* indexName: string,
|
||||
* document_id: string | number
|
||||
@@ -296,14 +296,14 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to delete all documents from an index.
|
||||
*
|
||||
*
|
||||
* @param {string} indexName - The index's name.
|
||||
* @returns {unknown} The response of deleting the documents of that index in the search engine, but there’s no required format of the response.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
*
|
||||
*
|
||||
* async deleteAllDocuments(indexName: string) {
|
||||
* return await this.client_
|
||||
* .deleteDocuments(indexName)
|
||||
@@ -314,26 +314,26 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to search through an index by a query.
|
||||
*
|
||||
* In the Medusa backend, this method is used within the [Search Products API Route](https://docs.medusajs.com/api/store#products_postproductssearch)
|
||||
*
|
||||
* In the Medusa backend, this method is used within the [Search Products API Route](https://docs.medusajs.com/api/store#products_postproductssearch)
|
||||
* to retrieve the search results. The API route's response type is an array of items, though the item's format is not defined as it depends on the
|
||||
* data returned by this method.
|
||||
*
|
||||
* @param {string} indexName - The index's name. In the case of the Search Products API Routes, its value is `products`.
|
||||
* @param {string | null} query - The search query to retrieve results for.
|
||||
* @param {unknown} options -
|
||||
* @param {unknown} options -
|
||||
* Options that can configure the search process. The Search Products API route passes an object having the properties:
|
||||
*
|
||||
*
|
||||
* - `paginationOptions`: An object having an `offset` and `limit` properties, which are passed in the API Route's body.
|
||||
* - `filter`: Filters that are passed in the API Route's request body. Its format is unknown, so you can pass filters based on your search service.
|
||||
* - `additionalOptions`: Any other parameters that may be passed in the request's body.
|
||||
*
|
||||
*
|
||||
* @returns {unknown} The list of results. For example, an array of products.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
*
|
||||
*
|
||||
* async search(
|
||||
* indexName: string,
|
||||
* query: string,
|
||||
@@ -355,18 +355,18 @@ export abstract class AbstractSearchService
|
||||
|
||||
/**
|
||||
* This method is used to update the settings of an index within the search service. This is useful if you want to update the index settings when the plugin options change.
|
||||
*
|
||||
* For example, in the Algolia plugin, a loader, which runs when the Medusa backend loads, is used to update the settings of indices based on the plugin options.
|
||||
*
|
||||
* For example, in the Algolia plugin, a loader, which runs when the Medusa backend loads, is used to update the settings of indices based on the plugin options.
|
||||
* The loader uses this method to update the settings.
|
||||
*
|
||||
*
|
||||
* @param {string} indexName - The index's name to update its settings.
|
||||
* @param {unknown} settings - The settings to update. Its format depends on your use case.
|
||||
* @returns {unknown} The response of updating the index in the search engine, but there’s no required format of the response.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* class MySearchService extends AbstractSearchService {
|
||||
* // ...
|
||||
*
|
||||
*
|
||||
* async updateSettings(
|
||||
* indexName: string,
|
||||
* settings: Record<string, any>
|
||||
|
||||
Reference in New Issue
Block a user