@amboras-dev/aliexpress-dropshipping 1.2.0 → 1.3.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.
- package/dist/admin/index.d.mts +3 -50
- package/dist/admin/index.d.ts +3 -50
- package/dist/client/index.d.mts +3 -18
- package/dist/client/index.d.ts +3 -18
- package/dist/client/index.js +0 -18
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +25 -5
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.d.mts +51 -4
- package/dist/index.d.ts +51 -4
- package/dist/index.js +2 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -7
- package/dist/{types-CLTkhq_u.d.mts → types-CiA0K7nl.d.mts} +1 -1
- package/dist/{types-CLTkhq_u.d.ts → types-CiA0K7nl.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-PK4PMTFZ.mjs +0 -47
- package/dist/chunk-PK4PMTFZ.mjs.map +0 -1
package/dist/admin/index.d.mts
CHANGED
|
@@ -1,50 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Admin settings form for the AliExpress Dropshipping integration.
|
|
6
|
-
*
|
|
7
|
-
* Class B: this component owns the UI and talks to the Medusa Store API
|
|
8
|
-
* under `/store/aliexpress-dropshipping/*`. It does NOT embed any
|
|
9
|
-
* AliExpress SDK, does not sign requests, and does not touch OAuth
|
|
10
|
-
* tokens directly - the backend does all of that.
|
|
11
|
-
*
|
|
12
|
-
* The component is intentionally dependency-light (no external UI kit,
|
|
13
|
-
* no @tanstack/react-query peer) so the admin bundle can drop it in
|
|
14
|
-
* without extra peer dep resolution.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
interface AliExpressDropshippingSettingsFormProps {
|
|
18
|
-
/** Current config for this store (fetched by the parent server component). */
|
|
19
|
-
initialConfig: AliExpressPluginConfig;
|
|
20
|
-
/** Current connection status (from `GET /status`). */
|
|
21
|
-
initialStatus: AliExpressConnectionStatusDto;
|
|
22
|
-
/**
|
|
23
|
-
* Persist non-secret + optionally new secret values. The parent maps
|
|
24
|
-
* this onto `PATCH /store/aliexpress-dropshipping/config` (or
|
|
25
|
-
* equivalent) and then re-fetches config on success.
|
|
26
|
-
*
|
|
27
|
-
* `appSecret` is only sent when the merchant actually typed a new
|
|
28
|
-
* value; if they leave the field untouched, this method receives
|
|
29
|
-
* `undefined` for that key so the backend keeps the existing secret.
|
|
30
|
-
*/
|
|
31
|
-
onSaveConfig: (patch: {
|
|
32
|
-
appKey?: string;
|
|
33
|
-
appSecret?: string;
|
|
34
|
-
enabled?: boolean;
|
|
35
|
-
}) => Promise<void>;
|
|
36
|
-
/** Kick off `POST /oauth/start` and redirect to the returned URL. */
|
|
37
|
-
onConnect: () => Promise<void>;
|
|
38
|
-
/** Kick off `POST /oauth/disconnect` and clear merchant credentials. */
|
|
39
|
-
onDisconnect: () => Promise<void>;
|
|
40
|
-
/** Call `POST /test-connection` and return the result. */
|
|
41
|
-
onTestConnection: () => Promise<AliExpressTestConnectionResult>;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Amboras admin settings surface for AliExpress Dropshipping.
|
|
45
|
-
* Renders AppKey + AppSecret inputs, Test / Connect / Disconnect
|
|
46
|
-
* buttons, status card, and a "Coming soon" order-forwarding block.
|
|
47
|
-
*/
|
|
48
|
-
declare function AliExpressDropshippingSettingsForm(props: AliExpressDropshippingSettingsFormProps): React.ReactElement;
|
|
49
|
-
|
|
50
|
-
export { AliExpressDropshippingSettingsForm, type AliExpressDropshippingSettingsFormProps };
|
|
1
|
+
export { AliExpressDropshippingSettingsForm, AliExpressDropshippingSettingsFormProps } from '../index.mjs';
|
|
2
|
+
import '../types-CiA0K7nl.mjs';
|
|
3
|
+
import 'react';
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1,50 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Admin settings form for the AliExpress Dropshipping integration.
|
|
6
|
-
*
|
|
7
|
-
* Class B: this component owns the UI and talks to the Medusa Store API
|
|
8
|
-
* under `/store/aliexpress-dropshipping/*`. It does NOT embed any
|
|
9
|
-
* AliExpress SDK, does not sign requests, and does not touch OAuth
|
|
10
|
-
* tokens directly - the backend does all of that.
|
|
11
|
-
*
|
|
12
|
-
* The component is intentionally dependency-light (no external UI kit,
|
|
13
|
-
* no @tanstack/react-query peer) so the admin bundle can drop it in
|
|
14
|
-
* without extra peer dep resolution.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
interface AliExpressDropshippingSettingsFormProps {
|
|
18
|
-
/** Current config for this store (fetched by the parent server component). */
|
|
19
|
-
initialConfig: AliExpressPluginConfig;
|
|
20
|
-
/** Current connection status (from `GET /status`). */
|
|
21
|
-
initialStatus: AliExpressConnectionStatusDto;
|
|
22
|
-
/**
|
|
23
|
-
* Persist non-secret + optionally new secret values. The parent maps
|
|
24
|
-
* this onto `PATCH /store/aliexpress-dropshipping/config` (or
|
|
25
|
-
* equivalent) and then re-fetches config on success.
|
|
26
|
-
*
|
|
27
|
-
* `appSecret` is only sent when the merchant actually typed a new
|
|
28
|
-
* value; if they leave the field untouched, this method receives
|
|
29
|
-
* `undefined` for that key so the backend keeps the existing secret.
|
|
30
|
-
*/
|
|
31
|
-
onSaveConfig: (patch: {
|
|
32
|
-
appKey?: string;
|
|
33
|
-
appSecret?: string;
|
|
34
|
-
enabled?: boolean;
|
|
35
|
-
}) => Promise<void>;
|
|
36
|
-
/** Kick off `POST /oauth/start` and redirect to the returned URL. */
|
|
37
|
-
onConnect: () => Promise<void>;
|
|
38
|
-
/** Kick off `POST /oauth/disconnect` and clear merchant credentials. */
|
|
39
|
-
onDisconnect: () => Promise<void>;
|
|
40
|
-
/** Call `POST /test-connection` and return the result. */
|
|
41
|
-
onTestConnection: () => Promise<AliExpressTestConnectionResult>;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Amboras admin settings surface for AliExpress Dropshipping.
|
|
45
|
-
* Renders AppKey + AppSecret inputs, Test / Connect / Disconnect
|
|
46
|
-
* buttons, status card, and a "Coming soon" order-forwarding block.
|
|
47
|
-
*/
|
|
48
|
-
declare function AliExpressDropshippingSettingsForm(props: AliExpressDropshippingSettingsFormProps): React.ReactElement;
|
|
49
|
-
|
|
50
|
-
export { AliExpressDropshippingSettingsForm, type AliExpressDropshippingSettingsFormProps };
|
|
1
|
+
export { AliExpressDropshippingSettingsForm, AliExpressDropshippingSettingsFormProps } from '../index.js';
|
|
2
|
+
import '../types-CiA0K7nl.js';
|
|
3
|
+
import 'react';
|
package/dist/client/index.d.mts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { P as PreflightResult } from '../types-
|
|
2
|
-
export {
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { ReactElement, MouseEvent } from 'react';
|
|
1
|
+
import { P as PreflightResult } from '../types-CiA0K7nl.mjs';
|
|
2
|
+
export { a as PreflightAddressError, b as PreflightItemError, c as PreflightMerchantError } from '../types-CiA0K7nl.mjs';
|
|
5
3
|
|
|
6
4
|
interface UseAliexpressPreflightOptions {
|
|
7
5
|
baseUrl?: string;
|
|
@@ -14,17 +12,4 @@ declare function useAliexpressPreflight(options?: UseAliexpressPreflightOptions)
|
|
|
14
12
|
isPending: boolean;
|
|
15
13
|
};
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
cartId: string;
|
|
19
|
-
children: ReactElement<{
|
|
20
|
-
onClick?: (event: MouseEvent) => void;
|
|
21
|
-
}>;
|
|
22
|
-
onBlock: (result: PreflightResult) => void;
|
|
23
|
-
onPass?: () => void | Promise<void>;
|
|
24
|
-
options?: UseAliexpressPreflightOptions;
|
|
25
|
-
}
|
|
26
|
-
declare function AliexpressCheckoutGuard({ cartId, children, onBlock, onPass, options }: AliexpressCheckoutGuardProps): ReactElement<{
|
|
27
|
-
onClick?: (event: MouseEvent) => void;
|
|
28
|
-
}, string | React.JSXElementConstructor<any>>;
|
|
29
|
-
|
|
30
|
-
export { AliexpressCheckoutGuard, type AliexpressCheckoutGuardProps, PreflightResult, type UseAliexpressPreflightOptions, useAliexpressPreflight };
|
|
15
|
+
export { PreflightResult, type UseAliexpressPreflightOptions, useAliexpressPreflight };
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { P as PreflightResult } from '../types-
|
|
2
|
-
export {
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { ReactElement, MouseEvent } from 'react';
|
|
1
|
+
import { P as PreflightResult } from '../types-CiA0K7nl.js';
|
|
2
|
+
export { a as PreflightAddressError, b as PreflightItemError, c as PreflightMerchantError } from '../types-CiA0K7nl.js';
|
|
5
3
|
|
|
6
4
|
interface UseAliexpressPreflightOptions {
|
|
7
5
|
baseUrl?: string;
|
|
@@ -14,17 +12,4 @@ declare function useAliexpressPreflight(options?: UseAliexpressPreflightOptions)
|
|
|
14
12
|
isPending: boolean;
|
|
15
13
|
};
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
cartId: string;
|
|
19
|
-
children: ReactElement<{
|
|
20
|
-
onClick?: (event: MouseEvent) => void;
|
|
21
|
-
}>;
|
|
22
|
-
onBlock: (result: PreflightResult) => void;
|
|
23
|
-
onPass?: () => void | Promise<void>;
|
|
24
|
-
options?: UseAliexpressPreflightOptions;
|
|
25
|
-
}
|
|
26
|
-
declare function AliexpressCheckoutGuard({ cartId, children, onBlock, onPass, options }: AliexpressCheckoutGuardProps): ReactElement<{
|
|
27
|
-
onClick?: (event: MouseEvent) => void;
|
|
28
|
-
}, string | React.JSXElementConstructor<any>>;
|
|
29
|
-
|
|
30
|
-
export { AliexpressCheckoutGuard, type AliexpressCheckoutGuardProps, PreflightResult, type UseAliexpressPreflightOptions, useAliexpressPreflight };
|
|
15
|
+
export { PreflightResult, type UseAliexpressPreflightOptions, useAliexpressPreflight };
|
package/dist/client/index.js
CHANGED
|
@@ -20,7 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/client/index.ts
|
|
21
21
|
var client_exports = {};
|
|
22
22
|
__export(client_exports, {
|
|
23
|
-
AliexpressCheckoutGuard: () => AliexpressCheckoutGuard,
|
|
24
23
|
useAliexpressPreflight: () => useAliexpressPreflight
|
|
25
24
|
});
|
|
26
25
|
module.exports = __toCommonJS(client_exports);
|
|
@@ -50,25 +49,8 @@ function useAliexpressPreflight(options = {}) {
|
|
|
50
49
|
}, [options.baseUrl, options.publishableKey]);
|
|
51
50
|
return { mutateAsync, isPending };
|
|
52
51
|
}
|
|
53
|
-
|
|
54
|
-
// src/client/preflight-guard.tsx
|
|
55
|
-
var import_react2 = require("react");
|
|
56
|
-
function AliexpressCheckoutGuard({ cartId, children, onBlock, onPass, options }) {
|
|
57
|
-
const preflight = useAliexpressPreflight(options);
|
|
58
|
-
const onClick = async (event) => {
|
|
59
|
-
event.preventDefault();
|
|
60
|
-
const result = await preflight.mutateAsync({ cartId });
|
|
61
|
-
if (!result.ok) {
|
|
62
|
-
onBlock(result);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
await onPass?.();
|
|
66
|
-
};
|
|
67
|
-
return (0, import_react2.cloneElement)(children, { onClick });
|
|
68
|
-
}
|
|
69
52
|
// Annotate the CommonJS export names for ESM import in node:
|
|
70
53
|
0 && (module.exports = {
|
|
71
|
-
AliexpressCheckoutGuard,
|
|
72
54
|
useAliexpressPreflight
|
|
73
55
|
});
|
|
74
56
|
//# sourceMappingURL=index.js.map
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/index.ts","../../src/client/use-preflight.ts"
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts","../../src/client/use-preflight.ts"],"sourcesContent":["export { useAliexpressPreflight, type UseAliexpressPreflightOptions } from './use-preflight'\nexport type {\n PreflightResult,\n PreflightMerchantError,\n PreflightAddressError,\n PreflightItemError,\n} from '../types'","'use client'\n\nimport { useCallback, useState } from 'react'\nimport type { PreflightResult } from '../types'\n\nexport interface UseAliexpressPreflightOptions {\n baseUrl?: string\n publishableKey?: string\n}\n\nexport function useAliexpressPreflight(options: UseAliexpressPreflightOptions = {}) {\n const [isPending, setIsPending] = useState(false)\n const mutateAsync = useCallback(async ({ cartId }: { cartId: string }): Promise<PreflightResult> => {\n setIsPending(true)\n try {\n const baseUrl = options.baseUrl ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? ''\n const publishableKey = options.publishableKey ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? ''\n const response = await fetch(`${baseUrl.replace(/\\/$/, '')}/store/aliexpress-dropshipping/preflight-cart`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(publishableKey ? { 'x-publishable-api-key': publishableKey } : {}),\n },\n body: JSON.stringify({ cart_id: cartId }),\n })\n if (!response.ok) throw new Error(`Preflight check failed: ${response.status}`)\n return await response.json() as PreflightResult\n } finally {\n setIsPending(false)\n }\n }, [options.baseUrl, options.publishableKey])\n\n return { mutateAsync, isPending }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,mBAAsC;AAQ/B,SAAS,uBAAuB,UAAyC,CAAC,GAAG;AAClF,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAChD,QAAM,kBAAc,0BAAY,OAAO,EAAE,OAAO,MAAoD;AAClG,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,UAAU,QAAQ,WAAW,QAAQ,IAAI,kCAAkC;AACjF,YAAM,iBAAiB,QAAQ,kBAAkB,QAAQ,IAAI,sCAAsC;AACnG,YAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC,iDAAiD;AAAA,QACzG,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAI,iBAAiB,EAAE,yBAAyB,eAAe,IAAI,CAAC;AAAA,QACtE;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,SAAS,OAAO,CAAC;AAAA,MAC1C,CAAC;AACD,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,2BAA2B,SAAS,MAAM,EAAE;AAC9E,aAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,QAAQ,cAAc,CAAC;AAE5C,SAAO,EAAE,aAAa,UAAU;AAClC;","names":[]}
|
package/dist/client/index.mjs
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// src/client/use-preflight.ts
|
|
2
|
+
import { useCallback, useState } from "react";
|
|
3
|
+
function useAliexpressPreflight(options = {}) {
|
|
4
|
+
const [isPending, setIsPending] = useState(false);
|
|
5
|
+
const mutateAsync = useCallback(async ({ cartId }) => {
|
|
6
|
+
setIsPending(true);
|
|
7
|
+
try {
|
|
8
|
+
const baseUrl = options.baseUrl ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? "";
|
|
9
|
+
const publishableKey = options.publishableKey ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? "";
|
|
10
|
+
const response = await fetch(`${baseUrl.replace(/\/$/, "")}/store/aliexpress-dropshipping/preflight-cart`, {
|
|
11
|
+
method: "POST",
|
|
12
|
+
headers: {
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
...publishableKey ? { "x-publishable-api-key": publishableKey } : {}
|
|
15
|
+
},
|
|
16
|
+
body: JSON.stringify({ cart_id: cartId })
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok) throw new Error(`Preflight check failed: ${response.status}`);
|
|
19
|
+
return await response.json();
|
|
20
|
+
} finally {
|
|
21
|
+
setIsPending(false);
|
|
22
|
+
}
|
|
23
|
+
}, [options.baseUrl, options.publishableKey]);
|
|
24
|
+
return { mutateAsync, isPending };
|
|
25
|
+
}
|
|
5
26
|
export {
|
|
6
|
-
AliexpressCheckoutGuard,
|
|
7
27
|
useAliexpressPreflight
|
|
8
28
|
};
|
|
9
29
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/use-preflight.ts"],"sourcesContent":["'use client'\n\nimport { useCallback, useState } from 'react'\nimport type { PreflightResult } from '../types'\n\nexport interface UseAliexpressPreflightOptions {\n baseUrl?: string\n publishableKey?: string\n}\n\nexport function useAliexpressPreflight(options: UseAliexpressPreflightOptions = {}) {\n const [isPending, setIsPending] = useState(false)\n const mutateAsync = useCallback(async ({ cartId }: { cartId: string }): Promise<PreflightResult> => {\n setIsPending(true)\n try {\n const baseUrl = options.baseUrl ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? ''\n const publishableKey = options.publishableKey ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? ''\n const response = await fetch(`${baseUrl.replace(/\\/$/, '')}/store/aliexpress-dropshipping/preflight-cart`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(publishableKey ? { 'x-publishable-api-key': publishableKey } : {}),\n },\n body: JSON.stringify({ cart_id: cartId }),\n })\n if (!response.ok) throw new Error(`Preflight check failed: ${response.status}`)\n return await response.json() as PreflightResult\n } finally {\n setIsPending(false)\n }\n }, [options.baseUrl, options.publishableKey])\n\n return { mutateAsync, isPending }\n}\n"],"mappings":";AAEA,SAAS,aAAa,gBAAgB;AAQ/B,SAAS,uBAAuB,UAAyC,CAAC,GAAG;AAClF,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,cAAc,YAAY,OAAO,EAAE,OAAO,MAAoD;AAClG,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,UAAU,QAAQ,WAAW,QAAQ,IAAI,kCAAkC;AACjF,YAAM,iBAAiB,QAAQ,kBAAkB,QAAQ,IAAI,sCAAsC;AACnG,YAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC,iDAAiD;AAAA,QACzG,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAI,iBAAiB,EAAE,yBAAyB,eAAe,IAAI,CAAC;AAAA,QACtE;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,SAAS,OAAO,CAAC;AAAA,MAC1C,CAAC;AACD,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,2BAA2B,SAAS,MAAM,EAAE;AAC9E,aAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,QAAQ,cAAc,CAAC;AAE5C,SAAO,EAAE,aAAa,UAAU;AAClC;","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { A as AliExpressPluginConfig, d as AliExpressConnectionStatusDto, e as AliExpressTestConnectionResult } from './types-CiA0K7nl.mjs';
|
|
2
|
+
export { f as AliExpressCategoryDto, g as AliExpressImportResultDto, h as AliExpressProductDto, i as AliExpressProductSummaryDto, j as AliExpressProductVariantDto, k as AliExpressReauthReason, S as SECRET_SET_SENTINEL, l as SecretSetSentinel } from './types-CiA0K7nl.mjs';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Admin settings form for the AliExpress Dropshipping integration.
|
|
7
|
+
*
|
|
8
|
+
* Class B: this component owns the UI and talks to the Medusa Store API
|
|
9
|
+
* under `/store/aliexpress-dropshipping/*`. It does NOT embed any
|
|
10
|
+
* AliExpress SDK, does not sign requests, and does not touch OAuth
|
|
11
|
+
* tokens directly - the backend does all of that.
|
|
12
|
+
*
|
|
13
|
+
* The component is intentionally dependency-light (no external UI kit,
|
|
14
|
+
* no @tanstack/react-query peer) so the admin bundle can drop it in
|
|
15
|
+
* without extra peer dep resolution.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface AliExpressDropshippingSettingsFormProps {
|
|
19
|
+
/** Current config for this store (fetched by the parent server component). */
|
|
20
|
+
initialConfig: AliExpressPluginConfig;
|
|
21
|
+
/** Current connection status (from `GET /status`). */
|
|
22
|
+
initialStatus: AliExpressConnectionStatusDto;
|
|
23
|
+
/**
|
|
24
|
+
* Persist non-secret + optionally new secret values. The parent maps
|
|
25
|
+
* this onto `PATCH /store/aliexpress-dropshipping/config` (or
|
|
26
|
+
* equivalent) and then re-fetches config on success.
|
|
27
|
+
*
|
|
28
|
+
* `appSecret` is only sent when the merchant actually typed a new
|
|
29
|
+
* value; if they leave the field untouched, this method receives
|
|
30
|
+
* `undefined` for that key so the backend keeps the existing secret.
|
|
31
|
+
*/
|
|
32
|
+
onSaveConfig: (patch: {
|
|
33
|
+
appKey?: string;
|
|
34
|
+
appSecret?: string;
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
}) => Promise<void>;
|
|
37
|
+
/** Kick off `POST /oauth/start` and redirect to the returned URL. */
|
|
38
|
+
onConnect: () => Promise<void>;
|
|
39
|
+
/** Kick off `POST /oauth/disconnect` and clear merchant credentials. */
|
|
40
|
+
onDisconnect: () => Promise<void>;
|
|
41
|
+
/** Call `POST /test-connection` and return the result. */
|
|
42
|
+
onTestConnection: () => Promise<AliExpressTestConnectionResult>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Amboras admin settings surface for AliExpress Dropshipping.
|
|
46
|
+
* Renders AppKey + AppSecret inputs, Test / Connect / Disconnect
|
|
47
|
+
* buttons, status card, and a "Coming soon" order-forwarding block.
|
|
48
|
+
*/
|
|
49
|
+
declare function AliExpressDropshippingSettingsForm(props: AliExpressDropshippingSettingsFormProps): React.ReactElement;
|
|
50
|
+
|
|
51
|
+
export { AliExpressConnectionStatusDto, AliExpressDropshippingSettingsForm, type AliExpressDropshippingSettingsFormProps, AliExpressPluginConfig, AliExpressTestConnectionResult };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { A as AliExpressPluginConfig, d as AliExpressConnectionStatusDto, e as AliExpressTestConnectionResult } from './types-CiA0K7nl.js';
|
|
2
|
+
export { f as AliExpressCategoryDto, g as AliExpressImportResultDto, h as AliExpressProductDto, i as AliExpressProductSummaryDto, j as AliExpressProductVariantDto, k as AliExpressReauthReason, S as SECRET_SET_SENTINEL, l as SecretSetSentinel } from './types-CiA0K7nl.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Admin settings form for the AliExpress Dropshipping integration.
|
|
7
|
+
*
|
|
8
|
+
* Class B: this component owns the UI and talks to the Medusa Store API
|
|
9
|
+
* under `/store/aliexpress-dropshipping/*`. It does NOT embed any
|
|
10
|
+
* AliExpress SDK, does not sign requests, and does not touch OAuth
|
|
11
|
+
* tokens directly - the backend does all of that.
|
|
12
|
+
*
|
|
13
|
+
* The component is intentionally dependency-light (no external UI kit,
|
|
14
|
+
* no @tanstack/react-query peer) so the admin bundle can drop it in
|
|
15
|
+
* without extra peer dep resolution.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface AliExpressDropshippingSettingsFormProps {
|
|
19
|
+
/** Current config for this store (fetched by the parent server component). */
|
|
20
|
+
initialConfig: AliExpressPluginConfig;
|
|
21
|
+
/** Current connection status (from `GET /status`). */
|
|
22
|
+
initialStatus: AliExpressConnectionStatusDto;
|
|
23
|
+
/**
|
|
24
|
+
* Persist non-secret + optionally new secret values. The parent maps
|
|
25
|
+
* this onto `PATCH /store/aliexpress-dropshipping/config` (or
|
|
26
|
+
* equivalent) and then re-fetches config on success.
|
|
27
|
+
*
|
|
28
|
+
* `appSecret` is only sent when the merchant actually typed a new
|
|
29
|
+
* value; if they leave the field untouched, this method receives
|
|
30
|
+
* `undefined` for that key so the backend keeps the existing secret.
|
|
31
|
+
*/
|
|
32
|
+
onSaveConfig: (patch: {
|
|
33
|
+
appKey?: string;
|
|
34
|
+
appSecret?: string;
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
}) => Promise<void>;
|
|
37
|
+
/** Kick off `POST /oauth/start` and redirect to the returned URL. */
|
|
38
|
+
onConnect: () => Promise<void>;
|
|
39
|
+
/** Kick off `POST /oauth/disconnect` and clear merchant credentials. */
|
|
40
|
+
onDisconnect: () => Promise<void>;
|
|
41
|
+
/** Call `POST /test-connection` and return the result. */
|
|
42
|
+
onTestConnection: () => Promise<AliExpressTestConnectionResult>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Amboras admin settings surface for AliExpress Dropshipping.
|
|
46
|
+
* Renders AppKey + AppSecret inputs, Test / Connect / Disconnect
|
|
47
|
+
* buttons, status card, and a "Coming soon" order-forwarding block.
|
|
48
|
+
*/
|
|
49
|
+
declare function AliExpressDropshippingSettingsForm(props: AliExpressDropshippingSettingsFormProps): React.ReactElement;
|
|
50
|
+
|
|
51
|
+
export { AliExpressConnectionStatusDto, AliExpressDropshippingSettingsForm, type AliExpressDropshippingSettingsFormProps, AliExpressPluginConfig, AliExpressTestConnectionResult };
|
package/dist/index.js
CHANGED
|
@@ -32,9 +32,7 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AliExpressDropshippingSettingsForm: () => AliExpressDropshippingSettingsForm,
|
|
34
34
|
AliExpressReauthReason: () => AliExpressReauthReason,
|
|
35
|
-
|
|
36
|
-
SECRET_SET_SENTINEL: () => SECRET_SET_SENTINEL,
|
|
37
|
-
useAliexpressPreflight: () => useAliexpressPreflight
|
|
35
|
+
SECRET_SET_SENTINEL: () => SECRET_SET_SENTINEL
|
|
38
36
|
});
|
|
39
37
|
module.exports = __toCommonJS(src_exports);
|
|
40
38
|
|
|
@@ -257,54 +255,10 @@ function AliExpressDropshippingSettingsForm(props) {
|
|
|
257
255
|
] })
|
|
258
256
|
] });
|
|
259
257
|
}
|
|
260
|
-
|
|
261
|
-
// src/client/use-preflight.ts
|
|
262
|
-
var import_react = require("react");
|
|
263
|
-
function useAliexpressPreflight(options = {}) {
|
|
264
|
-
const [isPending, setIsPending] = (0, import_react.useState)(false);
|
|
265
|
-
const mutateAsync = (0, import_react.useCallback)(async ({ cartId }) => {
|
|
266
|
-
setIsPending(true);
|
|
267
|
-
try {
|
|
268
|
-
const baseUrl = options.baseUrl ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? "";
|
|
269
|
-
const publishableKey = options.publishableKey ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? "";
|
|
270
|
-
const response = await fetch(`${baseUrl.replace(/\/$/, "")}/store/aliexpress-dropshipping/preflight-cart`, {
|
|
271
|
-
method: "POST",
|
|
272
|
-
headers: {
|
|
273
|
-
"Content-Type": "application/json",
|
|
274
|
-
...publishableKey ? { "x-publishable-api-key": publishableKey } : {}
|
|
275
|
-
},
|
|
276
|
-
body: JSON.stringify({ cart_id: cartId })
|
|
277
|
-
});
|
|
278
|
-
if (!response.ok) throw new Error(`Preflight check failed: ${response.status}`);
|
|
279
|
-
return await response.json();
|
|
280
|
-
} finally {
|
|
281
|
-
setIsPending(false);
|
|
282
|
-
}
|
|
283
|
-
}, [options.baseUrl, options.publishableKey]);
|
|
284
|
-
return { mutateAsync, isPending };
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// src/client/preflight-guard.tsx
|
|
288
|
-
var import_react2 = require("react");
|
|
289
|
-
function AliexpressCheckoutGuard({ cartId, children, onBlock, onPass, options }) {
|
|
290
|
-
const preflight = useAliexpressPreflight(options);
|
|
291
|
-
const onClick = async (event) => {
|
|
292
|
-
event.preventDefault();
|
|
293
|
-
const result = await preflight.mutateAsync({ cartId });
|
|
294
|
-
if (!result.ok) {
|
|
295
|
-
onBlock(result);
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
await onPass?.();
|
|
299
|
-
};
|
|
300
|
-
return (0, import_react2.cloneElement)(children, { onClick });
|
|
301
|
-
}
|
|
302
258
|
// Annotate the CommonJS export names for ESM import in node:
|
|
303
259
|
0 && (module.exports = {
|
|
304
260
|
AliExpressDropshippingSettingsForm,
|
|
305
261
|
AliExpressReauthReason,
|
|
306
|
-
|
|
307
|
-
SECRET_SET_SENTINEL,
|
|
308
|
-
useAliexpressPreflight
|
|
262
|
+
SECRET_SET_SENTINEL
|
|
309
263
|
});
|
|
310
264
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/settings-form.tsx","../src/types.ts","../src/client/use-preflight.ts","../src/client/preflight-guard.tsx"],"sourcesContent":["// Admin settings form (Class B - the only React surface).\nexport {\n AliExpressDropshippingSettingsForm,\n type AliExpressDropshippingSettingsFormProps,\n} from './settings-form'\n\n// Shared wire types - kept in sync with the medusa-backend-orchestrator DTOs.\nexport {\n SECRET_SET_SENTINEL,\n AliExpressReauthReason,\n} from './types'\nexport type {\n SecretSetSentinel,\n AliExpressPluginConfig,\n AliExpressCategoryDto,\n AliExpressProductSummaryDto,\n AliExpressProductDto,\n AliExpressProductVariantDto,\n AliExpressImportResultDto,\n AliExpressConnectionStatusDto,\n AliExpressTestConnectionResult,\n} from './types'\n\nexport { useAliexpressPreflight, type UseAliexpressPreflightOptions } from './client/use-preflight'\nexport { AliexpressCheckoutGuard, type AliexpressCheckoutGuardProps } from './client/preflight-guard'\n","'use client'\n\n/**\n * Admin settings form for the AliExpress Dropshipping integration.\n *\n * Class B: this component owns the UI and talks to the Medusa Store API\n * under `/store/aliexpress-dropshipping/*`. It does NOT embed any\n * AliExpress SDK, does not sign requests, and does not touch OAuth\n * tokens directly - the backend does all of that.\n *\n * The component is intentionally dependency-light (no external UI kit,\n * no @tanstack/react-query peer) so the admin bundle can drop it in\n * without extra peer dep resolution.\n */\n\nimport * as React from 'react'\nimport type {\n AliExpressPluginConfig,\n AliExpressConnectionStatusDto,\n AliExpressTestConnectionResult,\n} from './types'\nimport { SECRET_SET_SENTINEL } from './types'\n\nexport interface AliExpressDropshippingSettingsFormProps {\n /** Current config for this store (fetched by the parent server component). */\n initialConfig: AliExpressPluginConfig\n /** Current connection status (from `GET /status`). */\n initialStatus: AliExpressConnectionStatusDto\n /**\n * Persist non-secret + optionally new secret values. The parent maps\n * this onto `PATCH /store/aliexpress-dropshipping/config` (or\n * equivalent) and then re-fetches config on success.\n *\n * `appSecret` is only sent when the merchant actually typed a new\n * value; if they leave the field untouched, this method receives\n * `undefined` for that key so the backend keeps the existing secret.\n */\n onSaveConfig: (patch: {\n appKey?: string\n appSecret?: string\n enabled?: boolean\n }) => Promise<void>\n /** Kick off `POST /oauth/start` and redirect to the returned URL. */\n onConnect: () => Promise<void>\n /** Kick off `POST /oauth/disconnect` and clear merchant credentials. */\n onDisconnect: () => Promise<void>\n /** Call `POST /test-connection` and return the result. */\n onTestConnection: () => Promise<AliExpressTestConnectionResult>\n}\n\ntype SaveState = 'idle' | 'saving' | 'saved' | 'error'\ntype TestState =\n | { kind: 'idle' }\n | { kind: 'running' }\n | { kind: 'ok'; categoryCount: number }\n | { kind: 'err'; code: string; msg: string }\n\n/**\n * Amboras admin settings surface for AliExpress Dropshipping.\n * Renders AppKey + AppSecret inputs, Test / Connect / Disconnect\n * buttons, status card, and a \"Coming soon\" order-forwarding block.\n */\nexport function AliExpressDropshippingSettingsForm(\n props: AliExpressDropshippingSettingsFormProps,\n): React.ReactElement {\n const {\n initialConfig,\n initialStatus,\n onSaveConfig,\n onConnect,\n onDisconnect,\n onTestConnection,\n } = props\n\n const [appKey, setAppKey] = React.useState<string>(\n initialConfig.appKey ?? '',\n )\n const secretPreset =\n initialConfig.appSecret === SECRET_SET_SENTINEL ||\n (typeof initialConfig.appSecret === 'string' &&\n initialConfig.appSecret.length > 0)\n const [appSecret, setAppSecret] = React.useState<string>('')\n const [secretDirty, setSecretDirty] = React.useState<boolean>(false)\n\n const [saveState, setSaveState] = React.useState<SaveState>('idle')\n const [saveError, setSaveError] = React.useState<string | null>(null)\n\n const [testState, setTestState] = React.useState<TestState>({ kind: 'idle' })\n const [testEverSucceeded, setTestEverSucceeded] = React.useState<boolean>(\n initialStatus.connected,\n )\n\n const [busyOAuth, setBusyOAuth] = React.useState<boolean>(false)\n\n const hasStoredSecret = secretPreset || secretDirty\n const canTest = appKey.trim().length > 0 && hasStoredSecret\n const canConnect = testEverSucceeded && !initialStatus.connected\n const canDisconnect = initialStatus.connected\n\n const handleSave = React.useCallback(async () => {\n setSaveState('saving')\n setSaveError(null)\n try {\n const patch: {\n appKey?: string\n appSecret?: string\n enabled?: boolean\n } = {}\n if (appKey.trim() !== (initialConfig.appKey ?? '')) {\n patch.appKey = appKey.trim()\n }\n if (secretDirty && appSecret.length > 0) {\n patch.appSecret = appSecret\n }\n await onSaveConfig(patch)\n setSaveState('saved')\n setSecretDirty(false)\n setAppSecret('')\n } catch (err) {\n setSaveState('error')\n setSaveError(err instanceof Error ? err.message : 'Save failed')\n }\n }, [appKey, appSecret, secretDirty, initialConfig.appKey, onSaveConfig])\n\n const handleTest = React.useCallback(async () => {\n setTestState({ kind: 'running' })\n try {\n const result = await onTestConnection()\n if (result.ok) {\n setTestState({ kind: 'ok', categoryCount: result.categoryCount })\n setTestEverSucceeded(true)\n } else {\n setTestState({ kind: 'err', code: result.code, msg: result.msg })\n }\n } catch (err) {\n setTestState({\n kind: 'err',\n code: 'UNKNOWN',\n msg: err instanceof Error ? err.message : 'Test failed',\n })\n }\n }, [onTestConnection])\n\n const handleConnect = React.useCallback(async () => {\n setBusyOAuth(true)\n try {\n await onConnect()\n } finally {\n setBusyOAuth(false)\n }\n }, [onConnect])\n\n const handleDisconnect = React.useCallback(async () => {\n setBusyOAuth(true)\n try {\n await onDisconnect()\n } finally {\n setBusyOAuth(false)\n }\n }, [onDisconnect])\n\n return (\n <div className=\"aliexpress-dropshipping-settings\">\n <section aria-labelledby=\"ae-credentials-heading\">\n <h2 id=\"ae-credentials-heading\">Developer app credentials</h2>\n <p>\n Enter your AliExpress Open Platform app credentials. These are\n stored encrypted at rest and used to sign every AliExpress API\n call for this store.\n </p>\n\n <label>\n <span>App Key</span>\n <input\n type=\"text\"\n value={appKey}\n onChange={(e) => setAppKey(e.target.value)}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </label>\n\n <label>\n <span>App Secret</span>\n <input\n type=\"password\"\n value={appSecret}\n placeholder={secretPreset ? '(secret set - leave blank to keep)' : ''}\n onChange={(e) => {\n setAppSecret(e.target.value)\n setSecretDirty(true)\n }}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </label>\n\n <div className=\"actions\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saveState === 'saving' || appKey.trim().length === 0}\n >\n {saveState === 'saving' ? 'Saving...' : 'Save credentials'}\n </button>\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={!canTest || testState.kind === 'running'}\n >\n {testState.kind === 'running' ? 'Testing...' : 'Test connection'}\n </button>\n </div>\n\n {saveState === 'saved' ? <p role=\"status\">Saved.</p> : null}\n {saveState === 'error' && saveError ? (\n <p role=\"alert\">Save failed: {saveError}</p>\n ) : null}\n\n {testState.kind === 'ok' ? (\n <p role=\"status\">\n Connected to AliExpress. Found {testState.categoryCount} categories.\n </p>\n ) : null}\n {testState.kind === 'err' ? (\n <p role=\"alert\">\n Test failed ({testState.code}): {testState.msg}\n </p>\n ) : null}\n </section>\n\n <section aria-labelledby=\"ae-oauth-heading\">\n <h2 id=\"ae-oauth-heading\">Merchant account connection</h2>\n <p>\n Connect a specific AliExpress seller account to enable product\n import into this store. This is separate from the developer app\n credentials above.\n </p>\n\n {initialStatus.needsReauth ? (\n <p role=\"alert\" className=\"reauth-banner\">\n Re-authentication required. Please reconnect your AliExpress account.\n </p>\n ) : null}\n\n <div className=\"status-card\">\n <div>\n <strong>Status:</strong>{' '}\n {initialStatus.connected ? 'Connected' : 'Not connected'}\n </div>\n {initialStatus.sellerId ? (\n <div>\n <strong>Seller ID:</strong> {initialStatus.sellerId}\n </div>\n ) : null}\n {initialStatus.lastSuccessfulCallAt ? (\n <div>\n <strong>Last successful call:</strong>{' '}\n {initialStatus.lastSuccessfulCallAt}\n </div>\n ) : null}\n </div>\n\n <div className=\"actions\">\n <button\n type=\"button\"\n onClick={handleConnect}\n disabled={!canConnect || busyOAuth}\n >\n {busyOAuth ? 'Working...' : 'Connect merchant AliExpress account'}\n </button>\n <button\n type=\"button\"\n onClick={handleDisconnect}\n disabled={!canDisconnect || busyOAuth}\n >\n Disconnect\n </button>\n </div>\n\n {!testEverSucceeded ? (\n <p>\n Run <em>Test connection</em> once with your AppKey/AppSecret before\n connecting a merchant account.\n </p>\n ) : null}\n </section>\n\n <section aria-labelledby=\"ae-coming-soon-heading\">\n <h2 id=\"ae-coming-soon-heading\">Order forwarding</h2>\n <p>\n Coming soon. Automatic order forwarding to AliExpress requires\n our app to be approved out of Test status by AliExpress. Product\n import and browsing work today.\n </p>\n </section>\n </div>\n )\n}\n\nexport default AliExpressDropshippingSettingsForm\n","/**\n * Public types for @amboras-dev/aliexpress-dropshipping.\n *\n * These are the single source of truth for the wire shape between the\n * Amboras admin settings form and the medusa-backend-orchestrator\n * Store API routes under `/store/aliexpress-dropshipping/*`. The DTO\n * files on the medusa side must stay byte-compatible with these.\n */\n\n/**\n * Sentinel returned in place of a stored secret when the settings form\n * reads back current config. Matches the pattern used by meta-ads and\n * pinterest so the admin never sees the plaintext secret after write.\n */\nexport const SECRET_SET_SENTINEL = '__SECRET_SET__' as const\nexport type SecretSetSentinel = typeof SECRET_SET_SENTINEL\n\n/**\n * Per-store AliExpress plugin configuration.\n *\n * - `appKey` / `appSecret` are per-store developer app credentials\n * supplied by the merchant. The admin form receives\n * `SECRET_SET_SENTINEL` for `appSecret` on read, and only sends a\n * real value on user edit.\n * - `connectedSellerId` is populated after the merchant completes the\n * OAuth flow to `/rest/auth/token/create`.\n * - `needsReauth` is flipped by the backend runtime detector when it\n * sees `MissingParameter access_token` or `IllegalAccessToken`\n * sub-codes on any envelope.\n * - `lastSuccessfulCallAt` is an ISO-8601 timestamp for the status card.\n */\nexport interface AliExpressPluginConfig {\n enabled: boolean\n appKey: string | null\n appSecret: string | SecretSetSentinel | null\n connectedSellerId: string | null\n needsReauth: boolean\n lastSuccessfulCallAt: string | null\n}\n\n/**\n * Reasons the backend surfaces when a merchant token becomes invalid.\n * Kept narrow so the admin banner can render a specific message.\n */\nexport enum AliExpressReauthReason {\n MissingAccessToken = 'missing_access_token',\n IllegalAccessToken = 'illegal_access_token',\n RefreshFailed = 'refresh_failed',\n Disconnected = 'disconnected',\n}\n\n/**\n * Category node returned by `aliexpress.ds.category.get`. The API\n * returns a flat list; the admin renders it as a tree by walking\n * `parentCategoryId`.\n */\nexport interface AliExpressCategoryDto {\n categoryId: string\n categoryName: string\n parentCategoryId: string | null\n}\n\n/**\n * Product summary shape returned by `aliexpress.ds.recommend.feed.get`.\n * Used by the \"browse products\" admin surface.\n */\nexport interface AliExpressProductSummaryDto {\n productId: string\n title: string\n imageUrl: string | null\n minPrice: number | null\n maxPrice: number | null\n currency: string | null\n productDetailUrl: string | null\n}\n\n/**\n * Full product shape returned by `aliexpress.ds.product.get`. Consumed\n * by the medusa-side mapper `aliexpressProductToMedusaDraft`.\n */\nexport interface AliExpressProductDto {\n productId: string\n title: string\n description: string | null\n images: string[]\n variants: AliExpressProductVariantDto[]\n weightGrams: number | null\n sourceUrl: string | null\n}\n\nexport interface AliExpressProductVariantDto {\n skuId: string\n title: string | null\n price: number\n currency: string\n stock: number | null\n attributes: Record<string, string>\n}\n\n/**\n * Return shape from `POST /store/aliexpress-dropshipping/products/:id/import`.\n */\nexport interface AliExpressImportResultDto {\n medusaProductId: string\n sourceProductId: string\n importedVariants: number\n}\n\n/**\n * Return shape from `GET /store/aliexpress-dropshipping/status` - drives\n * the admin status card.\n */\nexport interface AliExpressConnectionStatusDto {\n connected: boolean\n sellerId: string | null\n needsReauth: boolean\n reauthReason: AliExpressReauthReason | null\n lastSuccessfulCallAt: string | null\n}\n\n/**\n * Return shape from `POST /store/aliexpress-dropshipping/test-connection`.\n */\nexport type AliExpressTestConnectionResult =\n | { ok: true; categoryCount: number }\n | { ok: false; code: string; msg: string }\n\nexport interface PreflightMerchantError {\n code: string\n message: string\n}\n\nexport interface PreflightAddressError {\n code: string\n message: string\n field: string\n}\n\nexport interface PreflightItemError {\n variantId: string\n productTitle: string\n code: 'CORRUPT_METADATA' | 'PRODUCT_OFFLINE' | 'OUT_OF_STOCK' | 'CANNOT_SHIP' | 'PRICE_DRIFT'\n message: string\n removable: boolean\n}\n\nexport interface PreflightResult {\n ok: boolean\n merchantErrors: PreflightMerchantError[]\n addressErrors: PreflightAddressError[]\n itemErrors: PreflightItemError[]\n warnings: Array<{ code: string; message: string }>\n degraded?: boolean\n warning?: string\n}\n","'use client'\n\nimport { useCallback, useState } from 'react'\nimport type { PreflightResult } from '../types'\n\nexport interface UseAliexpressPreflightOptions {\n baseUrl?: string\n publishableKey?: string\n}\n\nexport function useAliexpressPreflight(options: UseAliexpressPreflightOptions = {}) {\n const [isPending, setIsPending] = useState(false)\n const mutateAsync = useCallback(async ({ cartId }: { cartId: string }): Promise<PreflightResult> => {\n setIsPending(true)\n try {\n const baseUrl = options.baseUrl ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? ''\n const publishableKey = options.publishableKey ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? ''\n const response = await fetch(`${baseUrl.replace(/\\/$/, '')}/store/aliexpress-dropshipping/preflight-cart`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(publishableKey ? { 'x-publishable-api-key': publishableKey } : {}),\n },\n body: JSON.stringify({ cart_id: cartId }),\n })\n if (!response.ok) throw new Error(`Preflight check failed: ${response.status}`)\n return await response.json() as PreflightResult\n } finally {\n setIsPending(false)\n }\n }, [options.baseUrl, options.publishableKey])\n\n return { mutateAsync, isPending }\n}\n","'use client'\n\nimport { cloneElement, type MouseEvent, type ReactElement } from 'react'\nimport { useAliexpressPreflight, type UseAliexpressPreflightOptions } from './use-preflight'\nimport type { PreflightResult } from '../types'\n\nexport interface AliexpressCheckoutGuardProps {\n cartId: string\n children: ReactElement<{ onClick?: (event: MouseEvent) => void }>\n onBlock: (result: PreflightResult) => void\n onPass?: () => void | Promise<void>\n options?: UseAliexpressPreflightOptions\n}\n\nexport function AliexpressCheckoutGuard({ cartId, children, onBlock, onPass, options }: AliexpressCheckoutGuardProps) {\n const preflight = useAliexpressPreflight(options)\n const onClick = async (event: MouseEvent) => {\n event.preventDefault()\n const result = await preflight.mutateAsync({ cartId })\n if (!result.ok) {\n onBlock(result)\n return\n }\n await onPass?.()\n }\n return cloneElement(children, { onClick })\n}\n"],"mappings":"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","names":["AliExpressReauthReason","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/settings-form.tsx","../src/types.ts"],"sourcesContent":["// Admin settings form (Class B - the only React surface).\nexport {\n AliExpressDropshippingSettingsForm,\n type AliExpressDropshippingSettingsFormProps,\n} from './settings-form'\n\n// Shared wire types - kept in sync with the medusa-backend-orchestrator DTOs.\nexport {\n SECRET_SET_SENTINEL,\n AliExpressReauthReason,\n} from './types'\nexport type {\n SecretSetSentinel,\n AliExpressPluginConfig,\n AliExpressCategoryDto,\n AliExpressProductSummaryDto,\n AliExpressProductDto,\n AliExpressProductVariantDto,\n AliExpressImportResultDto,\n AliExpressConnectionStatusDto,\n AliExpressTestConnectionResult,\n} from './types'\n\n","'use client'\n\n/**\n * Admin settings form for the AliExpress Dropshipping integration.\n *\n * Class B: this component owns the UI and talks to the Medusa Store API\n * under `/store/aliexpress-dropshipping/*`. It does NOT embed any\n * AliExpress SDK, does not sign requests, and does not touch OAuth\n * tokens directly - the backend does all of that.\n *\n * The component is intentionally dependency-light (no external UI kit,\n * no @tanstack/react-query peer) so the admin bundle can drop it in\n * without extra peer dep resolution.\n */\n\nimport * as React from 'react'\nimport type {\n AliExpressPluginConfig,\n AliExpressConnectionStatusDto,\n AliExpressTestConnectionResult,\n} from './types'\nimport { SECRET_SET_SENTINEL } from './types'\n\nexport interface AliExpressDropshippingSettingsFormProps {\n /** Current config for this store (fetched by the parent server component). */\n initialConfig: AliExpressPluginConfig\n /** Current connection status (from `GET /status`). */\n initialStatus: AliExpressConnectionStatusDto\n /**\n * Persist non-secret + optionally new secret values. The parent maps\n * this onto `PATCH /store/aliexpress-dropshipping/config` (or\n * equivalent) and then re-fetches config on success.\n *\n * `appSecret` is only sent when the merchant actually typed a new\n * value; if they leave the field untouched, this method receives\n * `undefined` for that key so the backend keeps the existing secret.\n */\n onSaveConfig: (patch: {\n appKey?: string\n appSecret?: string\n enabled?: boolean\n }) => Promise<void>\n /** Kick off `POST /oauth/start` and redirect to the returned URL. */\n onConnect: () => Promise<void>\n /** Kick off `POST /oauth/disconnect` and clear merchant credentials. */\n onDisconnect: () => Promise<void>\n /** Call `POST /test-connection` and return the result. */\n onTestConnection: () => Promise<AliExpressTestConnectionResult>\n}\n\ntype SaveState = 'idle' | 'saving' | 'saved' | 'error'\ntype TestState =\n | { kind: 'idle' }\n | { kind: 'running' }\n | { kind: 'ok'; categoryCount: number }\n | { kind: 'err'; code: string; msg: string }\n\n/**\n * Amboras admin settings surface for AliExpress Dropshipping.\n * Renders AppKey + AppSecret inputs, Test / Connect / Disconnect\n * buttons, status card, and a \"Coming soon\" order-forwarding block.\n */\nexport function AliExpressDropshippingSettingsForm(\n props: AliExpressDropshippingSettingsFormProps,\n): React.ReactElement {\n const {\n initialConfig,\n initialStatus,\n onSaveConfig,\n onConnect,\n onDisconnect,\n onTestConnection,\n } = props\n\n const [appKey, setAppKey] = React.useState<string>(\n initialConfig.appKey ?? '',\n )\n const secretPreset =\n initialConfig.appSecret === SECRET_SET_SENTINEL ||\n (typeof initialConfig.appSecret === 'string' &&\n initialConfig.appSecret.length > 0)\n const [appSecret, setAppSecret] = React.useState<string>('')\n const [secretDirty, setSecretDirty] = React.useState<boolean>(false)\n\n const [saveState, setSaveState] = React.useState<SaveState>('idle')\n const [saveError, setSaveError] = React.useState<string | null>(null)\n\n const [testState, setTestState] = React.useState<TestState>({ kind: 'idle' })\n const [testEverSucceeded, setTestEverSucceeded] = React.useState<boolean>(\n initialStatus.connected,\n )\n\n const [busyOAuth, setBusyOAuth] = React.useState<boolean>(false)\n\n const hasStoredSecret = secretPreset || secretDirty\n const canTest = appKey.trim().length > 0 && hasStoredSecret\n const canConnect = testEverSucceeded && !initialStatus.connected\n const canDisconnect = initialStatus.connected\n\n const handleSave = React.useCallback(async () => {\n setSaveState('saving')\n setSaveError(null)\n try {\n const patch: {\n appKey?: string\n appSecret?: string\n enabled?: boolean\n } = {}\n if (appKey.trim() !== (initialConfig.appKey ?? '')) {\n patch.appKey = appKey.trim()\n }\n if (secretDirty && appSecret.length > 0) {\n patch.appSecret = appSecret\n }\n await onSaveConfig(patch)\n setSaveState('saved')\n setSecretDirty(false)\n setAppSecret('')\n } catch (err) {\n setSaveState('error')\n setSaveError(err instanceof Error ? err.message : 'Save failed')\n }\n }, [appKey, appSecret, secretDirty, initialConfig.appKey, onSaveConfig])\n\n const handleTest = React.useCallback(async () => {\n setTestState({ kind: 'running' })\n try {\n const result = await onTestConnection()\n if (result.ok) {\n setTestState({ kind: 'ok', categoryCount: result.categoryCount })\n setTestEverSucceeded(true)\n } else {\n setTestState({ kind: 'err', code: result.code, msg: result.msg })\n }\n } catch (err) {\n setTestState({\n kind: 'err',\n code: 'UNKNOWN',\n msg: err instanceof Error ? err.message : 'Test failed',\n })\n }\n }, [onTestConnection])\n\n const handleConnect = React.useCallback(async () => {\n setBusyOAuth(true)\n try {\n await onConnect()\n } finally {\n setBusyOAuth(false)\n }\n }, [onConnect])\n\n const handleDisconnect = React.useCallback(async () => {\n setBusyOAuth(true)\n try {\n await onDisconnect()\n } finally {\n setBusyOAuth(false)\n }\n }, [onDisconnect])\n\n return (\n <div className=\"aliexpress-dropshipping-settings\">\n <section aria-labelledby=\"ae-credentials-heading\">\n <h2 id=\"ae-credentials-heading\">Developer app credentials</h2>\n <p>\n Enter your AliExpress Open Platform app credentials. These are\n stored encrypted at rest and used to sign every AliExpress API\n call for this store.\n </p>\n\n <label>\n <span>App Key</span>\n <input\n type=\"text\"\n value={appKey}\n onChange={(e) => setAppKey(e.target.value)}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </label>\n\n <label>\n <span>App Secret</span>\n <input\n type=\"password\"\n value={appSecret}\n placeholder={secretPreset ? '(secret set - leave blank to keep)' : ''}\n onChange={(e) => {\n setAppSecret(e.target.value)\n setSecretDirty(true)\n }}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </label>\n\n <div className=\"actions\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saveState === 'saving' || appKey.trim().length === 0}\n >\n {saveState === 'saving' ? 'Saving...' : 'Save credentials'}\n </button>\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={!canTest || testState.kind === 'running'}\n >\n {testState.kind === 'running' ? 'Testing...' : 'Test connection'}\n </button>\n </div>\n\n {saveState === 'saved' ? <p role=\"status\">Saved.</p> : null}\n {saveState === 'error' && saveError ? (\n <p role=\"alert\">Save failed: {saveError}</p>\n ) : null}\n\n {testState.kind === 'ok' ? (\n <p role=\"status\">\n Connected to AliExpress. Found {testState.categoryCount} categories.\n </p>\n ) : null}\n {testState.kind === 'err' ? (\n <p role=\"alert\">\n Test failed ({testState.code}): {testState.msg}\n </p>\n ) : null}\n </section>\n\n <section aria-labelledby=\"ae-oauth-heading\">\n <h2 id=\"ae-oauth-heading\">Merchant account connection</h2>\n <p>\n Connect a specific AliExpress seller account to enable product\n import into this store. This is separate from the developer app\n credentials above.\n </p>\n\n {initialStatus.needsReauth ? (\n <p role=\"alert\" className=\"reauth-banner\">\n Re-authentication required. Please reconnect your AliExpress account.\n </p>\n ) : null}\n\n <div className=\"status-card\">\n <div>\n <strong>Status:</strong>{' '}\n {initialStatus.connected ? 'Connected' : 'Not connected'}\n </div>\n {initialStatus.sellerId ? (\n <div>\n <strong>Seller ID:</strong> {initialStatus.sellerId}\n </div>\n ) : null}\n {initialStatus.lastSuccessfulCallAt ? (\n <div>\n <strong>Last successful call:</strong>{' '}\n {initialStatus.lastSuccessfulCallAt}\n </div>\n ) : null}\n </div>\n\n <div className=\"actions\">\n <button\n type=\"button\"\n onClick={handleConnect}\n disabled={!canConnect || busyOAuth}\n >\n {busyOAuth ? 'Working...' : 'Connect merchant AliExpress account'}\n </button>\n <button\n type=\"button\"\n onClick={handleDisconnect}\n disabled={!canDisconnect || busyOAuth}\n >\n Disconnect\n </button>\n </div>\n\n {!testEverSucceeded ? (\n <p>\n Run <em>Test connection</em> once with your AppKey/AppSecret before\n connecting a merchant account.\n </p>\n ) : null}\n </section>\n\n <section aria-labelledby=\"ae-coming-soon-heading\">\n <h2 id=\"ae-coming-soon-heading\">Order forwarding</h2>\n <p>\n Coming soon. Automatic order forwarding to AliExpress requires\n our app to be approved out of Test status by AliExpress. Product\n import and browsing work today.\n </p>\n </section>\n </div>\n )\n}\n\nexport default AliExpressDropshippingSettingsForm\n","/**\n * Public types for @amboras-dev/aliexpress-dropshipping.\n *\n * These are the single source of truth for the wire shape between the\n * Amboras admin settings form and the medusa-backend-orchestrator\n * Store API routes under `/store/aliexpress-dropshipping/*`. The DTO\n * files on the medusa side must stay byte-compatible with these.\n */\n\n/**\n * Sentinel returned in place of a stored secret when the settings form\n * reads back current config. Matches the pattern used by meta-ads and\n * pinterest so the admin never sees the plaintext secret after write.\n */\nexport const SECRET_SET_SENTINEL = '__SECRET_SET__' as const\nexport type SecretSetSentinel = typeof SECRET_SET_SENTINEL\n\n/**\n * Per-store AliExpress plugin configuration.\n *\n * - `appKey` / `appSecret` are per-store developer app credentials\n * supplied by the merchant. The admin form receives\n * `SECRET_SET_SENTINEL` for `appSecret` on read, and only sends a\n * real value on user edit.\n * - `connectedSellerId` is populated after the merchant completes the\n * OAuth flow to `/rest/auth/token/create`.\n * - `needsReauth` is flipped by the backend runtime detector when it\n * sees `MissingParameter access_token` or `IllegalAccessToken`\n * sub-codes on any envelope.\n * - `lastSuccessfulCallAt` is an ISO-8601 timestamp for the status card.\n */\nexport interface AliExpressPluginConfig {\n enabled: boolean\n appKey: string | null\n appSecret: string | SecretSetSentinel | null\n connectedSellerId: string | null\n needsReauth: boolean\n lastSuccessfulCallAt: string | null\n}\n\n/**\n * Reasons the backend surfaces when a merchant token becomes invalid.\n * Kept narrow so the admin banner can render a specific message.\n */\nexport enum AliExpressReauthReason {\n MissingAccessToken = 'missing_access_token',\n IllegalAccessToken = 'illegal_access_token',\n RefreshFailed = 'refresh_failed',\n Disconnected = 'disconnected',\n}\n\n/**\n * Category node returned by `aliexpress.ds.category.get`. The API\n * returns a flat list; the admin renders it as a tree by walking\n * `parentCategoryId`.\n */\nexport interface AliExpressCategoryDto {\n categoryId: string\n categoryName: string\n parentCategoryId: string | null\n}\n\n/**\n * Product summary shape returned by `aliexpress.ds.recommend.feed.get`.\n * Used by the \"browse products\" admin surface.\n */\nexport interface AliExpressProductSummaryDto {\n productId: string\n title: string\n imageUrl: string | null\n minPrice: number | null\n maxPrice: number | null\n currency: string | null\n productDetailUrl: string | null\n}\n\n/**\n * Full product shape returned by `aliexpress.ds.product.get`. Consumed\n * by the medusa-side mapper `aliexpressProductToMedusaDraft`.\n */\nexport interface AliExpressProductDto {\n productId: string\n title: string\n description: string | null\n images: string[]\n variants: AliExpressProductVariantDto[]\n weightGrams: number | null\n sourceUrl: string | null\n}\n\nexport interface AliExpressProductVariantDto {\n skuId: string\n title: string | null\n price: number\n currency: string\n stock: number | null\n attributes: Record<string, string>\n}\n\n/**\n * Return shape from `POST /store/aliexpress-dropshipping/products/:id/import`.\n */\nexport interface AliExpressImportResultDto {\n medusaProductId: string\n sourceProductId: string\n importedVariants: number\n}\n\n/**\n * Return shape from `GET /store/aliexpress-dropshipping/status` - drives\n * the admin status card.\n */\nexport interface AliExpressConnectionStatusDto {\n connected: boolean\n sellerId: string | null\n needsReauth: boolean\n reauthReason: AliExpressReauthReason | null\n lastSuccessfulCallAt: string | null\n}\n\n/**\n * Return shape from `POST /store/aliexpress-dropshipping/test-connection`.\n */\nexport type AliExpressTestConnectionResult =\n | { ok: true; categoryCount: number }\n | { ok: false; code: string; msg: string }\n\nexport interface PreflightMerchantError {\n code: string\n message: string\n}\n\nexport interface PreflightAddressError {\n code: string\n message: string\n field: string\n}\n\nexport interface PreflightItemError {\n variantId: string\n productTitle: string\n code: 'CORRUPT_METADATA' | 'PRODUCT_OFFLINE' | 'OUT_OF_STOCK' | 'CANNOT_SHIP' | 'PRICE_DRIFT'\n message: string\n removable: boolean\n}\n\nexport interface PreflightResult {\n ok: boolean\n merchantErrors: PreflightMerchantError[]\n addressErrors: PreflightAddressError[]\n itemErrors: PreflightItemError[]\n warnings: Array<{ code: string; message: string }>\n degraded?: boolean\n warning?: string\n}\n"],"mappings":"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","names":["AliExpressReauthReason"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AliexpressCheckoutGuard,
|
|
3
|
-
useAliexpressPreflight
|
|
4
|
-
} from "./chunk-PK4PMTFZ.mjs";
|
|
5
1
|
import {
|
|
6
2
|
AliExpressDropshippingSettingsForm,
|
|
7
3
|
AliExpressReauthReason,
|
|
@@ -10,8 +6,6 @@ import {
|
|
|
10
6
|
export {
|
|
11
7
|
AliExpressDropshippingSettingsForm,
|
|
12
8
|
AliExpressReauthReason,
|
|
13
|
-
|
|
14
|
-
SECRET_SET_SENTINEL,
|
|
15
|
-
useAliexpressPreflight
|
|
9
|
+
SECRET_SET_SENTINEL
|
|
16
10
|
};
|
|
17
11
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -148,4 +148,4 @@ interface PreflightResult {
|
|
|
148
148
|
warning?: string;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
export { type
|
|
151
|
+
export { type AliExpressPluginConfig as A, type PreflightResult as P, SECRET_SET_SENTINEL as S, type PreflightAddressError as a, type PreflightItemError as b, type PreflightMerchantError as c, type AliExpressConnectionStatusDto as d, type AliExpressTestConnectionResult as e, type AliExpressCategoryDto as f, type AliExpressImportResultDto as g, type AliExpressProductDto as h, type AliExpressProductSummaryDto as i, type AliExpressProductVariantDto as j, AliExpressReauthReason as k, type SecretSetSentinel as l };
|
|
@@ -148,4 +148,4 @@ interface PreflightResult {
|
|
|
148
148
|
warning?: string;
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
export { type
|
|
151
|
+
export { type AliExpressPluginConfig as A, type PreflightResult as P, SECRET_SET_SENTINEL as S, type PreflightAddressError as a, type PreflightItemError as b, type PreflightMerchantError as c, type AliExpressConnectionStatusDto as d, type AliExpressTestConnectionResult as e, type AliExpressCategoryDto as f, type AliExpressImportResultDto as g, type AliExpressProductDto as h, type AliExpressProductSummaryDto as i, type AliExpressProductVariantDto as j, AliExpressReauthReason as k, type SecretSetSentinel as l };
|
package/package.json
CHANGED
package/dist/chunk-PK4PMTFZ.mjs
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// src/client/use-preflight.ts
|
|
2
|
-
import { useCallback, useState } from "react";
|
|
3
|
-
function useAliexpressPreflight(options = {}) {
|
|
4
|
-
const [isPending, setIsPending] = useState(false);
|
|
5
|
-
const mutateAsync = useCallback(async ({ cartId }) => {
|
|
6
|
-
setIsPending(true);
|
|
7
|
-
try {
|
|
8
|
-
const baseUrl = options.baseUrl ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? "";
|
|
9
|
-
const publishableKey = options.publishableKey ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? "";
|
|
10
|
-
const response = await fetch(`${baseUrl.replace(/\/$/, "")}/store/aliexpress-dropshipping/preflight-cart`, {
|
|
11
|
-
method: "POST",
|
|
12
|
-
headers: {
|
|
13
|
-
"Content-Type": "application/json",
|
|
14
|
-
...publishableKey ? { "x-publishable-api-key": publishableKey } : {}
|
|
15
|
-
},
|
|
16
|
-
body: JSON.stringify({ cart_id: cartId })
|
|
17
|
-
});
|
|
18
|
-
if (!response.ok) throw new Error(`Preflight check failed: ${response.status}`);
|
|
19
|
-
return await response.json();
|
|
20
|
-
} finally {
|
|
21
|
-
setIsPending(false);
|
|
22
|
-
}
|
|
23
|
-
}, [options.baseUrl, options.publishableKey]);
|
|
24
|
-
return { mutateAsync, isPending };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// src/client/preflight-guard.tsx
|
|
28
|
-
import { cloneElement } from "react";
|
|
29
|
-
function AliexpressCheckoutGuard({ cartId, children, onBlock, onPass, options }) {
|
|
30
|
-
const preflight = useAliexpressPreflight(options);
|
|
31
|
-
const onClick = async (event) => {
|
|
32
|
-
event.preventDefault();
|
|
33
|
-
const result = await preflight.mutateAsync({ cartId });
|
|
34
|
-
if (!result.ok) {
|
|
35
|
-
onBlock(result);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
await onPass?.();
|
|
39
|
-
};
|
|
40
|
-
return cloneElement(children, { onClick });
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export {
|
|
44
|
-
useAliexpressPreflight,
|
|
45
|
-
AliexpressCheckoutGuard
|
|
46
|
-
};
|
|
47
|
-
//# sourceMappingURL=chunk-PK4PMTFZ.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/use-preflight.ts","../src/client/preflight-guard.tsx"],"sourcesContent":["'use client'\n\nimport { useCallback, useState } from 'react'\nimport type { PreflightResult } from '../types'\n\nexport interface UseAliexpressPreflightOptions {\n baseUrl?: string\n publishableKey?: string\n}\n\nexport function useAliexpressPreflight(options: UseAliexpressPreflightOptions = {}) {\n const [isPending, setIsPending] = useState(false)\n const mutateAsync = useCallback(async ({ cartId }: { cartId: string }): Promise<PreflightResult> => {\n setIsPending(true)\n try {\n const baseUrl = options.baseUrl ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? ''\n const publishableKey = options.publishableKey ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY ?? ''\n const response = await fetch(`${baseUrl.replace(/\\/$/, '')}/store/aliexpress-dropshipping/preflight-cart`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(publishableKey ? { 'x-publishable-api-key': publishableKey } : {}),\n },\n body: JSON.stringify({ cart_id: cartId }),\n })\n if (!response.ok) throw new Error(`Preflight check failed: ${response.status}`)\n return await response.json() as PreflightResult\n } finally {\n setIsPending(false)\n }\n }, [options.baseUrl, options.publishableKey])\n\n return { mutateAsync, isPending }\n}\n","'use client'\n\nimport { cloneElement, type MouseEvent, type ReactElement } from 'react'\nimport { useAliexpressPreflight, type UseAliexpressPreflightOptions } from './use-preflight'\nimport type { PreflightResult } from '../types'\n\nexport interface AliexpressCheckoutGuardProps {\n cartId: string\n children: ReactElement<{ onClick?: (event: MouseEvent) => void }>\n onBlock: (result: PreflightResult) => void\n onPass?: () => void | Promise<void>\n options?: UseAliexpressPreflightOptions\n}\n\nexport function AliexpressCheckoutGuard({ cartId, children, onBlock, onPass, options }: AliexpressCheckoutGuardProps) {\n const preflight = useAliexpressPreflight(options)\n const onClick = async (event: MouseEvent) => {\n event.preventDefault()\n const result = await preflight.mutateAsync({ cartId })\n if (!result.ok) {\n onBlock(result)\n return\n }\n await onPass?.()\n }\n return cloneElement(children, { onClick })\n}\n"],"mappings":";AAEA,SAAS,aAAa,gBAAgB;AAQ/B,SAAS,uBAAuB,UAAyC,CAAC,GAAG;AAClF,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,cAAc,YAAY,OAAO,EAAE,OAAO,MAAoD;AAClG,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,UAAU,QAAQ,WAAW,QAAQ,IAAI,kCAAkC;AACjF,YAAM,iBAAiB,QAAQ,kBAAkB,QAAQ,IAAI,sCAAsC;AACnG,YAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC,iDAAiD;AAAA,QACzG,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAI,iBAAiB,EAAE,yBAAyB,eAAe,IAAI,CAAC;AAAA,QACtE;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,SAAS,OAAO,CAAC;AAAA,MAC1C,CAAC;AACD,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,2BAA2B,SAAS,MAAM,EAAE;AAC9E,aAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,QAAQ,cAAc,CAAC;AAE5C,SAAO,EAAE,aAAa,UAAU;AAClC;;;AC/BA,SAAS,oBAAwD;AAY1D,SAAS,wBAAwB,EAAE,QAAQ,UAAU,SAAS,QAAQ,QAAQ,GAAiC;AACpH,QAAM,YAAY,uBAAuB,OAAO;AAChD,QAAM,UAAU,OAAO,UAAsB;AAC3C,UAAM,eAAe;AACrB,UAAM,SAAS,MAAM,UAAU,YAAY,EAAE,OAAO,CAAC;AACrD,QAAI,CAAC,OAAO,IAAI;AACd,cAAQ,MAAM;AACd;AAAA,IACF;AACA,UAAM,SAAS;AAAA,EACjB;AACA,SAAO,aAAa,UAAU,EAAE,QAAQ,CAAC;AAC3C;","names":[]}
|