@usecontextlayer/sdk 0.14.3 → 0.15.0
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/README.md +68 -15
- package/dist/index-Dle7CHzb.d.ts +10 -0
- package/dist/index-Dle7CHzb.d.ts.map +1 -0
- package/dist/index.d.ts +3 -10
- package/dist/index.js +3 -7
- package/dist/local.d.ts +50 -6
- package/dist/local.d.ts.map +1 -1
- package/dist/local.js +81 -10
- package/dist/local.js.map +1 -1
- package/dist/sdk-BMmzPuDi.js +18 -0
- package/dist/sdk-BMmzPuDi.js.map +1 -0
- package/dist/tools-BDLYKxEr.js +15 -0
- package/dist/tools-BDLYKxEr.js.map +1 -0
- package/dist/tools-BLXbCgQU-D3L2WEEd.d.ts +46 -0
- package/dist/tools-BLXbCgQU-D3L2WEEd.d.ts.map +1 -0
- package/dist/vite.d.ts +1 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +164 -16
- package/dist/vite.js.map +1 -1
- package/dist/worker.d.ts +20 -4
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +17 -3
- package/dist/worker.js.map +1 -1
- package/examples/{gmail.tsx → gmail/app/routes/home.tsx} +1 -0
- package/examples/gmail/public/slate.json +9 -0
- package/package.json +12 -4
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
# @usecontextlayer/sdk
|
|
2
2
|
|
|
3
|
-
ContextLayer integration for React Router apps: the shared document Layout and
|
|
3
|
+
ContextLayer integration for React Router apps: the shared document Layout, Tools and Databases capabilities. Local tool calls use the signed-in developer's personal accounts and current-folder connection bindings. Hosted calls use pushed requirements and platform-stored viewer/app-Owner assignments.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use Node.js 24 or newer, pnpm, and Git with configured author identity. Start with login, then create and run your app:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npx @usecontextlayer/cli login
|
|
9
|
+
npx @usecontextlayer/cli init my-app
|
|
10
|
+
cd my-app
|
|
11
|
+
pnpm dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The CLI installs this package and configures a development-only Cloudflare Worker and native service binding. Open the local URL printed by the development server. Initialization prints your dashboard link, hosted URL, and Git publication steps; the hosted URL becomes usable after deployment succeeds. Use `npx @usecontextlayer/cli` for subsequent CLI commands. First-party `@usecontextlayer/*` packages are exempt from pnpm's release-age policy in generated projects.
|
|
6
15
|
|
|
7
16
|
## Local login and assignment
|
|
8
17
|
|
|
9
|
-
Declare resources in `public/slate.json` and `agents/<name>/slate.json`, using the same Slate schema and shared resource names. Local commands read only the current app folder. Use
|
|
18
|
+
Declare resources in `public/slate.json` and `agents/<name>/slate.json`, using the same Slate schema and shared resource names. Local commands read only the current app folder. Use `npx @usecontextlayer/cli connections --help` and `npx @usecontextlayer/cli connection --help` for listing, personal account authorization, and assignment syntax. Local listing needs no login or push; choosing an account requires a matching `npx @usecontextlayer/cli login`. Account choices are saved in ignored `.contextlayer/connections.json` rather than production assignments.
|
|
10
19
|
|
|
11
|
-
Local development always uses your personal accounts, including owner-mode requirements in organization-owned apps. Local secrets read environment variables with exactly their declared names; local
|
|
20
|
+
Local development always uses your personal accounts, including owner-mode requirements in organization-owned apps. Local secrets read environment variables with exactly their declared names; local databases use native SQLite-backed Durable Objects persisted in `.contextlayer/databases`. Tooling ignores `.contextlayer/` in Git. Current-checkout SQL migrations are applied before local execution.
|
|
12
21
|
|
|
13
|
-
When `pnpm dev` starts, `contextlayer(env)` from `@usecontextlayer/sdk/vite` configures the Cloudflare Vite plugin and calls the CLI-owned `
|
|
22
|
+
When `pnpm dev` starts, `contextlayer(env)` from `@usecontextlayer/sdk/vite` configures the Cloudflare Vite plugin and calls the CLI-owned `getLocalResourcesBindings` helper. This helper assembles the complete current-folder configuration before selecting the app consumer through `resourcesForConsumer`. The app’s resolved connections, Git-origin AppID and CLI credential become trusted native Tools props when connections are required. Selected database references become separate Databases props; the full collected migration history is applied during native startup. Agent-only connections, secret values, database configuration, and local declarations are not sent to platform or browser code. The AppID supplies app access/subscription/usage context independently of personal credential ownership.
|
|
14
23
|
|
|
15
|
-
The auxiliary Worker exports
|
|
24
|
+
The auxiliary resource Worker exports `LocalTools` as `Tools`, `LocalDatabases` as `Databases`, `LocalDatabaseSetup` as `DatabaseSetup`, and the native `AppDatabase` class. Tools resolves the requested slug to the startup account ID and declaration toolkit, then calls the personal concrete-account endpoint. An undeclared local slug is a configuration error; a declared slug without an assigned account produces the shared setup response locally. There is no production-assignment fallback. The refresh token stays in `~/.contextlayer/auth.json`; the Composio project key stays on platform. Restart `pnpm dev` when the access token expires or declarations/local configuration change.
|
|
16
25
|
|
|
17
26
|
## App Layout
|
|
18
27
|
|
|
@@ -22,11 +31,11 @@ The generated `app/root.tsx` re-exports the SDK's document Layout:
|
|
|
22
31
|
export { Layout } from "@usecontextlayer/sdk/react"
|
|
23
32
|
```
|
|
24
33
|
|
|
25
|
-
The Layout owns the HTML document, React Router's metadata, links, scripts, scroll restoration, and
|
|
34
|
+
The Layout owns the HTML document, React Router's metadata, links, scripts, scroll restoration, and hosted ContextLayer header. Native Vite development detection disables the header locally, so local configuration never enters the platform frame. The app owns its routes, root component, error boundary, stylesheet, and font links. The trusted header supplies hosted connection configuration for Owners the viewer can manage.
|
|
26
35
|
|
|
27
|
-
|
|
36
|
+
Platform serves the header and connection tray in a cross-origin iframe on `slate.usecontextlayer.com`. Platform owns their presentation and data loading; the parent receives only presentation messages. The app's Tailwind/shadcn setup is independent; there is no SDK stylesheet export or chrome root loader.
|
|
28
37
|
|
|
29
|
-
The frame authenticates directly with the native web session. Its cookie always uses Secure, HttpOnly, and SameSite=None, in every environment. When browser third-party-cookie policy permits delivery, the existing web login authenticates the header automatically, without a separate sign-in or frame cookie. Web logout revokes subsequent frame authentication. The surrounding authored page receives neither credentials nor chrome data.
|
|
38
|
+
The frame authenticates directly with the native web session. Its cookie always uses Secure, HttpOnly, and SameSite=None, in every environment. When browser third-party-cookie policy permits delivery, the existing web login authenticates the header automatically, without a separate sign-in or frame cookie. Web logout revokes subsequent frame authentication. The surrounding authored page receives neither credentials nor chrome data.
|
|
30
39
|
|
|
31
40
|
## A loader that reads Gmail
|
|
32
41
|
|
|
@@ -46,13 +55,39 @@ export async function loader({ context }: LoaderFunctionArgs) {
|
|
|
46
55
|
}
|
|
47
56
|
```
|
|
48
57
|
|
|
49
|
-
Calls return `{ data, logId }`. Validate the tool-specific `data` in your loader. The
|
|
58
|
+
Calls return `{ data, logId }`. Validate the tool-specific `data` in your loader. The [Gmail route](examples/gmail/app/routes/home.tsx) validates the response with Zod and renders a message list. Its [Slate declaration](examples/gmail/public/slate.json) declares `work-email` as viewer-mode Gmail. The example follows the same `app/routes/home.tsx` and `public/slate.json` layout as your app.
|
|
59
|
+
|
|
60
|
+
From a newly generated app's root, copy both files from the installed SDK:
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
cp node_modules/@usecontextlayer/sdk/examples/gmail/app/routes/home.tsx app/routes/home.tsx
|
|
64
|
+
cp node_modules/@usecontextlayer/sdk/examples/gmail/public/slate.json public/slate.json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
If Gmail is not connected yet, request authorization:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
npx @usecontextlayer/cli connections add gmail
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Open the printed link and approve access in your browser. Authorization connects Gmail to ContextLayer. Next, assign the connected account to this app's `work-email` requirement through the chooser, then start development. If Gmail is already connected, begin with assignment:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
npx @usecontextlayer/cli connection local assign work-email
|
|
77
|
+
pnpm dev
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Open the local URL printed by the development server to see your inbox. If development is already running, restart it after copying the declaration and assigning the account so startup reads the new configuration.
|
|
81
|
+
|
|
82
|
+
If the declared connection has no account assigned yet, the generated app’s error boundary shows account-setup guidance. Locally, follow its assignment command and restart `pnpm dev`. In a hosted app, open the connections menu in the ContextLayer header, choose an account, and refresh the page. The Gmail route uses the generated root's error boundary.
|
|
50
83
|
|
|
51
84
|
## Runtime ownership
|
|
52
85
|
|
|
53
|
-
The package root exports
|
|
86
|
+
The package root exports `Tools`/`toolsContext` and `Databases`/`databasesContext`, plus `database` for native Drizzle queries. `@usecontextlayer/sdk/react` exports the shared document Layout, which mounts platform's chrome iframe only outside development. `@usecontextlayer/sdk/local` exports the local Tools and Databases entrypoints, DatabaseSetup and AppDatabase; dispatcher separately exports hosted Tools and Databases. Both tool entrypoints share result/error semantics and preserve the authored `tools.call` interface. `@usecontextlayer/sdk/worker` exports `createApp`, which creates the React Router request handler and supplies Tools and Databases from local bindings or production request props. `@usecontextlayer/sdk/vite` owns the `contextlayer` integration. The CLI package owns the Node startup helper and saved-login handling. The generated application supplies its virtual server-build import, mode, and development flag through thin Worker wiring. The Cloudflare Vite plugin runs the auxiliary Worker only in development; production bundles exclude it and its service binding. Profile and connection reads belong to the trusted chrome frame; the SDK exposes no Viewer or Connections capability.
|
|
87
|
+
|
|
88
|
+
In hosted apps, the dispatcher supplies `ctx.props.tools` as a request-scoped RPC handle. Its methods call platform’s private `Execution` entrypoint through the dispatcher’s `EXECUTION` service binding; the app cannot read the underlying viewer credential. Platform verifies that viewer session and applies viewing and billing policy before execution. That session authenticates the caller, while the coherent pushed declaration's mode selects the viewer or app Owner's assignment for the app and slug. Viewer-mode execution requires explicit app membership and uses that member's production assignment. Connection configuration remains available before joining; owner-mode execution requires viewing permission without membership. Local connection choices remain separate even when the developer is also a production viewer. Owner-mode requirements use the app Owner's configured account. Local access-token bindings are not included in production builds.
|
|
54
89
|
|
|
55
|
-
|
|
90
|
+
An undeclared hosted resource returns `not-declared`, and a hosted viewer-mode resource used before joining returns `membership-required`. These are ordinary Errors with those exact messages. An undeclared local connection is a configuration error; a declared connection with no account assignment is a setup condition. Hosted execution returns the typed `connection-required` outcome with its slug; Tools maps it to a native HTTP 409 Response with the shared `{ reason: "connection-required", slug }` payload. Tools carries a native Response over RPC; `createApp` throws it inside the authored app for React Router to handle. The package root exports `connectionRequiredSchema` so the app's error boundary can recognize this setup response through `isRouteErrorResponse(error)` and `error.data`. The generated root already does this. The response contains no account ID, profile, or credential. Successful authored `Tools.call` results remain `{ data, logId }`, and unrelated failures retain their existing error handling.
|
|
56
91
|
|
|
57
92
|
## Vite configuration
|
|
58
93
|
|
|
@@ -70,14 +105,32 @@ export default defineConfig((env) => ({
|
|
|
70
105
|
}))
|
|
71
106
|
```
|
|
72
107
|
|
|
73
|
-
This integration supplies the Cloudflare plugin; do not add a second instance. It uses the generated `workers/local-
|
|
108
|
+
This integration supplies the Cloudflare plugin; do not add a second instance. It uses the generated `workers/local-resources/wrangler.jsonc` to start the local resource Worker and supplies development-only Tools/Databases service bindings. At development startup, the CLI assembles current-checkout resources and reads Git origin/login when app connections require them. The restart prerequisites are described under [Local login and assignment](#local-login-and-assignment). Production builds exclude local credentials and the auxiliary Worker.
|
|
74
109
|
|
|
75
110
|
The app retains its routes, `public/slate.json`, and thin Worker/configuration files. `@usecontextlayer/sdk/worker` owns the React Router request handler and capability context setup.
|
|
76
111
|
|
|
77
112
|
## App requirements and saved assignments
|
|
78
113
|
|
|
79
|
-
The platform frame loader reads the browser viewer's profile and requirement/assignment rows through the shared app-connection listing operation. Signed-in viewers can inspect their required services and select accounts through each row's controls.
|
|
114
|
+
The platform frame loader reads the browser viewer's profile and requirement/assignment rows through the shared app-connection listing operation. Signed-in viewers can inspect their required services and select accounts through each row's controls. These data stay in the trusted frame; anonymous viewers receive no account controls.
|
|
80
115
|
|
|
81
|
-
The Slate schema and viewer/owner requirements live in `@usecontextlayer/shared/slate`. The neutral requirement/assignment response in `@usecontextlayer/shared/app-connections` is shared by platform and CLI.
|
|
116
|
+
The Slate schema and viewer/owner requirements live in `@usecontextlayer/shared/slate`. The neutral requirement/assignment response in `@usecontextlayer/shared/app-connections` is shared by platform and CLI. Use the hosted header to authorize or select accounts, then refresh the authored app’s data after configuration changes. Chrome is disabled during local development. Vite does not expose local configuration or app identity through a browser configuration plugin; the selected local connection inputs and credentials remain behind the Tools service binding. Restart development after editing requirements or bindings.
|
|
82
117
|
|
|
83
118
|
`createApp` returns the exported `App` type from `@usecontextlayer/sdk/worker`, derived from Cloudflare's native `ExportedHandler` fetch contract. The SDK owns its local binding and request-props types. This gives the generated Worker a portable public declaration under the Cloudflare scaffold's composite TypeScript configuration.
|
|
119
|
+
|
|
120
|
+
## A loader that queries cached data
|
|
121
|
+
|
|
122
|
+
Declare a database slug in `public/slate.json` and the same slug in `agents/<name>/slate.json` when both should share data. Store its authored SQL migrations under `databases/<name>/migrations`. The template supplies Drizzle configuration and query schema; `pnpm db:migration --config databases/<name>/drizzle.config.ts --name <change>` scaffolds a blank migration for you to write explicitly. Commit the SQL and native `meta/_journal.json` together. The TypeScript schema supplies query typing, never generated DDL.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { database, databasesContext } from "@usecontextlayer/sdk"
|
|
126
|
+
import { eq } from "drizzle-orm"
|
|
127
|
+
import type { LoaderFunctionArgs } from "react-router"
|
|
128
|
+
import * as schema from "@/databases/updates/schema"
|
|
129
|
+
|
|
130
|
+
export async function loader({ context }: LoaderFunctionArgs) {
|
|
131
|
+
const db = database(context.get(databasesContext), "updates", schema)
|
|
132
|
+
return db.select().from(schema.updates).where(eq(schema.updates.kind, "email"))
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The loader receives a request-scoped SQL capability. Hosted platform derives the database from the app, authorized actor and declared mode; local execution uses prepared developer-local SQLite state. App and agent declarations selecting the same resource share rows. For direct SQL, use `context.get(databasesContext).query("updates", sql, params)`. Agents use `database_query`; writes persist immediately, and sandbox files remain scratch data. Local startup applies the current checkout’s migrations before queries. Hosted publication applies pending committed migrations for existing members; joining applies the full history for the joining member. Queries and agent preparation do not apply migrations.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { a as Databases, t as Tools } from "./tools-BLXbCgQU-D3L2WEEd.js";
|
|
2
|
+
//#region database.d.ts
|
|
3
|
+
declare function database<TSchema extends Record<string, unknown>>(databases: Databases, slug: string, schema: TSchema): import("drizzle-orm/sqlite-proxy").SqliteRemoteDatabase<TSchema>;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region index.d.ts
|
|
6
|
+
declare const toolsContext: import("react-router").RouterContext<Tools>;
|
|
7
|
+
declare const databasesContext: import("react-router").RouterContext<Databases>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { toolsContext as n, database as r, databasesContext as t };
|
|
10
|
+
//# sourceMappingURL=index-Dle7CHzb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Dle7CHzb.d.ts","names":[],"sources":["../database.ts","../index.ts"],"mappings":";;iBAGgB,SAAS,gBAAgB,yBACxC,WAAW,WACX,cACA,QAAQ,6CAAO,qBAAA;;;cCAH,qCAAY,cAAA;cAEZ,yCAAgB,cAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
data: unknown;
|
|
5
|
-
logId: string;
|
|
6
|
-
}>;
|
|
7
|
-
}
|
|
8
|
-
export declare const toolsContext: import("react-router").RouterContext<Tools>;
|
|
9
|
-
//#endregion
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
|
1
|
+
import { a as Databases, r as connectionRequiredSchema, t as Tools } from "./tools-BLXbCgQU-D3L2WEEd.js";
|
|
2
|
+
import { n as toolsContext, r as database, t as databasesContext } from "./index-Dle7CHzb.js";
|
|
3
|
+
export { type Databases, type Tools, connectionRequiredSchema, database, databasesContext, toolsContext };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
//#endregion
|
|
5
|
-
export { toolsContext };
|
|
6
|
-
|
|
7
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import { t as connectionRequiredSchema } from "./tools-BDLYKxEr.js";
|
|
2
|
+
import { n as toolsContext, r as database, t as databasesContext } from "./sdk-BMmzPuDi.js";
|
|
3
|
+
export { connectionRequiredSchema, database, databasesContext, toolsContext };
|
package/dist/local.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { i as DatabaseMigrations, o as SqlValue } from "./tools-BLXbCgQU-D3L2WEEd.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
|
-
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
3
|
-
//#region ../shared/dist/app-resources.d.mts
|
|
3
|
+
import { DurableObject, WorkerEntrypoint } from "cloudflare:workers";
|
|
4
|
+
//#region ../shared/dist/app-resources-CJH87mYB.d.mts
|
|
4
5
|
declare const localResourceConfigurationSchema: z.ZodObject<{
|
|
5
6
|
connections: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
6
7
|
mode: z.ZodEnum<{
|
|
@@ -16,7 +17,7 @@ declare const localResourceConfigurationSchema: z.ZodObject<{
|
|
|
16
17
|
}, z.core.$strict>], "type">>;
|
|
17
18
|
connection_id: z.ZodNullable<z.ZodString>;
|
|
18
19
|
}, z.core.$strict>>;
|
|
19
|
-
|
|
20
|
+
databases: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
20
21
|
mode: z.ZodEnum<{
|
|
21
22
|
owner: "owner";
|
|
22
23
|
viewer: "viewer";
|
|
@@ -27,7 +28,18 @@ declare const localResourceConfigurationSchema: z.ZodObject<{
|
|
|
27
28
|
name: z.ZodString;
|
|
28
29
|
type: z.ZodLiteral<"agent">;
|
|
29
30
|
}, z.core.$strict>], "type">>;
|
|
30
|
-
|
|
31
|
+
instance_name: z.ZodString;
|
|
32
|
+
migrations: z.ZodObject<{
|
|
33
|
+
journal: z.ZodObject<{
|
|
34
|
+
entries: z.ZodArray<z.ZodObject<{
|
|
35
|
+
breakpoints: z.ZodBoolean;
|
|
36
|
+
idx: z.ZodNumber;
|
|
37
|
+
tag: z.ZodString;
|
|
38
|
+
when: z.ZodNumber;
|
|
39
|
+
}, z.core.$strip>>;
|
|
40
|
+
}, z.core.$strip>;
|
|
41
|
+
migrations: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
42
|
+
}, z.core.$strip>;
|
|
31
43
|
}, z.core.$strict>>;
|
|
32
44
|
secrets: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
33
45
|
mode: z.ZodEnum<{
|
|
@@ -45,6 +57,38 @@ declare const localResourceConfigurationSchema: z.ZodObject<{
|
|
|
45
57
|
}, z.core.$strict>;
|
|
46
58
|
type LocalResourceConfiguration = z.infer<typeof localResourceConfigurationSchema>;
|
|
47
59
|
//#endregion
|
|
60
|
+
//#region ../shared/dist/database-worker.d.mts
|
|
61
|
+
//#region lib/database-worker.d.ts
|
|
62
|
+
export declare class AppDatabase extends DurableObject {
|
|
63
|
+
setup(migrations: DatabaseMigrations): Promise<void>;
|
|
64
|
+
query(sql: string, params?: SqlValue[]): Promise<{
|
|
65
|
+
columns: string[];
|
|
66
|
+
rows: (string | number | null)[][];
|
|
67
|
+
rowsRead: number;
|
|
68
|
+
rowsWritten: number;
|
|
69
|
+
}>;
|
|
70
|
+
}
|
|
71
|
+
declare class LocalDatabases extends WorkerEntrypoint<{
|
|
72
|
+
DATABASE_STORAGE: DurableObjectNamespace<AppDatabase>;
|
|
73
|
+
}, {
|
|
74
|
+
databases: LocalResourceConfiguration["databases"];
|
|
75
|
+
}> {
|
|
76
|
+
fetch(request: Request): Promise<Response>;
|
|
77
|
+
query(slug: string, sql: string, params?: SqlValue[]): Promise<{
|
|
78
|
+
columns: string[];
|
|
79
|
+
rows: (string | number | null)[][];
|
|
80
|
+
rowsRead: number;
|
|
81
|
+
rowsWritten: number;
|
|
82
|
+
} & Disposable>;
|
|
83
|
+
}
|
|
84
|
+
declare class LocalDatabaseSetup extends WorkerEntrypoint<{
|
|
85
|
+
DATABASE_STORAGE: DurableObjectNamespace<AppDatabase>;
|
|
86
|
+
}, {
|
|
87
|
+
databases: LocalResourceConfiguration["databases"];
|
|
88
|
+
}> {
|
|
89
|
+
fetch(): Promise<Response>;
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
48
92
|
//#endregion
|
|
49
93
|
//#region ../shared/dist/tools-worker.d.mts
|
|
50
94
|
interface LocalToolsProps {
|
|
@@ -58,12 +102,12 @@ interface LocalToolsProps {
|
|
|
58
102
|
declare class LocalTools extends WorkerEntrypoint<{
|
|
59
103
|
CTX_PLATFORM_URL: string;
|
|
60
104
|
}, LocalToolsProps> {
|
|
61
|
-
call(slug: string, toolSlug: string, args: Record<string, unknown>): Promise<{
|
|
105
|
+
call(slug: string, toolSlug: string, args: Record<string, unknown>): Promise<Response | {
|
|
62
106
|
data: Record<string, unknown>;
|
|
63
107
|
logId: string;
|
|
64
108
|
}>;
|
|
65
109
|
}
|
|
66
110
|
//#endregion
|
|
67
111
|
//#endregion
|
|
68
|
-
export { LocalTools as Tools };
|
|
112
|
+
export { LocalDatabaseSetup as DatabaseSetup, LocalDatabases as Databases, LocalTools as Tools };
|
|
69
113
|
//# sourceMappingURL=local.d.ts.map
|
package/dist/local.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","names":[],"sources":["../../shared/dist/app-resources.d.mts","../../shared/dist/tools-worker.d.mts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"local.d.ts","names":[],"sources":["../../shared/dist/app-resources-CJH87mYB.d.mts","../../shared/dist/database-worker.d.mts","../../shared/dist/tools-worker.d.mts"],"mappings":";;;;cAiIc,kCAAkC,EAAE;EAChD,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE;IACtC,MAAM,EAAE;MACN;MACA;;IAEF,SAAS,EAAE;IACX,WAAW,EAAE,SAAS,EAAE,uBAAuB,EAAE;MAC/C,MAAM,EAAE;OACP,EAAE,KAAK,UAAU,EAAE;MACpB,MAAM,EAAE;MACR,MAAM,EAAE;OACP,EAAE,KAAK;IACV,eAAe,EAAE,YAAY,EAAE;KAC9B,EAAE,KAAK;EACV,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE;IACpC,MAAM,EAAE;MACN;MACA;;IAEF,WAAW,EAAE,SAAS,EAAE,uBAAuB,EAAE;MAC/C,MAAM,EAAE;OACP,EAAE,KAAK,UAAU,EAAE;MACpB,MAAM,EAAE;MACR,MAAM,EAAE;OACP,EAAE,KAAK;IACV,eAAe,EAAE;IACjB,YAAY,EAAE;MACZ,SAAS,EAAE;QACT,SAAS,EAAE,SAAS,EAAE;UACpB,aAAa,EAAE;UACf,KAAK,EAAE;UACP,KAAK,EAAE;UACP,MAAM,EAAE;WACP,EAAE,KAAK;SACT,EAAE,KAAK;MACV,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE;OACtC,EAAE,KAAK;KACT,EAAE,KAAK;EACV,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE;IAClC,MAAM,EAAE;MACN;MACA;;IAEF,WAAW,EAAE,SAAS,EAAE,uBAAuB,EAAE;MAC/C,MAAM,EAAE;OACP,EAAE,KAAK,UAAU,EAAE;MACpB,MAAM,EAAE;MACR,MAAM,EAAE;OACP,EAAE,KAAK;IACV,OAAO,EAAE,YAAY,EAAE;KACtB,EAAE,KAAK;GACT,EAAE,KAAK;KACL,6BAA6B,EAAE,aAAa;;;;qBClL5B,oBAAoB;EACvC,MAAM,YAAY,qBAAqB;EACvC,MAAM,aAAa,SAAS,aAAa;IACvC;IACA;IACA;IACA;;;cAGiB,uBAAuB;EAC1C,kBAAkB,uBAAuB;;EAEzC,WAAW;;EAEX,MAAM,SAAS,UAAU,QAAQ;EACjC,MAAM,cAAc,aAAa,SAAS,aAAa;IACrD;IACA;IACA;IACA;MACE;;cAEe,2BAA2B;EAC9C,kBAAkB,uBAAuB;;EAEzC,WAAW;;EAEX,SAAS,QAAQ;;;;;UCIF;EACf;EACA,aAAa;EACb;IACE;IACA;;;cAWiB,mBAAmB;EACtC;GACC;EACD,KAAK,cAAc,kBAAkB,MAAM,0BAA0B,QAAQ;IAC3E,MAAM;IACN"}
|
package/dist/local.js
CHANGED
|
@@ -1,19 +1,77 @@
|
|
|
1
|
+
import { n as toolResultSchema, t as connectionRequiredSchema } from "./tools-BDLYKxEr.js";
|
|
1
2
|
import { z } from "zod";
|
|
2
|
-
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { DurableObject, WorkerEntrypoint } from "cloudflare:workers";
|
|
4
|
+
import { drizzle } from "drizzle-orm/durable-sqlite";
|
|
5
|
+
import { migrate } from "drizzle-orm/durable-sqlite/migrator";
|
|
6
|
+
//#region ../shared/dist/databases.mjs
|
|
7
|
+
const databaseJournalSchema = z.object({ entries: z.array(z.object({
|
|
8
|
+
breakpoints: z.boolean(),
|
|
9
|
+
idx: z.number().int().nonnegative(),
|
|
10
|
+
tag: z.string().min(1),
|
|
11
|
+
when: z.number()
|
|
12
|
+
})) });
|
|
13
|
+
const databaseMigrationsSchema = z.object({
|
|
14
|
+
journal: databaseJournalSchema,
|
|
15
|
+
migrations: z.record(z.string(), z.string())
|
|
16
|
+
});
|
|
17
|
+
const sqlValueSchema = z.union([
|
|
18
|
+
z.string(),
|
|
19
|
+
z.number(),
|
|
20
|
+
z.null()
|
|
21
|
+
]);
|
|
22
|
+
const databaseQuerySchema = z.strictObject({
|
|
23
|
+
params: z.array(sqlValueSchema).default([]),
|
|
24
|
+
slug: z.string().min(1),
|
|
25
|
+
sql: z.string().min(1)
|
|
26
|
+
});
|
|
27
|
+
const databaseResultSchema = z.object({
|
|
28
|
+
columns: z.array(z.string()),
|
|
29
|
+
rows: z.array(z.array(sqlValueSchema)),
|
|
30
|
+
rowsRead: z.number(),
|
|
31
|
+
rowsWritten: z.number()
|
|
8
32
|
});
|
|
9
33
|
//#endregion
|
|
34
|
+
//#region ../shared/dist/database-worker.mjs
|
|
35
|
+
var AppDatabase = class extends DurableObject {
|
|
36
|
+
async setup(migrations) {
|
|
37
|
+
await migrate(drizzle(this.ctx.storage), databaseMigrationsSchema.parse(migrations));
|
|
38
|
+
}
|
|
39
|
+
async query(sql, params = []) {
|
|
40
|
+
const cursor = this.ctx.storage.sql.exec(sql, ...params);
|
|
41
|
+
const rows = Array.from(cursor.raw());
|
|
42
|
+
return databaseResultSchema.parse({
|
|
43
|
+
columns: cursor.columnNames,
|
|
44
|
+
rows,
|
|
45
|
+
rowsRead: cursor.rowsRead,
|
|
46
|
+
rowsWritten: cursor.rowsWritten
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var LocalDatabases = class extends WorkerEntrypoint {
|
|
51
|
+
async fetch(request) {
|
|
52
|
+
const { slug, sql, params } = databaseQuerySchema.parse(await request.json());
|
|
53
|
+
return Response.json(await this.query(slug, sql, params));
|
|
54
|
+
}
|
|
55
|
+
async query(slug, sql, params = []) {
|
|
56
|
+
const database = this.ctx.props.databases[slug];
|
|
57
|
+
if (!database) throw new Error(`No local database requirement for "${slug}"`);
|
|
58
|
+
return this.env.DATABASE_STORAGE.getByName(database.instance_name).query(sql, params);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var LocalDatabaseSetup = class extends WorkerEntrypoint {
|
|
62
|
+
async fetch() {
|
|
63
|
+
for (const database of Object.values(this.ctx.props.databases)) await this.env.DATABASE_STORAGE.getByName(database.instance_name).setup(database.migrations);
|
|
64
|
+
return new Response(null, { status: 204 });
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
//#endregion
|
|
10
68
|
//#region ../shared/dist/tools-worker.mjs
|
|
11
69
|
var LocalTools = class extends WorkerEntrypoint {
|
|
12
70
|
async call(slug, toolSlug, args) {
|
|
13
71
|
const { appId, connections, credential } = this.ctx.props;
|
|
14
72
|
const connection = new Map(Object.entries(connections)).get(slug);
|
|
15
|
-
if (!connection) throw new Error(
|
|
16
|
-
if (connection.connection_id === null)
|
|
73
|
+
if (!connection) throw new Error("not-declared");
|
|
74
|
+
if (connection.connection_id === null) return connectionRequiredResponse(slug);
|
|
17
75
|
return executeToolRequest(new Request(new URL(`/api/connections/${encodeURIComponent(connection.connection_id)}/tools/call`, this.env.CTX_PLATFORM_URL), {
|
|
18
76
|
body: JSON.stringify({
|
|
19
77
|
app_id: appId,
|
|
@@ -31,15 +89,28 @@ var LocalTools = class extends WorkerEntrypoint {
|
|
|
31
89
|
};
|
|
32
90
|
async function executeToolRequest(request) {
|
|
33
91
|
const response = await fetch(request);
|
|
92
|
+
if (response.status === 409) return connectionRequiredResponse(connectionRequiredSchema.parse(await response.json()).slug);
|
|
93
|
+
if (response.status === 402) throw new Error(await response.text());
|
|
34
94
|
if (!response.ok) throw new Error(`Tool call failed: HTTP ${response.status}`);
|
|
35
|
-
|
|
95
|
+
return readToolResult(toolResultSchema.parse(await response.json()));
|
|
96
|
+
}
|
|
97
|
+
function readToolResult(result) {
|
|
36
98
|
if (result.error !== null) throw new Error(`${result.error} (log: ${result.logId})`);
|
|
37
99
|
return {
|
|
38
100
|
data: result.data,
|
|
39
101
|
logId: result.logId
|
|
40
102
|
};
|
|
41
103
|
}
|
|
104
|
+
function connectionRequiredResponse(slug) {
|
|
105
|
+
return Response.json({
|
|
106
|
+
reason: "connection-required",
|
|
107
|
+
slug
|
|
108
|
+
}, {
|
|
109
|
+
status: 409,
|
|
110
|
+
statusText: "Connection required"
|
|
111
|
+
});
|
|
112
|
+
}
|
|
42
113
|
//#endregion
|
|
43
|
-
export { LocalTools as Tools };
|
|
114
|
+
export { AppDatabase, LocalDatabaseSetup as DatabaseSetup, LocalDatabases as Databases, LocalTools as Tools };
|
|
44
115
|
|
|
45
116
|
//# sourceMappingURL=local.js.map
|
package/dist/local.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","names":[],"sources":["../../shared/dist/
|
|
1
|
+
{"version":3,"file":"local.js","names":[],"sources":["../../shared/dist/databases.mjs","../../shared/dist/database-worker.mjs","../../shared/dist/tools-worker.mjs"],"sourcesContent":["import { z } from \"zod\";\n\n//#region lib/databases.ts\nconst databaseJournalSchema = z.object({ entries: z.array(z.object({\n\tbreakpoints: z.boolean(),\n\tidx: z.number().int().nonnegative(),\n\ttag: z.string().min(1),\n\twhen: z.number()\n})) });\nconst databaseMigrationsSchema = z.object({\n\tjournal: databaseJournalSchema,\n\tmigrations: z.record(z.string(), z.string())\n});\nasync function readDatabaseMigrations(slug, read) {\n\tconst directory = `databases/${slug}/migrations`;\n\tconst contents = await read(`${directory}/meta/_journal.json`);\n\tif (contents === null) return {\n\t\tjournal: { entries: [] },\n\t\tmigrations: {}\n\t};\n\tconst journal = databaseJournalSchema.parse(JSON.parse(contents));\n\tconst migrations = await Promise.all(journal.entries.map(async (entry) => {\n\t\tconst sql = await read(`${directory}/${entry.tag}.sql`);\n\t\tif (sql === null) throw new Error(`Missing database migration: ${slug}/${entry.tag}.sql`);\n\t\treturn [`m${entry.idx.toString().padStart(4, \"0\")}`, sql];\n\t}));\n\treturn {\n\t\tjournal,\n\t\tmigrations: Object.fromEntries(migrations)\n\t};\n}\nconst sqlValueSchema = z.union([\n\tz.string(),\n\tz.number(),\n\tz.null()\n]);\nconst databaseQuerySchema = z.strictObject({\n\tparams: z.array(sqlValueSchema).default([]),\n\tslug: z.string().min(1),\n\tsql: z.string().min(1)\n});\nconst databaseResultSchema = z.object({\n\tcolumns: z.array(z.string()),\n\trows: z.array(z.array(sqlValueSchema)),\n\trowsRead: z.number(),\n\trowsWritten: z.number()\n});\n\n//#endregion\nexport { databaseJournalSchema, databaseMigrationsSchema, databaseQuerySchema, databaseResultSchema, readDatabaseMigrations, sqlValueSchema };","import { databaseMigrationsSchema, databaseQuerySchema, databaseResultSchema } from \"./databases.mjs\";\nimport { DurableObject, WorkerEntrypoint } from \"cloudflare:workers\";\nimport { drizzle } from \"drizzle-orm/durable-sqlite\";\nimport { migrate } from \"drizzle-orm/durable-sqlite/migrator\";\n\n//#region lib/database-worker.ts\nvar AppDatabase = class extends DurableObject {\n\tasync setup(migrations) {\n\t\tawait migrate(drizzle(this.ctx.storage), databaseMigrationsSchema.parse(migrations));\n\t}\n\tasync query(sql, params = []) {\n\t\tconst cursor = this.ctx.storage.sql.exec(sql, ...params);\n\t\tconst rows = Array.from(cursor.raw());\n\t\treturn databaseResultSchema.parse({\n\t\t\tcolumns: cursor.columnNames,\n\t\t\trows,\n\t\t\trowsRead: cursor.rowsRead,\n\t\t\trowsWritten: cursor.rowsWritten\n\t\t});\n\t}\n};\nvar LocalDatabases = class extends WorkerEntrypoint {\n\tasync fetch(request) {\n\t\tconst { slug, sql, params } = databaseQuerySchema.parse(await request.json());\n\t\treturn Response.json(await this.query(slug, sql, params));\n\t}\n\tasync query(slug, sql, params = []) {\n\t\tconst database = this.ctx.props.databases[slug];\n\t\tif (!database) throw new Error(`No local database requirement for \"${slug}\"`);\n\t\treturn this.env.DATABASE_STORAGE.getByName(database.instance_name).query(sql, params);\n\t}\n};\nvar LocalDatabaseSetup = class extends WorkerEntrypoint {\n\tasync fetch() {\n\t\tfor (const database of Object.values(this.ctx.props.databases)) await this.env.DATABASE_STORAGE.getByName(database.instance_name).setup(database.migrations);\n\t\treturn new Response(null, { status: 204 });\n\t}\n};\n\n//#endregion\nexport { AppDatabase, LocalDatabaseSetup, LocalDatabases };","import { connectionRequiredSchema, toolResultSchema } from \"./tools.mjs\";\nimport { WorkerEntrypoint } from \"cloudflare:workers\";\n\n//#region lib/tools-worker.ts\nfunction readHostedExecutionResult(result) {\n\tif (!result.allowed) throw new Error(\"message\" in result ? result.message : result.reason);\n\treturn result.result;\n}\nvar Tools = class extends WorkerEntrypoint {\n\tasync call(slug, toolSlug, args) {\n\t\tconst { appId, credential } = this.ctx.props;\n\t\tconst result = await this.env.EXECUTION.callTool(appId, credential.token, {\n\t\t\targuments: args,\n\t\t\tslug,\n\t\t\ttool: toolSlug\n\t\t});\n\t\tif (!result.allowed && result.reason === \"connection-required\") return connectionRequiredResponse(result.slug);\n\t\treturn readToolResult(toolResultSchema.parse(readHostedExecutionResult(result)));\n\t}\n};\nvar LocalTools = class extends WorkerEntrypoint {\n\tasync call(slug, toolSlug, args) {\n\t\tconst { appId, connections, credential } = this.ctx.props;\n\t\tconst connection = new Map(Object.entries(connections)).get(slug);\n\t\tif (!connection) throw new Error(\"not-declared\");\n\t\tif (connection.connection_id === null) return connectionRequiredResponse(slug);\n\t\treturn executeToolRequest(new Request(new URL(`/api/connections/${encodeURIComponent(connection.connection_id)}/tools/call`, this.env.CTX_PLATFORM_URL), {\n\t\t\tbody: JSON.stringify({\n\t\t\t\tapp_id: appId,\n\t\t\t\targuments: args,\n\t\t\t\ttool: toolSlug,\n\t\t\t\ttoolkit: connection.toolkit\n\t\t\t}),\n\t\t\theaders: {\n\t\t\t\tauthorization: `Bearer ${credential.token}`,\n\t\t\t\t\"content-type\": \"application/json\"\n\t\t\t},\n\t\t\tmethod: \"POST\"\n\t\t}));\n\t}\n};\nasync function executeToolRequest(request) {\n\tconst response = await fetch(request);\n\tif (response.status === 409) return connectionRequiredResponse(connectionRequiredSchema.parse(await response.json()).slug);\n\tif (response.status === 402) throw new Error(await response.text());\n\tif (!response.ok) throw new Error(`Tool call failed: HTTP ${response.status}`);\n\treturn readToolResult(toolResultSchema.parse(await response.json()));\n}\nfunction readToolResult(result) {\n\tif (result.error !== null) throw new Error(`${result.error} (log: ${result.logId})`);\n\treturn {\n\t\tdata: result.data,\n\t\tlogId: result.logId\n\t};\n}\nfunction connectionRequiredResponse(slug) {\n\treturn Response.json({\n\t\treason: \"connection-required\",\n\t\tslug\n\t}, {\n\t\tstatus: 409,\n\t\tstatusText: \"Connection required\"\n\t});\n}\n\n//#endregion\nexport { LocalTools, Tools, readHostedExecutionResult };"],"mappings":";;;;;;AAGA,MAAM,wBAAwB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO;CAClE,aAAa,EAAE,QAAQ;CACvB,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;CAClC,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACrB,MAAM,EAAE,OAAO;AAChB,CAAC,CAAC,EAAE,CAAC;AACL,MAAM,2BAA2B,EAAE,OAAO;CACzC,SAAS;CACT,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC;AAC5C,CAAC;AAmBD,MAAM,iBAAiB,EAAE,MAAM;CAC9B,EAAE,OAAO;CACT,EAAE,OAAO;CACT,EAAE,KAAK;AACR,CAAC;AACD,MAAM,sBAAsB,EAAE,aAAa;CAC1C,QAAQ,EAAE,MAAM,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC;CAC1C,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACtB,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;AACtB,CAAC;AACD,MAAM,uBAAuB,EAAE,OAAO;CACrC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC;CAC3B,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;CACrC,UAAU,EAAE,OAAO;CACnB,aAAa,EAAE,OAAO;AACvB,CAAC;;;ACxCD,IAAI,cAAc,cAAc,cAAc;CAC7C,MAAM,MAAM,YAAY;EACvB,MAAM,QAAQ,QAAQ,KAAK,IAAI,OAAO,GAAG,yBAAyB,MAAM,UAAU,CAAC;CACpF;CACA,MAAM,MAAM,KAAK,SAAS,CAAC,GAAG;EAC7B,MAAM,SAAS,KAAK,IAAI,QAAQ,IAAI,KAAK,KAAK,GAAG,MAAM;EACvD,MAAM,OAAO,MAAM,KAAK,OAAO,IAAI,CAAC;EACpC,OAAO,qBAAqB,MAAM;GACjC,SAAS,OAAO;GAChB;GACA,UAAU,OAAO;GACjB,aAAa,OAAO;EACrB,CAAC;CACF;AACD;AACA,IAAI,iBAAiB,cAAc,iBAAiB;CACnD,MAAM,MAAM,SAAS;EACpB,MAAM,EAAE,MAAM,KAAK,WAAW,oBAAoB,MAAM,MAAM,QAAQ,KAAK,CAAC;EAC5E,OAAO,SAAS,KAAK,MAAM,KAAK,MAAM,MAAM,KAAK,MAAM,CAAC;CACzD;CACA,MAAM,MAAM,MAAM,KAAK,SAAS,CAAC,GAAG;EACnC,MAAM,WAAW,KAAK,IAAI,MAAM,UAAU;EAC1C,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,sCAAsC,KAAK,EAAE;EAC5E,OAAO,KAAK,IAAI,iBAAiB,UAAU,SAAS,aAAa,CAAC,CAAC,MAAM,KAAK,MAAM;CACrF;AACD;AACA,IAAI,qBAAqB,cAAc,iBAAiB;CACvD,MAAM,QAAQ;EACb,KAAK,MAAM,YAAY,OAAO,OAAO,KAAK,IAAI,MAAM,SAAS,GAAG,MAAM,KAAK,IAAI,iBAAiB,UAAU,SAAS,aAAa,CAAC,CAAC,MAAM,SAAS,UAAU;EAC3J,OAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;CAC1C;AACD;;;ACjBA,IAAI,aAAa,cAAc,iBAAiB;CAC/C,MAAM,KAAK,MAAM,UAAU,MAAM;EAChC,MAAM,EAAE,OAAO,aAAa,eAAe,KAAK,IAAI;EACpD,MAAM,aAAa,IAAI,IAAI,OAAO,QAAQ,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI;EAChE,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,cAAc;EAC/C,IAAI,WAAW,kBAAkB,MAAM,OAAO,2BAA2B,IAAI;EAC7E,OAAO,mBAAmB,IAAI,QAAQ,IAAI,IAAI,oBAAoB,mBAAmB,WAAW,aAAa,EAAE,cAAc,KAAK,IAAI,gBAAgB,GAAG;GACxJ,MAAM,KAAK,UAAU;IACpB,QAAQ;IACR,WAAW;IACX,MAAM;IACN,SAAS,WAAW;GACrB,CAAC;GACD,SAAS;IACR,eAAe,UAAU,WAAW;IACpC,gBAAgB;GACjB;GACA,QAAQ;EACT,CAAC,CAAC;CACH;AACD;AACA,eAAe,mBAAmB,SAAS;CAC1C,MAAM,WAAW,MAAM,MAAM,OAAO;CACpC,IAAI,SAAS,WAAW,KAAK,OAAO,2BAA2B,yBAAyB,MAAM,MAAM,SAAS,KAAK,CAAC,CAAC,CAAC,IAAI;CACzH,IAAI,SAAS,WAAW,KAAK,MAAM,IAAI,MAAM,MAAM,SAAS,KAAK,CAAC;CAClE,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,0BAA0B,SAAS,QAAQ;CAC7E,OAAO,eAAe,iBAAiB,MAAM,MAAM,SAAS,KAAK,CAAC,CAAC;AACpE;AACA,SAAS,eAAe,QAAQ;CAC/B,IAAI,OAAO,UAAU,MAAM,MAAM,IAAI,MAAM,GAAG,OAAO,MAAM,SAAS,OAAO,MAAM,EAAE;CACnF,OAAO;EACN,MAAM,OAAO;EACb,OAAO,OAAO;CACf;AACD;AACA,SAAS,2BAA2B,MAAM;CACzC,OAAO,SAAS,KAAK;EACpB,QAAQ;EACR;CACD,GAAG;EACF,QAAQ;EACR,YAAY;CACb,CAAC;AACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import "./tools-BDLYKxEr.js";
|
|
2
|
+
import { createContext } from "react-router";
|
|
3
|
+
import { drizzle } from "drizzle-orm/sqlite-proxy";
|
|
4
|
+
//#region database.ts
|
|
5
|
+
function database(databases, slug, schema) {
|
|
6
|
+
return drizzle(async (sql, params, method) => {
|
|
7
|
+
const result = await databases.query(slug, sql, params);
|
|
8
|
+
return { rows: method === "get" ? result.rows[0] : result.rows };
|
|
9
|
+
}, { schema });
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region index.ts
|
|
13
|
+
const toolsContext = createContext();
|
|
14
|
+
const databasesContext = createContext();
|
|
15
|
+
//#endregion
|
|
16
|
+
export { toolsContext as n, database as r, databasesContext as t };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=sdk-BMmzPuDi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-BMmzPuDi.js","names":[],"sources":["../database.ts","../index.ts"],"sourcesContent":["import type { Databases } from \"@usecontextlayer/shared/databases\"\nimport { drizzle } from \"drizzle-orm/sqlite-proxy\"\n\nexport function database<TSchema extends Record<string, unknown>>(\n\tdatabases: Databases,\n\tslug: string,\n\tschema: TSchema,\n) {\n\treturn drizzle(\n\t\tasync (sql, params, method) => {\n\t\t\tconst result = await databases.query(slug, sql, params)\n\t\t\t// sqlite-proxy maps undefined to a missing row despite its array-only callback type.\n\t\t\treturn { rows: method === \"get\" ? (result.rows[0] as unknown[]) : result.rows }\n\t\t},\n\t\t{ schema },\n\t)\n}\n","import type { Databases } from \"@usecontextlayer/shared/databases\"\nimport type { Tools } from \"@usecontextlayer/shared/tools\"\nimport { createContext } from \"react-router\"\n\nexport { connectionRequiredSchema, type Tools } from \"@usecontextlayer/shared/tools\"\n\nexport const toolsContext = createContext<Tools>()\n\nexport const databasesContext = createContext<Databases>()\nexport type { Databases } from \"@usecontextlayer/shared/databases\"\nexport { database } from \"@/database\"\n"],"mappings":";;;;AAGA,SAAgB,SACf,WACA,MACA,QACC;CACD,OAAO,QACN,OAAO,KAAK,QAAQ,WAAW;EAC9B,MAAM,SAAS,MAAM,UAAU,MAAM,MAAM,KAAK,MAAM;EAEtD,OAAO,EAAE,MAAM,WAAW,QAAS,OAAO,KAAK,KAAmB,OAAO,KAAK;CAC/E,GACA,EAAE,OAAO,CACV;AACD;;;ACVA,MAAa,eAAe,cAAqB;AAEjD,MAAa,mBAAmB,cAAyB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region ../shared/dist/tools.mjs
|
|
3
|
+
const connectionRequiredSchema = z.object({
|
|
4
|
+
reason: z.literal("connection-required"),
|
|
5
|
+
slug: z.string().min(1)
|
|
6
|
+
});
|
|
7
|
+
const toolResultSchema = z.object({
|
|
8
|
+
data: z.record(z.string(), z.unknown()),
|
|
9
|
+
error: z.string().nullable(),
|
|
10
|
+
logId: z.string()
|
|
11
|
+
});
|
|
12
|
+
//#endregion
|
|
13
|
+
export { toolResultSchema as n, connectionRequiredSchema as t };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=tools-BDLYKxEr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-BDLYKxEr.js","names":[],"sources":["../../shared/dist/tools.mjs"],"sourcesContent":["import { z } from \"zod\";\n\n//#region lib/tools.ts\nconst connectionRequiredSchema = z.object({\n\treason: z.literal(\"connection-required\"),\n\tslug: z.string().min(1)\n});\nconst toolResultSchema = z.object({\n\tdata: z.record(z.string(), z.unknown()),\n\terror: z.string().nullable(),\n\tlogId: z.string()\n});\n\n//#endregion\nexport { connectionRequiredSchema, toolResultSchema };"],"mappings":";;AAGA,MAAM,2BAA2B,EAAE,OAAO;CACzC,QAAQ,EAAE,QAAQ,qBAAqB;CACvC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;AACvB,CAAC;AACD,MAAM,mBAAmB,EAAE,OAAO;CACjC,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;CACtC,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;CAC3B,OAAO,EAAE,OAAO;AACjB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region ../shared/dist/databases.d.mts
|
|
3
|
+
declare const databaseMigrationsSchema: z.ZodObject<{
|
|
4
|
+
journal: z.ZodObject<{
|
|
5
|
+
entries: z.ZodArray<z.ZodObject<{
|
|
6
|
+
breakpoints: z.ZodBoolean;
|
|
7
|
+
idx: z.ZodNumber;
|
|
8
|
+
tag: z.ZodString;
|
|
9
|
+
when: z.ZodNumber;
|
|
10
|
+
}, z.core.$strip>>;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
migrations: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
13
|
+
}, z.core.$strip>;
|
|
14
|
+
type DatabaseMigrations = z.infer<typeof databaseMigrationsSchema>;
|
|
15
|
+
declare const sqlValueSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodNull]>;
|
|
16
|
+
type SqlValue = z.infer<typeof sqlValueSchema>;
|
|
17
|
+
declare const databaseResultSchema: z.ZodObject<{
|
|
18
|
+
columns: z.ZodArray<z.ZodString>;
|
|
19
|
+
rows: z.ZodArray<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodNull]>>>;
|
|
20
|
+
rowsRead: z.ZodNumber;
|
|
21
|
+
rowsWritten: z.ZodNumber;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
type DatabaseResult = z.infer<typeof databaseResultSchema>;
|
|
24
|
+
interface Databases {
|
|
25
|
+
query(slug: string, sql: string, params?: SqlValue[]): Promise<DatabaseResult>;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region ../shared/dist/tools-BLXbCgQU.d.mts
|
|
30
|
+
//#region lib/tools.d.ts
|
|
31
|
+
declare const connectionRequiredSchema: z.ZodObject<{
|
|
32
|
+
reason: z.ZodLiteral<"connection-required">;
|
|
33
|
+
slug: z.ZodString;
|
|
34
|
+
}, z.core.$strip>;
|
|
35
|
+
interface Tools {
|
|
36
|
+
call(slug: string, toolSlug: string, args: Record<string, unknown>): Promise<{
|
|
37
|
+
data: unknown;
|
|
38
|
+
logId: string;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
interface ToolsBinding {
|
|
42
|
+
call(...args: Parameters<Tools["call"]>): Promise<Awaited<ReturnType<Tools["call"]>> | Response>;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { Databases as a, DatabaseMigrations as i, ToolsBinding as n, SqlValue as o, connectionRequiredSchema as r, Tools as t };
|
|
46
|
+
//# sourceMappingURL=tools-BLXbCgQU-D3L2WEEd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-BLXbCgQU-D3L2WEEd.d.ts","names":[],"sources":["../../shared/dist/databases.d.mts","../../shared/dist/tools-BLXbCgQU.d.mts"],"mappings":";;cAUqB,0BAA0B,EAAE;EAC/C,SAAS,EAAE;IACT,SAAS,EAAE,SAAS,EAAE;MACpB,aAAa,EAAE;MACf,KAAK,EAAE;MACP,KAAK,EAAE;MACP,MAAM,EAAE;OACP,EAAE,KAAK;KACT,EAAE,KAAK;EACV,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE;GACtC,EAAE,KAAK;KACE,qBAAqB,EAAE,aAAa;cAE3B,gBAAgB,EAAE,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE;KAM1E,WAAW,EAAE,aAAa;cACjB,sBAAsB,EAAE;EAC3C,SAAS,EAAE,SAAS,EAAE;EACtB,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE;EAC7E,UAAU,EAAE;EACZ,aAAa,EAAE;GACd,EAAE,KAAK;KACE,iBAAiB,EAAE,aAAa;UAC3B;EACf,MAAM,cAAc,aAAa,SAAS,aAAa,QAAQ;;;;;;cCpCnD,0BAA0B,EAAE;EACxC,QAAQ,EAAE;EACV,MAAM,EAAE;GACP,EAAE,KAAK;UAMA;EACR,KAAK,cAAc,kBAAkB,MAAM,0BAA0B;IACnE;IACA;;;UAGM;EACR,QAAQ,MAAM,WAAW,iBAAiB,QAAQ,QAAQ,WAAW,kBAAkB"}
|
package/dist/vite.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConfigEnv } from "vite";
|
|
2
2
|
//#region vite.d.ts
|
|
3
|
-
export declare function contextlayer({ command }: ConfigEnv): Promise<import("vite").Plugin<any>[][]>;
|
|
3
|
+
export declare function contextlayer({ command }: ConfigEnv): Promise<(import("vite").Plugin<any>[] | import("vite").Plugin<any> | undefined)[]>;
|
|
4
4
|
//#endregion
|
|
5
5
|
//# sourceMappingURL=vite.d.ts.map
|
package/dist/vite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.d.ts","names":[],"sources":["../vite.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"vite.d.ts","names":[],"sources":["../vite.ts"],"mappings":";;wBAKsB,eAAe,WAAW,YAAS,wBAAA,+BAAA"}
|
package/dist/vite.js
CHANGED
|
@@ -1,22 +1,170 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
1
2
|
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
2
|
-
import {
|
|
3
|
+
import { getLocalResourcesBindings, localDatabaseSetup } from "@usecontextlayer/cli/vite";
|
|
4
|
+
import { glob, readFile } from "node:fs/promises";
|
|
5
|
+
import { dirname, join, relative } from "node:path";
|
|
6
|
+
import { RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
|
|
7
|
+
import { ResourceSchema, ToolSchema } from "@modelcontextprotocol/core";
|
|
8
|
+
import { build, createServer, createServerModuleRunner } from "vite";
|
|
9
|
+
import { viteSingleFile } from "vite-plugin-singlefile";
|
|
10
|
+
//#region ../shared/dist/slate.mjs
|
|
11
|
+
const credentialModeSchema = z.enum(["viewer", "owner"]);
|
|
12
|
+
const connectionRequirementSchema = z.strictObject({
|
|
13
|
+
mode: credentialModeSchema,
|
|
14
|
+
toolkit: z.string().min(1)
|
|
15
|
+
});
|
|
16
|
+
const secretNameSchema = z.string().regex(/^[A-Z_][A-Z0-9_]*$/);
|
|
17
|
+
const secretRequirementSchema = z.strictObject({ mode: credentialModeSchema });
|
|
18
|
+
const databaseRequirementSchema = z.strictObject({ mode: credentialModeSchema });
|
|
19
|
+
const databaseNameSchema = z.string().min(1).regex(/^(?!\.{1,2}$)[^/\\]+$/);
|
|
20
|
+
const slateSchema = z.strictObject({
|
|
21
|
+
connections: z.record(z.string().min(1), connectionRequirementSchema),
|
|
22
|
+
databases: z.record(databaseNameSchema, databaseRequirementSchema).default({}),
|
|
23
|
+
secrets: z.record(secretNameSchema, secretRequirementSchema).default({})
|
|
24
|
+
});
|
|
25
|
+
z.strictObject({
|
|
26
|
+
agents: z.record(z.string().min(1), slateSchema),
|
|
27
|
+
app: slateSchema
|
|
28
|
+
});
|
|
29
|
+
const resourceConsumerSchema = z.discriminatedUnion("type", [z.strictObject({ type: z.literal("app") }), z.strictObject({
|
|
30
|
+
name: z.string().min(1),
|
|
31
|
+
type: z.literal("agent")
|
|
32
|
+
})]);
|
|
33
|
+
slateSchema.extend({
|
|
34
|
+
connections: z.record(z.string().min(1), connectionRequirementSchema.extend({ consumers: z.array(resourceConsumerSchema) })),
|
|
35
|
+
databases: z.record(databaseNameSchema, databaseRequirementSchema.extend({ consumers: z.array(resourceConsumerSchema) })),
|
|
36
|
+
secrets: z.record(secretNameSchema, secretRequirementSchema.extend({ consumers: z.array(resourceConsumerSchema) }))
|
|
37
|
+
});
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region ../shared/dist/mcp.mjs
|
|
40
|
+
const MCP_MANIFEST_PATH = "/mcp.json";
|
|
41
|
+
const mcpManifestSchema = z.object({
|
|
42
|
+
resources: z.array(ResourceSchema.extend({ path: z.string() })),
|
|
43
|
+
tools: z.array(ToolSchema.extend({ slate: slateSchema }))
|
|
44
|
+
});
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region mcp-vite.ts
|
|
47
|
+
function mcpApps() {
|
|
48
|
+
let root;
|
|
49
|
+
let compiled;
|
|
50
|
+
async function compile() {
|
|
51
|
+
const server = await createServer({
|
|
52
|
+
appType: "custom",
|
|
53
|
+
configFile: false,
|
|
54
|
+
resolve: { tsconfigPaths: true },
|
|
55
|
+
root,
|
|
56
|
+
server: { middlewareMode: true }
|
|
57
|
+
});
|
|
58
|
+
const runner = createServerModuleRunner(server.environments.ssr);
|
|
59
|
+
try {
|
|
60
|
+
const tools = [];
|
|
61
|
+
for await (const file of glob("mcp/*/index.ts", { cwd: root })) {
|
|
62
|
+
const { tool } = await runner.import(join(root, file));
|
|
63
|
+
const slate = slateSchema.parse(JSON.parse(await readFile(join(root, dirname(file), "slate.json"), "utf8")));
|
|
64
|
+
if (Object.keys(slate.connections).length || Object.keys(slate.databases).length || Object.keys(slate.secrets).length) throw new Error(`${file}: MCP resource consumers are not implemented yet`);
|
|
65
|
+
tools.push({
|
|
66
|
+
...tool,
|
|
67
|
+
inputSchema: z.toJSONSchema(tool.inputSchema),
|
|
68
|
+
outputSchema: tool.outputSchema ? z.toJSONSchema(tool.outputSchema) : void 0,
|
|
69
|
+
slate
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const assets = [];
|
|
73
|
+
const resources = [];
|
|
74
|
+
for await (const file of glob("mcp-ui/*/index.html", { cwd: root })) {
|
|
75
|
+
const name = relative("mcp-ui", dirname(file));
|
|
76
|
+
const result = await build({
|
|
77
|
+
build: {
|
|
78
|
+
rolldownOptions: { input: join(root, file) },
|
|
79
|
+
write: false
|
|
80
|
+
},
|
|
81
|
+
configFile: false,
|
|
82
|
+
plugins: [viteSingleFile()],
|
|
83
|
+
publicDir: false,
|
|
84
|
+
resolve: { tsconfigPaths: true },
|
|
85
|
+
root
|
|
86
|
+
});
|
|
87
|
+
if (Array.isArray(result) || !("output" in result)) throw new Error("MCP View build must produce one bundle");
|
|
88
|
+
const html = result.output.find((asset) => asset.type === "asset" && asset.fileName.endsWith(".html"));
|
|
89
|
+
if (html?.type !== "asset") throw new Error(`${file}: missing built HTML`);
|
|
90
|
+
const path = `/mcp-ui/${name}`;
|
|
91
|
+
assets.push({
|
|
92
|
+
fileName: `${path.slice(1)}.html`,
|
|
93
|
+
source: html.source,
|
|
94
|
+
type: "asset"
|
|
95
|
+
});
|
|
96
|
+
resources.push({
|
|
97
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
98
|
+
name,
|
|
99
|
+
path,
|
|
100
|
+
uri: `ui://${name}/index.html`
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const manifest = mcpManifestSchema.parse({
|
|
104
|
+
resources,
|
|
105
|
+
tools
|
|
106
|
+
});
|
|
107
|
+
assets.push({
|
|
108
|
+
fileName: MCP_MANIFEST_PATH.slice(1),
|
|
109
|
+
source: JSON.stringify(manifest),
|
|
110
|
+
type: "asset"
|
|
111
|
+
});
|
|
112
|
+
return assets;
|
|
113
|
+
} finally {
|
|
114
|
+
await runner.close();
|
|
115
|
+
await server.close();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
configResolved(config) {
|
|
120
|
+
root = config.root;
|
|
121
|
+
},
|
|
122
|
+
async generateBundle() {
|
|
123
|
+
if (this.environment.config.consumer !== "client") return;
|
|
124
|
+
compiled ??= compile();
|
|
125
|
+
for (const asset of await compiled) this.emitFile(asset);
|
|
126
|
+
},
|
|
127
|
+
name: "contextlayer-mcp-apps"
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
3
131
|
//#region vite.ts
|
|
4
132
|
async function contextlayer({ command }) {
|
|
5
|
-
const bindings = command === "serve" ? await
|
|
6
|
-
return [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
133
|
+
const bindings = command === "serve" ? await getLocalResourcesBindings() : void 0;
|
|
134
|
+
return [
|
|
135
|
+
mcpApps(),
|
|
136
|
+
cloudflare({
|
|
137
|
+
auxiliaryWorkers: [{
|
|
138
|
+
config: bindings ? {
|
|
139
|
+
name: bindings.workerName,
|
|
140
|
+
vars: bindings.vars
|
|
141
|
+
} : {},
|
|
142
|
+
configPath: "workers/local-resources/wrangler.jsonc",
|
|
143
|
+
devOnly: true
|
|
144
|
+
}],
|
|
145
|
+
config: {
|
|
146
|
+
assets: { run_worker_first: [
|
|
147
|
+
"/*",
|
|
148
|
+
"!/mcp.json",
|
|
149
|
+
"!/mcp-ui/*"
|
|
150
|
+
] },
|
|
151
|
+
...bindings ? { services: [...bindings.props ? [{
|
|
152
|
+
binding: "TOOLS",
|
|
153
|
+
entrypoint: "Tools",
|
|
154
|
+
props: bindings.props,
|
|
155
|
+
service: bindings.workerName
|
|
156
|
+
}] : [], {
|
|
157
|
+
binding: "DATABASES",
|
|
158
|
+
entrypoint: "Databases",
|
|
159
|
+
props: bindings.databaseProps,
|
|
160
|
+
service: bindings.workerName
|
|
161
|
+
}] } : {}
|
|
162
|
+
},
|
|
163
|
+
persistState: { path: ".contextlayer/databases" },
|
|
164
|
+
viteEnvironment: { name: "ssr" }
|
|
165
|
+
}),
|
|
166
|
+
bindings ? localDatabaseSetup(bindings) : void 0
|
|
167
|
+
];
|
|
20
168
|
}
|
|
21
169
|
//#endregion
|
|
22
170
|
export { contextlayer };
|
package/dist/vite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.js","names":[],"sources":["../vite.ts"],"sourcesContent":["import { cloudflare } from \"@cloudflare/vite-plugin\"\nimport { getLocalToolsBindings } from \"@usecontextlayer/cli/vite\"\nimport type { ConfigEnv } from \"vite\"\n\nexport async function contextlayer({ command }: ConfigEnv) {\n\tconst bindings = command === \"serve\" ? await getLocalToolsBindings() : undefined\n\treturn [\n\t\tcloudflare({\n\t\t\tauxiliaryWorkers: [\n\t\t\t\t{\n\t\t\t\t\tconfig: bindings ? { vars: bindings.vars } : {},\n\t\t\t\t\tconfigPath: \"workers/local-tools/wrangler.jsonc\",\n\t\t\t\t\tdevOnly: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\tconfig: bindings\n\t\t\t\t? {\n\t\t\t\t\t\tservices: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbinding: \"TOOLS\",\n\t\t\t\t\t\t\t\tentrypoint: \"Tools\",\n\t\t\t\t\t\t\t\tprops: bindings.props,\n\t\t\t\t\t\t\t\tservice: \"ctx-local-tools\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t}\n\t\t\t\t: {},\n\t\t\tviteEnvironment: { name: \"ssr\" },\n\t\t}),\n\t]\n}\n"],"mappings":";;;AAIA,eAAsB,aAAa,EAAE,WAAsB;CAC1D,MAAM,WAAW,YAAY,UAAU,MAAM,sBAAsB,IAAI,KAAA;CACvE,OAAO,CACN,WAAW;EACV,kBAAkB,CACjB;GACC,QAAQ,WAAW,EAAE,MAAM,SAAS,KAAK,IAAI,CAAC;GAC9C,YAAY;GACZ,SAAS;EACV,CACD;EACA,QAAQ,WACL,EACA,UAAU,CACT;GACC,SAAS;GACT,YAAY;GACZ,OAAO,SAAS;GAChB,SAAS;EACV,CACD,EACD,IACC,CAAC;EACJ,iBAAiB,EAAE,MAAM,MAAM;CAChC,CAAC,CACF;AACD"}
|
|
1
|
+
{"version":3,"file":"vite.js","names":[],"sources":["../../shared/dist/slate.mjs","../../shared/dist/mcp.mjs","../mcp-vite.ts","../vite.ts"],"sourcesContent":["import { z } from \"zod\";\n\n//#region lib/slate.ts\nconst credentialModeSchema = z.enum([\"viewer\", \"owner\"]);\nconst connectionRequirementSchema = z.strictObject({\n\tmode: credentialModeSchema,\n\ttoolkit: z.string().min(1)\n});\nconst secretNameSchema = z.string().regex(/^[A-Z_][A-Z0-9_]*$/);\nconst secretRequirementSchema = z.strictObject({ mode: credentialModeSchema });\nconst databaseRequirementSchema = z.strictObject({ mode: credentialModeSchema });\nconst databaseNameSchema = z.string().min(1).regex(/^(?!\\.{1,2}$)[^/\\\\]+$/);\nconst slateSchema = z.strictObject({\n\tconnections: z.record(z.string().min(1), connectionRequirementSchema),\n\tdatabases: z.record(databaseNameSchema, databaseRequirementSchema).default({}),\n\tsecrets: z.record(secretNameSchema, secretRequirementSchema).default({})\n});\nconst appSlatesSchema = z.strictObject({\n\tagents: z.record(z.string().min(1), slateSchema),\n\tapp: slateSchema\n});\nconst resourceConsumerSchema = z.discriminatedUnion(\"type\", [z.strictObject({ type: z.literal(\"app\") }), z.strictObject({\n\tname: z.string().min(1),\n\ttype: z.literal(\"agent\")\n})]);\nconst resourcesSchema = slateSchema.extend({\n\tconnections: z.record(z.string().min(1), connectionRequirementSchema.extend({ consumers: z.array(resourceConsumerSchema) })),\n\tdatabases: z.record(databaseNameSchema, databaseRequirementSchema.extend({ consumers: z.array(resourceConsumerSchema) })),\n\tsecrets: z.record(secretNameSchema, secretRequirementSchema.extend({ consumers: z.array(resourceConsumerSchema) }))\n});\nfunction hasViewerResources(resources) {\n\treturn Object.values(resources).some((requirements) => Object.values(requirements).some(({ mode }) => mode === \"viewer\"));\n}\nfunction collectAppResources(slates) {\n\tconst declarations = [{\n\t\tconsumer: { type: \"app\" },\n\t\tslate: slates.app\n\t}, ...Object.entries(slates.agents).map(([name, slate]) => ({\n\t\tconsumer: {\n\t\t\tname,\n\t\t\ttype: \"agent\"\n\t\t},\n\t\tslate\n\t}))];\n\treturn {\n\t\tconnections: collectRequirements(\"connections\", declarations, (slate) => slate.connections),\n\t\tdatabases: collectRequirements(\"databases\", declarations, (slate) => slate.databases),\n\t\tsecrets: collectRequirements(\"secrets\", declarations, (slate) => slate.secrets)\n\t};\n}\nfunction resourcesForConsumer(resources, consumer) {\n\treturn {\n\t\tconnections: filterRequirements(resources.connections, consumer),\n\t\tdatabases: filterRequirements(resources.databases, consumer),\n\t\tsecrets: filterRequirements(resources.secrets, consumer)\n\t};\n}\nfunction filterRequirements(requirements, consumer) {\n\treturn Object.fromEntries(Object.entries(requirements).filter(([, requirement]) => requirement.consumers.some((declared) => declared.type === consumer.type && (consumer.type === \"app\" || declared.type === \"agent\" && declared.name === consumer.name))));\n}\nfunction collectRequirements(category, declarations, select) {\n\tconst resources = /* @__PURE__ */ new Map();\n\tfor (const { consumer, slate } of declarations) for (const [name, requirement] of Object.entries(select(slate))) {\n\t\tconst existing = resources.get(name);\n\t\tif (!existing) {\n\t\t\tresources.set(name, {\n\t\t\t\t...requirement,\n\t\t\t\tconsumers: [consumer]\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (existing.mode !== requirement.mode || existing.toolkit !== requirement.toolkit) throw new z.ZodError([{\n\t\t\tcode: \"custom\",\n\t\t\tmessage: `Conflicting ${category} requirement \"${name}\": declarations must agree on mode${category === \"connections\" ? \" and toolkit\" : \"\"}`,\n\t\t\tpath: [\n\t\t\t\t...consumer.type === \"app\" ? [\"app\"] : [\"agents\", consumer.name],\n\t\t\t\tcategory,\n\t\t\t\tname\n\t\t\t]\n\t\t}]);\n\t\texisting.consumers.push(consumer);\n\t}\n\treturn Object.fromEntries(resources);\n}\n\n//#endregion\nexport { appSlatesSchema, collectAppResources, connectionRequirementSchema, credentialModeSchema, databaseNameSchema, databaseRequirementSchema, hasViewerResources, resourceConsumerSchema, resourcesForConsumer, resourcesSchema, secretNameSchema, secretRequirementSchema, slateSchema };","import { slateSchema } from \"./slate.mjs\";\nimport { z } from \"zod\";\nimport { ResourceSchema, ToolSchema } from \"@modelcontextprotocol/core\";\n\n//#region lib/mcp.ts\nconst MCP_MANIFEST_PATH = \"/mcp.json\";\nconst mcpManifestSchema = z.object({\n\tresources: z.array(ResourceSchema.extend({ path: z.string() })),\n\ttools: z.array(ToolSchema.extend({ slate: slateSchema }))\n});\n\n//#endregion\nexport { MCP_MANIFEST_PATH, mcpManifestSchema };","import { glob, readFile } from \"node:fs/promises\"\nimport { dirname, join, relative } from \"node:path\"\nimport { RESOURCE_MIME_TYPE } from \"@modelcontextprotocol/ext-apps/server\"\nimport { MCP_MANIFEST_PATH, mcpManifestSchema } from \"@usecontextlayer/shared/mcp\"\nimport { slateSchema } from \"@usecontextlayer/shared/slate\"\nimport { build, createServer, createServerModuleRunner, type Plugin } from \"vite\"\nimport { viteSingleFile } from \"vite-plugin-singlefile\"\nimport { z } from \"zod\"\nimport type { McpToolModule } from \"@/worker\"\n\nexport function mcpApps(): Plugin {\n\tlet root: string\n\tlet compiled: ReturnType<typeof compile>\n\n\tasync function compile() {\n\t\tconst server = await createServer({\n\t\t\tappType: \"custom\",\n\t\t\tconfigFile: false,\n\t\t\tresolve: { tsconfigPaths: true },\n\t\t\troot,\n\t\t\tserver: { middlewareMode: true },\n\t\t})\n\t\tconst runner = createServerModuleRunner(server.environments.ssr)\n\t\ttry {\n\t\t\tconst tools = []\n\t\t\tfor await (const file of glob(\"mcp/*/index.ts\", { cwd: root })) {\n\t\t\t\tconst { tool } = await runner.import<McpToolModule>(join(root, file))\n\t\t\t\tconst slate = slateSchema.parse(\n\t\t\t\t\tJSON.parse(await readFile(join(root, dirname(file), \"slate.json\"), \"utf8\")),\n\t\t\t\t)\n\t\t\t\tif (\n\t\t\t\t\tObject.keys(slate.connections).length ||\n\t\t\t\t\tObject.keys(slate.databases).length ||\n\t\t\t\t\tObject.keys(slate.secrets).length\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(`${file}: MCP resource consumers are not implemented yet`)\n\t\t\t\t}\n\t\t\t\ttools.push({\n\t\t\t\t\t...tool,\n\t\t\t\t\tinputSchema: z.toJSONSchema(tool.inputSchema),\n\t\t\t\t\toutputSchema: tool.outputSchema ? z.toJSONSchema(tool.outputSchema) : undefined,\n\t\t\t\t\tslate,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst assets = []\n\t\t\tconst resources = []\n\t\t\tfor await (const file of glob(\"mcp-ui/*/index.html\", { cwd: root })) {\n\t\t\t\tconst name = relative(\"mcp-ui\", dirname(file))\n\t\t\t\tconst result = await build({\n\t\t\t\t\tbuild: { rolldownOptions: { input: join(root, file) }, write: false },\n\t\t\t\t\tconfigFile: false,\n\t\t\t\t\tplugins: [viteSingleFile()],\n\t\t\t\t\tpublicDir: false,\n\t\t\t\t\tresolve: { tsconfigPaths: true },\n\t\t\t\t\troot,\n\t\t\t\t})\n\t\t\t\tif (Array.isArray(result) || !(\"output\" in result)) {\n\t\t\t\t\tthrow new Error(\"MCP View build must produce one bundle\")\n\t\t\t\t}\n\t\t\t\tconst html = result.output.find(\n\t\t\t\t\t(asset) => asset.type === \"asset\" && asset.fileName.endsWith(\".html\"),\n\t\t\t\t)\n\t\t\t\tif (html?.type !== \"asset\") throw new Error(`${file}: missing built HTML`)\n\t\t\t\tconst path = `/mcp-ui/${name}`\n\t\t\t\tassets.push({\n\t\t\t\t\tfileName: `${path.slice(1)}.html`,\n\t\t\t\t\tsource: html.source,\n\t\t\t\t\ttype: \"asset\" as const,\n\t\t\t\t})\n\t\t\t\tresources.push({\n\t\t\t\t\tmimeType: RESOURCE_MIME_TYPE,\n\t\t\t\t\tname,\n\t\t\t\t\tpath,\n\t\t\t\t\turi: `ui://${name}/index.html`,\n\t\t\t\t})\n\t\t\t}\n\t\t\tconst manifest = mcpManifestSchema.parse({ resources, tools })\n\t\t\tassets.push({\n\t\t\t\tfileName: MCP_MANIFEST_PATH.slice(1),\n\t\t\t\tsource: JSON.stringify(manifest),\n\t\t\t\ttype: \"asset\" as const,\n\t\t\t})\n\t\t\treturn assets\n\t\t} finally {\n\t\t\tawait runner.close()\n\t\t\tawait server.close()\n\t\t}\n\t}\n\n\treturn {\n\t\tconfigResolved(config) {\n\t\t\troot = config.root\n\t\t},\n\t\tasync generateBundle() {\n\t\t\tif (this.environment.config.consumer !== \"client\") return\n\t\t\tcompiled ??= compile()\n\t\t\tfor (const asset of await compiled) this.emitFile(asset)\n\t\t},\n\t\tname: \"contextlayer-mcp-apps\",\n\t}\n}\n","import { cloudflare } from \"@cloudflare/vite-plugin\"\nimport { getLocalResourcesBindings, localDatabaseSetup } from \"@usecontextlayer/cli/vite\"\nimport type { ConfigEnv } from \"vite\"\nimport { mcpApps } from \"@/mcp-vite\"\n\nexport async function contextlayer({ command }: ConfigEnv) {\n\tconst bindings = command === \"serve\" ? await getLocalResourcesBindings() : undefined\n\treturn [\n\t\tmcpApps(),\n\t\tcloudflare({\n\t\t\tauxiliaryWorkers: [\n\t\t\t\t{\n\t\t\t\t\tconfig: bindings ? { name: bindings.workerName, vars: bindings.vars } : {},\n\t\t\t\t\tconfigPath: \"workers/local-resources/wrangler.jsonc\",\n\t\t\t\t\tdevOnly: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\tconfig: {\n\t\t\t\tassets: { run_worker_first: [\"/*\", \"!/mcp.json\", \"!/mcp-ui/*\"] },\n\t\t\t\t...(bindings\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tservices: [\n\t\t\t\t\t\t\t\t...(bindings.props\n\t\t\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tbinding: \"TOOLS\",\n\t\t\t\t\t\t\t\t\t\t\t\tentrypoint: \"Tools\",\n\t\t\t\t\t\t\t\t\t\t\t\tprops: bindings.props,\n\t\t\t\t\t\t\t\t\t\t\t\tservice: bindings.workerName,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tbinding: \"DATABASES\",\n\t\t\t\t\t\t\t\t\tentrypoint: \"Databases\",\n\t\t\t\t\t\t\t\t\tprops: bindings.databaseProps,\n\t\t\t\t\t\t\t\t\tservice: bindings.workerName,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t},\n\t\t\tpersistState: { path: \".contextlayer/databases\" },\n\t\t\tviteEnvironment: { name: \"ssr\" },\n\t\t}),\n\t\tbindings ? localDatabaseSetup(bindings) : undefined,\n\t]\n}\n"],"mappings":"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"}
|
package/dist/worker.d.ts
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
|
-
import { Tools } from "./
|
|
1
|
+
import { a as Databases, n as ToolsBinding, t as Tools } from "./tools-BLXbCgQU-D3L2WEEd.js";
|
|
2
|
+
import "./index-Dle7CHzb.js";
|
|
2
3
|
import { createRequestHandler } from "react-router";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { ToolConfig } from "@modelcontextprotocol/ext-apps/server";
|
|
6
|
+
import { CallToolResult } from "@modelcontextprotocol/server";
|
|
3
7
|
//#region worker.d.ts
|
|
4
8
|
interface LocalBindings {
|
|
5
|
-
|
|
9
|
+
DATABASES: Databases;
|
|
10
|
+
TOOLS: ToolsBinding;
|
|
6
11
|
}
|
|
7
12
|
interface AppProps {
|
|
8
|
-
|
|
13
|
+
databases: Databases;
|
|
14
|
+
tools: ToolsBinding;
|
|
15
|
+
mcpTool?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface McpToolModule {
|
|
18
|
+
tool: Omit<ToolConfig, "inputSchema" | "outputSchema"> & {
|
|
19
|
+
name: string;
|
|
20
|
+
inputSchema: z.ZodType;
|
|
21
|
+
outputSchema?: z.ZodType;
|
|
22
|
+
};
|
|
23
|
+
handler(args: unknown, tools: Tools): CallToolResult | Promise<CallToolResult>;
|
|
9
24
|
}
|
|
10
25
|
export type App = Required<Pick<ExportedHandler<LocalBindings, unknown, unknown, AppProps>, "fetch">>;
|
|
11
|
-
export declare function createApp({ build, mode, development }: {
|
|
26
|
+
export declare function createApp({ build, mode, development, mcp }: {
|
|
12
27
|
build: Parameters<typeof createRequestHandler>[0];
|
|
13
28
|
mode: string;
|
|
14
29
|
development: boolean;
|
|
30
|
+
mcp?: Record<string, McpToolModule>;
|
|
15
31
|
}): App;
|
|
16
32
|
//#endregion
|
|
17
33
|
//# sourceMappingURL=worker.d.ts.map
|
package/dist/worker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","names":[],"sources":["../worker.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"worker.d.ts","names":[],"sources":["../worker.ts"],"mappings":";;;;;;;UAOU;EACT,WAAW;EACX,OAAO;;UAGE;EACT,WAAW;EACX,OAAO;EACP;;iBAGgB;EAChB,MAAM,KAAK;IACV;IACA,aAAa,EAAE;IACf,eAAe,EAAE;;EAElB,QAAQ,eAAe,OAAO,QAAQ,iBAAiB,QAAQ;;YAGpD,MAAM,SACjB,KAAK,gBAAgB,iCAAiC;wBAGvC,YACf,OACA,MACA,aACA;EAEA,OAAO,kBAAkB;EACzB;EACA;EACA,MAAM,eAAe;IAClB"}
|
package/dist/worker.js
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
|
-
import { toolsContext } from "./
|
|
1
|
+
import { n as toolsContext, t as databasesContext } from "./sdk-BMmzPuDi.js";
|
|
2
2
|
import { RouterContextProvider, createRequestHandler } from "react-router";
|
|
3
3
|
//#region worker.ts
|
|
4
|
-
function createApp({ build, mode, development }) {
|
|
4
|
+
function createApp({ build, mode, development, mcp = {} }) {
|
|
5
5
|
const requestHandler = createRequestHandler(build, mode);
|
|
6
6
|
return { async fetch(request, env, ctx) {
|
|
7
|
+
if (ctx.props.mcpTool) {
|
|
8
|
+
const module = Object.values(mcp).find(({ tool }) => tool.name === ctx.props.mcpTool);
|
|
9
|
+
if (!module) throw new Error(`Unknown MCP tool: ${ctx.props.mcpTool}`);
|
|
10
|
+
const args = await module.tool.inputSchema.parseAsync(await request.json());
|
|
11
|
+
return Response.json(await module.handler(args, createTools(ctx.props.tools)));
|
|
12
|
+
}
|
|
7
13
|
const context = new RouterContextProvider();
|
|
8
|
-
context.set(
|
|
14
|
+
context.set(databasesContext, development ? env.DATABASES : ctx.props.databases);
|
|
15
|
+
context.set(toolsContext, createTools(development ? env.TOOLS : ctx.props.tools));
|
|
9
16
|
return requestHandler(request, context);
|
|
10
17
|
} };
|
|
11
18
|
}
|
|
19
|
+
function createTools(binding) {
|
|
20
|
+
return { async call(...args) {
|
|
21
|
+
const result = await binding.call(...args);
|
|
22
|
+
if (result instanceof Response) throw result;
|
|
23
|
+
return result;
|
|
24
|
+
} };
|
|
25
|
+
}
|
|
12
26
|
//#endregion
|
|
13
27
|
export { createApp };
|
|
14
28
|
|
package/dist/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","names":[],"sources":["../worker.ts"],"sourcesContent":["import { createRequestHandler, RouterContextProvider } from \"react-router\"\nimport { type Tools, toolsContext } from \"@/index\"\n\ninterface LocalBindings {\n\tTOOLS:
|
|
1
|
+
{"version":3,"file":"worker.js","names":[],"sources":["../worker.ts"],"sourcesContent":["import type { ToolConfig } from \"@modelcontextprotocol/ext-apps/server\"\nimport type { CallToolResult } from \"@modelcontextprotocol/server\"\nimport type { ToolsBinding } from \"@usecontextlayer/shared/tools\"\nimport { createRequestHandler, RouterContextProvider } from \"react-router\"\nimport type { z } from \"zod\"\nimport { type Databases, databasesContext, type Tools, toolsContext } from \"@/index\"\n\ninterface LocalBindings {\n\tDATABASES: Databases\n\tTOOLS: ToolsBinding\n}\n\ninterface AppProps {\n\tdatabases: Databases\n\ttools: ToolsBinding\n\tmcpTool?: string\n}\n\nexport interface McpToolModule {\n\ttool: Omit<ToolConfig, \"inputSchema\" | \"outputSchema\"> & {\n\t\tname: string\n\t\tinputSchema: z.ZodType\n\t\toutputSchema?: z.ZodType\n\t}\n\thandler(args: unknown, tools: Tools): CallToolResult | Promise<CallToolResult>\n}\n\nexport type App = Required<\n\tPick<ExportedHandler<LocalBindings, unknown, unknown, AppProps>, \"fetch\">\n>\n\nexport function createApp({\n\tbuild,\n\tmode,\n\tdevelopment,\n\tmcp = {},\n}: {\n\tbuild: Parameters<typeof createRequestHandler>[0]\n\tmode: string\n\tdevelopment: boolean\n\tmcp?: Record<string, McpToolModule>\n}): App {\n\tconst requestHandler = createRequestHandler(build, mode)\n\treturn {\n\t\tasync fetch(request, env, ctx) {\n\t\t\tif (ctx.props.mcpTool) {\n\t\t\t\tconst module = Object.values(mcp).find(\n\t\t\t\t\t({ tool }) => tool.name === ctx.props.mcpTool,\n\t\t\t\t)\n\t\t\t\tif (!module) throw new Error(`Unknown MCP tool: ${ctx.props.mcpTool}`)\n\t\t\t\tconst args = await module.tool.inputSchema.parseAsync(await request.json())\n\t\t\t\treturn Response.json(await module.handler(args, createTools(ctx.props.tools)))\n\t\t\t}\n\t\t\tconst context = new RouterContextProvider()\n\t\t\tcontext.set(databasesContext, development ? env.DATABASES : ctx.props.databases)\n\t\t\tcontext.set(toolsContext, createTools(development ? env.TOOLS : ctx.props.tools))\n\t\t\treturn requestHandler(request, context)\n\t\t},\n\t}\n}\n\nfunction createTools(binding: ToolsBinding): Tools {\n\treturn {\n\t\tasync call(...args) {\n\t\t\tconst result = await binding.call(...args)\n\t\t\tif (result instanceof Response) throw result\n\t\t\treturn result\n\t\t},\n\t}\n}\n"],"mappings":";;;AA+BA,SAAgB,UAAU,EACzB,OACA,MACA,aACA,MAAM,CAAC,KAMA;CACP,MAAM,iBAAiB,qBAAqB,OAAO,IAAI;CACvD,OAAO,EACN,MAAM,MAAM,SAAS,KAAK,KAAK;EAC9B,IAAI,IAAI,MAAM,SAAS;GACtB,MAAM,SAAS,OAAO,OAAO,GAAG,CAAC,CAAC,MAChC,EAAE,WAAW,KAAK,SAAS,IAAI,MAAM,OACvC;GACA,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,qBAAqB,IAAI,MAAM,SAAS;GACrE,MAAM,OAAO,MAAM,OAAO,KAAK,YAAY,WAAW,MAAM,QAAQ,KAAK,CAAC;GAC1E,OAAO,SAAS,KAAK,MAAM,OAAO,QAAQ,MAAM,YAAY,IAAI,MAAM,KAAK,CAAC,CAAC;EAC9E;EACA,MAAM,UAAU,IAAI,sBAAsB;EAC1C,QAAQ,IAAI,kBAAkB,cAAc,IAAI,YAAY,IAAI,MAAM,SAAS;EAC/E,QAAQ,IAAI,cAAc,YAAY,cAAc,IAAI,QAAQ,IAAI,MAAM,KAAK,CAAC;EAChF,OAAO,eAAe,SAAS,OAAO;CACvC,EACD;AACD;AAEA,SAAS,YAAY,SAA8B;CAClD,OAAO,EACN,MAAM,KAAK,GAAG,MAAM;EACnB,MAAM,SAAS,MAAM,QAAQ,KAAK,GAAG,IAAI;EACzC,IAAI,kBAAkB,UAAU,MAAM;EACtC,OAAO;CACR,EACD;AACD"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// This example's public/slate.json declares the connection; follow the SDK README to copy the app files and assign a Gmail account.
|
|
1
2
|
import { toolsContext } from "@usecontextlayer/sdk"
|
|
2
3
|
import { type LoaderFunctionArgs, useLoaderData } from "react-router"
|
|
3
4
|
import { z } from "zod"
|
package/package.json
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"
|
|
4
|
-
"@
|
|
3
|
+
"@modelcontextprotocol/client": "2.3.1",
|
|
4
|
+
"@modelcontextprotocol/core": "2.3.1",
|
|
5
|
+
"@modelcontextprotocol/ext-apps": "2.0.3",
|
|
6
|
+
"@modelcontextprotocol/server": "2.3.1",
|
|
7
|
+
"drizzle-orm": "0.45.3",
|
|
8
|
+
"vite-plugin-singlefile": "2.3.3",
|
|
9
|
+
"zod": "^4.6.5",
|
|
10
|
+
"@usecontextlayer/cli": "0.15.0"
|
|
5
11
|
},
|
|
6
12
|
"devDependencies": {
|
|
7
13
|
"@cloudflare/vite-plugin": "^1.62.4",
|
|
@@ -15,7 +21,8 @@
|
|
|
15
21
|
"tsdown": "latest",
|
|
16
22
|
"typescript": "latest",
|
|
17
23
|
"vite": "^8.3.2",
|
|
18
|
-
"
|
|
24
|
+
"vitest": "^4.1.11",
|
|
25
|
+
"@usecontextlayer/shared": "0.15.0"
|
|
19
26
|
},
|
|
20
27
|
"exports": {
|
|
21
28
|
".": {
|
|
@@ -52,10 +59,11 @@
|
|
|
52
59
|
"vite": "^8.3.2"
|
|
53
60
|
},
|
|
54
61
|
"type": "module",
|
|
55
|
-
"version": "0.
|
|
62
|
+
"version": "0.15.0",
|
|
56
63
|
"scripts": {
|
|
57
64
|
"build": "tsdown",
|
|
58
65
|
"dev:watch": "tsdown --watch",
|
|
66
|
+
"test": "vitest run --config vitest.config.ts",
|
|
59
67
|
"tsc": "tsc -b tsconfig.json"
|
|
60
68
|
}
|
|
61
69
|
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../index.ts"],"mappings":";iBAEiB;EAChB,KACC,cACA,kBACA,MAAM,0BACJ;IAAU;IAAe;;;qBAGhB,qCAAY,cAAA"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../index.ts"],"sourcesContent":["import { createContext } from \"react-router\"\n\nexport interface Tools {\n\tcall(\n\t\tslug: string,\n\t\ttoolSlug: string,\n\t\targs: Record<string, unknown>,\n\t): Promise<{ data: unknown; logId: string }>\n}\n\nexport const toolsContext = createContext<Tools>()\n"],"mappings":";;AAUA,MAAa,eAAe,cAAqB"}
|