@thorprovider/medusa-extended 1.13.2 → 1.13.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thorprovider/medusa-extended",
3
- "version": "1.13.2",
3
+ "version": "1.13.4",
4
4
  "description": "Thor Commerce multi-tenant admin extensions for Medusa v2",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -262,6 +262,18 @@ describe('DropshipperClient.getOrder', () => {
262
262
  totals: { subtotal: 5000, shipping_total: 0, discount_total: 0, total: 5000, cost_total: 2000, profit: 3000, margin_percent: 60 },
263
263
  payment_collected_by: 'dropshipper',
264
264
  settlement_status: 'unsettled',
265
+ financial_summary: {
266
+ paid_total: 0,
267
+ refunded_total: 0,
268
+ pending_difference: 5000,
269
+ current_order_total: 5000,
270
+ original_order_total: 5000,
271
+ transaction_total: 0,
272
+ accounting_total: 5000,
273
+ credit_line_total: 0,
274
+ effective: { paid_total: 0, pending_difference: 5000 },
275
+ },
276
+ credit_lines: [],
265
277
  timeline: [],
266
278
  },
267
279
  })
@@ -271,6 +283,8 @@ describe('DropshipperClient.getOrder', () => {
271
283
  const result = await client().getOrder('ord_1')
272
284
  expect(result.order.id).toBe('ord_1')
273
285
  expect(result.order.totals.profit).toBe(3000)
286
+ expect(result.order.financial_summary.credit_line_total).toBe(0)
287
+ expect(result.order.credit_lines).toEqual([])
274
288
  })
275
289
  })
276
290
 
package/src/recovery.ts CHANGED
@@ -9,12 +9,12 @@
9
9
  * logged in. Backend URLs are owned here; the dashboard never builds them.
10
10
  *
11
11
  * Endpoints:
12
- * - `POST /auth/user/emailpass/reset-password` (request reset, Medusa native)
13
- * - `GET /store/dropshipper/auth/reset-password/verify` (verify reset token, no consume)
14
- * - `POST /auth/user/emailpass/update` (confirm reset, consumes token)
15
- * - `GET /store/dropshipper/applications/activate/verify`(verify activation token, no consume)
16
- * - `POST /store/dropshipper/applications/activate` (confirm activation, consumes token)
17
- * - `POST /public/dropshipper/applications` (submit application, no auth)
12
+ * - `POST /dropshipper/auth/emailpass/reset-password` (request reset, dropshipper)
13
+ * - `GET /dropshipper/auth/emailpass/reset-password/verify` (verify reset token, no consume)
14
+ * - `POST /dropshipper/auth/emailpass/update` (confirm reset, consumes token)
15
+ * - `GET /store/dropshipper/applications/activate/verify` (verify activation token, no consume)
16
+ * - `POST /store/dropshipper/applications/activate` (confirm activation, consumes token)
17
+ * - `POST /public/dropshipper/applications` (submit application, no auth)
18
18
  *
19
19
  * Confirm methods follow the two-phase contract: verify (no consume) first,
20
20
  * then confirm (atomic consume). A re-verify after a failed confirm maps the
@@ -127,31 +127,20 @@ export class RecoveryClient {
127
127
  );
128
128
  }
129
129
 
130
- return response.json() as Promise<T>;
131
- }
132
-
133
- // -------------------------------------------------------------------------
134
- // Private — reset token helpers
135
- // -------------------------------------------------------------------------
136
-
137
- /**
138
- * Decodes the `entity_id` (email) claim from a Medusa reset-password JWT.
139
- *
140
- * The JWT is unsigned-trust for this claim: the email is later sent to
141
- * `POST /auth/user/emailpass/update`, where Medusa itself re-validates the
142
- * token signature and payload before applying the change.
143
- */
144
- private decodeResetTokenEmail(token: string): string | null {
145
- const parts = token.split('.');
146
- if (parts.length !== 3) return null;
147
- try {
148
- const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8'));
149
- return typeof payload.entity_id === 'string' && payload.entity_id.length > 0
150
- ? payload.entity_id
151
- : null;
152
- } catch {
153
- return null;
130
+ // 2xx success with a JSON body: parse and return it.
131
+ if ((response.headers.get('content-type') ?? '').includes('application/json')) {
132
+ try {
133
+ return (await response.json()) as T;
134
+ } catch {
135
+ // A 2xx that claims JSON but fails to parse should not crash the
136
+ // caller as a raw SyntaxError; the stub lets the caller handle it.
137
+ return {} as T;
138
+ }
154
139
  }
140
+
141
+ // 2xx success without a JSON body (204 No Content, or plain-text bodies
142
+ // like `201 Created` from native endpoints). No value to return.
143
+ return {} as T;
155
144
  }
156
145
 
157
146
  // -------------------------------------------------------------------------
@@ -163,11 +152,11 @@ export class RecoveryClient {
163
152
  * (dropshippers). El backend responde de forma uniforme exista o no la
164
153
  * cuenta (anti enumeración).
165
154
  *
166
- * `POST /auth/user/emailpass/reset-password`
155
+ * `POST /dropshipper/auth/emailpass/reset-password`
167
156
  */
168
157
  async requestUserPasswordReset(email: string): Promise<void> {
169
- await this.request('POST', '/auth/user/emailpass/reset-password', {
170
- identifier: email,
158
+ await this.request('POST', '/dropshipper/auth/emailpass/reset-password', {
159
+ email,
171
160
  });
172
161
  }
173
162
 
@@ -175,16 +164,17 @@ export class RecoveryClient {
175
164
  * Verifica un token de reset de contraseña sin consumirlo. Devuelve el
176
165
  * email enmascarado (p. ej. `j***@ejemplo.com`) solo cuando `status === 'valid'`.
177
166
  *
178
- * `GET /store/dropshipper/auth/reset-password/verify`
167
+ * `GET /dropshipper/auth/emailpass/reset-password/verify`
179
168
  */
180
169
  async verifyUserPasswordResetToken(token: string): Promise<TokenVerifyResult> {
181
- return this.request('GET', `/store/dropshipper/auth/reset-password/verify?token=${encodeURIComponent(token)}`);
170
+ return this.request('GET', `/dropshipper/auth/emailpass/reset-password/verify?token=${encodeURIComponent(token)}`);
182
171
  }
183
172
 
184
173
  /**
185
174
  * Confirma el reset: re-verifica el token (sin consumir), luego consume el
186
- * token vía `POST /auth/user/emailpass/update`. El email se deriva del
187
- * propio JWT. Nunca devuelve auto-login: al éxito, la UI redirige a /login.
175
+ * token vía `POST /dropshipper/auth/emailpass/update`. El email se deriva del
176
+ * propio JWT en el backend; aquí solo se envía la nueva contraseña. Nunca
177
+ * devuelve auto-login: al éxito, la UI redirige a /login.
188
178
  */
189
179
  async confirmUserPasswordReset(token: string, password: string): Promise<RecoveryConfirmResult> {
190
180
  const verify = await this.verifyUserPasswordResetToken(token);
@@ -192,24 +182,19 @@ export class RecoveryClient {
192
182
  return { ok: false, status: verify.status };
193
183
  }
194
184
 
195
- const email = this.decodeResetTokenEmail(token);
196
- if (!email) {
197
- return { ok: false, status: 'invalid' };
198
- }
199
-
200
185
  try {
201
186
  const headers: Record<string, string> = {
202
187
  Authorization: `Bearer ${token}`,
203
188
  'Content-Type': 'application/json',
204
189
  };
205
- const response = await fetchBackendWithResilience(`${this.baseUrl}/auth/user/emailpass/update`, {
190
+ const response = await fetchBackendWithResilience(`${this.baseUrl}/dropshipper/auth/emailpass/update`, {
206
191
  method: 'POST',
207
192
  headers,
208
- body: JSON.stringify({ email, password }),
193
+ body: JSON.stringify({ password }),
209
194
  });
210
195
  if (!response.ok) {
211
196
  throw new ProviderAPIError(
212
- `[recovery] POST /auth/user/emailpass/update failed: HTTP ${response.status}`,
197
+ `[recovery] POST /dropshipper/auth/emailpass/update failed: HTTP ${response.status}`,
213
198
  'RECOVERY_API_' + response.status,
214
199
  response.status,
215
200
  );