@inzombieland/core 0.0.1 → 1.18.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/AppProvider.vue +36 -0
- package/LICENSE +8 -0
- package/api-client.d.ts +7 -0
- package/api-client.mjs +130 -0
- package/bus.d.ts +7 -0
- package/bus.mjs +22 -0
- package/comet-client.d.ts +11 -0
- package/comet-client.mjs +73 -0
- package/composables/use-active-sessions.d.ts +26 -0
- package/composables/use-active-sessions.mjs +14 -0
- package/composables/use-api-actions.d.ts +13 -0
- package/composables/use-api-actions.mjs +5 -0
- package/composables/use-app-locale.d.ts +1 -0
- package/composables/use-app-locale.mjs +13 -0
- package/composables/use-subscribe.d.ts +10 -0
- package/composables/use-subscribe.mjs +22 -0
- package/composables/use-theme-mode.d.ts +1 -0
- package/composables/use-theme-mode.mjs +14 -0
- package/composables/use-user.d.ts +32 -0
- package/composables/use-user.mjs +5 -0
- package/get-user.d.ts +2 -0
- package/get-user.mjs +55 -0
- package/get-visitor.d.ts +11 -0
- package/get-visitor.mjs +48 -0
- package/helpers/api-helper.d.ts +6 -0
- package/helpers/api-helper.mjs +99 -0
- package/helpers/current-device.d.ts +67 -0
- package/helpers/current-device.mjs +368 -0
- package/helpers/date-helper.d.ts +15 -0
- package/helpers/date-helper.mjs +230 -0
- package/helpers/device-helper.d.ts +43 -0
- package/helpers/device-helper.mjs +15 -0
- package/helpers/index.d.ts +4 -0
- package/helpers/index.mjs +15 -0
- package/index.d.ts +53 -0
- package/index.mjs +60 -0
- package/init-application.d.ts +1 -0
- package/init-application.mjs +89 -0
- package/package.json +12 -1
- package/refresh-token.d.ts +2 -0
- package/refresh-token.mjs +39 -0
- package/types.d.ts +71 -0
- package/types.mjs +0 -0
- package/user-actions.d.ts +15 -0
- package/user-actions.mjs +38 -0
package/AppProvider.vue
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { onBeforeMount, onMounted, ref } from "vue"
|
|
3
|
+
import bus from "./bus"
|
|
4
|
+
import { useThemeMode, useUser } from "./index"
|
|
5
|
+
import type { ConfigProviderTheme } from "vant"
|
|
6
|
+
import "@vant/touch-emulator"
|
|
7
|
+
|
|
8
|
+
const theme = useThemeMode()
|
|
9
|
+
const user = useUser()
|
|
10
|
+
const appLoading = ref(Boolean(user.value))
|
|
11
|
+
|
|
12
|
+
onBeforeMount(() => {
|
|
13
|
+
bus.publish("app:beforeMount", true)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
onMounted(() => {
|
|
17
|
+
appLoading.value = false
|
|
18
|
+
})
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div
|
|
23
|
+
class="h-full"
|
|
24
|
+
:class="{ app: appLoading }"
|
|
25
|
+
>
|
|
26
|
+
<slot />
|
|
27
|
+
<van-config-provider
|
|
28
|
+
v-if="theme?.value"
|
|
29
|
+
:theme="theme?.value as ConfigProviderTheme"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<style scoped>
|
|
35
|
+
.app{height:0;width:0}.app:after{background:#5a5a5a url(/images/loading.gif) no-repeat 50%;content:"";height:100%;left:0;position:absolute;top:0;transition:.5s;width:100%;z-index:10000}
|
|
36
|
+
</style>
|
package/LICENSE
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
ISC License:
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
|
|
4
|
+
Copyright (c) 1995-2003 by Internet Software Consortium
|
|
5
|
+
|
|
6
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/api-client.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Fetch, FetchConfig, FetchExtraOptions as FetchOptions, User } from "./types";
|
|
2
|
+
export declare const setUser: (newUser?: User | null) => void;
|
|
3
|
+
export declare const updateUser: (newUser: Partial<User>) => void;
|
|
4
|
+
export declare const getToken: () => string | null | undefined;
|
|
5
|
+
export declare const setToken: (newToken?: string | null) => void;
|
|
6
|
+
export declare const flush: () => void;
|
|
7
|
+
export declare const createApiFetch: (fetch: Fetch, config: FetchConfig) => (url: string, options?: FetchOptions) => Promise<any>;
|
package/api-client.mjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import bus from "./bus.mjs";
|
|
2
|
+
import { useApiActions } from "./composables/use-api-actions.mjs";
|
|
3
|
+
import { useUser } from "./composables/use-user.mjs";
|
|
4
|
+
import { getVisitor } from "./get-visitor.mjs";
|
|
5
|
+
import { apiHelper, once } from "./helpers/index.mjs";
|
|
6
|
+
let token = null;
|
|
7
|
+
export const setUser = (newUser) => {
|
|
8
|
+
const user = useUser();
|
|
9
|
+
user.value = newUser;
|
|
10
|
+
bus.publish("user:onUpdated", user.value);
|
|
11
|
+
};
|
|
12
|
+
export const updateUser = (newUser) => {
|
|
13
|
+
const user = useUser();
|
|
14
|
+
if (user.value && newUser) {
|
|
15
|
+
setUser({ ...user.value, ...newUser });
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export const getToken = () => {
|
|
19
|
+
return token;
|
|
20
|
+
};
|
|
21
|
+
export const setToken = (newToken) => {
|
|
22
|
+
token = newToken;
|
|
23
|
+
};
|
|
24
|
+
export const flush = () => {
|
|
25
|
+
setToken(null);
|
|
26
|
+
setUser(null);
|
|
27
|
+
};
|
|
28
|
+
const eventHandler = (requestID, eventName) => {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const subscription = bus.subscribe(eventName, (data) => {
|
|
31
|
+
if (requestID !== data?.requestID) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
subscription?.unsubscribe();
|
|
35
|
+
resolve(data);
|
|
36
|
+
});
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
if (subscription?.closed) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
subscription?.unsubscribe();
|
|
42
|
+
reject(new Error("Event Response Timeout"));
|
|
43
|
+
}, 1e4);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
const successHandler = async (response, options = {}) => {
|
|
47
|
+
const eventNameResult = options.headers?.event;
|
|
48
|
+
const checkResponse = options.checkResponse;
|
|
49
|
+
if (typeof eventNameResult === "string" && Boolean(eventNameResult)) {
|
|
50
|
+
const requestID = response?._data?.RequestID;
|
|
51
|
+
const data = await eventHandler(requestID, eventNameResult);
|
|
52
|
+
return resolveData(data);
|
|
53
|
+
} else {
|
|
54
|
+
return resolveData(response?._data);
|
|
55
|
+
}
|
|
56
|
+
function resolveData(resData) {
|
|
57
|
+
const data = apiHelper.convertToClient(resData);
|
|
58
|
+
if (import.meta.env.MODE !== "production" && checkResponse && !checkResponse(data)?.success) {
|
|
59
|
+
console.error(checkResponse(data).error);
|
|
60
|
+
}
|
|
61
|
+
return data;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const errorHandler = (error) => {
|
|
65
|
+
const { _data } = error?.response ?? { status: 500, _data: {} };
|
|
66
|
+
const data = apiHelper.convertToClient(_data.data ?? _data);
|
|
67
|
+
let message = "";
|
|
68
|
+
if (typeof data === "string") {
|
|
69
|
+
message = data.trim();
|
|
70
|
+
}
|
|
71
|
+
return new Error(message);
|
|
72
|
+
};
|
|
73
|
+
const optionsHandler = (options = {}, config) => {
|
|
74
|
+
const { apiBaseURL, appClientID, appClientSecret, isMobileApp, isDesktopApp, getHostname } = config;
|
|
75
|
+
const baseURL = "/api";
|
|
76
|
+
const headers = {};
|
|
77
|
+
const visitor = { platform: "web", hostname: getHostname() };
|
|
78
|
+
if (token) {
|
|
79
|
+
headers.authorization = `JWT ${token}`;
|
|
80
|
+
} else if (typeof window !== "undefined" && appClientID && appClientSecret) {
|
|
81
|
+
const credentials = btoa(`${appClientID}:${appClientSecret}`);
|
|
82
|
+
headers.authorization = `Basic ${credentials}`;
|
|
83
|
+
}
|
|
84
|
+
if (isMobileApp) {
|
|
85
|
+
options.baseURL = apiBaseURL;
|
|
86
|
+
visitor.platform = "mobile";
|
|
87
|
+
}
|
|
88
|
+
if (isDesktopApp) {
|
|
89
|
+
options.baseURL = apiBaseURL;
|
|
90
|
+
visitor.platform = "desktop";
|
|
91
|
+
}
|
|
92
|
+
if (typeof window !== "undefined") {
|
|
93
|
+
visitor.hostname = location.hostname;
|
|
94
|
+
}
|
|
95
|
+
const { platform, hostname } = visitor;
|
|
96
|
+
const visitorIdentifier = getVisitor();
|
|
97
|
+
if (visitorIdentifier) {
|
|
98
|
+
const { id, ip, device, appName } = visitorIdentifier;
|
|
99
|
+
headers.visitor = btoa(`${platform}|:|${hostname}|:|${id}|:|${ip}|:|${device}|:|${appName}`);
|
|
100
|
+
} else {
|
|
101
|
+
headers.visitor = btoa(`${platform}|:|${hostname}`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
baseURL,
|
|
105
|
+
...options,
|
|
106
|
+
body: apiHelper.convertToServer(options.body),
|
|
107
|
+
headers: { ...options.headers, ...headers }
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
const fetchRequest = (url, options = {}, fetch, config) => {
|
|
111
|
+
const request = async () => {
|
|
112
|
+
const opts = optionsHandler(options, config);
|
|
113
|
+
try {
|
|
114
|
+
const response = await fetch.raw(url, opts);
|
|
115
|
+
return await successHandler(response, options);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
const { status } = error?.response ?? { status: 500 };
|
|
118
|
+
if (status === 401 && url !== "/account/1/offline") {
|
|
119
|
+
const apiActions = useApiActions();
|
|
120
|
+
await apiActions.value?.refreshToken?.();
|
|
121
|
+
return request();
|
|
122
|
+
}
|
|
123
|
+
throw errorHandler(error);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
return request();
|
|
127
|
+
};
|
|
128
|
+
export const createApiFetch = once((fetch, config) => {
|
|
129
|
+
return (url, options) => fetchRequest(url, options, fetch, config);
|
|
130
|
+
});
|
package/bus.d.ts
ADDED
package/bus.mjs
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Subject } from "rxjs";
|
|
2
|
+
const hasOwnProp = {}.hasOwnProperty;
|
|
3
|
+
let subjects = {};
|
|
4
|
+
export default {
|
|
5
|
+
publish(eventName, data) {
|
|
6
|
+
subjects[eventName] || (subjects[eventName] = new Subject());
|
|
7
|
+
subjects[eventName]?.next(data);
|
|
8
|
+
},
|
|
9
|
+
subscribe(eventName, func) {
|
|
10
|
+
subjects[eventName] || (subjects[eventName] = new Subject());
|
|
11
|
+
return subjects[eventName]?.subscribe(func);
|
|
12
|
+
},
|
|
13
|
+
unsubscribeAll() {
|
|
14
|
+
const _subjects = subjects;
|
|
15
|
+
for (const eventName in _subjects) {
|
|
16
|
+
if (hasOwnProp.call(_subjects, eventName)) {
|
|
17
|
+
_subjects[eventName]?.unsubscribe();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
subjects = {};
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { User } from "./types";
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
wsPublish: (eventName: string, data: unknown) => void;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export declare function newCometClient(user: User, cometServerURL: string): {
|
|
8
|
+
isStarted: boolean;
|
|
9
|
+
start: () => void;
|
|
10
|
+
stop: () => void;
|
|
11
|
+
};
|
package/comet-client.mjs
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Centrifuge } from "centrifuge";
|
|
2
|
+
import { getToken } from "./api-client.mjs";
|
|
3
|
+
import bus from "./bus.mjs";
|
|
4
|
+
import { useApiActions } from "./composables/use-api-actions.mjs";
|
|
5
|
+
import { apiHelper } from "./helpers/index.mjs";
|
|
6
|
+
if (typeof window !== "undefined" && import.meta.env.MODE !== "production") {
|
|
7
|
+
window.wsPublish = (eventName, data) => {
|
|
8
|
+
setTimeout(() => bus.publish(`WS.${eventName}`, data), 0);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function newCometClient(user, cometServerURL) {
|
|
12
|
+
const transports = [
|
|
13
|
+
{
|
|
14
|
+
transport: "websocket",
|
|
15
|
+
endpoint: `wss://${cometServerURL}/connection/websocket`
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
transport: "http_stream",
|
|
19
|
+
endpoint: `https//${cometServerURL}/connection/http_stream`
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
transport: "sse",
|
|
23
|
+
endpoint: `https//${cometServerURL}/connection/sse`
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
const centrifuge = new Centrifuge(transports, {
|
|
27
|
+
token: getToken() ?? "",
|
|
28
|
+
debug: import.meta.env.MODE !== "production",
|
|
29
|
+
getToken: async () => {
|
|
30
|
+
const apiActions = useApiActions();
|
|
31
|
+
return await apiActions.value?.refreshToken?.() ?? "";
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const publish = (eventName, data) => () => {
|
|
35
|
+
bus.publish(`WS.${eventName}`, apiHelper.convertToClient(data));
|
|
36
|
+
};
|
|
37
|
+
let userSubscription;
|
|
38
|
+
return {
|
|
39
|
+
isStarted: false,
|
|
40
|
+
start: () => {
|
|
41
|
+
userSubscription || (userSubscription = centrifuge.newSubscription(`personal:user#${user?.id}`));
|
|
42
|
+
if (userSubscription.state === "subscribed") {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const publicationHandler = (message) => {
|
|
46
|
+
if (message?.data && Array.isArray(message.data)) {
|
|
47
|
+
message.data.forEach((event) => {
|
|
48
|
+
const eventName = event.NotificationName;
|
|
49
|
+
const data = event.Data;
|
|
50
|
+
if (import.meta.env.MODE !== "production") {
|
|
51
|
+
console.log("IO event handled:", eventName, data);
|
|
52
|
+
if (!eventName) {
|
|
53
|
+
console.log(`[${/* @__PURE__ */ new Date()}] Comet: no name event`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
setTimeout(publish(eventName, data), 400);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
userSubscription.on("publication", publicationHandler);
|
|
62
|
+
userSubscription.subscribe();
|
|
63
|
+
centrifuge.connect();
|
|
64
|
+
},
|
|
65
|
+
stop: () => {
|
|
66
|
+
if (userSubscription) {
|
|
67
|
+
userSubscription.unsubscribe();
|
|
68
|
+
userSubscription.removeAllListeners();
|
|
69
|
+
}
|
|
70
|
+
centrifuge.disconnect();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ActiveSession } from "../types";
|
|
2
|
+
export declare function useActiveSessions(): import("vue").Ref<{
|
|
3
|
+
id: string;
|
|
4
|
+
visitorId: string;
|
|
5
|
+
device: string;
|
|
6
|
+
appName: string;
|
|
7
|
+
location: string;
|
|
8
|
+
ipAddress: string;
|
|
9
|
+
isCurrentSession?: boolean | undefined;
|
|
10
|
+
isOnline?: boolean | undefined;
|
|
11
|
+
signedOut?: boolean | undefined;
|
|
12
|
+
dateTime: Date;
|
|
13
|
+
firstSignIn: Date;
|
|
14
|
+
}[], ActiveSession[] | {
|
|
15
|
+
id: string;
|
|
16
|
+
visitorId: string;
|
|
17
|
+
device: string;
|
|
18
|
+
appName: string;
|
|
19
|
+
location: string;
|
|
20
|
+
ipAddress: string;
|
|
21
|
+
isCurrentSession?: boolean | undefined;
|
|
22
|
+
isOnline?: boolean | undefined;
|
|
23
|
+
signedOut?: boolean | undefined;
|
|
24
|
+
dateTime: Date;
|
|
25
|
+
firstSignIn: Date;
|
|
26
|
+
}[]>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import { useUserActions } from "../index.mjs";
|
|
3
|
+
const activeSessions = ref([]);
|
|
4
|
+
export function useActiveSessions() {
|
|
5
|
+
const userActions = useUserActions();
|
|
6
|
+
const fetchActiveSessions = async () => {
|
|
7
|
+
if (activeSessions.value.length === 0) {
|
|
8
|
+
const data = await userActions?.value.fetchActiveSessions();
|
|
9
|
+
activeSessions.value = data?.sessions ?? [];
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
fetchActiveSessions();
|
|
13
|
+
return activeSessions;
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const useApiActions: () => import("vue").Ref<{
|
|
2
|
+
initialized: boolean;
|
|
3
|
+
getVisitorIdentifier?: (() => Promise<void>) | undefined;
|
|
4
|
+
refreshToken?: (() => Promise<string>) | undefined;
|
|
5
|
+
}, {
|
|
6
|
+
initialized: boolean;
|
|
7
|
+
getVisitorIdentifier?: () => Promise<void>;
|
|
8
|
+
refreshToken?: () => Promise<string>;
|
|
9
|
+
} | {
|
|
10
|
+
initialized: boolean;
|
|
11
|
+
getVisitorIdentifier?: (() => Promise<void>) | undefined;
|
|
12
|
+
refreshToken?: (() => Promise<string>) | undefined;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useAppLocale: () => import("@vueuse/shared").RemovableRef<any>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useLocalStorage } from "@vueuse/core";
|
|
2
|
+
export const useAppLocale = () => {
|
|
3
|
+
return useLocalStorage(
|
|
4
|
+
"app-preferences-locale",
|
|
5
|
+
{ value: "en" },
|
|
6
|
+
{
|
|
7
|
+
serializer: {
|
|
8
|
+
read: (v) => v ? JSON.parse(v) : null,
|
|
9
|
+
write: (v) => JSON.stringify(v)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Subscription } from "../bus";
|
|
2
|
+
export declare const useSubscribe: <T>(eventName: string, func: (data: T) => void, options?: {
|
|
3
|
+
once?: boolean;
|
|
4
|
+
unsubscribeOnUnmount?: boolean;
|
|
5
|
+
}) => Subscription | undefined;
|
|
6
|
+
declare const _default: <T>(eventName: string, func: (data: T) => void, options?: {
|
|
7
|
+
once?: boolean;
|
|
8
|
+
unsubscribeOnUnmount?: boolean;
|
|
9
|
+
}) => Subscription | undefined;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { onMounted, onUnmounted } from "vue";
|
|
2
|
+
import bus from "../bus.mjs";
|
|
3
|
+
export const useSubscribe = (eventName, func, options = { once: false, unsubscribeOnUnmount: true }) => {
|
|
4
|
+
let subscription;
|
|
5
|
+
onMounted(() => {
|
|
6
|
+
subscription = bus.subscribe(eventName, (data) => {
|
|
7
|
+
func(data);
|
|
8
|
+
if (options.once) {
|
|
9
|
+
subscription?.unsubscribe();
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
onUnmounted(() => {
|
|
14
|
+
if (options.unsubscribeOnUnmount) {
|
|
15
|
+
subscription?.unsubscribe();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return subscription;
|
|
19
|
+
};
|
|
20
|
+
export default (eventName, func, options) => {
|
|
21
|
+
return useSubscribe(eventName, func, options);
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useThemeMode: () => import("@vueuse/shared").RemovableRef<any>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useLocalStorage, usePreferredDark } from "@vueuse/core";
|
|
2
|
+
export const useThemeMode = () => {
|
|
3
|
+
const isDark = usePreferredDark();
|
|
4
|
+
return useLocalStorage(
|
|
5
|
+
"app-preferences-theme",
|
|
6
|
+
{ value: isDark.value ? "dark" : "light" },
|
|
7
|
+
{
|
|
8
|
+
serializer: {
|
|
9
|
+
read: (v) => v ? JSON.parse(v) : null,
|
|
10
|
+
write: (v) => JSON.stringify(v)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { User } from "../types";
|
|
2
|
+
export declare function useUser(): import("vue").Ref<{
|
|
3
|
+
id: string;
|
|
4
|
+
firstName: string;
|
|
5
|
+
lastName: string;
|
|
6
|
+
middleName: string;
|
|
7
|
+
email: string;
|
|
8
|
+
emailVerified: boolean;
|
|
9
|
+
phone: string;
|
|
10
|
+
phoneVerified: boolean;
|
|
11
|
+
gender: "" | "male" | "female";
|
|
12
|
+
birthday: Date;
|
|
13
|
+
passwordLastSet: Date;
|
|
14
|
+
theme: "light" | "dark";
|
|
15
|
+
locale: string;
|
|
16
|
+
avatar: string;
|
|
17
|
+
} | null | undefined, User | {
|
|
18
|
+
id: string;
|
|
19
|
+
firstName: string;
|
|
20
|
+
lastName: string;
|
|
21
|
+
middleName: string;
|
|
22
|
+
email: string;
|
|
23
|
+
emailVerified: boolean;
|
|
24
|
+
phone: string;
|
|
25
|
+
phoneVerified: boolean;
|
|
26
|
+
gender: "" | "male" | "female";
|
|
27
|
+
birthday: Date;
|
|
28
|
+
passwordLastSet: Date;
|
|
29
|
+
theme: "light" | "dark";
|
|
30
|
+
locale: string;
|
|
31
|
+
avatar: string;
|
|
32
|
+
} | null | undefined>;
|
package/get-user.d.ts
ADDED
package/get-user.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useLocalStorage } from "@vueuse/core";
|
|
2
|
+
import { flush, getToken, setUser } from "./api-client.mjs";
|
|
3
|
+
import { useApiActions } from "./composables/use-api-actions.mjs";
|
|
4
|
+
import { useUser } from "./composables/use-user.mjs";
|
|
5
|
+
import { once } from "./helpers/index.mjs";
|
|
6
|
+
let gettingUserInProgress = false;
|
|
7
|
+
let gettingUserPromise = null;
|
|
8
|
+
function getUser(fetch, config) {
|
|
9
|
+
if (gettingUserInProgress && gettingUserPromise) {
|
|
10
|
+
return gettingUserPromise;
|
|
11
|
+
}
|
|
12
|
+
return gettingUserStart(fetch, config);
|
|
13
|
+
}
|
|
14
|
+
function gettingUserStart(fetch, config) {
|
|
15
|
+
gettingUserInProgress = true;
|
|
16
|
+
gettingUserPromise = getUserRequest(fetch, config).finally(() => {
|
|
17
|
+
gettingUserInProgress = false;
|
|
18
|
+
gettingUserPromise = null;
|
|
19
|
+
});
|
|
20
|
+
return gettingUserPromise;
|
|
21
|
+
}
|
|
22
|
+
async function getUserRequest(fetch, config) {
|
|
23
|
+
const token = getToken();
|
|
24
|
+
const user = useUser();
|
|
25
|
+
if (token && user.value) {
|
|
26
|
+
return { token, user: user.value };
|
|
27
|
+
}
|
|
28
|
+
if (!token) {
|
|
29
|
+
const loggedIn = useLocalStorage("lin", "no");
|
|
30
|
+
if (loggedIn.value !== "yes") {
|
|
31
|
+
flush();
|
|
32
|
+
return { token: null, user: null };
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const apiActions = useApiActions();
|
|
36
|
+
await apiActions.value?.getVisitorIdentifier?.();
|
|
37
|
+
await apiActions.value?.refreshToken?.();
|
|
38
|
+
} catch {
|
|
39
|
+
flush();
|
|
40
|
+
return { token: null, user: null };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const user2 = await fetch("/account", config.useRequestHeaders?.(["cookie", "authorization"]));
|
|
45
|
+
setUser(user2);
|
|
46
|
+
const token2 = getToken();
|
|
47
|
+
return { token: token2, user: user2 };
|
|
48
|
+
} catch {
|
|
49
|
+
flush();
|
|
50
|
+
return { token: null, user: null };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export const createApiGetUser = once((fetch, config) => {
|
|
54
|
+
return () => getUser(fetch, config);
|
|
55
|
+
});
|
package/get-visitor.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FetchConfig } from "./types";
|
|
2
|
+
export declare type Visitor = {
|
|
3
|
+
id?: string;
|
|
4
|
+
ip?: string;
|
|
5
|
+
device?: string;
|
|
6
|
+
appName?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const getVisitorId: () => string | undefined;
|
|
9
|
+
export declare const getVisitor: () => Visitor | null;
|
|
10
|
+
export declare const getVisitorRequest: (config: FetchConfig) => Promise<void>;
|
|
11
|
+
export declare const createApiGetVisitorIdentifier: (config: FetchConfig) => () => Promise<void>;
|
package/get-visitor.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { hashComponents, load } from "@fingerprintjs/fingerprintjs";
|
|
2
|
+
import { ofetch } from "ofetch";
|
|
3
|
+
import { once } from "./helpers/index.mjs";
|
|
4
|
+
let visitor = null;
|
|
5
|
+
export const getVisitorId = () => {
|
|
6
|
+
return visitor?.id;
|
|
7
|
+
};
|
|
8
|
+
export const getVisitor = () => {
|
|
9
|
+
return visitor;
|
|
10
|
+
};
|
|
11
|
+
const setVisitor = (newVisitor) => {
|
|
12
|
+
visitor = !visitor ? newVisitor : { ...visitor, ...newVisitor };
|
|
13
|
+
};
|
|
14
|
+
let gettingInProgress = false;
|
|
15
|
+
let gettingPromise = null;
|
|
16
|
+
function getVisitorIdentifier(config) {
|
|
17
|
+
if (gettingInProgress && gettingPromise) {
|
|
18
|
+
return gettingPromise;
|
|
19
|
+
}
|
|
20
|
+
return gettingVisitorStart(config);
|
|
21
|
+
}
|
|
22
|
+
function gettingVisitorStart(config) {
|
|
23
|
+
gettingInProgress = true;
|
|
24
|
+
gettingPromise = getVisitorRequest(config).finally(() => {
|
|
25
|
+
gettingInProgress = false;
|
|
26
|
+
gettingPromise = null;
|
|
27
|
+
});
|
|
28
|
+
return gettingPromise;
|
|
29
|
+
}
|
|
30
|
+
export const getVisitorRequest = async (config) => {
|
|
31
|
+
if (typeof window === "undefined" || visitor) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const fp = await load();
|
|
35
|
+
const result = await fp.get();
|
|
36
|
+
const { canvas, colorDepth, hdr, languages, screenFrame, screenResolution, ...components } = result.components;
|
|
37
|
+
const id = hashComponents(components);
|
|
38
|
+
const ip = "unknown";
|
|
39
|
+
ofetch("https://api.ipify.org?format=json").then((data) => {
|
|
40
|
+
setVisitor({ ip: data?.ip ?? "unknown" });
|
|
41
|
+
});
|
|
42
|
+
const device = await config.getDevice() || "unknown";
|
|
43
|
+
const appName = config.appName || "unknown";
|
|
44
|
+
setVisitor({ id, ip, device, appName });
|
|
45
|
+
};
|
|
46
|
+
export const createApiGetVisitorIdentifier = once((config) => {
|
|
47
|
+
return () => getVisitorIdentifier(config);
|
|
48
|
+
});
|