@usecontextlayer/sdk 0.12.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/README.md +57 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/local.d.ts +20 -0
- package/dist/local.d.ts.map +1 -0
- package/dist/local.js +44 -0
- package/dist/local.js.map +1 -0
- package/dist/vite.d.ts +5 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +22 -0
- package/dist/vite.js.map +1 -0
- package/dist/worker.d.ts +16 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +15 -0
- package/dist/worker.js.map +1 -0
- package/examples/gmail.tsx +55 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @usecontextlayer/sdk
|
|
2
|
+
|
|
3
|
+
Tools for ContextLayer React Router apps. In local development, calls execute through the ContextLayer platform using your assigned Composio Platform connections.
|
|
4
|
+
|
|
5
|
+
Create an app with `npx @usecontextlayer/cli init my-app`. The CLI installs this package and configures a development-only Cloudflare Worker and native service binding. Use the generated app's normal `pnpm dev` command. First-party `@usecontextlayer/*` packages are exempt from pnpm's release-age policy in generated projects.
|
|
6
|
+
|
|
7
|
+
## Local login and assignment
|
|
8
|
+
|
|
9
|
+
Run `ctx login` to save your ContextLayer login. Declare `work-email` as an individual Gmail requirement in `public/slate.json`, then use `ctx connections list` to find your connection and `ctx connection local assign work-email <connection_id>` to assign it. Run local commands from the app root.
|
|
10
|
+
|
|
11
|
+
When `pnpm dev` starts, `contextlayer(env)` from `@usecontextlayer/sdk/vite` configures the Cloudflare Vite plugin and calls the CLI-owned `getLocalToolsBindings` helper. This Node helper reads the AppID from Git origin and obtains a current access token using the same saved login as the CLI. Only the AppID, platform URL, and access token enter the local Tools Worker. The refresh token stays in `~/.contextlayer/auth.json`; the Composio project key stays on the platform. Restart `pnpm dev` when the access token expires.
|
|
12
|
+
|
|
13
|
+
## A loader that reads Gmail
|
|
14
|
+
|
|
15
|
+
The first argument is the connection requirement slug in `public/slate.json`, such as `work-email`. The platform resolves it using the app and signed-in user:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { toolsContext } from "@usecontextlayer/sdk"
|
|
19
|
+
import type { LoaderFunctionArgs } from "react-router"
|
|
20
|
+
|
|
21
|
+
export async function loader({ context }: LoaderFunctionArgs) {
|
|
22
|
+
return context.get(toolsContext).call("work-email", "GMAIL_FETCH_EMAILS", {
|
|
23
|
+
max_results: 5,
|
|
24
|
+
label_ids: ["INBOX"],
|
|
25
|
+
include_payload: false,
|
|
26
|
+
verbose: false,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Calls return `{ data, logId }`. Validate the tool-specific `data` in your loader. The complete [Gmail example](examples/gmail.tsx) validates the response with Zod and renders a message list. Copy it to `app/routes/home.tsx` in a generated app and assign your Gmail connection to `work-email`.
|
|
32
|
+
|
|
33
|
+
## Runtime ownership
|
|
34
|
+
|
|
35
|
+
The package root exports the `Tools` interface and `toolsContext`. `@usecontextlayer/sdk/local` exports the local `Tools` Worker entrypoint. `@usecontextlayer/sdk/worker` exports `createApp`, which creates the React Router request handler and supplies `toolsContext` from the local binding 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, and composes Vite plugins. The Cloudflare Vite plugin runs the auxiliary Worker only in development; production bundles exclude it and its service binding.
|
|
36
|
+
|
|
37
|
+
The platform execution API is implemented; deployed viewer integration is not yet implemented. The packaged request handler reserves `ctx.props.tools` for that later path. Local access-token bindings are not included in production builds.
|
|
38
|
+
|
|
39
|
+
## Vite configuration
|
|
40
|
+
|
|
41
|
+
ContextLayer's Vite integration for Cloudflare React Router apps. Compose it with the app's React Router and Tailwind plugins:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { contextlayer } from "@usecontextlayer/sdk/vite"
|
|
45
|
+
import { reactRouter } from "@react-router/dev/vite"
|
|
46
|
+
import tailwindcss from "@tailwindcss/vite"
|
|
47
|
+
import { defineConfig } from "vite"
|
|
48
|
+
|
|
49
|
+
export default defineConfig((env) => ({
|
|
50
|
+
plugins: [contextlayer(env), tailwindcss(), reactRouter()],
|
|
51
|
+
resolve: { tsconfigPaths: true },
|
|
52
|
+
}))
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This integration supplies the Cloudflare plugin; do not add a second instance. It uses the generated `workers/local-tools/wrangler.jsonc` to start the local Tools Worker and provides its development-only service binding. At development startup, the CLI reads the app's Git origin and saved ContextLayer login. Production builds exclude local credentials and the auxiliary Worker.
|
|
56
|
+
|
|
57
|
+
The app retains its routes, `public/slate.json`, and thin Worker/configuration files. `@usecontextlayer/sdk/worker` owns the React Router request handler and Tools context setup.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region index.d.ts
|
|
2
|
+
export interface Tools {
|
|
3
|
+
call(slug: string, toolSlug: string, args: Record<string, unknown>): Promise<{
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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
ADDED
|
@@ -0,0 +1 @@
|
|
|
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"}
|
package/dist/local.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Tools as Tools$1 } from "./index.js";
|
|
2
|
+
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region env.d.ts
|
|
5
|
+
declare const schema: z.ZodObject<{
|
|
6
|
+
CTX_ACCESS_TOKEN: z.ZodString;
|
|
7
|
+
CTX_APP_ID: z.ZodUUID;
|
|
8
|
+
CTX_PLATFORM_URL: z.ZodURL;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
type Bindings = z.input<typeof schema>;
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region local.d.ts
|
|
13
|
+
export declare class Tools extends WorkerEntrypoint<Bindings> implements Tools$1 {
|
|
14
|
+
call(slug: string, toolSlug: string, args: Record<string, unknown>): Promise<{
|
|
15
|
+
data: Record<string, unknown>;
|
|
16
|
+
logId: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.d.ts","names":[],"sources":["../env.ts","../local.ts"],"mappings":";;;;cAEM,QAAM,EAAA;;;;GAIV,EAAA,KAAA;KACU,WAAW,EAAE,aAAa;;;qBCIzB,cAAc,iBAAiB,qBAAqB;EAC1D,KAAK,cAAc,kBAAkB,MAAM,0BAAuB"}
|
package/dist/local.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region env.ts
|
|
4
|
+
const schema = z.object({
|
|
5
|
+
CTX_ACCESS_TOKEN: z.string().min(1),
|
|
6
|
+
CTX_APP_ID: z.uuid(),
|
|
7
|
+
CTX_PLATFORM_URL: z.url()
|
|
8
|
+
});
|
|
9
|
+
const parseEnv = (bindings) => schema.parse(bindings);
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region local.ts
|
|
12
|
+
const execution = z.object({
|
|
13
|
+
data: z.record(z.string(), z.unknown()),
|
|
14
|
+
error: z.string().nullable(),
|
|
15
|
+
logId: z.string()
|
|
16
|
+
});
|
|
17
|
+
var Tools = class extends WorkerEntrypoint {
|
|
18
|
+
async call(slug, toolSlug, args) {
|
|
19
|
+
const env = parseEnv(this.env);
|
|
20
|
+
const response = await fetch(new URL(`/api/apps/${env.CTX_APP_ID}/tools/call`, env.CTX_PLATFORM_URL), {
|
|
21
|
+
body: JSON.stringify({
|
|
22
|
+
arguments: args,
|
|
23
|
+
slug,
|
|
24
|
+
tool: toolSlug
|
|
25
|
+
}),
|
|
26
|
+
headers: {
|
|
27
|
+
authorization: `Bearer ${env.CTX_ACCESS_TOKEN}`,
|
|
28
|
+
"content-type": "application/json"
|
|
29
|
+
},
|
|
30
|
+
method: "POST"
|
|
31
|
+
});
|
|
32
|
+
if (!response.ok) throw new Error(`Tool call failed: HTTP ${response.status}`);
|
|
33
|
+
const result = execution.parse(await response.json());
|
|
34
|
+
if (result.error !== null) throw new Error(`${result.error} (log: ${result.logId})`);
|
|
35
|
+
return {
|
|
36
|
+
data: result.data,
|
|
37
|
+
logId: result.logId
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
42
|
+
export { Tools };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","names":[],"sources":["../env.ts","../local.ts"],"sourcesContent":["import { z } from \"zod\"\n\nconst schema = z.object({\n\tCTX_ACCESS_TOKEN: z.string().min(1),\n\tCTX_APP_ID: z.uuid(),\n\tCTX_PLATFORM_URL: z.url(),\n})\nexport type Bindings = z.input<typeof schema>\nexport const parseEnv = (bindings: Bindings) => schema.parse(bindings)\n","import { WorkerEntrypoint } from \"cloudflare:workers\"\nimport { z } from \"zod\"\nimport { type Bindings, parseEnv } from \"@/env\"\nimport type { Tools as ToolsContract } from \"@/index\"\n\nconst execution = z.object({\n\tdata: z.record(z.string(), z.unknown()),\n\terror: z.string().nullable(),\n\tlogId: z.string(),\n})\n\nexport class Tools extends WorkerEntrypoint<Bindings> implements ToolsContract {\n\tasync call(slug: string, toolSlug: string, args: Record<string, unknown>) {\n\t\tconst env = parseEnv(this.env)\n\t\tconst response = await fetch(\n\t\t\tnew URL(`/api/apps/${env.CTX_APP_ID}/tools/call`, env.CTX_PLATFORM_URL),\n\t\t\t{\n\t\t\t\tbody: JSON.stringify({ arguments: args, slug, tool: toolSlug }),\n\t\t\t\theaders: {\n\t\t\t\t\tauthorization: `Bearer ${env.CTX_ACCESS_TOKEN}`,\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tmethod: \"POST\",\n\t\t\t},\n\t\t)\n\t\tif (!response.ok) throw new Error(`Tool call failed: HTTP ${response.status}`)\n\t\tconst result = execution.parse(await response.json())\n\t\tif (result.error !== null) throw new Error(`${result.error} (log: ${result.logId})`)\n\t\treturn { data: result.data, logId: result.logId }\n\t}\n}\n"],"mappings":";;;AAEA,MAAM,SAAS,EAAE,OAAO;CACvB,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAClC,YAAY,EAAE,KAAK;CACnB,kBAAkB,EAAE,IAAI;AACzB,CAAC;AAED,MAAa,YAAY,aAAuB,OAAO,MAAM,QAAQ;;;ACHrE,MAAM,YAAY,EAAE,OAAO;CAC1B,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;CACtC,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;CAC3B,OAAO,EAAE,OAAO;AACjB,CAAC;AAED,IAAa,QAAb,cAA2B,iBAAoD;CAC9E,MAAM,KAAK,MAAc,UAAkB,MAA+B;EACzE,MAAM,MAAM,SAAS,KAAK,GAAG;EAC7B,MAAM,WAAW,MAAM,MACtB,IAAI,IAAI,aAAa,IAAI,WAAW,cAAc,IAAI,gBAAgB,GACtE;GACC,MAAM,KAAK,UAAU;IAAE,WAAW;IAAM;IAAM,MAAM;GAAS,CAAC;GAC9D,SAAS;IACR,eAAe,UAAU,IAAI;IAC7B,gBAAgB;GACjB;GACA,QAAQ;EACT,CACD;EACA,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,0BAA0B,SAAS,QAAQ;EAC7E,MAAM,SAAS,UAAU,MAAM,MAAM,SAAS,KAAK,CAAC;EACpD,IAAI,OAAO,UAAU,MAAM,MAAM,IAAI,MAAM,GAAG,OAAO,MAAM,SAAS,OAAO,MAAM,EAAE;EACnF,OAAO;GAAE,MAAM,OAAO;GAAM,OAAO,OAAO;EAAM;CACjD;AACD"}
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.d.ts","names":[],"sources":["../vite.ts"],"mappings":";;wBAIsB,eAAe,WAAW,YAAS,uBAAA"}
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
2
|
+
import { getLocalToolsBindings } from "@usecontextlayer/cli/vite";
|
|
3
|
+
//#region vite.ts
|
|
4
|
+
async function contextlayer({ command }) {
|
|
5
|
+
return cloudflare({
|
|
6
|
+
auxiliaryWorkers: [{
|
|
7
|
+
config: command === "serve" ? { vars: await getLocalToolsBindings() } : {},
|
|
8
|
+
configPath: "workers/local-tools/wrangler.jsonc",
|
|
9
|
+
devOnly: true
|
|
10
|
+
}],
|
|
11
|
+
config: command === "serve" ? { services: [{
|
|
12
|
+
binding: "TOOLS",
|
|
13
|
+
entrypoint: "Tools",
|
|
14
|
+
service: "ctx-local-tools"
|
|
15
|
+
}] } : {},
|
|
16
|
+
viteEnvironment: { name: "ssr" }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { contextlayer };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=vite.js.map
|
package/dist/vite.js.map
ADDED
|
@@ -0,0 +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\treturn cloudflare({\n\t\tauxiliaryWorkers: [\n\t\t\t{\n\t\t\t\tconfig: command === \"serve\" ? { vars: await getLocalToolsBindings() } : {},\n\t\t\t\tconfigPath: \"workers/local-tools/wrangler.jsonc\",\n\t\t\t\tdevOnly: true,\n\t\t\t},\n\t\t],\n\t\tconfig:\n\t\t\tcommand === \"serve\"\n\t\t\t\t? {\n\t\t\t\t\t\tservices: [\n\t\t\t\t\t\t\t{ binding: \"TOOLS\", entrypoint: \"Tools\", service: \"ctx-local-tools\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t}\n\t\t\t\t: {},\n\t\tviteEnvironment: { name: \"ssr\" },\n\t})\n}\n"],"mappings":";;;AAIA,eAAsB,aAAa,EAAE,WAAsB;CAC1D,OAAO,WAAW;EACjB,kBAAkB,CACjB;GACC,QAAQ,YAAY,UAAU,EAAE,MAAM,MAAM,sBAAsB,EAAE,IAAI,CAAC;GACzE,YAAY;GACZ,SAAS;EACV,CACD;EACA,QACC,YAAY,UACT,EACA,UAAU,CACT;GAAE,SAAS;GAAS,YAAY;GAAS,SAAS;EAAkB,CACrE,EACD,IACC,CAAC;EACL,iBAAiB,EAAE,MAAM,MAAM;CAChC,CAAC;AACF"}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Tools } from "./index.js";
|
|
2
|
+
import { createRequestHandler } from "react-router";
|
|
3
|
+
//#region worker.d.ts
|
|
4
|
+
export declare function createApp({ build, mode, development }: {
|
|
5
|
+
build: Parameters<typeof createRequestHandler>[0];
|
|
6
|
+
mode: string;
|
|
7
|
+
development: boolean;
|
|
8
|
+
}): {
|
|
9
|
+
fetch(request: Request, env: {
|
|
10
|
+
TOOLS: Tools;
|
|
11
|
+
}, ctx: ExecutionContext<{
|
|
12
|
+
tools: Tools;
|
|
13
|
+
}>): Promise<Response>;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","names":[],"sources":["../worker.ts"],"mappings":";;;wBAGgB,YACf,OACA,MACA;EAEA,OAAO,kBAAkB;EACzB;EACA;;EAIO,MAAK,SACD,SAAO;IACT,OAAO;KAAO,KAChB;IAAmB,OAAO;OAAQ,QAAA"}
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { toolsContext } from "./index.js";
|
|
2
|
+
import { RouterContextProvider, createRequestHandler } from "react-router";
|
|
3
|
+
//#region worker.ts
|
|
4
|
+
function createApp({ build, mode, development }) {
|
|
5
|
+
const requestHandler = createRequestHandler(build, mode);
|
|
6
|
+
return { async fetch(request, env, ctx) {
|
|
7
|
+
const context = new RouterContextProvider();
|
|
8
|
+
context.set(toolsContext, development ? env.TOOLS : ctx.props.tools);
|
|
9
|
+
return requestHandler(request, context);
|
|
10
|
+
} };
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { createApp };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +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\nexport function createApp({\n\tbuild,\n\tmode,\n\tdevelopment,\n}: {\n\tbuild: Parameters<typeof createRequestHandler>[0]\n\tmode: string\n\tdevelopment: boolean\n}) {\n\tconst requestHandler = createRequestHandler(build, mode)\n\treturn {\n\t\tasync fetch(\n\t\t\trequest: Request,\n\t\t\tenv: { TOOLS: Tools },\n\t\t\tctx: ExecutionContext<{ tools: Tools }>,\n\t\t) {\n\t\t\tconst context = new RouterContextProvider()\n\t\t\tcontext.set(toolsContext, development ? env.TOOLS : ctx.props.tools)\n\t\t\treturn requestHandler(request, context)\n\t\t},\n\t}\n}\n"],"mappings":";;;AAGA,SAAgB,UAAU,EACzB,OACA,MACA,eAKE;CACF,MAAM,iBAAiB,qBAAqB,OAAO,IAAI;CACvD,OAAO,EACN,MAAM,MACL,SACA,KACA,KACC;EACD,MAAM,UAAU,IAAI,sBAAsB;EAC1C,QAAQ,IAAI,cAAc,cAAc,IAAI,QAAQ,IAAI,MAAM,KAAK;EACnE,OAAO,eAAe,SAAS,OAAO;CACvC,EACD;AACD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { toolsContext } from "@usecontextlayer/sdk"
|
|
2
|
+
import { type LoaderFunctionArgs, useLoaderData } from "react-router"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
const inbox = z.object({
|
|
6
|
+
messages: z.array(
|
|
7
|
+
z.object({
|
|
8
|
+
messageId: z.string(),
|
|
9
|
+
messageTimestamp: z.string(),
|
|
10
|
+
sender: z.string(),
|
|
11
|
+
subject: z.string(),
|
|
12
|
+
}),
|
|
13
|
+
),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export async function loader({ context }: LoaderFunctionArgs) {
|
|
17
|
+
const result = await context
|
|
18
|
+
.get(toolsContext)
|
|
19
|
+
.call("work-email", "GMAIL_FETCH_EMAILS", {
|
|
20
|
+
include_payload: false,
|
|
21
|
+
label_ids: ["INBOX"],
|
|
22
|
+
max_results: 5,
|
|
23
|
+
verbose: false,
|
|
24
|
+
})
|
|
25
|
+
return { logId: result.logId, messages: inbox.parse(result.data).messages }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default function Home() {
|
|
29
|
+
const loaderData = useLoaderData<typeof loader>()
|
|
30
|
+
return (
|
|
31
|
+
<main className="mx-auto max-w-3xl p-8">
|
|
32
|
+
<h1 className="text-2xl font-semibold">Your Gmail inbox</h1>
|
|
33
|
+
<p className="mt-2 text-sm text-gray-500">
|
|
34
|
+
Fetched by this page's server loader through your assigned Gmail connection.
|
|
35
|
+
</p>
|
|
36
|
+
<ul className="mt-6 divide-y divide-gray-200">
|
|
37
|
+
{loaderData.messages.map((message) => (
|
|
38
|
+
<li
|
|
39
|
+
key={message.messageId}
|
|
40
|
+
className="py-4"
|
|
41
|
+
>
|
|
42
|
+
<h2 className="font-medium">{message.subject}</h2>
|
|
43
|
+
<p className="mt-1 text-sm text-gray-500">{message.sender}</p>
|
|
44
|
+
<time
|
|
45
|
+
className="text-xs text-gray-500"
|
|
46
|
+
dateTime={message.messageTimestamp}
|
|
47
|
+
>
|
|
48
|
+
{message.messageTimestamp}
|
|
49
|
+
</time>
|
|
50
|
+
</li>
|
|
51
|
+
))}
|
|
52
|
+
</ul>
|
|
53
|
+
</main>
|
|
54
|
+
)
|
|
55
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"zod": "^4.4.3",
|
|
4
|
+
"@usecontextlayer/cli": "0.12.1"
|
|
5
|
+
},
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"@cloudflare/vite-plugin": "^1.62.4",
|
|
8
|
+
"@cloudflare/workers-types": "^5.20261001.1",
|
|
9
|
+
"@types/node": "^24.13.3",
|
|
10
|
+
"@types/react": "^19.0.0",
|
|
11
|
+
"react-router": "^8.4.0",
|
|
12
|
+
"tsdown": "latest",
|
|
13
|
+
"typescript": "latest",
|
|
14
|
+
"vite": "^8.3.2"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./local": {
|
|
22
|
+
"import": "./dist/local.js",
|
|
23
|
+
"types": "./dist/local.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./vite": {
|
|
26
|
+
"import": "./dist/vite.js",
|
|
27
|
+
"types": "./dist/vite.d.ts"
|
|
28
|
+
},
|
|
29
|
+
"./worker": {
|
|
30
|
+
"import": "./dist/worker.js",
|
|
31
|
+
"types": "./dist/worker.d.ts"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"examples"
|
|
37
|
+
],
|
|
38
|
+
"name": "@usecontextlayer/sdk",
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@cloudflare/vite-plugin": "^1.62.4",
|
|
41
|
+
"react-router": "^8.4.0",
|
|
42
|
+
"vite": "^8.3.2"
|
|
43
|
+
},
|
|
44
|
+
"type": "module",
|
|
45
|
+
"version": "0.12.1",
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsdown",
|
|
48
|
+
"dev:watch": "tsdown --watch",
|
|
49
|
+
"tsc": "tsc -b tsconfig.json"
|
|
50
|
+
}
|
|
51
|
+
}
|