├── .gitignore ├── .npmignore ├── .npmrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── src ├── app.d.ts ├── app.html ├── index.test.ts └── lib │ └── index.ts ├── svelte.config.js ├── tsconfig.json ├── vite.config.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /dist 5 | /.svelte-kit 6 | /package 7 | .env 8 | .env.* 9 | !.env.example 10 | vite.config.js.timestamp-* 11 | vite.config.ts.timestamp-* 12 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .svelte-kit 2 | node_modules 3 | src 4 | .DS_Store 5 | jsconfig.json 6 | package-lock.json 7 | yarn.lock 8 | svelte.config.js 9 | vite.config.js 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 3.1.2 4 | 5 | ### Patch Changes 6 | 7 | - Removed client option 'disableCache' from interface definition to avoid confuction since it is no longer used. Cache is not enabled by default and is instead enabled when a function is called for that specific function call. 8 | 9 | ## 3.1.1 10 | 11 | ### Patch Changes 12 | 13 | - Added cache option: revalidate If a cache key is passed and revalidate is set to true, this will cause the query to pull fresh data, cache the new data, and update the ttl. 14 | 15 | ## 3.1.0 16 | 17 | ### Patch Changes 18 | 19 | - Caching API change: Caching is no longer set at the client/class level. Caching is now enabled by passing a key string in the options for particular functions that support caching. The key is the unique identifier for that particular query response. Optionally, you can also pass a ttl. The ttl is the max age of the cache in milliseconds. The default ttl is 1000. See the latest README for more information. 20 | 21 | The list of functions that support caching: 22 | 23 | ```js 24 | getSearchResults(q:string, cacheOptions?:CacheOptions) 25 | getProducts(options?:ProductRetrievalOptions, cacheOptions?:CacheOptions) 26 | getCollections(options?:CollectionRetrievalOptions, cacheOptions?:CacheOptions) 27 | getCollection(handle:string, cacheOptions?:CacheOptions) 28 | getCollectionProducts(id:string, options?:ProductRetrievalOptions, cacheOptions?:CacheOptions) 29 | getProduct(handle:string, cacheOptions?:CacheOptions) 30 | getReviews(productId:string, options?:ReviewRetrievalOptions, cacheOptions?:CacheOptions) 31 | ``` 32 | 33 | Example: To enable caching for the getProduct function (`medusa.getProduct(handle)`), call the function like this: 34 | 35 | ```js 36 | let product = await medusa.getProduct(handle, { key: `${params.slug}_product`, ttl: 10000 }) 37 | ``` 38 | 39 | ## 3.0.0 40 | 41 | ### Patch Changes 42 | 43 | - Fix: No more ts warning about type mismatch when not using custom headers (by @ellicodan) 44 | - Chore: Update sveltekit-superfetch dependency to ^3.0 45 | - Feat: Enabled caching of product, collection, and search requests by default. To disable, in options object set 'disableCache' to true. 46 | 47 | ## 2.0.2 48 | 49 | ### Patch Changes 50 | 51 | - Fix: Bug in 2.0 that caused the login function to return 'true' even though the auth failed and the user was not logged in (session cookie not set). This bug did not affect access but could cause UX issues in the login flow. 52 | 53 | ## 2.0.0 54 | 55 | ### Patch Changes 56 | 57 | - Chore: Bumped sveltekit-superfetch dependency to ^2.0. This changed the syntax slightly for sending queries, which you should only notice if you were using the public query() method directly. 58 | - Feat: Enabled optional logging. You can inject a winston logger or other logger instance into the MedusaClient constructor. If 'debug' is set to true but no logger instance is passed, console will be used by default. See updated docs. 59 | 60 | ## 1.13.2 61 | 62 | ### Patch Changes 63 | 64 | - Fix: Update User interface to make phone property optional 65 | 66 | ## 1.13.0 67 | 68 | ### Patch Changes 69 | 70 | - Feat: Added typing for product-related functions. Will add typing for Users, Carts, and other return values as Medusa team moves them over to @medusajs/types package. 71 | - Fix: Bug where getCart function could return a cart that had been completed on a different device if persistentCart was set to true in certain situations. 72 | - Chore: Versioning changed. Version numbers will now follow semantic versioning and no longer mirror medusa backend versioning. 73 | 74 | ## 1.12.1-c 75 | 76 | ### Patch Changes 77 | 78 | - Chore: Compatibility with latest medusa-plugin-ratings v1.3 79 | 80 | ## 1.12.1-b 81 | 82 | ### Patch Changes 83 | 84 | - Chore: Bump versions on all dependencies to latest 85 | 86 | ## 1.12.1 87 | 88 | ### Patch Changes 89 | 90 | - Fix: Update method of parsing set-cookie headers to account for other headers being set other than the Medusa connect.sid session header 91 | 92 | ## 1.12.0-b 93 | 94 | ### Patch Changes 95 | 96 | - Fix: getCustomer function: Move fetch request to get customer session back inside try block to enable smoother error handling. It was left outside of the block by accident after debugging. 97 | - Fix: Bug with new persistent cart feature that caused an error when user logged in and did not already have any cart sessions 98 | - Fix: Bug in the first login after registering a user that caused register to return false even though it was successful 99 | 100 | ## 1.12.0 101 | 102 | ### Patch Changes 103 | 104 | - Feat: Session cookie expiration now matches any custom ttl set in medusa.config.js 105 | - Feat: Session cookie now supports rolling:true (refresh) session option in medusa.config.js 106 | - Feat: Options object passed to constructor now supports custom timeout (in milliseconds) and retry settings. 107 | - Feat: Options object passed to contructor can now include persistentCart (bool) which if true will attempt to load customer's existing cart across multiple browsers or devices. This requires a custom API route to work (/store/customer/me/cart) and defaults to false. The API route should take the general form of: 108 | ``` 109 | router.use("/store/customers/me/cart", authenticateCustomer()) 110 | router.get("/store/customers/me/cart", cors(storeCorsOptions), async (req, res) => { 111 | if (req.user && req.user.customer_id) { 112 | const cartService = req.scope.resolve("cartService") 113 | const cart = await cartService.retrieveByCustomerId(req.user.customer_id) 114 | return res.json({ cart }) 115 | } else { 116 | return res.status(404).json({ cart: null }) 117 | } 118 | }) 119 | ``` 120 | 121 | ## 1.11.0-b 122 | 123 | ### Patch Changes 124 | 125 | - Feat: Added retrieval options for products and collections (limit, offset, etc.). These match the API options available for each entity. 126 | - Chore: getAllProducts() renamed to getProducts() 127 | 128 | ## 1.11.0 129 | 130 | ### Patch Changes 131 | 132 | - Fix: getProduct() will return null and not throw an error if product not found 133 | - Feat: add ability to pass a second 'options' argument to the contructor. If present, this argument must be an object. For now, the only handled property of options is 'headers', which can be an object of custom headers to be sent with each fetch request to the Medusa server. These headers will be in addition to, and will not replace, the session cookie and content type headers the client already sends. For example, if your Medusa server sits behind a cloudflared tunnel with access key security, you can now pass an additional header with the access key through the client. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Lacey Pevey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sveltekit-medusa-client 2 | 3 | A client library for communicating with a Medusa ecommerce backend in SvelteKit 4 | 5 | [Documentation](https://pevey.com/sveltekit-medusa-client) 6 | 7 | If you are not familiar with Medusa, you can learn more on [the project web site](https://www.medusajs.com/). 8 | 9 | > Medusa is a set of commerce modules and tools that allow you to build rich, reliable, and performant commerce applications without reinventing core commerce logic. The modules can be customized and used to build advanced ecommerce stores, marketplaces, or any product that needs foundational commerce primitives. All modules are open-source and freely available on npm. 10 | 11 | This client is designed to be used on the server. It cannot be exported to the browser. This means you must make your calls to your Medusa backend from your storefront server, not from the client browser. Calls to the library can be made from: 12 | 13 | * A handler in `hooks.server.js/ts` 14 | * A page load function in `+page.server.js/ts` 15 | * A form action in `+page.server.js/ts`, or 16 | * An API endpoint, aka `+server.js/ts` 17 | 18 | One of the benefits of newer frameworks like SvelteKit is that they combine the fluid user experience of client-side reactivity with the ability to handle logic on the server when you choose to. Keeping your Medusa backend firewalled and accessible only to your storefront application server provides an additional layer of security versus having your backend directly exposed. This type of deployment also allows us to use tools like Turnstile or reCAPTCHA to provide some protection against bots and brute force attacks. Without firewalling your backend, it would not be of much use to implement turnstile protection on your frontend. It could easily be bypassed. 19 | 20 | ## Example Project 21 | 22 | You can view an example project using this client library [here](https://github.com/pevey/sveltekit-medusa-starter). 23 | 24 | ## Installation 25 | 26 | Create a new SvelteKit app if needed. Then, install this package. 27 | 28 | ```bash 29 | 30 | yarn add sveltekit-medusa-client 31 | 32 | ``` 33 | 34 | You should set the location of your Medusa server as an environment variable. For example: 35 | 36 | `.env` 37 | 38 | ```bash 39 | MEDUSA_BACKEND_URL="http://localhost:9000" 40 | ``` 41 | 42 | ## Basic Usage 43 | 44 | To create a new client, invoke the MedusaClient constructor, passsing the location of your Medusa server as an argument. For example: 45 | 46 | `+page.server.js` 47 | 48 | ```js 49 | import { MedusaClient } from 'sveltekit-medusa-client' 50 | import { MEDUSA_BACKEND_URL } from '$env/static/private' 51 | 52 | export const load = async function () { 53 | const medusa = new MedusaClient(MEDUSA_BACKEND_URL) 54 | return { 55 | products: medusa.getProducts() 56 | } 57 | } 58 | ``` 59 | 60 | Then, on the corresponding `+page.svelte`, you can use the products data you exported: 61 | (For more information on the data returned, refer to the [Medusa API Documentation](https://docs.medusajs.com/api/store#tag/Products/operation/GetProducts)) 62 | 63 | ```svelte 64 | 68 | 69 |