nuxt-convex-module 0.0.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/LICENSE +21 -0
- package/README.md +242 -0
- package/dist/chunks/index.mjs +64 -0
- package/dist/devtools-client/200.html +1 -0
- package/dist/devtools-client/404.html +1 -0
- package/dist/devtools-client/_nuxt/B29GGJ5n.js +1 -0
- package/dist/devtools-client/_nuxt/BSDEpQet.js +1 -0
- package/dist/devtools-client/_nuxt/BY23OQOo.js +1 -0
- package/dist/devtools-client/_nuxt/BZYRaL-G.js +1 -0
- package/dist/devtools-client/_nuxt/Byw6FxnC.js +1 -0
- package/dist/devtools-client/_nuxt/CJJ_hcZN.js +1 -0
- package/dist/devtools-client/_nuxt/CS6WMFOx.js +2 -0
- package/dist/devtools-client/_nuxt/CZbAGcNC.js +1 -0
- package/dist/devtools-client/_nuxt/Cr6_aklh.js +2 -0
- package/dist/devtools-client/_nuxt/DNfpyBVU.js +3 -0
- package/dist/devtools-client/_nuxt/DPWXUmcI.js +1 -0
- package/dist/devtools-client/_nuxt/builds/latest.json +1 -0
- package/dist/devtools-client/_nuxt/builds/meta/a7708498-bd09-4de2-b5ab-19b380293c77.json +1 -0
- package/dist/devtools-client/_nuxt/dy_xXcv9.js +1 -0
- package/dist/devtools-client/_nuxt/entry.DbTJhkHT.css +1 -0
- package/dist/devtools-client/_nuxt/error-404.CwGGO2Kz.css +1 -0
- package/dist/devtools-client/_nuxt/error-500.8ZJqCQm8.css +1 -0
- package/dist/devtools-client/_nuxt/ncgEdbEt.js +1 -0
- package/dist/devtools-client/_nuxt/queries.CE_dtt9-.css +1 -0
- package/dist/devtools-client/auth/index.html +1 -0
- package/dist/devtools-client/icon.svg +6 -0
- package/dist/devtools-client/index.html +1 -0
- package/dist/devtools-client/logs/index.html +1 -0
- package/dist/devtools-client/queries/index.html +1 -0
- package/dist/module.d.ts +189 -0
- package/dist/module.js +489 -0
- package/dist/module.json +13 -0
- package/dist/runtime/auth0/vue/index.d.ts +58 -0
- package/dist/runtime/auth0/vue/index.js +33 -0
- package/dist/runtime/better-auth/nuxt/middleware.d.ts +14 -0
- package/dist/runtime/better-auth/nuxt/middleware.js +39 -0
- package/dist/runtime/better-auth/nuxt/proxy.d.ts +6 -0
- package/dist/runtime/better-auth/nuxt/proxy.js +11 -0
- package/dist/runtime/better-auth/nuxt/server.d.ts +106 -0
- package/dist/runtime/better-auth/nuxt/server.js +123 -0
- package/dist/runtime/better-auth/vue/auth-boundary.d.ts +131 -0
- package/dist/runtime/better-auth/vue/auth-boundary.js +78 -0
- package/dist/runtime/better-auth/vue/client.d.ts +358 -0
- package/dist/runtime/better-auth/vue/client.js +5 -0
- package/dist/runtime/better-auth/vue/cross-domain.d.ts +39 -0
- package/dist/runtime/better-auth/vue/cross-domain.js +45 -0
- package/dist/runtime/better-auth/vue/hydration.d.ts +20 -0
- package/dist/runtime/better-auth/vue/hydration.js +52 -0
- package/dist/runtime/better-auth/vue/index.d.ts +12 -0
- package/dist/runtime/better-auth/vue/index.js +6 -0
- package/dist/runtime/better-auth/vue/plugin.client.d.ts +6 -0
- package/dist/runtime/better-auth/vue/plugin.client.js +32 -0
- package/dist/runtime/better-auth/vue/plugin.server.d.ts +24 -0
- package/dist/runtime/better-auth/vue/plugin.server.js +42 -0
- package/dist/runtime/better-auth/vue/use-auth.d.ts +92 -0
- package/dist/runtime/better-auth/vue/use-auth.js +82 -0
- package/dist/runtime/clerk/vue/index.d.ts +81 -0
- package/dist/runtime/clerk/vue/index.js +49 -0
- package/dist/runtime/devtools/bridge.d.ts +12 -0
- package/dist/runtime/devtools/bridge.js +191 -0
- package/dist/runtime/devtools/plugin.client.d.ts +8 -0
- package/dist/runtime/devtools/plugin.client.js +34 -0
- package/dist/runtime/devtools/types.d.ts +78 -0
- package/dist/runtime/devtools/types.js +0 -0
- package/dist/runtime/nuxt/composables/use-async-query.d.ts +144 -0
- package/dist/runtime/nuxt/composables/use-async-query.js +104 -0
- package/dist/runtime/nuxt/config.d.ts +7 -0
- package/dist/runtime/nuxt/config.js +12 -0
- package/dist/runtime/nuxt/index.d.ts +136 -0
- package/dist/runtime/nuxt/index.js +91 -0
- package/dist/runtime/polar/vue/components.d.ts +184 -0
- package/dist/runtime/polar/vue/components.js +115 -0
- package/dist/runtime/vue/auth/helpers.d.ts +67 -0
- package/dist/runtime/vue/auth/helpers.js +50 -0
- package/dist/runtime/vue/auth/index.d.ts +125 -0
- package/dist/runtime/vue/auth/index.js +97 -0
- package/dist/runtime/vue/client.d.ts +305 -0
- package/dist/runtime/vue/client.js +382 -0
- package/dist/runtime/vue/composables/use-action.d.ts +62 -0
- package/dist/runtime/vue/composables/use-action.js +13 -0
- package/dist/runtime/vue/composables/use-connection-state.d.ts +30 -0
- package/dist/runtime/vue/composables/use-connection-state.js +14 -0
- package/dist/runtime/vue/composables/use-mutation.d.ts +76 -0
- package/dist/runtime/vue/composables/use-mutation.js +34 -0
- package/dist/runtime/vue/composables/use-paginated-query.d.ts +132 -0
- package/dist/runtime/vue/composables/use-paginated-query.js +513 -0
- package/dist/runtime/vue/composables/use-queries.d.ts +62 -0
- package/dist/runtime/vue/composables/use-queries.js +37 -0
- package/dist/runtime/vue/composables/use-query.d.ts +87 -0
- package/dist/runtime/vue/composables/use-query.js +53 -0
- package/dist/runtime/vue/composables/use-storage-url.d.ts +46 -0
- package/dist/runtime/vue/composables/use-storage-url.js +9 -0
- package/dist/runtime/vue/composables/use-subscription.d.ts +15 -0
- package/dist/runtime/vue/composables/use-subscription.js +33 -0
- package/dist/runtime/vue/composables/use-upload-queue.d.ts +117 -0
- package/dist/runtime/vue/composables/use-upload-queue.js +115 -0
- package/dist/runtime/vue/composables/use-upload.d.ts +134 -0
- package/dist/runtime/vue/composables/use-upload.js +114 -0
- package/dist/runtime/vue/hydration.d.ts +66 -0
- package/dist/runtime/vue/hydration.js +46 -0
- package/dist/runtime/vue/index.d.ts +94 -0
- package/dist/runtime/vue/index.js +42 -0
- package/dist/runtime/vue/plugin.d.ts +18 -0
- package/dist/runtime/vue/plugin.js +16 -0
- package/dist/runtime/vue/provide.d.ts +39 -0
- package/dist/runtime/vue/provide.js +15 -0
- package/dist/runtime/vue/queries-observer.d.ts +41 -0
- package/dist/runtime/vue/queries-observer.js +126 -0
- package/dist/types.d.ts +3 -0
- package/package.json +233 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nuxt-idiomatic data fetching for Convex queries.
|
|
3
|
+
*
|
|
4
|
+
* {@link useAsyncQuery} is a Vue/Nuxt-only addition (no `convex/react`
|
|
5
|
+
* counterpart — see PARITY.md): it marries Nuxt's `useAsyncData` model with
|
|
6
|
+
* Convex's live queries. During SSR the query runs over HTTP and the result is
|
|
7
|
+
* embedded in the Nuxt payload; after hydration the composable upgrades to the
|
|
8
|
+
* WebSocket subscription, so the page paints with server data and stays live —
|
|
9
|
+
* no loading flash, no client refetch.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
14
|
+
import type { FunctionArgs, FunctionReference, FunctionReturnType } from 'convex/server';
|
|
15
|
+
/**
|
|
16
|
+
* Request status of a {@link useAsyncQuery} call — mirrors Nuxt's
|
|
17
|
+
* `useAsyncData` statuses.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export type AsyncQueryStatus = 'idle' | 'pending' | 'success' | 'error';
|
|
22
|
+
/**
|
|
23
|
+
* Options for {@link useAsyncQuery}.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export interface AsyncQueryOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Key for the underlying `useAsyncData` entry (payload dedup across
|
|
30
|
+
* components). Defaults to a key derived from the query name and the
|
|
31
|
+
* initial args. Provide an explicit key when two call sites must not
|
|
32
|
+
* share a payload entry.
|
|
33
|
+
*/
|
|
34
|
+
key?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Fetch the query on the server during SSR and embed the result in the Nuxt
|
|
37
|
+
* payload. Set `false` to fetch on the client only.
|
|
38
|
+
*
|
|
39
|
+
* @default true
|
|
40
|
+
*/
|
|
41
|
+
server?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Mirror `useAsyncData`'s `lazy` option: don't block client-side navigation
|
|
44
|
+
* on the initial fetch.
|
|
45
|
+
*
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
lazy?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Upgrade to a live WebSocket subscription on the client. Set `false` for
|
|
51
|
+
* SSR + hydration *without* realtime updates — no WebSocket is opened for
|
|
52
|
+
* this query, and {@link AsyncQueryReturn.refresh | refresh} becomes the way
|
|
53
|
+
* to get fresh data.
|
|
54
|
+
*
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
live?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* JWT to authenticate the SSR fetch, or a function resolving one. Defaults
|
|
60
|
+
* to the token the Better Auth server plugin prefetched for this request
|
|
61
|
+
* (when that integration is enabled); pass a value here to integrate any
|
|
62
|
+
* other server-side auth source. The client-side live subscription
|
|
63
|
+
* authenticates through the Convex client's own `setAuth` wiring.
|
|
64
|
+
*/
|
|
65
|
+
token?: string | (() => string | null | Promise<string | null>);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reactive result of {@link useAsyncQuery}. Also awaitable — `await
|
|
69
|
+
* useAsyncQuery(...)` blocks until the initial fetch settles, like
|
|
70
|
+
* `useAsyncData`.
|
|
71
|
+
*
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
export interface AsyncQueryReturn<T> extends PromiseLike<AsyncQueryData<T>> {
|
|
75
|
+
/**
|
|
76
|
+
* The query result: the server-fetched value first, replaced by the live
|
|
77
|
+
* subscription's value once the client receives one. `undefined` while
|
|
78
|
+
* nothing has loaded (or while skipped).
|
|
79
|
+
*/
|
|
80
|
+
data: ComputedRef<T | undefined>;
|
|
81
|
+
/** The initial-fetch or live-subscription error, `null` when none. */
|
|
82
|
+
error: ComputedRef<Error | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Initial-fetch status. Live pushes don't churn it: once data exists it
|
|
85
|
+
* stays `'success'` unless the live subscription errors.
|
|
86
|
+
*/
|
|
87
|
+
status: ComputedRef<AsyncQueryStatus>;
|
|
88
|
+
/**
|
|
89
|
+
* Re-run the one-shot fetch. With a live subscription (`live: true`) the
|
|
90
|
+
* server already pushes updates, so this is mainly for retrying after an
|
|
91
|
+
* error; with `live: false` it is the way to get fresh data.
|
|
92
|
+
*/
|
|
93
|
+
refresh: (opts?: {
|
|
94
|
+
dedupe?: 'cancel' | 'defer';
|
|
95
|
+
}) => Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
type AsyncQueryData<T> = Pick<AsyncQueryReturn<T>, 'data' | 'error' | 'status' | 'refresh'>;
|
|
98
|
+
/**
|
|
99
|
+
* Load a Convex query the Nuxt way: fetched on the server during SSR,
|
|
100
|
+
* hydrated through the Nuxt payload, then seamlessly upgraded to a live
|
|
101
|
+
* WebSocket subscription on the client.
|
|
102
|
+
*
|
|
103
|
+
* Compared to {@link useQuery} (which renders `undefined` during SSR and
|
|
104
|
+
* fetches on the client), `useAsyncQuery` puts real data in the
|
|
105
|
+
* server-rendered HTML and never refetches it on hydration — the live
|
|
106
|
+
* subscription simply takes over. Compared to `preloadQuery` +
|
|
107
|
+
* `usePreloadedQuery`, no server route or prop-threading is needed.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```vue
|
|
111
|
+
* <script setup lang="ts">
|
|
112
|
+
* import { api } from '#convex/api'
|
|
113
|
+
*
|
|
114
|
+
* // SSR-rendered AND live:
|
|
115
|
+
* const { data: tasks, status, error } = useAsyncQuery(api.tasks.list, { completed: false })
|
|
116
|
+
*
|
|
117
|
+
* // SSR + hydration without a WebSocket (fetch-once pages):
|
|
118
|
+
* const { data: stats, refresh } = useAsyncQuery(api.stats.summary, {}, { live: false })
|
|
119
|
+
* </script>
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* The Nuxt payload entry is keyed on the query name and the *initial* args
|
|
123
|
+
* (override with `options.key`). Reactive args are honored by the live
|
|
124
|
+
* subscription; the payload only matters for first paint.
|
|
125
|
+
*
|
|
126
|
+
* Pass `'skip'` as args (or a getter returning it) to pause the query — no
|
|
127
|
+
* fetch runs and no subscription opens until args become real.
|
|
128
|
+
*
|
|
129
|
+
* @param query - a `FunctionReference` for the public query to run, like
|
|
130
|
+
* `api.dir1.dir2.filename.func`.
|
|
131
|
+
* @param args - The arguments to the query function, or `'skip'`. Accepts a
|
|
132
|
+
* ref, computed, or getter for reactive args.
|
|
133
|
+
* @param options - {@link AsyncQueryOptions}.
|
|
134
|
+
* @returns An awaitable {@link AsyncQueryReturn} of `data` / `error` /
|
|
135
|
+
* `status` refs and a `refresh` function.
|
|
136
|
+
*
|
|
137
|
+
* @public
|
|
138
|
+
*/
|
|
139
|
+
export declare function useAsyncQuery<Query extends FunctionReference<'query'>>(query: Query, args?: MaybeRefOrGetter<FunctionArgs<Query> | 'skip'>, options?: AsyncQueryOptions): AsyncQueryReturn<FunctionReturnType<Query>>;
|
|
140
|
+
/** Payload key for a query + initial args. Exported for tests. @internal */
|
|
141
|
+
export declare function defaultAsyncQueryKey(queryName: string, initialArgs: unknown): string;
|
|
142
|
+
/** @public */
|
|
143
|
+
export declare const useConvexAsyncQuery: typeof useAsyncQuery;
|
|
144
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { useAsyncData, useRuntimeConfig, useState } from "#app";
|
|
2
|
+
import { computed, shallowRef, toValue } from "vue";
|
|
3
|
+
import { getFunctionName, makeFunctionReference } from "convex/server";
|
|
4
|
+
import { convexToJson, jsonToConvex } from "convex/values";
|
|
5
|
+
import { useConvex } from "../../vue/client.js";
|
|
6
|
+
import { useConvexQueries } from "../../vue/composables/use-queries.js";
|
|
7
|
+
import { fetchQuery } from "../index.js";
|
|
8
|
+
export function useAsyncQuery(query, args, options = {}) {
|
|
9
|
+
const { server = true, lazy = false, live = true, token } = options;
|
|
10
|
+
const queryReference = typeof query === "string" ? makeFunctionReference(query) : query;
|
|
11
|
+
const queryName = getFunctionName(queryReference);
|
|
12
|
+
const initialArgs = toValue(args) ?? {};
|
|
13
|
+
const key = options.key ?? defaultAsyncQueryKey(queryName, initialArgs);
|
|
14
|
+
const initialToken = useState("convex:initialToken", () => null);
|
|
15
|
+
const client = useConvex();
|
|
16
|
+
const deploymentUrl = import.meta.server ? useRuntimeConfig().public.convex.url : "";
|
|
17
|
+
const resolveToken = async () => {
|
|
18
|
+
const resolved = typeof token === "function" ? await token() : token ?? initialToken.value;
|
|
19
|
+
return resolved ?? void 0;
|
|
20
|
+
};
|
|
21
|
+
const asyncData = useAsyncData(
|
|
22
|
+
key,
|
|
23
|
+
async () => {
|
|
24
|
+
const currentArgs = toValue(args) ?? {};
|
|
25
|
+
if (currentArgs === "skip") {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (import.meta.server) {
|
|
29
|
+
if (!deploymentUrl) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"`useAsyncQuery` could not fetch during SSR: no Convex deployment URL is configured. Set the `convex.url` module option or NUXT_PUBLIC_CONVEX_URL."
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const value2 = await fetchQuery(queryReference, currentArgs, {
|
|
35
|
+
token: await resolveToken(),
|
|
36
|
+
url: deploymentUrl
|
|
37
|
+
});
|
|
38
|
+
return { value: convexToJson(value2) };
|
|
39
|
+
}
|
|
40
|
+
if (!client) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"`useAsyncQuery` could not fetch on the client: no Convex client is available. Is the `convex.url` module option (or NUXT_PUBLIC_CONVEX_URL) configured?"
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const value = await client.query(queryReference, currentArgs);
|
|
46
|
+
return { value: convexToJson(value) };
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
server,
|
|
50
|
+
lazy,
|
|
51
|
+
deep: false,
|
|
52
|
+
// Skipped-at-setup queries start idle instead of "successfully null".
|
|
53
|
+
immediate: initialArgs !== "skip"
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
const payloadValue = computed(() => {
|
|
57
|
+
const entry = asyncData.data.value;
|
|
58
|
+
if (entry === null || entry === void 0) {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
return jsonToConvex(entry.value);
|
|
62
|
+
});
|
|
63
|
+
const liveResults = !import.meta.server && live && client ? useConvexQueries(computed(() => {
|
|
64
|
+
const currentArgs = toValue(args) ?? {};
|
|
65
|
+
if (currentArgs === "skip") {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
query: { query: queryReference, args: currentArgs }
|
|
70
|
+
};
|
|
71
|
+
})) : shallowRef({});
|
|
72
|
+
const liveValue = computed(() => {
|
|
73
|
+
const result2 = liveResults.value["query"];
|
|
74
|
+
return result2 instanceof Error ? void 0 : result2;
|
|
75
|
+
});
|
|
76
|
+
const liveError = computed(() => {
|
|
77
|
+
const result2 = liveResults.value["query"];
|
|
78
|
+
return result2 instanceof Error ? result2 : null;
|
|
79
|
+
});
|
|
80
|
+
const data = computed(
|
|
81
|
+
() => liveValue.value !== void 0 ? liveValue.value : payloadValue.value
|
|
82
|
+
);
|
|
83
|
+
const error = computed(
|
|
84
|
+
() => liveError.value ?? asyncData.error.value ?? null
|
|
85
|
+
);
|
|
86
|
+
const status = computed(() => {
|
|
87
|
+
if (liveError.value) {
|
|
88
|
+
return "error";
|
|
89
|
+
}
|
|
90
|
+
if (liveValue.value !== void 0) {
|
|
91
|
+
return "success";
|
|
92
|
+
}
|
|
93
|
+
return asyncData.status.value;
|
|
94
|
+
});
|
|
95
|
+
const refresh = (opts) => asyncData.refresh(opts);
|
|
96
|
+
const result = { data, error, status, refresh };
|
|
97
|
+
const promise = Promise.resolve(asyncData).then(() => result);
|
|
98
|
+
return Object.assign(promise, result);
|
|
99
|
+
}
|
|
100
|
+
export function defaultAsyncQueryKey(queryName, initialArgs) {
|
|
101
|
+
const argsJson = initialArgs === "skip" ? '"skip"' : JSON.stringify(convexToJson(initialArgs ?? {}));
|
|
102
|
+
return `convex:${queryName}:${argsJson}`;
|
|
103
|
+
}
|
|
104
|
+
export const useConvexAsyncQuery = useAsyncQuery;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
export function getConvexRuntimeConfig() {
|
|
3
|
+
try {
|
|
4
|
+
const config = useRuntimeConfig();
|
|
5
|
+
return {
|
|
6
|
+
url: config.public?.convex?.url,
|
|
7
|
+
siteUrl: config.convex?.siteUrl || config.public?.convex?.siteUrl
|
|
8
|
+
};
|
|
9
|
+
} catch {
|
|
10
|
+
return {};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for integrating Convex into Nuxt applications using server rendering.
|
|
3
|
+
*
|
|
4
|
+
* This module contains:
|
|
5
|
+
* 1. {@link preloadQuery}, for preloading data for reactive client components.
|
|
6
|
+
* 2. {@link fetchQuery}, {@link fetchMutation} and {@link fetchAction} for loading and mutating Convex data
|
|
7
|
+
* from Nuxt server routes, API handlers, and middleware.
|
|
8
|
+
*
|
|
9
|
+
* ## Usage
|
|
10
|
+
*
|
|
11
|
+
* All exported functions assume that a Convex deployment URL is set in the
|
|
12
|
+
* `NUXT_PUBLIC_CONVEX_URL` environment variable. `npx convex dev` will
|
|
13
|
+
* automatically set it during local development.
|
|
14
|
+
*
|
|
15
|
+
* ### Preloading data
|
|
16
|
+
*
|
|
17
|
+
* Preload data inside a server route:
|
|
18
|
+
*
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // server/api/tasks.get.ts
|
|
21
|
+
* export default defineEventHandler(async () => {
|
|
22
|
+
* return await preloadQuery(api.foo.baz)
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* And pass it to a client component:
|
|
27
|
+
* ```vue
|
|
28
|
+
* <script setup lang="ts">
|
|
29
|
+
* const props = defineProps<{
|
|
30
|
+
* preloaded: Preloaded<typeof api.foo.baz>
|
|
31
|
+
* }>()
|
|
32
|
+
*
|
|
33
|
+
* const data = usePreloadedQuery(props.preloaded)
|
|
34
|
+
* // render `data`...
|
|
35
|
+
* </script>
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @module server
|
|
39
|
+
*/
|
|
40
|
+
import type { ArgsAndOptions, FunctionReference, FunctionReturnType } from 'convex/server';
|
|
41
|
+
import type { Preloaded } from '../vue/index.js';
|
|
42
|
+
/**
|
|
43
|
+
* Options to {@link preloadQuery}, {@link fetchQuery}, {@link fetchMutation} and {@link fetchAction}.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export type NuxtOptions = {
|
|
48
|
+
/**
|
|
49
|
+
* The JWT-encoded OpenID Connect authentication token to use for the function call.
|
|
50
|
+
*/
|
|
51
|
+
token?: string;
|
|
52
|
+
/**
|
|
53
|
+
* The URL of the Convex deployment to use for the function call.
|
|
54
|
+
* Defaults to `process.env.NUXT_PUBLIC_CONVEX_URL` if not provided.
|
|
55
|
+
*
|
|
56
|
+
* Explicitly passing undefined here (such as from missing ENV variables) will throw an error in the future.
|
|
57
|
+
*/
|
|
58
|
+
url?: string;
|
|
59
|
+
/**
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
adminToken?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Skip validating that the Convex deployment URL looks like
|
|
65
|
+
* `https://happy-animal-123.convex.cloud` or localhost.
|
|
66
|
+
*
|
|
67
|
+
* This can be useful if running a self-hosted Convex deployment that uses a different
|
|
68
|
+
* URL.
|
|
69
|
+
*
|
|
70
|
+
* The default value is `false`
|
|
71
|
+
*/
|
|
72
|
+
skipConvexDeploymentUrlCheck?: boolean;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Execute a Convex query function and return a `Preloaded`
|
|
76
|
+
* payload which can be passed to `usePreloadedQuery` in a client
|
|
77
|
+
* component.
|
|
78
|
+
*
|
|
79
|
+
* @param query - a `FunctionReference` for the public query to run
|
|
80
|
+
* like `api.dir1.dir2.filename.func`.
|
|
81
|
+
* @param args - The arguments object for the query. If this is omitted,
|
|
82
|
+
* the arguments will be `{}`.
|
|
83
|
+
* @param options - A {@link NuxtOptions} options object for the query.
|
|
84
|
+
* @returns A promise of the `Preloaded` payload.
|
|
85
|
+
*
|
|
86
|
+
* @public
|
|
87
|
+
*/
|
|
88
|
+
export declare function preloadQuery<Query extends FunctionReference<'query'>>(query: Query, ...args: ArgsAndOptions<Query, NuxtOptions>): Promise<Preloaded<Query>>;
|
|
89
|
+
/**
|
|
90
|
+
* Returns the result of executing a query via {@link preloadQuery}.
|
|
91
|
+
*
|
|
92
|
+
* @param preloaded - The `Preloaded` payload returned by {@link preloadQuery}.
|
|
93
|
+
* @returns The query result.
|
|
94
|
+
*
|
|
95
|
+
* @public
|
|
96
|
+
*/
|
|
97
|
+
export declare function preloadedQueryResult<Query extends FunctionReference<'query'>>(preloaded: Preloaded<Query>): FunctionReturnType<Query>;
|
|
98
|
+
/**
|
|
99
|
+
* Execute a Convex query function.
|
|
100
|
+
*
|
|
101
|
+
* @param query - a `FunctionReference` for the public query to run
|
|
102
|
+
* like `api.dir1.dir2.filename.func`.
|
|
103
|
+
* @param args - The arguments object for the query. If this is omitted,
|
|
104
|
+
* the arguments will be `{}`.
|
|
105
|
+
* @param options - A {@link NuxtOptions} options object for the query.
|
|
106
|
+
* @returns A promise of the query's result.
|
|
107
|
+
*
|
|
108
|
+
* @public
|
|
109
|
+
*/
|
|
110
|
+
export declare function fetchQuery<Query extends FunctionReference<'query'>>(query: Query, ...args: ArgsAndOptions<Query, NuxtOptions>): Promise<FunctionReturnType<Query>>;
|
|
111
|
+
/**
|
|
112
|
+
* Execute a Convex mutation function.
|
|
113
|
+
*
|
|
114
|
+
* @param mutation - A `FunctionReference` for the public mutation
|
|
115
|
+
* to run like `api.dir1.dir2.filename.func`.
|
|
116
|
+
* @param args - The arguments object for the mutation. If this is omitted,
|
|
117
|
+
* the arguments will be `{}`.
|
|
118
|
+
* @param options - A {@link NuxtOptions} options object for the mutation.
|
|
119
|
+
* @returns A promise of the mutation's result.
|
|
120
|
+
*
|
|
121
|
+
* @public
|
|
122
|
+
*/
|
|
123
|
+
export declare function fetchMutation<Mutation extends FunctionReference<'mutation'>>(mutation: Mutation, ...args: ArgsAndOptions<Mutation, NuxtOptions>): Promise<FunctionReturnType<Mutation>>;
|
|
124
|
+
/**
|
|
125
|
+
* Execute a Convex action function.
|
|
126
|
+
*
|
|
127
|
+
* @param action - A `FunctionReference` for the public action
|
|
128
|
+
* to run like `api.dir1.dir2.filename.func`.
|
|
129
|
+
* @param args - The arguments object for the action. If this is omitted,
|
|
130
|
+
* the arguments will be `{}`.
|
|
131
|
+
* @param options - A {@link NuxtOptions} options object for the action.
|
|
132
|
+
* @returns A promise of the action's result.
|
|
133
|
+
*
|
|
134
|
+
* @public
|
|
135
|
+
*/
|
|
136
|
+
export declare function fetchAction<Action extends FunctionReference<'action'>>(action: Action, ...args: ArgsAndOptions<Action, NuxtOptions>): Promise<FunctionReturnType<Action>>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
2
|
+
import { getFunctionName } from "convex/server";
|
|
3
|
+
import { convexToJson, jsonToConvex } from "convex/values";
|
|
4
|
+
import { getConvexRuntimeConfig } from "./config.js";
|
|
5
|
+
export async function preloadQuery(query, ...args) {
|
|
6
|
+
const value = await fetchQuery(query, ...args);
|
|
7
|
+
const preloaded = {
|
|
8
|
+
_name: getFunctionName(query),
|
|
9
|
+
_argsJSON: convexToJson(args[0] ?? {}),
|
|
10
|
+
_valueJSON: convexToJson(value)
|
|
11
|
+
};
|
|
12
|
+
return preloaded;
|
|
13
|
+
}
|
|
14
|
+
export function preloadedQueryResult(preloaded) {
|
|
15
|
+
return jsonToConvex(preloaded._valueJSON);
|
|
16
|
+
}
|
|
17
|
+
export async function fetchQuery(query, ...args) {
|
|
18
|
+
const [fnArgs, options] = args;
|
|
19
|
+
const client = setupClient(options ?? {});
|
|
20
|
+
return client.query(query, fnArgs || {});
|
|
21
|
+
}
|
|
22
|
+
export async function fetchMutation(mutation, ...args) {
|
|
23
|
+
const [fnArgs, options] = args;
|
|
24
|
+
const client = setupClient(options ?? {});
|
|
25
|
+
return client.mutation(mutation, fnArgs || {});
|
|
26
|
+
}
|
|
27
|
+
export async function fetchAction(action, ...args) {
|
|
28
|
+
const [fnArgs, options] = args;
|
|
29
|
+
const client = setupClient(options ?? {});
|
|
30
|
+
return client.action(action, fnArgs || {});
|
|
31
|
+
}
|
|
32
|
+
function setupClient(options) {
|
|
33
|
+
if ("url" in options && options.url === void 0) {
|
|
34
|
+
console.error(
|
|
35
|
+
"deploymentUrl is undefined, are your environment variables set? In the future explicitly passing undefined will cause an error. To explicitly use the default, pass `process.env.NUXT_PUBLIC_CONVEX_URL`."
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const client = new ConvexHttpClient(
|
|
39
|
+
getConvexUrl(options.url, options.skipConvexDeploymentUrlCheck ?? false)
|
|
40
|
+
);
|
|
41
|
+
if (options.token !== void 0) {
|
|
42
|
+
client.setAuth(options.token);
|
|
43
|
+
}
|
|
44
|
+
if (options.adminToken !== void 0) {
|
|
45
|
+
client.setAdminAuth(options.adminToken);
|
|
46
|
+
}
|
|
47
|
+
client.setFetchOptions({ cache: "no-store" });
|
|
48
|
+
return client;
|
|
49
|
+
}
|
|
50
|
+
function getConvexUrl(deploymentUrl, skipConvexDeploymentUrlCheck) {
|
|
51
|
+
const url = deploymentUrl ?? (getConvexRuntimeConfig().url || void 0) ?? (process.env.NUXT_PUBLIC_CONVEX_URL || void 0);
|
|
52
|
+
const isFromEnv = deploymentUrl === void 0;
|
|
53
|
+
if (typeof url !== "string") {
|
|
54
|
+
throw new TypeError(
|
|
55
|
+
isFromEnv ? `Environment variable NUXT_PUBLIC_CONVEX_URL is not set.` : `Convex function called with invalid deployment address.`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (!skipConvexDeploymentUrlCheck) {
|
|
59
|
+
validateDeploymentUrl(url);
|
|
60
|
+
}
|
|
61
|
+
return url;
|
|
62
|
+
}
|
|
63
|
+
function validateDeploymentUrl(deploymentUrl) {
|
|
64
|
+
if (typeof deploymentUrl === "undefined") {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Client created with undefined deployment address. If you used an environment variable, check that it's set.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (typeof deploymentUrl !== "string") {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Invalid deployment address: found ${deploymentUrl}".`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
if (!(deploymentUrl.startsWith("http:") || deploymentUrl.startsWith("https:"))) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Invalid deployment address: Must start with "https://" or "http://". Found "${deploymentUrl}".`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
new URL(deploymentUrl);
|
|
81
|
+
} catch {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Invalid deployment address: "${deploymentUrl}" is not a valid URL. If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (deploymentUrl.endsWith(".convex.site")) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Invalid deployment address: "${deploymentUrl}" ends with .convex.site, which is used for HTTP Actions. Convex deployment URLs typically end with .convex.cloud? If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vue ports of `@convex-dev/polar/react`'s billing components —
|
|
3
|
+
* {@link CheckoutLink} and {@link CustomerPortalLink}.
|
|
4
|
+
*
|
|
5
|
+
* @module polar/client
|
|
6
|
+
*/
|
|
7
|
+
import { type PropType } from 'vue';
|
|
8
|
+
import type { FunctionReference } from 'convex/server';
|
|
9
|
+
/**
|
|
10
|
+
* Args of the Polar-generated `generateCheckoutLink` action. Mirrors the
|
|
11
|
+
* argument shape `@convex-dev/polar`'s component exposes.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export type CheckoutArgs = {
|
|
16
|
+
productIds: string[];
|
|
17
|
+
origin: string;
|
|
18
|
+
successUrl: string;
|
|
19
|
+
subscriptionId?: string;
|
|
20
|
+
metadata?: Record<string, string>;
|
|
21
|
+
/**
|
|
22
|
+
* `string | null` — not the literal-day/week/month/year union — because
|
|
23
|
+
* upstream's action arg is validator-derived (`v.union(v.string(), v.null())`),
|
|
24
|
+
* so the user's `_generated/api` reference types it that way; a narrower type
|
|
25
|
+
* here would reject their `:polar-api` binding. The component *prop* keeps
|
|
26
|
+
* the literal union, matching upstream's React prop declaration.
|
|
27
|
+
*/
|
|
28
|
+
trialInterval?: string | null;
|
|
29
|
+
trialIntervalCount?: number | null;
|
|
30
|
+
locale?: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The subset of the Polar component's action references these components need —
|
|
34
|
+
* a Vue port mirror of `@convex-dev/polar`'s `PolarComponentApi`
|
|
35
|
+
* (`Pick<…, 'generateCheckoutLink' | 'generateCustomerPortalUrl'>`). Supplied
|
|
36
|
+
* via the auto-provided `api.billing` namespace, or passed through `:polar-api`.
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export interface PolarComponentApi {
|
|
41
|
+
generateCheckoutLink?: FunctionReference<'action', 'public', CheckoutArgs, {
|
|
42
|
+
url: string;
|
|
43
|
+
}>;
|
|
44
|
+
generateCustomerPortalUrl?: FunctionReference<'action', 'public', {
|
|
45
|
+
returnUrl?: string;
|
|
46
|
+
}, {
|
|
47
|
+
url: string;
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @example
|
|
52
|
+
* ```vue
|
|
53
|
+
* <CustomerPortalLink>Manage subscription</CustomerPortalLink>
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare const CustomerPortalLink: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
57
|
+
polarApi: {
|
|
58
|
+
type: PropType<PolarComponentApi>;
|
|
59
|
+
default: undefined;
|
|
60
|
+
};
|
|
61
|
+
returnUrl: {
|
|
62
|
+
type: StringConstructor;
|
|
63
|
+
default: undefined;
|
|
64
|
+
};
|
|
65
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
}> | null, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
68
|
+
polarApi: {
|
|
69
|
+
type: PropType<PolarComponentApi>;
|
|
70
|
+
default: undefined;
|
|
71
|
+
};
|
|
72
|
+
returnUrl: {
|
|
73
|
+
type: StringConstructor;
|
|
74
|
+
default: undefined;
|
|
75
|
+
};
|
|
76
|
+
}>> & Readonly<{}>, {
|
|
77
|
+
returnUrl: string;
|
|
78
|
+
polarApi: PolarComponentApi;
|
|
79
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
80
|
+
/**
|
|
81
|
+
* Renders a checkout link. Supports embedded or redirect checkout, with optional lazy loading and trial configuration.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```vue
|
|
85
|
+
* <CheckoutLink :product-ids="[productId]" :trial-interval-count="7" trial-interval="day">
|
|
86
|
+
* Start free trial
|
|
87
|
+
* </CheckoutLink>
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare const CheckoutLink: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
91
|
+
polarApi: {
|
|
92
|
+
type: PropType<PolarComponentApi>;
|
|
93
|
+
default: undefined;
|
|
94
|
+
};
|
|
95
|
+
productIds: {
|
|
96
|
+
type: PropType<string[]>;
|
|
97
|
+
required: true;
|
|
98
|
+
};
|
|
99
|
+
subscriptionId: {
|
|
100
|
+
type: StringConstructor;
|
|
101
|
+
default: undefined;
|
|
102
|
+
};
|
|
103
|
+
metadata: {
|
|
104
|
+
type: PropType<Record<string, string>>;
|
|
105
|
+
default: undefined;
|
|
106
|
+
};
|
|
107
|
+
trialInterval: {
|
|
108
|
+
type: PropType<"day" | "week" | "month" | "year" | null>;
|
|
109
|
+
default: undefined;
|
|
110
|
+
};
|
|
111
|
+
trialIntervalCount: {
|
|
112
|
+
type: PropType<number | null>;
|
|
113
|
+
default: undefined;
|
|
114
|
+
};
|
|
115
|
+
locale: {
|
|
116
|
+
type: StringConstructor;
|
|
117
|
+
default: undefined;
|
|
118
|
+
};
|
|
119
|
+
theme: {
|
|
120
|
+
type: PropType<"dark" | "light">;
|
|
121
|
+
default: string;
|
|
122
|
+
};
|
|
123
|
+
embed: {
|
|
124
|
+
type: BooleanConstructor;
|
|
125
|
+
default: boolean;
|
|
126
|
+
};
|
|
127
|
+
lazy: {
|
|
128
|
+
type: BooleanConstructor;
|
|
129
|
+
default: boolean;
|
|
130
|
+
};
|
|
131
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
132
|
+
[key: string]: any;
|
|
133
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
134
|
+
polarApi: {
|
|
135
|
+
type: PropType<PolarComponentApi>;
|
|
136
|
+
default: undefined;
|
|
137
|
+
};
|
|
138
|
+
productIds: {
|
|
139
|
+
type: PropType<string[]>;
|
|
140
|
+
required: true;
|
|
141
|
+
};
|
|
142
|
+
subscriptionId: {
|
|
143
|
+
type: StringConstructor;
|
|
144
|
+
default: undefined;
|
|
145
|
+
};
|
|
146
|
+
metadata: {
|
|
147
|
+
type: PropType<Record<string, string>>;
|
|
148
|
+
default: undefined;
|
|
149
|
+
};
|
|
150
|
+
trialInterval: {
|
|
151
|
+
type: PropType<"day" | "week" | "month" | "year" | null>;
|
|
152
|
+
default: undefined;
|
|
153
|
+
};
|
|
154
|
+
trialIntervalCount: {
|
|
155
|
+
type: PropType<number | null>;
|
|
156
|
+
default: undefined;
|
|
157
|
+
};
|
|
158
|
+
locale: {
|
|
159
|
+
type: StringConstructor;
|
|
160
|
+
default: undefined;
|
|
161
|
+
};
|
|
162
|
+
theme: {
|
|
163
|
+
type: PropType<"dark" | "light">;
|
|
164
|
+
default: string;
|
|
165
|
+
};
|
|
166
|
+
embed: {
|
|
167
|
+
type: BooleanConstructor;
|
|
168
|
+
default: boolean;
|
|
169
|
+
};
|
|
170
|
+
lazy: {
|
|
171
|
+
type: BooleanConstructor;
|
|
172
|
+
default: boolean;
|
|
173
|
+
};
|
|
174
|
+
}>> & Readonly<{}>, {
|
|
175
|
+
lazy: boolean;
|
|
176
|
+
metadata: Record<string, string>;
|
|
177
|
+
embed: boolean;
|
|
178
|
+
subscriptionId: string;
|
|
179
|
+
trialInterval: "day" | "week" | "month" | "year" | null;
|
|
180
|
+
trialIntervalCount: number | null;
|
|
181
|
+
locale: string;
|
|
182
|
+
polarApi: PolarComponentApi;
|
|
183
|
+
theme: "dark" | "light";
|
|
184
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|