@ctil/gql 1.0.4 → 1.0.6

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.
@@ -1,116 +0,0 @@
1
- import { v4 as uuidv4 } from "uuid";
2
-
3
- export interface DeviceInfo {
4
- deviceId: string;
5
- deviceName: string;
6
- env: "node" | "browser";
7
- }
8
-
9
- /** 浏览器 IndexedDB 存取 deviceId */
10
- function getDeviceIdFromIndexedDB(): Promise<string | null> {
11
- return new Promise((resolve) => {
12
- if (typeof indexedDB === "undefined") return resolve(null);
13
-
14
- const request = indexedDB.open("DeviceDB", 1);
15
- request.onupgradeneeded = () => {
16
- const db = request.result;
17
- db.createObjectStore("info");
18
- };
19
- request.onsuccess = () => {
20
- const db = request.result;
21
- const tx = db.transaction("info", "readonly");
22
- const store = tx.objectStore("info");
23
- const getReq = store.get("deviceId");
24
- getReq.onsuccess = () => resolve(getReq.result ?? null);
25
- getReq.onerror = () => resolve(null);
26
- };
27
- request.onerror = () => resolve(null);
28
- });
29
- }
30
-
31
- function setDeviceIdToIndexedDB(id: string): Promise<void> {
32
- return new Promise((resolve) => {
33
- if (typeof indexedDB === "undefined") return resolve();
34
-
35
- const request = indexedDB.open("DeviceDB", 1);
36
- request.onupgradeneeded = () => {
37
- const db = request.result;
38
- db.createObjectStore("info");
39
- };
40
- request.onsuccess = () => {
41
- const db = request.result;
42
- const tx = db.transaction("info", "readwrite");
43
- const store = tx.objectStore("info");
44
- store.put(id, "deviceId");
45
- tx.oncomplete = () => resolve();
46
- tx.onerror = () => resolve();
47
- };
48
- request.onerror = () => resolve();
49
- });
50
- }
51
-
52
- /** 浏览器端设备信息 */
53
- export async function getBrowserDeviceInfo(): Promise<DeviceInfo> {
54
- let deviceId: string;
55
-
56
- try {
57
- const { load } = await import("@fingerprintjs/fingerprintjs");
58
- const fp = await load();
59
- const result = await fp.get();
60
- deviceId = result.visitorId;
61
- } catch {
62
- // FingerprintJS 不可用,使用 IndexedDB + UUID
63
- let id = await getDeviceIdFromIndexedDB();
64
- if (!id) {
65
- id = uuidv4();
66
- await setDeviceIdToIndexedDB(id);
67
- }
68
- deviceId = id;
69
- }
70
-
71
- // 生成 deviceName,不依赖 userAgent
72
- const deviceName = (() => {
73
- const platform = navigator.platform || "unknown";
74
- const width = screen.width || 0;
75
- const height = screen.height || 0;
76
- const colorDepth = screen.colorDepth || 24;
77
- return `${platform}-${width}x${height}x${colorDepth}`;
78
- })();
79
-
80
- return {
81
- deviceId,
82
- deviceName,
83
- env: "browser",
84
- };
85
- }
86
-
87
- /** Node 端设备信息 */
88
- async function getNodeDeviceInfo(): Promise<DeviceInfo> {
89
- const os = await import("os");
90
- const machine = await import("node-machine-id");
91
-
92
- const machineIdSync =
93
- (machine as any).machineIdSync ||
94
- (machine as any).default?.machineIdSync;
95
-
96
- if (typeof machineIdSync !== "function") {
97
- throw new Error("node-machine-id: machineIdSync not found");
98
- }
99
-
100
- const id = machineIdSync(true);
101
- return {
102
- deviceId: id,
103
- deviceName: os.hostname(),
104
- env: "node",
105
- };
106
- }
107
-
108
- /** 跨平台获取设备信息 */
109
- export async function getDeviceInfo(): Promise<DeviceInfo> {
110
- const isBrowser =
111
- typeof window !== "undefined" &&
112
- typeof navigator !== "undefined" &&
113
- typeof screen !== "undefined";
114
-
115
- return isBrowser ? getBrowserDeviceInfo() : getNodeDeviceInfo();
116
- }
package/src/index.ts DELETED
@@ -1,60 +0,0 @@
1
- // src/index.ts
2
-
3
- // 1️⃣ GraphQL client 初始化与获取
4
- export {
5
- initGraphQLClient,
6
- useInterceptor,
7
- getClient,
8
- setToken,
9
- removeToken,
10
- setEndpoint,
11
- setHeader,
12
- setHeaders,
13
- removeHeader,
14
- clearHeaders
15
- } from './core/client.js';
16
-
17
- // 2️⃣ 类型定义(统一导出)
18
- export type * from './core/type.js';
19
-
20
- // 3️⃣ GraphQL 构建器(buildXXX 方法)
21
- export type {
22
- //Query
23
- QueryInput,
24
- QueryPageListInput,
25
- QueryByIdInput,
26
- QueryAggregateInput,
27
- AggregateFieldInput,
28
- //Mutation
29
- InsertOneInput,
30
- BatchInsertInput,
31
- DeleteInput,
32
- DeleteByIdInput,
33
- BatchUpdateInput,
34
- UpdateByPkInput,
35
- UpdateInput,
36
- //鉴权
37
- LoginInput,
38
- RegisterUserInput,
39
- LogoutInput,
40
- LogoutDeviceInput,
41
- RefreshTokenInput,
42
- //SMS
43
- SendCodeInput,
44
- VerifyCodeInput
45
- } from './builders/index.ts';
46
-
47
- // 4️⃣ 业务 API 模块(每个模块有默认泛型)
48
- export * from './core/api/auth.js';
49
- export * from './core/api/query.js';
50
- export * from './core/api/mutation.js';
51
- export * from './core/api/sms.js';
52
- export * from './core/api/gql.js';
53
-
54
-
55
-
56
- // 5️⃣ 设备信息
57
- export * from './device/index.ts'
58
-
59
-
60
- // 6️⃣7️⃣8️⃣9️⃣🔟
@@ -1,51 +0,0 @@
1
- import { rateLimitConfig as defaultConfig } from './rateLimitConfig.ts';
2
-
3
- interface RateLimitRule {
4
- max: number;
5
- window: number; // 秒
6
- debounce: number; // 毫秒
7
- }
8
-
9
- interface TrackerItem {
10
- timestamps: number[];
11
- timeout?: NodeJS.Timeout;
12
- }
13
-
14
- const trackers = new Map<string, TrackerItem>();
15
-
16
- function getRule(operateName: string, type: 'query' | 'mutation', config: any): RateLimitRule {
17
- return config.custom?.[operateName] || config.defaultRules[type];
18
- }
19
-
20
- export function rateLimit<T>(
21
- operateName: string,
22
- type: 'query' | 'mutation',
23
- fn: () => Promise<T>,
24
- config = defaultConfig // <-- 默认使用内置配置
25
- ): Promise<T> {
26
- const rule = getRule(operateName, type, config);
27
- const now = Date.now();
28
- const key = `${type}::${operateName}`;
29
-
30
- if (!trackers.has(key)) trackers.set(key, { timestamps: [] });
31
- const tracker = trackers.get(key)!;
32
-
33
- tracker.timestamps = tracker.timestamps.filter(ts => now - ts < rule.window * 1000);
34
-
35
- return new Promise((resolve, reject) => {
36
- const exec = () => {
37
- if (tracker.timestamps.length >= rule.max) {
38
- return reject(new Error(`Rate limit exceeded for ${operateName}`));
39
- }
40
- tracker.timestamps.push(Date.now());
41
- fn().then(resolve).catch(reject);
42
- };
43
-
44
- if (rule.debounce > 0) {
45
- if (tracker.timeout) clearTimeout(tracker.timeout);
46
- tracker.timeout = setTimeout(exec, rule.debounce);
47
- } else {
48
- exec();
49
- }
50
- });
51
- }
@@ -1,12 +0,0 @@
1
- export const rateLimitConfig = {
2
- defaultRules: {
3
- query: { max: 10, window: 1, debounce: 0 },
4
- mutation: { max: 3, window: 1, debounce: 200 },
5
- },
6
- custom: {
7
- login: { max: 1, window: 5, debounce: 0 },
8
- refreshToken: { max: 2, window: 5, debounce: 0 },
9
-
10
- },
11
- };
12
-
package/src/test.ts DELETED
@@ -1,80 +0,0 @@
1
- import { initGraphQLClient,auth,query,setToken,removeToken,useInterceptor } from "./index.ts"; // 本地调试用相对路径
2
-
3
- const client = initGraphQLClient({
4
- endpoint: "http://localhost:9526/graphql",
5
-
6
- // Authorization:"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEwMDAwMDAwMDAsImxvZ2luQWNjb3VudCI6ImNhaWNhaSIsInR5cGUiOiJhY2Nlc3MiLCJkZXZpY2VJZCI6IjEwMDAwMDgiLCJqdGkiOiJjMTJjNjQ5ZS05OTIwLTRkNDgtOWRjZS0yYWJkZGMzYTc1OWIiLCJpYXQiOjE3NjE3MzIxMzEsImV4cCI6MTc2MTczMzkzMX0.CkJf3fYdto7zugkkej8sfLCw03Yrgc1zMAoPL2PaFUk"
7
- });
8
-
9
-
10
- // ✅ 注册请求 / 响应 / 错误拦截器
11
- useInterceptor({
12
- onRequest: async ({ query, variables, headers }) => {
13
- // console.log("[Request Interceptor]", { query, variables, headers });
14
- // 可以在这里加上时间戳或日志
15
- return { query, variables, headers };
16
- },
17
- onResponse: async (response) => {
18
- // console.log("[Response Interceptor]", response);
19
- // 可以在这里统一处理响应结构,比如包装 data
20
- return response;
21
- },
22
- onError: async (error) => {
23
- // console.error("[Error Interceptor]", error);
24
- // 比如 token 过期时可以自动重试或刷新
25
- if (error.status === 401) {
26
- console.log("⚠️ Token expired, redirecting to login...");
27
- }
28
- // 返回错误或重新抛出
29
- throw error;
30
- },
31
- });
32
-
33
- async function test() {
34
-
35
- try {
36
- // const loginRs=await auth.login({
37
- // account:"caicai",
38
- // password:"caicai"
39
- // })
40
- // console.log(loginRs.login.token);
41
-
42
- // setToken(loginRs.login.token);
43
- // debugger;
44
- // console.log(loginRs);
45
- const rs=await query.byId({
46
- operationName:"user",
47
- pk:"1000000000",
48
- fields:["id","username","nickname","phone",{
49
- roles:{
50
- fields:["id","roleCode","roleName"]
51
- }
52
- }]
53
- })
54
- // debugger;
55
- console.log(rs);
56
-
57
- // removeToken()
58
-
59
- // const res=await query.byId({
60
- // operationName:"user",
61
- // pk:"1000000000",
62
- // fields:["id","username","nickname","phone",{
63
- // roles:{
64
- // fields:["id","roleCode","roleName"]
65
- // }
66
- // }]
67
- // })
68
- // debugger;
69
- // console.log(res);
70
-
71
- } catch (err:any) {
72
-
73
- // debugger;
74
- console.error("GraphQL request failed:", err);
75
- console.error("GraphQL request failed:", err.message);
76
- }
77
- }
78
-
79
-
80
- test();
package/tsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "nodenext", // ✅ 必须和 moduleResolution 配套
5
- "moduleResolution": "nodenext", // ✅ 支持 Node ESM
6
- "esModuleInterop": true,
7
- "allowSyntheticDefaultImports": true,
8
- "allowImportingTsExtensions": true,
9
- "noEmit":true,
10
- "declaration": true,
11
- "declarationMap": true,
12
- "outDir": "dist",
13
- "strict": true,
14
- "skipLibCheck": true
15
- },
16
- "include": ["src"]
17
- }
package/tsup.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- entry: ["src/index.ts"],
5
- format: ["esm", "cjs"],
6
- dts: true,
7
- sourcemap: true,
8
- clean: true,
9
- outDir: "dist",
10
- });