@wervt/nuxt 0.2.14 → 0.2.16
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/module.js +37 -1
- package/dist/provision.d.ts +12 -0
- package/dist/provision.js +35 -1
- package/dist/runtime/app/useShape.d.ts +19 -11
- package/dist/runtime/app/useShape.js +3 -8
- package/dist/runtime/email/components.d.ts +191 -0
- package/dist/runtime/email/components.js +602 -0
- package/dist/runtime/email/index.d.ts +3 -0
- package/dist/runtime/email/index.js +3 -0
- package/dist/runtime/email/render.d.ts +17 -0
- package/dist/runtime/email/render.js +68 -0
- package/dist/runtime/server/email-preview.d.ts +4 -0
- package/dist/runtime/server/email-preview.js +30 -0
- package/dist/runtime/server/index.d.ts +5 -2
- package/dist/runtime/server/index.js +3 -1
- package/dist/runtime/server/mail.d.ts +23 -0
- package/dist/runtime/server/mail.js +43 -0
- package/dist/runtime/server/shape.d.ts +12 -5
- package/dist/runtime/server/shape.js +3 -1
- package/dist/runtime/shared/shape.d.ts +18 -0
- package/dist/runtime/shared/shape.js +16 -0
- package/dist/shapes.js +67 -0
- package/package.json +7 -1
package/dist/module.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveAppName, setupDev } from "./dev.js";
|
|
2
|
-
import {
|
|
2
|
+
import { findShapeRoutes, shapeRoutesTypes } from "./shapes.js";
|
|
3
|
+
import { addImports, addPlugin, addServerHandler, addServerPlugin, addServerTemplate, addTypeTemplate, createResolver, defineNuxtModule, getNuxtVersion, hasNuxtModule, installModule, updateTemplates, useLogger } from "nuxt/kit";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
4
5
|
import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
5
6
|
import { builtinModules, createRequire } from "node:module";
|
|
@@ -228,6 +229,21 @@ var module_default = defineNuxtModule({
|
|
|
228
229
|
const app = await resolveAppName(nuxt.options.rootDir, options.app);
|
|
229
230
|
await setupDev(nuxt, app, options.dev ?? {}, { storage: useAblage });
|
|
230
231
|
}
|
|
232
|
+
addTypeTemplate({
|
|
233
|
+
filename: "types/wervt-email.d.ts",
|
|
234
|
+
getContents: () => "declare module '*.vue' {\n import type { DefineComponent } from 'vue'\n const component: DefineComponent<Record<string, unknown>>\n export default component\n}\n"
|
|
235
|
+
}, { nitro: true });
|
|
236
|
+
if (nuxt.options.dev) {
|
|
237
|
+
const templates = await findEmailTemplates([join(nuxt.options.srcDir, "emails"), join(nuxt.options.rootDir, "emails")]);
|
|
238
|
+
addServerTemplate({
|
|
239
|
+
filename: "#wervt/emails",
|
|
240
|
+
getContents: () => `export const templates = {\n${templates.map(({ name, path }) => ` ${JSON.stringify(name)}: () => import(${JSON.stringify(path)}),`).join("\n")}\n}\n`
|
|
241
|
+
});
|
|
242
|
+
for (const route of ["/_wervt/emails", "/_wervt/emails/**"]) addServerHandler({
|
|
243
|
+
route,
|
|
244
|
+
handler: resolver.resolve("./runtime/server/email-preview")
|
|
245
|
+
});
|
|
246
|
+
}
|
|
231
247
|
if (nuxt.options.dev) for (const route of ["/_wervt/login", "/_wervt/logout"]) addServerHandler({
|
|
232
248
|
route,
|
|
233
249
|
handler: resolver.resolve("./runtime/server/dev-auth")
|
|
@@ -283,6 +299,15 @@ var module_default = defineNuxtModule({
|
|
|
283
299
|
mode: "client"
|
|
284
300
|
});
|
|
285
301
|
}
|
|
302
|
+
const shapesDir = join(nuxt.options.serverDir, "api/shapes");
|
|
303
|
+
const shapeTypes = addTypeTemplate({
|
|
304
|
+
filename: "types/wervt-shapes.d.ts",
|
|
305
|
+
getContents: async () => shapeRoutesTypes(await findShapeRoutes(shapesDir), join(nuxt.options.buildDir, "types"), resolver.resolve("./runtime/shared/shape"))
|
|
306
|
+
});
|
|
307
|
+
if (nuxt.options.dev) nuxt.hook("builder:watch", async (event, path) => {
|
|
308
|
+
const file = relative(shapesDir, resolve(nuxt.options.srcDir, path));
|
|
309
|
+
if ((event === "add" || event === "unlink") && !file.startsWith("..")) await updateTemplates({ filter: (template) => template.filename === shapeTypes.filename });
|
|
310
|
+
});
|
|
286
311
|
nuxt.options.build.transpile.push(resolver.resolve("./runtime"));
|
|
287
312
|
addImports([
|
|
288
313
|
{
|
|
@@ -324,6 +349,17 @@ const TOOL_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
324
349
|
]);
|
|
325
350
|
const TOOL_NAME_RE = /^[\w.-]{1,128}$/;
|
|
326
351
|
/** The tools in `server/tools/`: `todos/add.ts` is `todos.add`, like Nitro names tasks. */
|
|
352
|
+
async function findEmailTemplates(dirs) {
|
|
353
|
+
const templates = /* @__PURE__ */ new Map();
|
|
354
|
+
for (const dir of new Set(dirs)) {
|
|
355
|
+
if (!existsSync(dir)) continue;
|
|
356
|
+
for (const file of await readdir(dir)) if (extname(file) === ".vue") templates.set(file.slice(0, -4), join(dir, file));
|
|
357
|
+
}
|
|
358
|
+
return [...templates].map(([name, path]) => ({
|
|
359
|
+
name,
|
|
360
|
+
path
|
|
361
|
+
}));
|
|
362
|
+
}
|
|
327
363
|
async function findTools(dir) {
|
|
328
364
|
const files = await readdir(dir, { recursive: true }).catch(() => []);
|
|
329
365
|
const tools = [];
|
package/dist/provision.d.ts
CHANGED
|
@@ -28,6 +28,18 @@ export declare function appDatabaseUrl({ app, adminUrl, secret }: ProvisionOptio
|
|
|
28
28
|
* only connect to the wervt database.
|
|
29
29
|
*/
|
|
30
30
|
export declare function provisionDatabase(options: ProvisionOptions): Promise<void>;
|
|
31
|
+
/** The role PgBouncer signs in with to look up app roles' password hashes (`auth_query`). */
|
|
32
|
+
export declare const POOLER_ROLE = "pgbouncer";
|
|
33
|
+
/**
|
|
34
|
+
* Prepares Postgres for PgBouncer in front of the app isolates: a login role for PgBouncer and
|
|
35
|
+
* `pgbouncer.get_auth()`, which hands out the SCRAM hashes of app roles (`app_*`) only, never
|
|
36
|
+
* those of the superuser or other roles. App passwords are derived, not stored anywhere
|
|
37
|
+
* PgBouncer could read them, so it has to ask Postgres.
|
|
38
|
+
*/
|
|
39
|
+
export declare function setupPooler({ adminUrl, password }: {
|
|
40
|
+
adminUrl: string;
|
|
41
|
+
password: string;
|
|
42
|
+
}): Promise<void>;
|
|
31
43
|
/** Drops the app's schema (all its data) and role. */
|
|
32
44
|
export declare function dropDatabase({ app, adminUrl }: Pick<ProvisionOptions, 'app' | 'adminUrl'>): Promise<void>;
|
|
33
45
|
//#endregion
|
package/dist/provision.js
CHANGED
|
@@ -108,6 +108,40 @@ async function claimSchema(admin, role) {
|
|
|
108
108
|
where n.nspname = ${role} and p.proowner <> ${role}::regrole`;
|
|
109
109
|
for (const { kind, name } of objects) await admin.unsafe(`alter ${kind} ${name} owner to "${role}"`);
|
|
110
110
|
}
|
|
111
|
+
/** The role PgBouncer signs in with to look up app roles' password hashes (`auth_query`). */
|
|
112
|
+
const POOLER_ROLE = "pgbouncer";
|
|
113
|
+
/**
|
|
114
|
+
* Prepares Postgres for PgBouncer in front of the app isolates: a login role for PgBouncer and
|
|
115
|
+
* `pgbouncer.get_auth()`, which hands out the SCRAM hashes of app roles (`app_*`) only, never
|
|
116
|
+
* those of the superuser or other roles. App passwords are derived, not stored anywhere
|
|
117
|
+
* PgBouncer could read them, so it has to ask Postgres.
|
|
118
|
+
*/
|
|
119
|
+
async function setupPooler({ adminUrl, password }) {
|
|
120
|
+
const database = new URL(adminUrl).pathname.slice(1);
|
|
121
|
+
const admin = postgres(adminUrl, {
|
|
122
|
+
max: 1,
|
|
123
|
+
onnotice: () => {}
|
|
124
|
+
});
|
|
125
|
+
try {
|
|
126
|
+
const [row] = await admin`select exists(select 1 from pg_roles where rolname = ${POOLER_ROLE})`;
|
|
127
|
+
await admin.unsafe(`${row?.exists ? "alter" : "create"} role "${POOLER_ROLE}" login password '${password.replaceAll("'", "''")}'`);
|
|
128
|
+
await admin.unsafe(`grant connect on database "${database}" to "${POOLER_ROLE}"`);
|
|
129
|
+
await admin.unsafe(`create schema if not exists "${POOLER_ROLE}"`);
|
|
130
|
+
await admin.unsafe(`revoke all on schema "${POOLER_ROLE}" from public`);
|
|
131
|
+
await admin.unsafe(`grant usage on schema "${POOLER_ROLE}" to "${POOLER_ROLE}"`);
|
|
132
|
+
await admin.unsafe(`
|
|
133
|
+
create or replace function "${POOLER_ROLE}".get_auth(p_usename text)
|
|
134
|
+
returns table(usename name, passwd text)
|
|
135
|
+
language sql security definer set search_path = pg_catalog as $$
|
|
136
|
+
select usename, passwd from pg_shadow
|
|
137
|
+
where usename = p_usename and usename like 'app_%' and not usesuper
|
|
138
|
+
$$`);
|
|
139
|
+
await admin.unsafe(`revoke all on function "${POOLER_ROLE}".get_auth(text) from public`);
|
|
140
|
+
await admin.unsafe(`grant execute on function "${POOLER_ROLE}".get_auth(text) to "${POOLER_ROLE}"`);
|
|
141
|
+
} finally {
|
|
142
|
+
await admin.end();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
111
145
|
/** Drops the app's schema (all its data) and role. */
|
|
112
146
|
async function dropDatabase({ app, adminUrl }) {
|
|
113
147
|
const role = dbRole(app);
|
|
@@ -129,4 +163,4 @@ async function dropDatabase({ app, adminUrl }) {
|
|
|
129
163
|
}
|
|
130
164
|
}
|
|
131
165
|
//#endregion
|
|
132
|
-
export { StorageError, appDatabaseUrl, createStorage, dbPassword, dbRole, dropDatabase, hmac, provisionDatabase, storageCredentials };
|
|
166
|
+
export { POOLER_ROLE, StorageError, appDatabaseUrl, createStorage, dbPassword, dbRole, dropDatabase, hmac, provisionDatabase, setupPooler, storageCredentials };
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
import { Row } from "@electric-sql/client";
|
|
2
|
+
import { Ref, ShallowRef } from "vue";
|
|
2
3
|
//#region src/runtime/app/useShape.d.ts
|
|
4
|
+
declare global {
|
|
5
|
+
/**
|
|
6
|
+
* Shape routes and their rows, generated from `server/api/shapes/` (`.nuxt/types/wervt-shapes.d.ts`).
|
|
7
|
+
*/
|
|
8
|
+
interface WervtShapeRoutes {}
|
|
9
|
+
}
|
|
3
10
|
export interface UseShapeOptions {
|
|
4
11
|
/** Payload key. Defaults to the path. */
|
|
5
12
|
key?: string;
|
|
6
13
|
/** Keep the shape live on the client. Defaults to true. */
|
|
7
14
|
live?: boolean;
|
|
8
15
|
}
|
|
16
|
+
type ShapeResult<T> = Promise<ShapeRefs<T>> & ShapeRefs<T>;
|
|
17
|
+
interface ShapeRefs<T> {
|
|
18
|
+
data: ShallowRef<T[]>;
|
|
19
|
+
error: Ref<unknown>;
|
|
20
|
+
isLive: Ref<boolean>;
|
|
21
|
+
}
|
|
9
22
|
/**
|
|
10
23
|
* Live rows of an Electric shape served by one of the app's shape routes
|
|
11
24
|
* (see `proxyShape`). The snapshot is loaded during SSR and sent in the payload;
|
|
12
25
|
* the client resumes the stream from the snapshot's offset, so rows are not
|
|
13
|
-
* fetched twice.
|
|
26
|
+
* fetched twice. Timestamps arrive as Dates, like Drizzle reads them.
|
|
27
|
+
*
|
|
28
|
+
* The row type comes from the route when it passes a Drizzle table to `proxyShape`.
|
|
14
29
|
*
|
|
15
|
-
* @example const { data: todos } = await useShape
|
|
30
|
+
* @example const { data: todos } = await useShape('/api/shapes/todos')
|
|
16
31
|
*/
|
|
17
|
-
export declare function useShape<
|
|
18
|
-
|
|
19
|
-
error: import("vue").Ref<unknown, unknown>;
|
|
20
|
-
isLive: import("vue").Ref<boolean, boolean>;
|
|
21
|
-
}> & {
|
|
22
|
-
data: import("vue").ShallowRef<T[], T[]>;
|
|
23
|
-
error: import("vue").Ref<unknown, unknown>;
|
|
24
|
-
isLive: import("vue").Ref<boolean, boolean>;
|
|
25
|
-
};
|
|
32
|
+
export declare function useShape<P extends keyof WervtShapeRoutes>(path: P, options?: UseShapeOptions): ShapeResult<WervtShapeRoutes[P]>;
|
|
33
|
+
export declare function useShape<T extends Row<unknown>>(path: string, options?: UseShapeOptions): ShapeResult<T>;
|
|
26
34
|
//#endregion
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
+
import { shapeParser } from "../shared/shape.js";
|
|
1
2
|
import { ShapeStream, isChangeMessage, isControlMessage } from "@electric-sql/client";
|
|
2
3
|
import { getCurrentScope, onScopeDispose, ref, shallowRef } from "vue";
|
|
3
4
|
import { onNuxtReady, useAsyncData, useRequestEvent, useRequestFetch } from "#app";
|
|
4
5
|
//#region src/runtime/app/useShape.ts
|
|
5
|
-
/**
|
|
6
|
-
* Live rows of an Electric shape served by one of the app's shape routes
|
|
7
|
-
* (see `proxyShape`). The snapshot is loaded during SSR and sent in the payload;
|
|
8
|
-
* the client resumes the stream from the snapshot's offset, so rows are not
|
|
9
|
-
* fetched twice.
|
|
10
|
-
*
|
|
11
|
-
* @example const { data: todos } = await useShape<Todo>('/api/shapes/todos')
|
|
12
|
-
*/
|
|
13
6
|
function useShape(path, options = {}) {
|
|
14
7
|
const fetchClient = import.meta.server ? inProcessFetch() : void 0;
|
|
15
8
|
const asyncData = useAsyncData(options.key ?? `wervt-shape:${path}`, () => loadSnapshot(path, fetchClient));
|
|
@@ -40,6 +33,7 @@ function useShape(path, options = {}) {
|
|
|
40
33
|
url: absolute(path),
|
|
41
34
|
offset: snapshot?.offset,
|
|
42
35
|
handle: snapshot?.handle,
|
|
36
|
+
parser: shapeParser,
|
|
43
37
|
signal: controller.signal,
|
|
44
38
|
onError: (e) => {
|
|
45
39
|
error.value = e;
|
|
@@ -64,6 +58,7 @@ async function loadSnapshot(path, fetchClient) {
|
|
|
64
58
|
url: absolute(path),
|
|
65
59
|
subscribe: false,
|
|
66
60
|
fetchClient,
|
|
61
|
+
parser: shapeParser,
|
|
67
62
|
onError: (e) => fail(e)
|
|
68
63
|
});
|
|
69
64
|
await new Promise((resolve, reject) => {
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { InjectionKey, PropType } from "vue";
|
|
2
|
+
//#region src/runtime/email/components.d.ts
|
|
3
|
+
/** The template's subject, handed to renderEmail() while rendering. */
|
|
4
|
+
export declare const SUBJECT_KEY: InjectionKey<(subject: string) => void>;
|
|
5
|
+
export declare const emailTheme: {
|
|
6
|
+
page: string;
|
|
7
|
+
card: string;
|
|
8
|
+
border: string;
|
|
9
|
+
rule: string;
|
|
10
|
+
text: string;
|
|
11
|
+
highlighted: string;
|
|
12
|
+
muted: string;
|
|
13
|
+
dimmed: string;
|
|
14
|
+
accent: string;
|
|
15
|
+
accentSoft: string;
|
|
16
|
+
accentBorder: string;
|
|
17
|
+
band: string;
|
|
18
|
+
bandText: string;
|
|
19
|
+
bandDimmed: string;
|
|
20
|
+
button: string;
|
|
21
|
+
buttonText: string;
|
|
22
|
+
codeBackground: string;
|
|
23
|
+
radius: string;
|
|
24
|
+
font: string;
|
|
25
|
+
mono: string;
|
|
26
|
+
/** Where the logo images live. PNG, because Gmail and Outlook don't show SVG. */
|
|
27
|
+
assets: string;
|
|
28
|
+
site: string;
|
|
29
|
+
docs: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The whole email: document, preheader, header with the logo, body and footer. Put it at the
|
|
33
|
+
* root of every template.
|
|
34
|
+
*
|
|
35
|
+
* ```vue
|
|
36
|
+
* <WervtEmail subject="Your code" app="kontor"> … </WervtEmail>
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const WervtEmail: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
40
|
+
/** The email's subject line. */
|
|
41
|
+
subject: {
|
|
42
|
+
type: StringConstructor;
|
|
43
|
+
required: true;
|
|
44
|
+
};
|
|
45
|
+
/** The app that sends the mail, shown in the header and the footer. */
|
|
46
|
+
app: {
|
|
47
|
+
type: StringConstructor;
|
|
48
|
+
default: string;
|
|
49
|
+
};
|
|
50
|
+
/** The preview line inboxes show after the subject. */
|
|
51
|
+
preview: {
|
|
52
|
+
type: StringConstructor;
|
|
53
|
+
default: string;
|
|
54
|
+
};
|
|
55
|
+
/** Replaces the footer's "Sent by <app> via wervt" line. */
|
|
56
|
+
footer: {
|
|
57
|
+
type: StringConstructor;
|
|
58
|
+
default: string;
|
|
59
|
+
};
|
|
60
|
+
/** Why the recipient got this mail, shown small in the footer. */
|
|
61
|
+
reason: {
|
|
62
|
+
type: StringConstructor;
|
|
63
|
+
default: string;
|
|
64
|
+
};
|
|
65
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
68
|
+
/** The email's subject line. */
|
|
69
|
+
subject: {
|
|
70
|
+
type: StringConstructor;
|
|
71
|
+
required: true;
|
|
72
|
+
};
|
|
73
|
+
/** The app that sends the mail, shown in the header and the footer. */
|
|
74
|
+
app: {
|
|
75
|
+
type: StringConstructor;
|
|
76
|
+
default: string;
|
|
77
|
+
};
|
|
78
|
+
/** The preview line inboxes show after the subject. */
|
|
79
|
+
preview: {
|
|
80
|
+
type: StringConstructor;
|
|
81
|
+
default: string;
|
|
82
|
+
};
|
|
83
|
+
/** Replaces the footer's "Sent by <app> via wervt" line. */
|
|
84
|
+
footer: {
|
|
85
|
+
type: StringConstructor;
|
|
86
|
+
default: string;
|
|
87
|
+
};
|
|
88
|
+
/** Why the recipient got this mail, shown small in the footer. */
|
|
89
|
+
reason: {
|
|
90
|
+
type: StringConstructor;
|
|
91
|
+
default: string;
|
|
92
|
+
};
|
|
93
|
+
}>> & Readonly<{}>, {
|
|
94
|
+
app: string;
|
|
95
|
+
preview: string;
|
|
96
|
+
footer: string;
|
|
97
|
+
reason: string;
|
|
98
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
99
|
+
export declare const EmailHeading: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
100
|
+
/** A short label above the heading, in the landing page's mono eyebrow style. */
|
|
101
|
+
eyebrow: {
|
|
102
|
+
type: StringConstructor;
|
|
103
|
+
default: string;
|
|
104
|
+
};
|
|
105
|
+
}>, () => (import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
106
|
+
[key: string]: any;
|
|
107
|
+
}> | null)[], {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
108
|
+
/** A short label above the heading, in the landing page's mono eyebrow style. */
|
|
109
|
+
eyebrow: {
|
|
110
|
+
type: StringConstructor;
|
|
111
|
+
default: string;
|
|
112
|
+
};
|
|
113
|
+
}>> & Readonly<{}>, {
|
|
114
|
+
eyebrow: string;
|
|
115
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
116
|
+
export declare const EmailText: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
117
|
+
[key: string]: any;
|
|
118
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
119
|
+
/** Secondary text: hints, "ignore this if …". */
|
|
120
|
+
export declare const EmailMuted: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
121
|
+
[key: string]: any;
|
|
122
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
123
|
+
export declare const EmailLink: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
124
|
+
href: {
|
|
125
|
+
type: StringConstructor;
|
|
126
|
+
required: true;
|
|
127
|
+
};
|
|
128
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
129
|
+
[key: string]: any;
|
|
130
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
131
|
+
href: {
|
|
132
|
+
type: StringConstructor;
|
|
133
|
+
required: true;
|
|
134
|
+
};
|
|
135
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
136
|
+
/** A call to action. Bulletproof: a table cell carries the background, so Outlook shows it too. */
|
|
137
|
+
export declare const EmailButton: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
138
|
+
href: {
|
|
139
|
+
type: StringConstructor;
|
|
140
|
+
required: true;
|
|
141
|
+
};
|
|
142
|
+
/** `primary` is the landing page's blue; `neutral` the dashboard's black. */
|
|
143
|
+
color: {
|
|
144
|
+
type: PropType<'primary' | 'neutral'>;
|
|
145
|
+
default: string;
|
|
146
|
+
};
|
|
147
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
148
|
+
[key: string]: any;
|
|
149
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
150
|
+
href: {
|
|
151
|
+
type: StringConstructor;
|
|
152
|
+
required: true;
|
|
153
|
+
};
|
|
154
|
+
/** `primary` is the landing page's blue; `neutral` the dashboard's black. */
|
|
155
|
+
color: {
|
|
156
|
+
type: PropType<'primary' | 'neutral'>;
|
|
157
|
+
default: string;
|
|
158
|
+
};
|
|
159
|
+
}>> & Readonly<{}>, {
|
|
160
|
+
color: "neutral" | "primary";
|
|
161
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
162
|
+
/** A one-time code, large and spaced so it reads (and copies) easily. */
|
|
163
|
+
export declare const EmailCode: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
164
|
+
code: {
|
|
165
|
+
type: StringConstructor;
|
|
166
|
+
required: true;
|
|
167
|
+
};
|
|
168
|
+
/** A small line under the code, e.g. when it expires. */
|
|
169
|
+
caption: {
|
|
170
|
+
type: StringConstructor;
|
|
171
|
+
default: string;
|
|
172
|
+
};
|
|
173
|
+
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
174
|
+
[key: string]: any;
|
|
175
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
176
|
+
code: {
|
|
177
|
+
type: StringConstructor;
|
|
178
|
+
required: true;
|
|
179
|
+
};
|
|
180
|
+
/** A small line under the code, e.g. when it expires. */
|
|
181
|
+
caption: {
|
|
182
|
+
type: StringConstructor;
|
|
183
|
+
default: string;
|
|
184
|
+
};
|
|
185
|
+
}>> & Readonly<{}>, {
|
|
186
|
+
caption: string;
|
|
187
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
188
|
+
export declare const EmailDivider: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
189
|
+
[key: string]: any;
|
|
190
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
191
|
+
//#endregion
|