@wervt/nuxt 0.3.7 → 0.3.9

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/brand.d.ts CHANGED
@@ -18,4 +18,11 @@ export interface BrandOptions {
18
18
  * why the address bar shows wervt and that the account works in other apps too.
19
19
  */
20
20
  securedByWervt?: boolean;
21
- }
21
+ /**
22
+ * The sign-in options the login offers for this app, in wervt's order (`['twitch']`). All of
23
+ * them by default. Providers the server has no keys for stay hidden either way.
24
+ */
25
+ signIn?: SignInMethod[];
26
+ }
27
+ export declare const SIGN_IN_METHODS: readonly ['google', 'github', 'discord', 'twitch', 'spotify', 'passkey', 'email'];
28
+ export type SignInMethod = (typeof SIGN_IN_METHODS)[number];
package/dist/brand.js CHANGED
@@ -1,5 +1,20 @@
1
1
  import { headIcon, headMeta } from "./preview.js";
2
2
  // src/brand.ts
3
+ const SIGN_IN_METHODS = [
4
+ "google",
5
+ "github",
6
+ "discord",
7
+ "twitch",
8
+ "spotify",
9
+ "passkey",
10
+ "email"
11
+ ];
12
+ /** The known methods of a list, without duplicates; undefined when none is left. */
13
+ function signInMethods(value) {
14
+ if (!Array.isArray(value)) return void 0;
15
+ const methods = SIGN_IN_METHODS.filter((m) => value.includes(m));
16
+ return methods.length ? methods : void 0;
17
+ }
3
18
  const HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
4
19
  /** The login's branding for the app, or undefined while the app keeps wervt's. */
5
20
  function brandManifest(option, head, app, favicon) {
@@ -8,12 +23,14 @@ function brandManifest(option, head, app, favicon) {
8
23
  const pick = (value, fallback) => value?.trim() || fallback;
9
24
  const title = typeof head.title === "string" && head.title.trim() ? head.title.trim() : app;
10
25
  const color = pick(custom.color, headMeta(head, "theme-color"));
26
+ const signIn = signInMethods(custom.signIn);
11
27
  return {
12
28
  name: pick(custom.name, title).slice(0, 60),
13
29
  logo: pick(custom.logo, void 0),
14
30
  icon: pick(custom.icon, headIcon(head) ?? favicon),
15
31
  color: color && HEX_COLOR.test(color) ? color : void 0,
16
- ...custom.securedByWervt === false && { securedByWervt: false }
32
+ ...custom.securedByWervt === false && { securedByWervt: false },
33
+ ...signIn && { signIn }
17
34
  };
18
35
  }
19
- export { HEX_COLOR, brandManifest };
36
+ export { HEX_COLOR, SIGN_IN_METHODS, brandManifest, signInMethods };
package/dist/module.js CHANGED
@@ -7,7 +7,7 @@ import { iconDefaults, iconSources, iconWarning } from "./icons.js";
7
7
  import { stripJsdocImports } from "./jsdoc-imports.js";
8
8
  import { findRouteTools } from "./route-tools.js";
9
9
  import { localFiles, previewManifest } from "./preview.js";
10
- import { brandManifest } from "./brand.js";
10
+ import { SIGN_IN_METHODS, brandManifest } from "./brand.js";
11
11
  import { findShapeRoutes, shapeRoutesTypes, shapesManifest } from "./shapes.js";
12
12
  import { addImports, addPlugin, addServerHandler, addServerPlugin, addServerTemplate, addTypeTemplate, createResolver, defineNuxtModule, getNuxtVersion, hasNuxtModule, installModule, updateTemplates, useLogger } from "nuxt/kit";
13
13
  import { existsSync } from "node:fs";
@@ -398,6 +398,11 @@ var module_default = defineNuxtModule({
398
398
  image: brand.logo
399
399
  } : false)) if (!existsSync(join(publicDir, file))) logger.warn(`The login branding names \`${file}\`, which isn't in public/.`);
400
400
  if (typeof options.brand === "object" && options.brand.color && !brand?.color) logger.warn("`wervt.brand.color` must be a hex color like `#ff5a1f`; it is ignored.");
401
+ if (typeof options.brand === "object" && options.brand.signIn) {
402
+ const unknown = options.brand.signIn.filter((m) => !SIGN_IN_METHODS.includes(m));
403
+ if (unknown.length) logger.warn(`\`wervt.brand.signIn\` ignores ${unknown.map((m) => `\`${m}\``).join(", ")}; it knows ${SIGN_IN_METHODS.join(", ")}.`);
404
+ if (!brand?.signIn) logger.warn("`wervt.brand.signIn` names no sign-in option; the login offers all.");
405
+ }
401
406
  nuxt.hook("nitro:init", (instance) => {
402
407
  const { serverDir } = instance.options.output;
403
408
  instance.hooks.hook("compiled", async () => {
@@ -22,9 +22,14 @@ export declare const emailTheme: {
22
22
  radius: string;
23
23
  font: string;
24
24
  mono: string;
25
- /** Where the logo images live. PNG, because Gmail and Outlook don't show SVG. */
25
+ /**
26
+ * Where the logo images live. PNG, because Gmail and Outlook don't show SVG. Always wervt.app's,
27
+ * even on a self-hosted instance: its docs, which would serve them, may not run there.
28
+ */
26
29
  assets: string;
30
+ /** @deprecated wervt.app's only; `wervtInstance().site` is the instance the app runs on. */
27
31
  site: string;
32
+ /** @deprecated wervt.app's only; `wervtInstance().docs` is the instance's, if it runs any. */
28
33
  docs: string;
29
34
  };
30
35
  /**
@@ -1,3 +1,4 @@
1
+ import { wervtInstance } from "../shared/instance.js";
1
2
  import { defineComponent, h, inject } from "vue";
2
3
  // src/runtime/email/components.ts
3
4
  /** The template's subject, handed to renderEmail() while rendering. */
@@ -23,9 +24,14 @@ const emailTheme = {
23
24
  radius: "8px",
24
25
  font: "Poppins, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
25
26
  mono: "'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
26
- /** Where the logo images live. PNG, because Gmail and Outlook don't show SVG. */
27
+ /**
28
+ * Where the logo images live. PNG, because Gmail and Outlook don't show SVG. Always wervt.app's,
29
+ * even on a self-hosted instance: its docs, which would serve them, may not run there.
30
+ */
27
31
  assets: "https://wervt.app/email",
32
+ /** @deprecated wervt.app's only; `wervtInstance().site` is the instance the app runs on. */
28
33
  site: "https://wervt.app",
34
+ /** @deprecated wervt.app's only; `wervtInstance().docs` is the instance's, if it runs any. */
29
35
  docs: "https://wervt.app/getting-started/introduction"
30
36
  };
31
37
  const t = emailTheme;
@@ -198,7 +204,7 @@ function header(app) {
198
204
  verticalAlign: "middle"
199
205
  }
200
206
  }, h("a", {
201
- href: t.site,
207
+ href: wervtInstance().site,
202
208
  style: {
203
209
  textDecoration: "none",
204
210
  color: "#fafafa"
@@ -309,6 +315,7 @@ function footer(props) {
309
315
  color: t.muted,
310
316
  textDecoration: "none"
311
317
  };
318
+ const instance = wervtInstance();
312
319
  return table({ width: "100%" }, [h("tr", [tile ? h("td", {
313
320
  width: 40,
314
321
  style: {
@@ -357,22 +364,18 @@ function footer(props) {
357
364
  color: t.dimmed
358
365
  }
359
366
  }, brand ? brand.securedByWervt === false ? [] : [h("a", {
360
- href: t.site,
367
+ href: instance.site,
361
368
  class: "wv-muted",
362
369
  style: link
363
- }, "Secured by wervt")] : [
364
- h("a", {
365
- href: t.site,
366
- class: "wv-muted",
367
- style: link
368
- }, "wervt.app"),
369
- separator(),
370
- h("a", {
371
- href: t.docs,
372
- class: "wv-muted",
373
- style: link
374
- }, "Docs")
375
- ])
370
+ }, "Secured by wervt")] : [h("a", {
371
+ href: instance.site,
372
+ class: "wv-muted",
373
+ style: link
374
+ }, instance.domain), ...instance.docs ? [separator(), h("a", {
375
+ href: `${instance.docs}/getting-started/introduction`,
376
+ class: "wv-muted",
377
+ style: link
378
+ }, "Docs")] : []])
376
379
  ])])]);
377
380
  }
378
381
  function separator() {
@@ -1,5 +1,6 @@
1
1
  import { LogAlertEmail } from "./alert.js";
2
2
  import { EmailBrand, EmailButton, EmailCode, EmailDivider, EmailHeading, EmailLink, EmailMuted, EmailText, WervtEmail, emailTheme } from "./components.js";
3
3
  import { InviteEmail } from "./invite.js";
4
+ import { WervtInstance, wervtInstance } from "../shared/instance.js";
4
5
  import { EmailProps, RenderedEmail, renderEmail } from "./render.js";
5
- export { type EmailBrand, EmailButton, EmailCode, EmailDivider, EmailHeading, EmailLink, EmailMuted, type EmailProps, EmailText, InviteEmail, LogAlertEmail, type RenderedEmail, WervtEmail, emailTheme, renderEmail };
6
+ export { type EmailBrand, EmailButton, EmailCode, EmailDivider, EmailHeading, EmailLink, EmailMuted, type EmailProps, EmailText, InviteEmail, LogAlertEmail, type RenderedEmail, WervtEmail, type WervtInstance, emailTheme, renderEmail, wervtInstance };
@@ -1,5 +1,6 @@
1
+ import { wervtInstance } from "../shared/instance.js";
1
2
  import { EmailButton, EmailCode, EmailDivider, EmailHeading, EmailLink, EmailMuted, EmailText, WervtEmail, emailTheme } from "./components.js";
2
3
  import { LogAlertEmail } from "./alert.js";
3
4
  import { InviteEmail } from "./invite.js";
4
5
  import { renderEmail } from "./render.js";
5
- export { EmailButton, EmailCode, EmailDivider, EmailHeading, EmailLink, EmailMuted, EmailText, InviteEmail, LogAlertEmail, WervtEmail, emailTheme, renderEmail };
6
+ export { EmailButton, EmailCode, EmailDivider, EmailHeading, EmailLink, EmailMuted, EmailText, InviteEmail, LogAlertEmail, WervtEmail, emailTheme, renderEmail, wervtInstance };
@@ -1,4 +1,5 @@
1
1
  import { WervtRole, WervtUser } from "../shared/user.js";
2
+ import { WervtInstance, wervtInstance } from "../shared/instance.js";
2
3
  import { EmailProps, RenderedEmail, renderEmail } from "../email/render.js";
3
4
  import { WervtAccess, WervtInvite, useWervtAccess } from "./access.js";
4
5
  import { useDb } from "./db.js";
@@ -13,4 +14,4 @@ import { AccountMergedPayload, Task, TaskEvent, TaskResult, defineTask } from ".
13
14
  import { SafeResult, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, vh } from "./validate.js";
14
15
  import { Tool, ToolRoute, defineTool, defineToolRoute } from "./tools.js";
15
16
  import { requireWervtRole, useWervtUser } from "./user.js";
16
- export { type AccountMergedPayload, type EmailProps, type McpTokenContext, type RenderedEmail, type SafeResult, type SendMailOptions, type ShapeOptions, type ShapeResponse, type ShapeRow, type Task, type TaskEvent, type TaskResult, type Tool, type ToolRoute, type WervtAccess, type WervtInvite, type WervtRole, type WervtUser, type WorkloadIdentity, createEvlogError, defineTask, defineTool, defineToolRoute, log, proxyShape, renderEmail, requireWervtRole, seedTable, sendMail, useDb, useLogger, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, useWervtAccess, useWervtUser, useWorkloadIdentity, vh };
17
+ export { type AccountMergedPayload, type EmailProps, type McpTokenContext, type RenderedEmail, type SafeResult, type SendMailOptions, type ShapeOptions, type ShapeResponse, type ShapeRow, type Task, type TaskEvent, type TaskResult, type Tool, type ToolRoute, type WervtAccess, type WervtInstance, type WervtInvite, type WervtRole, type WervtUser, type WorkloadIdentity, createEvlogError, defineTask, defineTool, defineToolRoute, log, proxyShape, renderEmail, requireWervtRole, seedTable, sendMail, useDb, useLogger, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, useWervtAccess, useWervtUser, useWorkloadIdentity, vh, wervtInstance };
@@ -1,3 +1,4 @@
1
+ import { wervtInstance } from "../shared/instance.js";
1
2
  import { renderEmail } from "../email/render.js";
2
3
  import { useWervtAccess } from "./access.js";
3
4
  import { useWorkloadIdentity } from "./identity.js";
@@ -10,4 +11,4 @@ import { defineTask } from "./tasks.js";
10
11
  import { useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, vh } from "./validate.js";
11
12
  import { defineTool, defineToolRoute } from "./tools.js";
12
13
  import { requireWervtRole, useWervtUser } from "./user.js";
13
- export { createEvlogError, defineTask, defineTool, defineToolRoute, log, proxyShape, renderEmail, requireWervtRole, seedTable, sendMail, useDb, useLogger, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, useWervtAccess, useWervtUser, useWorkloadIdentity, vh };
14
+ export { createEvlogError, defineTask, defineTool, defineToolRoute, log, proxyShape, renderEmail, requireWervtRole, seedTable, sendMail, useDb, useLogger, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, useWervtAccess, useWervtUser, useWorkloadIdentity, vh, wervtInstance };
@@ -11,8 +11,8 @@ type Registry = Record<string, {
11
11
  }>;
12
12
  /** `POST /_wervt/tasks/:name`: runs a task when the control plane asks. */
13
13
  export declare function taskRunHandler(runTask: RunTask): import("nuxt/server").EventHandler<Promise<{
14
- error: string;
15
14
  result?: undefined;
15
+ error: string;
16
16
  } | {
17
17
  error?: undefined;
18
18
  result: {} | null;
@@ -36,7 +36,7 @@ export declare const runTool: import("nuxt/server").EventHandler<Promise<{
36
36
  };
37
37
  result?: undefined;
38
38
  } | {
39
+ error?: undefined;
39
40
  issues?: undefined;
40
41
  result: {} | null;
41
- error?: undefined;
42
42
  }>>;
@@ -0,0 +1,17 @@
1
+ /** The wervt instance an app runs on: wervt.app, or a self-hosted one at its own domain. */
2
+ export interface WervtInstance {
3
+ /** E.g. `wervt.app` or `lightdrop.cloud`. */
4
+ domain: string;
5
+ /** The domain as a link. */
6
+ site: string;
7
+ /** The instance's docs site, or `undefined` when it runs none. */
8
+ docs?: string;
9
+ }
10
+ type Env = Record<string, string | undefined>;
11
+ /**
12
+ * Read at call time from what the runtime gives each isolate (`WERVT_BASE_DOMAIN`,
13
+ * `WERVT_DOCS_URL`, empty without docs), so an app built for wervt.app links to the right place
14
+ * on any other instance. Older runtimes pass neither, and were all wervt.app's.
15
+ */
16
+ export declare function wervtInstance(env?: Env): WervtInstance;
17
+ export {};
@@ -0,0 +1,17 @@
1
+ // src/runtime/shared/instance.ts
2
+ const processEnv = () => typeof process === "undefined" ? {} : process.env;
3
+ /**
4
+ * Read at call time from what the runtime gives each isolate (`WERVT_BASE_DOMAIN`,
5
+ * `WERVT_DOCS_URL`, empty without docs), so an app built for wervt.app links to the right place
6
+ * on any other instance. Older runtimes pass neither, and were all wervt.app's.
7
+ */
8
+ function wervtInstance(env = processEnv()) {
9
+ const domain = env.WERVT_BASE_DOMAIN || "wervt.app";
10
+ const site = `${/(^|\.)localhost(:\d+)?$/.test(domain) ? "http" : "https"}://${domain}`;
11
+ return {
12
+ domain,
13
+ site,
14
+ docs: env.WERVT_DOCS_URL === void 0 ? domain === "wervt.app" ? site : void 0 : env.WERVT_DOCS_URL.replace(/\/+$/, "") || void 0
15
+ };
16
+ }
17
+ export { wervtInstance };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wervt/nuxt",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Nuxt module for apps hosted on wervt: database, live data, MCP and runtime setup.",
5
5
  "keywords": [
6
6
  "drizzle",