@unchainedshop/api 4.0.0-rc.2 → 4.0.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api-index.d.ts.map +1 -1
- package/lib/api-index.js +4 -1
- package/lib/api-index.js.map +1 -1
- package/lib/errors.d.ts +1 -1
- package/lib/errors.d.ts.map +1 -1
- package/lib/errors.js +1 -1
- package/lib/errors.js.map +1 -1
- package/lib/express/chatRouter.d.ts +3 -0
- package/lib/express/chatRouter.d.ts.map +1 -0
- package/lib/express/chatRouter.js +86 -0
- package/lib/express/chatRouter.js.map +1 -0
- package/lib/express/createApolloMiddleware.d.ts +4 -0
- package/lib/express/createApolloMiddleware.d.ts.map +1 -0
- package/lib/express/createApolloMiddleware.js +36 -0
- package/lib/express/createApolloMiddleware.js.map +1 -0
- package/lib/express/createBulkImportMiddleware copy.d.ts +6 -0
- package/lib/express/createBulkImportMiddleware copy.d.ts.map +1 -0
- package/lib/express/createBulkImportMiddleware copy.js +49 -0
- package/lib/express/createBulkImportMiddleware copy.js.map +1 -0
- package/lib/express/createMCPMiddleware.d.ts +2 -6
- package/lib/express/createMCPMiddleware.d.ts.map +1 -1
- package/lib/express/createMCPMiddleware.js +73 -42
- package/lib/express/createMCPMiddleware.js.map +1 -1
- package/lib/express/createSingleSignOnMiddleware.d.ts +5 -0
- package/lib/express/createSingleSignOnMiddleware.d.ts.map +1 -0
- package/lib/express/createSingleSignOnMiddleware.js +71 -0
- package/lib/express/createSingleSignOnMiddleware.js.map +1 -0
- package/lib/express/createTempUploadMiddleware.d.ts +7 -0
- package/lib/express/createTempUploadMiddleware.d.ts.map +1 -0
- package/lib/express/createTempUploadMiddleware.js +48 -0
- package/lib/express/createTempUploadMiddleware.js.map +1 -0
- package/lib/express/index.d.ts.map +1 -1
- package/lib/express/index.js +17 -4
- package/lib/express/index.js.map +1 -1
- package/lib/express/setupMCPChatHandler.d.ts +3 -0
- package/lib/express/setupMCPChatHandler.d.ts.map +1 -0
- package/lib/express/setupMCPChatHandler.js +57 -0
- package/lib/express/setupMCPChatHandler.js.map +1 -0
- package/lib/fastify/index.d.ts.map +1 -1
- package/lib/fastify/index.js +24 -2
- package/lib/fastify/index.js.map +1 -1
- package/lib/fastify/mcpChatHandler.d.ts +3 -0
- package/lib/fastify/mcpChatHandler.d.ts.map +1 -0
- package/lib/fastify/mcpChatHandler.js +60 -0
- package/lib/fastify/mcpChatHandler.js.map +1 -0
- package/lib/fastify/mcpHandler copy.d.ts +4 -0
- package/lib/fastify/mcpHandler copy.d.ts.map +1 -0
- package/lib/fastify/mcpHandler copy.js +72 -0
- package/lib/fastify/mcpHandler copy.js.map +1 -0
- package/lib/fastify/mcpHandler.d.ts +3 -7
- package/lib/fastify/mcpHandler.d.ts.map +1 -1
- package/lib/fastify/mcpHandler.js +71 -39
- package/lib/fastify/mcpHandler.js.map +1 -1
- package/lib/fastify/tempUploadHandler.d.ts +4 -0
- package/lib/fastify/tempUploadHandler.d.ts.map +1 -0
- package/lib/fastify/tempUploadHandler.js +41 -0
- package/lib/fastify/tempUploadHandler.js.map +1 -0
- package/lib/hashPassword.d.ts +2 -0
- package/lib/hashPassword.d.ts.map +1 -0
- package/lib/hashPassword.js +5 -0
- package/lib/hashPassword.js.map +1 -0
- package/lib/loaders/assortmentMediaTextLoader.js +1 -1
- package/lib/loaders/assortmentMediaTextLoader.js.map +1 -1
- package/lib/loaders/assortmentTextLoader.js +1 -1
- package/lib/loaders/assortmentTextLoader.js.map +1 -1
- package/lib/loaders/buildLocaleMap.d.ts +6 -0
- package/lib/loaders/buildLocaleMap.d.ts.map +1 -0
- package/lib/loaders/buildLocaleMap.js +67 -0
- package/lib/loaders/buildLocaleMap.js.map +1 -0
- package/lib/loaders/buildTextMap.d.ts +1 -1
- package/lib/loaders/buildTextMap.d.ts.map +1 -1
- package/lib/loaders/buildTextMap.js +19 -6
- package/lib/loaders/buildTextMap.js.map +1 -1
- package/lib/loaders/filterTextLoader.js +1 -1
- package/lib/loaders/filterTextLoader.js.map +1 -1
- package/lib/loaders/productMediaTextLoader.d.ts.map +1 -1
- package/lib/loaders/productMediaTextLoader.js +1 -1
- package/lib/loaders/productMediaTextLoader.js.map +1 -1
- package/lib/loaders/productTextLoader.d.ts.map +1 -1
- package/lib/loaders/productTextLoader.js +1 -1
- package/lib/loaders/productTextLoader.js.map +1 -1
- package/lib/mcp/index.d.ts +3 -94
- package/lib/mcp/index.d.ts.map +1 -1
- package/lib/mcp/index.js +45 -135
- package/lib/mcp/index.js.map +1 -1
- package/lib/mcp/tools/addProductAssignmentHandler.d.ts +52 -0
- package/lib/mcp/tools/addProductAssignmentHandler.d.ts.map +1 -0
- package/lib/mcp/tools/addProductAssignmentHandler.js +97 -0
- package/lib/mcp/tools/addProductAssignmentHandler.js.map +1 -0
- package/lib/mcp/tools/addProductMediaUploadHandler.d.ts +28 -0
- package/lib/mcp/tools/addProductMediaUploadHandler.d.ts.map +1 -0
- package/lib/mcp/tools/addProductMediaUploadHandler.js +62 -0
- package/lib/mcp/tools/addProductMediaUploadHandler.js.map +1 -0
- package/lib/mcp/tools/countriesHandler.d.ts +60 -0
- package/lib/mcp/tools/countriesHandler.d.ts.map +1 -0
- package/lib/mcp/tools/countriesHandler.js +48 -0
- package/lib/mcp/tools/countriesHandler.js.map +1 -0
- package/lib/mcp/tools/countryHandler.d.ts +20 -0
- package/lib/mcp/tools/countryHandler.d.ts.map +1 -0
- package/lib/mcp/tools/countryHandler.js +34 -0
- package/lib/mcp/tools/countryHandler.js.map +1 -0
- package/lib/mcp/tools/createLanguageHandler.d.ts +36 -0
- package/lib/mcp/tools/createLanguageHandler.d.ts.map +1 -0
- package/lib/mcp/tools/createLanguageHandler.js +39 -0
- package/lib/mcp/tools/createLanguageHandler.js.map +1 -0
- package/lib/mcp/tools/createProduct.d.ts +138 -0
- package/lib/mcp/tools/createProduct.d.ts.map +1 -0
- package/lib/mcp/tools/createProduct.js +60 -0
- package/lib/mcp/tools/createProduct.js.map +1 -0
- package/lib/mcp/tools/createProductVariationHandler.d.ts +84 -0
- package/lib/mcp/tools/createProductVariationHandler.d.ts.map +1 -0
- package/lib/mcp/tools/createProductVariationHandler.js +73 -0
- package/lib/mcp/tools/createProductVariationHandler.js.map +1 -0
- package/lib/mcp/tools/createProductVariationOptionHandler.d.ts +60 -0
- package/lib/mcp/tools/createProductVariationOptionHandler.d.ts.map +1 -0
- package/lib/mcp/tools/createProductVariationOptionHandler.js +59 -0
- package/lib/mcp/tools/createProductVariationOptionHandler.js.map +1 -0
- package/lib/mcp/tools/currenciesHandler.d.ts +60 -0
- package/lib/mcp/tools/currenciesHandler.d.ts.map +1 -0
- package/lib/mcp/tools/currenciesHandler.js +50 -0
- package/lib/mcp/tools/currenciesHandler.js.map +1 -0
- package/lib/mcp/tools/currencyHandler.d.ts +20 -0
- package/lib/mcp/tools/currencyHandler.d.ts.map +1 -0
- package/lib/mcp/tools/currencyHandler.js +34 -0
- package/lib/mcp/tools/currencyHandler.js.map +1 -0
- package/lib/mcp/tools/getProduct.d.ts +48 -0
- package/lib/mcp/tools/getProduct.d.ts.map +1 -0
- package/lib/mcp/tools/getProduct.js +61 -0
- package/lib/mcp/tools/getProduct.js.map +1 -0
- package/lib/mcp/tools/index.d.ts +39 -0
- package/lib/mcp/tools/index.d.ts.map +1 -0
- package/lib/mcp/tools/index.js +39 -0
- package/lib/mcp/tools/index.js.map +1 -0
- package/lib/mcp/tools/languageHandler.d.ts +20 -0
- package/lib/mcp/tools/languageHandler.d.ts.map +1 -0
- package/lib/mcp/tools/languageHandler.js +31 -0
- package/lib/mcp/tools/languageHandler.js.map +1 -0
- package/lib/mcp/tools/languagesHandler.d.ts +60 -0
- package/lib/mcp/tools/languagesHandler.d.ts.map +1 -0
- package/lib/mcp/tools/languagesHandler.js +42 -0
- package/lib/mcp/tools/languagesHandler.js.map +1 -0
- package/lib/mcp/tools/listProducts.d.ts +112 -0
- package/lib/mcp/tools/listProducts.d.ts.map +1 -0
- package/lib/mcp/tools/listProducts.js +110 -0
- package/lib/mcp/tools/listProducts.js.map +1 -0
- package/lib/mcp/tools/normalizeMediaUrl.d.ts +3 -0
- package/lib/mcp/tools/normalizeMediaUrl.d.ts.map +1 -0
- package/lib/mcp/tools/normalizeMediaUrl.js +21 -0
- package/lib/mcp/tools/normalizeMediaUrl.js.map +1 -0
- package/lib/mcp/tools/productReviewsCountHandler.d.ts +20 -0
- package/lib/mcp/tools/productReviewsCountHandler.d.ts.map +1 -0
- package/lib/mcp/tools/productReviewsCountHandler.js +30 -0
- package/lib/mcp/tools/productReviewsCountHandler.js.map +1 -0
- package/lib/mcp/tools/productReviewsHandler.d.ts +56 -0
- package/lib/mcp/tools/productReviewsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/productReviewsHandler.js +45 -0
- package/lib/mcp/tools/productReviewsHandler.js.map +1 -0
- package/lib/mcp/tools/productsCountHandler.d.ts +32 -0
- package/lib/mcp/tools/productsCountHandler.d.ts.map +1 -0
- package/lib/mcp/tools/productsCountHandler.js +33 -0
- package/lib/mcp/tools/productsCountHandler.js.map +1 -0
- package/lib/mcp/tools/publishProduct.d.ts +20 -0
- package/lib/mcp/tools/publishProduct.d.ts.map +1 -0
- package/lib/mcp/tools/publishProduct.js +40 -0
- package/lib/mcp/tools/publishProduct.js.map +1 -0
- package/lib/mcp/tools/removeLanguageHandler.d.ts +20 -0
- package/lib/mcp/tools/removeLanguageHandler.d.ts.map +1 -0
- package/lib/mcp/tools/removeLanguageHandler.js +35 -0
- package/lib/mcp/tools/removeLanguageHandler.js.map +1 -0
- package/lib/mcp/tools/removeProduct.d.ts +20 -0
- package/lib/mcp/tools/removeProduct.d.ts.map +1 -0
- package/lib/mcp/tools/removeProduct.js +34 -0
- package/lib/mcp/tools/removeProduct.js.map +1 -0
- package/lib/mcp/tools/removeProductAssignmentHandler.d.ts +48 -0
- package/lib/mcp/tools/removeProductAssignmentHandler.d.ts.map +1 -0
- package/lib/mcp/tools/removeProductAssignmentHandler.js +51 -0
- package/lib/mcp/tools/removeProductAssignmentHandler.js.map +1 -0
- package/lib/mcp/tools/removeProductHandler.d.ts +20 -0
- package/lib/mcp/tools/removeProductHandler.d.ts.map +1 -0
- package/lib/mcp/tools/removeProductHandler.js +34 -0
- package/lib/mcp/tools/removeProductHandler.js.map +1 -0
- package/lib/mcp/tools/removeProductMediaHandler.d.ts +20 -0
- package/lib/mcp/tools/removeProductMediaHandler.d.ts.map +1 -0
- package/lib/mcp/tools/removeProductMediaHandler.js +42 -0
- package/lib/mcp/tools/removeProductMediaHandler.js.map +1 -0
- package/lib/mcp/tools/removeProductVariationHandler.d.ts +20 -0
- package/lib/mcp/tools/removeProductVariationHandler.d.ts.map +1 -0
- package/lib/mcp/tools/removeProductVariationHandler.js +43 -0
- package/lib/mcp/tools/removeProductVariationHandler.js.map +1 -0
- package/lib/mcp/tools/removeProductVariationOptionHandler.d.ts +24 -0
- package/lib/mcp/tools/removeProductVariationOptionHandler.d.ts.map +1 -0
- package/lib/mcp/tools/removeProductVariationOptionHandler.js +47 -0
- package/lib/mcp/tools/removeProductVariationOptionHandler.js.map +1 -0
- package/lib/mcp/tools/reorderProductMediaHandler.d.ts +44 -0
- package/lib/mcp/tools/reorderProductMediaHandler.d.ts.map +1 -0
- package/lib/mcp/tools/reorderProductMediaHandler.js +39 -0
- package/lib/mcp/tools/reorderProductMediaHandler.js.map +1 -0
- package/lib/mcp/tools/unPublishProduct.d.ts +20 -0
- package/lib/mcp/tools/unPublishProduct.d.ts.map +1 -0
- package/lib/mcp/tools/unPublishProduct.js +40 -0
- package/lib/mcp/tools/unPublishProduct.js.map +1 -0
- package/lib/mcp/tools/updateLanguageHandler.d.ts +48 -0
- package/lib/mcp/tools/updateLanguageHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateLanguageHandler.js +40 -0
- package/lib/mcp/tools/updateLanguageHandler.js.map +1 -0
- package/lib/mcp/tools/updateProduct.d.ts +56 -0
- package/lib/mcp/tools/updateProduct.d.ts.map +1 -0
- package/lib/mcp/tools/updateProduct.js +44 -0
- package/lib/mcp/tools/updateProduct.js.map +1 -0
- package/lib/mcp/tools/updateProductCommerceHandler.d.ts +166 -0
- package/lib/mcp/tools/updateProductCommerceHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateProductCommerceHandler.js +64 -0
- package/lib/mcp/tools/updateProductCommerceHandler.js.map +1 -0
- package/lib/mcp/tools/updateProductMediaTextsHandler.d.ts +56 -0
- package/lib/mcp/tools/updateProductMediaTextsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateProductMediaTextsHandler.js +45 -0
- package/lib/mcp/tools/updateProductMediaTextsHandler.js.map +1 -0
- package/lib/mcp/tools/updateProductPlanHandler.d.ts +72 -0
- package/lib/mcp/tools/updateProductPlanHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateProductPlanHandler.js +51 -0
- package/lib/mcp/tools/updateProductPlanHandler.js.map +1 -0
- package/lib/mcp/tools/updateProductSupplyHandler.d.ts +64 -0
- package/lib/mcp/tools/updateProductSupplyHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateProductSupplyHandler.js +52 -0
- package/lib/mcp/tools/updateProductSupplyHandler.js.map +1 -0
- package/lib/mcp/tools/updateProductTextsHandler.d.ts +114 -0
- package/lib/mcp/tools/updateProductTextsHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateProductTextsHandler.js +50 -0
- package/lib/mcp/tools/updateProductTextsHandler.js.map +1 -0
- package/lib/mcp/tools/updateProductTokenizationHandler.d.ts +72 -0
- package/lib/mcp/tools/updateProductTokenizationHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateProductTokenizationHandler.js +49 -0
- package/lib/mcp/tools/updateProductTokenizationHandler.js.map +1 -0
- package/lib/mcp/tools/updateProductWarehousingHandler.d.ts +48 -0
- package/lib/mcp/tools/updateProductWarehousingHandler.d.ts.map +1 -0
- package/lib/mcp/tools/updateProductWarehousingHandler.js +45 -0
- package/lib/mcp/tools/updateProductWarehousingHandler.js.map +1 -0
- package/lib/mcp/utils/getNormalizedProductDetails.d.ts +26 -0
- package/lib/mcp/utils/getNormalizedProductDetails.d.ts.map +1 -0
- package/lib/mcp/utils/getNormalizedProductDetails.js +38 -0
- package/lib/mcp/utils/getNormalizedProductDetails.js.map +1 -0
- package/lib/mcp/utils/normalizeMediaUrl.d.ts +3 -0
- package/lib/mcp/utils/normalizeMediaUrl.d.ts.map +1 -0
- package/lib/mcp/utils/normalizeMediaUrl.js +21 -0
- package/lib/mcp/utils/normalizeMediaUrl.js.map +1 -0
- package/lib/resolvers/mutations/accounts/buildSecretTOTPAuthURL.d.ts +3 -0
- package/lib/resolvers/mutations/accounts/buildSecretTOTPAuthURL.d.ts.map +1 -0
- package/lib/resolvers/mutations/accounts/buildSecretTOTPAuthURL.js +6 -0
- package/lib/resolvers/mutations/accounts/buildSecretTOTPAuthURL.js.map +1 -0
- package/lib/resolvers/mutations/accounts/disableTOTP.d.ts +6 -0
- package/lib/resolvers/mutations/accounts/disableTOTP.d.ts.map +1 -0
- package/lib/resolvers/mutations/accounts/disableTOTP.js +27 -0
- package/lib/resolvers/mutations/accounts/disableTOTP.js.map +1 -0
- package/lib/resolvers/mutations/accounts/enableTOTP.d.ts +6 -0
- package/lib/resolvers/mutations/accounts/enableTOTP.d.ts.map +1 -0
- package/lib/resolvers/mutations/accounts/enableTOTP.js +20 -0
- package/lib/resolvers/mutations/accounts/enableTOTP.js.map +1 -0
- package/lib/resolvers/mutations/accounts/linkOAuthAccount.d.ts +7 -0
- package/lib/resolvers/mutations/accounts/linkOAuthAccount.d.ts.map +1 -0
- package/lib/resolvers/mutations/accounts/linkOAuthAccount.js +30 -0
- package/lib/resolvers/mutations/accounts/linkOAuthAccount.js.map +1 -0
- package/lib/resolvers/mutations/accounts/loginWithOAuth.d.ts +8 -0
- package/lib/resolvers/mutations/accounts/loginWithOAuth.d.ts.map +1 -0
- package/lib/resolvers/mutations/accounts/loginWithOAuth.js +25 -0
- package/lib/resolvers/mutations/accounts/loginWithOAuth.js.map +1 -0
- package/lib/resolvers/mutations/accounts/logoutAllSessions.d.ts +5 -0
- package/lib/resolvers/mutations/accounts/logoutAllSessions.d.ts.map +1 -0
- package/lib/resolvers/mutations/accounts/logoutAllSessions.js +20 -0
- package/lib/resolvers/mutations/accounts/logoutAllSessions.js.map +1 -0
- package/lib/resolvers/mutations/accounts/unlinkOAuthAccount.d.ts +6 -0
- package/lib/resolvers/mutations/accounts/unlinkOAuthAccount.d.ts.map +1 -0
- package/lib/resolvers/mutations/accounts/unlinkOAuthAccount.js +13 -0
- package/lib/resolvers/mutations/accounts/unlinkOAuthAccount.js.map +1 -0
- package/lib/resolvers/mutations/assortments/addAssortmentMedia.d.ts +6 -0
- package/lib/resolvers/mutations/assortments/addAssortmentMedia.d.ts.map +1 -0
- package/lib/resolvers/mutations/assortments/addAssortmentMedia.js +18 -0
- package/lib/resolvers/mutations/assortments/addAssortmentMedia.js.map +1 -0
- package/lib/resolvers/mutations/products/addProductAssignment.d.ts.map +1 -1
- package/lib/resolvers/mutations/products/addProductAssignment.js +3 -1
- package/lib/resolvers/mutations/products/addProductAssignment.js.map +1 -1
- package/lib/resolvers/mutations/products/addProductMedia.d.ts +6 -0
- package/lib/resolvers/mutations/products/addProductMedia.d.ts.map +1 -0
- package/lib/resolvers/mutations/products/addProductMedia.js +18 -0
- package/lib/resolvers/mutations/products/addProductMedia.js.map +1 -0
- package/lib/resolvers/mutations/users/updateUserAvatar.d.ts +6 -0
- package/lib/resolvers/mutations/users/updateUserAvatar.d.ts.map +1 -0
- package/lib/resolvers/mutations/users/updateUserAvatar.js +22 -0
- package/lib/resolvers/mutations/users/updateUserAvatar.js.map +1 -0
- package/lib/resolvers/mutations/utils/getOrderCart.d.ts +7 -0
- package/lib/resolvers/mutations/utils/getOrderCart.d.ts.map +1 -0
- package/lib/resolvers/mutations/utils/getOrderCart.js +13 -0
- package/lib/resolvers/mutations/utils/getOrderCart.js.map +1 -0
- package/lib/resolvers/queries/filters/searchAssortments.d.ts.map +1 -1
- package/lib/resolvers/queries/filters/searchAssortments.js +0 -5
- package/lib/resolvers/queries/filters/searchAssortments.js.map +1 -1
- package/lib/resolvers/queries/filters/searchProducts.d.ts.map +1 -1
- package/lib/resolvers/queries/filters/searchProducts.js +2 -7
- package/lib/resolvers/queries/filters/searchProducts.js.map +1 -1
- package/lib/resolvers/type/dispatch-types.d.ts +15 -0
- package/lib/resolvers/type/dispatch-types.d.ts.map +1 -0
- package/lib/resolvers/type/dispatch-types.js +16 -0
- package/lib/resolvers/type/dispatch-types.js.map +1 -0
- package/lib/resolvers/type/oauth-account.d.ts +6 -0
- package/lib/resolvers/type/oauth-account.d.ts.map +1 -0
- package/lib/resolvers/type/oauth-account.js +7 -0
- package/lib/resolvers/type/oauth-account.js.map +1 -0
- package/lib/resolvers/type/oauth-provider.d.ts +6 -0
- package/lib/resolvers/type/oauth-provider.d.ts.map +1 -0
- package/lib/resolvers/type/oauth-provider.js +6 -0
- package/lib/resolvers/type/oauth-provider.js.map +1 -0
- package/lib/resolvers/type/stock-types.d.ts +14 -0
- package/lib/resolvers/type/stock-types.d.ts.map +1 -0
- package/lib/resolvers/type/stock-types.js +15 -0
- package/lib/resolvers/type/stock-types.js.map +1 -0
- package/lib/roles/all.d.ts.map +1 -1
- package/lib/roles/all.js +1 -0
- package/lib/roles/all.js.map +1 -1
- package/lib/roles/index.d.ts.map +1 -1
- package/lib/roles/index.js +1 -0
- package/lib/roles/index.js.map +1 -1
- package/lib/roles/loggedIn.d.ts.map +1 -1
- package/lib/roles/loggedIn.js +1 -0
- package/lib/roles/loggedIn.js.map +1 -1
- package/lib/user-context.d.ts +7 -0
- package/lib/user-context.d.ts.map +1 -0
- package/lib/user-context.js +76 -0
- package/lib/user-context.js.map +1 -0
- package/package.json +34 -18
- package/src/api-index.ts +4 -1
- package/src/errors.ts +5 -4
- package/src/express/createMCPMiddleware.ts +91 -0
- package/src/express/createTempUploadMiddleware.ts +60 -0
- package/src/express/index.ts +35 -6
- package/src/fastify/index.ts +32 -2
- package/src/fastify/mcpHandler.ts +97 -0
- package/src/fastify/tempUploadHandler.ts +52 -0
- package/src/loaders/assortmentMediaTextLoader.ts +1 -1
- package/src/loaders/assortmentTextLoader.ts +1 -1
- package/src/loaders/buildLocaleMap.test.ts +65 -0
- package/src/loaders/buildLocaleMap.ts +73 -0
- package/src/loaders/buildTextMap.test.ts +54 -0
- package/src/loaders/buildTextMap.ts +25 -6
- package/src/loaders/filterTextLoader.ts +1 -1
- package/src/loaders/productMediaTextLoader.ts +1 -1
- package/src/loaders/productTextLoader.ts +1 -1
- package/src/mcp/README.md +25 -0
- package/src/mcp/index.ts +313 -0
- package/src/mcp/tools/addProductAssignmentHandler.ts +118 -0
- package/src/mcp/tools/addProductMediaUploadHandler.ts +79 -0
- package/src/mcp/tools/countriesHandler.ts +60 -0
- package/src/mcp/tools/countryHandler.ts +40 -0
- package/src/mcp/tools/createLanguageHandler.ts +46 -0
- package/src/mcp/tools/createProduct.ts +75 -0
- package/src/mcp/tools/createProductVariationHandler.ts +93 -0
- package/src/mcp/tools/createProductVariationOptionHandler.ts +73 -0
- package/src/mcp/tools/currenciesHandler.ts +63 -0
- package/src/mcp/tools/currencyHandler.ts +40 -0
- package/src/mcp/tools/getProduct.ts +74 -0
- package/src/mcp/tools/index.ts +39 -0
- package/src/mcp/tools/languageHandler.ts +37 -0
- package/src/mcp/tools/languagesHandler.ts +54 -0
- package/src/mcp/tools/listProducts.ts +148 -0
- package/src/mcp/tools/productReviewsCountHandler.ts +36 -0
- package/src/mcp/tools/productReviewsHandler.ts +54 -0
- package/src/mcp/tools/productsCountHandler.ts +38 -0
- package/src/mcp/tools/publishProduct.ts +45 -0
- package/src/mcp/tools/removeLanguageHandler.ts +42 -0
- package/src/mcp/tools/removeProductAssignmentHandler.ts +61 -0
- package/src/mcp/tools/removeProductHandler.ts +40 -0
- package/src/mcp/tools/removeProductMediaHandler.ts +49 -0
- package/src/mcp/tools/removeProductVariationHandler.ts +51 -0
- package/src/mcp/tools/removeProductVariationOptionHandler.ts +58 -0
- package/src/mcp/tools/reorderProductMediaHandler.ts +48 -0
- package/src/mcp/tools/unPublishProduct.ts +46 -0
- package/src/mcp/tools/updateLanguageHandler.ts +47 -0
- package/src/mcp/tools/updateProduct.ts +51 -0
- package/src/mcp/tools/updateProductCommerceHandler.ts +79 -0
- package/src/mcp/tools/updateProductMediaTextsHandler.ts +56 -0
- package/src/mcp/tools/updateProductPlanHandler.ts +58 -0
- package/src/mcp/tools/updateProductSupplyHandler.ts +59 -0
- package/src/mcp/tools/updateProductTextsHandler.ts +59 -0
- package/src/mcp/tools/updateProductTokenizationHandler.ts +58 -0
- package/src/mcp/tools/updateProductWarehousingHandler.ts +54 -0
- package/src/mcp/utils/getNormalizedProductDetails.ts +42 -0
- package/src/mcp/utils/normalizeMediaUrl.ts +26 -0
- package/src/resolvers/mutations/products/addProductAssignment.ts +3 -0
- package/src/resolvers/queries/filters/searchAssortments.ts +0 -5
- package/src/resolvers/queries/filters/searchProducts.ts +2 -7
- package/src/roles/all.ts +1 -0
- package/src/roles/index.ts +1 -0
- package/src/roles/loggedIn.ts +1 -0
- package/lib/express/mcpHandler.d.ts.map +0 -1
- package/lib/express/mcpHandler.js +0 -68
- package/lib/express/mcpHandler.js.map +0 -1
- package/lib/fastify/index copy.d.ts.map +0 -1
- package/lib/fastify/index copy.js +0 -157
- package/lib/fastify/index copy.js.map +0 -1
- package/lib/mcp/server.d.ts +0 -4
- package/lib/mcp/server.d.ts.map +0 -1
- package/lib/mcp/server.js +0 -60
- package/lib/mcp/server.js.map +0 -1
- package/lib/mcp/types.d.ts +0 -28
- package/lib/mcp/types.d.ts.map +0 -1
- package/lib/mcp/types.js +0 -2
- package/lib/mcp/types.js.map +0 -1
- package/lib/middleware/accountLockout.d.ts.map +0 -1
- package/lib/middleware/accountLockout.js +0 -84
- package/lib/middleware/accountLockout.js.map +0 -1
- package/lib/middleware/rateLimiter.d.ts.map +0 -1
- package/lib/middleware/rateLimiter.js +0 -91
- package/lib/middleware/rateLimiter.js.map +0 -1
- package/lib/plugins/inputValidation.d.ts.map +0 -1
- package/lib/plugins/inputValidation.js +0 -95
- package/lib/plugins/inputValidation.js.map +0 -1
- package/lib/utils/inputValidation.d.ts.map +0 -1
- package/lib/utils/inputValidation.js +0 -51
- package/lib/utils/inputValidation.js.map +0 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
+
import { checkAction } from '../acl.js';
|
|
3
|
+
import { actions } from '../roles/index.js';
|
|
4
|
+
import { Context } from '../context.js';
|
|
5
|
+
import { getFileAdapter } from '@unchainedshop/core-files';
|
|
6
|
+
|
|
7
|
+
const logger = createLogger('unchained:temp-upload');
|
|
8
|
+
|
|
9
|
+
const methodWrongHandler = (res) => {
|
|
10
|
+
logger.error('Method not supported, return 404');
|
|
11
|
+
res.writeHead(404);
|
|
12
|
+
res.end();
|
|
13
|
+
return;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default async function tempUploadMiddleware(
|
|
17
|
+
req: Request & { query?: any; files: any; unchainedContext: Context },
|
|
18
|
+
res,
|
|
19
|
+
) {
|
|
20
|
+
try {
|
|
21
|
+
const context = req.unchainedContext;
|
|
22
|
+
|
|
23
|
+
if (req.method !== 'POST') {
|
|
24
|
+
return methodWrongHandler(res);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await checkAction(context, (actions as any).uploadTempFile);
|
|
28
|
+
|
|
29
|
+
const [data] = req.files || [];
|
|
30
|
+
|
|
31
|
+
const file = await context.services.files.uploadFileFromStream({
|
|
32
|
+
directoryName: 'temp-uploads',
|
|
33
|
+
rawFile: {
|
|
34
|
+
filename: data.originalname,
|
|
35
|
+
buffer: data.buffer,
|
|
36
|
+
mimetype: data.mimetype,
|
|
37
|
+
},
|
|
38
|
+
meta: { fieldname: data.fieldname, encoding: data.encoding },
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Add an expiration date to this file manually!
|
|
42
|
+
const expires = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
|
43
|
+
await context.modules.files.update(file._id, {
|
|
44
|
+
expires, // Default to 1 hour
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const fileUploadAdapter = getFileAdapter();
|
|
48
|
+
const rawUrl = await fileUploadAdapter.createDownloadURL(file);
|
|
49
|
+
const url = context.modules.files.normalizeUrl(rawUrl, {});
|
|
50
|
+
const body = JSON.stringify({ fileId: file._id, url, expires: expires.toISOString() });
|
|
51
|
+
|
|
52
|
+
res.writeHead(200);
|
|
53
|
+
res.end(body);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
logger.error(e.message);
|
|
56
|
+
res.writeHead(503);
|
|
57
|
+
res.end(JSON.stringify({ name: e.name, code: e.code, message: e.message }));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
package/src/express/index.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import e from 'express';
|
|
2
|
-
import { getCurrentContextResolver, LoginFn, LogoutFn } from '../context.js';
|
|
3
|
-
import createBulkImportMiddleware from './createBulkImportMiddleware.js';
|
|
4
|
-
import createERCMetadataMiddleware from './createERCMetadataMiddleware.js';
|
|
5
2
|
import session from 'express-session';
|
|
3
|
+
import multer from 'multer';
|
|
6
4
|
import MongoStore from 'connect-mongo';
|
|
7
5
|
import { Passport } from 'passport';
|
|
8
6
|
import { YogaServerInstance } from 'graphql-yoga';
|
|
9
7
|
import { mongodb } from '@unchainedshop/mongodb';
|
|
10
8
|
import { UnchainedCore } from '@unchainedshop/core';
|
|
11
9
|
import { emit } from '@unchainedshop/events';
|
|
12
|
-
import { API_EVENTS } from '../events.js';
|
|
13
10
|
import { User } from '@unchainedshop/core-users';
|
|
14
11
|
|
|
12
|
+
import { getCurrentContextResolver, LoginFn, LogoutFn } from '../context.js';
|
|
13
|
+
import createBulkImportMiddleware from './createBulkImportMiddleware.js';
|
|
14
|
+
import createERCMetadataMiddleware from './createERCMetadataMiddleware.js';
|
|
15
|
+
import createTempUploadMiddleware from './createTempUploadMiddleware.js';
|
|
16
|
+
import createMCPMiddleware from './createMCPMiddleware.js';
|
|
17
|
+
import { API_EVENTS } from '../events.js';
|
|
18
|
+
|
|
15
19
|
const resolveUserRemoteAddress = (req: e.Request) => {
|
|
16
20
|
const remoteAddress =
|
|
17
21
|
(req.headers['x-real-ip'] as string) ||
|
|
@@ -23,9 +27,14 @@ const resolveUserRemoteAddress = (req: e.Request) => {
|
|
|
23
27
|
return { remoteAddress, remotePort };
|
|
24
28
|
};
|
|
25
29
|
|
|
30
|
+
const storage = multer.memoryStorage();
|
|
31
|
+
const upload = multer({ storage: storage });
|
|
32
|
+
|
|
26
33
|
const {
|
|
27
34
|
BULK_IMPORT_API_PATH = '/bulk-import',
|
|
28
35
|
ERC_METADATA_API_PATH = '/erc-metadata',
|
|
36
|
+
TEMP_UPLOAD_API_PATH = '/temp-upload',
|
|
37
|
+
MCP_API_PATH = '/mcp',
|
|
29
38
|
GRAPHQL_API_PATH = '/graphql',
|
|
30
39
|
UNCHAINED_COOKIE_NAME = 'unchained_token',
|
|
31
40
|
UNCHAINED_COOKIE_PATH = '/',
|
|
@@ -126,10 +135,16 @@ export const connect = (
|
|
|
126
135
|
{
|
|
127
136
|
graphqlHandler,
|
|
128
137
|
db,
|
|
129
|
-
}: {
|
|
138
|
+
}: {
|
|
139
|
+
graphqlHandler: YogaServerInstance<any, any>;
|
|
140
|
+
db: mongodb.Db;
|
|
141
|
+
unchainedAPI: UnchainedCore;
|
|
142
|
+
},
|
|
130
143
|
{
|
|
131
144
|
allowRemoteToLocalhostSecureCookies = false,
|
|
132
|
-
}: {
|
|
145
|
+
}: {
|
|
146
|
+
allowRemoteToLocalhostSecureCookies?: boolean;
|
|
147
|
+
} = {},
|
|
133
148
|
) => {
|
|
134
149
|
if (allowRemoteToLocalhostSecureCookies) {
|
|
135
150
|
// Workaround: Allow to use sandbox with localhost
|
|
@@ -137,6 +152,16 @@ export const connect = (
|
|
|
137
152
|
expressApp.use((req, res, next) => {
|
|
138
153
|
req.headers['x-forwarded-proto'] = 'https';
|
|
139
154
|
res.setHeader('Access-Control-Allow-Private-Network', 'true');
|
|
155
|
+
res.setHeader('Access-Control-Allow-Origin', req.headers.origin || '*');
|
|
156
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
157
|
+
res.setHeader(
|
|
158
|
+
'Access-Control-Allow-Methods',
|
|
159
|
+
['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'].join(', '),
|
|
160
|
+
);
|
|
161
|
+
res.setHeader(
|
|
162
|
+
'Access-Control-Allow-Headers',
|
|
163
|
+
req.headers['access-control-request-headers'] || '*',
|
|
164
|
+
);
|
|
140
165
|
next();
|
|
141
166
|
});
|
|
142
167
|
}
|
|
@@ -189,4 +214,8 @@ export const connect = (
|
|
|
189
214
|
expressApp.use(GRAPHQL_API_PATH, graphqlHandler.handle);
|
|
190
215
|
expressApp.use(ERC_METADATA_API_PATH, createERCMetadataMiddleware);
|
|
191
216
|
expressApp.use(BULK_IMPORT_API_PATH, createBulkImportMiddleware);
|
|
217
|
+
expressApp.use(TEMP_UPLOAD_API_PATH, upload.any(), createTempUploadMiddleware);
|
|
218
|
+
|
|
219
|
+
expressApp.use(MCP_API_PATH, e.json({ limit: '10mb' }));
|
|
220
|
+
expressApp.use(MCP_API_PATH, createMCPMiddleware);
|
|
192
221
|
};
|
package/src/fastify/index.ts
CHANGED
|
@@ -10,8 +10,11 @@ import { API_EVENTS } from '../events.js';
|
|
|
10
10
|
import { User } from '@unchainedshop/core-users';
|
|
11
11
|
import fastifySession from '@fastify/session';
|
|
12
12
|
import fastifyCookie from '@fastify/cookie';
|
|
13
|
+
import fastifyMultipart from '@fastify/multipart';
|
|
13
14
|
import { FastifyBaseLogger, FastifyInstance, FastifyRequest } from 'fastify';
|
|
14
15
|
import { createLogger } from '@unchainedshop/logger';
|
|
16
|
+
import mcpHandler from './mcpHandler.js';
|
|
17
|
+
import tempUploadHandler from './tempUploadHandler.js';
|
|
15
18
|
|
|
16
19
|
const resolveUserRemoteAddress = (req: FastifyRequest) => {
|
|
17
20
|
const remoteAddress =
|
|
@@ -25,8 +28,10 @@ const resolveUserRemoteAddress = (req: FastifyRequest) => {
|
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
const {
|
|
31
|
+
MCP_API_PATH = '/mcp',
|
|
28
32
|
GRAPHQL_API_PATH = '/graphql',
|
|
29
33
|
BULK_IMPORT_API_PATH = '/bulk-import',
|
|
34
|
+
TEMP_UPLOAD_API_PATH = '/temp-upload',
|
|
30
35
|
ERC_METADATA_API_PATH = '/erc-metadata/:productId/:localeOrTokenFilename/:tokenFileName?',
|
|
31
36
|
UNCHAINED_COOKIE_NAME = 'unchained_token',
|
|
32
37
|
UNCHAINED_COOKIE_PATH = '/',
|
|
@@ -112,7 +117,11 @@ export const connect = (
|
|
|
112
117
|
{
|
|
113
118
|
graphqlHandler,
|
|
114
119
|
db,
|
|
115
|
-
}: {
|
|
120
|
+
}: {
|
|
121
|
+
graphqlHandler: YogaServerInstance<any, any>;
|
|
122
|
+
db: mongodb.Db;
|
|
123
|
+
unchainedAPI: UnchainedCore;
|
|
124
|
+
},
|
|
116
125
|
{
|
|
117
126
|
allowRemoteToLocalhostSecureCookies = false,
|
|
118
127
|
}: { allowRemoteToLocalhostSecureCookies?: boolean } = {},
|
|
@@ -123,9 +132,13 @@ export const connect = (
|
|
|
123
132
|
fastify.addHook('preHandler', async function (request) {
|
|
124
133
|
request.headers['x-forwarded-proto'] = 'https';
|
|
125
134
|
});
|
|
126
|
-
fastify.addHook('onSend', async function (
|
|
135
|
+
fastify.addHook('onSend', async function (req, reply) {
|
|
127
136
|
reply.headers({
|
|
128
137
|
'Access-Control-Allow-Private-Network': 'true',
|
|
138
|
+
'Access-Control-Allow-Origin': req.headers.origin || '*',
|
|
139
|
+
'Access-Control-Allow-Credentials': 'true',
|
|
140
|
+
'Access-Control-Allow-Methods': ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'].join(', '),
|
|
141
|
+
'Access-Control-Allow-Headers': req.headers['access-control-request-headers'] || '*',
|
|
129
142
|
});
|
|
130
143
|
});
|
|
131
144
|
}
|
|
@@ -190,6 +203,23 @@ export const connect = (
|
|
|
190
203
|
handler: ercMetadataHandler,
|
|
191
204
|
});
|
|
192
205
|
|
|
206
|
+
fastify.route({
|
|
207
|
+
url: MCP_API_PATH,
|
|
208
|
+
method: ['GET', 'POST', 'DELETE'],
|
|
209
|
+
handler: mcpHandler,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
fastify.register((s, opts, registered) => {
|
|
213
|
+
s.register(fastifyMultipart);
|
|
214
|
+
s.route({
|
|
215
|
+
url: TEMP_UPLOAD_API_PATH,
|
|
216
|
+
method: ['POST'],
|
|
217
|
+
bodyLimit: 1024 * 1024 * 35, // 35MB
|
|
218
|
+
handler: tempUploadHandler,
|
|
219
|
+
});
|
|
220
|
+
registered();
|
|
221
|
+
});
|
|
222
|
+
|
|
193
223
|
fastify.register((s, opts, registered) => {
|
|
194
224
|
s.removeAllContentTypeParsers();
|
|
195
225
|
s.addContentTypeParser('*', function (req, payload, done) {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
+
import { Context } from '../context.js';
|
|
3
|
+
import { FastifyRequest, RouteHandlerMethod } from 'fastify';
|
|
4
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
5
|
+
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import createMcpServer from '../mcp/index.js';
|
|
7
|
+
|
|
8
|
+
const logger = createLogger('unchained:mcp-handler');
|
|
9
|
+
|
|
10
|
+
const transports: Record<string, StreamableHTTPServerTransport> = {};
|
|
11
|
+
|
|
12
|
+
const mcpHandler: RouteHandlerMethod = async (
|
|
13
|
+
req: FastifyRequest & { unchainedContext: Context },
|
|
14
|
+
res,
|
|
15
|
+
) => {
|
|
16
|
+
if (!req.unchainedContext.user) {
|
|
17
|
+
res.status(401);
|
|
18
|
+
res.header(
|
|
19
|
+
'WWW-Authenticate',
|
|
20
|
+
`Bearer realm="Unchained MCP", error="invalid_token", resource="${process.env.ROOT_URL || 'http://localhost:4010'}",`,
|
|
21
|
+
);
|
|
22
|
+
return res.send(
|
|
23
|
+
JSON.stringify({
|
|
24
|
+
error: 'invalid_token',
|
|
25
|
+
resource_metadata: `${process.env.ROOT_URL || 'http://localhost:4010'}/.well-known/oauth-protected-resource`,
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
if (req.method === 'POST') {
|
|
32
|
+
const sessionId = req.headers['mcp-session-id'] as string | undefined;
|
|
33
|
+
|
|
34
|
+
let transport: StreamableHTTPServerTransport;
|
|
35
|
+
|
|
36
|
+
if (sessionId && transports[sessionId]) {
|
|
37
|
+
// Reuse existing transport
|
|
38
|
+
transport = transports[sessionId];
|
|
39
|
+
} else if (!sessionId && isInitializeRequest(req.body)) {
|
|
40
|
+
// New initialization request
|
|
41
|
+
transport = new StreamableHTTPServerTransport({
|
|
42
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
43
|
+
onsessioninitialized: (sessionId) => {
|
|
44
|
+
// Store the transport by session ID
|
|
45
|
+
transports[sessionId] = transport;
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Clean up transport when closed
|
|
50
|
+
transport.onclose = () => {
|
|
51
|
+
if (transport.sessionId) {
|
|
52
|
+
delete transports[transport.sessionId];
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const roles = req.unchainedContext.user.roles || [];
|
|
57
|
+
const server = createMcpServer(req.unchainedContext, roles);
|
|
58
|
+
await server.connect(transport);
|
|
59
|
+
} else {
|
|
60
|
+
// Invalid request
|
|
61
|
+
res.status(400);
|
|
62
|
+
return res.send(
|
|
63
|
+
JSON.stringify({
|
|
64
|
+
jsonrpc: '2.0',
|
|
65
|
+
error: {
|
|
66
|
+
code: -32000,
|
|
67
|
+
message: 'Bad Request: No valid session ID provided',
|
|
68
|
+
},
|
|
69
|
+
id: null,
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await transport.handleRequest(req.raw, res.raw, req.body);
|
|
75
|
+
return res;
|
|
76
|
+
} else if (req.method === 'GET' || req.method === 'DELETE') {
|
|
77
|
+
const sessionId = req.headers['mcp-session-id'] as string | undefined;
|
|
78
|
+
if (!sessionId || !transports[sessionId]) {
|
|
79
|
+
res.status(400).send('Invalid or missing session ID');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const transport = transports[sessionId];
|
|
84
|
+
await transport.handleRequest(req.raw, res.raw);
|
|
85
|
+
return res;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
res.status(405);
|
|
89
|
+
return res.send('Method Not Allowed');
|
|
90
|
+
} catch (e) {
|
|
91
|
+
logger.error(e.message);
|
|
92
|
+
res.status(503);
|
|
93
|
+
return res.send(JSON.stringify({ name: e.name, code: e.code, message: e.message }));
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export default mcpHandler;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createLogger } from '@unchainedshop/logger';
|
|
2
|
+
import { getFileAdapter } from '@unchainedshop/core-files';
|
|
3
|
+
import { checkAction } from '../acl.js';
|
|
4
|
+
import { actions } from '../roles/index.js';
|
|
5
|
+
import { Context } from '../context.js';
|
|
6
|
+
import { FastifyRequest, RouteHandlerMethod } from 'fastify';
|
|
7
|
+
|
|
8
|
+
const logger = createLogger('unchained:temp-upload');
|
|
9
|
+
|
|
10
|
+
const tempUploadHandler: RouteHandlerMethod = async (
|
|
11
|
+
req: FastifyRequest & { file: any; unchainedContext: Context },
|
|
12
|
+
res,
|
|
13
|
+
) => {
|
|
14
|
+
try {
|
|
15
|
+
const context = req.unchainedContext;
|
|
16
|
+
|
|
17
|
+
await checkAction(context, (actions as any).uploadTempFile);
|
|
18
|
+
|
|
19
|
+
const data = await req.file();
|
|
20
|
+
|
|
21
|
+
const file = await context.services.files.uploadFileFromStream({
|
|
22
|
+
directoryName: 'temp-uploads',
|
|
23
|
+
rawFile: Promise.resolve({
|
|
24
|
+
filename: data.filename,
|
|
25
|
+
createReadStream: () => data.file,
|
|
26
|
+
mimetype: data.mimetype,
|
|
27
|
+
}),
|
|
28
|
+
meta: { fieldname: data.fieldname, encoding: data.encoding },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Add an expiration date to this file manually!
|
|
32
|
+
const expires = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
|
33
|
+
await context.modules.files.update(file._id, {
|
|
34
|
+
expires, // Default to 1 hour
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const fileUploadAdapter = getFileAdapter();
|
|
38
|
+
const rawUrl = await fileUploadAdapter.createDownloadURL(file);
|
|
39
|
+
const url = context.modules.files.normalizeUrl(rawUrl, {});
|
|
40
|
+
const body = JSON.stringify({ fileId: file._id, url, expires: expires.toISOString() });
|
|
41
|
+
res.status(200);
|
|
42
|
+
res.header('Content-Length', Buffer.byteLength(body));
|
|
43
|
+
res.header('Content-Type', 'application/json');
|
|
44
|
+
return res.send(body);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
logger.error(e.message);
|
|
47
|
+
res.status(503);
|
|
48
|
+
return res.send(JSON.stringify({ name: e.name, code: e.code, message: e.message }));
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default tempUploadHandler;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { UnchainedCore } from '@unchainedshop/core';
|
|
2
2
|
import { AssortmentMediaText } from '@unchainedshop/core-assortments';
|
|
3
3
|
import DataLoader from 'dataloader';
|
|
4
|
-
import { buildLocaleMap } from './utils.js';
|
|
5
4
|
import buildTextMap from './buildTextMap.js';
|
|
5
|
+
import buildLocaleMap from './buildLocaleMap.js';
|
|
6
6
|
|
|
7
7
|
export default (unchainedAPI: UnchainedCore) =>
|
|
8
8
|
new DataLoader<{ assortmentMediaId: string; locale: Intl.Locale }, AssortmentMediaText>(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { UnchainedCore } from '@unchainedshop/core';
|
|
2
2
|
import { AssortmentText } from '@unchainedshop/core-assortments';
|
|
3
3
|
import DataLoader from 'dataloader';
|
|
4
|
-
import { buildLocaleMap } from './utils.js';
|
|
5
4
|
import buildTextMap from './buildTextMap.js';
|
|
5
|
+
import buildLocaleMap from './buildLocaleMap.js';
|
|
6
6
|
|
|
7
7
|
export default (unchainedAPI: UnchainedCore) =>
|
|
8
8
|
new DataLoader<{ assortmentId: string; locale: Intl.Locale }, AssortmentText>(async (queries) => {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import buildLocaleMap from './buildLocaleMap.js';
|
|
4
|
+
|
|
5
|
+
const testTexts = [
|
|
6
|
+
// 1 has translations in French and German
|
|
7
|
+
{ locale: 'fr', _id: '1', entityId: '1' },
|
|
8
|
+
{ locale: 'de', _id: '2', entityId: '1' },
|
|
9
|
+
|
|
10
|
+
// 2 only has Ialien translations
|
|
11
|
+
{ locale: 'it', _id: '3', entityId: '2' },
|
|
12
|
+
|
|
13
|
+
// 3 only has English translations
|
|
14
|
+
{ locale: 'en', _id: '4', entityId: '3' },
|
|
15
|
+
|
|
16
|
+
// 4 only has German translations
|
|
17
|
+
{ locale: 'de', _id: '5', entityId: '4' },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
describe('buildLocaleMap', () => {
|
|
21
|
+
it('Mixed usage of default locale and forced languages', () => {
|
|
22
|
+
const queries = [
|
|
23
|
+
{ locale: new Intl.Locale('de-CH') },
|
|
24
|
+
{ locale: new Intl.Locale('fr') },
|
|
25
|
+
{ locale: new Intl.Locale('it') },
|
|
26
|
+
];
|
|
27
|
+
const expected = {
|
|
28
|
+
de: ['de-CH', 'fr', 'it'],
|
|
29
|
+
fr: ['fr'],
|
|
30
|
+
it: ['it'],
|
|
31
|
+
};
|
|
32
|
+
const result = buildLocaleMap(queries, testTexts);
|
|
33
|
+
assert.deepStrictEqual(result, expected);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('Mixed usage of forced languages', () => {
|
|
37
|
+
const queries = [{ locale: new Intl.Locale('fr') }, { locale: new Intl.Locale('it') }];
|
|
38
|
+
const expected = {
|
|
39
|
+
de: ['fr', 'it'],
|
|
40
|
+
fr: ['fr'],
|
|
41
|
+
it: ['it'],
|
|
42
|
+
};
|
|
43
|
+
const result = buildLocaleMap(queries, testTexts);
|
|
44
|
+
assert.deepStrictEqual(result, expected);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('Only default locale', () => {
|
|
48
|
+
const queries = [{ locale: new Intl.Locale('de-CH') }];
|
|
49
|
+
const expected = {
|
|
50
|
+
de: ['de-CH'],
|
|
51
|
+
};
|
|
52
|
+
const result = buildLocaleMap(queries, testTexts);
|
|
53
|
+
assert.deepStrictEqual(result, expected);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('Only one forced language locale', () => {
|
|
57
|
+
const queries = [{ locale: new Intl.Locale('fr') }];
|
|
58
|
+
const expected = {
|
|
59
|
+
fr: ['fr'],
|
|
60
|
+
de: ['fr'],
|
|
61
|
+
};
|
|
62
|
+
const result = buildLocaleMap(queries, testTexts);
|
|
63
|
+
assert.deepStrictEqual(result, expected);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { systemLocale } from '@unchainedshop/utils';
|
|
2
|
+
|
|
3
|
+
function getLocaleStrings(locale: Intl.Locale): string[] {
|
|
4
|
+
try {
|
|
5
|
+
const locales = new Set<string>();
|
|
6
|
+
locales.add(locale.baseName);
|
|
7
|
+
locales.add(locale.language);
|
|
8
|
+
locales.add(systemLocale.baseName);
|
|
9
|
+
locales.add(systemLocale.language);
|
|
10
|
+
return Array.from(locales);
|
|
11
|
+
} catch {
|
|
12
|
+
// Optimized Set creation and spread
|
|
13
|
+
const locales = new Set<string>();
|
|
14
|
+
locales.add(systemLocale.baseName);
|
|
15
|
+
locales.add(systemLocale.language);
|
|
16
|
+
return Array.from(locales);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export default function buildLocaleMap(
|
|
20
|
+
queries: readonly { locale: Intl.Locale }[],
|
|
21
|
+
texts: readonly { locale?: string }[],
|
|
22
|
+
): Record<string, string[]> {
|
|
23
|
+
// key = texts.locale
|
|
24
|
+
// value = input query locale
|
|
25
|
+
const queryLocales = new Set(queries.map((q) => q.locale));
|
|
26
|
+
const textLocales = new Set(texts.map((t) => t.locale));
|
|
27
|
+
const localeMap: Record<string, string[]> = {};
|
|
28
|
+
for (const queryLocale of queryLocales) {
|
|
29
|
+
const potentialMatches = getLocaleStrings(queryLocale);
|
|
30
|
+
const matches = potentialMatches.filter((l) => textLocales.has(l));
|
|
31
|
+
for (const match of matches) {
|
|
32
|
+
if (!localeMap[match]) localeMap[match] = [];
|
|
33
|
+
localeMap[match].push(queryLocale.toString());
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return localeMap;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// import { systemLocale } from '@unchainedshop/utils';
|
|
40
|
+
|
|
41
|
+
// export function getLocaleStrings(locale: Intl.Locale) {
|
|
42
|
+
// try {
|
|
43
|
+
// return [
|
|
44
|
+
// ...new Set([locale.baseName, locale.language, systemLocale.baseName, systemLocale.language]),
|
|
45
|
+
// ];
|
|
46
|
+
// } catch {
|
|
47
|
+
// return [...new Set([systemLocale.baseName, systemLocale.language])];
|
|
48
|
+
// }
|
|
49
|
+
// }
|
|
50
|
+
|
|
51
|
+
// export function buildLocaleMap(
|
|
52
|
+
// queries: readonly { locale: Intl.Locale }[],
|
|
53
|
+
// texts: readonly { locale?: string }[],
|
|
54
|
+
// ): Record<string, string[]> {
|
|
55
|
+
// // key = texts.locale
|
|
56
|
+
// // value = input query locale
|
|
57
|
+
|
|
58
|
+
// const queryLocales = Object.values(
|
|
59
|
+
// Object.fromEntries(queries.map((q) => [q.locale.baseName, q.locale])),
|
|
60
|
+
// );
|
|
61
|
+
|
|
62
|
+
// const textLocales: string[] = [...new Set(texts.map((t) => t.locale))];
|
|
63
|
+
// const localeMap = {};
|
|
64
|
+
// for (const queryLocale of queryLocales) {
|
|
65
|
+
// const potentialMatches = getLocaleStrings(queryLocale);
|
|
66
|
+
// const matches = potentialMatches.filter((l) => textLocales.includes(l));
|
|
67
|
+
// for (const match of matches) {
|
|
68
|
+
// if (!localeMap[match]) localeMap[match] = [];
|
|
69
|
+
// localeMap[match].push(queryLocale);
|
|
70
|
+
// }
|
|
71
|
+
// }
|
|
72
|
+
// return localeMap;
|
|
73
|
+
// }
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import buildTextMap from './buildTextMap.js';
|
|
4
|
+
|
|
5
|
+
const testTexts = [
|
|
6
|
+
// 1 has translations in French and German
|
|
7
|
+
{ locale: 'fr', _id: 'french-1', entityId: '1' },
|
|
8
|
+
{ locale: 'de', _id: 'german-1', entityId: '1' },
|
|
9
|
+
|
|
10
|
+
// 2 only has Ialien translations
|
|
11
|
+
{ locale: 'it', _id: 'italian-2', entityId: '2' },
|
|
12
|
+
|
|
13
|
+
// 3 only has English translations
|
|
14
|
+
{ locale: 'en', _id: 'english-3', entityId: '3' },
|
|
15
|
+
|
|
16
|
+
// 4 only has German translations
|
|
17
|
+
{ locale: 'de', _id: 'german-4', entityId: '4' },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
describe('buildTextMap', () => {
|
|
21
|
+
it('Generate a correct text map for all fallbacks', () => {
|
|
22
|
+
const localeMap = {
|
|
23
|
+
de: ['de-CH', 'fr', 'it'],
|
|
24
|
+
fr: ['fr'],
|
|
25
|
+
it: ['it'],
|
|
26
|
+
};
|
|
27
|
+
const expected = {
|
|
28
|
+
'de-CH1': {
|
|
29
|
+
_id: 'german-1',
|
|
30
|
+
},
|
|
31
|
+
fr1: {
|
|
32
|
+
_id: 'french-1',
|
|
33
|
+
},
|
|
34
|
+
it1: {
|
|
35
|
+
_id: 'german-1',
|
|
36
|
+
},
|
|
37
|
+
'de-CH4': {
|
|
38
|
+
_id: 'german-4',
|
|
39
|
+
},
|
|
40
|
+
fr4: {
|
|
41
|
+
_id: 'german-4',
|
|
42
|
+
},
|
|
43
|
+
it4: {
|
|
44
|
+
_id: 'german-4',
|
|
45
|
+
},
|
|
46
|
+
it2: {
|
|
47
|
+
_id: 'italian-2',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const result = buildTextMap(localeMap, testTexts, (text) => text.entityId);
|
|
51
|
+
|
|
52
|
+
assert.partialDeepStrictEqual(result, expected);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
type ArrayElement<T> = T extends (infer U)[] ? U : never;
|
|
2
2
|
|
|
3
|
+
/* This file has been optimized for performance to the last drop. Don't refactor! */
|
|
4
|
+
|
|
3
5
|
export default function buildTextMap<T extends { locale?: string }[]>(
|
|
4
6
|
localeMap: Record<string, string[]>,
|
|
5
7
|
texts: Readonly<T>,
|
|
6
8
|
buildId: (item: ArrayElement<T>) => string,
|
|
7
9
|
) {
|
|
8
|
-
const textsMap = {};
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const textsMap: Record<string, ArrayElement<T>> = {}; // Added type for textsMap
|
|
11
|
+
const localeMapKeys = Object.keys(localeMap);
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line
|
|
14
|
+
for (let i = 0; i < localeMapKeys.length; i++) {
|
|
15
|
+
const originLocale = localeMapKeys[i];
|
|
16
|
+
const localesForText = localeMap[originLocale];
|
|
17
|
+
|
|
18
|
+
// eslint-disable-next-line
|
|
19
|
+
for (let j = 0; j < texts.length; j++) {
|
|
20
|
+
const text = texts[j];
|
|
11
21
|
if (originLocale !== text.locale) continue;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
|
|
23
|
+
const idPart = buildId(text as ArrayElement<T>); // Ensured correct type for buildId argument
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line
|
|
26
|
+
for (let k = 0; k < localesForText.length; k++) {
|
|
27
|
+
const locale = localesForText[k];
|
|
28
|
+
const key = locale + idPart;
|
|
29
|
+
if (textsMap[key] && locale !== text.locale) {
|
|
30
|
+
// If the key already exists and the locale is a fallback, skip this text
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
textsMap[key] = text as ArrayElement<T>; // Ensured correct type for assignment
|
|
15
34
|
}
|
|
16
35
|
}
|
|
17
36
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UnchainedCore } from '@unchainedshop/core';
|
|
2
2
|
import DataLoader from 'dataloader';
|
|
3
|
-
import
|
|
3
|
+
import buildLocaleMap from './buildLocaleMap.js';
|
|
4
4
|
import { FilterText } from '@unchainedshop/core-filters';
|
|
5
5
|
import buildTextMap from './buildTextMap.js';
|
|
6
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UnchainedCore } from '@unchainedshop/core';
|
|
2
2
|
import DataLoader from 'dataloader';
|
|
3
|
-
import { buildLocaleMap } from './utils.js';
|
|
4
3
|
import { ProductMediaText } from '@unchainedshop/core-products';
|
|
4
|
+
import buildLocaleMap from './buildLocaleMap.js';
|
|
5
5
|
import buildTextMap from './buildTextMap.js';
|
|
6
6
|
|
|
7
7
|
export default (unchainedAPI: UnchainedCore) =>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { UnchainedCore } from '@unchainedshop/core';
|
|
2
2
|
import DataLoader from 'dataloader';
|
|
3
|
-
import { buildLocaleMap } from './utils.js';
|
|
4
3
|
import { ProductText } from '@unchainedshop/core-products';
|
|
5
4
|
import buildTextMap from './buildTextMap.js';
|
|
5
|
+
import buildLocaleMap from './buildLocaleMap.js';
|
|
6
6
|
|
|
7
7
|
export default (unchainedAPI: UnchainedCore) =>
|
|
8
8
|
new DataLoader<{ productId: string; locale: Intl.Locale }, ProductText>(async (queries) => {
|