diff --git a/.changeset/eight-wasps-buy.md b/.changeset/eight-wasps-buy.md new file mode 100644 index 0000000000..1bed62c1cd --- /dev/null +++ b/.changeset/eight-wasps-buy.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +chore(feature-flag): Remove PublishableAPIKeys feature flag diff --git a/docs/content/advanced/backend/subscribers/events-list.md b/docs/content/advanced/backend/subscribers/events-list.md index db9f845be5..165b7184ff 100644 --- a/docs/content/advanced/backend/subscribers/events-list.md +++ b/docs/content/advanced/backend/subscribers/events-list.md @@ -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. - -::: - diff --git a/integration-tests/api/__tests__/admin/publishable-api-key.js b/integration-tests/api/__tests__/admin/publishable-api-key.js index 73c4ee360a..edff187d3f 100644 --- a/integration-tests/api/__tests__/admin/publishable-api-key.js +++ b/integration-tests/api/__tests__/admin/publishable-api-key.js @@ -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 () => { diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts b/packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts index a71c7939bc..f563cfd17f 100644 --- a/packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts +++ b/packages/medusa/src/api/middlewares/publishable-api-key/extend-request-params.ts @@ -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[] } /** diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts b/packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts index d119ce734f..f05bb09944 100644 --- a/packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts +++ b/packages/medusa/src/api/middlewares/publishable-api-key/validate-product-sales-channel-association.ts @@ -23,7 +23,7 @@ async function validateProductSalesChannelAssociation( "publishableApiKeyService" ) - const { sales_channel_id: salesChannelIds } = + const { sales_channel_ids: salesChannelIds } = await publishableKeyService.getResourceScopes(pubKey) if ( diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts b/packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts index 657038c54d..e6959d5a4a 100644 --- a/packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts +++ b/packages/medusa/src/api/middlewares/publishable-api-key/validate-sales-channel-param.ts @@ -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( diff --git a/packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts b/packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts index cb7d00d127..ce7e4cfc07 100644 --- a/packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts +++ b/packages/medusa/src/api/middlewares/publishable-api-key/validate-variant-sales-channel-association.ts @@ -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 ( diff --git a/packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts b/packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts index 8d3343b2c7..2b64489b66 100644 --- a/packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts +++ b/packages/medusa/src/api/routes/admin/publishable-api-keys/index.ts @@ -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( "/", diff --git a/packages/medusa/src/api/routes/store/carts/create-cart.ts b/packages/medusa/src/api/routes/store/carts/create-cart.ts index 6f98220412..14c86f97aa 100644 --- a/packages/medusa/src/api/routes/store/carts/create-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/create-cart.ts @@ -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 diff --git a/packages/medusa/src/api/routes/store/carts/index.ts b/packages/medusa/src/api/routes/store/carts/index.ts index 01477d3d39..b812105920 100644 --- a/packages/medusa/src/api/routes/store/carts/index.ts +++ b/packages/medusa/src/api/routes/store/carts/index.ts @@ -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, diff --git a/packages/medusa/src/api/routes/store/index.js b/packages/medusa/src/api/routes/store/index.js index 6fc886f2db..b0a990b26b 100644 --- a/packages/medusa/src/api/routes/store/index.js +++ b/packages/medusa/src/api/routes/store/index.js @@ -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) diff --git a/packages/medusa/src/api/routes/store/products/get-product.ts b/packages/medusa/src/api/routes/store/products/get-product.ts index a1dd467e6d..199589b7a7 100644 --- a/packages/medusa/src/api/routes/store/products/get-product.ts +++ b/packages/medusa/src/api/routes/store/products/get-product.ts @@ -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 diff --git a/packages/medusa/src/api/routes/store/products/index.ts b/packages/medusa/src/api/routes/store/products/index.ts index b281e82e2f..8e3d264f04 100644 --- a/packages/medusa/src/api/routes/store/products/index.ts +++ b/packages/medusa/src/api/routes/store/products/index.ts @@ -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" diff --git a/packages/medusa/src/api/routes/store/products/list-products.ts b/packages/medusa/src/api/routes/store/products/list-products.ts index 2a74ea4b4e..be7b924ced 100644 --- a/packages/medusa/src/api/routes/store/products/list-products.ts +++ b/packages/medusa/src/api/routes/store/products/list-products.ts @@ -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") } } diff --git a/packages/medusa/src/api/routes/store/variants/get-variant.ts b/packages/medusa/src/api/routes/store/variants/get-variant.ts index d1306e3bb5..ebe7ac40f7 100644 --- a/packages/medusa/src/api/routes/store/variants/get-variant.ts +++ b/packages/medusa/src/api/routes/store/variants/get-variant.ts @@ -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 diff --git a/packages/medusa/src/api/routes/store/variants/index.ts b/packages/medusa/src/api/routes/store/variants/index.ts index 45bc4627c8..fddfb0ba78 100644 --- a/packages/medusa/src/api/routes/store/variants/index.ts +++ b/packages/medusa/src/api/routes/store/variants/index.ts @@ -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)) diff --git a/packages/medusa/src/api/routes/store/variants/list-variants.ts b/packages/medusa/src/api/routes/store/variants/list-variants.ts index 5a9120c846..8a1b5817e5 100644 --- a/packages/medusa/src/api/routes/store/variants/list-variants.ts +++ b/packages/medusa/src/api/routes/store/variants/list-variants.ts @@ -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") diff --git a/packages/medusa/src/migrations/1667815005070-publishable_api_key.ts b/packages/medusa/src/migrations/1667815005070-publishable_api_key.ts index 5d8baab4aa..0562a1b9f9 100644 --- a/packages/medusa/src/migrations/1667815005070-publishable_api_key.ts +++ b/packages/medusa/src/migrations/1667815005070-publishable_api_key.ts @@ -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" diff --git a/packages/medusa/src/models/publishable-api-key-sales-channel.ts b/packages/medusa/src/models/publishable-api-key-sales-channel.ts index 4f6154d97e..3a30dfd78c 100644 --- a/packages/medusa/src/models/publishable-api-key-sales-channel.ts +++ b/packages/medusa/src/models/publishable-api-key-sales-channel.ts @@ -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 diff --git a/packages/medusa/src/models/publishable-api-key.ts b/packages/medusa/src/models/publishable-api-key.ts index 06aa70216a..3ce50269b7 100644 --- a/packages/medusa/src/models/publishable-api-key.ts +++ b/packages/medusa/src/models/publishable-api-key.ts @@ -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 diff --git a/packages/medusa/src/services/publishable-api-key.ts b/packages/medusa/src/services/publishable-api-key.ts index ed8e3afc46..c48d1e1613 100644 --- a/packages/medusa/src/services/publishable-api-key.ts +++ b/packages/medusa/src/services/publishable-api-key.ts @@ -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 ), }