@metagptx/web-sdk 0.0.52-beta.11 → 0.0.52-beta.13
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.ts +2 -28
- package/dist/index.js +1 -82
- package/dist/plugins.d.ts +141 -0
- package/dist/plugins.js +82 -0
- package/package.json +33 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as axios0 from "axios";
|
|
2
2
|
import { AxiosRequestConfig } from "axios";
|
|
3
|
-
import { Plugin } from "vite";
|
|
4
3
|
|
|
5
4
|
//#region src/utils/request.d.ts
|
|
6
5
|
/**
|
|
@@ -118,31 +117,6 @@ type IntegrationFunction = (params?: IntegrationParams) => Promise<AnyType>;
|
|
|
118
117
|
* @param params.requestInstance - Axios instance for making HTTP requests
|
|
119
118
|
* @returns Proxy object that dynamically creates integration calls
|
|
120
119
|
*/
|
|
120
|
+
|
|
121
121
|
//#endregion
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Vite plugin to create a virtual 404 React component and automatically add a 404 route
|
|
125
|
-
*/
|
|
126
|
-
declare function vitePlugin404(): Plugin;
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/plugins/vite-plugin-routes.d.ts
|
|
129
|
-
interface PluginOptions {
|
|
130
|
-
/** 路由文件路径,默认 'src/App.tsx' */
|
|
131
|
-
routeFile?: string;
|
|
132
|
-
/** 入口文件路径,用于自动注入,默认 'src/main.tsx' */
|
|
133
|
-
entryFile?: string;
|
|
134
|
-
/** 虚拟模块 ID */
|
|
135
|
-
moduleId?: string;
|
|
136
|
-
/** 是否自动向父级 iframe 发送路由信息,默认 true */
|
|
137
|
-
notifyParent?: boolean;
|
|
138
|
-
/** 发送给父级的消息类型标识 */
|
|
139
|
-
messageType?: string;
|
|
140
|
-
/** 要排除的路由路径模式 */
|
|
141
|
-
excludePaths?: string[];
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Vite 插件:解析 React Router 的 Route 组件,生成路由信息
|
|
145
|
-
*/
|
|
146
|
-
declare function vitePluginRoutes(options?: PluginOptions): Plugin;
|
|
147
|
-
//#endregion
|
|
148
|
-
export { type AnyType, type ApiCallParams, type ClientConfig, type IntegrationFunction, type IntegrationParams, type RequestConfig, createClient, vitePlugin404, vitePluginRoutes };
|
|
122
|
+
export { type AnyType, type ApiCallParams, type ClientConfig, type IntegrationFunction, type IntegrationParams, type RequestConfig, createClient };
|
package/dist/index.js
CHANGED
|
@@ -1,82 +1 @@
|
|
|
1
|
-
import e from"axios";import t from"qs";
|
|
2
|
-
import { createClient } from '@metagptx/web-sdk';
|
|
3
|
-
|
|
4
|
-
// Create client instance
|
|
5
|
-
const client = createClient();
|
|
6
|
-
|
|
7
|
-
export default function NotFoundPage() {
|
|
8
|
-
const isInMGXIframe =
|
|
9
|
-
window.self !== window.top && window.name?.includes('devIframe');
|
|
10
|
-
return (
|
|
11
|
-
<div className="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-gray-50 to-blue-50 p-6 text-center">
|
|
12
|
-
<div className="space-y-6 max-w-md">
|
|
13
|
-
<div className="space-y-3">
|
|
14
|
-
<h1 className="text-5xl font-bold text-primary">404</h1>
|
|
15
|
-
<h2 className="text-2xl font-semibold text-gray-800">
|
|
16
|
-
Page Not Found
|
|
17
|
-
</h2>
|
|
18
|
-
<p className="text-muted-foreground">
|
|
19
|
-
The page you're looking for doesn't exist or may have been moved.
|
|
20
|
-
</p>
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
|
24
|
-
<Button asChild>
|
|
25
|
-
<a href="/">Return Home</a>
|
|
26
|
-
</Button>
|
|
27
|
-
{isInMGXIframe ? (
|
|
28
|
-
<Button variant="outline" onClick={() => client.frame.createPage()}>
|
|
29
|
-
Create page
|
|
30
|
-
</Button>
|
|
31
|
-
) : (
|
|
32
|
-
<Button
|
|
33
|
-
variant="outline"
|
|
34
|
-
onClick={() => (window.location.href = 'https://mgx.dev')}
|
|
35
|
-
>
|
|
36
|
-
Go to MGX
|
|
37
|
-
</Button>
|
|
38
|
-
)}
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
`;return{name:`vite-plugin-404`,enforce:`pre`,resolveId(t){return t===e||t.startsWith(e)?`\0${e}.tsx`:null},load(n){return n===`\0${e}.tsx`||n.includes(`virtual:404-page`)?t:null},transform(e,t){if(!t.includes(`App.tsx`)||!t.endsWith(`.tsx`))return null;let n=e.includes(`virtual:404-page`)||e.includes(`NotFound404`)||e.includes(`NotFoundPage`)||/path\s*=\s*["']\*["']/.test(e);if(n)return null;let r=!1,i=e.includes(`virtual:404-page`);if(!i){let t=/(import\s+AuthError\s+from\s+['"][^'"]+AuthError[^'"]*['"];)/;if(t.test(e))e=e.replace(t,`$1
|
|
45
|
-
import NotFoundPage from 'virtual:404-page';`),r=!0;else if(/\/\/\s*MODULE_IMPORTS_END/.test(e))e=e.replace(/(\/\/\s*MODULE_IMPORTS_END)/,`$1
|
|
46
|
-
import NotFoundPage from 'virtual:404-page';`),r=!0;else if(/\/\/\s*MODULE_IMPORTS_START/.test(e))e=e.replace(/(\/\/\s*MODULE_IMPORTS_START)/,`import NotFoundPage from 'virtual:404-page';
|
|
47
|
-
$1`),r=!0;else{let t=/(^import\s[^;]+;)/gm,n=[...e.matchAll(t)];if(n.length>0){let t=n[n.length-1],i=t.index+t[0].length,a=e.substring(0,i),o=e.substring(i);e=`${a}\nimport NotFoundPage from 'virtual:404-page';${o}`,r=!0}}}let a=/path\s*=\s*["']\*["']/.test(e);if(!a){if(/\/\/\s*MODULE_ROUTES_END/.test(e)){let t=e.match(/(\s*)\/\/\s*MODULE_ROUTES_END/);if(t){let n=t[1];e=e.replace(/(\s*)\/\/\s*MODULE_ROUTES_END/,`${n}<Route path="*" element={<NotFoundPage />} />\n$1// MODULE_ROUTES_END`),r=!0}}else if(/<\/Routes>/.test(e)){let t=e.match(/(\s*)<\/Routes>/);if(t){let n=t[1],i=e.match(/(\s+)<Route\s+path=/),a=i?i[1]:`${n} `;e=e.replace(/(\s*)<\/Routes>/,`${a}<Route path="*" element={<NotFoundPage />} />\n$1</Routes>`),r=!0}}else if(/<Route\s+path=/.test(e)){let t=/<Route\s[^>]*\/>|<Route\s[^>]*>[\s\S]*?<\/Route>/g,n=[...e.matchAll(t)];if(n.length>0){let t=n[n.length-1],i=t.index+t[0].length,a=e.substring(0,i),o=e.substring(i),s=a.split(`
|
|
48
|
-
`),c=s[s.length-1],l=c.match(/^(\s*)/)?.[1]||``;e=`${a}\n${l}<Route path="*" element={<NotFoundPage />} />${o}`,r=!0}}}return r?{code:e,map:null}:null}}}const D=a.default||a;function O(e={}){let{routeFile:t=`src/App.tsx`,entryFile:a=`src/main.tsx`,moduleId:s=`virtual:routes-manifest`,notifyParent:c=!0,messageType:l=`ROUTES_MANIFEST`,excludePaths:u=[`*`]}=e,d=`\0${s}`,f=process.cwd();function p(e,t){for(let n of e)if(o.isJSXAttribute(n)&&o.isJSXIdentifier(n.name,{name:t})&&o.isStringLiteral(n.value))return n.value.value}function m(e){for(let t of e)if(o.isJSXAttribute(t)&&o.isJSXIdentifier(t.name,{name:`element`})){let e=t.value;if(o.isJSXExpressionContainer(e)){let t=e.expression;if(o.isJSXElement(t)){let e=t.openingElement;if(o.isJSXIdentifier(e.name))return e.name.name}}}}function h(e){return e.some(e=>o.isJSXAttribute(e)&&o.isJSXIdentifier(e.name,{name:`element`}))}function g(e){return e.some(e=>o.isJSXAttribute(e)&&o.isJSXIdentifier(e.name,{name:`index`}))}function _(e,t){let n=[];for(let r of e)if(o.isJSXElement(r)){let e=r.openingElement;if(o.isJSXIdentifier(e.name,{name:`Route`})){let e=v(r,t);e&&n.push(e)}}return n}function v(e,t){let n=e.openingElement.attributes,r=p(n,`path`),i=g(n),a=h(n),o=m(n),s;if(i)s=t||`/`;else if(r===void 0)return null;else s=r.startsWith(`/`)?r:t===`/`?`/${r}`:`${t}/${r}`;s=s.replace(/\/+/g,`/`),s!==`/`&&s.endsWith(`/`)&&(s=s.slice(0,-1));let c={path:s,hasElement:a,elementName:o,isWildcard:r===`*`,isIndex:i};if(e.children&&e.children.length>0){let t=_(e.children,s);t.length>0&&(c.children=t)}return c}function y(e,t=[]){for(let n of e)n.hasElement&&t.push({path:n.path,elementName:n.elementName}),n.children&&y(n.children,t);return t}function b(e){let t=0;for(let n of e)t++,n.children&&(t+=b(n.children));return t}function x(e){let t={routeTree:[],routes:[],pageCount:0,total:0,generatedAt:new Date().toISOString()};if(!n.existsSync(e))return console.warn(`[routes-scanner] Route file not found: ${e}`),t;let r=n.readFileSync(e,`utf-8`),a;try{a=i.parse(r,{sourceType:`module`,plugins:[`jsx`,`typescript`]})}catch(e){return console.error(`[routes-scanner] Failed to parse route file:`,e),t}let s=[];D(a,{JSXElement(e){let t=e.node.openingElement;if(o.isJSXIdentifier(t.name,{name:`Routes`})){let t=e.node.children;for(let e of t)if(o.isJSXElement(e)){let t=e.openingElement;if(o.isJSXIdentifier(t.name,{name:`Route`})){let t=v(e,``);t&&s.push(t)}}e.stop()}}});let c=y(s),l=c.filter(e=>!u.some(t=>e.path===t||e.path.match(RegExp(`^${t.replace(`*`,`.*`)}$`))));return{routeTree:s,routes:c,pageCount:l.length,total:b(s),generatedAt:new Date().toISOString()}}return{name:`vite-plugin-routes-scanner`,configResolved(e){f=e.root},resolveId(e){if(e===s)return d},load(e){if(e===d){let e=r.resolve(f,t),n=x(e),i=c?`
|
|
49
|
-
// 向父级 iframe 发送路由信息
|
|
50
|
-
function notifyParentWindow() {
|
|
51
|
-
console.log('[routes-scanner] notifyParentWindow', routesManifest);
|
|
52
|
-
if (typeof window !== 'undefined' && window.parent && window.parent !== window) {
|
|
53
|
-
try {
|
|
54
|
-
window.parent.postMessage({
|
|
55
|
-
type: '${l}',
|
|
56
|
-
payload: routesManifest,
|
|
57
|
-
}, '*');
|
|
58
|
-
} catch (e) {
|
|
59
|
-
console.warn('[routes-scanner] Failed to notify parent window:', e);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// 页面加载完成后发送
|
|
65
|
-
if (typeof window !== 'undefined') {
|
|
66
|
-
if (document.readyState === 'complete') {
|
|
67
|
-
notifyParentWindow();
|
|
68
|
-
} else {
|
|
69
|
-
window.addEventListener('load', notifyParentWindow);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export { notifyParentWindow };
|
|
74
|
-
`:``;return`
|
|
75
|
-
export const routesManifest = ${JSON.stringify(n,null,2)};
|
|
76
|
-
export const routeTree = routesManifest.routeTree;
|
|
77
|
-
export const routes = routesManifest.routes;
|
|
78
|
-
export const pageCount = routesManifest.pageCount;
|
|
79
|
-
export const total = routesManifest.total;
|
|
80
|
-
${i}
|
|
81
|
-
export default routesManifest;
|
|
82
|
-
`}},transform(e,t){let n=t.replace(/\\/g,`/`),i=r.resolve(f,a).replace(/\\/g,`/`);if(n===i&&c){let t=`import "${s}";\n`;return e.includes(s)?null:{code:t+e,map:null}}return null},configureServer(e){let n=r.resolve(f,t);e.watcher.add(n),e.watcher.on(`change`,t=>{if(t===n){let t=e.moduleGraph.getModuleById(d);t&&(e.moduleGraph.invalidateModule(t),e.ws.send({type:`full-reload`}))}})}}}export{T as createClient,E as vitePlugin404,O as vitePluginRoutes};
|
|
1
|
+
import e from"axios";import t from"qs";const n=e=>{let t=e.response?.status;if(t&&t>=400&&t!==401)try{typeof window<`u`&&window.top&&window.top?.postMessage({type:`mgx-appview-error`,targetName:window.name,data:{errMsg:e.response?.data?.message||e.response?.data?.detail||`Server Error`,stack:JSON.stringify({url:e.response?.config?.url,data:e.response?.data,status:e.response?.status})}},`*`)}catch(e){console.warn(`Failed to notify parent window about API error:`,e)}},r=(r={})=>{let{onUnauthorized:i,...a}=r,o=typeof globalThis<`u`&&`localStorage`in globalThis&&typeof globalThis.localStorage?.getItem==`function`?globalThis.localStorage.getItem(`token`)??void 0:void 0,s={timeout:6e4,paramsSerializer:e=>t.stringify(e,{arrayFormat:`brackets`}),...a,headers:{"Content-Type":`application/json`,"App-Host":globalThis?.window?.location?.origin??``,...o?{Authorization:`Bearer ${o}`}:{},...a.headers}},c=e.create(s);return c.interceptors.request.use(e=>e,e=>Promise.reject(e)),c.interceptors.response.use(e=>e,e=>{let t=e.response?.status;return t===401&&i&&i(),n(e),Promise.reject(e)}),c},i=[`stripe.com`],a=e=>typeof e==`string`?e.startsWith(`_`)||e.startsWith(`$`)||e===`constructor`||e===`toString`||e===`valueOf`||e===`inspect`||e===`toJSON`:!0,o=()=>{let e=window.location?.href??``,t=``;e.startsWith(`/`)?t=e:e&&(t=e.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]+/i,``));let n=new URLSearchParams({from_url:t});window.location.href=`/api/v1/auth/login?${n.toString()}`},s=()=>globalThis?.window?.name?.includes(`devIframe`),c=e=>e?i.some(t=>e.toString().includes(t)):!1,l=e=>{let{requestInstance:t}=e;return{async login(){let e=new URLSearchParams(window.location.search),t=e.get(`token`);return t&&typeof globalThis<`u`&&`localStorage`in globalThis&&(globalThis.localStorage?.setItem(`token`,t),globalThis.localStorage?.setItem(`isLougOutManual`,`false`),console.log(`login success----`,globalThis.localStorage?.getItem(`token`),globalThis.localStorage?.getItem(`isLougOutManual`)),window.location.href=`/`),t},async me(){return t.get(`/api/v1/auth/me`)},async logout(){typeof globalThis<`u`&&`localStorage`in globalThis&&(globalThis.localStorage?.removeItem(`token`),globalThis.localStorage?.setItem(`isLougOutManual`,`true`),console.log(`logout success----`,globalThis.localStorage?.getItem(`token`),globalThis.localStorage?.getItem(`isLougOutManual`)));let e=await t.get(`/api/v1/auth/logout`);return typeof globalThis<`u`&&`window`in globalThis&&(globalThis.window.opener=null),window.location.href=`/`,e},toLogin:o}},u=e=>{let{requestInstance:t,entityName:n}=e,r=`/api/v1/entities/${n}`,i=e=>{if(!e)return;let t={...e};return e.fields&&Array.isArray(e.fields)&&(t.fields=e.fields.join(`,`)),e.query&&typeof e.query==`object`&&(t.query=JSON.stringify(e.query)),t};return{async query(e){let n=i(e);return t.get(r,{params:n})},async queryAll(e){let n=i(e);return t.get(`${r}/all`,{params:n})},async get(e){let{id:n,...a}=e,o=i(a);return t.get(`${r}/${n}`,{params:o})},async create(e){return t.post(r,e.data)},async update(e){return t.put(`${r}/${e.id}`,e.data)},async delete(e){return t.delete(`${r}/${e.id}`)},async deleteBatch(e){return t.delete(`${r}/batch`,{data:{ids:e.ids}})},async createBatch(e){return t.post(`${r}/batch`,e.data)},async updateBatch(e){return t.put(`${r}/batch`,e.data)}}},d=e=>{let{requestInstance:t}=e,n=new Map;return new Proxy({},{get(e,r){if(!a(r))return n.has(r)||n.set(r,u({requestInstance:t,entityName:r})),n.get(r)}})},f=e=>{let{requestInstance:t}=e;return{async invoke(e){let{url:n,method:r=`GET`,data:i,options:a={}}=e;if(typeof window<`u`&&a?.responseType===`stream`){let e;try{typeof globalThis<`u`&&`localStorage`in globalThis&&typeof globalThis.localStorage?.getItem==`function`&&(e=globalThis.localStorage.getItem(`token`)??void 0)}catch{}let t={"Content-Type":`application/json`,"App-Host":globalThis?.window?.location?.origin??``,...e?{Authorization:`Bearer ${e}`}:{},...a.headers||{}},o;i&&[`POST`,`PUT`,`PATCH`].includes(r.toUpperCase())&&(o=JSON.stringify(i));let s=await fetch(n,{method:r.toUpperCase(),headers:t,body:o});return s}let o={method:r.toUpperCase(),url:n,...a};return i&&[`POST`,`PUT`,`PATCH`].includes(o.method)?o.data=i:i&&[`GET`,`DELETE`].includes(o.method)&&(o.params=i),t.request(o)}}},p=e=>{let{requestInstance:t}=e;return new Proxy({},{get(e,n){if(!a(n))return new Proxy({},{get(e,r){if(!a(r))return(e={})=>{let i=`/api/integrations/core/${r}`;n!==`core`&&(i=`/api/integrations/providers/${n}/${r}`);let{payload:a={},option:o={}}=e,s=a instanceof FormData?{...o,headers:{...o.headers,"Content-Type":void 0}}:o;return t.post(i,a,s)}}})}})};let m=null;const h=e=>{if(m)return;let{requestInstance:t}=e,n=async e=>{let n=globalThis?.localStorage?.getItem(`token`);if(n)return;let r=e.token,i=await t.post(`/api/v1/auth/token/exchange`,{platform_token:r});i.status===200&&i.data.token&&(globalThis?.localStorage?.setItem(`token`,i.data.token),window.location.href=`/`)},r=e=>{switch(e.data.type){case`mgx-token-saved`:n(e.data.data);break;default:break}};m={requestInstance:t,handleMessage:r},globalThis?.window?.addEventListener(`message`,r)},g=()=>{let e=(e,t,n,r)=>{if(globalThis?.window===void 0||!globalThis?.window?.top){console.warn(`postMessage: window.top is not available`);return}try{let{targetOrigin:i=`*`,targetName:a=globalThis?.window?.name??``}=n||{},o={type:e,targetName:a,data:t};(r??globalThis?.window?.top)?.postMessage(o,i)}catch(e){console.warn(`Failed to send postMessage:`,e)}};return{postMessage:e}};let _=!1;const v=e=>{h(e);let{postMessage:t}=g(),n=()=>{if(_)return;_=!0;let e=globalThis?.localStorage?.getItem(`token`),n=globalThis?.localStorage?.getItem(`isLougOutManual`)===`true`,r=window.self!==window.top&&window.name?.includes(`devIframe`);console.log(`init----`,e,n,r),!e&&!n&&r&&(console.log(`init----`,`send mgx-token-request`),t(`mgx-token-request`,{domain:globalThis?.window?.location?.href??``},{},globalThis?.window?.opener),t(`mgx-token-request`,{domain:globalThis?.window?.location?.href??``}))};return n(),{createPage(e){let n=e??globalThis?.window?.location?.pathname??``;t(`mgx-create-page`,{path:n})}}},y=()=>{let{postMessage:e}=g(),t=t=>{if(t){if(globalThis?.window===void 0){console.warn(`openUrl: window is not available`);return}if(c(t)&&s()){e(`mgx-open-url`,{url:t.toString()},{},globalThis?.window?.opener);return}globalThis.window.location.href=t.toString()}};return{openUrl:t}},b=(e={})=>{let t=r({baseURL:`/`,...e});console.log(`createClient----`,t);let n=l({requestInstance:t}),i=d({requestInstance:t}),a=f({requestInstance:t}),o=p({requestInstance:t}),s=v({requestInstance:t}),c=y();return{auth:n,entities:i,apiCall:a,integrations:o,frame:s,utils:c}};export{b as createClient};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/types/plugins.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Vite 插件相关类型定义
|
|
7
|
+
*/
|
|
8
|
+
// ==================== vite-plugin-routes 类型 ====================
|
|
9
|
+
interface RouteInfo {
|
|
10
|
+
/** 完整路由路径 */
|
|
11
|
+
path: string;
|
|
12
|
+
/** 是否有 element(即是否为可访问页面) */
|
|
13
|
+
hasElement: boolean;
|
|
14
|
+
/** element 组件名称(如果可识别) */
|
|
15
|
+
elementName?: string;
|
|
16
|
+
/** 是否为通配符路由 */
|
|
17
|
+
isWildcard: boolean;
|
|
18
|
+
/** 是否为 index 路由 */
|
|
19
|
+
isIndex: boolean;
|
|
20
|
+
/** 子路由 */
|
|
21
|
+
children?: RouteInfo[];
|
|
22
|
+
}
|
|
23
|
+
interface RoutesManifest {
|
|
24
|
+
/** 所有路由(树形结构) */
|
|
25
|
+
routeTree: RouteInfo[];
|
|
26
|
+
/** 扁平化的路由列表(只包含有 element 的路由) */
|
|
27
|
+
routes: Array<{
|
|
28
|
+
path: string;
|
|
29
|
+
elementName?: string;
|
|
30
|
+
}>;
|
|
31
|
+
/** 可访问页面总数(排除通配符和纯布局路由) */
|
|
32
|
+
pageCount: number;
|
|
33
|
+
/** 所有路由总数 */
|
|
34
|
+
total: number;
|
|
35
|
+
/** 生成时间戳 */
|
|
36
|
+
generatedAt: string;
|
|
37
|
+
}
|
|
38
|
+
interface PluginRoutesOptions {
|
|
39
|
+
/**
|
|
40
|
+
* 路由文件路径
|
|
41
|
+
* @default 'src/App.tsx'
|
|
42
|
+
*/
|
|
43
|
+
routeFile?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 入口文件路径,用于自动注入
|
|
47
|
+
* @default 'src/main.tsx'
|
|
48
|
+
*/
|
|
49
|
+
entryFile?: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 虚拟模块 ID
|
|
53
|
+
* @default 'virtual:routes-manifest'
|
|
54
|
+
*/
|
|
55
|
+
moduleId?: string;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 是否自动向父级 iframe 发送路由信息
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
notifyParent?: boolean;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 发送给父级的消息类型标识
|
|
65
|
+
* @default 'ROUTES_MANIFEST'
|
|
66
|
+
*/
|
|
67
|
+
messageType?: string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 要排除的路由路径模式
|
|
71
|
+
* @default ['*']
|
|
72
|
+
*/
|
|
73
|
+
excludePaths?: string[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ==================== vite-plugin-404 类型 ====================
|
|
77
|
+
|
|
78
|
+
// vite-plugin-404 目前不需要配置选项
|
|
79
|
+
|
|
80
|
+
// ==================== atomsPlugins 容器类型 ====================
|
|
81
|
+
|
|
82
|
+
interface Plugin404Options {
|
|
83
|
+
/**
|
|
84
|
+
* 是否启用 404 插件
|
|
85
|
+
* @default true
|
|
86
|
+
*/
|
|
87
|
+
enable?: boolean;
|
|
88
|
+
}
|
|
89
|
+
interface AtomsPluginRoutesOptions extends PluginRoutesOptions {
|
|
90
|
+
/**
|
|
91
|
+
* 是否启用路由扫描插件
|
|
92
|
+
* @default true
|
|
93
|
+
*/
|
|
94
|
+
enable?: boolean;
|
|
95
|
+
}
|
|
96
|
+
interface AtomsPluginOptions {
|
|
97
|
+
/**
|
|
98
|
+
* 404 页面插件配置
|
|
99
|
+
*/
|
|
100
|
+
'404'?: Plugin404Options;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 路由扫描插件配置
|
|
104
|
+
*/
|
|
105
|
+
routes?: AtomsPluginRoutesOptions;
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/plugins/vite-plugin-atoms.d.ts
|
|
109
|
+
/**
|
|
110
|
+
* Atoms Vite 插件容器
|
|
111
|
+
*
|
|
112
|
+
* 整合了 404 页面插件和路由扫描插件
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* // vite.config.ts
|
|
117
|
+
* import { atoms } from '@metagptx/web-sdk/plugins';
|
|
118
|
+
*
|
|
119
|
+
* export default defineConfig({
|
|
120
|
+
* plugins: [
|
|
121
|
+
* atoms(),
|
|
122
|
+
* ],
|
|
123
|
+
* });
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* // 自定义配置
|
|
129
|
+
* atomsPlugins({
|
|
130
|
+
* '404': { enable: true },
|
|
131
|
+
* routes: {
|
|
132
|
+
* enable: true,
|
|
133
|
+
* routeFile: 'src/App.tsx',
|
|
134
|
+
* notifyParent: true,
|
|
135
|
+
* },
|
|
136
|
+
* })
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
declare function atoms(options?: AtomsPluginOptions): Plugin[];
|
|
140
|
+
//#endregion
|
|
141
|
+
export { type AtomsPluginOptions, type AtomsPluginRoutesOptions, type Plugin404Options, type PluginRoutesOptions, type RouteInfo, type RoutesManifest, atoms };
|
package/dist/plugins.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import e from"node:fs";import t from"node:path";import*as n from"@babel/parser";import r from"@babel/traverse";import*as i from"@babel/types";function a(){let e=`virtual:404-page`,t=`import { Button } from '@/components/ui/button';
|
|
2
|
+
import { createClient } from '@metagptx/web-sdk';
|
|
3
|
+
|
|
4
|
+
// Create client instance
|
|
5
|
+
const client = createClient();
|
|
6
|
+
|
|
7
|
+
export default function NotFoundPage() {
|
|
8
|
+
const isInMGXIframe =
|
|
9
|
+
window.self !== window.top && window.name?.includes('devIframe');
|
|
10
|
+
return (
|
|
11
|
+
<div className="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-gray-50 to-blue-50 p-6 text-center">
|
|
12
|
+
<div className="space-y-6 max-w-md">
|
|
13
|
+
<div className="space-y-3">
|
|
14
|
+
<h1 className="text-5xl font-bold text-primary">404</h1>
|
|
15
|
+
<h2 className="text-2xl font-semibold text-gray-800">
|
|
16
|
+
Page Not Found
|
|
17
|
+
</h2>
|
|
18
|
+
<p className="text-muted-foreground">
|
|
19
|
+
The page you're looking for doesn't exist or may have been moved.
|
|
20
|
+
</p>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div className="flex flex-col sm:flex-row gap-3 justify-center">
|
|
24
|
+
<Button asChild>
|
|
25
|
+
<a href="/">Return Home</a>
|
|
26
|
+
</Button>
|
|
27
|
+
{isInMGXIframe ? (
|
|
28
|
+
<Button variant="outline" onClick={() => client.frame.createPage()}>
|
|
29
|
+
Create page
|
|
30
|
+
</Button>
|
|
31
|
+
) : (
|
|
32
|
+
<Button
|
|
33
|
+
variant="outline"
|
|
34
|
+
onClick={() => (window.location.href = 'https://mgx.dev')}
|
|
35
|
+
>
|
|
36
|
+
Go to MGX
|
|
37
|
+
</Button>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
`;return{name:`vite-plugin-404`,enforce:`pre`,resolveId(t){return t===e||t.startsWith(e)?`\0${e}.tsx`:null},load(n){return n===`\0${e}.tsx`||n.includes(`virtual:404-page`)?t:null},transform(e,t){if(!t.includes(`App.tsx`)||!t.endsWith(`.tsx`))return null;let n=e.includes(`virtual:404-page`)||e.includes(`NotFound404`)||e.includes(`NotFoundPage`)||/path\s*=\s*["']\*["']/.test(e);if(n)return null;let r=!1,i=e.includes(`virtual:404-page`);if(!i){let t=/(import\s+AuthError\s+from\s+['"][^'"]+AuthError[^'"]*['"];)/;if(t.test(e))e=e.replace(t,`$1
|
|
45
|
+
import NotFoundPage from 'virtual:404-page';`),r=!0;else if(/\/\/\s*MODULE_IMPORTS_END/.test(e))e=e.replace(/(\/\/\s*MODULE_IMPORTS_END)/,`$1
|
|
46
|
+
import NotFoundPage from 'virtual:404-page';`),r=!0;else if(/\/\/\s*MODULE_IMPORTS_START/.test(e))e=e.replace(/(\/\/\s*MODULE_IMPORTS_START)/,`import NotFoundPage from 'virtual:404-page';
|
|
47
|
+
$1`),r=!0;else{let t=/(^import\s[^;]+;)/gm,n=[...e.matchAll(t)];if(n.length>0){let t=n[n.length-1],i=t.index+t[0].length,a=e.substring(0,i),o=e.substring(i);e=`${a}\nimport NotFoundPage from 'virtual:404-page';${o}`,r=!0}}}let a=/path\s*=\s*["']\*["']/.test(e);if(!a){if(/\/\/\s*MODULE_ROUTES_END/.test(e)){let t=e.match(/(\s*)\/\/\s*MODULE_ROUTES_END/);if(t){let n=t[1];e=e.replace(/(\s*)\/\/\s*MODULE_ROUTES_END/,`${n}<Route path="*" element={<NotFoundPage />} />\n$1// MODULE_ROUTES_END`),r=!0}}else if(/<\/Routes>/.test(e)){let t=e.match(/(\s*)<\/Routes>/);if(t){let n=t[1],i=e.match(/(\s+)<Route\s+path=/),a=i?i[1]:`${n} `;e=e.replace(/(\s*)<\/Routes>/,`${a}<Route path="*" element={<NotFoundPage />} />\n$1</Routes>`),r=!0}}else if(/<Route\s+path=/.test(e)){let t=/<Route\s[^>]*\/>|<Route\s[^>]*>[\s\S]*?<\/Route>/g,n=[...e.matchAll(t)];if(n.length>0){let t=n[n.length-1],i=t.index+t[0].length,a=e.substring(0,i),o=e.substring(i),s=a.split(`
|
|
48
|
+
`),c=s[s.length-1],l=c.match(/^(\s*)/)?.[1]||``;e=`${a}\n${l}<Route path="*" element={<NotFoundPage />} />${o}`,r=!0}}}return r?{code:e,map:null}:null}}}const o=r.default||r;function s(r={}){let{routeFile:a=`src/App.tsx`,entryFile:s=`src/main.tsx`,moduleId:c=`virtual:routes-manifest`,notifyParent:l=!0,messageType:u=`ROUTES_MANIFEST`,excludePaths:d=[`*`]}=r,f=`\0${c}`,p=process.cwd();function m(e,t){for(let n of e)if(i.isJSXAttribute(n)&&i.isJSXIdentifier(n.name,{name:t})&&i.isStringLiteral(n.value))return n.value.value}function h(e){for(let t of e)if(i.isJSXAttribute(t)&&i.isJSXIdentifier(t.name,{name:`element`})){let e=t.value;if(i.isJSXExpressionContainer(e)){let t=e.expression;if(i.isJSXElement(t)){let e=t.openingElement;if(i.isJSXIdentifier(e.name))return e.name.name}}}}function g(e){return e.some(e=>i.isJSXAttribute(e)&&i.isJSXIdentifier(e.name,{name:`element`}))}function _(e){return e.some(e=>i.isJSXAttribute(e)&&i.isJSXIdentifier(e.name,{name:`index`}))}function v(e,t){let n=[];for(let r of e)if(i.isJSXElement(r)){let e=r.openingElement;if(i.isJSXIdentifier(e.name,{name:`Route`})){let e=y(r,t);e&&n.push(e)}}return n}function y(e,t){let n=e.openingElement.attributes,r=m(n,`path`),i=_(n),a=g(n),o=h(n),s;if(i)s=t||`/`;else if(r===void 0)return null;else s=r.startsWith(`/`)?r:t===`/`?`/${r}`:`${t}/${r}`;s=s.replace(/\/+/g,`/`),s!==`/`&&s.endsWith(`/`)&&(s=s.slice(0,-1));let c={path:s,hasElement:a,elementName:o,isWildcard:r===`*`,isIndex:i};if(e.children&&e.children.length>0){let t=v(e.children,s);t.length>0&&(c.children=t)}return c}function b(e,t=[]){for(let n of e)n.hasElement&&t.push({path:n.path,elementName:n.elementName}),n.children&&b(n.children,t);return t}function x(e){let t=0;for(let n of e)t++,n.children&&(t+=x(n.children));return t}function S(t){let r={routeTree:[],routes:[],pageCount:0,total:0,generatedAt:new Date().toISOString()};if(!e.existsSync(t))return console.warn(`[routes-scanner] Route file not found: ${t}`),r;let a=e.readFileSync(t,`utf-8`),s;try{s=n.parse(a,{sourceType:`module`,plugins:[`jsx`,`typescript`]})}catch(e){return console.error(`[routes-scanner] Failed to parse route file:`,e),r}let c=[];o(s,{JSXElement(e){let t=e.node.openingElement;if(i.isJSXIdentifier(t.name,{name:`Routes`})){let t=e.node.children;for(let e of t)if(i.isJSXElement(e)){let t=e.openingElement;if(i.isJSXIdentifier(t.name,{name:`Route`})){let t=y(e,``);t&&c.push(t)}}e.stop()}}});let l=b(c),u=l.filter(e=>!d.some(t=>e.path===t||e.path.match(RegExp(`^${t.replace(`*`,`.*`)}$`))));return{routeTree:c,routes:l,pageCount:u.length,total:x(c),generatedAt:new Date().toISOString()}}return{name:`vite-plugin-routes-scanner`,configResolved(e){p=e.root},resolveId(e){if(e===c)return f},load(e){if(e===f){let e=t.resolve(p,a),n=S(e),r=l?`
|
|
49
|
+
// 向父级 iframe 发送路由信息
|
|
50
|
+
function notifyParentWindow() {
|
|
51
|
+
console.log('[routes-scanner] notifyParentWindow', routesManifest);
|
|
52
|
+
if (typeof window !== 'undefined' && window.parent && window.parent !== window) {
|
|
53
|
+
try {
|
|
54
|
+
window.parent.postMessage({
|
|
55
|
+
type: '${u}',
|
|
56
|
+
payload: routesManifest,
|
|
57
|
+
}, '*');
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.warn('[routes-scanner] Failed to notify parent window:', e);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 页面加载完成后发送
|
|
65
|
+
if (typeof window !== 'undefined') {
|
|
66
|
+
if (document.readyState === 'complete') {
|
|
67
|
+
notifyParentWindow();
|
|
68
|
+
} else {
|
|
69
|
+
window.addEventListener('load', notifyParentWindow);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { notifyParentWindow };
|
|
74
|
+
`:``;return`
|
|
75
|
+
export const routesManifest = ${JSON.stringify(n,null,2)};
|
|
76
|
+
export const routeTree = routesManifest.routeTree;
|
|
77
|
+
export const routes = routesManifest.routes;
|
|
78
|
+
export const pageCount = routesManifest.pageCount;
|
|
79
|
+
export const total = routesManifest.total;
|
|
80
|
+
${r}
|
|
81
|
+
export default routesManifest;
|
|
82
|
+
`}},transform(e,n){let r=n.replace(/\\/g,`/`),i=t.resolve(p,s).replace(/\\/g,`/`);if(r===i&&l){let t=`import "${c}";\n`;return e.includes(c)?null:{code:t+e,map:null}}return null},configureServer(e){let n=t.resolve(p,a);e.watcher.add(n),e.watcher.on(`change`,t=>{if(t===n){let t=e.moduleGraph.getModuleById(f);t&&(e.moduleGraph.invalidateModule(t),e.ws.send({type:`full-reload`}))}})}}}function c(e={}){let{404:t={},routes:n={}}=e,{enable:r=!0}=t,{enable:i=!0,...o}=n,c=[];return r&&c.push(a()),i&&c.push(s(o)),c}export{c as atoms};
|
package/package.json
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metagptx/web-sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.52-beta.
|
|
4
|
+
"version": "0.0.52-beta.13",
|
|
5
5
|
"packageManager": "pnpm@10.15.0+sha512.486ebc259d3e999a4e8691ce03b5cac4a71cbeca39372a9b762cb500cfdf0873e2cb16abe3d951b1ee2cf012503f027b98b6584e4df22524e0c7450d9ec7aa7b",
|
|
6
6
|
"description": "TypeScript SDK for interacting with FuncSea API",
|
|
7
7
|
"author": "MetaGPTX",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"exports": {
|
|
10
|
-
".":
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./plugins": {
|
|
16
|
+
"types": "./dist/plugins.d.ts",
|
|
17
|
+
"import": "./dist/plugins.js",
|
|
18
|
+
"default": "./dist/plugins.js"
|
|
19
|
+
},
|
|
11
20
|
"./package.json": "./package.json"
|
|
12
21
|
},
|
|
13
22
|
"main": "./dist/index.js",
|
|
@@ -31,6 +40,26 @@
|
|
|
31
40
|
"precommit": "npm run typecheck && lint-staged && npm run test:coverage",
|
|
32
41
|
"commit-msg": "echo commit-msg"
|
|
33
42
|
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@babel/parser": "^7.0.0",
|
|
45
|
+
"@babel/traverse": "^7.0.0",
|
|
46
|
+
"@babel/types": "^7.0.0",
|
|
47
|
+
"vite": "^4.0.0 || ^5.0.0 || ^6.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"@babel/parser": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"@babel/traverse": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"@babel/types": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"vite": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
34
63
|
"dependencies": {
|
|
35
64
|
"@types/qs": "^6.14.0",
|
|
36
65
|
"axios": "^1.12.2",
|
|
@@ -38,8 +67,7 @@
|
|
|
38
67
|
"eslint-plugin-prettier": "^5.5.4",
|
|
39
68
|
"lint-staged": "^16.2.3",
|
|
40
69
|
"qs": "^6.14.0",
|
|
41
|
-
"simple-git-hooks": "^2.13.1"
|
|
42
|
-
"vite": "^5.4.1"
|
|
70
|
+
"simple-git-hooks": "^2.13.1"
|
|
43
71
|
},
|
|
44
72
|
"devDependencies": {
|
|
45
73
|
"@antfu/eslint-config": "^5.4.1",
|
|
@@ -55,6 +83,7 @@
|
|
|
55
83
|
"prettier": "^3.6.2",
|
|
56
84
|
"tsdown": "^0.11.9",
|
|
57
85
|
"typescript": "^5.8.3",
|
|
86
|
+
"vite": "^5.4.1",
|
|
58
87
|
"vitest": "^3.1.3"
|
|
59
88
|
},
|
|
60
89
|
"simple-git-hooks": {
|