chore(medusa): remove PublishableAPIKeys feature flag (#3087)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
---
|
||||
|
||||
chore(feature-flag): Remove PublishableAPIKeys feature flag
|
||||
@@ -2273,17 +2273,6 @@ Object of the following format:
|
||||
|
||||
This section holds all events related to publishable API keys.
|
||||
|
||||
:::note
|
||||
|
||||
As of Medusa v1.6.3, Publishable API Keys are available but guarded by a feature flag. To use Publishable API Keys either:
|
||||
|
||||
1. Enable the `MEDUSA_FF_PUBLISHABLE_API_KEYS` environment variable;
|
||||
2. Or enable the `publishable_api_keys` key in the Medusa server's settings.
|
||||
|
||||
You can learn more about enabling it in the [feature flags](../feature-flags/toggle.md) documentation.
|
||||
|
||||
:::
|
||||
|
||||
<table class="reference-table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
const path = require("path")
|
||||
const { IdMap } = require("medusa-test-utils")
|
||||
|
||||
const startServerWithEnvironment =
|
||||
require("../../../helpers/start-server-with-environment").default
|
||||
const { useApi } = require("../../../helpers/use-api")
|
||||
const { useDb } = require("../../../helpers/use-db")
|
||||
const { useDb, initDb } = require("../../../helpers/use-db")
|
||||
const adminSeeder = require("../../helpers/admin-seeder")
|
||||
const {
|
||||
simplePublishableApiKeyFactory,
|
||||
@@ -14,6 +12,7 @@ const {
|
||||
simpleProductFactory,
|
||||
simpleRegionFactory,
|
||||
} = require("../../factories")
|
||||
const setupServer = require("../../../helpers/setup-server")
|
||||
|
||||
jest.setTimeout(50000)
|
||||
|
||||
@@ -30,22 +29,15 @@ const customerData = {
|
||||
last_name: "medusa",
|
||||
}
|
||||
|
||||
describe("[MEDUSA_FF_PUBLISHABLE_API_KEYS] Publishable API keys", () => {
|
||||
describe("Publishable API keys", () => {
|
||||
let medusaProcess
|
||||
let dbConnection
|
||||
const adminUserId = "admin_user"
|
||||
|
||||
beforeAll(async () => {
|
||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||
const [process, connection] = await startServerWithEnvironment({
|
||||
cwd,
|
||||
env: {
|
||||
MEDUSA_FF_PUBLISHABLE_API_KEYS: true,
|
||||
MEDUSA_FF_SALES_CHANNELS: true,
|
||||
},
|
||||
})
|
||||
dbConnection = connection
|
||||
medusaProcess = process
|
||||
dbConnection = await initDb({ cwd })
|
||||
medusaProcess = await setupServer({ cwd })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { NextFunction, Request, Response } from "express"
|
||||
import PublishableApiKeyService from "../../../services/publishable-api-key"
|
||||
|
||||
export type PublishableApiKeyScopes = {
|
||||
sales_channel_id: string[]
|
||||
sales_channel_ids: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ async function validateProductSalesChannelAssociation(
|
||||
"publishableApiKeyService"
|
||||
)
|
||||
|
||||
const { sales_channel_id: salesChannelIds } =
|
||||
const { sales_channel_ids: salesChannelIds } =
|
||||
await publishableKeyService.getResourceScopes(pubKey)
|
||||
|
||||
if (
|
||||
|
||||
+2
-2
@@ -30,8 +30,8 @@ async function validateSalesChannelParam(
|
||||
channelIds = !Array.isArray(channelIds) ? [channelIds] : channelIds
|
||||
|
||||
if (
|
||||
scopes.sales_channel_id.length &&
|
||||
!channelIds.every((sc) => scopes.sales_channel_id.includes(sc))
|
||||
scopes.sales_channel_ids.length &&
|
||||
!channelIds.every((sc) => scopes.sales_channel_ids.includes(sc))
|
||||
) {
|
||||
req.errors = req.errors ?? []
|
||||
req.errors.push(
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { NextFunction, Request, Response } from "express"
|
||||
|
||||
import PublishableApiKeyService from "../../../services/publishable-api-key"
|
||||
import { ProductService, ProductVariantService } from "../../../services"
|
||||
import { ProductVariantService } from "../../../services"
|
||||
|
||||
/**
|
||||
* The middleware check if requested product is assigned to a SC associated with PK in the header.
|
||||
@@ -25,7 +25,7 @@ async function validateProductVariantSalesChannelAssociation(
|
||||
"publishableApiKeyService"
|
||||
)
|
||||
|
||||
const { sales_channel_id: salesChannelIds } =
|
||||
const { sales_channel_ids: salesChannelIds } =
|
||||
await publishableKeyService.getResourceScopes(pubKey)
|
||||
|
||||
if (
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Router } from "express"
|
||||
|
||||
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import middlewares, {
|
||||
transformBody,
|
||||
transformQuery,
|
||||
@@ -18,11 +16,7 @@ import { GetPublishableApiKeySalesChannelsParams } from "./list-publishable-api-
|
||||
const route = Router()
|
||||
|
||||
export default (app) => {
|
||||
app.use(
|
||||
"/publishable-api-keys",
|
||||
isFeatureFlagEnabled(PublishableAPIKeysFeatureFlag.key),
|
||||
route
|
||||
)
|
||||
app.use("/publishable-api-keys", route)
|
||||
|
||||
route.post(
|
||||
"/",
|
||||
|
||||
@@ -22,7 +22,6 @@ import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators
|
||||
import { FlagRouter } from "../../../../utils/flag-router"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import { CartCreateProps } from "../../../../types/cart"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
|
||||
/**
|
||||
* @oas [post] /carts
|
||||
@@ -125,21 +124,18 @@ export default async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
if (
|
||||
!toCreate.sales_channel_id &&
|
||||
req.publishableApiKeyScopes?.sales_channel_id.length
|
||||
) {
|
||||
if (req.publishableApiKeyScopes.sales_channel_id.length > 1) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.UNEXPECTED_STATE,
|
||||
"The PublishableApiKey provided in the request header has multiple associated sales channels."
|
||||
)
|
||||
}
|
||||
|
||||
toCreate.sales_channel_id =
|
||||
req.publishableApiKeyScopes.sales_channel_id[0]
|
||||
if (
|
||||
!toCreate.sales_channel_id &&
|
||||
req.publishableApiKeyScopes?.sales_channel_ids.length
|
||||
) {
|
||||
if (req.publishableApiKeyScopes.sales_channel_ids.length > 1) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.UNEXPECTED_STATE,
|
||||
"The PublishableApiKey provided in the request header has multiple associated sales channels."
|
||||
)
|
||||
}
|
||||
|
||||
toCreate.sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0]
|
||||
}
|
||||
|
||||
let cart: Cart
|
||||
|
||||
@@ -10,7 +10,6 @@ import middlewares, {
|
||||
import { StorePostCartsCartReq } from "./update-cart"
|
||||
import { StorePostCartReq } from "./create-cart"
|
||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params"
|
||||
import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param"
|
||||
|
||||
@@ -45,15 +44,10 @@ export default (app, container) => {
|
||||
const createMiddlewares = [
|
||||
middlewareService.usePreCartCreation(),
|
||||
transformBody(StorePostCartReq),
|
||||
extendRequestParams,
|
||||
validateSalesChannelParam,
|
||||
]
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
createMiddlewares.push(
|
||||
extendRequestParams as unknown as RequestHandler,
|
||||
validateSalesChannelParam as unknown as RequestHandler
|
||||
)
|
||||
}
|
||||
|
||||
route.post(
|
||||
"/",
|
||||
...createMiddlewares,
|
||||
|
||||
@@ -34,14 +34,12 @@ export default (app, container, config) => {
|
||||
})
|
||||
)
|
||||
|
||||
const featureFlagRouter = container.resolve("featureFlagRouter")
|
||||
|
||||
route.use(middlewares.authenticateCustomer())
|
||||
|
||||
authRoutes(route)
|
||||
collectionRoutes(route)
|
||||
customerRoutes(route, container)
|
||||
productRoutes(route, featureFlagRouter)
|
||||
productRoutes(route)
|
||||
productTagsRoutes(route)
|
||||
productTypesRoutes(route)
|
||||
orderRoutes(route)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import { defaultStoreProductsRelations } from "."
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import {
|
||||
CartService,
|
||||
PricingService,
|
||||
@@ -9,7 +8,6 @@ import {
|
||||
RegionService,
|
||||
} from "../../../../services"
|
||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||
import { FlagRouter } from "../../../../utils/flag-router"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
|
||||
/**
|
||||
@@ -87,11 +85,8 @@ export default async (req, res) => {
|
||||
const rawProduct = await productService.retrieve(id, req.retrieveConfig)
|
||||
|
||||
let sales_channel_id = validated.sales_channel_id
|
||||
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
if (req.publishableApiKeyScopes?.sales_channel_id.length === 1) {
|
||||
sales_channel_id = req.publishableApiKeyScopes.sales_channel_id[0]
|
||||
}
|
||||
if (req.publishableApiKeyScopes?.sales_channel_ids.length === 1) {
|
||||
sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0]
|
||||
}
|
||||
|
||||
let regionId = validated.region_id
|
||||
|
||||
@@ -3,10 +3,8 @@ import "reflect-metadata"
|
||||
|
||||
import { Product } from "../../../.."
|
||||
import middlewares, { transformQuery } from "../../../middlewares"
|
||||
import { FlagRouter } from "../../../../utils/flag-router"
|
||||
import { PaginatedResponse } from "../../../../types/common"
|
||||
import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import { validateProductSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-product-sales-channel-association"
|
||||
import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param"
|
||||
import { StoreGetProductsParams } from "./list-products"
|
||||
@@ -14,17 +12,10 @@ import { StoreGetProductsProductParams } from "./get-product"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default (app, featureFlagRouter: FlagRouter) => {
|
||||
app.use("/products", route)
|
||||
export default (app) => {
|
||||
app.use("/products", extendRequestParams, validateSalesChannelParam, route)
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
route.use(
|
||||
"/",
|
||||
extendRequestParams as unknown as RequestHandler,
|
||||
validateSalesChannelParam as unknown as RequestHandler
|
||||
)
|
||||
route.use("/:id", validateProductSalesChannelAssociation)
|
||||
}
|
||||
route.use("/:id", validateProductSalesChannelAssociation)
|
||||
|
||||
route.get(
|
||||
"/",
|
||||
@@ -105,6 +96,7 @@ export const allowedStoreProductsRelations = [
|
||||
...defaultStoreProductsRelations,
|
||||
"variants.title",
|
||||
"variants.prices.amount",
|
||||
"sales_channels",
|
||||
]
|
||||
|
||||
export * from "./list-products"
|
||||
|
||||
@@ -19,8 +19,6 @@ import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import { FlagRouter } from "../../../../utils/flag-router"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
import { Cart, Product } from "../../../../models"
|
||||
|
||||
@@ -202,13 +200,12 @@ export default async (req, res) => {
|
||||
// get only published products for store endpoint
|
||||
filterableFields["status"] = ["published"]
|
||||
|
||||
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
if (req.publishableApiKeyScopes?.sales_channel_id.length) {
|
||||
filterableFields.sales_channel_id =
|
||||
filterableFields.sales_channel_id ||
|
||||
req.publishableApiKeyScopes.sales_channel_id
|
||||
if (req.publishableApiKeyScopes?.sales_channel_ids.length) {
|
||||
filterableFields.sales_channel_id =
|
||||
filterableFields.sales_channel_id ||
|
||||
req.publishableApiKeyScopes.sales_channel_ids
|
||||
|
||||
if (!listConfig.relations.includes("listConfig.relations")) {
|
||||
listConfig.relations.push("sales_channels")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||
import { defaultStoreVariantRelations } from "."
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import { FlagRouter } from "../../../../utils/flag-router"
|
||||
|
||||
/**
|
||||
* @oas [get] /variants/{variant_id}
|
||||
@@ -82,11 +80,8 @@ export default async (req, res) => {
|
||||
})
|
||||
|
||||
let sales_channel_id = validated.sales_channel_id
|
||||
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
if (req.publishableApiKeyScopes?.sales_channel_id.length === 1) {
|
||||
sales_channel_id = req.publishableApiKeyScopes.sales_channel_id[0]
|
||||
}
|
||||
if (req.publishableApiKeyScopes?.sales_channel_ids.length === 1) {
|
||||
sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0]
|
||||
}
|
||||
|
||||
let regionId = validated.region_id
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Router } from "express"
|
||||
|
||||
import { ProductVariant } from "../../../../"
|
||||
import { RequestHandler, Router } from "express"
|
||||
import middlewares from "../../../middlewares"
|
||||
import { featureFlagRouter } from "../../../../loaders/feature-flags"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params"
|
||||
import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param"
|
||||
import { validateProductVariantSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-variant-sales-channel-association"
|
||||
@@ -10,16 +9,9 @@ import { validateProductVariantSalesChannelAssociation } from "../../../middlewa
|
||||
const route = Router()
|
||||
|
||||
export default (app) => {
|
||||
app.use("/variants", route)
|
||||
app.use("/variants", extendRequestParams, validateSalesChannelParam, route)
|
||||
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
route.use(
|
||||
"/",
|
||||
extendRequestParams as unknown as RequestHandler,
|
||||
validateSalesChannelParam as unknown as RequestHandler
|
||||
)
|
||||
route.use("/:id", validateProductVariantSalesChannelAssociation)
|
||||
}
|
||||
route.use("/:id", validateProductVariantSalesChannelAssociation)
|
||||
|
||||
route.get("/", middlewares.wrap(require("./list-variants").default))
|
||||
route.get("/:id", middlewares.wrap(require("./get-variant").default))
|
||||
|
||||
@@ -15,8 +15,6 @@ import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||
import { FilterableProductVariantProps } from "../../../../types/product-variant"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { IsType } from "../../../../utils/validators/is-type"
|
||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||
import { FlagRouter } from "../../../../utils/flag-router"
|
||||
|
||||
/**
|
||||
* @oas [get] /variants
|
||||
@@ -129,11 +127,9 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
let sales_channel_id = validated.sales_channel_id
|
||||
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
|
||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||
if (req.publishableApiKeyScopes?.sales_channel_id.length === 1) {
|
||||
sales_channel_id = req.publishableApiKeyScopes.sales_channel_id[0]
|
||||
}
|
||||
|
||||
if (req.publishableApiKeyScopes?.sales_channel_ids.length === 1) {
|
||||
sales_channel_id = req.publishableApiKeyScopes.sales_channel_ids[0]
|
||||
}
|
||||
|
||||
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
|
||||
import PublishableAPIKeysFeatureFlag from "../loaders/feature-flags/publishable-api-keys"
|
||||
|
||||
export const featureFlag = PublishableAPIKeysFeatureFlag.key
|
||||
|
||||
export class publishableApiKey1667815005070 implements MigrationInterface {
|
||||
name = "publishableApiKey1667815005070"
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { PrimaryColumn } from "typeorm"
|
||||
import { Entity, PrimaryColumn } from "typeorm"
|
||||
|
||||
import { FeatureFlagEntity } from "../utils/feature-flag-decorators"
|
||||
import PublishableAPIKeysFeatureFlag from "../loaders/feature-flags/publishable-api-keys"
|
||||
|
||||
@FeatureFlagEntity(PublishableAPIKeysFeatureFlag.key)
|
||||
@Entity()
|
||||
export class PublishableApiKeySalesChannel {
|
||||
@PrimaryColumn()
|
||||
sales_channel_id: string
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { BeforeInsert, Column } from "typeorm"
|
||||
import { BeforeInsert, Column, Entity } from "typeorm"
|
||||
|
||||
import { BaseEntity } from "../interfaces"
|
||||
import { resolveDbType } from "../utils/db-aware-column"
|
||||
import { generateEntityId } from "../utils"
|
||||
import { FeatureFlagEntity } from "../utils/feature-flag-decorators"
|
||||
import PublishableAPIKeysFeatureFlag from "../loaders/feature-flags/publishable-api-keys"
|
||||
import { generateEntityId, resolveDbType } from "../utils"
|
||||
|
||||
@FeatureFlagEntity(PublishableAPIKeysFeatureFlag.key)
|
||||
@Entity()
|
||||
export class PublishableApiKey extends BaseEntity {
|
||||
@Column({ type: "varchar", nullable: true })
|
||||
created_by: string | null
|
||||
|
||||
@@ -326,7 +326,7 @@ class PublishableApiKeyService extends TransactionBaseService {
|
||||
*/
|
||||
async getResourceScopes(
|
||||
publishableApiKeyId: string
|
||||
): Promise<{ sales_channel_id: string[] }> {
|
||||
): Promise<{ sales_channel_ids: string[] }> {
|
||||
const pubKeySalesChannelRepo = this.activeManager_.withRepository(
|
||||
this.publishableApiKeySalesChannelRepository_
|
||||
)
|
||||
@@ -337,7 +337,7 @@ class PublishableApiKeyService extends TransactionBaseService {
|
||||
})
|
||||
|
||||
return {
|
||||
sales_channel_id: salesChannels.map(
|
||||
sales_channel_ids: salesChannels.map(
|
||||
({ sales_channel_id }) => sales_channel_id
|
||||
),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user