@tthr/vue 0.0.88 → 0.0.89
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/nuxt/module.js +1 -0
- package/nuxt/module.ts +10 -0
- package/nuxt/runtime/composables.ts +48 -0
- package/nuxt/runtime/plugin.client.ts +7 -2
- package/package.json +1 -1
package/nuxt/module.js
CHANGED
|
@@ -60,6 +60,7 @@ export default defineNuxtModule({
|
|
|
60
60
|
nuxt.options.runtimeConfig.public.tether = {
|
|
61
61
|
projectId,
|
|
62
62
|
wsUrl,
|
|
63
|
+
auth: options.auth || null,
|
|
63
64
|
};
|
|
64
65
|
// Add server API routes for proxying Tether requests
|
|
65
66
|
// Use .js — Nitro's rollup can't parse .ts from node_modules
|
package/nuxt/module.ts
CHANGED
|
@@ -21,6 +21,13 @@
|
|
|
21
21
|
|
|
22
22
|
import { defineNuxtModule, addPlugin, createResolver, addImports, addComponent, addServerHandler, addServerImports } from '@nuxt/kit';
|
|
23
23
|
|
|
24
|
+
export interface TetherAuthOptions {
|
|
25
|
+
/** Where to read the auth token from */
|
|
26
|
+
mode: 'localstorage' | 'cookie';
|
|
27
|
+
/** The localStorage key or cookie name to read the token from */
|
|
28
|
+
key: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
24
31
|
export interface TetherModuleOptions {
|
|
25
32
|
/** Project ID from Tether dashboard */
|
|
26
33
|
projectId?: string;
|
|
@@ -28,6 +35,8 @@ export interface TetherModuleOptions {
|
|
|
28
35
|
url?: string;
|
|
29
36
|
/** Enable verbose logging for debugging WebSocket connections */
|
|
30
37
|
verbose?: boolean;
|
|
38
|
+
/** Auth token configuration — attaches the token to all tether requests */
|
|
39
|
+
auth?: TetherAuthOptions;
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
export default defineNuxtModule<TetherModuleOptions>({
|
|
@@ -75,6 +84,7 @@ export default defineNuxtModule<TetherModuleOptions>({
|
|
|
75
84
|
(nuxt.options.runtimeConfig.public as any).tether = {
|
|
76
85
|
projectId,
|
|
77
86
|
wsUrl,
|
|
87
|
+
auth: options.auth || null,
|
|
78
88
|
};
|
|
79
89
|
|
|
80
90
|
// Add server API routes for proxying Tether requests
|
|
@@ -25,6 +25,50 @@ function toPlainArgs<T>(value: T): T {
|
|
|
25
25
|
return out as T;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Read auth token from the configured source and return as headers.
|
|
30
|
+
* Returns empty object if no auth is configured or no token is found.
|
|
31
|
+
*
|
|
32
|
+
* For localStorage mode, the key supports dot-notation to read nested
|
|
33
|
+
* values from JSON objects, e.g. 'strands_oauth_session.accessToken'
|
|
34
|
+
* reads localStorage key 'strands_oauth_session', parses it as JSON,
|
|
35
|
+
* then accesses the 'accessToken' property.
|
|
36
|
+
*/
|
|
37
|
+
function getAuthHeaders(): Record<string, string> {
|
|
38
|
+
if (typeof window === 'undefined') return {};
|
|
39
|
+
const config = (window as any).__TETHER_CONFIG__;
|
|
40
|
+
if (!config?.auth) return {};
|
|
41
|
+
|
|
42
|
+
const { mode, key } = config.auth;
|
|
43
|
+
let token: string | null = null;
|
|
44
|
+
|
|
45
|
+
if (mode === 'localstorage') {
|
|
46
|
+
const parts = key.split('.');
|
|
47
|
+
const storageKey = parts[0];
|
|
48
|
+
const raw = localStorage.getItem(storageKey);
|
|
49
|
+
if (raw && parts.length > 1) {
|
|
50
|
+
try {
|
|
51
|
+
let value: unknown = JSON.parse(raw);
|
|
52
|
+
for (let i = 1; i < parts.length; i++) {
|
|
53
|
+
value = (value as Record<string, unknown>)?.[parts[i]];
|
|
54
|
+
}
|
|
55
|
+
token = typeof value === 'string' ? value : null;
|
|
56
|
+
} catch {
|
|
57
|
+
token = null;
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
token = raw;
|
|
61
|
+
}
|
|
62
|
+
} else if (mode === 'cookie') {
|
|
63
|
+
const cookieKey = key.split('.')[0];
|
|
64
|
+
const match = document.cookie.match(new RegExp(`(?:^|;\\s*)${cookieKey}=([^;]*)`));
|
|
65
|
+
token = match ? decodeURIComponent(match[1]) : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!token) return {};
|
|
69
|
+
return { Authorization: `Bearer ${token}` };
|
|
70
|
+
}
|
|
71
|
+
|
|
28
72
|
// ============================================================================
|
|
29
73
|
// Shared WebSocket Connection Manager
|
|
30
74
|
// ============================================================================
|
|
@@ -309,6 +353,7 @@ export function useQuery<TArgs, TResult>(
|
|
|
309
353
|
async () => {
|
|
310
354
|
const response = await $fetch<{ data: TResult }>('/api/_tether/query', {
|
|
311
355
|
method: 'POST',
|
|
356
|
+
headers: getAuthHeaders(),
|
|
312
357
|
body: {
|
|
313
358
|
function: queryName,
|
|
314
359
|
args: plainArgs,
|
|
@@ -429,6 +474,7 @@ export async function $query<TArgs, TResult>(
|
|
|
429
474
|
|
|
430
475
|
const response = await $fetch<{ data: TResult }>('/api/_tether/query', {
|
|
431
476
|
method: 'POST',
|
|
477
|
+
headers: getAuthHeaders(),
|
|
432
478
|
body: {
|
|
433
479
|
function: queryName,
|
|
434
480
|
args: plainArgs,
|
|
@@ -492,6 +538,7 @@ export function useMutation<TArgs, TResult>(
|
|
|
492
538
|
|
|
493
539
|
const response = await $fetch<{ data: TResult }>('/api/_tether/mutation', {
|
|
494
540
|
method: 'POST',
|
|
541
|
+
headers: getAuthHeaders(),
|
|
495
542
|
body: {
|
|
496
543
|
function: mutationName,
|
|
497
544
|
args: toPlainArgs(args),
|
|
@@ -555,6 +602,7 @@ export async function $mutation<TArgs, TResult>(
|
|
|
555
602
|
|
|
556
603
|
const response = await $fetch<{ data: TResult }>('/api/_tether/mutation', {
|
|
557
604
|
method: 'POST',
|
|
605
|
+
headers: getAuthHeaders(),
|
|
558
606
|
body: {
|
|
559
607
|
function: mutationName,
|
|
560
608
|
args: plainArgs,
|
|
@@ -12,6 +12,10 @@ declare global {
|
|
|
12
12
|
__TETHER_CONFIG__?: {
|
|
13
13
|
projectId: string;
|
|
14
14
|
wsUrl: string;
|
|
15
|
+
auth?: {
|
|
16
|
+
mode: 'localstorage' | 'cookie';
|
|
17
|
+
key: string;
|
|
18
|
+
} | null;
|
|
15
19
|
};
|
|
16
20
|
}
|
|
17
21
|
}
|
|
@@ -19,11 +23,12 @@ declare global {
|
|
|
19
23
|
export default defineNuxtPlugin(() => {
|
|
20
24
|
const config = useRuntimeConfig();
|
|
21
25
|
|
|
22
|
-
// Make config available for WebSocket connections
|
|
23
|
-
// This is safe - no secrets are exposed
|
|
26
|
+
// Make config available for WebSocket connections and auth
|
|
27
|
+
// This is safe - no secrets are exposed (just mode + key name)
|
|
24
28
|
const tetherConfig = {
|
|
25
29
|
projectId: config.public.tether?.projectId || '',
|
|
26
30
|
wsUrl: config.public.tether?.wsUrl || '',
|
|
31
|
+
auth: config.public.tether?.auth || null,
|
|
27
32
|
};
|
|
28
33
|
|
|
29
34
|
window.__TETHER_CONFIG__ = tetherConfig;
|