chore(medusa): remove PublishableAPIKeys feature flag (#3087)

This commit is contained in:
Frane Polić authored and GitHub committed 2023-02-20 21:16:08 +01:00
1 parent 46547f29c7
commit 6c04624727
21 files changed
+46 -121

No files matched your search

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