@wervt/nuxt 0.3.1 → 0.3.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/README.md +4 -0
- package/dist/dev.d.ts +3 -1
- package/dist/env-types.js +14 -0
- package/dist/icons.js +31 -0
- package/dist/module.d.ts +8 -0
- package/dist/module.js +59 -0
- package/dist/node_modules/.pnpm/nitro@3.0.260903-beta/node_modules/nitro/dist/runtime/task.js +1 -2
- package/dist/og-image.js +39 -0
- package/dist/preview.d.ts +14 -0
- package/dist/preview.js +39 -0
- package/dist/provision.d.ts +19 -2
- package/dist/provision.js +49 -2
- package/dist/runtime/app/snapshot.d.ts +17 -0
- package/dist/runtime/app/snapshot.js +64 -0
- package/dist/runtime/app/useShape.d.ts +8 -1
- package/dist/runtime/app/useShape.js +8 -52
- package/dist/runtime/app/useWervtFeedback.d.ts +2 -1
- package/dist/runtime/email/index.d.ts +2 -1
- package/dist/runtime/email/index.js +2 -1
- package/dist/runtime/email/invite.d.ts +75 -0
- package/dist/runtime/email/invite.js +60 -0
- package/dist/runtime/server/access.d.ts +35 -0
- package/dist/runtime/server/access.js +88 -0
- package/dist/runtime/server/agent-token-plugin.d.ts +13 -0
- package/dist/runtime/server/agent-token-plugin.js +10 -0
- package/dist/runtime/server/anthropic.d.ts +21 -0
- package/dist/runtime/server/anthropic.js +53 -0
- package/dist/runtime/server/identity.d.ts +20 -0
- package/dist/runtime/server/identity.js +37 -0
- package/dist/runtime/server/index.d.ts +5 -3
- package/dist/runtime/server/index.js +4 -2
- package/dist/runtime/server/task-handlers.d.ts +2 -1
- package/dist/runtime/server/tools.d.ts +2 -1
- package/dist/runtime/server/user.d.ts +9 -3
- package/dist/runtime/server/user.js +28 -3
- package/dist/runtime/server/validate.d.ts +2 -1
- package/dist/runtime/shared/agent-token.d.ts +9 -0
- package/dist/runtime/shared/agent-token.js +17 -0
- package/dist/runtime/shared/shape.d.ts +2 -1
- package/dist/runtime/shared/user.d.ts +8 -0
- package/dist/runtime/shared/user.js +4 -1
- package/dist/storage.d.ts +48 -1
- package/dist/storage.js +217 -3
- package/package.json +15 -6
package/dist/storage.d.ts
CHANGED
|
@@ -13,14 +13,61 @@ export interface StorageUsage {
|
|
|
13
13
|
bytes: number;
|
|
14
14
|
/** Multipart uploads started but never completed or aborted. */
|
|
15
15
|
unfinishedUploads: number;
|
|
16
|
+
/** The bucket's size limit in bytes, null for none. */
|
|
17
|
+
maxBytes: number | null;
|
|
18
|
+
}
|
|
19
|
+
export interface StorageQuota {
|
|
20
|
+
/** Bytes the bucket may hold; null for no limit. Garage refuses uploads past it. */
|
|
21
|
+
maxBytes: number | null;
|
|
16
22
|
}
|
|
17
23
|
export declare class StorageError extends Error {}
|
|
24
|
+
export interface StoredObject {
|
|
25
|
+
key: string;
|
|
26
|
+
size: number;
|
|
27
|
+
/** ISO time. */
|
|
28
|
+
lastModified: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ObjectListing {
|
|
31
|
+
prefix: string;
|
|
32
|
+
/** Prefixes one level below `prefix`, ending in `/`. */
|
|
33
|
+
folders: string[];
|
|
34
|
+
files: StoredObject[];
|
|
35
|
+
/** Pass as `token` for the next page. */
|
|
36
|
+
next?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ObjectDetails extends StoredObject {
|
|
39
|
+
contentType: string | null;
|
|
40
|
+
/** `x-amz-meta-*` headers, without the prefix. */
|
|
41
|
+
metadata: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
/** S3's limit for object keys, in bytes. */
|
|
44
|
+
export declare const MAX_KEY_BYTES = 1024;
|
|
18
45
|
export declare function createStorage(options: StorageOptions): {
|
|
19
46
|
ensureLayout: () => Promise<void>;
|
|
20
|
-
provision: (app: string, appOrigin: string) => Promise<{
|
|
47
|
+
provision: (app: string, appOrigin: string, quota?: StorageQuota) => Promise<{
|
|
21
48
|
bucket: string;
|
|
22
49
|
}>;
|
|
50
|
+
setQuota: (app: string, quota: StorageQuota) => Promise<boolean>;
|
|
23
51
|
usage: (app: string) => Promise<StorageUsage | undefined>;
|
|
52
|
+
list: (app: string, { prefix, token, limit }?: {
|
|
53
|
+
prefix?: string;
|
|
54
|
+
token?: string;
|
|
55
|
+
limit?: number;
|
|
56
|
+
}) => Promise<ObjectListing | undefined>;
|
|
57
|
+
describe: (app: string, key: string) => Promise<ObjectDetails | undefined>;
|
|
58
|
+
downloadUrl: (app: string, key: string, { publicUrl, expiresIn }: {
|
|
59
|
+
publicUrl: string;
|
|
60
|
+
expiresIn?: number;
|
|
61
|
+
}) => Promise<string>;
|
|
62
|
+
remove: (app: string, key: string) => Promise<{
|
|
63
|
+
deleted: string[];
|
|
64
|
+
} | undefined>;
|
|
65
|
+
sweepAbandonedUploads: (app: string, { graceMs, now }?: {
|
|
66
|
+
graceMs?: number | undefined;
|
|
67
|
+
now?: number | undefined;
|
|
68
|
+
}) => Promise<{
|
|
69
|
+
deleted: string[];
|
|
70
|
+
}>;
|
|
24
71
|
drop: (app: string) => Promise<void>;
|
|
25
72
|
};
|
|
26
73
|
//#endregion
|
package/dist/storage.js
CHANGED
|
@@ -2,6 +2,75 @@ import { storageCredentials } from "./provision.js";
|
|
|
2
2
|
import { AwsClient } from "aws4fetch";
|
|
3
3
|
//#region src/storage.ts
|
|
4
4
|
var StorageError = class extends Error {};
|
|
5
|
+
/**
|
|
6
|
+
* ablage marks bytes uploaded straight from browsers (`x-amz-meta-ablage-direct-upload`). Its
|
|
7
|
+
* metadata object (`<group>/meta/<id>`) is only written once `completeUpload()` has checked them,
|
|
8
|
+
* so marked bytes without one belong to an upload that was never completed.
|
|
9
|
+
*/
|
|
10
|
+
const DIRECT_UPLOAD_MARKER = "x-amz-meta-ablage-direct-upload";
|
|
11
|
+
/**
|
|
12
|
+
* How old abandoned direct-upload bytes must be before the sweep deletes them. The browser calls
|
|
13
|
+
* `completeUpload()` right after its `PUT` finishes, so a day leaves any upload in flight alone;
|
|
14
|
+
* it matches the lifecycle rule for multipart uploads.
|
|
15
|
+
*/
|
|
16
|
+
const ABANDONED_UPLOAD_GRACE_MS = 864e5;
|
|
17
|
+
/** ablage's S3 layout: `<group>/data/<id>` holds the bytes, `<group>/meta/<id>` the metadata. */
|
|
18
|
+
function metaKeyOf(key) {
|
|
19
|
+
const parts = key.split("/");
|
|
20
|
+
if (parts.length < 3 || parts.at(-2) !== "data" || !parts.at(-1)) return void 0;
|
|
21
|
+
return [
|
|
22
|
+
...parts.slice(0, -2),
|
|
23
|
+
"meta",
|
|
24
|
+
parts.at(-1)
|
|
25
|
+
].join("/");
|
|
26
|
+
}
|
|
27
|
+
const unescapeXml = (text) => text.replace(/&(amp|lt|gt|quot|apos|#x?[0-9a-f]+);/gi, (_, entity) => {
|
|
28
|
+
const named = {
|
|
29
|
+
amp: "&",
|
|
30
|
+
lt: "<",
|
|
31
|
+
gt: ">",
|
|
32
|
+
quot: "\"",
|
|
33
|
+
apos: "'"
|
|
34
|
+
};
|
|
35
|
+
if (entity in named) return named[entity];
|
|
36
|
+
const hex = entity[1] === "x" || entity[1] === "X";
|
|
37
|
+
return String.fromCodePoint(parseInt(entity.slice(hex ? 2 : 1), hex ? 16 : 10));
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Objects of a ListObjectsV2 page, its folders (listed with a delimiter), and the token for the
|
|
41
|
+
* next page.
|
|
42
|
+
*/
|
|
43
|
+
function parseObjectList(xml) {
|
|
44
|
+
const objects = [...xml.matchAll(/<Contents>([\s\S]*?)<\/Contents>/g)].map(([, entry]) => ({
|
|
45
|
+
key: unescapeXml(/<Key>([^<]*)<\/Key>/.exec(entry)?.[1] ?? ""),
|
|
46
|
+
lastModified: Date.parse(/<LastModified>([^<]*)<\/LastModified>/.exec(entry)?.[1] ?? ""),
|
|
47
|
+
size: Number(/<Size>([^<]*)<\/Size>/.exec(entry)?.[1] ?? 0)
|
|
48
|
+
}));
|
|
49
|
+
const prefixes = [...xml.matchAll(/<CommonPrefixes>([\s\S]*?)<\/CommonPrefixes>/g)].map(([, entry]) => unescapeXml(/<Prefix>([^<]*)<\/Prefix>/.exec(entry)?.[1] ?? ""));
|
|
50
|
+
const next = /<IsTruncated>true<\/IsTruncated>/.test(xml) ? /<NextContinuationToken>([^<]*)<\/NextContinuationToken>/.exec(xml)?.[1] : void 0;
|
|
51
|
+
return {
|
|
52
|
+
objects,
|
|
53
|
+
prefixes,
|
|
54
|
+
next: next === void 0 ? void 0 : unescapeXml(next)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* ablage keeps a file as bytes and metadata, which only make sense together: the metadata key
|
|
59
|
+
* for bytes, the bytes for metadata, undefined for anything else.
|
|
60
|
+
*/
|
|
61
|
+
function companionKeyOf(key) {
|
|
62
|
+
const meta = metaKeyOf(key);
|
|
63
|
+
if (meta !== void 0) return meta;
|
|
64
|
+
const parts = key.split("/");
|
|
65
|
+
if (parts.length < 3 || parts.at(-2) !== "meta" || !parts.at(-1)) return void 0;
|
|
66
|
+
return [
|
|
67
|
+
...parts.slice(0, -2),
|
|
68
|
+
"data",
|
|
69
|
+
parts.at(-1)
|
|
70
|
+
].join("/");
|
|
71
|
+
}
|
|
72
|
+
/** S3's limit for object keys, in bytes. */
|
|
73
|
+
const MAX_KEY_BYTES = 1024;
|
|
5
74
|
function createStorage(options) {
|
|
6
75
|
async function admin(path, body) {
|
|
7
76
|
const res = await fetch(`${options.adminUrl}/v2/${path}`, {
|
|
@@ -52,8 +121,9 @@ function createStorage(options) {
|
|
|
52
121
|
/**
|
|
53
122
|
* Creates the app's bucket and key if they're missing, lets the app's origin upload and
|
|
54
123
|
* download from browsers (CORS), and cleans up abandoned uploads. Safe to run on every deploy.
|
|
124
|
+
* With `quota`, sets the bucket's size limit too; without, leaves it as it is.
|
|
55
125
|
*/
|
|
56
|
-
async function provision(app, appOrigin) {
|
|
126
|
+
async function provision(app, appOrigin, quota) {
|
|
57
127
|
const { creds, client, base } = await s3(app);
|
|
58
128
|
const bucket = await exists(`GetBucketInfo?globalAlias=${creds.bucket}`) ?? await admin("CreateBucket", { globalAlias: creds.bucket });
|
|
59
129
|
if (!await exists(`GetKeyInfo?id=${creds.accessKeyId}`)) await admin("ImportKey", {
|
|
@@ -70,6 +140,7 @@ function createStorage(options) {
|
|
|
70
140
|
owner: true
|
|
71
141
|
}
|
|
72
142
|
});
|
|
143
|
+
if (quota) await applyQuota(bucket.id, quota);
|
|
73
144
|
const cors = `<CORSConfiguration><CORSRule>
|
|
74
145
|
<AllowedOrigin>${appOrigin}</AllowedOrigin>
|
|
75
146
|
<AllowedMethod>GET</AllowedMethod><AllowedMethod>HEAD</AllowedMethod>
|
|
@@ -92,6 +163,20 @@ function createStorage(options) {
|
|
|
92
163
|
if (!rules.ok) throw new StorageError(`setting the lifecycle for ${creds.bucket}: ${await rules.text()}`);
|
|
93
164
|
return { bucket: creds.bucket };
|
|
94
165
|
}
|
|
166
|
+
function applyQuota(bucketId, quota) {
|
|
167
|
+
return admin(`UpdateBucket?id=${bucketId}`, { quotas: {
|
|
168
|
+
maxSize: quota.maxBytes,
|
|
169
|
+
maxObjects: null
|
|
170
|
+
} });
|
|
171
|
+
}
|
|
172
|
+
/** Changes the size limit of an existing bucket. False when the app has no bucket yet. */
|
|
173
|
+
async function setQuota(app, quota) {
|
|
174
|
+
const { creds } = await s3(app);
|
|
175
|
+
const bucket = await exists(`GetBucketInfo?globalAlias=${creds.bucket}`);
|
|
176
|
+
if (!bucket) return false;
|
|
177
|
+
await applyQuota(bucket.id, quota);
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
95
180
|
async function usage(app) {
|
|
96
181
|
const { creds } = await s3(app);
|
|
97
182
|
const info = await exists(`GetBucketInfo?globalAlias=${creds.bucket}`);
|
|
@@ -100,9 +185,48 @@ function createStorage(options) {
|
|
|
100
185
|
bucket: creds.bucket,
|
|
101
186
|
objects: info.objects,
|
|
102
187
|
bytes: info.bytes,
|
|
103
|
-
unfinishedUploads: info.unfinishedMultipartUploads
|
|
188
|
+
unfinishedUploads: info.unfinishedMultipartUploads,
|
|
189
|
+
maxBytes: info.quotas?.maxSize ?? null
|
|
104
190
|
};
|
|
105
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Deletes the bytes of direct uploads that were never completed: marked by ablage, older than
|
|
194
|
+
* `graceMs` and without a metadata object. ablage never lists them, but they count against the
|
|
195
|
+
* bucket quota. Safe to run any time and as often as wanted.
|
|
196
|
+
*/
|
|
197
|
+
async function sweepAbandonedUploads(app, { graceMs = ABANDONED_UPLOAD_GRACE_MS, now = Date.now() } = {}) {
|
|
198
|
+
const { creds, client, base } = await s3(app);
|
|
199
|
+
if (!await exists(`GetBucketInfo?globalAlias=${creds.bucket}`)) return { deleted: [] };
|
|
200
|
+
const url = (key) => `${base}/${key.split("/").map(encodeURIComponent).join("/")}`;
|
|
201
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
202
|
+
let token;
|
|
203
|
+
do {
|
|
204
|
+
const query = `list-type=2&max-keys=1000${token ? `&continuation-token=${encodeURIComponent(token)}` : ""}`;
|
|
205
|
+
const res = await client.fetch(`${base}?${query}`);
|
|
206
|
+
if (!res.ok) throw new StorageError(`listing ${creds.bucket}: ${await res.text()}`);
|
|
207
|
+
const page = parseObjectList(await res.text());
|
|
208
|
+
for (const object of page.objects) {
|
|
209
|
+
candidates.delete(object.key);
|
|
210
|
+
const metaKey = metaKeyOf(object.key);
|
|
211
|
+
if (metaKey !== void 0 && now - object.lastModified >= graceMs) candidates.set(metaKey, object.key);
|
|
212
|
+
}
|
|
213
|
+
token = page.next;
|
|
214
|
+
} while (token);
|
|
215
|
+
const deleted = [];
|
|
216
|
+
for (const [metaKey, key] of candidates) {
|
|
217
|
+
const head = await client.fetch(url(key), { method: "HEAD" });
|
|
218
|
+
if (head.status === 404) continue;
|
|
219
|
+
if (!head.ok) throw new StorageError(`checking ${key} in ${creds.bucket}: ${head.status}`);
|
|
220
|
+
if (!head.headers.get(DIRECT_UPLOAD_MARKER)) continue;
|
|
221
|
+
const meta = await client.fetch(url(metaKey), { method: "HEAD" });
|
|
222
|
+
if (meta.ok) continue;
|
|
223
|
+
if (meta.status !== 404) throw new StorageError(`checking ${metaKey} in ${creds.bucket}: ${meta.status}`);
|
|
224
|
+
const res = await client.fetch(url(key), { method: "DELETE" });
|
|
225
|
+
if (!res.ok && res.status !== 404) throw new StorageError(`deleting ${key} in ${creds.bucket}: ${await res.text()}`);
|
|
226
|
+
deleted.push(key);
|
|
227
|
+
}
|
|
228
|
+
return { deleted };
|
|
229
|
+
}
|
|
106
230
|
/** Deletes every object and unfinished upload, then the bucket. Only with "drop data". */
|
|
107
231
|
async function drop(app) {
|
|
108
232
|
const { creds, client, base } = await s3(app);
|
|
@@ -133,12 +257,102 @@ function createStorage(options) {
|
|
|
133
257
|
await admin(`DeleteBucket?id=${String(bucket.id)}`, {});
|
|
134
258
|
}
|
|
135
259
|
}
|
|
260
|
+
const objectUrl = (base, key) => `${base}/${key.split("/").map(encodeURIComponent).join("/")}`;
|
|
261
|
+
/**
|
|
262
|
+
* One page of the bucket, one folder level at a time like a file browser: the files directly
|
|
263
|
+
* in `prefix` and the folders below it. Undefined when the app has no bucket.
|
|
264
|
+
*/
|
|
265
|
+
async function list(app, { prefix = "", token, limit = 200 } = {}) {
|
|
266
|
+
const { creds, client, base } = await s3(app);
|
|
267
|
+
const query = new URLSearchParams({
|
|
268
|
+
"list-type": "2",
|
|
269
|
+
delimiter: "/",
|
|
270
|
+
prefix,
|
|
271
|
+
"max-keys": String(Math.min(Math.max(limit, 1), 1e3))
|
|
272
|
+
});
|
|
273
|
+
if (token) query.set("continuation-token", token);
|
|
274
|
+
const res = await client.fetch(`${base}?${query.toString()}`);
|
|
275
|
+
if (res.status === 404) return void 0;
|
|
276
|
+
if (!res.ok) throw new StorageError(`listing ${creds.bucket}: ${await res.text()}`);
|
|
277
|
+
const page = parseObjectList(await res.text());
|
|
278
|
+
return {
|
|
279
|
+
prefix,
|
|
280
|
+
folders: page.prefixes,
|
|
281
|
+
files: page.objects.map((object) => ({
|
|
282
|
+
key: object.key,
|
|
283
|
+
size: object.size,
|
|
284
|
+
lastModified: new Date(object.lastModified).toISOString()
|
|
285
|
+
})),
|
|
286
|
+
next: page.next
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
/** Size, type and metadata of one object; undefined when it doesn't exist. */
|
|
290
|
+
async function describe(app, key) {
|
|
291
|
+
const { creds, client, base } = await s3(app);
|
|
292
|
+
const res = await client.fetch(objectUrl(base, key), { method: "HEAD" });
|
|
293
|
+
if (res.status === 404) return void 0;
|
|
294
|
+
if (!res.ok) throw new StorageError(`reading ${key} in ${creds.bucket}: ${res.status}`);
|
|
295
|
+
const metadata = {};
|
|
296
|
+
for (const [name, value] of res.headers) if (name.startsWith("x-amz-meta-")) metadata[name.slice(11)] = value;
|
|
297
|
+
const modified = res.headers.get("last-modified");
|
|
298
|
+
return {
|
|
299
|
+
key,
|
|
300
|
+
size: Number(res.headers.get("content-length") ?? 0),
|
|
301
|
+
lastModified: modified ? new Date(modified).toISOString() : "",
|
|
302
|
+
contentType: res.headers.get("content-type"),
|
|
303
|
+
metadata
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* A presigned download link on `publicUrl`, the S3 API as browsers reach it, so files go from
|
|
308
|
+
* Garage straight to the browser. Always an attachment, never shown inline: the file is the
|
|
309
|
+
* app's users' content and may well be HTML.
|
|
310
|
+
*/
|
|
311
|
+
async function downloadUrl(app, key, { publicUrl, expiresIn = 300 }) {
|
|
312
|
+
const { creds, client } = await s3(app);
|
|
313
|
+
const url = new URL(objectUrl(`${publicUrl.replace(/\/$/, "")}/${creds.bucket}`, key));
|
|
314
|
+
const name = key.split("/").at(-1) || "download";
|
|
315
|
+
const ascii = name.replace(/[^\x20-\x7e]|["\\]/g, "_");
|
|
316
|
+
url.searchParams.set("response-content-disposition", `attachment; filename="${ascii}"; filename*=UTF-8''${encodeURIComponent(name)}`);
|
|
317
|
+
url.searchParams.set("X-Amz-Expires", String(expiresIn));
|
|
318
|
+
return (await client.sign(url.toString(), {
|
|
319
|
+
method: "GET",
|
|
320
|
+
aws: { signQuery: true }
|
|
321
|
+
})).url;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Deletes one object, and its ablage companion (see companionKeyOf) so ablage never lists a
|
|
325
|
+
* file whose bytes are gone. Undefined when the object doesn't exist.
|
|
326
|
+
*/
|
|
327
|
+
async function remove(app, key) {
|
|
328
|
+
const { creds, client, base } = await s3(app);
|
|
329
|
+
const present = async (k) => {
|
|
330
|
+
const res = await client.fetch(objectUrl(base, k), { method: "HEAD" });
|
|
331
|
+
if (res.status === 404) return false;
|
|
332
|
+
if (!res.ok) throw new StorageError(`checking ${k} in ${creds.bucket}: ${res.status}`);
|
|
333
|
+
return true;
|
|
334
|
+
};
|
|
335
|
+
if (!await present(key)) return void 0;
|
|
336
|
+
const companion = companionKeyOf(key);
|
|
337
|
+
const keys = companion !== void 0 && await present(companion) ? [key, companion] : [key];
|
|
338
|
+
for (const k of keys) {
|
|
339
|
+
const res = await client.fetch(objectUrl(base, k), { method: "DELETE" });
|
|
340
|
+
if (!res.ok && res.status !== 404) throw new StorageError(`deleting ${k} in ${creds.bucket}: ${await res.text()}`);
|
|
341
|
+
}
|
|
342
|
+
return { deleted: keys };
|
|
343
|
+
}
|
|
136
344
|
return {
|
|
137
345
|
ensureLayout,
|
|
138
346
|
provision,
|
|
347
|
+
setQuota,
|
|
139
348
|
usage,
|
|
349
|
+
list,
|
|
350
|
+
describe,
|
|
351
|
+
downloadUrl,
|
|
352
|
+
remove,
|
|
353
|
+
sweepAbandonedUploads,
|
|
140
354
|
drop
|
|
141
355
|
};
|
|
142
356
|
}
|
|
143
357
|
//#endregion
|
|
144
|
-
export { StorageError, createStorage };
|
|
358
|
+
export { ABANDONED_UPLOAD_GRACE_MS, MAX_KEY_BYTES, StorageError, companionKeyOf, createStorage, metaKeyOf, parseObjectList };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wervt/nuxt",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Nuxt module for apps hosted on wervt: database, live data, MCP and runtime setup.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"drizzle",
|
|
@@ -37,6 +37,10 @@
|
|
|
37
37
|
"types": "./dist/runtime/email/index.d.ts",
|
|
38
38
|
"default": "./dist/runtime/email/index.js"
|
|
39
39
|
},
|
|
40
|
+
"./anthropic": {
|
|
41
|
+
"types": "./dist/runtime/server/anthropic.d.ts",
|
|
42
|
+
"default": "./dist/runtime/server/anthropic.js"
|
|
43
|
+
},
|
|
40
44
|
"./provision": {
|
|
41
45
|
"types": "./dist/provision.d.ts",
|
|
42
46
|
"default": "./dist/provision.js"
|
|
@@ -46,7 +50,7 @@
|
|
|
46
50
|
"@electric-sql/client": "^1.5.28",
|
|
47
51
|
"@valibot/to-json-schema": "^1.8.0",
|
|
48
52
|
"aws4fetch": "^1.0.20",
|
|
49
|
-
"evlog": "^2.
|
|
53
|
+
"evlog": "^2.33.1",
|
|
50
54
|
"h3-mcp": "0.2.0",
|
|
51
55
|
"html-to-text": "^9.0.5",
|
|
52
56
|
"jose": "^6.2.12",
|
|
@@ -54,19 +58,24 @@
|
|
|
54
58
|
"valibot": "^1.5.0"
|
|
55
59
|
},
|
|
56
60
|
"devDependencies": {
|
|
61
|
+
"@anthropic-ai/sdk": "^0.97.1",
|
|
57
62
|
"@types/html-to-text": "^9.0.4",
|
|
58
|
-
"drizzle-orm": "1.0.0-rc.
|
|
59
|
-
"h3": "2.0.
|
|
63
|
+
"drizzle-orm": "1.0.0-rc.5",
|
|
64
|
+
"h3": "2.0.5",
|
|
60
65
|
"nitro": "3.0.260903-beta",
|
|
61
66
|
"nuxt": "npm:nuxt-nightly@5x",
|
|
62
|
-
"vue": "^3.5.
|
|
67
|
+
"vue": "^3.5.44"
|
|
63
68
|
},
|
|
64
69
|
"peerDependencies": {
|
|
65
|
-
"
|
|
70
|
+
"@anthropic-ai/sdk": ">=0.97.1",
|
|
71
|
+
"drizzle-orm": ">=1.0.0-rc.5 <2",
|
|
66
72
|
"h3": "^2.0.1",
|
|
67
73
|
"nuxt": ">=4.2"
|
|
68
74
|
},
|
|
69
75
|
"peerDependenciesMeta": {
|
|
76
|
+
"@anthropic-ai/sdk": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
70
79
|
"h3": {
|
|
71
80
|
"optional": true
|
|
72
81
|
}
|