yichong-canva2 1.1.27
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/README.md +65 -0
- package/dist/index.js +8 -0
- package/dist/login/context.js +36 -0
- package/dist/login/login/apis/index.js +78 -0
- package/dist/login/login/apis/request.js +6 -0
- package/dist/login/login/login.js +190 -0
- package/dist/login/privider.js +603 -0
- package/dist/login/use_canva.js +12 -0
- package/dist/login/version.js +26 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/login/context.d.ts +76 -0
- package/dist/types/login/index.d.ts +4 -0
- package/dist/types/login/interface.d.ts +72 -0
- package/dist/types/login/login/apis/index.d.ts +32 -0
- package/dist/types/login/login/apis/request.d.ts +9 -0
- package/dist/types/login/login/interface.d.ts +16 -0
- package/dist/types/login/login/login.d.ts +77 -0
- package/dist/types/login/privider.d.ts +38 -0
- package/dist/types/login/use_canva.d.ts +6 -0
- package/dist/types/login/version.d.ts +4 -0
- package/package.json +50 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { canUseError, CheckoutSessionOptions, TestMode, UserStatus } from './interface';
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @interface 上下文类型
|
|
6
|
+
* @property {UserStatus} userStatus 用户状态
|
|
7
|
+
* @property {() => void} updateUserStatus 更新用户状态
|
|
8
|
+
* @property {() => void} handleLogin 登录
|
|
9
|
+
* @property {number} credits 余额
|
|
10
|
+
* @property {() => number | null} getLimitUsage 获取月限额使用额度
|
|
11
|
+
* @property {boolean} isSubscribed 是否订阅
|
|
12
|
+
* @property {() => void} use 使用次数减少
|
|
13
|
+
* @property {() => boolean canUse 是否能使用
|
|
14
|
+
* @property {() => { error?: 'userStatus_error' | 'monthly_usage_limit' | 'no_credits', canUse: boolean }} canUseLimit 新版本增加了月度限额逻辑是否能使用
|
|
15
|
+
* @property {(options?: CheckoutSessionOptions) => Promise<UserStatus> | undefined} pollUserStatus 结账会话:打开外部定价页后调用;相对「打开前基线」检测订阅/额度变化;TTL 或 stopCurrentPolling 时补拉一次并 resolve(Promise 一定结束);回侧栏不停止;登录前调用返回 undefined
|
|
16
|
+
* @property {() => string} getPricingLink 获取付费链接
|
|
17
|
+
* @property {() => void} updateTestMode 更新测试模式, 只有在开发环境下有效
|
|
18
|
+
*/
|
|
19
|
+
export interface YiChongCanvaContextType {
|
|
20
|
+
userStatus: UserStatus;
|
|
21
|
+
updateUserStatus: (user: Partial<UserStatus>) => void;
|
|
22
|
+
handleLogin: () => void;
|
|
23
|
+
credits: number;
|
|
24
|
+
getLimitUsage: () => number | null;
|
|
25
|
+
getMonthlyUsageLimit: () => number | null;
|
|
26
|
+
isSubscribed: boolean;
|
|
27
|
+
use: (cnt?: number, force?: boolean, notUpload?: boolean) => void;
|
|
28
|
+
canUse: (cnt?: number, force?: boolean) => boolean;
|
|
29
|
+
canUseLimit: (cnt?: number, force?: boolean) => {
|
|
30
|
+
error?: canUseError;
|
|
31
|
+
canUse: boolean;
|
|
32
|
+
};
|
|
33
|
+
isFreeUnlimited: () => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* 结账会话(checkout session)。
|
|
36
|
+
* - 打开外部定价页(getPricingLink)后调用;无参调用使用默认参数(快 5s×30s → 慢 15s,TTL 5 分钟)
|
|
37
|
+
* - 成功判定相对「打开定价页前」的基线:出现/变更 subscription.detail、free_cnt 增加、可用额度增加
|
|
38
|
+
* - TTL 到期或 stopCurrentPolling() 时补拉一次 status 后 resolve —— Promise 一定会结束
|
|
39
|
+
* - 用户回到 Canva 侧栏(focus / visibilitychange)不会停止会话
|
|
40
|
+
* - 再次调用会先停掉上一轮会话,任何时刻只有一条轮询
|
|
41
|
+
* - 登录完成前调用返回 undefined(不是 Promise)
|
|
42
|
+
*/
|
|
43
|
+
pollUserStatus: (options?: CheckoutSessionOptions) => Promise<UserStatus> | undefined;
|
|
44
|
+
getPricingLink: () => string;
|
|
45
|
+
updateTestMode: (m: TestMode) => void;
|
|
46
|
+
refreshUserStatus: () => Promise<UserStatus>;
|
|
47
|
+
hasClickedUpgrade: boolean;
|
|
48
|
+
setHasClickedUpgrade: (v: boolean) => void;
|
|
49
|
+
/** 停止当前结账会话:有会话则停止(补拉一次后让其 Promise resolve)并返回 true;无会话返回 false */
|
|
50
|
+
stopCurrentPolling: () => boolean;
|
|
51
|
+
updateCredits: (credits: number) => void;
|
|
52
|
+
loginStatus: "success" | "error" | "loading" | "idle";
|
|
53
|
+
manualLogin: (_retry?: number) => void;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 上下文
|
|
57
|
+
* @description 上下文
|
|
58
|
+
* @property {UserStatus} userStatus 用户状态
|
|
59
|
+
* @property {() => void} updateUserStatus 更新用户状态
|
|
60
|
+
* @property {() => void} handleLogin 登录
|
|
61
|
+
* @property {number} credits 余额
|
|
62
|
+
* @property {boolean} isSubscribed 是否订阅
|
|
63
|
+
* @property {() => void} use 使用次数减少
|
|
64
|
+
* @property {() => { error?: 'userStatus_error' | 'monthly_usage_limit' | 'no_credits', canUse: boolean }} canUse 是否能使用
|
|
65
|
+
* @property {() => void} pollUserStatus 轮询用户状态, 如果积分和订阅状态发生改变就会更新用户信息
|
|
66
|
+
* @property {() => string} getPricingLink 获取付费链接
|
|
67
|
+
* @property {() => void} updateTestMode 更新测试模式, 只有在开发环境下有效
|
|
68
|
+
* @property {() => void} refreshUserStatus 刷新用户状态
|
|
69
|
+
* @property {boolean} hasClickedUpgrade 是否点击过升级
|
|
70
|
+
* @property {() => void} setHasClickedUpgrade 设置是否点击过升级
|
|
71
|
+
* @property {() => void} stopCurrentPolling 停止当前轮询
|
|
72
|
+
* @property {() => void} updateCredits 更新积分
|
|
73
|
+
* @property {() => void} manualLogin 手动登录
|
|
74
|
+
* @property {"success" | "error" | "loading" | "idle"} loginStatus 登录状态
|
|
75
|
+
*/
|
|
76
|
+
export declare const YiChongCanvaContext: React.Context<YiChongCanvaContextType>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface UserStatus {
|
|
2
|
+
jwt?: string;
|
|
3
|
+
api_auth?: {
|
|
4
|
+
time: number;
|
|
5
|
+
expire_at: number;
|
|
6
|
+
};
|
|
7
|
+
profile?: {
|
|
8
|
+
id: string;
|
|
9
|
+
username: string;
|
|
10
|
+
email: string;
|
|
11
|
+
avatar: string;
|
|
12
|
+
token: string;
|
|
13
|
+
from_app: string;
|
|
14
|
+
expire_at: number;
|
|
15
|
+
usage_limits: {
|
|
16
|
+
free_limit: number;
|
|
17
|
+
monthly_usage_limit: number;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
subscription?: {
|
|
21
|
+
detail?: {
|
|
22
|
+
ends_at: string | null | number;
|
|
23
|
+
name: string;
|
|
24
|
+
};
|
|
25
|
+
is_subscribed?: boolean;
|
|
26
|
+
free_cnt?: number;
|
|
27
|
+
monthly_usage_cnt?: number;
|
|
28
|
+
free_usage_cnt?: number;
|
|
29
|
+
on_trial?: number;
|
|
30
|
+
};
|
|
31
|
+
team_subscription?: {
|
|
32
|
+
detail: {
|
|
33
|
+
name: string;
|
|
34
|
+
ends_at: string | null | number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
drive?: {
|
|
38
|
+
fresh_token: string;
|
|
39
|
+
};
|
|
40
|
+
userId?: string;
|
|
41
|
+
planName?: 'Free' | 'Pro Monthly plan' | 'Pro Yearly plan' | 'Premium';
|
|
42
|
+
}
|
|
43
|
+
declare global {
|
|
44
|
+
interface Window {
|
|
45
|
+
pollUserSubscribe: () => void;
|
|
46
|
+
g_canva_token: string;
|
|
47
|
+
g_token: string;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 结账会话参数(pollUserStatus 可选入参,均有默认值,无参调用保持向后兼容)。
|
|
52
|
+
*
|
|
53
|
+
* 语义:打开外部定价页后进入一段有 TTL 的轮询会话 ——
|
|
54
|
+
* 快阶段每 fastIntervalMs 拉一次 status,持续 fastPhaseMs 后降频到 slowIntervalMs,
|
|
55
|
+
* 检测到「相对打开定价页前基线」的订阅/额度变化即成功;
|
|
56
|
+
* 会话满 sessionTtlMs 或手动 stopCurrentPolling() 时补拉一次 status 后 resolve。
|
|
57
|
+
* 注意:回到 Canva 侧栏(focus / visibilitychange)不会终止会话 ——
|
|
58
|
+
* Canva 拿不到定价页关闭事件,回侧栏往往表示定价页还开着。
|
|
59
|
+
*/
|
|
60
|
+
export interface CheckoutSessionOptions {
|
|
61
|
+
/** 快阶段轮询间隔,默认 5000ms */
|
|
62
|
+
fastIntervalMs?: number;
|
|
63
|
+
/** 快阶段持续时长,默认 30000ms */
|
|
64
|
+
fastPhaseMs?: number;
|
|
65
|
+
/** 慢阶段轮询间隔,默认 15000ms */
|
|
66
|
+
slowIntervalMs?: number;
|
|
67
|
+
/** 会话总时长(TTL),默认 300000ms(5 分钟),到期补刷一次并 resolve */
|
|
68
|
+
sessionTtlMs?: number;
|
|
69
|
+
}
|
|
70
|
+
export type TestMode = 'noTest' | 'credits' | 'subscribed' | 'expired';
|
|
71
|
+
export type Mode = 'normal' | 'server_credits';
|
|
72
|
+
export type canUseError = 'userStatus_error' | 'monthly_usage_limit' | 'no_credits' | undefined;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 由token和appId获取用户唯一的id
|
|
3
|
+
* @param token canva颁发的token
|
|
4
|
+
* @param appId 当前应用的appId
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
declare function getUserIds(token: string, appId: string): Promise<any>;
|
|
8
|
+
/**
|
|
9
|
+
* 利用id登录用户
|
|
10
|
+
* @param userId 获取到的用户唯一id
|
|
11
|
+
*/
|
|
12
|
+
declare function handleUserLoginByCanvaId(userId: string, productName?: string): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* 由id获取通行证
|
|
15
|
+
* @param userId
|
|
16
|
+
* @param appName
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
declare function getPassport(userId: string, productName: string): Promise<any>;
|
|
20
|
+
/**
|
|
21
|
+
* 由通行证获取用户信息
|
|
22
|
+
* @param passport
|
|
23
|
+
* @returns
|
|
24
|
+
*/
|
|
25
|
+
declare function getUserStatusByPassport(passport: string, productName: string): Promise<any>;
|
|
26
|
+
declare const apis: {
|
|
27
|
+
getUserIds: typeof getUserIds;
|
|
28
|
+
handleUserLoginByCanvaId: typeof handleUserLoginByCanvaId;
|
|
29
|
+
getPassport: typeof getPassport;
|
|
30
|
+
getUserStatusByPassport: typeof getUserStatusByPassport;
|
|
31
|
+
};
|
|
32
|
+
export default apis;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { UserStatus } from '../interface';
|
|
3
|
+
/**
|
|
4
|
+
* @interface 登录组件props
|
|
5
|
+
*/
|
|
6
|
+
export interface UseCanvaLoginProps {
|
|
7
|
+
onLogin?: (user: UserStatus) => void;
|
|
8
|
+
appId: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
productName: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CanvaLoginContextProps {
|
|
13
|
+
userStatus?: UserStatus;
|
|
14
|
+
userId?: string;
|
|
15
|
+
onLogin?: (userStatus: (userStatus: UserStatus) => void) => void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { UserStatus } from './../interface';
|
|
2
|
+
export declare function handleLogin({ appId, productName, }: LoginProps): Promise<UserStatus>;
|
|
3
|
+
/**
|
|
4
|
+
* 订阅比较基线:打开定价页「之前」的用户状态快照。
|
|
5
|
+
* 由 Provider 在会话开始时用当时的 userStatus 生成(takeSubscribeBaseline),
|
|
6
|
+
* 不允许被轮询的第一轮响应覆盖 —— 否则打开前已付款的场景会漏检,
|
|
7
|
+
* 且 detail 为 undefined 时会误判成功(1.1.26 的现网 bug)。
|
|
8
|
+
*/
|
|
9
|
+
export interface SubscribeBaseline {
|
|
10
|
+
free_cnt: number | null;
|
|
11
|
+
detailJson: string | null;
|
|
12
|
+
available: number | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 从 UserStatus 拍订阅基线。
|
|
16
|
+
* detail 快照必须写成 `detail == null ? null : JSON.stringify(detail)`:
|
|
17
|
+
* `JSON.stringify(undefined) || null` 会把 undefined 折成 null,
|
|
18
|
+
* 而后续 `null !== JSON.stringify(undefined)` 恒为 true,导致免费用户第一轮就误判成功。
|
|
19
|
+
*/
|
|
20
|
+
export declare function takeSubscribeBaseline(userStatus: UserStatus): SubscribeBaseline;
|
|
21
|
+
/**
|
|
22
|
+
* 用「原始响应体」计算可用额度的纯函数。
|
|
23
|
+
* 不要用 Provider 的 getLimitUsage():它读的是 React state,轮询期间不会更新。
|
|
24
|
+
* 口径对齐 Provider:订阅生效 = 月额度剩余(clamp 到 >=0)+ 积分;否则 = 积分。
|
|
25
|
+
* monthly_usage_limit 为 -1(无限额度)时返回 null。
|
|
26
|
+
*/
|
|
27
|
+
export declare function computeAvailableLimit(userStatus: UserStatus): number | null;
|
|
28
|
+
/**
|
|
29
|
+
* 默认的「相对基线是否已付费/到账」判断(对齐 Chrome 插件 loopSubscribe 思路):
|
|
30
|
+
* 1. subscription.detail 出现或变化(订阅、换套餐、续费改 ends_at,JSON 全量比较)
|
|
31
|
+
* 2. free_cnt 变多(买积分包;只认「增加」——会话中在侧栏消耗积分导致的减少不算成功)
|
|
32
|
+
* 3. 可用额度比基线变大(月订用户 free_cnt 常为 0,只盯它会把会话打满)
|
|
33
|
+
* 注意:monthly_usage_cnt 自增(用量上报)不构成成功。
|
|
34
|
+
*/
|
|
35
|
+
export declare function isSubscribeChanged(current: UserStatus, baseline: SubscribeBaseline): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* 拉取 / 轮询用户信息。
|
|
38
|
+
*
|
|
39
|
+
* 两种模式(isSubscribe 区分):
|
|
40
|
+
* - isSubscribe = false(handleLogin / refreshUserStatus):拿到带 profile 的
|
|
41
|
+
* userStatus 立刻 successCallback 并返回,行为与 1.1.26 一致
|
|
42
|
+
* (1.1.26 会在 finally 里多睡一轮 3s 才 resolve,属实现缺陷,已去掉;请求次数不变)。
|
|
43
|
+
* - isSubscribe = true(结账会话):相对 baseline 检测订阅/额度变化,变了才成功。
|
|
44
|
+
* 未传 baseline 时保持旧语义:用第一轮成功响应拍快照(但 detail 快照 bug 已修)。
|
|
45
|
+
*
|
|
46
|
+
* 结束方式:
|
|
47
|
+
* 1. 成功:successCallback + return userStatus
|
|
48
|
+
* 2. 手动停止(onStop 交出的函数被调用):打断等待中的 sleep,return undefined(不算失败)
|
|
49
|
+
* 3. maxCount 次数耗尽或 maxDurationMs 到期:failCallback + throw
|
|
50
|
+
*/
|
|
51
|
+
export declare function getUserProfile({ maxCount, interval, maxDurationMs, productName, userId, successCallback, failCallback, isSubscribe, baseline, isChanged, onStop, }: UserProfileProps): Promise<UserStatus | undefined>;
|
|
52
|
+
export interface UserProfileProps {
|
|
53
|
+
maxCount?: number;
|
|
54
|
+
interval?: number | (() => number);
|
|
55
|
+
maxDurationMs?: number;
|
|
56
|
+
productName: string;
|
|
57
|
+
userId: string;
|
|
58
|
+
successCallback?: (userStatus: UserStatus) => void;
|
|
59
|
+
failCallback?: () => void;
|
|
60
|
+
isSubscribe?: boolean;
|
|
61
|
+
baseline?: SubscribeBaseline;
|
|
62
|
+
isChanged?: (current: UserStatus, baseline: SubscribeBaseline) => boolean;
|
|
63
|
+
onStop?: (fn: () => void) => void;
|
|
64
|
+
}
|
|
65
|
+
export interface LoginProps {
|
|
66
|
+
callback?: (state: LoginState) => void;
|
|
67
|
+
appId: string;
|
|
68
|
+
productName: string;
|
|
69
|
+
requestConfig?: UserProfileProps;
|
|
70
|
+
}
|
|
71
|
+
export interface LoginState {
|
|
72
|
+
status: "finish" | "error" | "start" | "user_id";
|
|
73
|
+
data?: {
|
|
74
|
+
token?: string;
|
|
75
|
+
userId?: string;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { Mode, TestMode, UserStatus } from './interface';
|
|
3
|
+
/**
|
|
4
|
+
* @interface 参数
|
|
5
|
+
* @property {React.ReactNode} children 子节点
|
|
6
|
+
* @property {string} appId 应用ID
|
|
7
|
+
* @property {string} productName 产品名称
|
|
8
|
+
* @property {(userStatus: UserStatus) => void} onUpdateUserStatus 用户状态更新回调, 一般可以不用
|
|
9
|
+
* @property {number} freeTimes 免费次数, 默认为1
|
|
10
|
+
* @property {string} baseUrl 服务器地址
|
|
11
|
+
* @property {boolean} autoLogin 自动登录, 默认为true
|
|
12
|
+
*/
|
|
13
|
+
export interface YiChongCanvaProviderProps {
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
appId: string;
|
|
16
|
+
productName: string;
|
|
17
|
+
onUpdateUserStatus?: (userStatus: UserStatus) => void;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
autoLogin?: boolean;
|
|
20
|
+
testMode?: TestMode;
|
|
21
|
+
version: number;
|
|
22
|
+
mode?: Mode;
|
|
23
|
+
maxAvailablePoints?: number;
|
|
24
|
+
retry?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* YiChongCanvaProvider 全局登录,积分等方法提供
|
|
28
|
+
* @param {object} params0
|
|
29
|
+
* @param {children} params0.children 子元素
|
|
30
|
+
* @param {string} params0.appId 应用id
|
|
31
|
+
* @param {string} params0.productName 产品名称
|
|
32
|
+
* @param {Function} params0.onUpdateUserStatus 用户信息更新后的回调
|
|
33
|
+
* @param {string} params0.baseUrl 链接
|
|
34
|
+
* @param {boolean} params0.autoLogin 是否自动登录
|
|
35
|
+
* @param {string} params0.mode 测试模式
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
export declare const YiChongCanvaProvider: ({ children, appId, productName, onUpdateUserStatus, baseUrl, autoLogin, testMode: _testMode, version, mode, retry, maxAvailablePoints, }: YiChongCanvaProviderProps) => React.JSX.Element;
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "yichong-canva2",
|
|
3
|
+
"version": "1.1.27",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/types/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/types/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "vite",
|
|
19
|
+
"build": "vite build",
|
|
20
|
+
"lint": "eslint .",
|
|
21
|
+
"preview": "vite preview",
|
|
22
|
+
"publish": "npm publish"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@canva/user": ">=2.1.0",
|
|
26
|
+
"react": ">=18",
|
|
27
|
+
"react-dom": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@canva/user": "^2.2.0",
|
|
31
|
+
"@eslint/js": "^9.21.0",
|
|
32
|
+
"@types/lodash": "^4.17.16",
|
|
33
|
+
"@types/node": "^22.13.9",
|
|
34
|
+
"@types/react": "^19.0.10",
|
|
35
|
+
"@types/react-dom": "^19.0.4",
|
|
36
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
37
|
+
"eslint": "^9.21.0",
|
|
38
|
+
"eslint-plugin-react-hooks": "^5.1.0",
|
|
39
|
+
"eslint-plugin-react-refresh": "^0.4.19",
|
|
40
|
+
"globals": "^15.15.0",
|
|
41
|
+
"lodash": "^4.17.21",
|
|
42
|
+
"react": "18.3.1",
|
|
43
|
+
"react-dom": "18.3.1",
|
|
44
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
45
|
+
"typescript": "~5.7.3",
|
|
46
|
+
"typescript-eslint": "^8.24.1",
|
|
47
|
+
"vite": "^6.2.0",
|
|
48
|
+
"vite-plugin-dts": "^4.5.3"
|
|
49
|
+
}
|
|
50
|
+
}
|