@yoryoboy/bi-mcp 1.16.0 → 1.19.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 (158) hide show
  1. package/README.md +12 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +179 -6
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +3 -6
  6. package/dist/src/config/__tests__/google-store.test.js +30 -0
  7. package/dist/src/config/__tests__/google-store.test.js.map +7 -0
  8. package/dist/src/config/__tests__/mcp-tool-deadline.test.js +64 -0
  9. package/dist/src/config/__tests__/mcp-tool-deadline.test.js.map +7 -0
  10. package/dist/src/config/google-store.js +18 -0
  11. package/dist/src/config/google-store.js.map +2 -2
  12. package/dist/src/config/mcp-tool-deadline-context.js +34 -0
  13. package/dist/src/config/mcp-tool-deadline-context.js.map +7 -0
  14. package/dist/src/config/mcp-tool-deadline.js +67 -0
  15. package/dist/src/config/mcp-tool-deadline.js.map +7 -0
  16. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js +38 -3
  17. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js.map +2 -2
  18. package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js +226 -0
  19. package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js.map +7 -0
  20. package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js +127 -0
  21. package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js.map +7 -0
  22. package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js +103 -0
  23. package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js.map +7 -0
  24. package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js +582 -0
  25. package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js.map +7 -0
  26. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js +10 -0
  27. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js.map +2 -2
  28. package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js +36 -0
  29. package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js.map +7 -0
  30. package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js +137 -0
  31. package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js.map +7 -0
  32. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js +105 -0
  33. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js.map +7 -0
  34. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js +143 -0
  35. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js.map +7 -0
  36. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js +100 -0
  37. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js.map +7 -0
  38. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js +350 -0
  39. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js.map +7 -0
  40. package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js +228 -0
  41. package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js.map +7 -0
  42. package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js +58 -0
  43. package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js.map +7 -0
  44. package/dist/src/services/mercadolibre/mercadolibre-api.js +15 -3
  45. package/dist/src/services/mercadolibre/mercadolibre-api.js.map +2 -2
  46. package/dist/src/services/mercadolibre/mercadolibre-billing.js +110 -3
  47. package/dist/src/services/mercadolibre/mercadolibre-billing.js.map +2 -2
  48. package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js +368 -0
  49. package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js.map +7 -0
  50. package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js +399 -0
  51. package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js.map +7 -0
  52. package/dist/src/services/mercadolibre/mercadolibre-kits.js +55 -0
  53. package/dist/src/services/mercadolibre/mercadolibre-kits.js.map +7 -0
  54. package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js +392 -0
  55. package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js.map +7 -0
  56. package/dist/src/services/mercadolibre/mercadolibre-orders.js +8 -8
  57. package/dist/src/services/mercadolibre/mercadolibre-orders.js.map +2 -2
  58. package/dist/src/services/mercadolibre/mercadolibre-packs.js +21 -0
  59. package/dist/src/services/mercadolibre/mercadolibre-packs.js.map +7 -0
  60. package/dist/src/services/mercadolibre/mercadolibre-payments.js +60 -0
  61. package/dist/src/services/mercadolibre/mercadolibre-payments.js.map +7 -0
  62. package/dist/src/services/mercadolibre/mercadolibre-product-ads.js +429 -0
  63. package/dist/src/services/mercadolibre/mercadolibre-product-ads.js.map +7 -0
  64. package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js +436 -0
  65. package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js.map +7 -0
  66. package/dist/src/services/mercadolibre/mercadolibre-shipping.js +35 -0
  67. package/dist/src/services/mercadolibre/mercadolibre-shipping.js.map +7 -0
  68. package/dist/src/services/vtex/__tests__/vtex-api.test.js +67 -0
  69. package/dist/src/services/vtex/__tests__/vtex-api.test.js.map +7 -0
  70. package/dist/src/services/vtex/vtex-api.js +6 -0
  71. package/dist/src/services/vtex/vtex-api.js.map +2 -2
  72. package/dist/src/tools/config/__tests__/list-profiles.test.js +154 -0
  73. package/dist/src/tools/config/__tests__/list-profiles.test.js.map +7 -0
  74. package/dist/src/tools/config/list-profiles.js +39 -3
  75. package/dist/src/tools/config/list-profiles.js.map +2 -2
  76. package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js +339 -0
  77. package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js.map +7 -0
  78. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js +225 -0
  79. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js.map +7 -0
  80. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js +148 -0
  81. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js.map +7 -0
  82. package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js +60 -0
  83. package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js.map +7 -0
  84. package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js +128 -0
  85. package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js.map +7 -0
  86. package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js +435 -0
  87. package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js.map +7 -0
  88. package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js +31 -0
  89. package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js.map +7 -0
  90. package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js +36 -0
  91. package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js.map +7 -0
  92. package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js +205 -0
  93. package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js.map +7 -0
  94. package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js +313 -0
  95. package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js.map +7 -0
  96. package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js +176 -0
  97. package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js.map +7 -0
  98. package/dist/src/tools/mercadolibre/get-full-storage-charges.js +183 -0
  99. package/dist/src/tools/mercadolibre/get-full-storage-charges.js.map +7 -0
  100. package/dist/src/tools/mercadolibre/get-order-billing-info.js +189 -0
  101. package/dist/src/tools/mercadolibre/get-order-billing-info.js.map +7 -0
  102. package/dist/src/tools/mercadolibre/get-pack-context-by-order.js +150 -0
  103. package/dist/src/tools/mercadolibre/get-pack-context-by-order.js.map +7 -0
  104. package/dist/src/tools/mercadolibre/get-payment-details.js +322 -0
  105. package/dist/src/tools/mercadolibre/get-payment-details.js.map +7 -0
  106. package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js +144 -0
  107. package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js.map +7 -0
  108. package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js +59 -0
  109. package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js.map +7 -0
  110. package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js +104 -0
  111. package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js.map +7 -0
  112. package/dist/src/tools/mercadolibre/index.js +32 -0
  113. package/dist/src/tools/mercadolibre/index.js.map +2 -2
  114. package/dist/src/tools/mercadolibre/product-ads-helpers.js +130 -0
  115. package/dist/src/tools/mercadolibre/product-ads-helpers.js.map +7 -0
  116. package/dist/src/tools/mercadolibre/reconcile-buyer-data.js +27 -0
  117. package/dist/src/tools/mercadolibre/reconcile-buyer-data.js.map +7 -0
  118. package/dist/src/tools/mercadolibre/reconcile-claim-data.js +46 -0
  119. package/dist/src/tools/mercadolibre/reconcile-claim-data.js.map +7 -0
  120. package/dist/src/tools/mercadolibre/reconcile-return-data.js +25 -0
  121. package/dist/src/tools/mercadolibre/reconcile-return-data.js.map +7 -0
  122. package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js +162 -0
  123. package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js.map +7 -0
  124. package/dist/src/tools/mercadolibre/search-product-ads-ads.js +216 -0
  125. package/dist/src/tools/mercadolibre/search-product-ads-ads.js.map +7 -0
  126. package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js +116 -0
  127. package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js.map +7 -0
  128. package/dist/src/tools/mercadolibre/validate-connection.js +40 -12
  129. package/dist/src/tools/mercadolibre/validate-connection.js.map +2 -2
  130. package/dist/tests/meli/mercadolibre-billing-provisions.test.js +378 -0
  131. package/dist/tests/meli/mercadolibre-billing-provisions.test.js.map +2 -2
  132. package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js +123 -0
  133. package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js.map +7 -0
  134. package/dist/tests/meli/mercadolibre-payment-details.test.js +356 -0
  135. package/dist/tests/meli/mercadolibre-payment-details.test.js.map +7 -0
  136. package/dist/tests/meli/mercadolibre-payments.test.js +62 -0
  137. package/dist/tests/meli/mercadolibre-payments.test.js.map +7 -0
  138. package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js +90 -0
  139. package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js.map +7 -0
  140. package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js +72 -0
  141. package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js.map +7 -0
  142. package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js +400 -0
  143. package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js.map +7 -0
  144. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js +31 -12
  145. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js.map +2 -2
  146. package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js +1 -1
  147. package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js.map +1 -1
  148. package/package.json +1 -1
  149. package/dist/src/google-ads/report-utils.js +0 -78
  150. package/dist/src/google-ads/report-utils.js.map +0 -7
  151. package/dist/src/search-console/search-console-utils.js +0 -275
  152. package/dist/src/search-console/search-console-utils.js.map +0 -7
  153. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +0 -165
  154. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +0 -7
  155. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +0 -233
  156. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +0 -7
  157. package/dist/src/tools/vtex/catalog-admin-batch.js +0 -298
  158. package/dist/src/tools/vtex/catalog-admin-batch.js.map +0 -7
@@ -0,0 +1,205 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { meliValidateConnectionHandler } from "../validate-connection.js";
3
+ import { resolveMercadoLibreProfileOrSelection } from "../profile-resolution.js";
4
+ import {
5
+ getMercadoLibreConnectionRow,
6
+ markMercadoLibreConnectionValidation,
7
+ updateMercadoLibreConnectionTokens
8
+ } from "../../../config/mercadolibre-profile-store.js";
9
+ import { decryptSecret } from "../../../config/vtex-crypto.js";
10
+ import {
11
+ formatMercadoLibreError,
12
+ getMercadoLibreUsersMeWithAccessToken
13
+ } from "../../../services/mercadolibre/mercadolibre-api.js";
14
+ vi.mock("mcp-use/server", () => ({
15
+ object: vi.fn((payload) => ({ kind: "object", payload })),
16
+ error: vi.fn((message) => ({ kind: "error", message }))
17
+ }));
18
+ vi.mock("../profile-resolution.js", () => ({
19
+ resolveMercadoLibreProfileOrSelection: vi.fn()
20
+ }));
21
+ vi.mock("../write-helpers.js", async () => {
22
+ const { z } = await import("zod");
23
+ return { mercadolibreProfileIdSchemaField: z.string().optional() };
24
+ });
25
+ vi.mock("../../../config/mercadolibre-profile-store.js", () => ({
26
+ getMercadoLibreConnectionRow: vi.fn(),
27
+ markMercadoLibreConnectionValidation: vi.fn(),
28
+ updateMercadoLibreConnectionTokens: vi.fn()
29
+ }));
30
+ vi.mock("../../../config/vtex-crypto.js", () => ({
31
+ decryptSecret: vi.fn()
32
+ }));
33
+ vi.mock("../../../services/mercadolibre/mercadolibre-api.js", () => ({
34
+ getMercadoLibreUsersMeWithAccessToken: vi.fn(),
35
+ formatMercadoLibreError: vi.fn((_err, fallback) => `safe:${fallback}`)
36
+ }));
37
+ const usableConnection = {
38
+ sellerId: "seller-99",
39
+ encryptedAccessToken: "encrypted-token",
40
+ expiresAt: /* @__PURE__ */ new Date("2099-01-01T00:00:00.000Z"),
41
+ scopes: ["read"],
42
+ status: "error"
43
+ };
44
+ function expectNoPersistence() {
45
+ expect(markMercadoLibreConnectionValidation).not.toHaveBeenCalled();
46
+ expect(updateMercadoLibreConnectionTokens).not.toHaveBeenCalled();
47
+ }
48
+ describe("meliValidateConnectionHandler", () => {
49
+ beforeEach(() => {
50
+ vi.clearAllMocks();
51
+ vi.useFakeTimers();
52
+ vi.setSystemTime(/* @__PURE__ */ new Date("2026-07-10T12:00:00.000Z"));
53
+ vi.mocked(resolveMercadoLibreProfileOrSelection).mockResolvedValue({
54
+ ok: true,
55
+ value: { profileId: "meli-profile-1" }
56
+ });
57
+ });
58
+ afterEach(() => {
59
+ vi.useRealTimers();
60
+ });
61
+ it("reports a missing connection as credential maintenance without probing or persisting", async () => {
62
+ vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue(null);
63
+ const result = await meliValidateConnectionHandler({ profileId: "meli-profile-1" });
64
+ expect(result).toEqual({
65
+ kind: "object",
66
+ payload: {
67
+ profile_id: "meli-profile-1",
68
+ observation_only: true,
69
+ validation_status: "credential_maintenance_required",
70
+ credential_status: "connection_not_found",
71
+ message: "No usable unexpired stored access token is available. Credential maintenance or refresh is required; this observation-only validation did not refresh tokens or update connection state."
72
+ }
73
+ });
74
+ expect(decryptSecret).not.toHaveBeenCalled();
75
+ expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();
76
+ expectNoPersistence();
77
+ });
78
+ it("reports a disabled connection as credential maintenance without probing or persisting", async () => {
79
+ vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({
80
+ ...usableConnection,
81
+ status: "disabled"
82
+ });
83
+ const result = await meliValidateConnectionHandler({ profileId: "meli-profile-1" });
84
+ expect(result).toEqual({
85
+ kind: "object",
86
+ payload: {
87
+ profile_id: "meli-profile-1",
88
+ observation_only: true,
89
+ validation_status: "credential_maintenance_required",
90
+ credential_status: "connection_disabled",
91
+ expires_at: "2099-01-01T00:00:00.000Z",
92
+ message: "No usable unexpired stored access token is available. Credential maintenance or refresh is required; this observation-only validation did not refresh tokens or update connection state."
93
+ }
94
+ });
95
+ expect(decryptSecret).not.toHaveBeenCalled();
96
+ expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();
97
+ expectNoPersistence();
98
+ });
99
+ it("reports a missing token as credential maintenance without probing or persisting", async () => {
100
+ vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({
101
+ ...usableConnection,
102
+ encryptedAccessToken: ""
103
+ });
104
+ const result = await meliValidateConnectionHandler({ profileId: "meli-profile-1" });
105
+ expect(result).toMatchObject({
106
+ kind: "object",
107
+ payload: {
108
+ profile_id: "meli-profile-1",
109
+ observation_only: true,
110
+ validation_status: "credential_maintenance_required",
111
+ credential_status: "token_missing",
112
+ expires_at: "2099-01-01T00:00:00.000Z"
113
+ }
114
+ });
115
+ expect(decryptSecret).not.toHaveBeenCalled();
116
+ expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();
117
+ expectNoPersistence();
118
+ });
119
+ it("reports an unknown expiry as credential maintenance without probing or persisting", async () => {
120
+ vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({
121
+ ...usableConnection,
122
+ expiresAt: null
123
+ });
124
+ const result = await meliValidateConnectionHandler({ profileId: "meli-profile-1" });
125
+ expect(result).toMatchObject({
126
+ kind: "object",
127
+ payload: {
128
+ profile_id: "meli-profile-1",
129
+ observation_only: true,
130
+ validation_status: "credential_maintenance_required",
131
+ credential_status: "expiry_unknown"
132
+ }
133
+ });
134
+ expect(result).not.toMatchObject({
135
+ payload: { expires_at: expect.anything() }
136
+ });
137
+ expect(decryptSecret).not.toHaveBeenCalled();
138
+ expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();
139
+ expectNoPersistence();
140
+ });
141
+ it("probes /users/me with the persisted unexpired token without changing connection state", async () => {
142
+ vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue(usableConnection);
143
+ vi.mocked(decryptSecret).mockReturnValue("stored-access-token");
144
+ vi.mocked(getMercadoLibreUsersMeWithAccessToken).mockResolvedValue({
145
+ id: 12345,
146
+ nickname: "meli-store"
147
+ });
148
+ const result = await meliValidateConnectionHandler({ profileId: "meli-profile-1" });
149
+ expect(getMercadoLibreUsersMeWithAccessToken).toHaveBeenCalledWith("stored-access-token");
150
+ expect(result).toEqual({
151
+ kind: "object",
152
+ payload: {
153
+ profile_id: "meli-profile-1",
154
+ observation_only: true,
155
+ validation_status: "valid",
156
+ seller_id: "seller-99",
157
+ account_id: 12345,
158
+ nickname: "meli-store",
159
+ expires_at: "2099-01-01T00:00:00.000Z",
160
+ scopes: ["read"]
161
+ }
162
+ });
163
+ expectNoPersistence();
164
+ });
165
+ it("reports expired credentials without decrypting, refreshing, or persisting tokens", async () => {
166
+ vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({
167
+ ...usableConnection,
168
+ expiresAt: /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z")
169
+ });
170
+ const result = await meliValidateConnectionHandler({ profileId: "meli-profile-1" });
171
+ expect(result).toEqual({
172
+ kind: "object",
173
+ payload: {
174
+ profile_id: "meli-profile-1",
175
+ observation_only: true,
176
+ validation_status: "credential_maintenance_required",
177
+ credential_status: "token_expired",
178
+ expires_at: "2000-01-01T00:00:00.000Z",
179
+ message: "No usable unexpired stored access token is available. Credential maintenance or refresh is required; this observation-only validation did not refresh tokens or update connection state."
180
+ }
181
+ });
182
+ expect(decryptSecret).not.toHaveBeenCalled();
183
+ expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();
184
+ expectNoPersistence();
185
+ });
186
+ it("returns a safe upstream probe error without mutating connection state", async () => {
187
+ vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue(usableConnection);
188
+ vi.mocked(decryptSecret).mockReturnValue("stored-access-token");
189
+ vi.mocked(getMercadoLibreUsersMeWithAccessToken).mockRejectedValue(
190
+ new Error("upstream unavailable: Bearer stored-access-token access_token=stored-access-token")
191
+ );
192
+ const result = await meliValidateConnectionHandler({ profileId: "meli-profile-1" });
193
+ expect(formatMercadoLibreError).toHaveBeenCalledWith(
194
+ expect.any(Error),
195
+ "Failed to validate MercadoLibre connection"
196
+ );
197
+ expect(result).toEqual({
198
+ kind: "error",
199
+ message: "safe:Failed to validate MercadoLibre connection"
200
+ });
201
+ expect(JSON.stringify(result)).not.toContain("stored-access-token");
202
+ expectNoPersistence();
203
+ });
204
+ });
205
+ //# sourceMappingURL=validate-connection.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/tools/mercadolibre/__tests__/validate-connection.test.ts"],
4
+ "sourcesContent": ["import { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { meliValidateConnectionHandler } from \"../validate-connection.js\";\nimport { resolveMercadoLibreProfileOrSelection } from \"../profile-resolution.js\";\nimport {\n getMercadoLibreConnectionRow,\n markMercadoLibreConnectionValidation,\n updateMercadoLibreConnectionTokens,\n} from \"../../../config/mercadolibre-profile-store.js\";\nimport { decryptSecret } from \"../../../config/vtex-crypto.js\";\nimport {\n formatMercadoLibreError,\n getMercadoLibreUsersMeWithAccessToken,\n} from \"../../../services/mercadolibre/mercadolibre-api.js\";\n\nvi.mock(\"mcp-use/server\", () => ({\n object: vi.fn((payload: unknown) => ({ kind: \"object\", payload })),\n error: vi.fn((message: string) => ({ kind: \"error\", message })),\n}));\n\nvi.mock(\"../profile-resolution.js\", () => ({\n resolveMercadoLibreProfileOrSelection: vi.fn(),\n}));\n\nvi.mock(\"../write-helpers.js\", async () => {\n const { z } = await import(\"zod\");\n return { mercadolibreProfileIdSchemaField: z.string().optional() };\n});\n\nvi.mock(\"../../../config/mercadolibre-profile-store.js\", () => ({\n getMercadoLibreConnectionRow: vi.fn(),\n markMercadoLibreConnectionValidation: vi.fn(),\n updateMercadoLibreConnectionTokens: vi.fn(),\n}));\n\nvi.mock(\"../../../config/vtex-crypto.js\", () => ({\n decryptSecret: vi.fn(),\n}));\n\nvi.mock(\"../../../services/mercadolibre/mercadolibre-api.js\", () => ({\n getMercadoLibreUsersMeWithAccessToken: vi.fn(),\n formatMercadoLibreError: vi.fn((_err: unknown, fallback: string) => `safe:${fallback}`),\n}));\n\nconst usableConnection = {\n sellerId: \"seller-99\",\n encryptedAccessToken: \"encrypted-token\",\n expiresAt: new Date(\"2099-01-01T00:00:00.000Z\"),\n scopes: [\"read\"],\n status: \"error\",\n};\n\nfunction expectNoPersistence() {\n expect(markMercadoLibreConnectionValidation).not.toHaveBeenCalled();\n expect(updateMercadoLibreConnectionTokens).not.toHaveBeenCalled();\n}\n\ndescribe(\"meliValidateConnectionHandler\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n vi.useFakeTimers();\n vi.setSystemTime(new Date(\"2026-07-10T12:00:00.000Z\"));\n vi.mocked(resolveMercadoLibreProfileOrSelection).mockResolvedValue({\n ok: true,\n value: { profileId: \"meli-profile-1\" },\n });\n });\n\n afterEach(() => {\n vi.useRealTimers();\n });\n\n it(\"reports a missing connection as credential maintenance without probing or persisting\", async () => {\n vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue(null);\n\n const result = await meliValidateConnectionHandler({ profileId: \"meli-profile-1\" });\n\n expect(result).toEqual({\n kind: \"object\",\n payload: {\n profile_id: \"meli-profile-1\",\n observation_only: true,\n validation_status: \"credential_maintenance_required\",\n credential_status: \"connection_not_found\",\n message:\n \"No usable unexpired stored access token is available. Credential maintenance or refresh is required; this observation-only validation did not refresh tokens or update connection state.\",\n },\n });\n expect(decryptSecret).not.toHaveBeenCalled();\n expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();\n expectNoPersistence();\n });\n\n it(\"reports a disabled connection as credential maintenance without probing or persisting\", async () => {\n vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({\n ...usableConnection,\n status: \"disabled\",\n } as never);\n\n const result = await meliValidateConnectionHandler({ profileId: \"meli-profile-1\" });\n\n expect(result).toEqual({\n kind: \"object\",\n payload: {\n profile_id: \"meli-profile-1\",\n observation_only: true,\n validation_status: \"credential_maintenance_required\",\n credential_status: \"connection_disabled\",\n expires_at: \"2099-01-01T00:00:00.000Z\",\n message:\n \"No usable unexpired stored access token is available. Credential maintenance or refresh is required; this observation-only validation did not refresh tokens or update connection state.\",\n },\n });\n expect(decryptSecret).not.toHaveBeenCalled();\n expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();\n expectNoPersistence();\n });\n\n it(\"reports a missing token as credential maintenance without probing or persisting\", async () => {\n vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({\n ...usableConnection,\n encryptedAccessToken: \"\",\n } as never);\n\n const result = await meliValidateConnectionHandler({ profileId: \"meli-profile-1\" });\n\n expect(result).toMatchObject({\n kind: \"object\",\n payload: {\n profile_id: \"meli-profile-1\",\n observation_only: true,\n validation_status: \"credential_maintenance_required\",\n credential_status: \"token_missing\",\n expires_at: \"2099-01-01T00:00:00.000Z\",\n },\n });\n expect(decryptSecret).not.toHaveBeenCalled();\n expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();\n expectNoPersistence();\n });\n\n it(\"reports an unknown expiry as credential maintenance without probing or persisting\", async () => {\n vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({\n ...usableConnection,\n expiresAt: null,\n } as never);\n\n const result = await meliValidateConnectionHandler({ profileId: \"meli-profile-1\" });\n\n expect(result).toMatchObject({\n kind: \"object\",\n payload: {\n profile_id: \"meli-profile-1\",\n observation_only: true,\n validation_status: \"credential_maintenance_required\",\n credential_status: \"expiry_unknown\",\n },\n });\n expect(result).not.toMatchObject({\n payload: { expires_at: expect.anything() },\n });\n expect(decryptSecret).not.toHaveBeenCalled();\n expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();\n expectNoPersistence();\n });\n\n it(\"probes /users/me with the persisted unexpired token without changing connection state\", async () => {\n vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue(usableConnection as never);\n vi.mocked(decryptSecret).mockReturnValue(\"stored-access-token\");\n vi.mocked(getMercadoLibreUsersMeWithAccessToken).mockResolvedValue({\n id: 12345,\n nickname: \"meli-store\",\n });\n\n const result = await meliValidateConnectionHandler({ profileId: \"meli-profile-1\" });\n\n expect(getMercadoLibreUsersMeWithAccessToken).toHaveBeenCalledWith(\"stored-access-token\");\n expect(result).toEqual({\n kind: \"object\",\n payload: {\n profile_id: \"meli-profile-1\",\n observation_only: true,\n validation_status: \"valid\",\n seller_id: \"seller-99\",\n account_id: 12345,\n nickname: \"meli-store\",\n expires_at: \"2099-01-01T00:00:00.000Z\",\n scopes: [\"read\"],\n },\n });\n expectNoPersistence();\n });\n\n it(\"reports expired credentials without decrypting, refreshing, or persisting tokens\", async () => {\n vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue({\n ...usableConnection,\n expiresAt: new Date(\"2000-01-01T00:00:00.000Z\"),\n } as never);\n\n const result = await meliValidateConnectionHandler({ profileId: \"meli-profile-1\" });\n\n expect(result).toEqual({\n kind: \"object\",\n payload: {\n profile_id: \"meli-profile-1\",\n observation_only: true,\n validation_status: \"credential_maintenance_required\",\n credential_status: \"token_expired\",\n expires_at: \"2000-01-01T00:00:00.000Z\",\n message:\n \"No usable unexpired stored access token is available. Credential maintenance or refresh is required; this observation-only validation did not refresh tokens or update connection state.\",\n },\n });\n expect(decryptSecret).not.toHaveBeenCalled();\n expect(getMercadoLibreUsersMeWithAccessToken).not.toHaveBeenCalled();\n expectNoPersistence();\n });\n\n it(\"returns a safe upstream probe error without mutating connection state\", async () => {\n vi.mocked(getMercadoLibreConnectionRow).mockResolvedValue(usableConnection as never);\n vi.mocked(decryptSecret).mockReturnValue(\"stored-access-token\");\n vi.mocked(getMercadoLibreUsersMeWithAccessToken).mockRejectedValue(\n new Error(\"upstream unavailable: Bearer stored-access-token access_token=stored-access-token\")\n );\n\n const result = await meliValidateConnectionHandler({ profileId: \"meli-profile-1\" });\n\n expect(formatMercadoLibreError).toHaveBeenCalledWith(\n expect.any(Error),\n \"Failed to validate MercadoLibre connection\"\n );\n expect(result).toEqual({\n kind: \"error\",\n message: \"safe:Failed to validate MercadoLibre connection\",\n });\n expect(JSON.stringify(result)).not.toContain(\"stored-access-token\");\n expectNoPersistence();\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,313 @@
1
+ import { error, object } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import {
4
+ formatMercadoLibreError
5
+ } from "../../services/mercadolibre/mercadolibre-api.js";
6
+ import {
7
+ getMercadoLibreBillingProvisionsByOrder
8
+ } from "../../services/mercadolibre/mercadolibre-billing.js";
9
+ import { stripNulls } from "../../utils/strip-payload.js";
10
+ import {
11
+ asRecord,
12
+ normalizeScalarString
13
+ } from "./helpers.js";
14
+ import { resolveMercadoLibreProfileOrSelection } from "./profile-resolution.js";
15
+ const meliGetBillingProvisionsByOrderSchema = z.object({
16
+ profileId: z.string().trim().min(1).describe("Explicit MercadoLibre profile id to use."),
17
+ orderIds: z.array(z.string().trim().min(1).describe("MercadoLibre order id.")).min(1).describe("One or more MercadoLibre order IDs to fetch billing provisions for.")
18
+ });
19
+ const ordersSchema = [
20
+ "order_id",
21
+ "sale_fee",
22
+ "payment_info_count",
23
+ "detail_count",
24
+ "document_id",
25
+ "currency_id",
26
+ "marketplace"
27
+ ];
28
+ const paymentInfoSchema = [
29
+ "order_id",
30
+ "payment_id",
31
+ "payment_type",
32
+ "payment_method_id",
33
+ "installments",
34
+ "transaction_amount",
35
+ "total_paid_amount",
36
+ "shipping_cost",
37
+ "coupon_amount",
38
+ "status",
39
+ "status_detail"
40
+ ];
41
+ const detailsSchema = [
42
+ "order_id",
43
+ "detail_id",
44
+ "detail_type",
45
+ "detail_sub_type",
46
+ "transaction_detail",
47
+ "detail_amount",
48
+ "currency_id",
49
+ "concept_type",
50
+ "operation_id",
51
+ "shipping_id",
52
+ "pack_id",
53
+ "inventory_id"
54
+ ];
55
+ const detailsSalesSchema = [
56
+ "detail_id",
57
+ "order_id",
58
+ "operation_id",
59
+ "sale_date_time",
60
+ "payer_nickname",
61
+ "transaction_amount"
62
+ ];
63
+ const detailsItemsSchema = [
64
+ "detail_id",
65
+ "item_id",
66
+ "item_title",
67
+ "item_amount",
68
+ "item_price",
69
+ "item_kit_id",
70
+ "store_id",
71
+ "order_id",
72
+ "fees_added_in_publication"
73
+ ];
74
+ function asRecordArray(value) {
75
+ if (Array.isArray(value)) {
76
+ return value.filter(
77
+ (entry) => entry != null && typeof entry === "object" && !Array.isArray(entry)
78
+ );
79
+ }
80
+ const record = asRecord(value);
81
+ return Object.keys(record).length > 0 ? [record] : [];
82
+ }
83
+ function toOptionalNumber(value) {
84
+ if (typeof value === "number") {
85
+ return Number.isFinite(value) ? value : null;
86
+ }
87
+ if (typeof value !== "string" || value.trim() === "") {
88
+ return null;
89
+ }
90
+ const numericValue = Number(value);
91
+ return Number.isFinite(numericValue) ? numericValue : null;
92
+ }
93
+ function normalizeFeesAddedInPublication(value) {
94
+ return value === "Si" || value === "No" ? value : null;
95
+ }
96
+ function resolveDetailOrderId(detail, fallbackOrderId) {
97
+ const salesInfo = asRecordArray(detail.sales_info ?? detail.details_sales);
98
+ return normalizeScalarString(salesInfo[0]?.order_id) || normalizeScalarString(detail.order_id) || fallbackOrderId;
99
+ }
100
+ function projectOrderRow(row) {
101
+ const paymentInfo = asRecordArray(row.payment_info);
102
+ const details = asRecordArray(row.details);
103
+ const firstDetail = details[0] ?? {};
104
+ const orderId = normalizeScalarString(row.order_id) || normalizeScalarString(paymentInfo[0]?.order_id) || normalizeScalarString(firstDetail.order_id) || resolveDetailOrderId(firstDetail, null) || null;
105
+ const documentInfo = asRecord(row.document_info);
106
+ const currencyInfo = asRecord(row.currency_info);
107
+ const marketplaceInfo = asRecord(row.marketplace_info);
108
+ return [
109
+ orderId,
110
+ // 0: order_id
111
+ toOptionalNumber(row.sale_fee),
112
+ // 1: sale_fee
113
+ paymentInfo.length,
114
+ // 2: payment_info_count
115
+ details.length,
116
+ // 3: detail_count
117
+ normalizeScalarString(documentInfo.document_id ?? row.document_id) || null,
118
+ // 4: document_id
119
+ normalizeScalarString(currencyInfo.currency_id ?? row.currency_id) || null,
120
+ // 5: currency_id
121
+ normalizeScalarString(marketplaceInfo.marketplace ?? row.marketplace) || null
122
+ // 6: marketplace
123
+ ];
124
+ }
125
+ function projectPaymentRow(orderId, payment) {
126
+ return [
127
+ orderId,
128
+ // 0: order_id
129
+ normalizeScalarString(payment.payment_id ?? payment.id) || null,
130
+ // 1: payment_id
131
+ normalizeScalarString(payment.payment_type) || null,
132
+ // 2: payment_type
133
+ normalizeScalarString(payment.payment_method_id) || null,
134
+ // 3: payment_method_id
135
+ toOptionalNumber(payment.installments),
136
+ // 4: installments
137
+ toOptionalNumber(payment.transaction_amount),
138
+ // 5: transaction_amount
139
+ toOptionalNumber(payment.total_paid_amount),
140
+ // 6: total_paid_amount
141
+ toOptionalNumber(payment.shipping_cost),
142
+ // 7: shipping_cost
143
+ toOptionalNumber(payment.coupon_amount),
144
+ // 8: coupon_amount
145
+ normalizeScalarString(payment.status) || null,
146
+ // 9: status
147
+ normalizeScalarString(payment.status_detail) || null
148
+ // 10: status_detail
149
+ ];
150
+ }
151
+ function projectDetailRow(orderId, detail, fallbackCurrencyId) {
152
+ const chargeInfo = asRecord(detail.charge_info);
153
+ const currencyInfo = asRecord(detail.currency_info);
154
+ const detailOrderId = resolveDetailOrderId(detail, orderId);
155
+ const detailAmount = chargeInfo.detail_amount ?? detail.detail_amount;
156
+ return [
157
+ detailOrderId,
158
+ // 0: order_id
159
+ normalizeScalarString(chargeInfo.detail_id ?? detail.detail_id) || null,
160
+ // 1: detail_id
161
+ normalizeScalarString(chargeInfo.detail_type ?? detail.detail_type) || null,
162
+ // 2: detail_type
163
+ normalizeScalarString(chargeInfo.detail_sub_type ?? detail.detail_sub_type) || null,
164
+ // 3: detail_sub_type
165
+ normalizeScalarString(chargeInfo.transaction_detail ?? detail.transaction_detail) || null,
166
+ // 4: transaction_detail
167
+ toOptionalNumber(detailAmount),
168
+ // 5: detail_amount
169
+ normalizeScalarString(currencyInfo.currency_id ?? detail.currency_id) || fallbackCurrencyId,
170
+ // 6: currency_id
171
+ normalizeScalarString(chargeInfo.concept_type ?? detail.concept_type) || null,
172
+ // 7: concept_type
173
+ normalizeScalarString(chargeInfo.operation_id ?? detail.operation_id) || null,
174
+ // 8: operation_id
175
+ normalizeScalarString(chargeInfo.shipping_id ?? detail.shipping_id) || null,
176
+ // 9: shipping_id
177
+ normalizeScalarString(chargeInfo.pack_id ?? detail.pack_id) || null,
178
+ // 10: pack_id
179
+ normalizeScalarString(chargeInfo.inventory_id ?? detail.inventory_id) || null
180
+ // 11: inventory_id
181
+ ];
182
+ }
183
+ function projectSalesRow(detailId, sale) {
184
+ return [
185
+ detailId,
186
+ // 0: detail_id
187
+ normalizeScalarString(sale.order_id) || null,
188
+ // 1: order_id
189
+ normalizeScalarString(sale.operation_id) || null,
190
+ // 2: operation_id
191
+ normalizeScalarString(sale.sale_date_time) || null,
192
+ // 3: sale_date_time
193
+ null,
194
+ // 4: payer_nickname (redacted)
195
+ toOptionalNumber(sale.transaction_amount)
196
+ // 5: transaction_amount
197
+ ];
198
+ }
199
+ function projectItemsRow(detailId, detailOrderId, item) {
200
+ return [
201
+ detailId,
202
+ // 0: detail_id
203
+ normalizeScalarString(item.item_id) || null,
204
+ // 1: item_id
205
+ normalizeScalarString(item.item_title) || null,
206
+ // 2: item_title
207
+ toOptionalNumber(item.item_amount),
208
+ // 3: item_amount
209
+ toOptionalNumber(item.item_price),
210
+ // 4: item_price
211
+ normalizeScalarString(item.item_kit_id) || null,
212
+ // 5: item_kit_id
213
+ normalizeScalarString(item.store_id) || null,
214
+ // 6: store_id
215
+ normalizeScalarString(item.order_id) || detailOrderId,
216
+ // 7: order_id
217
+ normalizeFeesAddedInPublication(item.fees_added_in_publication)
218
+ // 8: fees_added_in_publication
219
+ ];
220
+ }
221
+ async function meliGetBillingProvisionsByOrderHandler(params) {
222
+ try {
223
+ const profileResolution = await resolveMercadoLibreProfileOrSelection(params.profileId);
224
+ if (!profileResolution.ok) {
225
+ return profileResolution.response;
226
+ }
227
+ const profileId = profileResolution.value.profileId;
228
+ const result = await getMercadoLibreBillingProvisionsByOrder(profileId, {
229
+ orderIds: params.orderIds
230
+ });
231
+ const orderRows = [];
232
+ const paymentRows = [];
233
+ const detailRows = [];
234
+ const salesRows = [];
235
+ const itemsRows = [];
236
+ for (const row of result.results) {
237
+ const projectedOrder = projectOrderRow(row);
238
+ const orderId = normalizeScalarString(projectedOrder[0]) || null;
239
+ const fallbackCurrencyId = normalizeScalarString(projectedOrder[5]) || null;
240
+ orderRows.push(projectedOrder);
241
+ const paymentInfoRows = asRecordArray(row.payment_info);
242
+ for (const paymentInfo of paymentInfoRows) {
243
+ paymentRows.push(projectPaymentRow(orderId, paymentInfo));
244
+ }
245
+ const details = asRecordArray(row.details);
246
+ for (const detail of details) {
247
+ const chargeInfo = asRecord(detail.charge_info);
248
+ const detailId = normalizeScalarString(chargeInfo.detail_id ?? detail.detail_id) || null;
249
+ const detailOrderId = resolveDetailOrderId(detail, orderId);
250
+ detailRows.push(projectDetailRow(orderId, detail, fallbackCurrencyId));
251
+ const detailSales = asRecordArray(detail.sales_info ?? detail.details_sales);
252
+ for (const ds of detailSales) {
253
+ salesRows.push(projectSalesRow(detailId, ds));
254
+ }
255
+ const detailItems = asRecordArray(detail.items_info ?? detail.details_items);
256
+ for (const di of detailItems) {
257
+ itemsRows.push(projectItemsRow(detailId, detailOrderId, di));
258
+ }
259
+ }
260
+ }
261
+ const saleFeeNote = "sale_fee may be null for some orders depending on how Mercado Libre settles the billing provision. Preserve it as nullable in downstream analysis.";
262
+ const metadata = {
263
+ order_ids_requested: result.order_ids_requested,
264
+ order_ids_found: result.order_ids_found,
265
+ order_ids_not_found: result.order_ids_not_found,
266
+ request_chunks_total: result.chunks_total,
267
+ request_chunks_succeeded: result.chunks_succeeded,
268
+ request_chunks_failed: result.chunks_failed,
269
+ coverage_complete: result.coverage_complete,
270
+ endpoint: "/billing/integration/group/ML/order/details",
271
+ sale_fee_note: saleFeeNote,
272
+ fees_added_in_publication_note: 'items_info.fees_added_in_publication preserves only exact upstream "Si"/"No" values; all other values are null. It represents installments offered in the listing, not buyer-used payment installments or the CVFN financing cost.',
273
+ pack_resolution_note: "This tool operates on order IDs and does not inherit a value across pack members. Consumers must resolve every member order and apply unanimity externally."
274
+ };
275
+ if (result.failures.length > 0) {
276
+ metadata.failures = result.failures;
277
+ }
278
+ const stripped = stripNulls({
279
+ profile_id: profileId,
280
+ endpoint: "/billing/integration/group/ML/order/details",
281
+ metadata
282
+ });
283
+ stripped.orders_schema = ordersSchema;
284
+ stripped.orders = orderRows;
285
+ stripped.payment_info_schema = paymentInfoSchema;
286
+ stripped.payment_info = paymentRows;
287
+ stripped.details_schema = detailsSchema;
288
+ stripped.details = detailRows;
289
+ stripped.details_sales_schema = detailsSalesSchema;
290
+ stripped.details_sales = salesRows;
291
+ stripped.details_items_schema = detailsItemsSchema;
292
+ stripped.details_items = itemsRows;
293
+ const meta = stripped.metadata;
294
+ meta.order_ids_requested = result.order_ids_requested;
295
+ meta.order_ids_found = result.order_ids_found;
296
+ meta.order_ids_not_found = result.order_ids_not_found;
297
+ return object(stripped);
298
+ } catch (err) {
299
+ return error(
300
+ formatMercadoLibreError(err, "Failed to get MercadoLibre billing provisions by order")
301
+ );
302
+ }
303
+ }
304
+ export {
305
+ detailsItemsSchema,
306
+ detailsSalesSchema,
307
+ detailsSchema,
308
+ meliGetBillingProvisionsByOrderHandler,
309
+ meliGetBillingProvisionsByOrderSchema,
310
+ ordersSchema,
311
+ paymentInfoSchema
312
+ };
313
+ //# sourceMappingURL=get-billing-provisions-by-order.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/mercadolibre/get-billing-provisions-by-order.ts"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n formatMercadoLibreError,\n} from \"../../services/mercadolibre/mercadolibre-api.js\";\nimport {\n getMercadoLibreBillingProvisionsByOrder,\n} from \"../../services/mercadolibre/mercadolibre-billing.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport {\n asRecord,\n normalizeScalarString,\n} from \"./helpers.js\";\nimport { resolveMercadoLibreProfileOrSelection } from \"./profile-resolution.js\";\n\n// \u2500\u2500 Schema \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const meliGetBillingProvisionsByOrderSchema = z.object({\n profileId: z.string().trim().min(1).describe(\"Explicit MercadoLibre profile id to use.\"),\n orderIds: z\n .array(z.string().trim().min(1).describe(\"MercadoLibre order id.\"))\n .min(1)\n .describe(\"One or more MercadoLibre order IDs to fetch billing provisions for.\"),\n});\n\n// \u2500\u2500 Compact schemas \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Top-level order info returned by the official by-order endpoint. */\nexport const ordersSchema = [\n \"order_id\",\n \"sale_fee\",\n \"payment_info_count\",\n \"detail_count\",\n \"document_id\",\n \"currency_id\",\n \"marketplace\",\n] as const;\n\n/** Payment info per order. */\nexport const paymentInfoSchema = [\n \"order_id\",\n \"payment_id\",\n \"payment_type\",\n \"payment_method_id\",\n \"installments\",\n \"transaction_amount\",\n \"total_paid_amount\",\n \"shipping_cost\",\n \"coupon_amount\",\n \"status\",\n \"status_detail\",\n] as const;\n\n/** Detail-level charges within an order. */\nexport const detailsSchema = [\n \"order_id\",\n \"detail_id\",\n \"detail_type\",\n \"detail_sub_type\",\n \"transaction_detail\",\n \"detail_amount\",\n \"currency_id\",\n \"concept_type\",\n \"operation_id\",\n \"shipping_id\",\n \"pack_id\",\n \"inventory_id\",\n] as const;\n\n/** Sales info within details (multiplicity). */\nexport const detailsSalesSchema = [\n \"detail_id\",\n \"order_id\",\n \"operation_id\",\n \"sale_date_time\",\n \"payer_nickname\",\n \"transaction_amount\",\n] as const;\n\n/** Items info within details (multiplicity). */\nexport const detailsItemsSchema = [\n \"detail_id\",\n \"item_id\",\n \"item_title\",\n \"item_amount\",\n \"item_price\",\n \"item_kit_id\",\n \"store_id\",\n \"order_id\",\n \"fees_added_in_publication\",\n] as const;\n\n// \u2500\u2500 Row projectors \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype OrderRow = (string | number | null)[];\ntype PaymentRow = (string | number | null)[];\ntype DetailRow = (string | number | null)[];\ntype SalesRow = (string | number | null)[];\ntype ItemsRow = (string | number | null)[];\n\nfunction asRecordArray(value: unknown): Record<string, unknown>[] {\n if (Array.isArray(value)) {\n return value.filter(\n (entry): entry is Record<string, unknown> =>\n entry != null && typeof entry === \"object\" && !Array.isArray(entry)\n ) as Record<string, unknown>[];\n }\n\n const record = asRecord(value);\n return Object.keys(record).length > 0 ? [record] : [];\n}\n\nfunction toOptionalNumber(value: unknown): number | null {\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : null;\n }\n\n if (typeof value !== \"string\" || value.trim() === \"\") {\n return null;\n }\n\n const numericValue = Number(value);\n return Number.isFinite(numericValue) ? numericValue : null;\n}\n\nfunction normalizeFeesAddedInPublication(value: unknown): \"Si\" | \"No\" | null {\n return value === \"Si\" || value === \"No\" ? value : null;\n}\n\nfunction resolveDetailOrderId(\n detail: Record<string, unknown>,\n fallbackOrderId: string | null\n): string | null {\n const salesInfo = asRecordArray(detail.sales_info ?? detail.details_sales);\n return (\n normalizeScalarString(salesInfo[0]?.order_id) ||\n normalizeScalarString(detail.order_id) ||\n fallbackOrderId\n );\n}\n\nfunction projectOrderRow(row: Record<string, unknown>): OrderRow {\n const paymentInfo = asRecordArray(row.payment_info);\n const details = asRecordArray(row.details);\n const firstDetail = details[0] ?? {};\n const orderId =\n normalizeScalarString(row.order_id) ||\n normalizeScalarString(paymentInfo[0]?.order_id) ||\n normalizeScalarString(firstDetail.order_id) ||\n resolveDetailOrderId(firstDetail, null) ||\n null;\n const documentInfo = asRecord(row.document_info);\n const currencyInfo = asRecord(row.currency_info);\n const marketplaceInfo = asRecord(row.marketplace_info);\n\n return [\n orderId, // 0: order_id\n toOptionalNumber(row.sale_fee), // 1: sale_fee\n paymentInfo.length, // 2: payment_info_count\n details.length, // 3: detail_count\n normalizeScalarString(documentInfo.document_id ?? row.document_id) || null, // 4: document_id\n normalizeScalarString(currencyInfo.currency_id ?? row.currency_id) || null, // 5: currency_id\n normalizeScalarString(marketplaceInfo.marketplace ?? row.marketplace) || null, // 6: marketplace\n ];\n}\n\nfunction projectPaymentRow(orderId: string | null, payment: Record<string, unknown>): PaymentRow {\n return [\n orderId, // 0: order_id\n normalizeScalarString(payment.payment_id ?? payment.id) || null, // 1: payment_id\n normalizeScalarString(payment.payment_type) || null, // 2: payment_type\n normalizeScalarString(payment.payment_method_id) || null, // 3: payment_method_id\n toOptionalNumber(payment.installments), // 4: installments\n toOptionalNumber(payment.transaction_amount), // 5: transaction_amount\n toOptionalNumber(payment.total_paid_amount), // 6: total_paid_amount\n toOptionalNumber(payment.shipping_cost), // 7: shipping_cost\n toOptionalNumber(payment.coupon_amount), // 8: coupon_amount\n normalizeScalarString(payment.status) || null, // 9: status\n normalizeScalarString(payment.status_detail) || null, // 10: status_detail\n ];\n}\n\nfunction projectDetailRow(\n orderId: string | null,\n detail: Record<string, unknown>,\n fallbackCurrencyId: string | null\n): DetailRow {\n const chargeInfo = asRecord(detail.charge_info);\n const currencyInfo = asRecord(detail.currency_info);\n const detailOrderId = resolveDetailOrderId(detail, orderId);\n const detailAmount = chargeInfo.detail_amount ?? detail.detail_amount;\n\n return [\n detailOrderId, // 0: order_id\n normalizeScalarString(chargeInfo.detail_id ?? detail.detail_id) || null, // 1: detail_id\n normalizeScalarString(chargeInfo.detail_type ?? detail.detail_type) || null, // 2: detail_type\n normalizeScalarString(chargeInfo.detail_sub_type ?? detail.detail_sub_type) || null, // 3: detail_sub_type\n normalizeScalarString(chargeInfo.transaction_detail ?? detail.transaction_detail) || null, // 4: transaction_detail\n toOptionalNumber(detailAmount), // 5: detail_amount\n normalizeScalarString(currencyInfo.currency_id ?? detail.currency_id) || fallbackCurrencyId, // 6: currency_id\n normalizeScalarString(chargeInfo.concept_type ?? detail.concept_type) || null, // 7: concept_type\n normalizeScalarString(chargeInfo.operation_id ?? detail.operation_id) || null, // 8: operation_id\n normalizeScalarString(chargeInfo.shipping_id ?? detail.shipping_id) || null, // 9: shipping_id\n normalizeScalarString(chargeInfo.pack_id ?? detail.pack_id) || null, // 10: pack_id\n normalizeScalarString(chargeInfo.inventory_id ?? detail.inventory_id) || null, // 11: inventory_id\n ];\n}\n\nfunction projectSalesRow(detailId: string | null, sale: Record<string, unknown>): SalesRow {\n return [\n detailId, // 0: detail_id\n normalizeScalarString(sale.order_id) || null, // 1: order_id\n normalizeScalarString(sale.operation_id) || null, // 2: operation_id\n normalizeScalarString(sale.sale_date_time) || null, // 3: sale_date_time\n null, // 4: payer_nickname (redacted)\n toOptionalNumber(sale.transaction_amount), // 5: transaction_amount\n ];\n}\n\nfunction projectItemsRow(\n detailId: string | null,\n detailOrderId: string | null,\n item: Record<string, unknown>\n): ItemsRow {\n return [\n detailId, // 0: detail_id\n normalizeScalarString(item.item_id) || null, // 1: item_id\n normalizeScalarString(item.item_title) || null, // 2: item_title\n toOptionalNumber(item.item_amount), // 3: item_amount\n toOptionalNumber(item.item_price), // 4: item_price\n normalizeScalarString(item.item_kit_id) || null, // 5: item_kit_id\n normalizeScalarString(item.store_id) || null, // 6: store_id\n normalizeScalarString(item.order_id) || detailOrderId, // 7: order_id\n normalizeFeesAddedInPublication(item.fees_added_in_publication), // 8: fees_added_in_publication\n ];\n}\n\n// \u2500\u2500 Handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function meliGetBillingProvisionsByOrderHandler(\n params: z.infer<typeof meliGetBillingProvisionsByOrderSchema>\n) {\n try {\n const profileResolution = await resolveMercadoLibreProfileOrSelection(params.profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const profileId = profileResolution.value.profileId;\n\n const result = await getMercadoLibreBillingProvisionsByOrder(profileId, {\n orderIds: params.orderIds,\n });\n\n // \u2500\u2500 Accumulate compact rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const orderRows: OrderRow[] = [];\n const paymentRows: PaymentRow[] = [];\n const detailRows: DetailRow[] = [];\n const salesRows: SalesRow[] = [];\n const itemsRows: ItemsRow[] = [];\n\n for (const row of result.results) {\n const projectedOrder = projectOrderRow(row);\n const orderId = normalizeScalarString(projectedOrder[0]) || null;\n const fallbackCurrencyId = normalizeScalarString(projectedOrder[5]) || null;\n\n // \u2500\u2500 Order row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n orderRows.push(projectedOrder);\n\n // \u2500\u2500 Payment info rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const paymentInfoRows = asRecordArray(row.payment_info);\n for (const paymentInfo of paymentInfoRows) {\n paymentRows.push(projectPaymentRow(orderId, paymentInfo));\n }\n\n // \u2500\u2500 Details + secondary blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const details = asRecordArray(row.details);\n for (const detail of details) {\n const chargeInfo = asRecord(detail.charge_info);\n const detailId = normalizeScalarString(chargeInfo.detail_id ?? detail.detail_id) || null;\n const detailOrderId = resolveDetailOrderId(detail, orderId);\n detailRows.push(projectDetailRow(orderId, detail, fallbackCurrencyId));\n\n // \u2500\u2500 Details sales \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const detailSales = asRecordArray(detail.sales_info ?? detail.details_sales);\n for (const ds of detailSales) {\n salesRows.push(projectSalesRow(detailId, ds));\n }\n\n // \u2500\u2500 Details items \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const detailItems = asRecordArray(detail.items_info ?? detail.details_items);\n for (const di of detailItems) {\n itemsRows.push(projectItemsRow(detailId, detailOrderId, di));\n }\n }\n }\n\n // \u2500\u2500 Build metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const saleFeeNote =\n \"sale_fee may be null for some orders depending on how Mercado Libre settles the billing provision. \" +\n \"Preserve it as nullable in downstream analysis.\";\n\n const metadata: Record<string, unknown> = {\n order_ids_requested: result.order_ids_requested,\n order_ids_found: result.order_ids_found,\n order_ids_not_found: result.order_ids_not_found,\n request_chunks_total: result.chunks_total,\n request_chunks_succeeded: result.chunks_succeeded,\n request_chunks_failed: result.chunks_failed,\n coverage_complete: result.coverage_complete,\n endpoint: \"/billing/integration/group/ML/order/details\",\n sale_fee_note: saleFeeNote,\n fees_added_in_publication_note:\n 'items_info.fees_added_in_publication preserves only exact upstream \"Si\"/\"No\" values; all other values are null. ' +\n \"It represents installments offered in the listing, not buyer-used payment installments or the CVFN financing cost.\",\n pack_resolution_note:\n \"This tool operates on order IDs and does not inherit a value across pack members. Consumers must resolve every member order and apply unanimity externally.\",\n };\n\n if (result.failures.length > 0) {\n metadata.failures = result.failures;\n }\n\n // Build response \u2014 stripNulls top-level, then add back compact arrays\n const stripped = stripNulls({\n profile_id: profileId,\n endpoint: \"/billing/integration/group/ML/order/details\",\n metadata,\n }) as Record<string, unknown>;\n\n // Always attach compact blocks (preserve positional contract)\n stripped.orders_schema = ordersSchema;\n stripped.orders = orderRows;\n stripped.payment_info_schema = paymentInfoSchema;\n stripped.payment_info = paymentRows;\n stripped.details_schema = detailsSchema;\n stripped.details = detailRows;\n stripped.details_sales_schema = detailsSalesSchema;\n stripped.details_sales = salesRows;\n stripped.details_items_schema = detailsItemsSchema;\n stripped.details_items = itemsRows;\n\n // Ensure metadata arrays survive stripNulls\n const meta = stripped.metadata as Record<string, unknown>;\n meta.order_ids_requested = result.order_ids_requested;\n meta.order_ids_found = result.order_ids_found;\n meta.order_ids_not_found = result.order_ids_not_found;\n\n return object(stripped);\n } catch (err) {\n return error(\n formatMercadoLibreError(err, \"Failed to get MercadoLibre billing provisions by order\")\n );\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,OACK;AACP;AAAA,EACE;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,6CAA6C;AAI/C,MAAM,wCAAwC,EAAE,OAAO;AAAA,EAC5D,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,SAAS,0CAA0C;AAAA,EACvF,UAAU,EACP,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,SAAS,wBAAwB,CAAC,EACjE,IAAI,CAAC,EACL,SAAS,qEAAqE;AACnF,CAAC;AAKM,MAAM,eAAe;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,MAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,MAAM,qBAAqB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAUA,SAAS,cAAc,OAA2C;AAChE,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM;AAAA,MACX,CAAC,UACC,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAAA,IACtE;AAAA,EACF;AAEA,QAAM,SAAS,SAAS,KAAK;AAC7B,SAAO,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,CAAC,MAAM,IAAI,CAAC;AACtD;AAEA,SAAS,iBAAiB,OAA+B;AACvD,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AAAA,EAC1C;AAEA,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,IAAI;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,OAAO,KAAK;AACjC,SAAO,OAAO,SAAS,YAAY,IAAI,eAAe;AACxD;AAEA,SAAS,gCAAgC,OAAoC;AAC3E,SAAO,UAAU,QAAQ,UAAU,OAAO,QAAQ;AACpD;AAEA,SAAS,qBACP,QACA,iBACe;AACf,QAAM,YAAY,cAAc,OAAO,cAAc,OAAO,aAAa;AACzE,SACE,sBAAsB,UAAU,CAAC,GAAG,QAAQ,KAC5C,sBAAsB,OAAO,QAAQ,KACrC;AAEJ;AAEA,SAAS,gBAAgB,KAAwC;AAC/D,QAAM,cAAc,cAAc,IAAI,YAAY;AAClD,QAAM,UAAU,cAAc,IAAI,OAAO;AACzC,QAAM,cAAc,QAAQ,CAAC,KAAK,CAAC;AACnC,QAAM,UACJ,sBAAsB,IAAI,QAAQ,KAClC,sBAAsB,YAAY,CAAC,GAAG,QAAQ,KAC9C,sBAAsB,YAAY,QAAQ,KAC1C,qBAAqB,aAAa,IAAI,KACtC;AACF,QAAM,eAAe,SAAS,IAAI,aAAa;AAC/C,QAAM,eAAe,SAAS,IAAI,aAAa;AAC/C,QAAM,kBAAkB,SAAS,IAAI,gBAAgB;AAErD,SAAO;AAAA,IACL;AAAA;AAAA,IACA,iBAAiB,IAAI,QAAQ;AAAA;AAAA,IAC7B,YAAY;AAAA;AAAA,IACZ,QAAQ;AAAA;AAAA,IACR,sBAAsB,aAAa,eAAe,IAAI,WAAW,KAAK;AAAA;AAAA,IACtE,sBAAsB,aAAa,eAAe,IAAI,WAAW,KAAK;AAAA;AAAA,IACtE,sBAAsB,gBAAgB,eAAe,IAAI,WAAW,KAAK;AAAA;AAAA,EAC3E;AACF;AAEA,SAAS,kBAAkB,SAAwB,SAA8C;AAC/F,SAAO;AAAA,IACL;AAAA;AAAA,IACA,sBAAsB,QAAQ,cAAc,QAAQ,EAAE,KAAK;AAAA;AAAA,IAC3D,sBAAsB,QAAQ,YAAY,KAAK;AAAA;AAAA,IAC/C,sBAAsB,QAAQ,iBAAiB,KAAK;AAAA;AAAA,IACpD,iBAAiB,QAAQ,YAAY;AAAA;AAAA,IACrC,iBAAiB,QAAQ,kBAAkB;AAAA;AAAA,IAC3C,iBAAiB,QAAQ,iBAAiB;AAAA;AAAA,IAC1C,iBAAiB,QAAQ,aAAa;AAAA;AAAA,IACtC,iBAAiB,QAAQ,aAAa;AAAA;AAAA,IACtC,sBAAsB,QAAQ,MAAM,KAAK;AAAA;AAAA,IACzC,sBAAsB,QAAQ,aAAa,KAAK;AAAA;AAAA,EAClD;AACF;AAEA,SAAS,iBACP,SACA,QACA,oBACW;AACX,QAAM,aAAa,SAAS,OAAO,WAAW;AAC9C,QAAM,eAAe,SAAS,OAAO,aAAa;AAClD,QAAM,gBAAgB,qBAAqB,QAAQ,OAAO;AAC1D,QAAM,eAAe,WAAW,iBAAiB,OAAO;AAExD,SAAO;AAAA,IACL;AAAA;AAAA,IACA,sBAAsB,WAAW,aAAa,OAAO,SAAS,KAAK;AAAA;AAAA,IACnE,sBAAsB,WAAW,eAAe,OAAO,WAAW,KAAK;AAAA;AAAA,IACvE,sBAAsB,WAAW,mBAAmB,OAAO,eAAe,KAAK;AAAA;AAAA,IAC/E,sBAAsB,WAAW,sBAAsB,OAAO,kBAAkB,KAAK;AAAA;AAAA,IACrF,iBAAiB,YAAY;AAAA;AAAA,IAC7B,sBAAsB,aAAa,eAAe,OAAO,WAAW,KAAK;AAAA;AAAA,IACzE,sBAAsB,WAAW,gBAAgB,OAAO,YAAY,KAAK;AAAA;AAAA,IACzE,sBAAsB,WAAW,gBAAgB,OAAO,YAAY,KAAK;AAAA;AAAA,IACzE,sBAAsB,WAAW,eAAe,OAAO,WAAW,KAAK;AAAA;AAAA,IACvE,sBAAsB,WAAW,WAAW,OAAO,OAAO,KAAK;AAAA;AAAA,IAC/D,sBAAsB,WAAW,gBAAgB,OAAO,YAAY,KAAK;AAAA;AAAA,EAC3E;AACF;AAEA,SAAS,gBAAgB,UAAyB,MAAyC;AACzF,SAAO;AAAA,IACL;AAAA;AAAA,IACA,sBAAsB,KAAK,QAAQ,KAAK;AAAA;AAAA,IACxC,sBAAsB,KAAK,YAAY,KAAK;AAAA;AAAA,IAC5C,sBAAsB,KAAK,cAAc,KAAK;AAAA;AAAA,IAC9C;AAAA;AAAA,IACA,iBAAiB,KAAK,kBAAkB;AAAA;AAAA,EAC1C;AACF;AAEA,SAAS,gBACP,UACA,eACA,MACU;AACV,SAAO;AAAA,IACL;AAAA;AAAA,IACA,sBAAsB,KAAK,OAAO,KAAK;AAAA;AAAA,IACvC,sBAAsB,KAAK,UAAU,KAAK;AAAA;AAAA,IAC1C,iBAAiB,KAAK,WAAW;AAAA;AAAA,IACjC,iBAAiB,KAAK,UAAU;AAAA;AAAA,IAChC,sBAAsB,KAAK,WAAW,KAAK;AAAA;AAAA,IAC3C,sBAAsB,KAAK,QAAQ,KAAK;AAAA;AAAA,IACxC,sBAAsB,KAAK,QAAQ,KAAK;AAAA;AAAA,IACxC,gCAAgC,KAAK,yBAAyB;AAAA;AAAA,EAChE;AACF;AAIA,eAAsB,uCACpB,QACA;AACA,MAAI;AACF,UAAM,oBAAoB,MAAM,sCAAsC,OAAO,SAAS;AACtF,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,YAAY,kBAAkB,MAAM;AAE1C,UAAM,SAAS,MAAM,wCAAwC,WAAW;AAAA,MACtE,UAAU,OAAO;AAAA,IACnB,CAAC;AAID,UAAM,YAAwB,CAAC;AAC/B,UAAM,cAA4B,CAAC;AACnC,UAAM,aAA0B,CAAC;AACjC,UAAM,YAAwB,CAAC;AAC/B,UAAM,YAAwB,CAAC;AAE/B,eAAW,OAAO,OAAO,SAAS;AAChC,YAAM,iBAAiB,gBAAgB,GAAG;AAC1C,YAAM,UAAU,sBAAsB,eAAe,CAAC,CAAC,KAAK;AAC5D,YAAM,qBAAqB,sBAAsB,eAAe,CAAC,CAAC,KAAK;AAGvE,gBAAU,KAAK,cAAc;AAG7B,YAAM,kBAAkB,cAAc,IAAI,YAAY;AACtD,iBAAW,eAAe,iBAAiB;AACzC,oBAAY,KAAK,kBAAkB,SAAS,WAAW,CAAC;AAAA,MAC1D;AAGA,YAAM,UAAU,cAAc,IAAI,OAAO;AACzC,iBAAW,UAAU,SAAS;AAC5B,cAAM,aAAa,SAAS,OAAO,WAAW;AAC9C,cAAM,WAAW,sBAAsB,WAAW,aAAa,OAAO,SAAS,KAAK;AACpF,cAAM,gBAAgB,qBAAqB,QAAQ,OAAO;AAC1D,mBAAW,KAAK,iBAAiB,SAAS,QAAQ,kBAAkB,CAAC;AAGrE,cAAM,cAAc,cAAc,OAAO,cAAc,OAAO,aAAa;AAC3E,mBAAW,MAAM,aAAa;AAC5B,oBAAU,KAAK,gBAAgB,UAAU,EAAE,CAAC;AAAA,QAC9C;AAGA,cAAM,cAAc,cAAc,OAAO,cAAc,OAAO,aAAa;AAC3E,mBAAW,MAAM,aAAa;AAC5B,oBAAU,KAAK,gBAAgB,UAAU,eAAe,EAAE,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAIA,UAAM,cACJ;AAGF,UAAM,WAAoC;AAAA,MACxC,qBAAqB,OAAO;AAAA,MAC5B,iBAAiB,OAAO;AAAA,MACxB,qBAAqB,OAAO;AAAA,MAC5B,sBAAsB,OAAO;AAAA,MAC7B,0BAA0B,OAAO;AAAA,MACjC,uBAAuB,OAAO;AAAA,MAC9B,mBAAmB,OAAO;AAAA,MAC1B,UAAU;AAAA,MACV,eAAe;AAAA,MACf,gCACE;AAAA,MAEF,sBACE;AAAA,IACJ;AAEA,QAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,eAAS,WAAW,OAAO;AAAA,IAC7B;AAGA,UAAM,WAAW,WAAW;AAAA,MAC1B,YAAY;AAAA,MACZ,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAGD,aAAS,gBAAgB;AACzB,aAAS,SAAS;AAClB,aAAS,sBAAsB;AAC/B,aAAS,eAAe;AACxB,aAAS,iBAAiB;AAC1B,aAAS,UAAU;AACnB,aAAS,uBAAuB;AAChC,aAAS,gBAAgB;AACzB,aAAS,uBAAuB;AAChC,aAAS,gBAAgB;AAGzB,UAAM,OAAO,SAAS;AACtB,SAAK,sBAAsB,OAAO;AAClC,SAAK,kBAAkB,OAAO;AAC9B,SAAK,sBAAsB,OAAO;AAElC,WAAO,OAAO,QAAQ;AAAA,EACxB,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,wBAAwB,KAAK,wDAAwD;AAAA,IACvF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }