@tthr/vue 0.0.1 → 0.0.3
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/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/nuxt.d.ts +14 -0
- package/dist/nuxt.d.ts.map +1 -0
- package/dist/nuxt.js +48 -0
- package/dist/nuxt.js.map +1 -0
- package/dist/runtime/composables.d.ts +73 -0
- package/dist/runtime/composables.d.ts.map +1 -0
- package/dist/runtime/composables.js +112 -0
- package/dist/runtime/composables.js.map +1 -0
- package/dist/runtime/plugin.d.ts +11 -0
- package/dist/runtime/plugin.d.ts.map +1 -0
- package/dist/runtime/plugin.js +33 -0
- package/dist/runtime/plugin.js.map +1 -0
- package/nuxt/module.ts +76 -0
- package/nuxt/runtime/components/TetherWelcome.vue +467 -0
- package/nuxt/runtime/composables.ts +170 -0
- package/nuxt/runtime/plugin.ts +33 -0
- package/package.json +8 -3
package/dist/index.d.ts
CHANGED
|
@@ -81,4 +81,24 @@ export interface MutationFunction<TArgs = void, TResult = unknown> {
|
|
|
81
81
|
*/
|
|
82
82
|
export declare function useMutation<TArgs, TResult>(mutation: MutationFunction<TArgs, TResult>): MutationState<TArgs, TResult>;
|
|
83
83
|
export type { TetherClientOptions } from '@tthr/client';
|
|
84
|
+
/**
|
|
85
|
+
* Tether Nuxt/Vue project configuration
|
|
86
|
+
*/
|
|
87
|
+
export interface TetherConfig {
|
|
88
|
+
/** Project ID from Tether dashboard */
|
|
89
|
+
projectId?: string;
|
|
90
|
+
/** API endpoint (defaults to Tether Cloud) */
|
|
91
|
+
url?: string;
|
|
92
|
+
/** Path to schema file */
|
|
93
|
+
schema?: string;
|
|
94
|
+
/** Path to functions directory */
|
|
95
|
+
functions?: string;
|
|
96
|
+
/** Path for generated types output */
|
|
97
|
+
output?: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Define Tether project configuration
|
|
101
|
+
* Used in tether.config.ts at the project root
|
|
102
|
+
*/
|
|
103
|
+
export declare function defineConfig(config: TetherConfig): TetherConfig;
|
|
84
104
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAA+B,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAKtE;;GAEG;AACH,eAAO,MAAM,YAAY;iBACV,GAAG,WAAW,mBAAmB;uBAK3B,mBAAmB;CAGvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAKxC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzB,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EACrC,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,EACpC,IAAI,CAAC,EAAE,KAAK,GACX,UAAU,CAAC,OAAO,CAAC,CA4CrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO;IAC3C,IAAI,EAAE,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC/B,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EACxC,QAAQ,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,GACzC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAmC/B;AAGD,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAA+B,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAKtE;;GAEG;AACH,eAAO,MAAM,YAAY;iBACV,GAAG,WAAW,mBAAmB;uBAK3B,mBAAmB;CAGvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAKxC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzB,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EACrC,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,EACpC,IAAI,CAAC,EAAE,KAAK,GACX,UAAU,CAAC,OAAO,CAAC,CA4CrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO;IAC3C,IAAI,EAAE,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC/B,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EACxC,QAAQ,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,GACzC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAmC/B;AAGD,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAE/D"}
|
package/dist/index.js
CHANGED
|
@@ -129,4 +129,11 @@ export function useMutation(mutation) {
|
|
|
129
129
|
reset,
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Define Tether project configuration
|
|
134
|
+
* Used in tether.config.ts at the project root
|
|
135
|
+
*/
|
|
136
|
+
export function defineConfig(config) {
|
|
137
|
+
return config;
|
|
138
|
+
}
|
|
132
139
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/nuxt.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tthr/vue/nuxt - Tether Nuxt Module
|
|
3
|
+
*
|
|
4
|
+
* Automatically configures Tether for Nuxt applications.
|
|
5
|
+
*/
|
|
6
|
+
export interface TetherModuleOptions {
|
|
7
|
+
/** Project ID from Tether dashboard */
|
|
8
|
+
projectId?: string;
|
|
9
|
+
/** API endpoint (defaults to Tether Cloud) */
|
|
10
|
+
url?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const _default: import("@nuxt/schema").NuxtModule<TetherModuleOptions, TetherModuleOptions, false>;
|
|
13
|
+
export default _default;
|
|
14
|
+
//# sourceMappingURL=nuxt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuxt.d.ts","sourceRoot":"","sources":["../src/nuxt.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;;AAED,wBA2CG"}
|
package/dist/nuxt.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tthr/vue/nuxt - Tether Nuxt Module
|
|
3
|
+
*
|
|
4
|
+
* Automatically configures Tether for Nuxt applications.
|
|
5
|
+
*/
|
|
6
|
+
import { defineNuxtModule, addPlugin, createResolver, addImports } from '@nuxt/kit';
|
|
7
|
+
export default defineNuxtModule({
|
|
8
|
+
meta: {
|
|
9
|
+
name: '@tthr/vue',
|
|
10
|
+
configKey: 'tether',
|
|
11
|
+
compatibility: {
|
|
12
|
+
nuxt: '>=3.0.0',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaults: {
|
|
16
|
+
projectId: undefined,
|
|
17
|
+
url: undefined,
|
|
18
|
+
},
|
|
19
|
+
setup(options, nuxt) {
|
|
20
|
+
const resolver = createResolver(import.meta.url);
|
|
21
|
+
// Add runtime config
|
|
22
|
+
nuxt.options.runtimeConfig.public.tether = {
|
|
23
|
+
projectId: options.projectId || '',
|
|
24
|
+
url: options.url || 'https://api.tether.strands.gg',
|
|
25
|
+
};
|
|
26
|
+
// Add the plugin that initialises Tether
|
|
27
|
+
addPlugin({
|
|
28
|
+
src: resolver.resolve('./runtime/plugin'),
|
|
29
|
+
mode: 'client',
|
|
30
|
+
});
|
|
31
|
+
// Auto-import composables
|
|
32
|
+
addImports([
|
|
33
|
+
{
|
|
34
|
+
name: 'useQuery',
|
|
35
|
+
from: resolver.resolve('./runtime/composables'),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'useMutation',
|
|
39
|
+
from: resolver.resolve('./runtime/composables'),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'useTether',
|
|
43
|
+
from: resolver.resolve('./runtime/composables'),
|
|
44
|
+
},
|
|
45
|
+
]);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=nuxt.js.map
|
package/dist/nuxt.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuxt.js","sourceRoot":"","sources":["../src/nuxt.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AASpF,eAAe,gBAAgB,CAAsB;IACnD,IAAI,EAAE;QACJ,IAAI,EAAE,WAAW;QACjB,SAAS,EAAE,QAAQ;QACnB,aAAa,EAAE;YACb,IAAI,EAAE,SAAS;SAChB;KACF;IACD,QAAQ,EAAE;QACR,SAAS,EAAE,SAAS;QACpB,GAAG,EAAE,SAAS;KACf;IACD,KAAK,CAAC,OAAO,EAAE,IAAI;QACjB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEjD,qBAAqB;QACrB,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,GAAG;YACzC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;YAClC,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,+BAA+B;SACpD,CAAC;QAEF,yCAAyC;QACzC,SAAS,CAAC;YACR,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,kBAAkB,CAAC;YACzC,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;QAEH,0BAA0B;QAC1B,UAAU,CAAC;YACT;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,uBAAuB,CAAC;aAChD;YACD;gBACE,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,uBAAuB,CAAC;aAChD;YACD;gBACE,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,uBAAuB,CAAC;aAChD;SACF,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt composables for Tether
|
|
3
|
+
*
|
|
4
|
+
* These are auto-imported when using the Tether Nuxt module.
|
|
5
|
+
*/
|
|
6
|
+
import { type Ref } from 'vue';
|
|
7
|
+
import type { TetherClient } from '@tthr/client';
|
|
8
|
+
/**
|
|
9
|
+
* Get the Tether client instance
|
|
10
|
+
*/
|
|
11
|
+
export declare function useTether(): TetherClient;
|
|
12
|
+
/**
|
|
13
|
+
* Query state returned by useQuery
|
|
14
|
+
*/
|
|
15
|
+
export interface QueryState<T> {
|
|
16
|
+
data: Ref<T | undefined>;
|
|
17
|
+
error: Ref<Error | null>;
|
|
18
|
+
isLoading: Ref<boolean>;
|
|
19
|
+
refetch: () => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Query function reference
|
|
23
|
+
*/
|
|
24
|
+
export interface QueryFunction<TArgs = void, TResult = unknown> {
|
|
25
|
+
_name: string;
|
|
26
|
+
_args?: TArgs;
|
|
27
|
+
_result?: TResult;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Reactive query composable with auto-subscription
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```vue
|
|
34
|
+
* <script setup>
|
|
35
|
+
* const { data: posts, isLoading } = useQuery(api.posts.list);
|
|
36
|
+
* </script>
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function useQuery<TArgs, TResult>(query: QueryFunction<TArgs, TResult>, args?: TArgs): QueryState<TResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Mutation state returned by useMutation
|
|
42
|
+
*/
|
|
43
|
+
export interface MutationState<TArgs, TResult> {
|
|
44
|
+
data: Ref<TResult | undefined>;
|
|
45
|
+
error: Ref<Error | null>;
|
|
46
|
+
isPending: Ref<boolean>;
|
|
47
|
+
mutate: (args: TArgs) => Promise<TResult>;
|
|
48
|
+
reset: () => void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Mutation function reference
|
|
52
|
+
*/
|
|
53
|
+
export interface MutationFunction<TArgs = void, TResult = unknown> {
|
|
54
|
+
_name: string;
|
|
55
|
+
_args?: TArgs;
|
|
56
|
+
_result?: TResult;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Mutation composable
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```vue
|
|
63
|
+
* <script setup>
|
|
64
|
+
* const { mutate: createPost, isPending } = useMutation(api.posts.create);
|
|
65
|
+
*
|
|
66
|
+
* async function handleSubmit() {
|
|
67
|
+
* await createPost({ title: 'Hello', content: '...' });
|
|
68
|
+
* }
|
|
69
|
+
* </script>
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function useMutation<TArgs, TResult>(mutation: MutationFunction<TArgs, TResult>): MutationState<TArgs, TResult>;
|
|
73
|
+
//# sourceMappingURL=composables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composables.d.ts","sourceRoot":"","sources":["../../src/runtime/composables.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAA+B,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;GAEG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAExC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzB,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EACrC,KAAK,EAAE,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,EACpC,IAAI,CAAC,EAAE,KAAK,GACX,UAAU,CAAC,OAAO,CAAC,CA4CrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,EAAE,OAAO;IAC3C,IAAI,EAAE,GAAG,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC/B,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,OAAO;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EACxC,QAAQ,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,GACzC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAmC/B"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt composables for Tether
|
|
3
|
+
*
|
|
4
|
+
* These are auto-imported when using the Tether Nuxt module.
|
|
5
|
+
*/
|
|
6
|
+
import { ref, onMounted, onUnmounted } from 'vue';
|
|
7
|
+
import { getTetherClient } from './plugin';
|
|
8
|
+
/**
|
|
9
|
+
* Get the Tether client instance
|
|
10
|
+
*/
|
|
11
|
+
export function useTether() {
|
|
12
|
+
return getTetherClient();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Reactive query composable with auto-subscription
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```vue
|
|
19
|
+
* <script setup>
|
|
20
|
+
* const { data: posts, isLoading } = useQuery(api.posts.list);
|
|
21
|
+
* </script>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function useQuery(query, args) {
|
|
25
|
+
const data = ref();
|
|
26
|
+
const error = ref(null);
|
|
27
|
+
const isLoading = ref(true);
|
|
28
|
+
let unsubscribe = null;
|
|
29
|
+
const fetchData = async () => {
|
|
30
|
+
try {
|
|
31
|
+
isLoading.value = true;
|
|
32
|
+
error.value = null;
|
|
33
|
+
const client = getTetherClient();
|
|
34
|
+
const result = await client.query(query._name, args);
|
|
35
|
+
data.value = result;
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
error.value = e instanceof Error ? e : new Error(String(e));
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
isLoading.value = false;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
onMounted(async () => {
|
|
45
|
+
await fetchData();
|
|
46
|
+
// Subscribe to realtime updates
|
|
47
|
+
const client = getTetherClient();
|
|
48
|
+
unsubscribe = client.subscribe(query._name, args, (newData) => {
|
|
49
|
+
data.value = newData;
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
onUnmounted(() => {
|
|
53
|
+
if (unsubscribe) {
|
|
54
|
+
unsubscribe();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
data: data,
|
|
59
|
+
error,
|
|
60
|
+
isLoading,
|
|
61
|
+
refetch: fetchData,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Mutation composable
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```vue
|
|
69
|
+
* <script setup>
|
|
70
|
+
* const { mutate: createPost, isPending } = useMutation(api.posts.create);
|
|
71
|
+
*
|
|
72
|
+
* async function handleSubmit() {
|
|
73
|
+
* await createPost({ title: 'Hello', content: '...' });
|
|
74
|
+
* }
|
|
75
|
+
* </script>
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export function useMutation(mutation) {
|
|
79
|
+
const data = ref();
|
|
80
|
+
const error = ref(null);
|
|
81
|
+
const isPending = ref(false);
|
|
82
|
+
const mutate = async (args) => {
|
|
83
|
+
try {
|
|
84
|
+
isPending.value = true;
|
|
85
|
+
error.value = null;
|
|
86
|
+
const client = getTetherClient();
|
|
87
|
+
const result = await client.mutation(mutation._name, args);
|
|
88
|
+
data.value = result;
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
error.value = e instanceof Error ? e : new Error(String(e));
|
|
93
|
+
throw e;
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
isPending.value = false;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const reset = () => {
|
|
100
|
+
data.value = undefined;
|
|
101
|
+
error.value = null;
|
|
102
|
+
isPending.value = false;
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
data: data,
|
|
106
|
+
error,
|
|
107
|
+
isPending,
|
|
108
|
+
mutate,
|
|
109
|
+
reset,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=composables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composables.js","sourceRoot":"","sources":["../../src/runtime/composables.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt plugin that initialises the Tether client
|
|
3
|
+
*/
|
|
4
|
+
import { TetherClient } from '@tthr/client';
|
|
5
|
+
declare const _default: any;
|
|
6
|
+
export default _default;
|
|
7
|
+
/**
|
|
8
|
+
* Get the Tether client instance (for internal use by composables)
|
|
9
|
+
*/
|
|
10
|
+
export declare function getTetherClient(): TetherClient;
|
|
11
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/runtime/plugin.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;;AAK5C,wBAkBG;AAEH;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAK9C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt plugin that initialises the Tether client
|
|
3
|
+
*/
|
|
4
|
+
import { defineNuxtPlugin, useRuntimeConfig } from '#app';
|
|
5
|
+
import { TetherClient } from '@tthr/client';
|
|
6
|
+
// Global client instance
|
|
7
|
+
let tetherClient = null;
|
|
8
|
+
export default defineNuxtPlugin(() => {
|
|
9
|
+
const config = useRuntimeConfig();
|
|
10
|
+
const tetherConfig = config.public.tether;
|
|
11
|
+
if (!tetherConfig.projectId) {
|
|
12
|
+
console.warn('[Tether] No projectId configured. Set it in nuxt.config.ts under tether.projectId or via NUXT_PUBLIC_TETHER_PROJECT_ID env var.');
|
|
13
|
+
}
|
|
14
|
+
tetherClient = new TetherClient({
|
|
15
|
+
projectId: tetherConfig.projectId,
|
|
16
|
+
url: tetherConfig.url,
|
|
17
|
+
});
|
|
18
|
+
return {
|
|
19
|
+
provide: {
|
|
20
|
+
tether: tetherClient,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Get the Tether client instance (for internal use by composables)
|
|
26
|
+
*/
|
|
27
|
+
export function getTetherClient() {
|
|
28
|
+
if (!tetherClient) {
|
|
29
|
+
throw new Error('[Tether] Client not initialised. Make sure the Tether module is configured in nuxt.config.ts');
|
|
30
|
+
}
|
|
31
|
+
return tetherClient;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/runtime/plugin.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,yBAAyB;AACzB,IAAI,YAAY,GAAwB,IAAI,CAAC;AAE7C,eAAe,gBAAgB,CAAC,GAAG,EAAE;IACnC,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAA4C,CAAC;IAEhF,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,iIAAiI,CAAC,CAAC;IAClJ,CAAC;IAED,YAAY,GAAG,IAAI,YAAY,CAAC;QAC9B,SAAS,EAAE,YAAY,CAAC,SAAS;QACjC,GAAG,EAAE,YAAY,CAAC,GAAG;KACtB,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE;YACP,MAAM,EAAE,YAAY;SACrB;KACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,8FAA8F,CAAC,CAAC;IAClH,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
package/nuxt/module.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @tthr/vue/nuxt - Tether Nuxt Module
|
|
3
|
+
*
|
|
4
|
+
* Automatically configures Tether for Nuxt applications.
|
|
5
|
+
*
|
|
6
|
+
* Usage in nuxt.config.ts:
|
|
7
|
+
* ```ts
|
|
8
|
+
* export default defineNuxtConfig({
|
|
9
|
+
* modules: ['@tthr/vue/nuxt'],
|
|
10
|
+
* tether: {
|
|
11
|
+
* projectId: 'your-project-id',
|
|
12
|
+
* url: 'https://api.tether.strands.gg', // optional
|
|
13
|
+
* },
|
|
14
|
+
* })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { defineNuxtModule, addPlugin, createResolver, addImports, addComponent } from '@nuxt/kit';
|
|
19
|
+
|
|
20
|
+
export interface TetherModuleOptions {
|
|
21
|
+
/** Project ID from Tether dashboard */
|
|
22
|
+
projectId?: string;
|
|
23
|
+
/** API endpoint (defaults to Tether Cloud) */
|
|
24
|
+
url?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default defineNuxtModule<TetherModuleOptions>({
|
|
28
|
+
meta: {
|
|
29
|
+
name: '@tthr/vue',
|
|
30
|
+
configKey: 'tether',
|
|
31
|
+
compatibility: {
|
|
32
|
+
nuxt: '>=3.0.0',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
defaults: {
|
|
36
|
+
projectId: undefined,
|
|
37
|
+
url: undefined,
|
|
38
|
+
},
|
|
39
|
+
setup(options, nuxt) {
|
|
40
|
+
const resolver = createResolver(import.meta.url);
|
|
41
|
+
|
|
42
|
+
// Add runtime config for client-side access
|
|
43
|
+
nuxt.options.runtimeConfig.public.tether = {
|
|
44
|
+
projectId: options.projectId || '',
|
|
45
|
+
url: options.url || 'https://api.tether.strands.gg',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Add the plugin that initialises Tether on the client
|
|
49
|
+
addPlugin({
|
|
50
|
+
src: resolver.resolve('./runtime/plugin'),
|
|
51
|
+
mode: 'client',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Auto-import composables so users don't need explicit imports
|
|
55
|
+
addImports([
|
|
56
|
+
{
|
|
57
|
+
name: 'useQuery',
|
|
58
|
+
from: resolver.resolve('./runtime/composables'),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'useMutation',
|
|
62
|
+
from: resolver.resolve('./runtime/composables'),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'useTether',
|
|
66
|
+
from: resolver.resolve('./runtime/composables'),
|
|
67
|
+
},
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
// Auto-import components
|
|
71
|
+
addComponent({
|
|
72
|
+
name: 'TetherWelcome',
|
|
73
|
+
filePath: resolver.resolve('./runtime/components/TetherWelcome.vue'),
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
});
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="tether-welcome">
|
|
3
|
+
<div class="tether-welcome__container">
|
|
4
|
+
<header class="tether-welcome__header">
|
|
5
|
+
<div class="tether-welcome__logo">
|
|
6
|
+
<svg viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
7
|
+
<rect width="40" height="40" rx="8" fill="currentColor" />
|
|
8
|
+
<path d="M12 14h16M20 14v14M14 28h12" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
9
|
+
</svg>
|
|
10
|
+
</div>
|
|
11
|
+
<h1>Welcome to Tether</h1>
|
|
12
|
+
<p class="tether-welcome__subtitle">Realtime SQLite for modern apps</p>
|
|
13
|
+
</header>
|
|
14
|
+
|
|
15
|
+
<div class="tether-welcome__status">
|
|
16
|
+
<div class="tether-welcome__status-item" :class="{ 'tether-welcome__status-item--success': isConnected }">
|
|
17
|
+
<span class="tether-welcome__status-dot"></span>
|
|
18
|
+
<span>{{ isConnected ? 'Connected to Tether' : 'Connecting...' }}</span>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<section class="tether-welcome__demo">
|
|
23
|
+
<h2>Try it out</h2>
|
|
24
|
+
<p class="tether-welcome__demo-intro">Create posts in realtime. Open this page in multiple tabs to see live updates!</p>
|
|
25
|
+
|
|
26
|
+
<form class="tether-welcome__form" @submit.prevent="handleCreatePost">
|
|
27
|
+
<input
|
|
28
|
+
v-model="newPostTitle"
|
|
29
|
+
type="text"
|
|
30
|
+
placeholder="Enter a post title..."
|
|
31
|
+
class="tether-welcome__input"
|
|
32
|
+
:disabled="createPost.isPending.value"
|
|
33
|
+
/>
|
|
34
|
+
<button
|
|
35
|
+
type="submit"
|
|
36
|
+
class="tether-welcome__button"
|
|
37
|
+
:disabled="!newPostTitle.trim() || createPost.isPending.value"
|
|
38
|
+
>
|
|
39
|
+
{{ createPost.isPending.value ? 'Creating...' : 'Create Post' }}
|
|
40
|
+
</button>
|
|
41
|
+
</form>
|
|
42
|
+
|
|
43
|
+
<div v-if="posts.error.value" class="tether-welcome__error">
|
|
44
|
+
{{ posts.error.value.message }}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="tether-welcome__posts">
|
|
48
|
+
<div v-if="posts.isLoading.value" class="tether-welcome__loading">
|
|
49
|
+
Loading posts...
|
|
50
|
+
</div>
|
|
51
|
+
<template v-else-if="posts.data.value?.length">
|
|
52
|
+
<article
|
|
53
|
+
v-for="post in posts.data.value"
|
|
54
|
+
:key="post.id"
|
|
55
|
+
class="tether-welcome__post"
|
|
56
|
+
>
|
|
57
|
+
<div class="tether-welcome__post-content">
|
|
58
|
+
<h3>{{ post.title }}</h3>
|
|
59
|
+
<time>{{ formatDate(post.createdAt) }}</time>
|
|
60
|
+
</div>
|
|
61
|
+
<button
|
|
62
|
+
class="tether-welcome__post-delete"
|
|
63
|
+
@click="handleDeletePost(post.id)"
|
|
64
|
+
:disabled="deletePost.isPending.value"
|
|
65
|
+
title="Delete post"
|
|
66
|
+
>
|
|
67
|
+
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
68
|
+
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
|
|
69
|
+
</svg>
|
|
70
|
+
</button>
|
|
71
|
+
</article>
|
|
72
|
+
</template>
|
|
73
|
+
<p v-else class="tether-welcome__empty">
|
|
74
|
+
No posts yet. Create your first one above!
|
|
75
|
+
</p>
|
|
76
|
+
</div>
|
|
77
|
+
</section>
|
|
78
|
+
|
|
79
|
+
<section class="tether-welcome__links">
|
|
80
|
+
<a href="https://tether.strands.gg/docs" target="_blank" rel="noopener" class="tether-welcome__link">
|
|
81
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
82
|
+
<path d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
|
|
83
|
+
</svg>
|
|
84
|
+
<span>Documentation</span>
|
|
85
|
+
</a>
|
|
86
|
+
<a href="https://github.com/StrandsServices/tether" target="_blank" rel="noopener" class="tether-welcome__link">
|
|
87
|
+
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
88
|
+
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
|
89
|
+
</svg>
|
|
90
|
+
<span>GitHub</span>
|
|
91
|
+
</a>
|
|
92
|
+
<a href="https://discord.gg/strands" target="_blank" rel="noopener" class="tether-welcome__link">
|
|
93
|
+
<svg viewBox="0 0 24 24" fill="currentColor">
|
|
94
|
+
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/>
|
|
95
|
+
</svg>
|
|
96
|
+
<span>Discord</span>
|
|
97
|
+
</a>
|
|
98
|
+
</section>
|
|
99
|
+
|
|
100
|
+
<footer class="tether-welcome__footer">
|
|
101
|
+
<p>Built with Tether by <a href="https://strands.gg" target="_blank" rel="noopener">Strands Services</a></p>
|
|
102
|
+
</footer>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
106
|
+
|
|
107
|
+
<script setup lang="ts">
|
|
108
|
+
import { ref, onMounted } from 'vue';
|
|
109
|
+
import { useTether, useQuery, useMutation } from '../composables';
|
|
110
|
+
|
|
111
|
+
interface Post {
|
|
112
|
+
id: string;
|
|
113
|
+
title: string;
|
|
114
|
+
content: string;
|
|
115
|
+
authorId: string;
|
|
116
|
+
createdAt: string;
|
|
117
|
+
updatedAt: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const isConnected = ref(false);
|
|
121
|
+
const newPostTitle = ref('');
|
|
122
|
+
|
|
123
|
+
// Set up queries and mutations
|
|
124
|
+
const posts = useQuery<void, Post[]>({ _name: 'posts.list' });
|
|
125
|
+
const createPost = useMutation<{ title: string; content?: string }, { id: string }>({ _name: 'posts.create' });
|
|
126
|
+
const deletePost = useMutation<{ id: string }, void>({ _name: 'posts.remove' });
|
|
127
|
+
|
|
128
|
+
onMounted(async () => {
|
|
129
|
+
try {
|
|
130
|
+
const client = useTether();
|
|
131
|
+
await client.connect();
|
|
132
|
+
isConnected.value = true;
|
|
133
|
+
} catch {
|
|
134
|
+
// Connection handled by client
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
async function handleCreatePost() {
|
|
139
|
+
if (!newPostTitle.value.trim()) return;
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
await createPost.mutate({
|
|
143
|
+
title: newPostTitle.value.trim(),
|
|
144
|
+
content: '',
|
|
145
|
+
});
|
|
146
|
+
newPostTitle.value = '';
|
|
147
|
+
await posts.refetch();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('Failed to create post:', error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function handleDeletePost(id: string) {
|
|
154
|
+
try {
|
|
155
|
+
await deletePost.mutate({ id });
|
|
156
|
+
await posts.refetch();
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error('Failed to delete post:', error);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function formatDate(dateString: string): string {
|
|
163
|
+
const date = new Date(dateString);
|
|
164
|
+
return date.toLocaleDateString('en-GB', {
|
|
165
|
+
day: 'numeric',
|
|
166
|
+
month: 'short',
|
|
167
|
+
year: 'numeric',
|
|
168
|
+
hour: '2-digit',
|
|
169
|
+
minute: '2-digit',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
</script>
|
|
173
|
+
|
|
174
|
+
<style scoped>
|
|
175
|
+
.tether-welcome {
|
|
176
|
+
min-height: 100vh;
|
|
177
|
+
background: linear-gradient(135deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%);
|
|
178
|
+
color: #e4e4e7;
|
|
179
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
180
|
+
padding: 2rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.tether-welcome__container {
|
|
184
|
+
max-width: 640px;
|
|
185
|
+
margin: 0 auto;
|
|
186
|
+
display: flex;
|
|
187
|
+
flex-direction: column;
|
|
188
|
+
gap: 2.5rem;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.tether-welcome__header {
|
|
192
|
+
text-align: center;
|
|
193
|
+
display: flex;
|
|
194
|
+
flex-direction: column;
|
|
195
|
+
align-items: center;
|
|
196
|
+
gap: 1rem;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.tether-welcome__logo {
|
|
200
|
+
width: 64px;
|
|
201
|
+
height: 64px;
|
|
202
|
+
color: #6366f1;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.tether-welcome__header h1 {
|
|
206
|
+
font-size: 2.5rem;
|
|
207
|
+
font-weight: 700;
|
|
208
|
+
margin: 0;
|
|
209
|
+
background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%);
|
|
210
|
+
-webkit-background-clip: text;
|
|
211
|
+
-webkit-text-fill-color: transparent;
|
|
212
|
+
background-clip: text;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.tether-welcome__subtitle {
|
|
216
|
+
color: #a1a1aa;
|
|
217
|
+
font-size: 1.125rem;
|
|
218
|
+
margin: 0;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.tether-welcome__status {
|
|
222
|
+
display: flex;
|
|
223
|
+
justify-content: center;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.tether-welcome__status-item {
|
|
227
|
+
display: flex;
|
|
228
|
+
align-items: center;
|
|
229
|
+
gap: 0.5rem;
|
|
230
|
+
padding: 0.5rem 1rem;
|
|
231
|
+
background: rgba(255, 255, 255, 0.05);
|
|
232
|
+
border-radius: 9999px;
|
|
233
|
+
font-size: 0.875rem;
|
|
234
|
+
color: #a1a1aa;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.tether-welcome__status-item--success {
|
|
238
|
+
color: #4ade80;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.tether-welcome__status-dot {
|
|
242
|
+
width: 8px;
|
|
243
|
+
height: 8px;
|
|
244
|
+
border-radius: 50%;
|
|
245
|
+
background: #a1a1aa;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.tether-welcome__status-item--success .tether-welcome__status-dot {
|
|
249
|
+
background: #4ade80;
|
|
250
|
+
box-shadow: 0 0 8px #4ade80;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.tether-welcome__demo {
|
|
254
|
+
background: rgba(255, 255, 255, 0.03);
|
|
255
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
256
|
+
border-radius: 1rem;
|
|
257
|
+
padding: 1.5rem;
|
|
258
|
+
display: flex;
|
|
259
|
+
flex-direction: column;
|
|
260
|
+
gap: 1rem;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.tether-welcome__demo h2 {
|
|
264
|
+
font-size: 1.25rem;
|
|
265
|
+
font-weight: 600;
|
|
266
|
+
margin: 0;
|
|
267
|
+
color: #f4f4f5;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.tether-welcome__demo-intro {
|
|
271
|
+
color: #a1a1aa;
|
|
272
|
+
font-size: 0.875rem;
|
|
273
|
+
margin: 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.tether-welcome__form {
|
|
277
|
+
display: flex;
|
|
278
|
+
gap: 0.75rem;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.tether-welcome__input {
|
|
282
|
+
flex: 1;
|
|
283
|
+
padding: 0.75rem 1rem;
|
|
284
|
+
background: rgba(0, 0, 0, 0.3);
|
|
285
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
286
|
+
border-radius: 0.5rem;
|
|
287
|
+
color: #e4e4e7;
|
|
288
|
+
font-size: 0.875rem;
|
|
289
|
+
outline: none;
|
|
290
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.tether-welcome__input:focus {
|
|
294
|
+
border-color: #6366f1;
|
|
295
|
+
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.tether-welcome__input::placeholder {
|
|
299
|
+
color: #71717a;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.tether-welcome__button {
|
|
303
|
+
padding: 0.75rem 1.5rem;
|
|
304
|
+
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
|
305
|
+
border: none;
|
|
306
|
+
border-radius: 0.5rem;
|
|
307
|
+
color: white;
|
|
308
|
+
font-size: 0.875rem;
|
|
309
|
+
font-weight: 500;
|
|
310
|
+
cursor: pointer;
|
|
311
|
+
transition: opacity 0.2s, transform 0.2s;
|
|
312
|
+
white-space: nowrap;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.tether-welcome__button:hover:not(:disabled) {
|
|
316
|
+
opacity: 0.9;
|
|
317
|
+
transform: translateY(-1px);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.tether-welcome__button:disabled {
|
|
321
|
+
opacity: 0.5;
|
|
322
|
+
cursor: not-allowed;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.tether-welcome__error {
|
|
326
|
+
padding: 0.75rem 1rem;
|
|
327
|
+
background: rgba(239, 68, 68, 0.1);
|
|
328
|
+
border: 1px solid rgba(239, 68, 68, 0.3);
|
|
329
|
+
border-radius: 0.5rem;
|
|
330
|
+
color: #fca5a5;
|
|
331
|
+
font-size: 0.875rem;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.tether-welcome__posts {
|
|
335
|
+
display: flex;
|
|
336
|
+
flex-direction: column;
|
|
337
|
+
gap: 0.5rem;
|
|
338
|
+
min-height: 100px;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.tether-welcome__loading,
|
|
342
|
+
.tether-welcome__empty {
|
|
343
|
+
color: #71717a;
|
|
344
|
+
font-size: 0.875rem;
|
|
345
|
+
text-align: center;
|
|
346
|
+
padding: 2rem;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.tether-welcome__post {
|
|
350
|
+
display: flex;
|
|
351
|
+
align-items: center;
|
|
352
|
+
justify-content: space-between;
|
|
353
|
+
gap: 1rem;
|
|
354
|
+
padding: 0.875rem 1rem;
|
|
355
|
+
background: rgba(0, 0, 0, 0.2);
|
|
356
|
+
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
357
|
+
border-radius: 0.5rem;
|
|
358
|
+
transition: background 0.2s;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.tether-welcome__post:hover {
|
|
362
|
+
background: rgba(0, 0, 0, 0.3);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.tether-welcome__post-content {
|
|
366
|
+
flex: 1;
|
|
367
|
+
min-width: 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.tether-welcome__post-content h3 {
|
|
371
|
+
font-size: 0.9375rem;
|
|
372
|
+
font-weight: 500;
|
|
373
|
+
margin: 0 0 0.25rem 0;
|
|
374
|
+
color: #f4f4f5;
|
|
375
|
+
overflow: hidden;
|
|
376
|
+
text-overflow: ellipsis;
|
|
377
|
+
white-space: nowrap;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.tether-welcome__post-content time {
|
|
381
|
+
font-size: 0.75rem;
|
|
382
|
+
color: #71717a;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.tether-welcome__post-delete {
|
|
386
|
+
flex-shrink: 0;
|
|
387
|
+
width: 32px;
|
|
388
|
+
height: 32px;
|
|
389
|
+
display: flex;
|
|
390
|
+
align-items: center;
|
|
391
|
+
justify-content: center;
|
|
392
|
+
background: transparent;
|
|
393
|
+
border: none;
|
|
394
|
+
border-radius: 0.375rem;
|
|
395
|
+
color: #71717a;
|
|
396
|
+
cursor: pointer;
|
|
397
|
+
transition: color 0.2s, background 0.2s;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.tether-welcome__post-delete:hover:not(:disabled) {
|
|
401
|
+
color: #ef4444;
|
|
402
|
+
background: rgba(239, 68, 68, 0.1);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.tether-welcome__post-delete:disabled {
|
|
406
|
+
opacity: 0.5;
|
|
407
|
+
cursor: not-allowed;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.tether-welcome__post-delete svg {
|
|
411
|
+
width: 18px;
|
|
412
|
+
height: 18px;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.tether-welcome__links {
|
|
416
|
+
display: flex;
|
|
417
|
+
justify-content: center;
|
|
418
|
+
gap: 1rem;
|
|
419
|
+
flex-wrap: wrap;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.tether-welcome__link {
|
|
423
|
+
display: flex;
|
|
424
|
+
align-items: center;
|
|
425
|
+
gap: 0.5rem;
|
|
426
|
+
padding: 0.625rem 1rem;
|
|
427
|
+
background: rgba(255, 255, 255, 0.05);
|
|
428
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
429
|
+
border-radius: 0.5rem;
|
|
430
|
+
color: #a1a1aa;
|
|
431
|
+
text-decoration: none;
|
|
432
|
+
font-size: 0.875rem;
|
|
433
|
+
transition: background 0.2s, color 0.2s, border-color 0.2s;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.tether-welcome__link:hover {
|
|
437
|
+
background: rgba(255, 255, 255, 0.08);
|
|
438
|
+
color: #e4e4e7;
|
|
439
|
+
border-color: rgba(255, 255, 255, 0.15);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.tether-welcome__link svg {
|
|
443
|
+
width: 18px;
|
|
444
|
+
height: 18px;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.tether-welcome__footer {
|
|
448
|
+
text-align: center;
|
|
449
|
+
padding-top: 1rem;
|
|
450
|
+
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.tether-welcome__footer p {
|
|
454
|
+
color: #52525b;
|
|
455
|
+
font-size: 0.8125rem;
|
|
456
|
+
margin: 0;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.tether-welcome__footer a {
|
|
460
|
+
color: #6366f1;
|
|
461
|
+
text-decoration: none;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.tether-welcome__footer a:hover {
|
|
465
|
+
text-decoration: underline;
|
|
466
|
+
}
|
|
467
|
+
</style>
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt composables for Tether
|
|
3
|
+
*
|
|
4
|
+
* These are auto-imported when using the Tether Nuxt module.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ref, onMounted, onUnmounted, type Ref } from 'vue';
|
|
8
|
+
import { tetherClient } from './plugin';
|
|
9
|
+
import type { TetherClient } from '@tthr/client';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the Tether client instance
|
|
13
|
+
*/
|
|
14
|
+
export function useTether(): TetherClient {
|
|
15
|
+
if (!tetherClient) {
|
|
16
|
+
throw new Error('[Tether] Client not initialised. Make sure the Tether module is configured in nuxt.config.ts');
|
|
17
|
+
}
|
|
18
|
+
return tetherClient;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Query state returned by useQuery
|
|
23
|
+
*/
|
|
24
|
+
export interface QueryState<T> {
|
|
25
|
+
data: Ref<T | undefined>;
|
|
26
|
+
error: Ref<Error | null>;
|
|
27
|
+
isLoading: Ref<boolean>;
|
|
28
|
+
refetch: () => Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Query function reference
|
|
33
|
+
*/
|
|
34
|
+
export interface QueryFunction<TArgs = void, TResult = unknown> {
|
|
35
|
+
_name: string;
|
|
36
|
+
_args?: TArgs;
|
|
37
|
+
_result?: TResult;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Reactive query composable with auto-subscription
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```vue
|
|
45
|
+
* <script setup>
|
|
46
|
+
* const { data: posts, isLoading } = useQuery(api.posts.list);
|
|
47
|
+
* </script>
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function useQuery<TArgs, TResult>(
|
|
51
|
+
query: QueryFunction<TArgs, TResult>,
|
|
52
|
+
args?: TArgs
|
|
53
|
+
): QueryState<TResult> {
|
|
54
|
+
const data = ref<TResult>();
|
|
55
|
+
const error = ref<Error | null>(null);
|
|
56
|
+
const isLoading = ref(true);
|
|
57
|
+
|
|
58
|
+
let unsubscribe: (() => void) | null = null;
|
|
59
|
+
|
|
60
|
+
const fetchData = async () => {
|
|
61
|
+
try {
|
|
62
|
+
isLoading.value = true;
|
|
63
|
+
error.value = null;
|
|
64
|
+
|
|
65
|
+
const client = useTether();
|
|
66
|
+
const result = await client.query(query._name, args);
|
|
67
|
+
data.value = result as TResult;
|
|
68
|
+
} catch (e) {
|
|
69
|
+
error.value = e instanceof Error ? e : new Error(String(e));
|
|
70
|
+
} finally {
|
|
71
|
+
isLoading.value = false;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
onMounted(async () => {
|
|
76
|
+
await fetchData();
|
|
77
|
+
|
|
78
|
+
// Subscribe to realtime updates
|
|
79
|
+
const client = useTether();
|
|
80
|
+
unsubscribe = client.subscribe(query._name, args, (newData) => {
|
|
81
|
+
data.value = newData as TResult;
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
onUnmounted(() => {
|
|
86
|
+
if (unsubscribe) {
|
|
87
|
+
unsubscribe();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
data: data as Ref<TResult | undefined>,
|
|
93
|
+
error,
|
|
94
|
+
isLoading,
|
|
95
|
+
refetch: fetchData,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Mutation state returned by useMutation
|
|
101
|
+
*/
|
|
102
|
+
export interface MutationState<TArgs, TResult> {
|
|
103
|
+
data: Ref<TResult | undefined>;
|
|
104
|
+
error: Ref<Error | null>;
|
|
105
|
+
isPending: Ref<boolean>;
|
|
106
|
+
mutate: (args: TArgs) => Promise<TResult>;
|
|
107
|
+
reset: () => void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Mutation function reference
|
|
112
|
+
*/
|
|
113
|
+
export interface MutationFunction<TArgs = void, TResult = unknown> {
|
|
114
|
+
_name: string;
|
|
115
|
+
_args?: TArgs;
|
|
116
|
+
_result?: TResult;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Mutation composable
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```vue
|
|
124
|
+
* <script setup>
|
|
125
|
+
* const { mutate: createPost, isPending } = useMutation(api.posts.create);
|
|
126
|
+
*
|
|
127
|
+
* async function handleSubmit() {
|
|
128
|
+
* await createPost({ title: 'Hello', content: '...' });
|
|
129
|
+
* }
|
|
130
|
+
* </script>
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function useMutation<TArgs, TResult>(
|
|
134
|
+
mutation: MutationFunction<TArgs, TResult>
|
|
135
|
+
): MutationState<TArgs, TResult> {
|
|
136
|
+
const data = ref<TResult>();
|
|
137
|
+
const error = ref<Error | null>(null);
|
|
138
|
+
const isPending = ref(false);
|
|
139
|
+
|
|
140
|
+
const mutate = async (args: TArgs): Promise<TResult> => {
|
|
141
|
+
try {
|
|
142
|
+
isPending.value = true;
|
|
143
|
+
error.value = null;
|
|
144
|
+
|
|
145
|
+
const client = useTether();
|
|
146
|
+
const result = await client.mutation(mutation._name, args);
|
|
147
|
+
data.value = result as TResult;
|
|
148
|
+
return result as TResult;
|
|
149
|
+
} catch (e) {
|
|
150
|
+
error.value = e instanceof Error ? e : new Error(String(e));
|
|
151
|
+
throw e;
|
|
152
|
+
} finally {
|
|
153
|
+
isPending.value = false;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const reset = () => {
|
|
158
|
+
data.value = undefined;
|
|
159
|
+
error.value = null;
|
|
160
|
+
isPending.value = false;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
data: data as Ref<TResult | undefined>,
|
|
165
|
+
error,
|
|
166
|
+
isPending,
|
|
167
|
+
mutate,
|
|
168
|
+
reset,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt plugin that initialises the Tether client
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { defineNuxtPlugin, useRuntimeConfig } from '#app';
|
|
6
|
+
import { TetherClient } from '@tthr/client';
|
|
7
|
+
|
|
8
|
+
// Global client instance for use by composables
|
|
9
|
+
export let tetherClient: TetherClient | null = null;
|
|
10
|
+
|
|
11
|
+
export default defineNuxtPlugin(() => {
|
|
12
|
+
const config = useRuntimeConfig();
|
|
13
|
+
const tetherConfig = config.public.tether as { projectId: string; url: string };
|
|
14
|
+
|
|
15
|
+
if (!tetherConfig.projectId) {
|
|
16
|
+
console.warn('[Tether] No projectId configured. Set it in nuxt.config.ts under tether.projectId or via NUXT_PUBLIC_TETHER_PROJECT_ID env var.');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Build the WebSocket URL from the API URL and project ID
|
|
20
|
+
const wsUrl = tetherConfig.url
|
|
21
|
+
.replace('https://', 'wss://')
|
|
22
|
+
.replace('http://', 'ws://');
|
|
23
|
+
|
|
24
|
+
tetherClient = new TetherClient({
|
|
25
|
+
url: `${wsUrl}/ws/${tetherConfig.projectId}`,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
provide: {
|
|
30
|
+
tether: tetherClient,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tthr/vue",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Tether Vue/Nuxt SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,10 +9,14 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./nuxt": {
|
|
14
|
+
"import": "./nuxt/module.ts"
|
|
12
15
|
}
|
|
13
16
|
},
|
|
14
17
|
"files": [
|
|
15
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"nuxt"
|
|
16
20
|
],
|
|
17
21
|
"scripts": {
|
|
18
22
|
"build": "tsc",
|
|
@@ -20,12 +24,13 @@
|
|
|
20
24
|
"typecheck": "tsc --noEmit"
|
|
21
25
|
},
|
|
22
26
|
"dependencies": {
|
|
27
|
+
"@nuxt/kit": "^3.14.0",
|
|
23
28
|
"@tthr/client": "*"
|
|
24
29
|
},
|
|
25
30
|
"devDependencies": {
|
|
26
31
|
"typescript": "^5.7.2"
|
|
27
32
|
},
|
|
28
33
|
"peerDependencies": {
|
|
29
|
-
"vue": "^3.
|
|
34
|
+
"vue": "^3.0.0"
|
|
30
35
|
}
|
|
31
36
|
}
|