@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/dist/index.d.mts +11 -18
- package/dist/index.d.ts +11 -18
- package/dist/index.js +18 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/dropshipper.test.ts +14 -0
- package/src/recovery.ts +30 -45
package/package.json
CHANGED
package/src/dropshipper.test.ts
CHANGED
|
@@ -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/
|
|
13
|
-
* - `GET /
|
|
14
|
-
* - `POST /auth/
|
|
15
|
-
* - `GET /store/dropshipper/applications/activate/verify`(verify activation token, no consume)
|
|
16
|
-
* - `POST /store/dropshipper/applications/activate`
|
|
17
|
-
* - `POST /public/dropshipper/applications`
|
|
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
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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/
|
|
155
|
+
* `POST /dropshipper/auth/emailpass/reset-password`
|
|
167
156
|
*/
|
|
168
157
|
async requestUserPasswordReset(email: string): Promise<void> {
|
|
169
|
-
await this.request('POST', '/auth/
|
|
170
|
-
|
|
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 /
|
|
167
|
+
* `GET /dropshipper/auth/emailpass/reset-password/verify`
|
|
179
168
|
*/
|
|
180
169
|
async verifyUserPasswordResetToken(token: string): Promise<TokenVerifyResult> {
|
|
181
|
-
return this.request('GET', `/
|
|
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/
|
|
187
|
-
* propio JWT
|
|
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/
|
|
190
|
+
const response = await fetchBackendWithResilience(`${this.baseUrl}/dropshipper/auth/emailpass/update`, {
|
|
206
191
|
method: 'POST',
|
|
207
192
|
headers,
|
|
208
|
-
body: JSON.stringify({
|
|
193
|
+
body: JSON.stringify({ password }),
|
|
209
194
|
});
|
|
210
195
|
if (!response.ok) {
|
|
211
196
|
throw new ProviderAPIError(
|
|
212
|
-
`[recovery] POST /auth/
|
|
197
|
+
`[recovery] POST /dropshipper/auth/emailpass/update failed: HTTP ${response.status}`,
|
|
213
198
|
'RECOVERY_API_' + response.status,
|
|
214
199
|
response.status,
|
|
215
200
|
);
|