shopify_storefront_sdk 1.0.4 → 2.0.0

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.
Files changed (89) hide show
  1. package/README.md +136 -70
  2. package/dist/cjs/client/client.js +110 -22
  3. package/dist/cjs/generated/shopify.js +25 -49
  4. package/dist/cjs/helpers/CartManager.js +55 -0
  5. package/dist/cjs/helpers/CustomerSession.js +41 -0
  6. package/dist/cjs/index.js +210 -27
  7. package/dist/cjs/tests/integration/sdk.test.js +266 -0
  8. package/dist/cjs/tests/unit/cache.test.js +86 -0
  9. package/dist/cjs/tests/unit/cartManager.test.js +43 -0
  10. package/dist/cjs/tests/unit/client.test.js +134 -0
  11. package/dist/cjs/tests/unit/customerSession.test.js +50 -0
  12. package/dist/cjs/tests/unit/pagination.test.js +41 -0
  13. package/dist/cjs/tests/unit/webhooks.test.js +41 -0
  14. package/dist/cjs/utils/cache.js +29 -0
  15. package/dist/cjs/utils/errors.js +53 -0
  16. package/dist/cjs/utils/pagination.js +30 -0
  17. package/dist/cjs/utils/webhooks.js +33 -0
  18. package/dist/client/client.d.ts +12 -1
  19. package/dist/client/client.d.ts.map +1 -1
  20. package/dist/client/client.js +111 -21
  21. package/dist/client/client.js.map +1 -1
  22. package/dist/generated/shopify.d.ts +4048 -2764
  23. package/dist/generated/shopify.d.ts.map +1 -1
  24. package/dist/generated/shopify.js +26 -50
  25. package/dist/generated/shopify.js.map +1 -1
  26. package/dist/helpers/CartManager.d.ts +32 -0
  27. package/dist/helpers/CartManager.d.ts.map +1 -0
  28. package/dist/helpers/CartManager.js +53 -0
  29. package/dist/helpers/CartManager.js.map +1 -0
  30. package/dist/helpers/CustomerSession.d.ts +27 -0
  31. package/dist/helpers/CustomerSession.d.ts.map +1 -0
  32. package/dist/helpers/CustomerSession.js +40 -0
  33. package/dist/helpers/CustomerSession.js.map +1 -0
  34. package/dist/index.d.ts +179 -16
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +204 -28
  37. package/dist/index.js.map +1 -1
  38. package/dist/tests/integration/sdk.test.d.ts +2 -0
  39. package/dist/tests/integration/sdk.test.d.ts.map +1 -0
  40. package/dist/tests/integration/sdk.test.js +245 -0
  41. package/dist/tests/integration/sdk.test.js.map +1 -0
  42. package/dist/tests/unit/cache.test.d.ts +2 -0
  43. package/dist/tests/unit/cache.test.d.ts.map +1 -0
  44. package/dist/tests/unit/cache.test.js +85 -0
  45. package/dist/tests/unit/cache.test.js.map +1 -0
  46. package/dist/tests/unit/cartManager.test.d.ts +2 -0
  47. package/dist/tests/unit/cartManager.test.d.ts.map +1 -0
  48. package/dist/tests/unit/cartManager.test.js +43 -0
  49. package/dist/tests/unit/cartManager.test.js.map +1 -0
  50. package/dist/tests/unit/client.test.d.ts +2 -0
  51. package/dist/tests/unit/client.test.d.ts.map +1 -0
  52. package/dist/tests/unit/client.test.js +133 -0
  53. package/dist/tests/unit/client.test.js.map +1 -0
  54. package/dist/tests/unit/customerSession.test.d.ts +2 -0
  55. package/dist/tests/unit/customerSession.test.d.ts.map +1 -0
  56. package/dist/tests/unit/customerSession.test.js +49 -0
  57. package/dist/tests/unit/customerSession.test.js.map +1 -0
  58. package/dist/tests/unit/pagination.test.d.ts +2 -0
  59. package/dist/tests/unit/pagination.test.d.ts.map +1 -0
  60. package/dist/tests/unit/pagination.test.js +40 -0
  61. package/dist/tests/unit/pagination.test.js.map +1 -0
  62. package/dist/tests/unit/webhooks.test.d.ts +2 -0
  63. package/dist/tests/unit/webhooks.test.d.ts.map +1 -0
  64. package/dist/tests/unit/webhooks.test.js +40 -0
  65. package/dist/tests/unit/webhooks.test.js.map +1 -0
  66. package/dist/utils/cache.d.ts +14 -0
  67. package/dist/utils/cache.d.ts.map +1 -0
  68. package/dist/utils/cache.js +24 -0
  69. package/dist/utils/cache.js.map +1 -0
  70. package/dist/utils/config.d.ts +6 -0
  71. package/dist/utils/config.d.ts.map +1 -1
  72. package/dist/utils/errors.d.ts +30 -0
  73. package/dist/utils/errors.d.ts.map +1 -0
  74. package/dist/utils/errors.js +48 -0
  75. package/dist/utils/errors.js.map +1 -0
  76. package/dist/utils/pagination.d.ts +20 -0
  77. package/dist/utils/pagination.d.ts.map +1 -0
  78. package/dist/utils/pagination.js +28 -0
  79. package/dist/utils/pagination.js.map +1 -0
  80. package/dist/utils/webhooks.d.ts +10 -0
  81. package/dist/utils/webhooks.d.ts.map +1 -0
  82. package/dist/utils/webhooks.js +31 -0
  83. package/dist/utils/webhooks.js.map +1 -0
  84. package/package.json +11 -7
  85. package/dist/cjs/tests/test.js +0 -201
  86. package/dist/tests/test.d.ts +0 -34
  87. package/dist/tests/test.d.ts.map +0 -1
  88. package/dist/tests/test.js +0 -202
  89. package/dist/tests/test.js.map +0 -1
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import ShopifyStorefront from "../../index.js";
3
+ import { InMemoryCache } from "../../utils/cache.js";
4
+ const fetchMock = vi.fn();
5
+ vi.stubGlobal("fetch", fetchMock);
6
+ describe("Caching System", () => {
7
+ const MOCK_DOMAIN = "test-store.myshopify.com";
8
+ const MOCK_TOKEN = "mock-token-123";
9
+ let cache;
10
+ beforeEach(() => {
11
+ vi.resetAllMocks();
12
+ cache = new InMemoryCache();
13
+ });
14
+ it("should cache successful queries and prevent subsequent network requests", async () => {
15
+ const client = new ShopifyStorefront({
16
+ storeUrl: MOCK_DOMAIN,
17
+ storefrontToken: MOCK_TOKEN,
18
+ cache,
19
+ defaultCacheTtl: 60,
20
+ });
21
+ fetchMock.mockResolvedValueOnce({
22
+ ok: true,
23
+ json: async () => ({
24
+ data: { shop: { name: "First Fetch" } },
25
+ }),
26
+ });
27
+ // 1st call: Should hit the network (fetchMock called)
28
+ const result1 = await client.customQuery("query { shop { name } }", {});
29
+ expect(result1.shop.name).toBe("First Fetch");
30
+ expect(fetchMock).toHaveBeenCalledTimes(1);
31
+ // 2nd call: Should return from cache (fetchMock NOT called again)
32
+ const result2 = await client.customQuery("query { shop { name } }", {});
33
+ expect(result2.shop.name).toBe("First Fetch");
34
+ expect(fetchMock).toHaveBeenCalledTimes(1);
35
+ });
36
+ it("should NOT cache mutations", async () => {
37
+ const client = new ShopifyStorefront({
38
+ storeUrl: MOCK_DOMAIN,
39
+ storefrontToken: MOCK_TOKEN,
40
+ cache,
41
+ defaultCacheTtl: 60,
42
+ });
43
+ fetchMock.mockResolvedValue({
44
+ ok: true,
45
+ json: async () => ({
46
+ data: { customerCreate: { customer: { id: "123" } } },
47
+ }),
48
+ });
49
+ // 1st call
50
+ await client.customQuery("mutation { customerCreate(input: {}) { customer { id } } }", {});
51
+ // 2nd call with exactly the same mutation
52
+ await client.customQuery("mutation { customerCreate(input: {}) { customer { id } } }", {});
53
+ // Mutations should bypass the cache entirely
54
+ expect(fetchMock).toHaveBeenCalledTimes(2);
55
+ });
56
+ it("should expire cache entries after the TTL", async () => {
57
+ // Override Date.now for time travel
58
+ const originalDateNow = Date.now;
59
+ let mockedTime = 1000000;
60
+ vi.spyOn(Date, "now").mockImplementation(() => mockedTime);
61
+ const client = new ShopifyStorefront({
62
+ storeUrl: MOCK_DOMAIN,
63
+ storefrontToken: MOCK_TOKEN,
64
+ cache,
65
+ defaultCacheTtl: 1, // 1 second TTL
66
+ });
67
+ fetchMock.mockResolvedValue({
68
+ ok: true,
69
+ json: async () => ({
70
+ data: { data: "mocked" },
71
+ }),
72
+ });
73
+ // Initial fetch
74
+ await client.customQuery("query { something }", {});
75
+ expect(fetchMock).toHaveBeenCalledTimes(1);
76
+ // Fast forward time by 2 seconds (exceeding 1s TTL)
77
+ mockedTime += 2000;
78
+ // Subsequent fetch should hit network again because cache expired
79
+ await client.customQuery("query { something }", {});
80
+ expect(fetchMock).toHaveBeenCalledTimes(2);
81
+ // Restore Date.now
82
+ vi.restoreAllMocks();
83
+ });
84
+ });
85
+ //# sourceMappingURL=cache.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../../../src/tests/unit/cache.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cartManager.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cartManager.test.d.ts","sourceRoot":"","sources":["../../../src/tests/unit/cartManager.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import ShopifyStorefront from "../../index.js";
3
+ import { CartManager } from "../../helpers/CartManager.js";
4
+ describe("CartManager", () => {
5
+ const MOCK_DOMAIN = "test-store.myshopify.com";
6
+ const MOCK_TOKEN = "mock-token-123";
7
+ let shopify;
8
+ beforeEach(() => {
9
+ vi.resetAllMocks();
10
+ shopify = new ShopifyStorefront({ storeUrl: MOCK_DOMAIN, storefrontToken: MOCK_TOKEN });
11
+ });
12
+ it("should initialize with an existing cart ID", () => {
13
+ const cart = shopify.cart("existing-cart-123");
14
+ expect(cart.id).toBe("existing-cart-123");
15
+ });
16
+ it("should lazily create a cart if no ID is provided", async () => {
17
+ const cart = shopify.cart();
18
+ expect(cart.id).toBeNull();
19
+ // Mock createCart on the SDK instance
20
+ const createCartSpy = vi.spyOn(shopify, "createCart").mockResolvedValueOnce({
21
+ cartCreate: { cart: { id: "new-cart-456" } }
22
+ });
23
+ // Mock addCartLines
24
+ const addCartLinesSpy = vi.spyOn(shopify, "addCartLines").mockResolvedValueOnce({});
25
+ await cart.addLines([{ merchandiseId: "variant-1", quantity: 1 }]);
26
+ expect(createCartSpy).toHaveBeenCalledTimes(1);
27
+ expect(addCartLinesSpy).toHaveBeenCalledWith({
28
+ cartId: "new-cart-456",
29
+ lines: [{ merchandiseId: "variant-1", quantity: 1 }]
30
+ });
31
+ expect(cart.id).toBe("new-cart-456");
32
+ });
33
+ it("should reuse the cart ID for subsequent operations", async () => {
34
+ const cart = shopify.cart("existing-cart-123");
35
+ const createCartSpy = vi.spyOn(shopify, "createCart");
36
+ const getCartSpy = vi.spyOn(shopify, "getCart").mockResolvedValueOnce({});
37
+ await cart.get();
38
+ // Should NOT have called createCart since an ID was provided
39
+ expect(createCartSpy).not.toHaveBeenCalled();
40
+ expect(getCartSpy).toHaveBeenCalledWith({ cartId: "existing-cart-123", first: 250 });
41
+ });
42
+ });
43
+ //# sourceMappingURL=cartManager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cartManager.test.js","sourceRoot":"","sources":["../../../src/tests/unit/cartManager.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,iBAAiB,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAE3D,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,MAAM,WAAW,GAAG,0BAA0B,CAAC;IAC/C,MAAM,UAAU,GAAG,gBAAgB,CAAC;IACpC,IAAI,OAA0B,CAAC;IAE/B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,GAAG,IAAI,iBAAiB,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QAE3B,sCAAsC;QACtC,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,qBAAqB,CAAC;YAC1E,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE;SACtC,CAAC,CAAC;QAEV,oBAAoB;QACpB,MAAM,eAAe,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,qBAAqB,CAAC,EAAS,CAAC,CAAC;QAE3F,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAEnE,MAAM,CAAC,aAAa,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,eAAe,CAAC,CAAC,oBAAoB,CAAC;YAC3C,MAAM,EAAE,cAAc;YACtB,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;SACrD,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAE/C,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,qBAAqB,CAAC,EAAS,CAAC,CAAC;QAEjF,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAEjB,6DAA6D;QAC7D,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC7C,MAAM,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,mBAAmB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../../src/tests/unit/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,133 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import ShopifyStorefront from "../../index.js";
3
+ import { ShopifyInvalidRequestError, ShopifyNetworkError, ShopifyGraphQLError, ShopifyUserError, } from "../../utils/errors.js";
4
+ const fetchMock = vi.fn();
5
+ vi.stubGlobal("fetch", fetchMock);
6
+ describe("Shopify SDK Unit Tests", () => {
7
+ const MOCK_DOMAIN = "test-store.myshopify.com";
8
+ const MOCK_TOKEN = "mock-token-123";
9
+ beforeEach(() => {
10
+ vi.resetAllMocks();
11
+ });
12
+ describe("Initialization", () => {
13
+ it("should throw ShopifyInvalidRequestError if domain is missing", () => {
14
+ expect(() => {
15
+ new ShopifyStorefront({ storeUrl: "", storefrontToken: MOCK_TOKEN });
16
+ }).toThrow(ShopifyInvalidRequestError);
17
+ });
18
+ it("should throw ShopifyInvalidRequestError if domain is invalid", () => {
19
+ expect(() => {
20
+ new ShopifyStorefront({ storeUrl: "invalid-url.com", storefrontToken: MOCK_TOKEN });
21
+ }).toThrow(ShopifyInvalidRequestError);
22
+ });
23
+ it("should throw ShopifyInvalidRequestError if token is missing", () => {
24
+ expect(() => {
25
+ new ShopifyStorefront({ storeUrl: MOCK_DOMAIN, storefrontToken: "" });
26
+ }).toThrow(ShopifyInvalidRequestError);
27
+ });
28
+ it("should initialize successfully with valid config", () => {
29
+ const client = new ShopifyStorefront({ storeUrl: MOCK_DOMAIN, storefrontToken: MOCK_TOKEN });
30
+ expect(client).toBeDefined();
31
+ });
32
+ });
33
+ describe("API Versioning", () => {
34
+ it("should default to the 2025-01 API version if none is provided", async () => {
35
+ const client = new ShopifyStorefront({ storeUrl: MOCK_DOMAIN, storefrontToken: MOCK_TOKEN });
36
+ fetchMock.mockResolvedValueOnce({
37
+ ok: true,
38
+ json: async () => ({ data: {} }),
39
+ });
40
+ await client.customQuery("query { shop { name } }", {});
41
+ expect(fetchMock).toHaveBeenCalledWith(`https://${MOCK_DOMAIN}/api/2025-01/graphql.json`, expect.objectContaining({ method: "POST" }));
42
+ });
43
+ it("should use a custom API version if provided", async () => {
44
+ const client = new ShopifyStorefront({
45
+ storeUrl: MOCK_DOMAIN,
46
+ storefrontToken: MOCK_TOKEN,
47
+ apiVersion: "unstable"
48
+ });
49
+ fetchMock.mockResolvedValueOnce({
50
+ ok: true,
51
+ json: async () => ({ data: {} }),
52
+ });
53
+ await client.customQuery("query { shop { name } }", {});
54
+ expect(fetchMock).toHaveBeenCalledWith(`https://${MOCK_DOMAIN}/api/unstable/graphql.json`, expect.objectContaining({ method: "POST" }));
55
+ });
56
+ });
57
+ describe("Error Handling", () => {
58
+ let client;
59
+ beforeEach(() => {
60
+ // Reduce retries in tests to avoid slowing them down
61
+ client = new ShopifyStorefront({ storeUrl: MOCK_DOMAIN, storefrontToken: MOCK_TOKEN, maxRetries: 0 });
62
+ });
63
+ it("should throw ShopifyNetworkError when fetch fails (e.g. network down)", async () => {
64
+ fetchMock.mockRejectedValueOnce(new Error("Network connection lost"));
65
+ await expect(client.customQuery("query { shop { name } }", {})).rejects.toThrow(ShopifyNetworkError);
66
+ });
67
+ it("should throw ShopifyInvalidRequestError for 400 responses", async () => {
68
+ fetchMock.mockResolvedValueOnce({
69
+ ok: false,
70
+ status: 400,
71
+ statusText: "Bad Request"
72
+ });
73
+ await expect(client.customQuery("query { shop { name } }", {})).rejects.toThrow(ShopifyInvalidRequestError);
74
+ });
75
+ it("should throw ShopifyGraphQLError when Shopify returns top-level errors", async () => {
76
+ fetchMock.mockResolvedValueOnce({
77
+ ok: true,
78
+ json: async () => ({
79
+ errors: [{ message: "Unauthorized Request" }],
80
+ })
81
+ });
82
+ await expect(client.customQuery("query { shop { name } }", {})).rejects.toThrow(ShopifyGraphQLError);
83
+ });
84
+ it("should throw ShopifyUserError when a mutation returns nested userErrors", async () => {
85
+ fetchMock.mockResolvedValueOnce({
86
+ ok: true,
87
+ json: async () => ({
88
+ data: {
89
+ customerCreate: {
90
+ customer: null,
91
+ userErrors: [{ field: ["email"], message: "Email has already been taken" }],
92
+ },
93
+ },
94
+ })
95
+ });
96
+ await expect(client.customQuery("mutation { customerCreate { userErrors { message } } }", {})).rejects.toThrow(ShopifyUserError);
97
+ });
98
+ it("should return the correct data on a successful response", async () => {
99
+ fetchMock.mockResolvedValueOnce({
100
+ ok: true,
101
+ json: async () => ({
102
+ data: {
103
+ shop: { name: "Test Store" },
104
+ },
105
+ })
106
+ });
107
+ const response = await client.customQuery("query { shop { name } }", {});
108
+ expect(response.shop.name).toBe("Test Store");
109
+ });
110
+ });
111
+ describe("Auto-Retries", () => {
112
+ it("should successfully retry on a 429 rate limit response", async () => {
113
+ const client = new ShopifyStorefront({ storeUrl: MOCK_DOMAIN, storefrontToken: MOCK_TOKEN, maxRetries: 2 });
114
+ // First attempt: Rate Limited
115
+ fetchMock.mockResolvedValueOnce({
116
+ ok: false,
117
+ status: 429,
118
+ statusText: "Too Many Requests"
119
+ });
120
+ // Second attempt: Success
121
+ fetchMock.mockResolvedValueOnce({
122
+ ok: true,
123
+ json: async () => ({
124
+ data: { shop: { name: "Success After Retry" } },
125
+ })
126
+ });
127
+ const response = await client.customQuery("query { shop { name } }", {});
128
+ expect(response.shop.name).toBe("Success After Retry");
129
+ expect(fetchMock).toHaveBeenCalledTimes(2);
130
+ });
131
+ });
132
+ });
133
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../../src/tests/unit/client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=customerSession.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customerSession.test.d.ts","sourceRoot":"","sources":["../../../src/tests/unit/customerSession.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,49 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import ShopifyStorefront from "../../index.js";
3
+ describe("CustomerSession", () => {
4
+ const MOCK_DOMAIN = "test-store.myshopify.com";
5
+ const MOCK_TOKEN = "mock-token-123";
6
+ let shopify;
7
+ beforeEach(() => {
8
+ vi.resetAllMocks();
9
+ shopify = new ShopifyStorefront({ storeUrl: MOCK_DOMAIN, storefrontToken: MOCK_TOKEN });
10
+ });
11
+ it("should initialize with the provided token", () => {
12
+ const session = shopify.customer("customer-token-123");
13
+ expect(session.token).toBe("customer-token-123");
14
+ });
15
+ it("should forward the token when verifying the customer", async () => {
16
+ const session = shopify.customer("customer-token-123");
17
+ const verifySpy = vi.spyOn(shopify, "verifyCustomerToken").mockResolvedValueOnce({});
18
+ await session.verify();
19
+ expect(verifySpy).toHaveBeenCalledWith({ token: "customer-token-123" });
20
+ });
21
+ it("should forward the token and customer payload when updating the customer", async () => {
22
+ const session = shopify.customer("customer-token-123");
23
+ const updateSpy = vi.spyOn(shopify, "updateCustomer").mockResolvedValueOnce({});
24
+ await session.update({ firstName: "John", lastName: "Doe" });
25
+ expect(updateSpy).toHaveBeenCalledWith({
26
+ customerAccessToken: "customer-token-123",
27
+ customer: { firstName: "John", lastName: "Doe" }
28
+ });
29
+ });
30
+ it("should forward the token and first argument when fetching orders", async () => {
31
+ const session = shopify.customer("customer-token-123");
32
+ const getOrdersSpy = vi.spyOn(shopify, "getCustomerOrders").mockResolvedValueOnce({});
33
+ await session.getOrders(50);
34
+ expect(getOrdersSpy).toHaveBeenCalledWith({
35
+ customerAccessToken: "customer-token-123",
36
+ first: 50
37
+ });
38
+ });
39
+ it("should default to first: 250 when fetching orders if not specified", async () => {
40
+ const session = shopify.customer("customer-token-123");
41
+ const getOrdersSpy = vi.spyOn(shopify, "getCustomerOrders").mockResolvedValueOnce({});
42
+ await session.getOrders();
43
+ expect(getOrdersSpy).toHaveBeenCalledWith({
44
+ customerAccessToken: "customer-token-123",
45
+ first: 250
46
+ });
47
+ });
48
+ });
49
+ //# sourceMappingURL=customerSession.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customerSession.test.js","sourceRoot":"","sources":["../../../src/tests/unit/customerSession.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pagination.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.test.d.ts","sourceRoot":"","sources":["../../../src/tests/unit/pagination.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { autoPaginate } from "../../utils/pagination.js";
3
+ describe("Pagination Utility", () => {
4
+ it("should extract nodes and stop when hasNextPage is false", async () => {
5
+ // Mock a paginated API response
6
+ const mockResponses = [
7
+ {
8
+ data: {
9
+ edges: [{ node: { id: 1 } }, { node: { id: 2 } }],
10
+ pageInfo: { hasNextPage: true, endCursor: "cursor_1" },
11
+ },
12
+ },
13
+ {
14
+ data: {
15
+ edges: [{ node: { id: 3 } }, { node: { id: 4 } }],
16
+ pageInfo: { hasNextPage: false, endCursor: null },
17
+ },
18
+ },
19
+ ];
20
+ let requestCount = 0;
21
+ const fetchPage = async (cursor) => {
22
+ if (cursor === "cursor_1") {
23
+ requestCount++;
24
+ return mockResponses[1];
25
+ }
26
+ requestCount++;
27
+ return mockResponses[0];
28
+ };
29
+ const results = await autoPaginate(fetchPage, (res) => res?.data);
30
+ expect(requestCount).toBe(2);
31
+ expect(results).toHaveLength(4);
32
+ expect(results).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]);
33
+ });
34
+ it("should return early if the connection is null or missing", async () => {
35
+ const fetchPage = async () => ({ data: null });
36
+ const results = await autoPaginate(fetchPage, (res) => res?.data);
37
+ expect(results).toHaveLength(0);
38
+ });
39
+ });
40
+ //# sourceMappingURL=pagination.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.test.js","sourceRoot":"","sources":["../../../src/tests/unit/pagination.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,gCAAgC;QAChC,MAAM,aAAa,GAAG;YACpB;gBACE,IAAI,EAAE;oBACJ,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;oBACjD,QAAQ,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE;iBACvD;aACF;YACD;gBACE,IAAI,EAAE;oBACJ,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;oBACjD,QAAQ,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE;iBAClD;aACF;SACF,CAAC;QAEF,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,MAAM,SAAS,GAAG,KAAK,EAAE,MAAe,EAAE,EAAE;YAC1C,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;gBAC1B,YAAY,EAAE,CAAC;gBACf,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;YAC1B,CAAC;YACD,YAAY,EAAE,CAAC;YACf,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,YAAY,CAChC,SAAS,EACT,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,EAAE,IAAI,CACxB,CAAC;QAEF,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/C,MAAM,OAAO,GAAG,MAAM,YAAY,CAChC,SAAS,EACT,CAAC,GAAQ,EAAE,EAAE,CAAC,GAAG,EAAE,IAAI,CACxB,CAAC;QAEF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=webhooks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.test.d.ts","sourceRoot":"","sources":["../../../src/tests/unit/webhooks.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { verifyWebhook } from "../../utils/webhooks.js";
3
+ import ShopifyStorefront from "../../index.js";
4
+ import * as crypto from "node:crypto";
5
+ describe("Webhook Verification", () => {
6
+ const SECRET = "my_super_secret_key";
7
+ const PAYLOAD = JSON.stringify({ id: 12345, status: "created" });
8
+ it("should return true for a valid signature", () => {
9
+ // Generate valid HMAC
10
+ const validHmac = crypto
11
+ .createHmac("sha256", SECRET)
12
+ .update(PAYLOAD)
13
+ .digest("base64");
14
+ // Test standalone utility
15
+ expect(verifyWebhook(PAYLOAD, validHmac, SECRET)).toBe(true);
16
+ // Test SDK static method wrapper
17
+ expect(ShopifyStorefront.verifyWebhook(PAYLOAD, validHmac, SECRET)).toBe(true);
18
+ });
19
+ it("should return false for an invalid signature", () => {
20
+ const invalidHmac = crypto
21
+ .createHmac("sha256", "wrong_secret")
22
+ .update(PAYLOAD)
23
+ .digest("base64");
24
+ expect(verifyWebhook(PAYLOAD, invalidHmac, SECRET)).toBe(false);
25
+ });
26
+ it("should return false if payload has been tampered with", () => {
27
+ const validHmac = crypto
28
+ .createHmac("sha256", SECRET)
29
+ .update(PAYLOAD)
30
+ .digest("base64");
31
+ const tamperedPayload = JSON.stringify({ id: 12345, status: "deleted" });
32
+ expect(verifyWebhook(tamperedPayload, validHmac, SECRET)).toBe(false);
33
+ });
34
+ it("should return false if missing parameters", () => {
35
+ expect(verifyWebhook("", "hmac", SECRET)).toBe(false);
36
+ expect(verifyWebhook(PAYLOAD, "", SECRET)).toBe(false);
37
+ expect(verifyWebhook(PAYLOAD, "hmac", "")).toBe(false);
38
+ });
39
+ });
40
+ //# sourceMappingURL=webhooks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.test.js","sourceRoot":"","sources":["../../../src/tests/unit/webhooks.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,iBAAiB,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,MAAM,MAAM,GAAG,qBAAqB,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAEjE,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,sBAAsB;QACtB,MAAM,SAAS,GAAG,MAAM;aACrB,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;aAC5B,MAAM,CAAC,OAAO,CAAC;aACf,MAAM,CAAC,QAAQ,CAAC,CAAC;QAEpB,0BAA0B;QAC1B,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE7D,iCAAiC;QACjC,MAAM,CAAC,iBAAiB,CAAC,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,WAAW,GAAG,MAAM;aACvB,UAAU,CAAC,QAAQ,EAAE,cAAc,CAAC;aACpC,MAAM,CAAC,OAAO,CAAC;aACf,MAAM,CAAC,QAAQ,CAAC,CAAC;QAEpB,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,SAAS,GAAG,MAAM;aACrB,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;aAC5B,MAAM,CAAC,OAAO,CAAC;aACf,MAAM,CAAC,QAAQ,CAAC,CAAC;QAEpB,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,aAAa,CAAC,eAAe,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtD,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvD,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface ShopifyCache {
2
+ get(key: string): Promise<any> | any;
3
+ set(key: string, value: any, ttlSeconds: number): Promise<void> | void;
4
+ }
5
+ export declare class InMemoryCache implements ShopifyCache {
6
+ private cache;
7
+ get(key: string): any;
8
+ set(key: string, value: any, ttlSeconds: number): void;
9
+ /**
10
+ * Utility to manually clear the entire memory cache.
11
+ */
12
+ clear(): void;
13
+ }
14
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACrC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxE;AAED,qBAAa,aAAc,YAAW,YAAY;IAChD,OAAO,CAAC,KAAK,CAAwD;IAErE,GAAG,CAAC,GAAG,EAAE,MAAM;IAWf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM;IAK/C;;OAEG;IACH,KAAK;CAGN"}
@@ -0,0 +1,24 @@
1
+ export class InMemoryCache {
2
+ cache = new Map();
3
+ get(key) {
4
+ const item = this.cache.get(key);
5
+ if (!item)
6
+ return null;
7
+ if (Date.now() > item.expiresAt) {
8
+ this.cache.delete(key);
9
+ return null;
10
+ }
11
+ return item.value;
12
+ }
13
+ set(key, value, ttlSeconds) {
14
+ const expiresAt = Date.now() + ttlSeconds * 1000;
15
+ this.cache.set(key, { value, expiresAt });
16
+ }
17
+ /**
18
+ * Utility to manually clear the entire memory cache.
19
+ */
20
+ clear() {
21
+ this.cache.clear();
22
+ }
23
+ }
24
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,aAAa;IAChB,KAAK,GAAG,IAAI,GAAG,EAA6C,CAAC;IAErE,GAAG,CAAC,GAAW;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAEvB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,UAAkB;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC;QACjD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
@@ -1,5 +1,11 @@
1
+ import type { ShopifyCache } from "./cache.js";
2
+ export type ShopifyApiVersion = "2023-10" | "2024-01" | "2024-04" | "2024-07" | "2024-10" | "2025-01" | "unstable" | (string & {});
1
3
  export type StoreConfig = {
2
4
  storeUrl: string;
3
5
  storefrontToken: string;
6
+ apiVersion?: ShopifyApiVersion;
7
+ maxRetries?: number;
8
+ cache?: ShopifyCache;
9
+ defaultCacheTtl?: number;
4
10
  };
5
11
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,SAAS,GACT,UAAU,GACV,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC"}
@@ -0,0 +1,30 @@
1
+ export declare class ShopifyError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ /**
5
+ * Thrown when there is an issue with the network or the Shopify API is unreachable (e.g. timeouts, 5xx responses).
6
+ */
7
+ export declare class ShopifyNetworkError extends ShopifyError {
8
+ constructor(message: string);
9
+ }
10
+ /**
11
+ * Thrown when the GraphQL request is successfully made but Shopify returns top-level GraphQL errors.
12
+ */
13
+ export declare class ShopifyGraphQLError extends ShopifyError {
14
+ readonly graphqlErrors: any[];
15
+ constructor(message: string, graphqlErrors: any[]);
16
+ }
17
+ /**
18
+ * Thrown when a mutation returns user errors (e.g. invalid form data, missing fields)
19
+ */
20
+ export declare class ShopifyUserError extends ShopifyError {
21
+ readonly userErrors: any[];
22
+ constructor(message: string, userErrors: any[]);
23
+ }
24
+ /**
25
+ * Thrown when the SDK configuration is invalid or the request is malformed (e.g. 400 Bad Request, 401 Unauthorized).
26
+ */
27
+ export declare class ShopifyInvalidRequestError extends ShopifyError {
28
+ constructor(message: string);
29
+ }
30
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;IACnD,SAAgB,aAAa,EAAE,GAAG,EAAE,CAAC;gBAEzB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE;CAKlD;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,SAAgB,UAAU,EAAE,GAAG,EAAE,CAAC;gBAEtB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE;CAK/C;AAED;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,YAAY;gBAC9C,OAAO,EAAE,MAAM;CAI5B"}
@@ -0,0 +1,48 @@
1
+ export class ShopifyError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "ShopifyError";
5
+ Object.setPrototypeOf(this, new.target.prototype);
6
+ }
7
+ }
8
+ /**
9
+ * Thrown when there is an issue with the network or the Shopify API is unreachable (e.g. timeouts, 5xx responses).
10
+ */
11
+ export class ShopifyNetworkError extends ShopifyError {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = "ShopifyNetworkError";
15
+ }
16
+ }
17
+ /**
18
+ * Thrown when the GraphQL request is successfully made but Shopify returns top-level GraphQL errors.
19
+ */
20
+ export class ShopifyGraphQLError extends ShopifyError {
21
+ graphqlErrors;
22
+ constructor(message, graphqlErrors) {
23
+ super(message);
24
+ this.name = "ShopifyGraphQLError";
25
+ this.graphqlErrors = graphqlErrors;
26
+ }
27
+ }
28
+ /**
29
+ * Thrown when a mutation returns user errors (e.g. invalid form data, missing fields)
30
+ */
31
+ export class ShopifyUserError extends ShopifyError {
32
+ userErrors;
33
+ constructor(message, userErrors) {
34
+ super(message);
35
+ this.name = "ShopifyUserError";
36
+ this.userErrors = userErrors;
37
+ }
38
+ }
39
+ /**
40
+ * Thrown when the SDK configuration is invalid or the request is malformed (e.g. 400 Bad Request, 401 Unauthorized).
41
+ */
42
+ export class ShopifyInvalidRequestError extends ShopifyError {
43
+ constructor(message) {
44
+ super(message);
45
+ this.name = "ShopifyInvalidRequestError";
46
+ }
47
+ }
48
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACnD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACnC,aAAa,CAAQ;IAErC,YAAY,OAAe,EAAE,aAAoB;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAChC,UAAU,CAAQ;IAElC,YAAY,OAAe,EAAE,UAAiB;QAC5C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,0BAA2B,SAAQ,YAAY;IAC1D,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF"}