From 845eda46438248b925015fe5c07b77eba0a0bc85 Mon Sep 17 00:00:00 2001 From: Stevche Radevski Date: Thu, 16 May 2024 12:30:32 +0200 Subject: [PATCH] feat: Create the Medusa API SDK as js-sdk package (#7276) --- .changeset/weak-cherries-lie.md | 5 + .eslintrc.js | 1 + packages/core/js-sdk/CHANGELOG.md | 0 packages/core/js-sdk/jest.config.js | 7 + packages/core/js-sdk/package.json | 40 +++ .../core/js-sdk/src/__tests__/client.spec.ts | 145 ++++++++++ packages/core/js-sdk/src/admin/index.ts | 8 + packages/core/js-sdk/src/client.ts | 183 +++++++++++++ packages/core/js-sdk/src/index.ts | 18 ++ packages/core/js-sdk/src/store/index.ts | 250 ++++++++++++++++++ packages/core/js-sdk/src/types.ts | 37 +++ packages/core/js-sdk/tsconfig.json | 28 ++ yarn.lock | 246 ++++++++++++++++- 13 files changed, 963 insertions(+), 5 deletions(-) create mode 100644 .changeset/weak-cherries-lie.md create mode 100644 packages/core/js-sdk/CHANGELOG.md create mode 100644 packages/core/js-sdk/jest.config.js create mode 100644 packages/core/js-sdk/package.json create mode 100644 packages/core/js-sdk/src/__tests__/client.spec.ts create mode 100644 packages/core/js-sdk/src/admin/index.ts create mode 100644 packages/core/js-sdk/src/client.ts create mode 100644 packages/core/js-sdk/src/index.ts create mode 100644 packages/core/js-sdk/src/store/index.ts create mode 100644 packages/core/js-sdk/src/types.ts create mode 100644 packages/core/js-sdk/tsconfig.json diff --git a/.changeset/weak-cherries-lie.md b/.changeset/weak-cherries-lie.md new file mode 100644 index 0000000000..48c9a97852 --- /dev/null +++ b/.changeset/weak-cherries-lie.md @@ -0,0 +1,5 @@ +--- +"@medusajs/js-sdk": patch +--- + +Introduce a js-sdk package for the Medusa API diff --git a/.eslintrc.js b/.eslintrc.js index e1bccc2377..5bbd25a6f0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -100,6 +100,7 @@ module.exports = { "./packages/core/orchestration/tsconfig.json", "./packages/core/workflows-sdk/tsconfig.spec.json", "./packages/core/modules-sdk/tsconfig.spec.json", + "./packages/core/js-sdk/tsconfig.spec.json", "./packages/core/types/tsconfig.spec.json", "./packages/core/utils/tsconfig.spec.json", "./packages/core/medusa-test-utils/tsconfig.spec.json", diff --git a/packages/core/js-sdk/CHANGELOG.md b/packages/core/js-sdk/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/core/js-sdk/jest.config.js b/packages/core/js-sdk/jest.config.js new file mode 100644 index 0000000000..c22bbc6965 --- /dev/null +++ b/packages/core/js-sdk/jest.config.js @@ -0,0 +1,7 @@ +module.exports = { + transform: { + "^.+\\.[jt]s?$": "@swc/jest", + }, + testEnvironment: `node`, + moduleFileExtensions: [`js`, `ts`, `json`], +} diff --git a/packages/core/js-sdk/package.json b/packages/core/js-sdk/package.json new file mode 100644 index 0000000000..5e7a0469e9 --- /dev/null +++ b/packages/core/js-sdk/package.json @@ -0,0 +1,40 @@ +{ + "name": "@medusajs/js-sdk", + "version": "0.0.1", + "description": "SDK for the Medusa API", + "main": "dist/index.js", + "repository": { + "type": "git", + "url": "https://github.com/medusajs/medusa", + "directory": "packages/core/js-sdk" + }, + "engines": { + "node": ">=18" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "dist" + ], + "author": "Medusa", + "license": "MIT", + "devDependencies": { + "cross-env": "^5.2.1", + "jest": "^29.6.3", + "msw": "^2.3.0", + "rimraf": "^5.0.1", + "ts-jest": "^29.1.1", + "typescript": "^5.1.6" + }, + "dependencies": { + "@medusajs/types": "^1.11.16", + "qs": "^6.12.1" + }, + "scripts": { + "prepublishOnly": "cross-env NODE_ENV=production tsc --build", + "build": "rimraf dist && tsc --build", + "test": "jest --passWithNoTests --runInBand --bail --forceExit", + "watch": "tsc --build --watch" + } +} diff --git a/packages/core/js-sdk/src/__tests__/client.spec.ts b/packages/core/js-sdk/src/__tests__/client.spec.ts new file mode 100644 index 0000000000..6714c548c5 --- /dev/null +++ b/packages/core/js-sdk/src/__tests__/client.spec.ts @@ -0,0 +1,145 @@ +import { http, HttpResponse } from "msw" +import { setupServer } from "msw/node" + +import { Client, FetchError } from "../client" + +const baseUrl = "https://someurl.com" + +// This is just a network-layer mocking, it doesn't start an actual server +const server = setupServer( + http.get(`${baseUrl}/test`, ({ request, params, cookies }) => { + return HttpResponse.json({ + test: "test", + }) + }), + http.get(`${baseUrl}/throw`, ({ request, params, cookies }) => { + return new HttpResponse(null, { + status: 500, + statusText: "Internal Server Error", + }) + }), + http.get(`${baseUrl}/header`, ({ request, params, cookies }) => { + if ( + request.headers.get("X-custom-header") === "test" && + request.headers.get("Content-Type") === "application/json" + ) { + return HttpResponse.json({ + test: "test", + }) + } + }), + http.get(`${baseUrl}/apikey`, ({ request, params, cookies }) => { + console.log(request.headers.get("authorization")) + if (request.headers.get("authorization")?.startsWith("Basic")) { + return HttpResponse.json({ + test: "test", + }) + } + }), + http.get(`${baseUrl}/pubkey`, ({ request, params, cookies }) => { + if (request.headers.get("x-medusa-pub-key") === "test-pub-key") { + return HttpResponse.json({ + test: "test", + }) + } + }), + http.post(`${baseUrl}/create`, async ({ request, params, cookies }) => { + return HttpResponse.json(await request.json()) + }), + http.delete(`${baseUrl}/delete/123`, async ({ request, params, cookies }) => { + return HttpResponse.json({ test: "test" }) + }), + http.all("*", ({ request, params, cookies }) => { + return new HttpResponse(null, { + status: 404, + statusText: "Not Found", + }) + }) +) + +describe("Client", () => { + let client: Client + beforeAll(() => { + client = new Client({ + baseUrl, + }) + + server.listen() + }) + afterEach(() => server.resetHandlers()) + afterAll(() => server.close()) + + describe("header configuration", () => { + it("should allow passing custom request headers while the defaults are preserved", async () => { + const resp = await client.fetch("header", { + headers: { "X-custom-header": "test" }, + }) + + expect(resp).toEqual({ test: "test" }) + }) + + it("should allow passing global headers", async () => { + const headClient = new Client({ + baseUrl, + globalHeaders: { + "X-custom-header": "test", + }, + }) + + const resp = await headClient.fetch("header") + expect(resp).toEqual({ test: "test" }) + }) + + it("should allow setting an API key", async () => { + const authClient = new Client({ + baseUrl, + apiKey: "test-api-key", + }) + + const resp = await authClient.fetch("apikey") + expect(resp).toEqual({ test: "test" }) + }) + + it("should allow setting a publishable key", async () => { + const pubClient = new Client({ + baseUrl, + publishableKey: "test-pub-key", + }) + + const resp = await pubClient.fetch("pubkey") + expect(resp).toEqual({ test: "test" }) + }) + }) + + describe("GET requests", () => { + it("should fire a simple GET request and get back a JSON response by default", async () => { + const resp = await client.fetch<{ test: string }>("test") + expect(resp).toEqual({ test: "test" }) + }) + + it("should throw an exception if a non-2xx status is received", async () => { + const err: FetchError = await client.fetch("throw").catch((e) => e) + expect(err.status).toEqual(500) + expect(err.message).toEqual("Internal Server Error") + }) + }) + + describe("POST requests", () => { + it("should fire a simple POST request and get back a JSON response", async () => { + const resp = await client.fetch("create", { + body: { test: "test" }, + method: "POST", + }) + expect(resp).toEqual({ test: "test" }) + }) + }) + + describe("DELETE requests", () => { + it("should fire a simple DELETE request and get back a JSON response", async () => { + const resp = await client.fetch("delete/123", { + method: "DELETE", + }) + expect(resp).toEqual({ test: "test" }) + }) + }) +}) diff --git a/packages/core/js-sdk/src/admin/index.ts b/packages/core/js-sdk/src/admin/index.ts new file mode 100644 index 0000000000..657e3d789a --- /dev/null +++ b/packages/core/js-sdk/src/admin/index.ts @@ -0,0 +1,8 @@ +import { Client } from "../client" + +export class Admin { + private client: Client + constructor(client: Client) { + this.client = client + } +} diff --git a/packages/core/js-sdk/src/client.ts b/packages/core/js-sdk/src/client.ts new file mode 100644 index 0000000000..51e70290b1 --- /dev/null +++ b/packages/core/js-sdk/src/client.ts @@ -0,0 +1,183 @@ +import qs from "qs" +import { ClientFetch, Config, FetchArgs, FetchInput, Logger } from "./types" + +const isBrowser = () => typeof window !== "undefined" + +const toBase64 = (str: string) => { + if (typeof window !== "undefined") { + return window.btoa(str) + } + + return Buffer.from(str).toString("base64") +} + +const sanitizeHeaders = (headers: Headers) => { + return { + ...Object.fromEntries(headers.entries()), + Authorization: "", + } +} + +const normalizeRequest = ( + init: FetchArgs | undefined, + headers: Headers +): RequestInit | undefined => { + let body = init?.body + if (body && headers.get("content-type")?.includes("application/json")) { + body = JSON.stringify(body) + } + + return { + ...init, + headers, + ...(body ? { body: body as RequestInit["body"] } : {}), + } as RequestInit +} + +const normalizeResponse = async (resp: Response, reqHeaders: Headers) => { + if (resp.status >= 300) { + const error = new FetchError(resp.statusText, resp.status) + throw error + } + + // If we both requested JSON, we try to parse. Otherwise, we return the raw response. + const isJsonRequest = reqHeaders.get("accept")?.includes("application/json") + return isJsonRequest ? await resp.json() : resp +} + +export class FetchError extends Error { + status: number | undefined + + constructor(message: string, status?: number) { + super(message) + this.status = status + } +} + +export class Client { + public fetch_: ClientFetch + private logger: Logger + + private DEFAULT_JWT_STORAGE_KEY = "medusa_auth_token" + private token = "" + + constructor(config: Config) { + const logger = config.logger || { + error: console.error, + warn: console.warn, + info: console.info, + debug: console.debug, + } + + this.logger = { + ...logger, + debug: config.debug ? logger.debug : () => {}, + } + + this.fetch_ = this.initClient(config) + } + + // Since the response is dynamically determined, we cannot know if it is JSON or not. Therefore, it is important to pass `Response` as the return type + fetch(input: FetchInput, init?: FetchArgs): Promise { + return this.fetch_(input, init) as unknown as Promise + } + + protected initClient(config: Config): ClientFetch { + const defaultHeaders = new Headers({ + "content-type": "application/json", + accept: "application/json", + ...this.getApiKeyHeader(config), + ...this.getPublishableKeyHeader(config), + }) + + this.logger.debug( + "Initiating Medusa client with default headers:\n", + `${JSON.stringify(sanitizeHeaders(defaultHeaders), null, 2)}\n` + ) + + return (input: FetchInput, init?: FetchArgs) => { + // We always want to fetch the up-to-date JWT token before firing off a request. + const headers = new Headers(defaultHeaders) + const customHeaders = { + ...config.globalHeaders, + ...this.getJwtTokenHeader(config), + ...init?.headers, + } + // We use `headers.set` in order to ensure headers are overwritten in a case-insensitive manner. + Object.entries(customHeaders).forEach(([key, value]) => { + headers.set(key, value) + }) + + let normalizedInput: RequestInfo | URL = input + if (input instanceof URL || typeof input === "string") { + normalizedInput = new URL(input, config.baseUrl) + if (init?.query) { + const existing = qs.parse(normalizedInput.search) + const stringifiedQuery = qs.stringify({ existing, ...init.query }) + normalizedInput.search = stringifiedQuery + } + } + + this.logger.debug( + "Performing request to:\n", + `URL: ${normalizedInput.toString()}\n`, + `Headers: ${JSON.stringify(sanitizeHeaders(headers), null, 2)}\n` + ) + + // Any non-request errors (eg. invalid JSON in the response) will be thrown as-is. + return fetch(normalizedInput, normalizeRequest(init, headers)).then( + (resp) => { + this.logger.debug(`Received response with status ${resp.status}\n`) + return normalizeResponse(resp, headers) + } + ) + } + } + + protected getApiKeyHeader = ( + config: Config + ): { Authorization: string } | {} => { + return config.apiKey + ? { Authorization: "Basic " + toBase64(config.apiKey + ":") } + : {} + } + + protected getPublishableKeyHeader = ( + config: Config + ): { "x-medusa-pub-key": string } | {} => { + return config.publishableKey + ? { "x-medusa-pub-key": config.publishableKey } + : {} + } + + protected getJwtTokenHeader = ( + config: Config + ): { Authorization: string } | {} => { + const storageMethod = + config.jwtToken?.storageMethod || (isBrowser() ? "local" : "memory") + const storageKey = + config.jwtToken?.storageKey || this.DEFAULT_JWT_STORAGE_KEY + + switch (storageMethod) { + case "local": { + if (!isBrowser()) { + throw new Error("Local JWT storage is only available in the browser") + } + const token = window.localStorage.getItem(storageKey) + return token ? { Authorization: `Bearer ${token}` } : {} + } + case "session": { + if (!isBrowser()) { + throw new Error( + "Session JWT storage is only available in the browser" + ) + } + const token = window.sessionStorage.getItem(storageKey) + return token ? { Authorization: `Bearer ${token}` } : {} + } + case "memory": { + return this.token ? { Authorization: `Bearer ${this.token}` } : {} + } + } + } +} diff --git a/packages/core/js-sdk/src/index.ts b/packages/core/js-sdk/src/index.ts new file mode 100644 index 0000000000..6d2fdeb99f --- /dev/null +++ b/packages/core/js-sdk/src/index.ts @@ -0,0 +1,18 @@ +import { Admin } from "./admin" +import { Client } from "./client" +import { Store } from "./store" +import { Config } from "./types" + +class Medusa { + public client: Client + public admin: Admin + public store: Store + + constructor(config: Config) { + this.client = new Client(config) + this.admin = new Admin(this.client) + this.store = new Store(this.client) + } +} + +export default Medusa diff --git a/packages/core/js-sdk/src/store/index.ts b/packages/core/js-sdk/src/store/index.ts new file mode 100644 index 0000000000..a8403e17fd --- /dev/null +++ b/packages/core/js-sdk/src/store/index.ts @@ -0,0 +1,250 @@ +import { Client } from "../client" +import { ClientHeaders } from "../types" + +export class Store { + private client: Client + + constructor(client: Client) { + this.client = client + } + + public region = { + list: async ( + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/regions`, { + query: queryParams, + headers, + }) + }, + retrieve: async ( + id: string, + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/regions/${id}`, { + query: queryParams, + headers, + }) + }, + } + + public collection = { + list: async ( + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/collections`, { + query: queryParams, + headers, + }) + }, + retrieve: async ( + id: string, + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/collections/${id}`, { + query: queryParams, + headers, + }) + }, + } + + public category = { + list: async ( + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/product-categories`, { + query: queryParams, + headers, + }) + }, + retrieve: async ( + id: string, + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/product-categories/${id}`, { + query: queryParams, + headers, + }) + }, + } + + public product = { + list: async ( + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/products`, { + query: queryParams, + headers, + }) + }, + retrieve: async ( + id: string, + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/products/${id}`, { + query: queryParams, + headers, + }) + }, + } + + public order = { + retrieve: async ( + id: string, + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/orders/${id}`, { + query: queryParams, + headers, + }) + }, + } + + public cart = { + create: async (body: any, headers?: ClientHeaders) => { + return this.client.fetch(`/store/carts`, { + headers, + method: "POST", + body, + }) + }, + update: async (id: string, body: any, headers?: ClientHeaders) => { + return this.client.fetch(`/store/carts/${id}`, { + headers, + method: "POST", + body, + }) + }, + retrieve: async ( + id: string, + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/carts/${id}`, { + query: queryParams, + headers, + }) + }, + createLineItem: async ( + cartId: string, + body: any, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/carts/${cartId}/line-items`, { + headers, + method: "POST", + body, + }) + }, + updateLineItem: async ( + cartId: string, + lineItemId: string, + body: any, + headers?: ClientHeaders + ) => { + return this.client.fetch( + `/store/carts/${cartId}/line-items/${lineItemId}`, + { + headers, + method: "POST", + body, + } + ) + }, + deleteLineItem: async ( + cartId: string, + lineItemId: string, + headers?: ClientHeaders + ) => { + return this.client.fetch( + `/store/carts/${cartId}/line-items/${lineItemId}`, + { + headers, + method: "DELETE", + } + ) + }, + addShippingMethod: async ( + cartId: string, + body: any, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/carts/${cartId}/shipping-methods`, { + headers, + method: "POST", + body, + }) + }, + complete: async (cartId: string, headers?: ClientHeaders) => { + return this.client.fetch(`/store/carts/${cartId}/complete`, { + headers, + method: "POST", + }) + }, + } + + public fulfillment = { + listCartOptions: async ( + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/shipping-options`, { + query: queryParams, + headers, + }) + }, + } + + public payment = { + listPaymentProviders: async ( + queryParams?: Record, + headers?: ClientHeaders + ) => { + return this.client.fetch(`/store/payment-providers`, { + query: queryParams, + headers, + }) + }, + + initiatePaymentSession: async ( + cart: any, + body: Record, + headers?: ClientHeaders + ) => { + let paymentCollectionId = (cart as any).payment_collection?.id + if (!paymentCollectionId) { + const collectionBody = { + cart_id: cart.id, + region_id: cart.region_id, + currency_code: cart.currency_code, + amount: cart.total, + } + paymentCollectionId = ( + await this.client.fetch(`/store/payment-collections`, { + headers, + method: "POST", + body: collectionBody, + }) + ).payment_collection.id + } + + return this.client.fetch( + `/store/payment-collections/${paymentCollectionId}/payment-sessions`, + { + headers, + method: "POST", + body, + } + ) + }, + } +} diff --git a/packages/core/js-sdk/src/types.ts b/packages/core/js-sdk/src/types.ts new file mode 100644 index 0000000000..c3fa4b1097 --- /dev/null +++ b/packages/core/js-sdk/src/types.ts @@ -0,0 +1,37 @@ +export type Logger = { + error: (...messages: string[]) => void + warn: (...messages: string[]) => void + info: (...messages: string[]) => void + debug: (...messages: string[]) => void +} + +export type Config = { + baseUrl: string + globalHeaders?: ClientHeaders + publishableKey?: string + apiKey?: string + jwtToken?: { + storageKey?: string + // TODO: Add support for cookie storage + storageMethod?: "local" | "session" | "memory" + } + logger?: Logger + debug?: boolean +} + +export type FetchParams = Parameters + +export type ClientHeaders = Record + +export type FetchInput = FetchParams[0] + +export type FetchArgs = Omit & { + query?: Record + headers?: ClientHeaders + body?: RequestInit["body"] | Record +} + +export type ClientFetch = ( + input: FetchInput, + init?: FetchArgs +) => Promise diff --git a/packages/core/js-sdk/tsconfig.json b/packages/core/js-sdk/tsconfig.json new file mode 100644 index 0000000000..d41dc00d5c --- /dev/null +++ b/packages/core/js-sdk/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "lib": ["es2021"], + "target": "es2021", + "outDir": "./dist", + "esModuleInterop": true, + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "sourceMap": true, + "noImplicitReturns": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "allowJs": true, + "skipLibCheck": true, + "downlevelIteration": true // to use ES5 specific tooling + }, + "include": ["./src/**/*"], + "exclude": [ + "./dist/**/*", + "./src/**/__tests__", + "./src/**/__mocks__", + "node_modules" + ] +} diff --git a/yarn.lock b/yarn.lock index 26c2bee234..7cc06b870d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2861,6 +2861,24 @@ __metadata: languageName: node linkType: hard +"@bundled-es-modules/cookie@npm:^2.0.0": + version: 2.0.0 + resolution: "@bundled-es-modules/cookie@npm:2.0.0" + dependencies: + cookie: ^0.5.0 + checksum: 0655dd331b35d7b5b6dd2301c3bcfb7233018c0e3235a40ced1d53f00463ab92dc01f0091f153812867bc0ef0f8e0a157a30acb16e8d7ef149702bf8db9fe7a6 + languageName: node + linkType: hard + +"@bundled-es-modules/statuses@npm:^1.0.1": + version: 1.0.1 + resolution: "@bundled-es-modules/statuses@npm:1.0.1" + dependencies: + statuses: ^2.0.1 + checksum: c1a8ede3efa8da61ccda4b98e773582a9733edfbeeee569d4630785f8e018766202edb190a754a3ec7a7f6bd738e857829affc2fdb676b6dab4db1bb44e62785 + languageName: node + linkType: hard + "@changesets/apply-release-plan@npm:^7.0.0": version: 7.0.0 resolution: "@changesets/apply-release-plan@npm:7.0.0" @@ -4059,6 +4077,37 @@ __metadata: languageName: node linkType: hard +"@inquirer/confirm@npm:^3.0.0": + version: 3.1.7 + resolution: "@inquirer/confirm@npm:3.1.7" + dependencies: + "@inquirer/core": ^8.2.0 + "@inquirer/type": ^1.3.1 + checksum: e500fb3b39564a738b4403eb611621bab68a6dcf546d0c936f28e9c28e19cfb140eaa7b66f693ab2dff553257dbd7d8b1e1f6761674e078d7880d738f78f931f + languageName: node + linkType: hard + +"@inquirer/core@npm:^8.2.0": + version: 8.2.0 + resolution: "@inquirer/core@npm:8.2.0" + dependencies: + "@inquirer/figures": ^1.0.1 + "@inquirer/type": ^1.3.1 + "@types/mute-stream": ^0.0.4 + "@types/node": ^20.12.11 + "@types/wrap-ansi": ^3.0.0 + ansi-escapes: ^4.3.2 + chalk: ^4.1.2 + cli-spinners: ^2.9.2 + cli-width: ^4.1.0 + mute-stream: ^1.0.0 + signal-exit: ^4.1.0 + strip-ansi: ^6.0.1 + wrap-ansi: ^6.2.0 + checksum: 76db6c437789481147fd2c40f8fb63892b963c86de8e3e9837a443ff40737d528480add1ecf791e375e968efd037d59621c88e9957d60ba8de866822c2fc8b4d + languageName: node + linkType: hard + "@inquirer/figures@npm:^1.0.1": version: 1.0.1 resolution: "@inquirer/figures@npm:1.0.1" @@ -4066,6 +4115,13 @@ __metadata: languageName: node linkType: hard +"@inquirer/type@npm:^1.3.1": + version: 1.3.1 + resolution: "@inquirer/type@npm:1.3.1" + checksum: 7dbf7ca10f758f2b6dbc7b7302ce01e79596747692468805c340afa0bf608adecbe33cd3c3b2b806bb3987cadf233b52ead7652b479a052455bc06855849f97f + languageName: node + linkType: hard + "@internationalized/date@npm:^3.5.3": version: 3.5.3 resolution: "@internationalized/date@npm:3.5.3" @@ -5451,6 +5507,21 @@ __metadata: languageName: node linkType: hard +"@medusajs/js-sdk@workspace:packages/core/js-sdk": + version: 0.0.0-use.local + resolution: "@medusajs/js-sdk@workspace:packages/core/js-sdk" + dependencies: + "@medusajs/types": ^1.11.16 + cross-env: ^5.2.1 + jest: ^29.6.3 + msw: ^2.3.0 + qs: ^6.12.1 + rimraf: ^5.0.1 + ts-jest: ^29.1.1 + typescript: ^5.1.6 + languageName: unknown + linkType: soft + "@medusajs/link-modules@^0.2.11, @medusajs/link-modules@workspace:packages/modules/link-modules": version: 0.0.0-use.local resolution: "@medusajs/link-modules@workspace:packages/modules/link-modules" @@ -6521,6 +6592,27 @@ __metadata: languageName: node linkType: hard +"@mswjs/cookies@npm:^1.1.0": + version: 1.1.0 + resolution: "@mswjs/cookies@npm:1.1.0" + checksum: c8442b77f4d4f72c63a29049bbd33e7f9d85517471c09e1a1a71f424e5261feee5311b096d42d4447a51f199017b2227feb2b5dd77da83b733917560ace58940 + languageName: node + linkType: hard + +"@mswjs/interceptors@npm:^0.29.0": + version: 0.29.1 + resolution: "@mswjs/interceptors@npm:0.29.1" + dependencies: + "@open-draft/deferred-promise": ^2.2.0 + "@open-draft/logger": ^0.3.0 + "@open-draft/until": ^2.0.0 + is-node-process: ^1.2.0 + outvariant: ^1.2.1 + strict-event-emitter: ^0.5.1 + checksum: 816660a17b0e89e6e6955072b96882b5807c8c9faa316eab27104e8ba80e8e7d78b1862af42e1044156a5ae3ae2071289dc9211ecdc8fd5f7078d8c8a8a7caa3 + languageName: node + linkType: hard + "@ndelangen/get-tarball@npm:^3.0.7": version: 3.0.9 resolution: "@ndelangen/get-tarball@npm:3.0.9" @@ -6762,6 +6854,30 @@ __metadata: languageName: node linkType: hard +"@open-draft/deferred-promise@npm:^2.2.0": + version: 2.2.0 + resolution: "@open-draft/deferred-promise@npm:2.2.0" + checksum: eafc1b1d0fc8edb5e1c753c5e0f3293410b40dde2f92688211a54806d4136887051f39b98c1950370be258483deac9dfd17cf8b96557553765198ef2547e4549 + languageName: node + linkType: hard + +"@open-draft/logger@npm:^0.3.0": + version: 0.3.0 + resolution: "@open-draft/logger@npm:0.3.0" + dependencies: + is-node-process: ^1.2.0 + outvariant: ^1.4.0 + checksum: 90010647b22e9693c16258f4f9adb034824d1771d3baa313057b9a37797f571181005bc50415a934eaf7c891d90ff71dcd7a9d5048b0b6bb438f31bef2c7c5c1 + languageName: node + linkType: hard + +"@open-draft/until@npm:^2.0.0, @open-draft/until@npm:^2.1.0": + version: 2.1.0 + resolution: "@open-draft/until@npm:2.1.0" + checksum: 61d3f99718dd86bb393fee2d7a785f961dcaf12f2055f0c693b27f4d0cd5f7a03d498a6d9289773b117590d794a43cd129366fd8e99222e4832f67b1653d54cf + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -11080,6 +11196,13 @@ __metadata: languageName: node linkType: hard +"@types/cookie@npm:^0.6.0": + version: 0.6.0 + resolution: "@types/cookie@npm:0.6.0" + checksum: 5b326bd0188120fb32c0be086b141b1481fec9941b76ad537f9110e10d61ee2636beac145463319c71e4be67a17e85b81ca9e13ceb6e3bb63b93d16824d6c149 + languageName: node + linkType: hard + "@types/cross-spawn@npm:^6.0.2": version: 6.0.6 resolution: "@types/cross-spawn@npm:6.0.6" @@ -11423,6 +11546,15 @@ __metadata: languageName: node linkType: hard +"@types/mute-stream@npm:^0.0.4": + version: 0.0.4 + resolution: "@types/mute-stream@npm:0.0.4" + dependencies: + "@types/node": "*" + checksum: 944730fd7b398c5078de3c3d4d0afeec8584283bc694da1803fdfca14149ea385e18b1b774326f1601baf53898ce6d121a952c51eb62d188ef6fcc41f725c0dc + languageName: node + linkType: hard + "@types/node-emoji@npm:^1.8.2": version: 1.8.2 resolution: "@types/node-emoji@npm:1.8.2" @@ -11489,6 +11621,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^20.12.11": + version: 20.12.12 + resolution: "@types/node@npm:20.12.12" + dependencies: + undici-types: ~5.26.4 + checksum: f374b763c744e8f16e4f38cf6e2c0eef31781ec9228c9e43a6f267880fea420fab0a238b59f10a7cb3444e49547c5e3785787e371fc242307310995b21988812 + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0": version: 2.4.4 resolution: "@types/normalize-package-data@npm:2.4.4" @@ -11677,6 +11818,13 @@ __metadata: languageName: node linkType: hard +"@types/statuses@npm:^2.0.4": + version: 2.0.5 + resolution: "@types/statuses@npm:2.0.5" + checksum: 4dacec0b29483a44be902a022a11a22b339de7a6e7b2059daa4f7add10cb6dbcc28d02d2a416fe9687e48d335906bf983065391836d4e7c847e55ddef4de8fad + languageName: node + linkType: hard + "@types/stripe@npm:^8.0.417": version: 8.0.417 resolution: "@types/stripe@npm:8.0.417" @@ -11762,6 +11910,13 @@ __metadata: languageName: node linkType: hard +"@types/wrap-ansi@npm:^3.0.0": + version: 3.0.0 + resolution: "@types/wrap-ansi@npm:3.0.0" + checksum: 8d8f53363f360f38135301a06b596c295433ad01debd082078c33c6ed98b05a5c8fe8853a88265432126096084f4a135ec1564e3daad631b83296905509f90b3 + languageName: node + linkType: hard + "@types/yargs-parser@npm:*": version: 21.0.3 resolution: "@types/yargs-parser@npm:21.0.3" @@ -14520,7 +14675,7 @@ __metadata: languageName: node linkType: hard -"cli-spinners@npm:^2.5.0, cli-spinners@npm:^2.6.1": +"cli-spinners@npm:^2.5.0, cli-spinners@npm:^2.6.1, cli-spinners@npm:^2.9.2": version: 2.9.2 resolution: "cli-spinners@npm:2.9.2" checksum: 907a1c227ddf0d7a101e7ab8b300affc742ead4b4ebe920a5bf1bc6d45dce2958fcd195eb28fa25275062fe6fa9b109b93b63bc8033396ed3bcb50297008b3a3 @@ -15151,6 +15306,13 @@ __metadata: languageName: node linkType: hard +"cookie@npm:^0.5.0": + version: 0.5.0 + resolution: "cookie@npm:0.5.0" + checksum: c01ca3ef8d7b8187bae434434582288681273b5a9ed27521d4d7f9f7928fe0c920df0decd9f9d3bbd2d14ac432b8c8cf42b98b3bdd5bfe0e6edddeebebe8b61d + languageName: node + linkType: hard + "cookiejar@npm:^2.1.0": version: 2.1.4 resolution: "cookiejar@npm:2.1.4" @@ -19243,7 +19405,7 @@ __metadata: languageName: node linkType: hard -"graphql@npm:^16.6.0": +"graphql@npm:^16.6.0, graphql@npm:^16.8.1": version: 16.8.1 resolution: "graphql@npm:16.8.1" checksum: 129c318156b466f440914de80dbf7bc67d17f776f2a088a40cb0da611d19a97c224b1c6d2b13cbcbc6e5776e45ed7468b8432f9c3536724e079b44f1a3d57a8a @@ -19502,6 +19664,13 @@ __metadata: languageName: node linkType: hard +"headers-polyfill@npm:^4.0.2": + version: 4.0.3 + resolution: "headers-polyfill@npm:4.0.3" + checksum: 53e85b2c6385f8d411945fb890c5369f1469ce8aa32a6e8d28196df38568148de640c81cf88cbc7c67767103dd9acba48f4f891982da63178fc6e34560022afe + languageName: node + linkType: hard + "helpertypes@npm:^0.0.19": version: 0.0.19 resolution: "helpertypes@npm:0.0.19" @@ -20627,6 +20796,13 @@ __metadata: languageName: node linkType: hard +"is-node-process@npm:^1.2.0": + version: 1.2.0 + resolution: "is-node-process@npm:1.2.0" + checksum: 5b24fda6776d00e42431d7bcd86bce81cb0b6cabeb944142fe7b077a54ada2e155066ad06dbe790abdb397884bdc3151e04a9707b8cd185099efbc79780573ed + languageName: node + linkType: hard + "is-number-object@npm:^1.0.4": version: 1.0.7 resolution: "is-number-object@npm:1.0.7" @@ -24804,6 +24980,38 @@ __metadata: languageName: node linkType: hard +"msw@npm:^2.3.0": + version: 2.3.0 + resolution: "msw@npm:2.3.0" + dependencies: + "@bundled-es-modules/cookie": ^2.0.0 + "@bundled-es-modules/statuses": ^1.0.1 + "@inquirer/confirm": ^3.0.0 + "@mswjs/cookies": ^1.1.0 + "@mswjs/interceptors": ^0.29.0 + "@open-draft/until": ^2.1.0 + "@types/cookie": ^0.6.0 + "@types/statuses": ^2.0.4 + chalk: ^4.1.2 + graphql: ^16.8.1 + headers-polyfill: ^4.0.2 + is-node-process: ^1.2.0 + outvariant: ^1.4.2 + path-to-regexp: ^6.2.0 + strict-event-emitter: ^0.5.1 + type-fest: ^4.9.0 + yargs: ^17.7.2 + peerDependencies: + typescript: ">= 4.7.x" + peerDependenciesMeta: + typescript: + optional: true + bin: + msw: cli/index.js + checksum: 704d808741c7a7abc8757406816fd8fffa5450c1cdf8669355e7d01748c372818c61b4bf6fab3ffce5c3ad32e25302737da664e079973a18becb10396989f933 + languageName: node + linkType: hard + "multer@npm:^1.4.5-lts.1": version: 1.4.5-lts.1 resolution: "multer@npm:1.4.5-lts.1" @@ -24838,7 +25046,7 @@ __metadata: languageName: node linkType: hard -"mute-stream@npm:1.0.0": +"mute-stream@npm:1.0.0, mute-stream@npm:^1.0.0": version: 1.0.0 resolution: "mute-stream@npm:1.0.0" checksum: dce2a9ccda171ec979a3b4f869a102b1343dee35e920146776780de182f16eae459644d187e38d59a3d37adf85685e1c17c38cf7bfda7e39a9880f7a1d10a74c @@ -25805,6 +26013,13 @@ __metadata: languageName: node linkType: hard +"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0, outvariant@npm:^1.4.2": + version: 1.4.2 + resolution: "outvariant@npm:1.4.2" + checksum: 48041425a4cb725ff8871b7d9889bfc2eaded867b9b35b6c2450a36fb3632543173098654990caa6c9e9f67d902b2a01f4402c301835e9ecaf4b4695d3161853 + languageName: node + linkType: hard + "p-cancelable@npm:^2.0.0": version: 2.1.1 resolution: "p-cancelable@npm:2.1.1" @@ -26223,6 +26438,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:^6.2.0": + version: 6.2.2 + resolution: "path-to-regexp@npm:6.2.2" + checksum: 4b60852d3501fd05ca9dd08c70033d73844e5eca14e41f499f069afa8364f780f15c5098002f93bd42af8b3514de62ac6e82a53b5662de881d2b08c9ef21ea6b + languageName: node + linkType: hard + "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -27562,7 +27784,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.10.0, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.12.0, qs@npm:^6.5.1": +"qs@npm:^6.10.0, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.12.0, qs@npm:^6.12.1, qs@npm:^6.5.1": version: 6.12.1 resolution: "qs@npm:6.12.1" dependencies: @@ -30273,7 +30495,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:2.0.1": +"statuses@npm:2.0.1, statuses@npm:^2.0.1": version: 2.0.1 resolution: "statuses@npm:2.0.1" checksum: 34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 @@ -30390,6 +30612,13 @@ __metadata: languageName: node linkType: hard +"strict-event-emitter@npm:^0.5.1": + version: 0.5.1 + resolution: "strict-event-emitter@npm:0.5.1" + checksum: f5228a6e6b6393c57f52f62e673cfe3be3294b35d6f7842fc24b172ae0a6e6c209fa83241d0e433fc267c503bc2f4ffdbe41a9990ff8ffd5ac425ec0489417f7 + languageName: node + linkType: hard + "string-argv@npm:0.3.1": version: 0.3.1 resolution: "string-argv@npm:0.3.1" @@ -32008,6 +32237,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^4.9.0": + version: 4.18.2 + resolution: "type-fest@npm:4.18.2" + checksum: 5e669128bf7cbc9f9cea4e4862c974517a1d9f77652589c2ac0908a8be5d852d4e52593ed14f4d8a44a604fb5e8a8ec1b658e461acd8bb7592f5e5265a04cbab + languageName: node + linkType: hard + "type-is@npm:^1.6.4, type-is@npm:~1.6.17, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18"