@lark-apaas/client-toolkit 1.2.16 → 1.2.17-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/lib/components/AppContainer/IframeBridge.d.ts +1 -0
  2. package/lib/components/AppContainer/IframeBridge.js +20 -1
  3. package/lib/components/AppContainer/api-proxy/core.js +1 -2
  4. package/lib/components/AppContainer/index.d.ts +2 -5
  5. package/lib/components/AppContainer/index.js +46 -9
  6. package/lib/components/AppContainer/utils/childApi.js +0 -1
  7. package/lib/components/AppContainer/utils/listenHot.d.ts +1 -0
  8. package/lib/components/AppContainer/utils/listenHot.js +57 -0
  9. package/lib/components/AppContainer/utils/tea.js +1 -1
  10. package/lib/components/ErrorRender/index.js +11 -5
  11. package/lib/components/User/UserSelect.js +13 -1
  12. package/lib/hooks/index.d.ts +0 -1
  13. package/lib/hooks/index.js +0 -1
  14. package/lib/index.js +1 -5
  15. package/lib/integrations/dataloom.js +2 -4
  16. package/lib/logger/batch-logger.js +2 -3
  17. package/lib/logger/intercept-global-error.js +14 -16
  18. package/lib/logger/log-types.d.ts +4 -4
  19. package/lib/logger/log-types.js +1 -1
  20. package/lib/logger/selected-logs.js +2 -1
  21. package/lib/theme-layer.css +1 -2
  22. package/lib/utils/axiosConfig.js +3 -25
  23. package/lib/utils/getParentOrigin.js +2 -12
  24. package/lib/utils/module-hot.d.ts +5 -9
  25. package/lib/utils/module-hot.js +10 -9
  26. package/lib/utils/requestManager.js +3 -1
  27. package/package.json +10 -4
  28. package/lib/apis/components/ActiveLink.d.ts +0 -26
  29. package/lib/apis/components/ActiveLink.js +0 -66
  30. package/lib/apis/hooks/useScrollReveal.d.ts +0 -1
  31. package/lib/apis/hooks/useScrollReveal.js +0 -1
  32. package/lib/apis/utils/getEnv.d.ts +0 -1
  33. package/lib/apis/utils/getEnv.js +0 -2
  34. package/lib/apis/utils/scopedStorage.d.ts +0 -1
  35. package/lib/apis/utils/scopedStorage.js +0 -2
  36. package/lib/auth.d.ts +0 -1
  37. package/lib/auth.js +0 -2
  38. package/lib/components/ui/toast.d.ts +0 -2
  39. package/lib/components/ui/toast.js +0 -53
  40. package/lib/hooks/useScrollReveal.d.ts +0 -61
  41. package/lib/hooks/useScrollReveal.js +0 -37
  42. package/lib/runtime/axios.d.ts +0 -5
  43. package/lib/runtime/axios.js +0 -2
  44. package/lib/runtime/dayjs.d.ts +0 -5
  45. package/lib/runtime/dayjs.js +0 -2
  46. package/lib/runtime/iframe-bridge.d.ts +0 -11
  47. package/lib/runtime/iframe-bridge.js +0 -29
  48. package/lib/runtime/index.d.ts +0 -23
  49. package/lib/runtime/index.js +0 -16
  50. package/lib/runtime/observable.d.ts +0 -5
  51. package/lib/runtime/observable.js +0 -2
  52. package/lib/runtime/server-log.d.ts +0 -5
  53. package/lib/runtime/server-log.js +0 -41
  54. package/lib/runtime/styles.d.ts +0 -5
  55. package/lib/runtime/styles.js +0 -1
  56. package/lib/utils/hmr-api.d.ts +0 -39
  57. package/lib/utils/hmr-api.js +0 -36
  58. package/lib/utils/scopedStorage.d.ts +0 -5
  59. package/lib/utils/scopedStorage.js +0 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-toolkit",
3
- "version": "1.2.16",
3
+ "version": "1.2.17-alpha.1",
4
4
  "types": "./lib/index.d.ts",
5
5
  "main": "./lib/index.js",
6
6
  "files": [
@@ -71,6 +71,11 @@
71
71
  "require": "./lib/apis/utils/*.js",
72
72
  "types": "./lib/apis/utils/*.d.ts"
73
73
  },
74
+ "./aily-chat": {
75
+ "import": "./lib/apis/aily-chat.js",
76
+ "require": "./lib/apis/aily-chat.js",
77
+ "types": "./lib/apis/aily-chat.d.ts"
78
+ },
74
79
  "./auth": {
75
80
  "import": "./lib/auth.js",
76
81
  "require": "./lib/auth.js",
@@ -94,10 +99,11 @@
94
99
  "@ant-design/colors": "^7.2.1",
95
100
  "@ant-design/cssinjs": "^1.24.0",
96
101
  "@data-loom/js": "0.4.7",
102
+ "@lark-apaas/aily-web-sdk": ">=0.0.1",
97
103
  "@lark-apaas/auth-sdk": "^0.1.0",
98
104
  "@lark-apaas/client-capability": "^0.1.4",
99
- "@lark-apaas/miaoda-inspector": "^1.0.15",
100
- "@lark-apaas/observable-web": "^1.0.1",
105
+ "@lark-apaas/miaoda-inspector": "^1.0.16",
106
+ "@lark-apaas/observable-web": "^1.0.2-alpha.2",
101
107
  "@radix-ui/react-avatar": "^1.1.10",
102
108
  "@radix-ui/react-popover": "^1.1.15",
103
109
  "@radix-ui/react-slot": "^1.2.3",
@@ -168,4 +174,4 @@
168
174
  "react-router-dom": ">=6.26.2",
169
175
  "styled-jsx": ">=5.0.0"
170
176
  }
171
- }
177
+ }
@@ -1,26 +0,0 @@
1
- import React from 'react';
2
- import { type NavLinkProps } from 'react-router-dom';
3
- export interface ActiveLinkProps extends Omit<NavLinkProps, 'to'> {
4
- to: string;
5
- }
6
- /**
7
- * ActiveLink 组件
8
- *
9
- * 替换 react-router-dom 的 NavLink,扩展支持 hash 路由跳转和激活态功能
10
- *
11
- * @example
12
- * // 普通路由跳转
13
- * <ActiveLink to="/dashboard">Dashboard</ActiveLink>
14
- *
15
- * // hash 路由跳转
16
- * <ActiveLink to="#section1">Section 1</ActiveLink>
17
- *
18
- * // 使用函数式 className 显示激活态
19
- * <ActiveLink
20
- * to="#features"
21
- * className={({isActive}) => isActive ? 'active' : ''}
22
- * >
23
- * Features
24
- * </ActiveLink>
25
- */
26
- export declare const ActiveLink: React.ForwardRefExoticComponent<ActiveLinkProps & React.RefAttributes<HTMLAnchorElement>>;
@@ -1,66 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { forwardRef, useEffect, useState } from "react";
3
- import { NavLink } from "react-router-dom";
4
- const ActiveLink = /*#__PURE__*/ forwardRef(({ to, onClick, className, style, children, ...rest }, ref)=>{
5
- const [currentHash, setCurrentHash] = useState(()=>'undefined' != typeof window ? window.location.hash : '');
6
- const isHashRoute = 'string' == typeof to && to.startsWith('#');
7
- useEffect(()=>{
8
- if (!isHashRoute) return;
9
- const handleHashChange = ()=>{
10
- setCurrentHash(window.location.hash);
11
- };
12
- window.addEventListener('hashchange', handleHashChange);
13
- return ()=>window.removeEventListener('hashchange', handleHashChange);
14
- }, [
15
- isHashRoute
16
- ]);
17
- const isActive = isHashRoute && currentHash === to;
18
- if (!isHashRoute) return /*#__PURE__*/ jsx(NavLink, {
19
- ref: ref,
20
- to: to,
21
- onClick: onClick,
22
- className: className,
23
- style: style,
24
- ...rest,
25
- children: children
26
- });
27
- const handleHashClick = (e)=>{
28
- onClick?.(e);
29
- if (e.defaultPrevented) return;
30
- e.preventDefault();
31
- const targetId = to.slice(1);
32
- const targetElement = document.getElementById(targetId);
33
- history.pushState(null, '', to);
34
- setCurrentHash(to);
35
- window.dispatchEvent(new Event('hashchange'));
36
- if (targetElement && 'function' == typeof targetElement.scrollIntoView) targetElement.scrollIntoView({
37
- behavior: 'smooth'
38
- });
39
- };
40
- const computedClassName = 'function' == typeof className ? className({
41
- isActive,
42
- isPending: false,
43
- isTransitioning: false
44
- }) : className;
45
- const computedStyle = 'function' == typeof style ? style({
46
- isActive,
47
- isPending: false,
48
- isTransitioning: false
49
- }) : style;
50
- const computedChildren = 'function' == typeof children ? children({
51
- isActive,
52
- isPending: false,
53
- isTransitioning: false
54
- }) : children;
55
- return /*#__PURE__*/ jsx("a", {
56
- ref: ref,
57
- href: to,
58
- onClick: handleHashClick,
59
- className: computedClassName,
60
- style: computedStyle,
61
- ...rest,
62
- children: computedChildren
63
- });
64
- });
65
- ActiveLink.displayName = 'ActiveLink';
66
- export { ActiveLink };
@@ -1 +0,0 @@
1
- export * from '../../hooks/useScrollReveal';
@@ -1 +0,0 @@
1
- export * from "../../hooks/useScrollReveal.js";
@@ -1 +0,0 @@
1
- export { getEnv } from '../../utils/getParentOrigin';
@@ -1,2 +0,0 @@
1
- import { getEnv } from "../../utils/getParentOrigin.js";
2
- export { getEnv };
@@ -1 +0,0 @@
1
- export { scopedStorage } from '../../utils/scopedStorage';
@@ -1,2 +0,0 @@
1
- import { scopedStorage } from "../../utils/scopedStorage.js";
2
- export { scopedStorage };
package/lib/auth.d.ts DELETED
@@ -1 +0,0 @@
1
- export { CanRole, AbilityContext, ROLE_SUBJECT } from '@lark-apaas/auth-sdk';
package/lib/auth.js DELETED
@@ -1,2 +0,0 @@
1
- import { AbilityContext, CanRole, ROLE_SUBJECT } from "@lark-apaas/auth-sdk";
2
- export { AbilityContext, CanRole, ROLE_SUBJECT };
@@ -1,2 +0,0 @@
1
- /** 显示 toast 提示(兼容 PC/移动端) */
2
- export declare function showToast(message: string, duration?: number): Promise<void>;
@@ -1,53 +0,0 @@
1
- function showToast(message, duration = 3000) {
2
- return new Promise((resolve)=>{
3
- const toast = document.createElement('div');
4
- const iconSvg = `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
5
- <path fill-rule="evenodd" clip-rule="evenodd" d="M8 1.333a6.667 6.667 0 1 1 0 13.334A6.667 6.667 0 0 1 8 1.333ZM8 10a.667.667 0 1 0 0 1.333A.667.667 0 0 0 8 10Zm0-5.333a.667.667 0 0 0-.667.666v3.334a.667.667 0 0 0 1.334 0V5.333A.667.667 0 0 0 8 4.667Z" fill="#ff811a"/>
6
- </svg>`;
7
- const iconWrapper = document.createElement('span');
8
- iconWrapper.innerHTML = iconSvg;
9
- Object.assign(iconWrapper.style, {
10
- display: 'flex',
11
- alignItems: 'center',
12
- marginRight: '8px',
13
- flexShrink: '0'
14
- });
15
- const textWrapper = document.createElement('span');
16
- textWrapper.textContent = message;
17
- toast.appendChild(iconWrapper);
18
- toast.appendChild(textWrapper);
19
- Object.assign(toast.style, {
20
- position: 'fixed',
21
- top: '32px',
22
- left: '50%',
23
- transform: 'translate(-50%, -50%)',
24
- display: 'flex',
25
- alignItems: 'center',
26
- padding: '12px 16px',
27
- backgroundColor: '#fff',
28
- color: '#1f2329',
29
- border: '1px solid #dee0e3',
30
- borderRadius: '6px',
31
- fontSize: '14px',
32
- lineHeight: '1.5',
33
- zIndex: '99999',
34
- maxWidth: '80vw',
35
- wordBreak: 'break-word',
36
- boxShadow: '0 4px 8px rgba(0, 0, 0, 0.03), 0 3px 6px rgba(0, 0, 0, 0.05), 0 6px 18px rgba(0, 0, 0, 0.03)',
37
- opacity: '0',
38
- transition: 'opacity 0.3s ease'
39
- });
40
- document.body.appendChild(toast);
41
- requestAnimationFrame(()=>{
42
- toast.style.opacity = '1';
43
- });
44
- setTimeout(()=>{
45
- toast.style.opacity = '0';
46
- setTimeout(()=>{
47
- document.body.removeChild(toast);
48
- resolve();
49
- }, 300);
50
- }, duration);
51
- });
52
- }
53
- export { showToast };
@@ -1,61 +0,0 @@
1
- import { RefObject } from 'react';
2
- /**
3
- * Options for useScrollReveal hook
4
- */
5
- export interface UseScrollRevealOptions<T extends HTMLElement = HTMLElement> {
6
- /** Ref to the container element to scope the query (default: document.body) */
7
- containerRef?: RefObject<T | null>;
8
- /** IntersectionObserver threshold - element visibility percentage to trigger (default: 0.1) */
9
- threshold?: number;
10
- /** IntersectionObserver rootMargin - margin around root (default: '0px 0px -50px 0px') */
11
- rootMargin?: string;
12
- /** CSS class to add when element becomes visible (default: 'visible') */
13
- visibleClass?: string;
14
- /** CSS selector for elements to observe (default: '.scroll-reveal') */
15
- selector?: string;
16
- }
17
- /**
18
- * Hook to enable scroll reveal animations using IntersectionObserver.
19
- *
20
- * Observes elements with the specified selector and adds a visibility class
21
- * when they enter the viewport.
22
- *
23
- * @param options - Configuration options
24
- *
25
- * @example
26
- * ```tsx
27
- * // Usage without parameters (queries entire document.body)
28
- * import { useScrollReveal } from '@lark-apaas/client-toolkit/hooks/useScrollReveal';
29
- *
30
- * function MyComponent() {
31
- * useScrollReveal();
32
- *
33
- * return <div className="scroll-reveal">I will fade in on scroll!</div>;
34
- * }
35
- * ```
36
- *
37
- * @example
38
- * ```tsx
39
- * // Usage with container ref
40
- * import { useRef } from 'react';
41
- * import { useScrollReveal } from '@lark-apaas/client-toolkit/hooks/useScrollReveal';
42
- *
43
- * function MyComponent() {
44
- * const containerRef = useRef<HTMLDivElement>(null);
45
- * useScrollReveal({ containerRef });
46
- *
47
- * return (
48
- * <div ref={containerRef}>
49
- * <div className="scroll-reveal">I will fade in on scroll!</div>
50
- * </div>
51
- * );
52
- * }
53
- * ```
54
- *
55
- * @example
56
- * ```tsx
57
- * // Usage with custom options
58
- * useScrollReveal({ threshold: 0.2, visibleClass: 'animate-in' });
59
- * ```
60
- */
61
- export declare function useScrollReveal<T extends HTMLElement = HTMLElement>(options?: UseScrollRevealOptions<T>): void;
@@ -1,37 +0,0 @@
1
- import { useEffect } from "react";
2
- const DEFAULT_OPTIONS = {
3
- threshold: 0.1,
4
- rootMargin: '0px 0px -50px 0px',
5
- visibleClass: 'visible',
6
- selector: '.scroll-reveal'
7
- };
8
- function useScrollReveal(options) {
9
- const { containerRef, threshold, rootMargin, visibleClass, selector } = {
10
- ...DEFAULT_OPTIONS,
11
- ...options
12
- };
13
- useEffect(()=>{
14
- const container = containerRef?.current ?? document.body;
15
- if (!container) return;
16
- const observer = new IntersectionObserver((entries)=>{
17
- entries.forEach((entry)=>{
18
- if (entry.isIntersecting) entry.target.classList.add(visibleClass);
19
- });
20
- }, {
21
- threshold,
22
- rootMargin
23
- });
24
- const elements = container.querySelectorAll(selector);
25
- elements.forEach((el)=>observer.observe(el));
26
- return ()=>{
27
- observer.disconnect();
28
- };
29
- }, [
30
- containerRef,
31
- threshold,
32
- rootMargin,
33
- visibleClass,
34
- selector
35
- ]);
36
- }
37
- export { useScrollReveal };
@@ -1,5 +0,0 @@
1
- /**
2
- * Axios 配置初始化
3
- * 从原有的 axiosConfig.ts 迁移
4
- */
5
- export { initAxiosConfig } from '../utils/axiosConfig';
@@ -1,2 +0,0 @@
1
- import { initAxiosConfig } from "../utils/axiosConfig.js";
2
- export { initAxiosConfig };
@@ -1,5 +0,0 @@
1
- /**
2
- * Dayjs 插件注册
3
- * 从原有的 dayjsPlugins.ts 迁移
4
- */
5
- export { registerDayjsPlugins } from '../components/AppContainer/dayjsPlugins';
@@ -1,2 +0,0 @@
1
- import { registerDayjsPlugins } from "../components/AppContainer/dayjsPlugins.js";
2
- export { registerDayjsPlugins };
@@ -1,11 +0,0 @@
1
- /**
2
- * Iframe Bridge Runtime
3
- *
4
- * 开发环境下的 iframe 通信初始化:
5
- * - connectParent - 通过 penpal 连接父页面,建立双向通信
6
- */
7
- /**
8
- * 初始化 iframe bridge(仅开发环境)
9
- * - 连接父页面
10
- */
11
- export declare function initIframeBridge(): void;
@@ -1,29 +0,0 @@
1
- import { connectToParent } from "penpal";
2
- import { resolveParentOrigin, submitPostMessage } from "../utils/postMessage.js";
3
- import { batchLogInfo } from "../logger/batch-logger.js";
4
- import { childApi } from "../components/AppContainer/utils/childApi.js";
5
- async function connectParent() {
6
- submitPostMessage({
7
- type: 'PreviewReady',
8
- data: {}
9
- });
10
- batchLogInfo('info', JSON.stringify({
11
- type: 'PreviewReady',
12
- timestamp: Date.now(),
13
- url: window.location.href
14
- }));
15
- const parentOrigin = resolveParentOrigin();
16
- if (!parentOrigin) return;
17
- const connection = connectToParent({
18
- parentOrigin,
19
- methods: {
20
- ...childApi
21
- }
22
- });
23
- await connection.promise;
24
- }
25
- function initIframeBridge() {
26
- if (window.parent === window) return;
27
- connectParent();
28
- }
29
- export { initIframeBridge };
@@ -1,23 +0,0 @@
1
- /**
2
- * Client Toolkit Runtime
3
- *
4
- * 全局初始化逻辑,通过 rspack-plugin 自动注入到用户入口之前
5
- * 无论用户是否使用 AppContainer,这些基础能力始终可用
6
- *
7
- * 执行顺序:
8
- * 1. 全局样式
9
- * 2. Dayjs 插件注册
10
- * 3. Axios 配置
11
- * 4. 可观测初始化
12
- * 5. Server Log SSE (开发环境)
13
- *
14
- * 兼容性说明:
15
- * - 使用 __FULLSTACK_RUNTIME_INITIALIZED__ 标志位防止重复初始化
16
- * - 旧版 AppContainer 和新版 runtime 可以共存
17
- */
18
- import './styles';
19
- declare global {
20
- interface Window {
21
- __FULLSTACK_RUNTIME_INITIALIZED__?: boolean;
22
- }
23
- }
@@ -1,16 +0,0 @@
1
- import "./styles.js";
2
- import { registerDayjsPlugins } from "./dayjs.js";
3
- import { initAxiosConfig } from "./axios.js";
4
- import { initObservable } from "./observable.js";
5
- import { initServerLog } from "./server-log.js";
6
- import { initIframeBridge } from "./iframe-bridge.js";
7
- if (!window.__FULLSTACK_RUNTIME_INITIALIZED__) {
8
- window.__FULLSTACK_RUNTIME_INITIALIZED__ = true;
9
- registerDayjsPlugins();
10
- initAxiosConfig();
11
- initObservable();
12
- if ('production' !== process.env.NODE_ENV) {
13
- initServerLog();
14
- initIframeBridge();
15
- }
16
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * 可观测初始化
3
- * 从原有的 observable.ts 迁移
4
- */
5
- export { initObservable } from '../components/AppContainer/utils/observable';
@@ -1,2 +0,0 @@
1
- import { initObservable } from "../components/AppContainer/utils/observable.js";
2
- export { initObservable };
@@ -1,5 +0,0 @@
1
- /**
2
- * 初始化 Server Log SSE 客户端
3
- * 仅在开发环境且在 iframe 中时启用
4
- */
5
- export declare function initServerLog(): void;
@@ -1,41 +0,0 @@
1
- import { ServerLogSSEClient } from "../server-log/index.js";
2
- let client = null;
3
- function initServerLog() {
4
- if (window.parent === window) return;
5
- try {
6
- const backendUrl = window.location.origin;
7
- client = new ServerLogSSEClient({
8
- serverUrl: backendUrl,
9
- sseEndpoint: '/dev/logs/server-logs/stream',
10
- debug: true
11
- });
12
- client.start();
13
- console.log('[Runtime] Server log SSE client started');
14
- document.addEventListener('visibilitychange', handleVisibilityChange);
15
- window.addEventListener('beforeunload', cleanup);
16
- window.addEventListener('unload', cleanup);
17
- } catch (error) {
18
- console.error('[Runtime] Failed to start server log SSE client:', error);
19
- }
20
- }
21
- function handleVisibilityChange() {
22
- if (!client) return;
23
- if (document.hidden) {
24
- client.pause();
25
- console.log('[Runtime] Tab hidden, SSE paused');
26
- } else {
27
- client.resume();
28
- console.log('[Runtime] Tab visible, SSE resumed');
29
- }
30
- }
31
- function cleanup() {
32
- if (client) {
33
- document.removeEventListener('visibilitychange', handleVisibilityChange);
34
- window.removeEventListener('beforeunload', cleanup);
35
- window.removeEventListener('unload', cleanup);
36
- client.stop();
37
- client = null;
38
- console.log('[Runtime] Server log SSE client stopped');
39
- }
40
- }
41
- export { initServerLog };
@@ -1,5 +0,0 @@
1
- /**
2
- * 全局样式导入
3
- * 在 runtime 中最先执行,确保样式优先加载
4
- */
5
- import '../index.css';
@@ -1 +0,0 @@
1
- import "../index.css";
@@ -1,39 +0,0 @@
1
- /**
2
- * 统一 HMR API
3
- *
4
- * 提供统一的 HMR 成功/失败回调接口,屏蔽 Webpack 和 Vite 的差异。
5
- *
6
- * - Webpack/Rspack: 通过 import.meta.webpackHot 或 module.hot
7
- * - Vite: 通过 error-overlay 注入的 window.__VITE_HMR__
8
- *
9
- * @see docs/RFC_HMR_API.md
10
- */
11
- export interface HmrApi {
12
- /**
13
- * 注册 HMR 成功回调
14
- * @param callback 成功回调函数
15
- * @returns cleanup 函数,用于取消注册
16
- */
17
- onSuccess(callback: () => void): () => void;
18
- /**
19
- * 注册 HMR 失败回调
20
- * @param callback 失败回调函数,参数为错误信息
21
- * @returns cleanup 函数,用于取消注册
22
- */
23
- onError(callback: (error: unknown) => void): () => void;
24
- }
25
- declare global {
26
- interface Window {
27
- __VITE_HMR__?: HmrApi;
28
- }
29
- }
30
- /**
31
- * 获取 HMR API 实例
32
- *
33
- * 自动检测当前构建工具(Webpack/Vite)并返回对应实现:
34
- * - Webpack/Rspack: 使用内置适配器
35
- * - Vite: 使用 error-overlay 注入的 window.__VITE_HMR__
36
- *
37
- * @returns HmrApi 实例,如果不在开发环境或不支持 HMR 则返回 null
38
- */
39
- export declare function getHmrApi(): HmrApi | null;
@@ -1,36 +0,0 @@
1
- function createWebpackHmrApi(hot) {
2
- return {
3
- onSuccess (callback) {
4
- let lastStatus = null;
5
- const handler = (status)=>{
6
- if ('idle' === status && 'apply' === lastStatus) try {
7
- callback();
8
- } catch (e) {
9
- console.error('[HMR] Success callback error:', e);
10
- }
11
- lastStatus = status;
12
- };
13
- hot.addStatusHandler(handler);
14
- return ()=>hot.removeStatusHandler(handler);
15
- },
16
- onError (callback) {
17
- const handler = (status)=>{
18
- if ('fail' === status || 'abort' === status) try {
19
- callback(new Error(`HMR ${status}`));
20
- } catch (e) {
21
- console.error('[HMR] Error callback error:', e);
22
- }
23
- };
24
- hot.addStatusHandler(handler);
25
- return ()=>hot.removeStatusHandler(handler);
26
- }
27
- };
28
- }
29
- function getHmrApi() {
30
- if ('production' === process.env.NODE_ENV) return null;
31
- if (import.meta.webpackHot) return createWebpackHmrApi(import.meta.webpackHot);
32
- 'undefined' != typeof module && module.hot;
33
- if (window.__VITE_HMR__) return window.__VITE_HMR__;
34
- return null;
35
- }
36
- export { getHmrApi };
@@ -1,5 +0,0 @@
1
- /**
2
- * 按 appId 隔离的 localStorage 封装
3
- * API 与原生 localStorage 保持一致
4
- */
5
- export declare const scopedStorage: Storage;
@@ -1,46 +0,0 @@
1
- import { getAppId } from "./getAppId.js";
2
- function getPrefix() {
3
- const appId = getAppId(window.location.pathname);
4
- const namespace = appId || '__global__';
5
- return `__miaoda_${namespace}__:`;
6
- }
7
- function getScopedKeys() {
8
- const prefix = getPrefix();
9
- const keys = [];
10
- for(let i = 0; i < localStorage.length; i++){
11
- const key = localStorage.key(i);
12
- if (key && key.startsWith(prefix)) keys.push(key.substring(prefix.length));
13
- }
14
- return keys;
15
- }
16
- const scopedStorage = {
17
- getItem (key) {
18
- const prefixedKey = getPrefix() + key;
19
- return localStorage.getItem(prefixedKey);
20
- },
21
- setItem (key, value) {
22
- const prefixedKey = getPrefix() + key;
23
- localStorage.setItem(prefixedKey, value);
24
- },
25
- removeItem (key) {
26
- const prefixedKey = getPrefix() + key;
27
- localStorage.removeItem(prefixedKey);
28
- },
29
- clear () {
30
- const prefix = getPrefix();
31
- const keysToRemove = [];
32
- for(let i = 0; i < localStorage.length; i++){
33
- const key = localStorage.key(i);
34
- if (key && key.startsWith(prefix)) keysToRemove.push(key);
35
- }
36
- keysToRemove.forEach((key)=>localStorage.removeItem(key));
37
- },
38
- key (index) {
39
- const keys = getScopedKeys();
40
- return keys[index] || null;
41
- },
42
- get length () {
43
- return getScopedKeys().length;
44
- }
45
- };
46
- export { scopedStorage };