@elvix.is/sdk 0.0.0 → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,34 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 edvone
4
+ Aachen, Germany · edvone.dev
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+
24
+ ────────────────────────────────────────────────────────────────────────
25
+
26
+ TRADEMARK NOTICE
27
+
28
+ The MIT License above covers source code only. "elvix", the elvix logomark,
29
+ and the elvix brand chord (deep purple #5d4dff and #8e7dff) are trademarks
30
+ of edvone. Forks may not use the elvix name or logomark to identify
31
+ themselves or their products. Reasonable nominative use ("works with elvix",
32
+ "elvix-compatible", "integrates with elvix") is permitted.
33
+
34
+ Trademark questions: edvard@edvone.dev
package/README.md CHANGED
@@ -1,5 +1,191 @@
1
- # @elvix/sdk
1
+ <p align="center">
2
+ <img src="https://elvix.is/brand/elvix-icon-512.png" width="96" height="96" alt="elvix" />
3
+ </p>
2
4
 
3
- Placeholder. The real elvix SDK lands here when the public release is ready.
5
+ <h1 align="center">@elvix.is/sdk</h1>
4
6
 
5
- In the meantime: https://elvix.is/docs
7
+ <p align="center">
8
+ <strong>Identity, kept in Europe.</strong><br/>
9
+ Passwordless authentication for React + Next.js. Hosted in Aachen, German legal frame.
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="https://www.npmjs.com/package/@elvix.is/sdk"><img src="https://img.shields.io/npm/v/@elvix.is/sdk.svg?color=5d4dff" alt="npm" /></a>
14
+ <a href="https://www.npmjs.com/package/@elvix.is/sdk"><img src="https://img.shields.io/npm/dm/@elvix.is/sdk.svg?color=8e7dff" alt="downloads" /></a>
15
+ <a href="https://github.com/021is/elvix-sdk/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/021is/elvix-sdk/ci.yml?branch=main&label=CI" alt="CI" /></a>
16
+ <a href="https://github.com/021is/elvix-sdk/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-black.svg" alt="MIT" /></a>
17
+ <a href="https://elvix.is/docs"><img src="https://img.shields.io/badge/docs-elvix.is-5d4dff.svg" alt="docs" /></a>
18
+ <a href="https://bundlephobia.com/package/@elvix.is/sdk"><img src="https://img.shields.io/bundlephobia/minzip/@elvix.is/sdk?label=min%2Bgzip&color=black" alt="bundle size" /></a>
19
+ </p>
20
+
21
+ ---
22
+
23
+ ## Why elvix
24
+
25
+ Auth is the highest-leverage place to get an integration right or wrong. Roll your own and you ship an insecure copy of OAuth that future-you debugs at 2am. Use a US provider and your German users live under American legal frame. elvix is opinionated so the first answer is the safe answer, and EU-resident so the legal frame matches your customers.
26
+
27
+ - Passwordless from day one. Email OTP, passkeys, Google.
28
+ - Drop-in React components. One provider, one form, zero boilerplate.
29
+ - Server-side verify in three lines.
30
+ - Console-configured. Brand colors, allowed methods, redirects all live in elvix Console. The SDK reads them at runtime. No prop drilling.
31
+ - Agent-friendly. Ships an MCP server so Claude, Cursor, Codex, and Gemini can integrate elvix without human shepherding.
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ bun add @elvix.is/sdk
37
+ # or
38
+ npm install @elvix.is/sdk
39
+ ```
40
+
41
+ ## Quickstart
42
+
43
+ ```tsx
44
+ // app/layout.tsx
45
+ import { ElvixProvider } from "@elvix.is/sdk/react";
46
+
47
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
48
+ return (
49
+ <html>
50
+ <body>
51
+ <ElvixProvider clientId={process.env.NEXT_PUBLIC_ELVIX_CLIENT_ID!}>
52
+ {children}
53
+ </ElvixProvider>
54
+ </body>
55
+ </html>
56
+ );
57
+ }
58
+ ```
59
+
60
+ ```tsx
61
+ // app/sign-in/page.tsx
62
+ "use client";
63
+
64
+ import { ElvixSignIn } from "@elvix.is/sdk/react";
65
+ import { useRouter } from "next/navigation";
66
+
67
+ export default function SignInPage() {
68
+ const router = useRouter();
69
+ return (
70
+ <ElvixSignIn
71
+ onResult={(r) => {
72
+ if (r.ok) router.push(r.redirect ?? "/dashboard");
73
+ else console.warn(r.error, r.message);
74
+ }}
75
+ />
76
+ );
77
+ }
78
+ ```
79
+
80
+ ```ts
81
+ // app/api/protected/route.ts
82
+ export async function GET(request: Request) {
83
+ const token = request.headers.get("authorization")?.replace(/^Bearer /, "");
84
+ if (!token) return new Response("Unauthorized", { status: 401 });
85
+
86
+ const res = await fetch("https://elvix.is/api/v1/verify", {
87
+ method: "POST",
88
+ headers: {
89
+ "Content-Type": "application/json",
90
+ Authorization: `Bearer ${process.env.ELVIX_API_KEY!}`,
91
+ },
92
+ body: JSON.stringify({ token }),
93
+ });
94
+ const { ok, user, roles } = await res.json();
95
+ if (!ok) return new Response("Unauthorized", { status: 401 });
96
+ return Response.json({ hello: user.id, roles });
97
+ }
98
+ ```
99
+
100
+ That is the entire integration.
101
+
102
+ ## AI coding agents
103
+
104
+ elvix ships first-class agent support. Three surfaces:
105
+
106
+ 1. **Discovery via [llmstxt.org](https://llmstxt.org)**
107
+
108
+ ```
109
+ https://elvix.is/llms.txt index
110
+ https://elvix.is/llms-full.txt flat dump of every doc page
111
+ https://elvix.is/docs/install.md per-page Markdown twin
112
+ https://elvix.is/agent-prompt.md ready-to-paste system prompt
113
+ ```
114
+
115
+ 2. **OpenAPI for typed REST access**
116
+
117
+ ```
118
+ https://elvix.is/openapi.yaml full spec
119
+ https://elvix.is/openapi.roles.json per-endpoint role + admin scope
120
+ ```
121
+
122
+ 3. **MCP server bundled with the SDK**
123
+
124
+ ```json
125
+ {
126
+ "mcpServers": {
127
+ "elvix": {
128
+ "command": "bunx",
129
+ "args": ["@elvix.is/sdk", "elvix-mcp"],
130
+ "env": { "ELVIX_API_KEY": "eak_..." }
131
+ }
132
+ }
133
+ }
134
+ ```
135
+
136
+ Read-only by default. `--admin` opts in to mutation tools. Never logs the bearer token.
137
+
138
+ Full agent guide: <https://elvix.is/docs/agents>
139
+
140
+ ## Components
141
+
142
+ Every `<Elvix*>` component the SDK ships. Drop-in React, brand chord from `<ElvixProvider>`, no prop drilling.
143
+
144
+ - Primitives: `ElvixCard`, `ElvixProvider`
145
+ - Sign-in: `ElvixSignIn`, `ElvixSignInButton`, `ElvixRecoverGate`
146
+ - Identity: `ElvixUsername`, `ElvixIdentityForm`, `ElvixAvatar`, `ElvixBanner`, `ElvixRegion`, `ElvixLanguages`
147
+ - Account: `ElvixAddressBook`, `ElvixLegalEntities`, `ElvixSessions`, `ElvixExport`, `ElvixDeactivate`, `ElvixLeave`
148
+
149
+ Full catalog with previews: <https://elvix.is/docs/components>
150
+
151
+ ## Server helpers
152
+
153
+ ```ts
154
+ import { verifyElvixToken } from "@elvix.is/sdk/server";
155
+
156
+ const result = await verifyElvixToken(token, { apiKey: process.env.ELVIX_API_KEY! });
157
+ if (result.ok) {
158
+ // result.user, result.roles, result.scopes, result.memberships
159
+ }
160
+ ```
161
+
162
+ ## Brand
163
+
164
+ Deep purple chord: `#5d4dff` (light) and `#8e7dff` (dark). Override per-app from the Console. Set explicit `brand` on `<ElvixProvider>` to win over the Console default.
165
+
166
+ ## Security
167
+
168
+ - All requests over TLS 1.3.
169
+ - Session cookies `Secure; HttpOnly; SameSite=Lax`.
170
+ - Per-app session TTL + sliding-window renewal, owner-configurable.
171
+ - API keys carry per-key rate limits (60/min, 10000/day default).
172
+ - CSP, CORS, CSRF double-submit, allowedOrigins enforcement all live on `elvix.is`.
173
+ - Disclosure: <security@elvix.is>.
174
+
175
+ ## License
176
+
177
+ MIT. See [LICENSE](./LICENSE).
178
+
179
+ ## Security
180
+
181
+ Found something? Read [SECURITY.md](./SECURITY.md). Reports go to **security@elvix.is**. Critical issues get a 4-hour response.
182
+
183
+ ## Contributing
184
+
185
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). PRs welcome — we run CI on every push and require it green before merge.
186
+
187
+ ## Maintained by
188
+
189
+ **[edvone](https://edvone.dev)** · Aachen, Germany · [hi@edvone.dev](mailto:hi@edvone.dev)
190
+
191
+ elvix is an edvone product.
@@ -0,0 +1,77 @@
1
+ // src/mcp/index.ts
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import {
5
+ CallToolRequestSchema,
6
+ ListToolsRequestSchema
7
+ } from "@modelcontextprotocol/sdk/types.js";
8
+ var DEFAULT_BASE_URL = "https://elvix.is";
9
+ var SAFE_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
10
+ function toolName(method, path) {
11
+ return `${method.toLowerCase()}_${path.replace(/^\/api\//, "").replace(/[\/{}]+/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "")}`;
12
+ }
13
+ async function createElvixMcpServer(opts) {
14
+ const baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
15
+ const readonly = opts.readonly ?? true;
16
+ const manifestRes = await fetch(`${baseUrl}/openapi.roles.json`);
17
+ const manifest = await manifestRes.json();
18
+ const tools = manifest.endpoints.filter((e) => e.role === "api").filter((e) => readonly ? SAFE_METHODS.has(e.method.toUpperCase()) : true).map((e) => ({
19
+ name: toolName(e.method, e.path),
20
+ description: `${e.summary ?? `${e.method} ${e.path}`}${e.adminScope ? " (requires admin scope)" : ""}`,
21
+ inputSchema: {
22
+ type: "object",
23
+ properties: {
24
+ path: { type: "string", description: "Final URL path (substitute {params})." },
25
+ body: { type: "object", description: "JSON request body, when applicable." },
26
+ query: { type: "object", description: "Query parameters." }
27
+ },
28
+ required: ["path"]
29
+ },
30
+ _meta: { method: e.method, path: e.path, adminScope: e.adminScope ?? false }
31
+ }));
32
+ const server = new Server(
33
+ { name: "elvix", version: "0.1.0" },
34
+ { capabilities: { tools: {} } }
35
+ );
36
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
37
+ tools: tools.map(({ name, description, inputSchema }) => ({ name, description, inputSchema }))
38
+ }));
39
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
40
+ const tool = tools.find((t) => t.name === req.params.name);
41
+ if (!tool) {
42
+ return { content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }], isError: true };
43
+ }
44
+ const args = req.params.arguments ?? {};
45
+ const url = new URL(args.path ?? tool._meta.path, baseUrl);
46
+ if (args.query) {
47
+ for (const [k, v] of Object.entries(args.query)) url.searchParams.set(k, v);
48
+ }
49
+ const init = {
50
+ method: tool._meta.method,
51
+ headers: {
52
+ authorization: `Bearer ${opts.apiKey}`,
53
+ "content-type": "application/json"
54
+ }
55
+ };
56
+ if (args.body && !SAFE_METHODS.has(tool._meta.method.toUpperCase())) {
57
+ init.body = JSON.stringify(args.body);
58
+ }
59
+ const res = await fetch(url, init);
60
+ const text = await res.text();
61
+ return {
62
+ content: [{ type: "text", text }],
63
+ isError: !res.ok
64
+ };
65
+ });
66
+ return {
67
+ server,
68
+ connectStdio: async () => {
69
+ const transport = new StdioServerTransport();
70
+ await server.connect(transport);
71
+ }
72
+ };
73
+ }
74
+
75
+ export {
76
+ createElvixMcpServer
77
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Wire-level types shared between the React, server, and MCP layers.
3
+ * Mirrors the elvix.is REST envelopes — bump together with the
4
+ * server when they evolve.
5
+ */
6
+ type ElvixUser = {
7
+ id: string;
8
+ email: string;
9
+ name?: string;
10
+ avatarUrl?: string;
11
+ };
12
+ type ElvixVerifyOk = {
13
+ ok: true;
14
+ user: ElvixUser;
15
+ roles: string[];
16
+ scopes: string[];
17
+ memberships: string[];
18
+ };
19
+ type ElvixVerifyErr = {
20
+ ok: false;
21
+ error: "invalid_token" | "expired" | "revoked" | "membership_blocked" | "rate_limited";
22
+ message?: string;
23
+ };
24
+ type ElvixVerifyResult = ElvixVerifyOk | ElvixVerifyErr;
25
+ /**
26
+ * Discriminated union returned to host apps by every `<Elvix*>`
27
+ * mutation component's `onResult` callback. Always carries "safe to
28
+ * give back" data — no PII beyond what the customer already sees.
29
+ */
30
+ type ElvixActionResult<T = unknown> = {
31
+ ok: true;
32
+ data?: T;
33
+ redirect?: string;
34
+ } | {
35
+ ok: false;
36
+ error: string;
37
+ message?: string;
38
+ };
39
+
40
+ export type { ElvixActionResult, ElvixUser, ElvixVerifyErr, ElvixVerifyOk, ElvixVerifyResult };
package/dist/index.js ADDED
File without changes
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createElvixMcpServer
4
+ } from "../chunk-22IQNPXM.js";
5
+
6
+ // src/mcp/bin.ts
7
+ async function main() {
8
+ const apiKey = process.env.ELVIX_API_KEY;
9
+ if (!apiKey) {
10
+ process.stderr.write("ELVIX_API_KEY environment variable is required.\n");
11
+ process.exit(1);
12
+ }
13
+ const args = process.argv.slice(2);
14
+ const admin = args.includes("--admin");
15
+ const baseUrl = args.find((a) => a.startsWith("--base-url="))?.split("=")[1];
16
+ const { connectStdio } = await createElvixMcpServer({
17
+ apiKey,
18
+ readonly: !admin,
19
+ baseUrl
20
+ });
21
+ await connectStdio();
22
+ }
23
+ main().catch((e) => {
24
+ process.stderr.write(`elvix-mcp: ${e instanceof Error ? e.message : String(e)}
25
+ `);
26
+ process.exit(1);
27
+ });
@@ -0,0 +1,29 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+
3
+ /**
4
+ * Programmatic entry to the elvix MCP server. The CLI in `bin.ts`
5
+ * thin-wraps this so embedders can run an MCP server in-process if
6
+ * they want (testing, custom transports, multi-server hosts).
7
+ */
8
+
9
+ type ElvixMcpOptions = {
10
+ /** Bearer token used for every tool call. Required. */
11
+ apiKey: string;
12
+ /** Override the elvix origin (testing, proxy). */
13
+ baseUrl?: string;
14
+ /** When false, mutation tools (POST/PATCH/PUT/DELETE) are hidden
15
+ * from the tool list. Default true. Pass `--readonly`/`--admin`
16
+ * on the CLI to flip. */
17
+ readonly?: boolean;
18
+ };
19
+ /**
20
+ * Build (but don't connect) the MCP server. Returns the Server
21
+ * instance + a `connect()` to wire stdio. Lets callers choose
22
+ * transport.
23
+ */
24
+ declare function createElvixMcpServer(opts: ElvixMcpOptions): Promise<{
25
+ server: Server;
26
+ connectStdio: () => Promise<void>;
27
+ }>;
28
+
29
+ export { type ElvixMcpOptions, createElvixMcpServer };
@@ -0,0 +1,6 @@
1
+ import {
2
+ createElvixMcpServer
3
+ } from "../chunk-22IQNPXM.js";
4
+ export {
5
+ createElvixMcpServer
6
+ };
@@ -0,0 +1 @@
1
+ export { ElvixActionResult, ElvixUser, ElvixVerifyErr, ElvixVerifyOk, ElvixVerifyResult } from './index.js';
package/dist/react.js ADDED
File without changes
@@ -0,0 +1,27 @@
1
+ import { ElvixVerifyResult } from './index.js';
2
+
3
+ /**
4
+ * Server-side helpers for verifying elvix-issued session tokens.
5
+ * Customer backends call `verifyElvixToken` with the request's
6
+ * Authorization header. Bearer-token auth, no cookies.
7
+ */
8
+
9
+ type VerifyOptions = {
10
+ /** Application API key (Console → Credentials). */
11
+ apiKey: string;
12
+ /** Override the elvix origin for testing / proxy setups. */
13
+ baseUrl?: string;
14
+ /** Per-request timeout in ms. Default 5000. */
15
+ timeoutMs?: number;
16
+ };
17
+ /**
18
+ * Exchange an end-user session token for the verified user envelope
19
+ * (roles + scopes + memberships). Hit the `/api/v1/verify` endpoint
20
+ * with the customer's Application API key.
21
+ *
22
+ * Returns a discriminated union — never throws on auth failure.
23
+ * Throws only on infra failure (network, timeout, malformed JSON).
24
+ */
25
+ declare function verifyElvixToken(token: string, opts: VerifyOptions): Promise<ElvixVerifyResult>;
26
+
27
+ export { type VerifyOptions, verifyElvixToken };
package/dist/server.js ADDED
@@ -0,0 +1,47 @@
1
+ // src/server.ts
2
+ var DEFAULT_BASE_URL = "https://elvix.is";
3
+ async function verifyElvixToken(token, opts) {
4
+ const url = `${opts.baseUrl ?? DEFAULT_BASE_URL}/api/v1/verify`;
5
+ const ctrl = new AbortController();
6
+ const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 5e3);
7
+ try {
8
+ const res = await fetch(url, {
9
+ method: "POST",
10
+ headers: {
11
+ "content-type": "application/json",
12
+ authorization: `Bearer ${opts.apiKey}`
13
+ },
14
+ body: JSON.stringify({ token }),
15
+ signal: ctrl.signal
16
+ });
17
+ const body = await res.json();
18
+ if (!res.ok || !body.success || !body.data) {
19
+ return {
20
+ ok: false,
21
+ error: pickError(body.errorMessage, res.status),
22
+ message: body.errorMessage
23
+ };
24
+ }
25
+ return {
26
+ ok: true,
27
+ user: body.data.user,
28
+ roles: body.data.roles,
29
+ scopes: body.data.scopes,
30
+ memberships: body.data.memberships
31
+ };
32
+ } finally {
33
+ clearTimeout(timer);
34
+ }
35
+ }
36
+ function pickError(raw, status) {
37
+ if (raw === "expired" || raw === "revoked" || raw === "membership_blocked" || raw === "rate_limited") {
38
+ return raw;
39
+ }
40
+ if (status === 401) return "invalid_token";
41
+ if (status === 403) return "membership_blocked";
42
+ if (status === 429) return "rate_limited";
43
+ return "invalid_token";
44
+ }
45
+ export {
46
+ verifyElvixToken
47
+ };
package/package.json CHANGED
@@ -1,9 +1,79 @@
1
1
  {
2
2
  "name": "@elvix.is/sdk",
3
- "version": "0.0.0",
4
- "description": "elvix Identity, kept in Europe. SDK (placeholder; real release coming).",
3
+ "version": "0.1.1",
4
+ "description": "Official elvix SDK. Drop-in React components, server helpers, and an MCP server so AI coding agents integrate elvix on the first try.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://elvix.is",
7
- "repository": "github:elvix-is/sdk",
8
- "keywords": ["auth", "identity", "gdpr", "passkeys", "oauth", "eu"]
7
+ "author": "edvone <hi@edvone.dev> (https://edvone.dev)",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/021is/elvix-sdk.git"
11
+ },
12
+ "bugs": "https://github.com/021is/elvix-sdk/issues",
13
+ "type": "module",
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "bin": {
17
+ "elvix-mcp": "./dist/mcp/bin.js"
18
+ },
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ },
24
+ "./react": {
25
+ "types": "./dist/react.d.ts",
26
+ "import": "./dist/react.js"
27
+ },
28
+ "./server": {
29
+ "types": "./dist/server.d.ts",
30
+ "import": "./dist/server.js"
31
+ },
32
+ "./types": {
33
+ "types": "./dist/types.d.ts",
34
+ "import": "./dist/types.js"
35
+ },
36
+ "./mcp": {
37
+ "types": "./dist/mcp/index.d.ts",
38
+ "import": "./dist/mcp/index.js"
39
+ }
40
+ },
41
+ "files": ["dist", "README.md", "LICENSE"],
42
+ "scripts": {
43
+ "build": "tsup src/index.ts src/react.ts src/server.ts src/types.ts src/mcp/index.ts src/mcp/bin.ts --format esm --dts --clean --external react --external next",
44
+ "typecheck": "tsc --noEmit",
45
+ "test": "vitest run"
46
+ },
47
+ "peerDependencies": {
48
+ "react": ">=18",
49
+ "next": ">=15"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "next": { "optional": true }
53
+ },
54
+ "dependencies": {
55
+ "@modelcontextprotocol/sdk": "^1.0.4"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^22.7.5",
59
+ "tsup": "^8.3.0",
60
+ "typescript": "^5.6.3",
61
+ "vitest": "^2.1.2"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ },
66
+ "keywords": [
67
+ "elvix",
68
+ "authentication",
69
+ "auth",
70
+ "passkey",
71
+ "otp",
72
+ "google-oauth",
73
+ "react",
74
+ "nextjs",
75
+ "mcp",
76
+ "model-context-protocol",
77
+ "ai-agents"
78
+ ]
9
79
  }