@wervt/nuxt 0.3.9 → 0.3.11

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 (68) hide show
  1. package/dist/brand.d.ts +16 -3
  2. package/dist/brand.js +22 -6
  3. package/dist/module.d.ts +3 -14
  4. package/dist/module.js +24 -59
  5. package/dist/provision.d.ts +1 -77
  6. package/dist/provision.js +1 -238
  7. package/dist/runtime/app/plugins/analytics.client.js +2 -2
  8. package/dist/runtime/app/plugins/feedback.client.js +11 -22
  9. package/dist/runtime/app/plugins/user.client.js +2 -7
  10. package/dist/runtime/app/plugins/webmcp.client.js +4 -41
  11. package/dist/runtime/app/snapshot.d.ts +2 -15
  12. package/dist/runtime/app/snapshot.js +1 -63
  13. package/dist/runtime/app/useShape.js +1 -1
  14. package/dist/runtime/app/useWervtFeedback.d.ts +1 -13
  15. package/dist/runtime/app/useWervtFeedback.js +3 -11
  16. package/dist/runtime/app/useWervtTrack.js +4 -8
  17. package/dist/runtime/app/useWervtUser.d.ts +3 -2
  18. package/dist/runtime/app/useWervtUser.js +3 -2
  19. package/dist/runtime/email/components.d.ts +18 -0
  20. package/dist/runtime/email/components.js +15 -4
  21. package/dist/runtime/email/invite.d.ts +13 -0
  22. package/dist/runtime/email/invite.js +30 -14
  23. package/dist/runtime/i18n.d.ts +3 -0
  24. package/dist/runtime/i18n.js +3 -0
  25. package/dist/runtime/server/access.d.ts +3 -22
  26. package/dist/runtime/server/access.js +7 -24
  27. package/dist/runtime/server/anthropic.d.ts +2 -7
  28. package/dist/runtime/server/anthropic.js +6 -37
  29. package/dist/runtime/server/db.d.ts +2 -17
  30. package/dist/runtime/server/db.js +1 -35
  31. package/dist/runtime/server/errors.d.ts +6 -0
  32. package/dist/runtime/server/errors.js +21 -0
  33. package/dist/runtime/server/identity.d.ts +3 -9
  34. package/dist/runtime/server/identity.js +4 -23
  35. package/dist/runtime/server/index.d.ts +1 -1
  36. package/dist/runtime/server/index.js +1 -1
  37. package/dist/runtime/server/mail.js +11 -29
  38. package/dist/runtime/server/mcp-claims.d.ts +2 -3
  39. package/dist/runtime/server/mcp-claims.js +1 -17
  40. package/dist/runtime/server/seed.d.ts +2 -16
  41. package/dist/runtime/server/seed.js +1 -26
  42. package/dist/runtime/server/shape.d.ts +2 -2
  43. package/dist/runtime/server/shape.js +5 -45
  44. package/dist/runtime/server/task-handlers.d.ts +1 -5
  45. package/dist/runtime/server/task-handlers.js +3 -9
  46. package/dist/runtime/server/task-run-nitro2.d.ts +1 -5
  47. package/dist/runtime/server/task-run-nitro3.d.ts +1 -5
  48. package/dist/runtime/server/tasks.d.ts +2 -32
  49. package/dist/runtime/server/tasks.js +1 -9
  50. package/dist/runtime/server/user-route.d.ts +1 -3
  51. package/dist/runtime/server/user.js +8 -11
  52. package/dist/runtime/shared/agent-token.d.ts +2 -7
  53. package/dist/runtime/shared/agent-token.js +1 -16
  54. package/dist/runtime/shared/i18n.d.ts +28 -0
  55. package/dist/runtime/shared/i18n.js +54 -0
  56. package/dist/runtime/shared/messages.d.ts +15 -0
  57. package/dist/runtime/shared/messages.js +33 -0
  58. package/dist/runtime/shared/shape.d.ts +2 -17
  59. package/dist/runtime/shared/shape.js +1 -15
  60. package/dist/runtime/shared/user.d.ts +3 -19
  61. package/dist/runtime/shared/user.js +1 -9
  62. package/package.json +9 -1
  63. package/dist/dev.d.ts +0 -31
  64. package/dist/dev.js +0 -158
  65. package/dist/jsdoc-imports.js +0 -25
  66. package/dist/seed.js +0 -51
  67. package/dist/storage.d.ts +0 -72
  68. package/dist/storage.js +0 -362
@@ -1,15 +1 @@
1
- // src/runtime/shared/shape.ts
2
- /**
3
- * Postgres text of a `timestamp`/`timestamptz` as a Date, like Drizzle's default `mode: 'date'`
4
- * reads it. Drizzle stores `timestamp` without time zone as UTC, so it's read as UTC too.
5
- */
6
- function parseTimestamp(value) {
7
- const iso = value.replace(" ", "T").replace(/([+-]\d{2})$/, "$1:00");
8
- return new Date(/(Z|[+-]\d{2}:\d{2})$/.test(iso) ? iso : `${iso}Z`);
9
- }
10
- /** Electric parsers for the types Drizzle reads differently from Electric's defaults. */
11
- const shapeParser = {
12
- timestamp: parseTimestamp,
13
- timestamptz: parseTimestamp
14
- };
15
- export { parseTimestamp, shapeParser };
1
+ export { parseTimestamp, shapeParser } from "@wervt/core";
@@ -1,22 +1,6 @@
1
- /**
2
- * What the user is to this app: its `owner` or one of its `member`s (`wervt members`), a wervt
3
- * `admin`, someone `invited` through the app (invite-only apps) or `allowed` by the app's list
4
- * (`wervt access --add`). `public` is anyone else signed in to a public app.
5
- */
6
- export type WervtRole = 'owner' | 'member' | 'admin' | 'invited' | 'allowed' | 'public';
7
- export interface WervtUser {
8
- id: string;
9
- email: string;
10
- name?: string;
11
- image?: string;
12
- /** Linked login accounts, provider id to the user's id there, e.g. `{ twitch: '1234' }`. */
13
- accounts?: Record<string, string>;
14
- /** Missing only for users an app's own `/mcp` tokens stand for (`wervt:mcp:token`). */
15
- role?: WervtRole;
16
- }
1
+ import { WervtRole, WervtUser, WervtUser as WervtUser$1, parseWervtUser } from "@wervt/core";
17
2
  /** Cookie set by the dev stand-in for `/_wervt/login` (see `server/dev-auth.ts`). */
18
3
  export declare const DEV_LOGIN_COOKIE = "wervt_dev_login";
19
- /** Parses the `x-wervt-user` header the runtime sets (and strips from client requests). */
20
- export declare function parseWervtUser(header: string | null | undefined): WervtUser | undefined;
21
4
  /** During `nuxt dev`: the configured dev user, after `/_wervt/login`. */
22
- export declare function devUser(loggedIn: boolean): WervtUser | undefined;
5
+ export declare function devUser(loggedIn: boolean): WervtUser$1 | undefined;
6
+ export { type WervtRole, type WervtUser, parseWervtUser };
@@ -1,15 +1,7 @@
1
+ import { parseWervtUser } from "@wervt/core";
1
2
  // src/runtime/shared/user.ts
2
3
  /** Cookie set by the dev stand-in for `/_wervt/login` (see `server/dev-auth.ts`). */
3
4
  const DEV_LOGIN_COOKIE = "wervt_dev_login";
4
- /** Parses the `x-wervt-user` header the runtime sets (and strips from client requests). */
5
- function parseWervtUser(header) {
6
- if (!header) return void 0;
7
- try {
8
- return JSON.parse(decodeURIComponent(header));
9
- } catch {
10
- return;
11
- }
12
- }
13
5
  /** During `nuxt dev`: the configured dev user, after `/_wervt/login`. */
14
6
  function devUser(loggedIn) {
15
7
  const user = process.env.WERVT_DEV_USER;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wervt/nuxt",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
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
+ "./i18n": {
41
+ "types": "./dist/runtime/i18n.d.ts",
42
+ "default": "./dist/runtime/i18n.js"
43
+ },
40
44
  "./anthropic": {
41
45
  "types": "./dist/runtime/server/anthropic.d.ts",
42
46
  "default": "./dist/runtime/server/anthropic.js"
@@ -49,6 +53,10 @@
49
53
  "dependencies": {
50
54
  "@electric-sql/client": "^1.5.28",
51
55
  "@valibot/to-json-schema": "^1.8.0",
56
+ "@wervt/client": "^0.0.2",
57
+ "@wervt/core": "^0.0.2",
58
+ "@wervt/nitro": "^0.0.2",
59
+ "@wervt/platform": "^0.0.2",
52
60
  "aws4fetch": "^1.0.20",
53
61
  "evlog": "^2.34.0",
54
62
  "h3-mcp": "0.2.0",
package/dist/dev.d.ts DELETED
@@ -1,31 +0,0 @@
1
- import { WervtRole } from "./runtime/shared/user.js";
2
- import "nuxt/schema";
3
- export interface DevOptions {
4
- /** Superuser URL of the local wervt Postgres. */
5
- adminUrl?: string;
6
- /** WERVT_DB_SECRET of the local setup. */
7
- dbSecret?: string;
8
- electricUrl?: string;
9
- electricSecret?: string;
10
- /** The local Garage, for apps with ablage: S3 API and admin API. */
11
- s3Url?: string;
12
- garageAdminUrl?: string;
13
- garageAdminToken?: string;
14
- /**
15
- * Runs the app's `db:seed` task (`server/tasks/db/seed.ts`) once its database was just created
16
- * and migrated. Defaults to true; `false` leaves seeding to `nuxt task run db:seed`.
17
- */
18
- seed?: boolean;
19
- /**
20
- * Who `/_wervt/login` signs in as during `nuxt dev` (there's no wervt auth locally).
21
- * Defaults to a dev user with a Twitch account linked. Without `role`, they're the app's owner.
22
- */
23
- user?: {
24
- id: string;
25
- email: string;
26
- name?: string;
27
- image?: string;
28
- accounts?: Record<string, string>;
29
- role?: WervtRole;
30
- };
31
- }
package/dist/dev.js DELETED
@@ -1,158 +0,0 @@
1
- import { createStorage } from "./storage.js";
2
- import { appDatabaseUrl, dbRole, migrateAs, provisionDatabase, storageCredentials } from "./provision.js";
3
- import { SEED_TASK, runDevSeed } from "./seed.js";
4
- import { useLogger } from "nuxt/kit";
5
- import { existsSync, watch } from "node:fs";
6
- import { readFile } from "node:fs/promises";
7
- import { join } from "node:path";
8
- // src/dev.ts
9
- const DEFAULTS = {
10
- adminUrl: "postgres://postgres:postgres@localhost:5432/wervt",
11
- dbSecret: "dev-secret",
12
- electricUrl: "http://localhost:3030",
13
- electricSecret: "dev-electric-secret",
14
- s3Url: "http://localhost:3900",
15
- garageAdminUrl: "http://localhost:3903",
16
- garageAdminToken: "dev-garage-admin"
17
- };
18
- const logger = useLogger("wervt");
19
- /**
20
- * `nuxt dev` against the local compose stack: provisions the app's role and schema,
21
- * runs its migrations (again whenever `drizzle/` changes), seeds a new database and
22
- * points the dev server at the app's database and Electric.
23
- */
24
- async function setupDev(nuxt, app, options, features = {}) {
25
- forgetOwnEnv(nuxt.options.rootDir);
26
- const config = {
27
- adminUrl: process.env.WERVT_PG_ADMIN_URL ?? options.adminUrl ?? DEFAULTS.adminUrl,
28
- dbSecret: process.env.WERVT_DB_SECRET ?? options.dbSecret ?? DEFAULTS.dbSecret,
29
- electricUrl: process.env.ELECTRIC_URL ?? options.electricUrl ?? DEFAULTS.electricUrl,
30
- electricSecret: process.env.ELECTRIC_SECRET ?? options.electricSecret ?? DEFAULTS.electricSecret
31
- };
32
- process.env.WERVT_DEV_USER ??= JSON.stringify(options.user ?? {
33
- id: "dev",
34
- email: "dev@wervt.localhost",
35
- name: "Dev",
36
- accounts: { twitch: "dev" }
37
- });
38
- if (features.storage) await setupStorage(app, config.dbSecret, options);
39
- const migrationsFolder = join(nuxt.options.rootDir, "drizzle");
40
- if (!existsSync(migrationsFolder)) {
41
- const watcher = watch(nuxt.options.rootDir, (_event, file) => {
42
- if (file !== "drizzle" || !existsSync(migrationsFolder)) return;
43
- watcher.close();
44
- logger.info("Migrations added, restarting…");
45
- nuxt.callHook("restart");
46
- });
47
- nuxt.hook("close", () => watcher.close());
48
- return;
49
- }
50
- const provision = {
51
- app,
52
- adminUrl: config.adminUrl,
53
- secret: config.dbSecret,
54
- migrationsFolder
55
- };
56
- const given = process.env.DATABASE_URL && process.env.WERVT_DB_SCHEMA ? {
57
- url: process.env.DATABASE_URL,
58
- schema: process.env.WERVT_DB_SCHEMA
59
- } : void 0;
60
- const database = given?.schema ?? dbRole(app);
61
- let serverUrl;
62
- let seedPending = false;
63
- const seed = async () => {
64
- if (!seedPending || !serverUrl) return;
65
- seedPending = false;
66
- try {
67
- if ((await runDevSeed(serverUrl)).status === "seeded") logger.success(`Seeded \`${database}\` (${SEED_TASK})`);
68
- } catch (e) {
69
- logger.warn(`\`${SEED_TASK}\` failed:`, e instanceof Error ? e.message : e);
70
- }
71
- };
72
- if (options.seed !== false) nuxt.hook("listen", (_server, listener) => {
73
- serverUrl = listener.url;
74
- seed();
75
- });
76
- const migrate = async () => {
77
- try {
78
- const { fresh } = given ? await migrateAs({
79
- ...given,
80
- migrationsFolder
81
- }) : await provisionDatabase(provision);
82
- logger.success(`Database \`${database}\` is up to date`);
83
- if (fresh && options.seed !== false) {
84
- seedPending = true;
85
- seed();
86
- }
87
- } catch (e) {
88
- logger.warn(given ? `Could not migrate \`${database}\`.` : `Could not migrate \`${database}\`. Is the wervt stack running (docker compose up -d)?`, e instanceof Error ? e.message : e);
89
- }
90
- };
91
- await migrate();
92
- const own = {
93
- DATABASE_URL: await appDatabaseUrl(provision),
94
- WERVT_DB_SCHEMA: dbRole(app),
95
- ELECTRIC_URL: config.electricUrl,
96
- ELECTRIC_SECRET: config.electricSecret
97
- };
98
- const set = Object.fromEntries(Object.entries(own).filter(([key]) => process.env[key] === void 0));
99
- Object.assign(process.env, set);
100
- process.env[OWN_ENV] = JSON.stringify(set);
101
- let timer;
102
- const watcher = watch(migrationsFolder, { recursive: true }, (_event, file) => {
103
- if (!file?.endsWith(".sql")) return;
104
- clearTimeout(timer);
105
- timer = setTimeout(() => {
106
- logger.info("Migrations changed, migrating…");
107
- migrate();
108
- }, 300);
109
- });
110
- nuxt.hook("close", () => watcher.close());
111
- }
112
- const OWN_ENV = "WERVT_DEV_OWN_ENV";
113
- function forgetOwnEnv(rootDir) {
114
- const own = process.env[OWN_ENV];
115
- if (!own) return;
116
- for (const [key, value] of Object.entries(JSON.parse(own))) if (process.env[key] === value) delete process.env[key];
117
- delete process.env[OWN_ENV];
118
- const file = join(rootDir, ".env");
119
- if (existsSync(file)) process.loadEnvFile(file);
120
- }
121
- /** The app's bucket in the local Garage, and WERVT_S3_* for ablage, like in production. */
122
- async function setupStorage(app, secret, options) {
123
- const s3Url = process.env.WERVT_S3_URL ?? options.s3Url ?? DEFAULTS.s3Url;
124
- const storage = createStorage({
125
- adminUrl: options.garageAdminUrl ?? DEFAULTS.garageAdminUrl,
126
- adminToken: process.env.WERVT_GARAGE_ADMIN_TOKEN ?? options.garageAdminToken ?? DEFAULTS.garageAdminToken,
127
- s3Url,
128
- secret
129
- });
130
- try {
131
- await storage.ensureLayout();
132
- const { bucket } = await storage.provision(app, "*");
133
- logger.success(`Storage bucket \`${bucket}\` is ready`);
134
- } catch (e) {
135
- return logger.warn("Could not set up storage. Is the wervt stack running (docker compose up -d)?", e instanceof Error ? e.message : e);
136
- }
137
- const creds = await storageCredentials(app, secret);
138
- process.env.WERVT_S3_URL ??= s3Url;
139
- process.env.WERVT_S3_PUBLIC_URL ??= s3Url;
140
- process.env.WERVT_S3_REGION ??= "garage";
141
- process.env.WERVT_S3_BUCKET ??= creds.bucket;
142
- process.env.WERVT_S3_ACCESS_KEY_ID ??= creds.accessKeyId;
143
- process.env.WERVT_S3_SECRET_ACCESS_KEY ??= creds.secretAccessKey;
144
- }
145
- /**
146
- * App name, normalised to `[a-z0-9-]+`: `WERVT_APP` first, which `wervt deploy` sets for its
147
- * build, so one codebase deployed as several apps (`--name`) builds each under its own name.
148
- * Then the module option, then package.json.
149
- */
150
- async function resolveAppName(rootDir, name) {
151
- name = process.env.WERVT_APP || name;
152
- if (!name) {
153
- const pkg = JSON.parse(await readFile(join(rootDir, "package.json"), "utf8").catch(() => "{}"));
154
- name = String(pkg.name ?? "app").replace(/^@[^/]+\//, "");
155
- }
156
- return name.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
157
- }
158
- export { resolveAppName, setupDev };
@@ -1,25 +0,0 @@
1
- // src/jsdoc-imports.ts
2
- /**
3
- * Deno's module graph reads JSDoc type imports (`{@link import('../internal/headers').x}`) as
4
- * real dependencies and refuses to boot when one can't be resolved. Packages ship such paths
5
- * relative to their own source tree (@anthropic-ai/sdk does), so once Nitro bundles them into
6
- * `server/_libs/…` the path points nowhere and the worker fails with "Module not found".
7
- * Dropping the `import(` from JSDoc lines keeps the comment readable and out of the graph. Only
8
- * lines that open a JSDoc block or continue one with `*` are touched, so code never changes.
9
- */
10
- function stripJsdocImports() {
11
- const JSDOC_LINE_RE = /^[ \t]*(?:\/\*\*|\*(?!\/)).*$/gm;
12
- const IMPORT_RE = /\bimport\(\s*(['"])/g;
13
- return {
14
- name: "wervt:strip-jsdoc-imports",
15
- renderChunk(code) {
16
- if (!code.includes("import(")) return null;
17
- const out = code.replace(JSDOC_LINE_RE, (line) => line.replace(IMPORT_RE, "$1"));
18
- return out === code ? null : {
19
- code: out,
20
- map: null
21
- };
22
- }
23
- };
24
- }
25
- export { stripJsdocImports };
package/dist/seed.js DELETED
@@ -1,51 +0,0 @@
1
- // src/seed.ts
2
- /** The conventional seed task: `server/tasks/db/seed.ts`. */
3
- const SEED_TASK = "db:seed";
4
- /**
5
- * `nitro.scheduledTasks` without the seed task, and the crons it was listed under. Seeding fills
6
- * an empty database on request; on a schedule it would run against production data.
7
- */
8
- function unscheduleSeed(schedules) {
9
- const kept = {};
10
- const removed = [];
11
- for (const [cron, entry] of Object.entries(schedules)) {
12
- const tasks = [entry].flat();
13
- const rest = tasks.filter((task) => task !== SEED_TASK);
14
- if (rest.length < tasks.length) removed.push(cron);
15
- if (rest.length > 0) kept[cron] = Array.isArray(entry) ? rest : rest[0];
16
- }
17
- return {
18
- schedules: kept,
19
- removed
20
- };
21
- }
22
- /**
23
- * Runs `db:seed` through the Nitro dev server's task route, once the server answers. The dev
24
- * server is still building when it starts listening, so its task list is polled first; that
25
- * also tells whether the app has a seed task at all.
26
- */
27
- async function runDevSeed(baseUrl, { fetch: request = fetch, timeout = 12e4, interval = 500 } = {}) {
28
- const base = baseUrl.replace(/\/+$/, "");
29
- const deadline = Date.now() + timeout;
30
- let tasks;
31
- while (!tasks) {
32
- const response = await request(`${base}/_nitro/tasks`).catch(() => void 0);
33
- const body = response?.ok ? await response.json().catch(() => void 0) : void 0;
34
- if (body && typeof body === "object" && "tasks" in body) tasks = body.tasks;
35
- else if (Date.now() >= deadline) throw new Error("the dev server did not answer in time");
36
- else await new Promise((resolve) => setTimeout(resolve, interval));
37
- }
38
- if (!("db:seed" in tasks)) return { status: "missing" };
39
- const response = await request(`${base}/_nitro/tasks/${SEED_TASK}`, {
40
- method: "POST",
41
- headers: { "content-type": "application/json" },
42
- body: JSON.stringify({ payload: {} })
43
- });
44
- const body = await response.json().catch(() => ({}));
45
- if (!response.ok) throw new Error(body.message ?? `${response.status} ${response.statusText}`);
46
- return {
47
- status: "seeded",
48
- result: body.result
49
- };
50
- }
51
- export { SEED_TASK, runDevSeed, unscheduleSeed };
package/dist/storage.d.ts DELETED
@@ -1,72 +0,0 @@
1
- export interface StorageOptions {
2
- /** Garage's admin API, e.g. http://garage:3903 */
3
- adminUrl: string;
4
- adminToken: string;
5
- /** Garage's S3 API as the control plane reaches it, e.g. http://garage:3900 */
6
- s3Url: string;
7
- secret: string;
8
- }
9
- export interface StorageUsage {
10
- bucket: string;
11
- objects: number;
12
- bytes: number;
13
- /** Multipart uploads started but never completed or aborted. */
14
- unfinishedUploads: number;
15
- /** The bucket's size limit in bytes, null for none. */
16
- maxBytes: number | null;
17
- }
18
- export interface StorageQuota {
19
- /** Bytes the bucket may hold; null for no limit. Garage refuses uploads past it. */
20
- maxBytes: number | null;
21
- }
22
- export declare class StorageError extends Error {}
23
- export interface StoredObject {
24
- key: string;
25
- size: number;
26
- /** ISO time. */
27
- lastModified: string;
28
- }
29
- export interface ObjectListing {
30
- prefix: string;
31
- /** Prefixes one level below `prefix`, ending in `/`. */
32
- folders: string[];
33
- files: StoredObject[];
34
- /** Pass as `token` for the next page. */
35
- next?: string;
36
- }
37
- export interface ObjectDetails extends StoredObject {
38
- contentType: string | null;
39
- /** `x-amz-meta-*` headers, without the prefix. */
40
- metadata: Record<string, string>;
41
- }
42
- /** S3's limit for object keys, in bytes. */
43
- export declare const MAX_KEY_BYTES = 1024;
44
- export declare function createStorage(options: StorageOptions): {
45
- ensureLayout: () => Promise<void>;
46
- provision: (app: string, appOrigins: string | string[], quota?: StorageQuota) => Promise<{
47
- bucket: string;
48
- }>;
49
- setQuota: (app: string, quota: StorageQuota) => Promise<boolean>;
50
- usage: (app: string) => Promise<StorageUsage | undefined>;
51
- list: (app: string, { prefix, token, limit }?: {
52
- prefix?: string;
53
- token?: string;
54
- limit?: number;
55
- }) => Promise<ObjectListing | undefined>;
56
- describe: (app: string, key: string) => Promise<ObjectDetails | undefined>;
57
- downloadUrl: (app: string, key: string, { publicUrl, expiresIn }: {
58
- publicUrl: string;
59
- expiresIn?: number;
60
- }) => Promise<string>;
61
- remove: (app: string, key: string) => Promise<{
62
- deleted: string[];
63
- } | undefined>;
64
- sweepAbandonedUploads: (app: string, { graceMs, now }?: {
65
- graceMs?: number | undefined;
66
- now?: number | undefined;
67
- }) => Promise<{
68
- deleted: string[];
69
- }>;
70
- hasBucket: (app: string) => Promise<boolean>;
71
- drop: (app: string) => Promise<void>;
72
- };