{"_id":"@dukerupert/sveltekit-medusa-client","name":"@dukerupert/sveltekit-medusa-client","dist-tags":{"latest":"3.1.2"},"versions":{"3.1.2":{"name":"@dukerupert/sveltekit-medusa-client","version":"3.1.2","description":"A client library for communicating with a Medusa ecommerce backend from a SvelteKit storefront","repository":{"type":"git","url":"git+https://github.com/dukerupert/sveltekit-medusa-client.git"},"author":{"name":"Logan Williams"},"license":"MIT","keywords":["svelte","sveltekit","medusa","ecommerce","client","headless commerce","medusa-plugin"],"scripts":{"dev":"vite dev","build":"shx rm -rf ./dist && vite build && npm run package","preview":"vite preview","package":"svelte-kit sync && svelte-package && publint","prepublishOnly":"npm run package","check":"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json","check:watch":"svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch","test":"vitest"},"exports":{".":{"types":"./dist/index.d.ts","svelte":"./dist/index.js"}},"publishConfig":{"access":"public"},"peerDependencies":{"svelte":"^4.0.0"},"devDependencies":{"@sveltejs/adapter-auto":"^2.0.0","@sveltejs/kit":"^1.25.0","@sveltejs/package":"^2.2.2","publint":"^0.2.2","shx":"^0.3.4","svelte":"^4.2.1","svelte-check":"^3.5.2","tslib":"^2.6.2","typescript":"^5.2.2","vite":"^4.4.2","vitest":"^0.34.5"},"dependencies":{"@medusajs/types":"^1.11.1","sveltekit-superfetch":"^3.0.2"},"svelte":"./dist/index.js","types":"./dist/index.d.ts","type":"module","_id":"@dukerupert/sveltekit-medusa-client@3.1.2","gitHead":"1aa4c86a16598d6c567ac5e1fbe9ac78b5a57ac7","bugs":{"url":"https://github.com/dukerupert/sveltekit-medusa-client/issues"},"homepage":"https://github.com/dukerupert/sveltekit-medusa-client#readme","_nodeVersion":"20.8.1","_npmVersion":"10.1.0","dist":{"integrity":"sha512-24XlBmZx89B3AwlsBQYU7tvc8Hak2lJqwqPK1OvG9sQVGCpLTPeh+wcoraREc0wtwgo65kyAEB6KgBflOFVjbw==","shasum":"cedce2356c582edce0f2447f3fb8b603aa6bf131","tarball":"https://registry.npmjs.org/@dukerupert/sveltekit-medusa-client/-/sveltekit-medusa-client-3.1.2.tgz","fileCount":5,"unpackedSize":39143,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBkCcNDGrdm1KJwdNUpTg1CHZLkdAzzJvmjI0DiEPLg/AiEAoffwB85CcOb1vbitpxOYK0/qkOqdg1OpOMaR2aODPVs="}]},"_npmUser":{"name":"dukerupert","email":"logan@fireflysoftware.dev"},"directories":{},"maintainers":[{"name":"dukerupert","email":"logan@fireflysoftware.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/sveltekit-medusa-client_3.1.2_1701373300425_0.629359331698242"},"_hasShrinkwrap":false}},"time":{"created":"2023-11-30T19:41:40.306Z","3.1.2":"2023-11-30T19:41:40.594Z","modified":"2023-11-30T19:41:40.878Z"},"maintainers":[{"name":"dukerupert","email":"logan@fireflysoftware.dev"}],"description":"A client library for communicating with a Medusa ecommerce backend from a SvelteKit storefront","homepage":"https://github.com/dukerupert/sveltekit-medusa-client#readme","keywords":["svelte","sveltekit","medusa","ecommerce","client","headless commerce","medusa-plugin"],"repository":{"type":"git","url":"git+https://github.com/dukerupert/sveltekit-medusa-client.git"},"author":{"name":"Logan Williams"},"bugs":{"url":"https://github.com/dukerupert/sveltekit-medusa-client/issues"},"license":"MIT","readme":"# sveltekit-medusa-client\n\nA client library for communicating with a Medusa ecommerce backend in SvelteKit\n\n[Documentation](https://pevey.com/sveltekit-medusa-client)\n\nIf you are not familiar with Medusa, you can learn more on [the project web site](https://www.medusajs.com/).\n\n> 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.\n\nThis 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:\n\n* A handler in `hooks.server.js/ts`\n* A page load function in `+page.server.js/ts`\n* A form action in `+page.server.js/ts`, or\n* An API endpoint, aka `+server.js/ts`\n\nOne 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.\n\n## Example Project\n\nYou can view an example project using this client library [here](https://github.com/pevey/sveltekit-medusa-starter).\n\n## Installation\n\nCreate a new SvelteKit app if needed.  Then, install this package.\n\n```bash\n\nyarn add sveltekit-medusa-client\n\n```\n\nYou should set the location of your Medusa server as an environment variable.  For example:\n\n`.env`\n\n```bash\nMEDUSA_BACKEND_URL=\"http://localhost:9000\"\n```\n\n## Basic Usage\n\nTo create a new client, invoke the MedusaClient constructor, passsing the location of your Medusa server as an argument.  For example:\n\n`+page.server.js`\n\n```js\nimport { MedusaClient } from 'sveltekit-medusa-client'\nimport { MEDUSA_BACKEND_URL } from '$env/static/private'\n\nexport const load = async function () {\n   const medusa = new MedusaClient(MEDUSA_BACKEND_URL)\n   return {\n      products: medusa.getProducts()\n   }\n}\n```\n\nThen, on the corresponding `+page.svelte`, you can use the products data you exported:\n(For more information on the data returned, refer to the [Medusa API Documentation](https://docs.medusajs.com/api/store#tag/Products/operation/GetProducts))\n\n```svelte\n<script>\n   export let data\n   const products = data.products  \n</script>\n\n<ul>\n{#each products as product}\n   <li>\n      Product id: {product.id}<br>\n      Product handle: {product.handle}<br>\n      {product.title}\n   </li>\n{:else}\n   <p>No products returned</p>\n{/each}\n<ul>\n```\n\n## Using the Client as a Singleton\n\nOne major drawback of the example above is that a new Medusa client is created for each page load.  \nYou can prevent that by adding a small library in your project that creates a single shared client that can be imported where needed.\nFor example:\n\n`lib/server/medusa.js`\n\n```js\nimport { MedusaClient } from 'sveltekit-medusa-client'\nimport { MEDUSA_BACKEND_URL } from '$env/static/private'\nexport default new MedusaClient(MEDUSA_BACKEND_URL)\n```\n\nNow, on our `+page.server.js` load function, we can do this:\n\n```js\nimport medusa from '$lib/server/medusa'\n\nexport const load = async function () {\n   return {\n      products: medusa.getProducts()\n   }\n}\n```\n\n## Client Options\n\nA number of options give some flexibility to the client.  The options object that can be injected in the client contructor takes this shape:\n\n```ts\nexport interface ClientOptions {\n   retry?: number\n   timeout?: number\n   headers?: {}\n   persistentCart?: boolean\n   logger?: Logger\n   logFormat?: 'text' | 'json' | 'majel'\n   logLevel?: 'verbose' | 'limited' | 'silent'\n   excludedPaths?: string[]\n   limitedPaths?: string[]\n}\n```\n\nFor example, you can create a new client instance like this:\n\n```js\nimport { MedusaClient } from 'sveltekit-medusa-client'\nimport { MEDUSA_BACKEND_URL, CLOUDFLARE_ACCESS_ID, CLOUDFLARE_ACCESS_SECRET } from '$env/static/private'\nexport default new MedusaClient(MEDUSA_BACKEND_URL, { \n   timeout: 3000, // 3 seconds\n   retry: 0,\n   headers: {\n      'CF-Access-Client-Id': CLOUDFLARE_ACCESS_ID,\n      'CF-Access-Client-Secret': CLOUDFLARE_ACCESS_SECRET,\n   },\n   persistentCart: true,\n   logger: console,\n   logFormat: 'json',\n   logLevel: 'verbose',\n   excludedPaths: ['/store/mycustomsensitiveroute'],\n   limitedPaths: ['/store/bulkyresponseroute']\n})\n```\n\n- `timeout` - The default is 8000, or 8 seconds.  The length of time to wait for a response before aborting \n- `retry` - The default is 3.  The number of times to retry a timed out request\n- `headers` - The default is undefined.  An object of HTTP headers, as many as you want, which will be added to all requests sent to the backend.  This can be useful in many situations.  If you would like to access a server behind a proxy with bearer auth, you can pass the auth header in this property.  You can also pass Cloudflare Access service auth credentials, as in the example above.\n- `persistentCart` - The default is false.  If true, the client will expect an endpoint at `/store/customers/me/cart` that will return the customer's cart.  For now, this endpoint is not included in the Medusa core and must be added.\n- `logger` - The default is `console`.  You can inject your own logger instance if you already have one configured in the application.  For example, a winston logger instance.  Any logger that implements the `info()` and `error()` methods should work.\n- `logFormat` - The default is json.  You can change to 'text' if you need to for some reason.\n- `excludedPaths` - The default is ['/store/auth'].  An array of strings that should be checked to exclude paths from logging.  The default can be added to, but not overridden.  Requests to URIs on your medusa backend that contain one or more of these strings will not be logged.  \n- `limitedPaths` - The default is undefined.  An array of strings that should be checked to reduce the level of detail when logging.  Requests to URIs on your medusa backend that contain one or more of these strings will not log request or response content, only metadata.  The url of the request will be logged, but not query params.\n\n## Authentication\n\nSome methods in the library, like the `getProducts` method in the example above, need no authentication.  Other methods need more context, such as whether the requester is a logged in user, or whether they have an existing shopping cart.  The first argument passed to those methods is the special SvelteKit `locals` object.  Locals on the server work much like a page or session store in the browser.  They are a place to hold on to data related to this particular request that we may need somewhere else in the application before this request/response cycle is complete.\n\nUse the middleware method `handleRequest` from this library to handle customer authentication on every request with very little effort.  If the user is logged in, the user object will be available at `locals.user.` Middleware is added in SvelteKit via the hooks.server.js/ts file:\n\n`hooks.server.js`\n\n```js\nimport medusa from '$lib/server/medusa'\n\nexport const handle = async ({ event, resolve }) => {\n   event = await medusa.handleRequest(event)\n   return await resolve(event)\n}\n```\n\nNow, we can invoke methods that require information about the user and the cart.\n\n`+page.server.js`\n\n```js\nimport medusa from '$lib/server/medusa'\n\nexport const load = async function ({ locals, cookies }) {\n   return {\n      cart: medusa.getCart(locals, cookies)\n   }\n}\n```\n\n## Caching\n\nCaching is enabled by passing a key string in the options for the 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.  \n\n### Caching Example\n\nTo enable caching on a call to the getProduct function (`medusa.getProduct(handle)`), call the function like this:\n\n```js\nlet product = await medusa.getProduct(handle, { key: `__${handle}__product`, ttl: 10000 })\n```\n\nBehind the scenes, the response will be cached in memory for the duration of the ttl.\n\n### Important Notes\n\n- Short cache times are recommended.  Even a short ttl can lead to a significant performance boost in your storefront application and reduction of load on your Medusa backend on high traffic sites.\n\n- The cache is stored in memory.  This is ideal in some scenarios, but not in memory-constrained environments or for especially large sites.\n\n- When deploying to a serverless platform, you will probably want to use something like Redis in your storefront application for caching and forgo the built-in cache option.\n\n### The Cache is a Shared, Server-Side Cache\n\n- Never attempt to cache cart or customer-specific information. Only functions that return data that can be safely shared across customers support cache options.\n\n- The list of functions that support caching:\n\n```js\ngetSearchResults(q:string, cacheOptions?:CacheOptions)\ngetProducts(options?:ProductRetrievalOptions, cacheOptions?:CacheOptions)\ngetCollections(options?:CollectionRetrievalOptions, cacheOptions?:CacheOptions)\ngetCollection(handle:string, cacheOptions?:CacheOptions)\ngetCollectionProducts(id:string, options?:ProductRetrievalOptions, cacheOptions?:CacheOptions)\ngetProduct(handle:string, cacheOptions?:CacheOptions)\ngetReviews(productId:string, options?:ReviewRetrievalOptions, cacheOptions?:CacheOptions)\n```\n\n### Make Sure Your Key is Unique\n\nKeys all share one namespace.  If you enable caching on multiple function calls, take care to ensure your keys will always be unique.\n\n### Cache Bypass\n\nTo bypass the cache and request fresh data, you can simply call the function again without a key.\n\n### Cache Bust\n\nTo cause the query to pull fresh data, cache the new data, and update the ttl, include `revalidate: true` in the cache options.  Example:\n\n```js\nlet product = await medusa.getProduct(handle, { \n   key: `__${handle}__product`, \n   ttl: 10000,\n   revalidate: true\n})\n```\n\n\n\n","readmeFilename":"README.md"}