@stacksjs/browser 0.70.58 → 0.70.59
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/auto-init.js +61 -0
- package/dist/composables/auth/useGithub.d.ts +12 -0
- package/dist/composables/auth/useGithub.js +41 -0
- package/dist/composables/index.js +110 -0
- package/dist/composables/useApi.js +66 -0
- package/dist/composables/useAuth.js +127 -0
- package/dist/composables/useFetch.d.ts +1 -0
- package/dist/composables/useFetch.js +1 -0
- package/dist/index.js +8 -1548
- package/dist/model-loader.js +61 -0
- package/dist/types/dashboard.js +3 -0
- package/dist/utils/base.js +4 -0
- package/dist/utils/billable.js +64 -0
- package/dist/utils/date.js +2 -0
- package/dist/utils/debounce.js +43 -0
- package/dist/utils/fetch.js +94 -0
- package/dist/utils/function.js +7 -0
- package/dist/utils/guards.js +12 -0
- package/dist/utils/index.js +17 -0
- package/dist/utils/lazy.js +9 -0
- package/dist/utils/math.js +23 -0
- package/dist/utils/plans.js +135 -0
- package/dist/utils/promise.js +55 -0
- package/dist/utils/random.js +67 -0
- package/dist/utils/regex.js +29 -0
- package/dist/utils/retry.js +28 -0
- package/dist/utils/sleep.js +59 -0
- package/dist/utils/throttle.js +18 -0
- package/dist/utils/vendors.js +37 -0
- package/package.json +3 -3
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
browserQuery,
|
|
3
|
+
BrowserQueryBuilder,
|
|
4
|
+
BrowserQueryError,
|
|
5
|
+
browserAuth,
|
|
6
|
+
configureBrowser,
|
|
7
|
+
getBrowserConfig,
|
|
8
|
+
createBrowserDb,
|
|
9
|
+
createBrowserModel,
|
|
10
|
+
isBrowser
|
|
11
|
+
} from "bun-query-builder/browser";
|
|
12
|
+
import * as Composables from "./composables";
|
|
13
|
+
import { loadBrowserModels } from "./model-loader";
|
|
14
|
+
let isInitialized = !1;
|
|
15
|
+
function autoInit() {
|
|
16
|
+
if (isInitialized)
|
|
17
|
+
return;
|
|
18
|
+
if (typeof window > "u")
|
|
19
|
+
return;
|
|
20
|
+
if (typeof document > "u")
|
|
21
|
+
return;
|
|
22
|
+
isInitialized = !0;
|
|
23
|
+
const baseUrl = window.__STACKS_API_URL__ || `${window.location.origin}/api`;
|
|
24
|
+
configureBrowser({
|
|
25
|
+
baseUrl,
|
|
26
|
+
getToken: () => {
|
|
27
|
+
try {
|
|
28
|
+
return localStorage.getItem("token");
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
onUnauthorized: () => {
|
|
34
|
+
const loginUrl = window.__STACKS_LOGIN_URL__ || "/login";
|
|
35
|
+
if (!window.location.pathname.startsWith(loginUrl))
|
|
36
|
+
window.location.href = loginUrl;
|
|
37
|
+
},
|
|
38
|
+
transformResponse: (data) => {
|
|
39
|
+
return data?.data ?? data;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
window.StacksBrowser = {
|
|
43
|
+
browserQuery,
|
|
44
|
+
BrowserQueryBuilder,
|
|
45
|
+
BrowserQueryError,
|
|
46
|
+
browserAuth,
|
|
47
|
+
configureBrowser,
|
|
48
|
+
getBrowserConfig,
|
|
49
|
+
createBrowserDb,
|
|
50
|
+
createBrowserModel,
|
|
51
|
+
isBrowser,
|
|
52
|
+
...Composables
|
|
53
|
+
};
|
|
54
|
+
loadBrowserModels();
|
|
55
|
+
window.dispatchEvent(new CustomEvent("stacks:api-ready"));
|
|
56
|
+
if (window.__STACKS_DEBUG__)
|
|
57
|
+
console.debug("[Stacks] Browser API initialized:", baseUrl);
|
|
58
|
+
}
|
|
59
|
+
autoInit();
|
|
60
|
+
|
|
61
|
+
export { autoInit, isInitialized };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Ref } from '@stacksjs/stx';
|
|
2
|
+
export declare function useGitHubOAuth(): GitHubOAuthReturn;
|
|
3
|
+
declare interface GitHubOAuthReturn {
|
|
4
|
+
login: () => void
|
|
5
|
+
accessToken: Ref<string | null>
|
|
6
|
+
error: Ref<string | null>
|
|
7
|
+
isLoading: Ref<boolean>
|
|
8
|
+
}
|
|
9
|
+
// @ts-ignore - Window.location override
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {}
|
|
12
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { onMounted, ref } from "@stacksjs/stx";
|
|
2
|
+
export function useGitHubOAuth() {
|
|
3
|
+
const stacksConfig = window.__STACKS_CONFIG__ || {}, clientId = stacksConfig.GITHUB_CLIENT_ID || "", redirectUri = `${stacksConfig.APP_URL || window.location.origin}/auth/github/callback`, accessToken = ref(null), error = ref(null), isLoading = ref(!1);
|
|
4
|
+
function login() {
|
|
5
|
+
const githubAuthUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=read:user user:email`;
|
|
6
|
+
window.location.href = githubAuthUrl;
|
|
7
|
+
}
|
|
8
|
+
async function fetchAccessToken(code) {
|
|
9
|
+
isLoading.value = !0;
|
|
10
|
+
error.value = null;
|
|
11
|
+
try {
|
|
12
|
+
const apiUrl = stacksConfig.APP_URL || window.location.origin, res = await fetch(`${apiUrl}/api/github/token`, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: { "Content-Type": "application/json" },
|
|
15
|
+
body: JSON.stringify({ code })
|
|
16
|
+
});
|
|
17
|
+
if (!res.ok)
|
|
18
|
+
throw Error("Failed to exchange code for access token");
|
|
19
|
+
const data = await res.json();
|
|
20
|
+
accessToken.value = data.access_token;
|
|
21
|
+
} catch (err) {
|
|
22
|
+
error.value = err.message || "Unknown error";
|
|
23
|
+
} finally {
|
|
24
|
+
isLoading.value = !1;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function handleCallback() {
|
|
28
|
+
const code = new URLSearchParams(window.location.search).get("code");
|
|
29
|
+
if (code)
|
|
30
|
+
fetchAccessToken(code);
|
|
31
|
+
}
|
|
32
|
+
onMounted(() => {
|
|
33
|
+
handleCallback();
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
login,
|
|
37
|
+
accessToken,
|
|
38
|
+
error,
|
|
39
|
+
isLoading
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export * from "./useAuth";
|
|
2
|
+
export * from "./useApi";
|
|
3
|
+
export {
|
|
4
|
+
useColorMode,
|
|
5
|
+
useDark,
|
|
6
|
+
usePreferredColorScheme,
|
|
7
|
+
usePreferredContrast,
|
|
8
|
+
usePreferredDark,
|
|
9
|
+
usePreferredReducedMotion,
|
|
10
|
+
useDateFormat,
|
|
11
|
+
useNow,
|
|
12
|
+
useTimeAgo,
|
|
13
|
+
useTimestamp,
|
|
14
|
+
useFetch,
|
|
15
|
+
useNetwork,
|
|
16
|
+
useOnline,
|
|
17
|
+
useLocalStorage,
|
|
18
|
+
useSessionStorage,
|
|
19
|
+
useStorage,
|
|
20
|
+
useToggle,
|
|
21
|
+
useCounter,
|
|
22
|
+
useStepper,
|
|
23
|
+
useCycleList,
|
|
24
|
+
useActiveElement,
|
|
25
|
+
useClipboard,
|
|
26
|
+
useClipboardItems,
|
|
27
|
+
useCssVar,
|
|
28
|
+
useDocumentVisibility,
|
|
29
|
+
useElementBounding,
|
|
30
|
+
useElementHover,
|
|
31
|
+
useElementSize,
|
|
32
|
+
useElementVisibility,
|
|
33
|
+
useFocus,
|
|
34
|
+
useFocusWithin,
|
|
35
|
+
useFullscreen,
|
|
36
|
+
useScroll,
|
|
37
|
+
useScrollLock,
|
|
38
|
+
useTitle,
|
|
39
|
+
useWindowFocus,
|
|
40
|
+
useWindowScroll,
|
|
41
|
+
useWindowSize,
|
|
42
|
+
onClickOutside,
|
|
43
|
+
onKeyDown,
|
|
44
|
+
onKeyStroke,
|
|
45
|
+
onKeyUp,
|
|
46
|
+
onLongPress,
|
|
47
|
+
onStartTyping,
|
|
48
|
+
useEventListener,
|
|
49
|
+
useKeyModifier,
|
|
50
|
+
useMagicKeys,
|
|
51
|
+
useDraggable,
|
|
52
|
+
useDropZone,
|
|
53
|
+
useMouse,
|
|
54
|
+
useMouseInElement,
|
|
55
|
+
useMousePressed,
|
|
56
|
+
usePointer,
|
|
57
|
+
usePointerSwipe,
|
|
58
|
+
useSwipe,
|
|
59
|
+
useBattery,
|
|
60
|
+
useDeviceMotion,
|
|
61
|
+
useDeviceOrientation,
|
|
62
|
+
useDevicePixelRatio,
|
|
63
|
+
useGeolocation,
|
|
64
|
+
useBreakpoints,
|
|
65
|
+
useMediaQuery,
|
|
66
|
+
breakpointsTailwind,
|
|
67
|
+
breakpointsBootstrapV5,
|
|
68
|
+
useBrowserLocation,
|
|
69
|
+
useIdle,
|
|
70
|
+
useInfiniteScroll,
|
|
71
|
+
useNavigatorLanguage,
|
|
72
|
+
usePageLeave,
|
|
73
|
+
usePreferredLanguages,
|
|
74
|
+
useScreenOrientation,
|
|
75
|
+
useTextDirection,
|
|
76
|
+
useTextSelection,
|
|
77
|
+
useUrlSearchParams,
|
|
78
|
+
useDebounceFn,
|
|
79
|
+
useInterval,
|
|
80
|
+
useIntervalFn,
|
|
81
|
+
useRafFn,
|
|
82
|
+
useThrottleFn,
|
|
83
|
+
useTimeout,
|
|
84
|
+
useTimeoutFn,
|
|
85
|
+
useTimeoutPoll,
|
|
86
|
+
useAnimate,
|
|
87
|
+
useTransition,
|
|
88
|
+
TransitionPresets,
|
|
89
|
+
useBase64,
|
|
90
|
+
useBroadcastChannel,
|
|
91
|
+
useConfirmDialog,
|
|
92
|
+
useEventBus,
|
|
93
|
+
useEventSource,
|
|
94
|
+
useEyeDropper,
|
|
95
|
+
useFavicon,
|
|
96
|
+
useFileDialog,
|
|
97
|
+
useImage,
|
|
98
|
+
useObjectUrl,
|
|
99
|
+
usePermission,
|
|
100
|
+
useShare,
|
|
101
|
+
useVibrate,
|
|
102
|
+
useWakeLock,
|
|
103
|
+
useWebNotification,
|
|
104
|
+
useWebSocket,
|
|
105
|
+
useWebWorker,
|
|
106
|
+
useWebWorkerFn,
|
|
107
|
+
useSupported,
|
|
108
|
+
useMemoize,
|
|
109
|
+
useMounted
|
|
110
|
+
} from "@stacksjs/composables";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { configureBrowser, browserAuth } from "bun-query-builder/browser";
|
|
2
|
+
export function initApi(options) {
|
|
3
|
+
const stacksConfig = globalThis.__STACKS_CONFIG__ || {}, baseUrl = options?.baseUrl || (typeof window < "u" ? `${window.location.origin}/api` : `http://localhost:${process.env.PORT_API || "3008"}/api`);
|
|
4
|
+
configureBrowser({
|
|
5
|
+
baseUrl,
|
|
6
|
+
getToken: () => {
|
|
7
|
+
if (typeof localStorage < "u")
|
|
8
|
+
return localStorage.getItem("token");
|
|
9
|
+
return null;
|
|
10
|
+
},
|
|
11
|
+
onUnauthorized: options?.onUnauthorized || (() => {
|
|
12
|
+
if (typeof window < "u")
|
|
13
|
+
window.location.href = "/login";
|
|
14
|
+
}),
|
|
15
|
+
transformResponse: (data) => {
|
|
16
|
+
return data?.data ?? data;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export const auth = browserAuth;
|
|
21
|
+
export function formatAreaSize(sqMeters) {
|
|
22
|
+
if (sqMeters >= 1e6)
|
|
23
|
+
return `${(sqMeters / 1e6).toFixed(2)} km\xB2`;
|
|
24
|
+
if (sqMeters >= 1e4)
|
|
25
|
+
return `${(sqMeters / 1e4).toFixed(2)} ha`;
|
|
26
|
+
return `${sqMeters.toLocaleString()} m\xB2`;
|
|
27
|
+
}
|
|
28
|
+
export function formatDistance(miles) {
|
|
29
|
+
return `${miles.toFixed(1)} mi`;
|
|
30
|
+
}
|
|
31
|
+
export function formatElevation(feet) {
|
|
32
|
+
return `${feet.toLocaleString()} ft`;
|
|
33
|
+
}
|
|
34
|
+
export function formatDuration(seconds) {
|
|
35
|
+
const hours = Math.floor(seconds / 3600), minutes = Math.floor(seconds % 3600 / 60), secs = seconds % 60;
|
|
36
|
+
if (hours > 0)
|
|
37
|
+
return `${hours}h ${minutes}m`;
|
|
38
|
+
if (minutes > 0)
|
|
39
|
+
return `${minutes}m ${secs}s`;
|
|
40
|
+
return `${secs}s`;
|
|
41
|
+
}
|
|
42
|
+
export function getRelativeTime(dateString) {
|
|
43
|
+
const date = new Date(dateString), diffMs = new Date().getTime() - date.getTime(), diffSeconds = Math.floor(diffMs / 1000), diffMinutes = Math.floor(diffSeconds / 60), diffHours = Math.floor(diffMinutes / 60), diffDays = Math.floor(diffHours / 24), diffWeeks = Math.floor(diffDays / 7);
|
|
44
|
+
if (diffSeconds < 60)
|
|
45
|
+
return "just now";
|
|
46
|
+
if (diffMinutes < 60)
|
|
47
|
+
return `${diffMinutes} minute${diffMinutes === 1 ? "" : "s"} ago`;
|
|
48
|
+
if (diffHours < 24)
|
|
49
|
+
return `${diffHours} hour${diffHours === 1 ? "" : "s"} ago`;
|
|
50
|
+
if (diffDays < 7)
|
|
51
|
+
return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
|
|
52
|
+
if (diffWeeks < 4)
|
|
53
|
+
return `${diffWeeks} week${diffWeeks === 1 ? "" : "s"} ago`;
|
|
54
|
+
return date.toLocaleDateString();
|
|
55
|
+
}
|
|
56
|
+
export async function fetchData(fetcher, options) {
|
|
57
|
+
try {
|
|
58
|
+
return await fetcher();
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (options?.onError)
|
|
61
|
+
options.onError(error);
|
|
62
|
+
else
|
|
63
|
+
console.error("API Error:", error);
|
|
64
|
+
return options?.fallback;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { useStorage } from "@stacksjs/composables";
|
|
2
|
+
import { ref } from "@stacksjs/stx";
|
|
3
|
+
const token = useStorage("token", ""), stacksConfig = globalThis.__STACKS_CONFIG__ || {}, baseUrl = stacksConfig.API_URL || (typeof window < "u" ? window.location.origin : `http://localhost:${process.env.PORT_API || "3008"}`), user = ref(null), isAuthenticated = ref(!1);
|
|
4
|
+
export function useAuth() {
|
|
5
|
+
async function fetchAuthUser() {
|
|
6
|
+
try {
|
|
7
|
+
if (!token.value) {
|
|
8
|
+
isAuthenticated.value = !1;
|
|
9
|
+
user.value = null;
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const response = await fetch(`${baseUrl}/me`, {
|
|
13
|
+
headers: {
|
|
14
|
+
Authorization: `Bearer ${token.value}`,
|
|
15
|
+
Accept: "application/json"
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
token.value = "";
|
|
20
|
+
isAuthenticated.value = !1;
|
|
21
|
+
user.value = null;
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const data = await response.json();
|
|
25
|
+
user.value = data;
|
|
26
|
+
isAuthenticated.value = !0;
|
|
27
|
+
return data;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error("Error fetching user:", error);
|
|
30
|
+
token.value = "";
|
|
31
|
+
isAuthenticated.value = !1;
|
|
32
|
+
user.value = null;
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function checkAuthentication() {
|
|
37
|
+
try {
|
|
38
|
+
return await fetchAuthUser() !== null;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error("Error checking authentication:", error);
|
|
41
|
+
return !1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function register(user) {
|
|
45
|
+
const url = `${baseUrl}/register`, data = await (await fetch(url, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"Content-Type": "application/json"
|
|
49
|
+
},
|
|
50
|
+
body: JSON.stringify(user)
|
|
51
|
+
})).json();
|
|
52
|
+
if (isRegisterError(data))
|
|
53
|
+
return data;
|
|
54
|
+
if (isRegisterResponse(data)) {
|
|
55
|
+
token.value = data.token;
|
|
56
|
+
return data;
|
|
57
|
+
}
|
|
58
|
+
return data;
|
|
59
|
+
}
|
|
60
|
+
function isRegisterError(data) {
|
|
61
|
+
return "errors" in data;
|
|
62
|
+
}
|
|
63
|
+
function isRegisterResponse(data) {
|
|
64
|
+
return "token" in data && "user" in data;
|
|
65
|
+
}
|
|
66
|
+
async function login(user) {
|
|
67
|
+
try {
|
|
68
|
+
const url = `${baseUrl}/login`, response = await fetch(url, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: {
|
|
71
|
+
"Content-Type": "application/json"
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify(user)
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const errorData = await response.json();
|
|
77
|
+
throw Error(errorData.message || `HTTP error! status: ${response.status}`);
|
|
78
|
+
}
|
|
79
|
+
const data = await response.json();
|
|
80
|
+
token.value = data.token;
|
|
81
|
+
await fetchAuthUser();
|
|
82
|
+
return data;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
return error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function logout() {
|
|
88
|
+
try {
|
|
89
|
+
const currentToken = token.value;
|
|
90
|
+
if (currentToken)
|
|
91
|
+
await fetch(`${baseUrl}/logout`, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: {
|
|
94
|
+
Authorization: `Bearer ${currentToken}`,
|
|
95
|
+
Accept: "application/json"
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error("Error during logout:", error);
|
|
100
|
+
} finally {
|
|
101
|
+
token.value = "";
|
|
102
|
+
user.value = null;
|
|
103
|
+
isAuthenticated.value = !1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
user,
|
|
108
|
+
isAuthenticated,
|
|
109
|
+
token,
|
|
110
|
+
getToken: () => token.value,
|
|
111
|
+
register,
|
|
112
|
+
login,
|
|
113
|
+
logout,
|
|
114
|
+
fetchAuthUser,
|
|
115
|
+
checkAuthentication
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export function authGuard(options = {}) {
|
|
119
|
+
const guest = options.guest ?? !1, { isAuthenticated } = useAuth();
|
|
120
|
+
if (guest) {
|
|
121
|
+
if (isAuthenticated.value)
|
|
122
|
+
window.location.replace("/");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (!isAuthenticated.value)
|
|
126
|
+
window.location.replace("/login");
|
|
127
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFetch } from '@stacksjs/composables';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFetch } from "@stacksjs/composables";
|