nuxt-convex-module 0.13.0 → 0.14.1

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.
Files changed (30) hide show
  1. package/dist/devtools-client/index.html +1 -1
  2. package/dist/module.d.mts +18 -0
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +120 -36
  5. package/dist/runtime/better-auth/nuxt/middleware.js +8 -2
  6. package/dist/runtime/better-auth/nuxt/no-session-vary.d.ts +38 -0
  7. package/dist/runtime/better-auth/nuxt/no-session-vary.js +21 -0
  8. package/dist/runtime/better-auth/nuxt/server.js +2 -1
  9. package/dist/runtime/better-auth/nuxt/shared-render.d.ts +9 -0
  10. package/dist/runtime/better-auth/nuxt/shared-render.js +17 -0
  11. package/dist/runtime/better-auth/vue/auth-client-loader.d.ts +17 -0
  12. package/dist/runtime/better-auth/vue/auth-client-loader.js +186 -0
  13. package/dist/runtime/better-auth/vue/cross-domain.d.ts +2 -2
  14. package/dist/runtime/better-auth/vue/cross-domain.js +41 -35
  15. package/dist/runtime/better-auth/vue/index.d.ts +1 -0
  16. package/dist/runtime/better-auth/vue/index.js +1 -0
  17. package/dist/runtime/better-auth/vue/plugin.client.js +21 -2
  18. package/dist/runtime/better-auth/vue/plugin.server.js +23 -3
  19. package/dist/runtime/better-auth/vue/token-store.js +4 -0
  20. package/dist/runtime/better-auth/vue/use-better-auth.d.ts +7 -1
  21. package/dist/runtime/better-auth/vue/use-better-auth.js +78 -6
  22. package/dist/runtime/nuxt/function-name.d.ts +9 -0
  23. package/dist/runtime/nuxt/function-name.js +44 -0
  24. package/dist/runtime/nuxt/index.js +4 -3
  25. package/dist/runtime/nuxt/testing.d.ts +21 -0
  26. package/dist/runtime/nuxt/testing.js +1 -0
  27. package/dist/runtime/vue/composables/use-upload-queue.d.ts +82 -6
  28. package/dist/runtime/vue/composables/use-upload-queue.js +96 -25
  29. package/dist/runtime/vue/index.d.ts +1 -1
  30. package/package.json +8 -1
@@ -1,4 +1,5 @@
1
- import { computed, ref } from "vue";
1
+ import { ConvexError } from "convex/values";
2
+ import { computed, ref, toRaw } from "vue";
2
3
  import { useConvexOrThrow } from "../client.js";
3
4
  import { uploadFile } from "./use-upload.js";
4
5
  function normalizeFiles(input) {
@@ -16,6 +17,12 @@ export function useUploadQueue(generateUploadUrl, options = {}) {
16
17
  const concurrency = Math.max(1, Math.floor(options.concurrency ?? 3));
17
18
  const items = ref([]);
18
19
  const controllers = /* @__PURE__ */ new Map();
20
+ const afterDone = /* @__PURE__ */ new Set();
21
+ const resend = /* @__PURE__ */ new Set();
22
+ let running = 0;
23
+ let generation = 0;
24
+ let cutOff = 0;
25
+ let held = false;
19
26
  const activeCount = computed(
20
27
  () => items.value.filter((item) => item.status === "uploading").length
21
28
  );
@@ -30,43 +37,81 @@ export function useUploadQueue(generateUploadUrl, options = {}) {
30
37
  });
31
38
  function pump() {
32
39
  if (typeof XMLHttpRequest === "undefined") return;
33
- let slots = concurrency - activeCount.value;
34
40
  for (const item of items.value) {
35
- if (slots <= 0) break;
41
+ if (held || activeCount.value >= concurrency) break;
36
42
  if (item.status !== "pending") continue;
37
- slots--;
38
43
  void run(item);
39
44
  }
40
45
  }
46
+ const isRefusal = options.isRefusal ?? ((error) => error instanceof ConvexError);
47
+ async function transfer(item, signal) {
48
+ if (options.prepare && item.prepared === null) {
49
+ item.stage = "prepare";
50
+ const prepared = await options.prepare(toRaw(item.file), item, signal);
51
+ signal.throwIfAborted();
52
+ item.prepared = prepared;
53
+ }
54
+ item.stage = "upload";
55
+ const url = await convex.mutation(generateUploadUrl, {});
56
+ const storageId = await uploadFile({
57
+ url,
58
+ // The blob itself, not a reactive proxy of it, wherever Vue would wrap one.
59
+ file: toRaw(item.prepared ?? item.file),
60
+ signal,
61
+ onProgress: (value) => {
62
+ item.progress = value;
63
+ }
64
+ });
65
+ item.progress = 1;
66
+ return storageId;
67
+ }
68
+ function refusal(failure, item) {
69
+ try {
70
+ return isRefusal(failure, item);
71
+ } catch {
72
+ return false;
73
+ }
74
+ }
75
+ function fail(item, caught, signal) {
76
+ const failure = caught instanceof Error ? caught : new Error(String(caught));
77
+ item.refused = !signal.aborted && refusal(failure, item);
78
+ if (item.refused && item.stage === "after") resend.add(item.id);
79
+ item.stage = null;
80
+ item.error = failure;
81
+ item.status = "error";
82
+ options.onItemError?.(failure, item);
83
+ }
41
84
  async function run(item) {
85
+ const own = generation;
86
+ running++;
42
87
  item.status = "uploading";
43
88
  const controller = new AbortController();
44
89
  controllers.set(item.id, controller);
90
+ const { signal } = controller;
45
91
  try {
46
- const url = await convex.mutation(generateUploadUrl, {});
47
- const storageId = await uploadFile({
48
- url,
49
- file: item.file,
50
- signal: controller.signal,
51
- onProgress: (value) => {
52
- item.progress = value;
53
- }
54
- });
55
- item.storageId = storageId;
56
- item.progress = 1;
92
+ const storageId = item.storageId ??= await transfer(item, signal);
93
+ if (options.after && !afterDone.has(item.id)) {
94
+ item.stage = "after";
95
+ await options.after(storageId, item, signal);
96
+ afterDone.add(item.id);
97
+ signal.throwIfAborted();
98
+ }
99
+ item.stage = null;
57
100
  item.status = "success";
58
101
  await options.onItemSuccess?.(storageId, item);
59
102
  } catch (caught) {
60
- const failure = caught instanceof Error ? caught : new Error(String(caught));
61
- item.error = failure;
62
- item.status = "error";
63
- options.onItemError?.(failure, item);
103
+ fail(item, caught, signal);
64
104
  } finally {
65
- controllers.delete(item.id);
66
- if (pendingCount.value === 0 && activeCount.value === 0) {
67
- options.onComplete?.(items.value);
105
+ if (own !== generation) {
106
+ if (--cutOff === 0 && items.value.length === 0) options.onComplete?.([]);
68
107
  } else {
69
- pump();
108
+ running--;
109
+ if (controllers.get(item.id) === controller) controllers.delete(item.id);
110
+ if (pendingCount.value === 0 && running === 0) {
111
+ options.onComplete?.(items.value);
112
+ } else if (!signal.aborted) {
113
+ pump();
114
+ }
70
115
  }
71
116
  }
72
117
  }
@@ -80,12 +125,17 @@ export function useUploadQueue(generateUploadUrl, options = {}) {
80
125
  status: "pending",
81
126
  progress: 0,
82
127
  storageId: null,
83
- error: null
128
+ error: null,
129
+ refused: false,
130
+ stage: null,
131
+ prepared: null
84
132
  }))
85
133
  );
134
+ held = false;
86
135
  pump();
87
136
  }
88
137
  function cancel() {
138
+ held = true;
89
139
  for (const controller of controllers.values()) {
90
140
  controller.abort();
91
141
  }
@@ -93,11 +143,31 @@ export function useUploadQueue(generateUploadUrl, options = {}) {
93
143
  function remove(id) {
94
144
  controllers.get(id)?.abort();
95
145
  controllers.delete(id);
146
+ afterDone.delete(id);
147
+ resend.delete(id);
96
148
  items.value = items.value.filter((item) => item.id !== id);
149
+ pump();
150
+ }
151
+ function retry(id) {
152
+ for (const item of items.value) {
153
+ if (item.status !== "error" || id !== void 0 && item.id !== id) continue;
154
+ item.status = "pending";
155
+ item.error = null;
156
+ item.refused = false;
157
+ if (resend.delete(item.id)) item.storageId = null;
158
+ if (item.storageId === null) item.progress = 0;
159
+ }
160
+ held = false;
161
+ pump();
97
162
  }
98
163
  function clear() {
99
164
  cancel();
165
+ generation++;
166
+ cutOff += running;
167
+ running = 0;
100
168
  controllers.clear();
169
+ afterDone.clear();
170
+ resend.clear();
101
171
  items.value = [];
102
172
  }
103
173
  return {
@@ -109,7 +179,8 @@ export function useUploadQueue(generateUploadUrl, options = {}) {
109
179
  activeCount,
110
180
  cancel,
111
181
  remove,
112
- clear
182
+ clear,
183
+ retry
113
184
  };
114
185
  }
115
186
  export const useConvexUploadQueue = useUploadQueue;
@@ -88,6 +88,6 @@ export type { ConnectionState, OptimisticUpdate, QueryJournal, } from 'convex/br
88
88
  export type { FunctionReference, FunctionReference_future, FunctionArgs, FunctionReturnType, OptionalRestArgs, ArgsAndOptions, } from 'convex/server';
89
89
  export type { Value } from 'convex/values';
90
90
  export { useUpload, useConvexUpload, uploadFile, type VueUpload, type UseUploadOptions, type UploadFileOptions, type GenerateUploadUrl, type StorageId, } from './composables/use-upload.js';
91
- export { useUploadQueue, useConvexUploadQueue, type VueUploadQueue, type UseUploadQueueOptions, type UploadQueueItem, type UploadItemStatus, type EnqueueInput, } from './composables/use-upload-queue.js';
91
+ export { useUploadQueue, useConvexUploadQueue, type VueUploadQueue, type UseUploadQueueOptions, type UploadQueueItem, type UploadItemStage, type UploadItemStatus, type EnqueueInput, } from './composables/use-upload-queue.js';
92
92
  export { useStorageUrl, useConvexStorageUrl, type GetStorageUrl, } from './composables/use-storage-url.js';
93
93
  export { ConvexImage } from './components/convex-image.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "nuxt-convex-module",
4
- "version": "0.13.0",
4
+ "version": "0.14.1",
5
5
  "description": "Convex backend integration with live queries, mutations, actions, pagination, file storage and SSR, auto-imported and typed against your deployment. The same Vue client runs without Nuxt; Better Auth, Clerk, Auth0 and Polar are opt-in.",
6
6
  "repository": {
7
7
  "type": "git",
@@ -60,6 +60,10 @@
60
60
  "types": "./dist/runtime/nuxt/app.d.ts",
61
61
  "import": "./dist/runtime/nuxt/app.js"
62
62
  },
63
+ "./testing": {
64
+ "types": "./dist/runtime/nuxt/testing.d.ts",
65
+ "import": "./dist/runtime/nuxt/testing.js"
66
+ },
63
67
  "./better-auth/client": {
64
68
  "types": "./dist/runtime/better-auth/vue/index.d.ts",
65
69
  "import": "./dist/runtime/better-auth/vue/index.js"
@@ -115,6 +119,9 @@
115
119
  "app": [
116
120
  "./dist/runtime/nuxt/app.d.ts"
117
121
  ],
122
+ "testing": [
123
+ "./dist/runtime/nuxt/testing.d.ts"
124
+ ],
118
125
  "better-auth/client": [
119
126
  "./dist/runtime/better-auth/vue/index.d.ts"
120
127
  ],