@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.
- package/dist/brand.d.ts +16 -3
- package/dist/brand.js +22 -6
- package/dist/module.d.ts +3 -14
- package/dist/module.js +24 -59
- package/dist/provision.d.ts +1 -77
- package/dist/provision.js +1 -238
- package/dist/runtime/app/plugins/analytics.client.js +2 -2
- package/dist/runtime/app/plugins/feedback.client.js +11 -22
- package/dist/runtime/app/plugins/user.client.js +2 -7
- package/dist/runtime/app/plugins/webmcp.client.js +4 -41
- package/dist/runtime/app/snapshot.d.ts +2 -15
- package/dist/runtime/app/snapshot.js +1 -63
- package/dist/runtime/app/useShape.js +1 -1
- package/dist/runtime/app/useWervtFeedback.d.ts +1 -13
- package/dist/runtime/app/useWervtFeedback.js +3 -11
- package/dist/runtime/app/useWervtTrack.js +4 -8
- package/dist/runtime/app/useWervtUser.d.ts +3 -2
- package/dist/runtime/app/useWervtUser.js +3 -2
- package/dist/runtime/email/components.d.ts +18 -0
- package/dist/runtime/email/components.js +15 -4
- package/dist/runtime/email/invite.d.ts +13 -0
- package/dist/runtime/email/invite.js +30 -14
- package/dist/runtime/i18n.d.ts +3 -0
- package/dist/runtime/i18n.js +3 -0
- package/dist/runtime/server/access.d.ts +3 -22
- package/dist/runtime/server/access.js +7 -24
- package/dist/runtime/server/anthropic.d.ts +2 -7
- package/dist/runtime/server/anthropic.js +6 -37
- package/dist/runtime/server/db.d.ts +2 -17
- package/dist/runtime/server/db.js +1 -35
- package/dist/runtime/server/errors.d.ts +6 -0
- package/dist/runtime/server/errors.js +21 -0
- package/dist/runtime/server/identity.d.ts +3 -9
- package/dist/runtime/server/identity.js +4 -23
- package/dist/runtime/server/index.d.ts +1 -1
- package/dist/runtime/server/index.js +1 -1
- package/dist/runtime/server/mail.js +11 -29
- package/dist/runtime/server/mcp-claims.d.ts +2 -3
- package/dist/runtime/server/mcp-claims.js +1 -17
- package/dist/runtime/server/seed.d.ts +2 -16
- package/dist/runtime/server/seed.js +1 -26
- package/dist/runtime/server/shape.d.ts +2 -2
- package/dist/runtime/server/shape.js +5 -45
- package/dist/runtime/server/task-handlers.d.ts +1 -5
- package/dist/runtime/server/task-handlers.js +3 -9
- package/dist/runtime/server/task-run-nitro2.d.ts +1 -5
- package/dist/runtime/server/task-run-nitro3.d.ts +1 -5
- package/dist/runtime/server/tasks.d.ts +2 -32
- package/dist/runtime/server/tasks.js +1 -9
- package/dist/runtime/server/user-route.d.ts +1 -3
- package/dist/runtime/server/user.js +8 -11
- package/dist/runtime/shared/agent-token.d.ts +2 -7
- package/dist/runtime/shared/agent-token.js +1 -16
- package/dist/runtime/shared/i18n.d.ts +28 -0
- package/dist/runtime/shared/i18n.js +54 -0
- package/dist/runtime/shared/messages.d.ts +15 -0
- package/dist/runtime/shared/messages.js +33 -0
- package/dist/runtime/shared/shape.d.ts +2 -17
- package/dist/runtime/shared/shape.js +1 -15
- package/dist/runtime/shared/user.d.ts +3 -19
- package/dist/runtime/shared/user.js +1 -9
- package/package.json +9 -1
- package/dist/dev.d.ts +0 -31
- package/dist/dev.js +0 -158
- package/dist/jsdoc-imports.js +0 -25
- package/dist/seed.js +0 -51
- package/dist/storage.d.ts +0 -72
- package/dist/storage.js +0 -362
|
@@ -1,49 +1,12 @@
|
|
|
1
1
|
import { defineNuxtPlugin, onNuxtReady, useRuntimeConfig } from "#app";
|
|
2
|
+
import { hasWebMcp, registerTools } from "@wervt/client";
|
|
2
3
|
// src/runtime/app/plugins/webmcp.client.ts
|
|
3
|
-
function pageModelContext() {
|
|
4
|
-
const context = document.modelContext ?? navigator.modelContext;
|
|
5
|
-
return typeof context?.registerTool === "function" ? context : void 0;
|
|
6
|
-
}
|
|
7
4
|
var webmcp_client_default = defineNuxtPlugin({
|
|
8
5
|
name: "wervt:webmcp",
|
|
9
6
|
setup() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
async function execute(name, input) {
|
|
14
|
-
const res = await fetch(`${base}/_wervt/tools/${encodeURIComponent(name)}`, {
|
|
15
|
-
method: "POST",
|
|
16
|
-
headers: { "content-type": "application/json" },
|
|
17
|
-
body: JSON.stringify(input ?? {})
|
|
18
|
-
});
|
|
19
|
-
const body = await res.json().catch(() => void 0);
|
|
20
|
-
if (res.ok) return body?.result ?? null;
|
|
21
|
-
const issues = body?.issues ?? body?.data;
|
|
22
|
-
const message = (typeof body?.error === "string" ? body.error : body?.message) ?? `${res.status} ${res.statusText}`;
|
|
23
|
-
throw new Error(issues ? `${message} ${JSON.stringify(issues)}` : message);
|
|
24
|
-
}
|
|
25
|
-
onNuxtReady(async () => {
|
|
26
|
-
let tools;
|
|
27
|
-
try {
|
|
28
|
-
const res = await fetch(`${base}/_wervt/tools`);
|
|
29
|
-
if (!res.ok) return;
|
|
30
|
-
tools = await res.json();
|
|
31
|
-
} catch {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
for (const tool of tools) try {
|
|
35
|
-
const result = context.registerTool({
|
|
36
|
-
name: tool.name,
|
|
37
|
-
description: tool.description,
|
|
38
|
-
inputSchema: tool.inputSchema,
|
|
39
|
-
...tool.readOnly ? { annotations: { readOnlyHint: true } } : {},
|
|
40
|
-
execute: (input) => execute(tool.name, input)
|
|
41
|
-
});
|
|
42
|
-
if (result instanceof Promise) result.catch((e) => console.warn(`wervt: could not register tool ${tool.name}`, e));
|
|
43
|
-
} catch (e) {
|
|
44
|
-
console.warn(`wervt: could not register tool ${tool.name}`, e);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
7
|
+
if (!hasWebMcp()) return;
|
|
8
|
+
const base = useRuntimeConfig().app.baseURL;
|
|
9
|
+
onNuxtReady(() => registerTools({ base }));
|
|
47
10
|
}
|
|
48
11
|
});
|
|
49
12
|
export { webmcp_client_default as default };
|
|
@@ -1,15 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
rows: [string, T][];
|
|
4
|
-
offset: Offset;
|
|
5
|
-
handle?: string;
|
|
6
|
-
/**
|
|
7
|
-
* The route answered 401: the shape needs a signed-in user and there is none, e.g. an anonymous
|
|
8
|
-
* visitor of a public app, or the deploy's page check. No rows, and nothing to stream.
|
|
9
|
-
*/
|
|
10
|
-
unauthorized?: true;
|
|
11
|
-
}
|
|
12
|
-
/** The rows of the shape at `url` (absolute) as of now, without subscribing. */
|
|
13
|
-
export declare function loadSnapshot<T extends Row<unknown>>(url: string, fetchClient?: typeof fetch): Promise<ShapeSnapshot<T>>;
|
|
14
|
-
/** Applies Electric change messages to `rows`. Returns whether anything changed. */
|
|
15
|
-
export declare function applyMessages<T extends Row<unknown>>(rows: Map<string, T>, messages: Message<T>[]): boolean;
|
|
1
|
+
import { ShapeSnapshot, applyMessages, loadSnapshot } from "@wervt/client/shape";
|
|
2
|
+
export { type ShapeSnapshot, applyMessages, loadSnapshot };
|
|
@@ -1,63 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { ShapeStream, isChangeMessage, isControlMessage } from "@electric-sql/client";
|
|
3
|
-
// src/runtime/app/snapshot.ts
|
|
4
|
-
/** The rows of the shape at `url` (absolute) as of now, without subscribing. */
|
|
5
|
-
async function loadSnapshot(url, fetchClient) {
|
|
6
|
-
const rows = /* @__PURE__ */ new Map();
|
|
7
|
-
let fail = () => {};
|
|
8
|
-
const stream = new ShapeStream({
|
|
9
|
-
url,
|
|
10
|
-
subscribe: false,
|
|
11
|
-
fetchClient,
|
|
12
|
-
parser: shapeParser,
|
|
13
|
-
onError: (e) => fail(e)
|
|
14
|
-
});
|
|
15
|
-
try {
|
|
16
|
-
await new Promise((resolve, reject) => {
|
|
17
|
-
fail = reject;
|
|
18
|
-
stream.subscribe((messages) => {
|
|
19
|
-
applyMessages(rows, messages);
|
|
20
|
-
if (stream.isUpToDate) resolve();
|
|
21
|
-
}, (e) => reject(e));
|
|
22
|
-
});
|
|
23
|
-
} catch (e) {
|
|
24
|
-
if (e?.status === 401) return {
|
|
25
|
-
rows: [],
|
|
26
|
-
offset: "-1",
|
|
27
|
-
unauthorized: true
|
|
28
|
-
};
|
|
29
|
-
throw e;
|
|
30
|
-
} finally {
|
|
31
|
-
stream.unsubscribeAll();
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
rows: [...rows],
|
|
35
|
-
offset: stream.lastOffset,
|
|
36
|
-
handle: stream.shapeHandle
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
/** Applies Electric change messages to `rows`. Returns whether anything changed. */
|
|
40
|
-
function applyMessages(rows, messages) {
|
|
41
|
-
let changed = false;
|
|
42
|
-
for (const message of messages) if (isChangeMessage(message)) {
|
|
43
|
-
const { key, value } = message;
|
|
44
|
-
switch (message.headers.operation) {
|
|
45
|
-
case "insert":
|
|
46
|
-
rows.set(key, value);
|
|
47
|
-
break;
|
|
48
|
-
case "update":
|
|
49
|
-
rows.set(key, {
|
|
50
|
-
...rows.get(key),
|
|
51
|
-
...value
|
|
52
|
-
});
|
|
53
|
-
break;
|
|
54
|
-
case "delete": rows.delete(key);
|
|
55
|
-
}
|
|
56
|
-
changed = true;
|
|
57
|
-
} else if (isControlMessage(message) && message.headers.control === "must-refetch") {
|
|
58
|
-
rows.clear();
|
|
59
|
-
changed = true;
|
|
60
|
-
}
|
|
61
|
-
return changed;
|
|
62
|
-
}
|
|
63
|
-
export { applyMessages, loadSnapshot };
|
|
1
|
+
export { applyMessages, loadSnapshot } from "@wervt/client/shape";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { shapeParser } from "../shared/shape.js";
|
|
2
1
|
import { applyMessages, loadSnapshot } from "./snapshot.js";
|
|
2
|
+
import { shapeParser } from "../shared/shape.js";
|
|
3
3
|
import { onNuxtReady, useAsyncData, useRequestEvent, useRequestFetch } from "#app";
|
|
4
4
|
import { getCurrentScope, onScopeDispose, ref, shallowRef } from "vue";
|
|
5
5
|
import { ShapeStream } from "@electric-sql/client";
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
interface KontorWidget {
|
|
2
|
-
open(): void;
|
|
3
|
-
close(): void;
|
|
4
|
-
setContext(values: Record<string, unknown>): void;
|
|
5
|
-
}
|
|
6
|
-
declare global {
|
|
7
|
-
interface Window {
|
|
8
|
-
kontor?: KontorWidget;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
export declare const pendingFeedbackContext: Record<string, unknown>;
|
|
12
1
|
/**
|
|
13
2
|
* Controls the feedback widget (`wervt: { feedback: { key } }`): open it from your own button,
|
|
14
3
|
* or add context to every report, e.g. what the user was looking at.
|
|
@@ -19,5 +8,4 @@ export declare function useWervtFeedback(): {
|
|
|
19
8
|
open: () => void | undefined;
|
|
20
9
|
close: () => void | undefined;
|
|
21
10
|
setContext(values: Record<string, unknown>): void;
|
|
22
|
-
};
|
|
23
|
-
export {};
|
|
11
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { feedback } from "@wervt/client";
|
|
1
2
|
// src/runtime/app/useWervtFeedback.ts
|
|
2
|
-
const pendingFeedbackContext = {};
|
|
3
3
|
/**
|
|
4
4
|
* Controls the feedback widget (`wervt: { feedback: { key } }`): open it from your own button,
|
|
5
5
|
* or add context to every report, e.g. what the user was looking at.
|
|
@@ -7,14 +7,6 @@ const pendingFeedbackContext = {};
|
|
|
7
7
|
* @example useWervtFeedback().setContext({ room: room.id })
|
|
8
8
|
*/
|
|
9
9
|
function useWervtFeedback() {
|
|
10
|
-
|
|
11
|
-
return {
|
|
12
|
-
open: () => widget()?.open(),
|
|
13
|
-
close: () => widget()?.close(),
|
|
14
|
-
setContext(values) {
|
|
15
|
-
Object.assign(pendingFeedbackContext, values);
|
|
16
|
-
widget()?.setContext(values);
|
|
17
|
-
}
|
|
18
|
-
};
|
|
10
|
+
return feedback;
|
|
19
11
|
}
|
|
20
|
-
export {
|
|
12
|
+
export { useWervtFeedback };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useRuntimeConfig } from "#app";
|
|
2
|
+
import { track } from "@wervt/client";
|
|
2
3
|
// src/runtime/app/useWervtTrack.ts
|
|
3
4
|
/**
|
|
4
5
|
* Custom events for wervt's analytics, e.g. `track('signup')` or `track('click', url)`. They
|
|
@@ -9,15 +10,10 @@ import { useRuntimeConfig } from "#app";
|
|
|
9
10
|
function useWervtTrack() {
|
|
10
11
|
const config = useRuntimeConfig();
|
|
11
12
|
const enabled = config.public.wervt?.analytics;
|
|
12
|
-
const base = config.app.baseURL
|
|
13
|
+
const base = config.app.baseURL;
|
|
13
14
|
return (name, label) => {
|
|
14
|
-
if (!enabled || import.meta.server
|
|
15
|
-
|
|
16
|
-
path: location.pathname,
|
|
17
|
-
name,
|
|
18
|
-
label
|
|
19
|
-
});
|
|
20
|
-
navigator.sendBeacon?.(`${base}/_wervt/view`, new Blob([body], { type: "application/json" }));
|
|
15
|
+
if (!enabled || import.meta.server) return;
|
|
16
|
+
track(name, label, { base });
|
|
21
17
|
};
|
|
22
18
|
}
|
|
23
19
|
export { useWervtTrack };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WervtUser } from "../shared/user.js";
|
|
2
|
+
import { loginUrl, logoutUrl } from "@wervt/client";
|
|
2
3
|
/**
|
|
3
4
|
* The signed-in wervt user, or `null`. Read during SSR and kept in the payload; apps without
|
|
4
5
|
* SSR load it from `/_wervt/user` before they render. Public apps get one when the visitor
|
|
@@ -6,6 +7,6 @@ import { WervtUser } from "../shared/user.js";
|
|
|
6
7
|
*/
|
|
7
8
|
export declare function useWervtUser(): import("vue").Ref<WervtUser | null, WervtUser | null>;
|
|
8
9
|
/** Sign in with wervt, then come back to `redirect` (a path in this app). */
|
|
9
|
-
export declare const wervtLoginUrl:
|
|
10
|
+
export declare const wervtLoginUrl: typeof loginUrl;
|
|
10
11
|
/** Sign out of wervt (all apps), then come back to `redirect`. */
|
|
11
|
-
export declare const wervtLogoutUrl:
|
|
12
|
+
export declare const wervtLogoutUrl: typeof logoutUrl;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DEV_LOGIN_COOKIE, devUser, parseWervtUser } from "../shared/user.js";
|
|
2
2
|
import { useCookie, useRequestHeaders, useState } from "#app";
|
|
3
|
+
import { loginUrl, logoutUrl } from "@wervt/client";
|
|
3
4
|
// src/runtime/app/useWervtUser.ts
|
|
4
5
|
/**
|
|
5
6
|
* The signed-in wervt user, or `null`. Read during SSR and kept in the payload; apps without
|
|
@@ -11,7 +12,7 @@ function useWervtUser() {
|
|
|
11
12
|
return useState("wervt-user", () => import.meta.server ? parseWervtUser(useRequestHeaders(["x-wervt-user"])["x-wervt-user"]) ?? devUser(String(devLogin?.value) === "1") ?? null : null);
|
|
12
13
|
}
|
|
13
14
|
/** Sign in with wervt, then come back to `redirect` (a path in this app). */
|
|
14
|
-
const wervtLoginUrl =
|
|
15
|
+
const wervtLoginUrl = loginUrl;
|
|
15
16
|
/** Sign out of wervt (all apps), then come back to `redirect`. */
|
|
16
|
-
const wervtLogoutUrl =
|
|
17
|
+
const wervtLogoutUrl = logoutUrl;
|
|
17
18
|
export { useWervtUser, wervtLoginUrl, wervtLogoutUrl };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Locale } from "../shared/i18n.js";
|
|
1
2
|
import { InjectionKey, PropType } from "vue";
|
|
2
3
|
/** The template's subject, handed to renderEmail() while rendering. */
|
|
3
4
|
export declare const SUBJECT_KEY: InjectionKey<(subject: string) => void>;
|
|
@@ -84,6 +85,14 @@ export declare const WervtEmail: import("vue").DefineComponent<import("vue").Ext
|
|
|
84
85
|
type: PropType<EmailBrand | null>;
|
|
85
86
|
default: null;
|
|
86
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* The language of the frame's own texts ("Sent by …") and the document. English unless set;
|
|
90
|
+
* the template's own texts are up to the template.
|
|
91
|
+
*/
|
|
92
|
+
lang: {
|
|
93
|
+
type: PropType<Locale>;
|
|
94
|
+
default: string;
|
|
95
|
+
};
|
|
87
96
|
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
88
97
|
[key: string]: any;
|
|
89
98
|
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -117,12 +126,21 @@ export declare const WervtEmail: import("vue").DefineComponent<import("vue").Ext
|
|
|
117
126
|
type: PropType<EmailBrand | null>;
|
|
118
127
|
default: null;
|
|
119
128
|
};
|
|
129
|
+
/**
|
|
130
|
+
* The language of the frame's own texts ("Sent by …") and the document. English unless set;
|
|
131
|
+
* the template's own texts are up to the template.
|
|
132
|
+
*/
|
|
133
|
+
lang: {
|
|
134
|
+
type: PropType<Locale>;
|
|
135
|
+
default: string;
|
|
136
|
+
};
|
|
120
137
|
}>> & Readonly<{}>, {
|
|
121
138
|
app: string;
|
|
122
139
|
preview: string;
|
|
123
140
|
footer: string;
|
|
124
141
|
reason: string;
|
|
125
142
|
brand: EmailBrand | null;
|
|
143
|
+
lang: "de" | "en";
|
|
126
144
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
127
145
|
export declare const EmailHeading: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
128
146
|
/** A short label above the heading, in the landing page's mono eyebrow style. */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isLocale, translator } from "../shared/i18n.js";
|
|
2
|
+
import { mailMessages } from "../shared/messages.js";
|
|
1
3
|
import { wervtInstance } from "../shared/instance.js";
|
|
2
4
|
import { defineComponent, h, inject } from "vue";
|
|
3
5
|
// src/runtime/email/components.ts
|
|
@@ -102,11 +104,19 @@ const WervtEmail = defineComponent({
|
|
|
102
104
|
brand: {
|
|
103
105
|
type: Object,
|
|
104
106
|
default: null
|
|
107
|
+
},
|
|
108
|
+
/**
|
|
109
|
+
* The language of the frame's own texts ("Sent by …") and the document. English unless set;
|
|
110
|
+
* the template's own texts are up to the template.
|
|
111
|
+
*/
|
|
112
|
+
lang: {
|
|
113
|
+
type: String,
|
|
114
|
+
default: "en"
|
|
105
115
|
}
|
|
106
116
|
},
|
|
107
117
|
setup(props, { slots }) {
|
|
108
118
|
inject(SUBJECT_KEY, void 0)?.(props.subject);
|
|
109
|
-
return () => h("html", { lang: "en" }, [h("head", [
|
|
119
|
+
return () => h("html", { lang: isLocale(props.lang) ? props.lang : "en" }, [h("head", [
|
|
110
120
|
h("meta", { charset: "utf-8" }),
|
|
111
121
|
h("meta", {
|
|
112
122
|
name: "viewport",
|
|
@@ -304,7 +314,8 @@ function accentLine(color) {
|
|
|
304
314
|
}
|
|
305
315
|
function footer(props) {
|
|
306
316
|
const { brand } = props;
|
|
307
|
-
const
|
|
317
|
+
const say = translator(mailMessages, isLocale(props.lang) ? props.lang : "en");
|
|
318
|
+
const sentBy = props.footer || (brand ? say("sentBy", { app: brand.name }) : props.app === "wervt" ? say("sentBy", { app: "wervt" }) : say("sentByVia", { app: props.app }));
|
|
308
319
|
const tile = brand ? mailIcon(brand) : `${t.assets}/mark-tile.png`;
|
|
309
320
|
const small = {
|
|
310
321
|
fontFamily: t.font,
|
|
@@ -367,7 +378,7 @@ function footer(props) {
|
|
|
367
378
|
href: instance.site,
|
|
368
379
|
class: "wv-muted",
|
|
369
380
|
style: link
|
|
370
|
-
}, "
|
|
381
|
+
}, say("securedBy"))] : [h("a", {
|
|
371
382
|
href: instance.site,
|
|
372
383
|
class: "wv-muted",
|
|
373
384
|
style: link
|
|
@@ -375,7 +386,7 @@ function footer(props) {
|
|
|
375
386
|
href: `${instance.docs}/getting-started/introduction`,
|
|
376
387
|
class: "wv-muted",
|
|
377
388
|
style: link
|
|
378
|
-
}, "
|
|
389
|
+
}, say("docs"))] : []])
|
|
379
390
|
])])]);
|
|
380
391
|
}
|
|
381
392
|
function separator() {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Locale } from "../shared/i18n.js";
|
|
2
|
+
import { PropType } from "vue";
|
|
1
3
|
/**
|
|
2
4
|
* An invitation to an app: who invited, where to go, and that signing in with this address is
|
|
3
5
|
* all it takes. Send it with `sendMail({ to, template: InviteEmail, props: { by, app, url } })`.
|
|
@@ -33,6 +35,11 @@ export declare const InviteEmail: import("vue").DefineComponent<import("vue").Ex
|
|
|
33
35
|
type: StringConstructor;
|
|
34
36
|
default: string;
|
|
35
37
|
};
|
|
38
|
+
/** The language of the invitation's own texts; `message`, `action` and `note` stay as given. */
|
|
39
|
+
lang: {
|
|
40
|
+
type: PropType<Locale>;
|
|
41
|
+
default: string;
|
|
42
|
+
};
|
|
36
43
|
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
37
44
|
[key: string]: any;
|
|
38
45
|
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -66,8 +73,14 @@ export declare const InviteEmail: import("vue").DefineComponent<import("vue").Ex
|
|
|
66
73
|
type: StringConstructor;
|
|
67
74
|
default: string;
|
|
68
75
|
};
|
|
76
|
+
/** The language of the invitation's own texts; `message`, `action` and `note` stay as given. */
|
|
77
|
+
lang: {
|
|
78
|
+
type: PropType<Locale>;
|
|
79
|
+
default: string;
|
|
80
|
+
};
|
|
69
81
|
}>> & Readonly<{}>, {
|
|
70
82
|
message: string;
|
|
71
83
|
action: string;
|
|
72
84
|
note: string;
|
|
85
|
+
lang: "de" | "en";
|
|
73
86
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isLocale, translator } from "../shared/i18n.js";
|
|
2
|
+
import { mailMessages } from "../shared/messages.js";
|
|
1
3
|
import { EmailButton, EmailHeading, EmailMuted, EmailText, WervtEmail } from "./components.js";
|
|
2
4
|
import { defineComponent, h } from "vue";
|
|
3
5
|
// src/runtime/email/invite.ts
|
|
@@ -37,23 +39,37 @@ const InviteEmail = defineComponent({
|
|
|
37
39
|
note: {
|
|
38
40
|
type: String,
|
|
39
41
|
default: ""
|
|
42
|
+
},
|
|
43
|
+
/** The language of the invitation's own texts; `message`, `action` and `note` stay as given. */
|
|
44
|
+
lang: {
|
|
45
|
+
type: String,
|
|
46
|
+
default: "en"
|
|
40
47
|
}
|
|
41
48
|
},
|
|
42
49
|
setup(props) {
|
|
43
|
-
return () =>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
h(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
return () => {
|
|
51
|
+
const lang = isLocale(props.lang) ? props.lang : "en";
|
|
52
|
+
const t = translator(mailMessages, lang);
|
|
53
|
+
const who = {
|
|
54
|
+
by: props.by,
|
|
55
|
+
app: props.app
|
|
56
|
+
};
|
|
57
|
+
return h(WervtEmail, {
|
|
58
|
+
subject: t("inviteSubject", who),
|
|
59
|
+
app: props.app,
|
|
60
|
+
preview: props.message || t("invitePreview", who),
|
|
61
|
+
reason: t("inviteReason", who),
|
|
62
|
+
lang
|
|
63
|
+
}, () => [
|
|
64
|
+
h(EmailHeading, { eyebrow: t("inviteEyebrow") }, () => t("inviteHeading", who)),
|
|
65
|
+
h(EmailText, () => [t("inviteText", who), props.message].filter(Boolean).join(" ")),
|
|
66
|
+
h(EmailButton, {
|
|
67
|
+
href: props.url,
|
|
68
|
+
color: "neutral"
|
|
69
|
+
}, () => props.action || t("inviteAction", who)),
|
|
70
|
+
h(EmailMuted, () => props.note || t("inviteNote"))
|
|
71
|
+
]);
|
|
72
|
+
};
|
|
57
73
|
}
|
|
58
74
|
});
|
|
59
75
|
export { InviteEmail };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Catalog, DEFAULT_LOCALE, LOCALES, Locale, Messages, Translate, catalogProblems, defineMessages, isLocale, negotiateLocale, translator } from "./shared/i18n.js";
|
|
2
|
+
import { mailMessages } from "./shared/messages.js";
|
|
3
|
+
export { Catalog, DEFAULT_LOCALE, LOCALES, Locale, Messages, Translate, catalogProblems, defineMessages, isLocale, mailMessages, negotiateLocale, translator };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { DEFAULT_LOCALE, LOCALES, catalogProblems, defineMessages, isLocale, negotiateLocale, translator } from "./shared/i18n.js";
|
|
2
|
+
import { mailMessages } from "./shared/messages.js";
|
|
3
|
+
export { DEFAULT_LOCALE, LOCALES, catalogProblems, defineMessages, isLocale, mailMessages, negotiateLocale, translator };
|
|
@@ -1,25 +1,5 @@
|
|
|
1
|
+
import { WervtAccess, WervtAccess as WervtAccess$1, WervtInvite } from "@wervt/core";
|
|
1
2
|
import { RequestEvent } from "nuxt/server";
|
|
2
|
-
export interface WervtInvite {
|
|
3
|
-
email: string;
|
|
4
|
-
/** Who invited them. */
|
|
5
|
-
by: string;
|
|
6
|
-
/** ISO time. */
|
|
7
|
-
at: string;
|
|
8
|
-
}
|
|
9
|
-
export interface WervtAccess {
|
|
10
|
-
/** Lets `email` into the app. `invited` is false when they could already get in. */
|
|
11
|
-
invite(email: string): Promise<{
|
|
12
|
-
email: string;
|
|
13
|
-
invited: boolean;
|
|
14
|
-
}>;
|
|
15
|
-
/** Takes back an invite (not the owner's allow list). */
|
|
16
|
-
revoke(email: string): Promise<{
|
|
17
|
-
email: string;
|
|
18
|
-
revoked: boolean;
|
|
19
|
-
}>;
|
|
20
|
-
/** Everyone the app invited, with who invited them and when. */
|
|
21
|
-
list(): Promise<WervtInvite[]>;
|
|
22
|
-
}
|
|
23
3
|
/**
|
|
24
4
|
* Invites on an invite-only app (`wervt access <app> --invite`), as the user of this request: the
|
|
25
5
|
* runtime vouches for them, and only someone with access can invite. Everyone with access may
|
|
@@ -30,4 +10,5 @@ export interface WervtAccess {
|
|
|
30
10
|
* 409 when the app isn't invite-only, 429 past the limits (25 invites per person and day, 500 per
|
|
31
11
|
* app).
|
|
32
12
|
*/
|
|
33
|
-
export declare function useWervtAccess(event: RequestEvent): WervtAccess;
|
|
13
|
+
export declare function useWervtAccess(event: RequestEvent): WervtAccess$1;
|
|
14
|
+
export type { WervtAccess, WervtInvite };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { DEV_LOGIN_COOKIE, devUser } from "../shared/user.js";
|
|
2
|
+
import { withH3Errors } from "./errors.js";
|
|
3
|
+
import { appAccess, runtimeUrl } from "@wervt/core";
|
|
2
4
|
import { createError, getCookie } from "nuxt/server";
|
|
3
5
|
// src/runtime/server/access.ts
|
|
4
6
|
const devInvites = [];
|
|
@@ -13,31 +15,12 @@ const devInvites = [];
|
|
|
13
15
|
* app).
|
|
14
16
|
*/
|
|
15
17
|
function useWervtAccess(event) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async function call(method, body) {
|
|
19
|
-
const res = await fetch(new URL("/_wervt/access", runtime), {
|
|
20
|
-
method,
|
|
21
|
-
headers: {
|
|
22
|
-
"content-type": "application/json",
|
|
23
|
-
"x-wervt-app": process.env.WERVT_APP ?? "",
|
|
24
|
-
"x-wervt-token": process.env.WERVT_TOKEN ?? "",
|
|
25
|
-
"x-wervt-user": event.req.headers.get("x-wervt-user") ?? "",
|
|
26
|
-
"x-wervt-user-proof": event.req.headers.get("x-wervt-user-proof") ?? ""
|
|
27
|
-
},
|
|
28
|
-
body: body && JSON.stringify(body)
|
|
29
|
-
});
|
|
30
|
-
const data = await res.json().catch(() => ({}));
|
|
31
|
-
if (!res.ok) throw createError({
|
|
32
|
-
status: res.status,
|
|
33
|
-
message: data.error ?? `access ${res.status}`
|
|
34
|
-
});
|
|
35
|
-
return data;
|
|
36
|
-
}
|
|
18
|
+
if (!runtimeUrl()) return devAccess(event);
|
|
19
|
+
const access = appAccess(event.req);
|
|
37
20
|
return {
|
|
38
|
-
invite: (email) =>
|
|
39
|
-
revoke: (email) =>
|
|
40
|
-
list:
|
|
21
|
+
invite: (email) => withH3Errors(access.invite(email)),
|
|
22
|
+
revoke: (email) => withH3Errors(access.revoke(email)),
|
|
23
|
+
list: () => withH3Errors(access.list())
|
|
41
24
|
};
|
|
42
25
|
}
|
|
43
26
|
function devAccess(event) {
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
+
import { AnthropicOptions } from "@wervt/core/anthropic";
|
|
1
2
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
-
export
|
|
3
|
-
/**
|
|
4
|
-
* The key for `nuxt dev`, where there is no workload identity. Default: `ANTHROPIC_API_KEY`.
|
|
5
|
-
* Never used on wervt.
|
|
6
|
-
*/
|
|
7
|
-
devApiKey?: string;
|
|
8
|
-
}
|
|
3
|
+
export type UseAnthropicOptions = AnthropicOptions;
|
|
9
4
|
/**
|
|
10
5
|
* An Anthropic client that authenticates as this app through its wervt identity: no API key, only
|
|
11
6
|
* IDs from the Anthropic Console in the app's env (`ANTHROPIC_FEDERATION_RULE_ID`,
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
4
|
-
import { oidcFederationProvider } from "@anthropic-ai/sdk/lib/credentials/oidc-federation";
|
|
1
|
+
import { toH3Error } from "./errors.js";
|
|
2
|
+
import { getAnthropic } from "@wervt/core/anthropic";
|
|
5
3
|
// src/runtime/server/anthropic.ts
|
|
6
|
-
const BASE_URL = "https://api.anthropic.com";
|
|
7
|
-
let client;
|
|
8
4
|
/**
|
|
9
5
|
* An Anthropic client that authenticates as this app through its wervt identity: no API key, only
|
|
10
6
|
* IDs from the Anthropic Console in the app's env (`ANTHROPIC_FEDERATION_RULE_ID`,
|
|
@@ -16,37 +12,10 @@ let client;
|
|
|
16
12
|
* (`wervt identity status <app>`). In `nuxt dev` it uses `options.devApiKey` instead.
|
|
17
13
|
*/
|
|
18
14
|
function useAnthropic(options = {}) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const apiKey = options.devApiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
24
|
-
if (!apiKey) throw createError({
|
|
25
|
-
status: 503,
|
|
26
|
-
message: "useAnthropic() in `nuxt dev` needs an API key (ANTHROPIC_API_KEY or devApiKey)."
|
|
27
|
-
});
|
|
28
|
-
return new Anthropic({ apiKey });
|
|
15
|
+
try {
|
|
16
|
+
return getAnthropic(options);
|
|
17
|
+
} catch (e) {
|
|
18
|
+
throw toH3Error(e);
|
|
29
19
|
}
|
|
30
|
-
const federationRuleId = process.env.ANTHROPIC_FEDERATION_RULE_ID;
|
|
31
|
-
const organizationId = process.env.ANTHROPIC_ORGANIZATION_ID;
|
|
32
|
-
if (!federationRuleId || !organizationId) throw createError({
|
|
33
|
-
status: 503,
|
|
34
|
-
message: "useAnthropic() needs ANTHROPIC_FEDERATION_RULE_ID and ANTHROPIC_ORGANIZATION_ID (wervt env <app> --set …)."
|
|
35
|
-
});
|
|
36
|
-
const identity = useWorkloadIdentity();
|
|
37
|
-
return new Anthropic({
|
|
38
|
-
apiKey: null,
|
|
39
|
-
authToken: null,
|
|
40
|
-
baseURL: BASE_URL,
|
|
41
|
-
credentials: oidcFederationProvider({
|
|
42
|
-
identityTokenProvider: () => identity.token(BASE_URL),
|
|
43
|
-
federationRuleId,
|
|
44
|
-
organizationId,
|
|
45
|
-
serviceAccountId: process.env.ANTHROPIC_SERVICE_ACCOUNT_ID || void 0,
|
|
46
|
-
workspaceId: process.env.ANTHROPIC_WORKSPACE_ID || void 0,
|
|
47
|
-
baseURL: BASE_URL,
|
|
48
|
-
fetch: (...args) => fetch(...args)
|
|
49
|
-
})
|
|
50
|
-
});
|
|
51
20
|
}
|
|
52
21
|
export { useAnthropic };
|
|
@@ -1,17 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Drizzle client for the app's database. In production the wervt runtime injects
|
|
5
|
-
* DATABASE_URL for the app's own role, whose search_path is its own schema, so
|
|
6
|
-
* tables are declared without a schema.
|
|
7
|
-
*
|
|
8
|
-
* Pass the app's relations (from `defineRelations`) to use `db.query.*`. All clients
|
|
9
|
-
* share one connection pool.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* const db = useDb({ relations })
|
|
13
|
-
* const room = await db.query.rooms.findFirst({ where: { id }, with: { players: true } })
|
|
14
|
-
*/
|
|
15
|
-
export declare function useDb<TRelations extends AnyRelations = EmptyRelations>(options?: {
|
|
16
|
-
relations?: TRelations;
|
|
17
|
-
}): PostgresJsDatabase<TRelations>;
|
|
1
|
+
import { useDb } from "@wervt/core/db";
|
|
2
|
+
export { useDb };
|
|
@@ -1,35 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import postgres from "postgres";
|
|
3
|
-
// src/runtime/server/db.ts
|
|
4
|
-
let client;
|
|
5
|
-
const clients = /* @__PURE__ */ new Map();
|
|
6
|
-
/**
|
|
7
|
-
* Drizzle client for the app's database. In production the wervt runtime injects
|
|
8
|
-
* DATABASE_URL for the app's own role, whose search_path is its own schema, so
|
|
9
|
-
* tables are declared without a schema.
|
|
10
|
-
*
|
|
11
|
-
* Pass the app's relations (from `defineRelations`) to use `db.query.*`. All clients
|
|
12
|
-
* share one connection pool.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* const db = useDb({ relations })
|
|
16
|
-
* const room = await db.query.rooms.findFirst({ where: { id }, with: { players: true } })
|
|
17
|
-
*/
|
|
18
|
-
function useDb(options) {
|
|
19
|
-
if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL is not set");
|
|
20
|
-
client ??= postgres(process.env.DATABASE_URL, {
|
|
21
|
-
max: 2,
|
|
22
|
-
idle_timeout: 20
|
|
23
|
-
});
|
|
24
|
-
const relations = options?.relations;
|
|
25
|
-
let db = clients.get(relations);
|
|
26
|
-
if (!db) {
|
|
27
|
-
db = drizzle({
|
|
28
|
-
client,
|
|
29
|
-
relations
|
|
30
|
-
});
|
|
31
|
-
clients.set(relations, db);
|
|
32
|
-
}
|
|
33
|
-
return db;
|
|
34
|
-
}
|
|
35
|
-
export { useDb };
|
|
1
|
+
export { useDb } from "@wervt/core/db";
|