@usecontextlayer/sdk 0.13.0 → 0.14.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 +8 -6
- package/dist/local.d.ts +9 -0
- package/dist/local.d.ts.map +1 -1
- package/dist/local.js +15 -0
- package/dist/local.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# @usecontextlayer/sdk
|
|
2
2
|
|
|
3
|
-
ContextLayer integration for React Router apps: the shared document Layout and Tools/Viewer capabilities. In local development, tool calls execute through the ContextLayer platform using
|
|
3
|
+
ContextLayer integration for React Router apps: the shared document Layout and Tools/Viewer capabilities. In local development, tool calls execute through the ContextLayer platform using the manifest-selected viewer or app Owner's assigned Composio Platform connections.
|
|
4
4
|
|
|
5
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
6
|
|
|
7
7
|
## Local login and assignment
|
|
8
8
|
|
|
9
|
-
Run `ctx login` to save your ContextLayer login. Declare `work-email` as
|
|
9
|
+
Run `ctx login` to save your ContextLayer login. Declare `work-email` as a viewer-mode 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
10
|
|
|
11
|
-
|
|
11
|
+
For an organization-owned app's owner-mode requirement, authorize and list the account under the organization before assigning it. The connection commands' `--help` owns organization selection. The member completes OAuth for that Owner, and the platform uses the same organization's Composio identity when executing the requirement.
|
|
12
|
+
|
|
13
|
+
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, validates `public/slate.json`, and obtains a current access token using the same saved login as the CLI. The AppID, platform URL, auth issuer, access token, and manifest startup snapshot enter the existing local auxiliary Worker, which exports Tools and Viewer entrypoints. The refresh token stays in `~/.contextlayer/auth.json`; the Composio project key stays on the platform. Restart `pnpm dev` when the access token expires or the manifest changes.
|
|
12
14
|
|
|
13
15
|
## App Layout
|
|
14
16
|
|
|
@@ -24,7 +26,7 @@ The header and settings panel render into a native ShadowRoot through a React po
|
|
|
24
26
|
|
|
25
27
|
## A loader that reads Gmail
|
|
26
28
|
|
|
27
|
-
The first argument is the connection requirement slug in `public/slate.json`, such as `work-email`.
|
|
29
|
+
The first argument is the connection requirement slug in `public/slate.json`, such as `work-email`. Its manifest mode selects the acting user's assignment (`viewer`) or the app's owning user or organization's assignment (`owner`):
|
|
28
30
|
|
|
29
31
|
```ts
|
|
30
32
|
import { toolsContext } from "@usecontextlayer/sdk"
|
|
@@ -61,7 +63,7 @@ The result is `{ id, name, image }` with nullable image, or `null` for an anonym
|
|
|
61
63
|
|
|
62
64
|
The package root exports the `Tools` and `Viewer` interfaces, `User` profile type, and `toolsContext`/`viewerContext`. `@usecontextlayer/sdk/react` exports the shared React Router document `Layout` and profile `loader`; `@usecontextlayer/sdk/styles.css` exports the chrome stylesheet for Vite to process and render inside the ShadowRoot. `@usecontextlayer/sdk/local` exports the local `Tools` and `Viewer` Worker entrypoints. `@usecontextlayer/sdk/worker` exports `createApp`, which creates the React Router request handler and supplies `toolsContext` and `viewerContext` from local bindings or production request props. The native default `viewerContext` returns null for anonymous viewers. `@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.
|
|
63
65
|
|
|
64
|
-
In hosted apps, the dispatcher supplies `ctx.props.tools` as a request-scoped RPC handle. Its methods call the same platform execution API using the viewer session; the app cannot read the underlying viewer credential.
|
|
66
|
+
In hosted apps, the dispatcher supplies `ctx.props.tools` as a request-scoped RPC handle. Its methods call the same platform execution API using the viewer session; the app cannot read the underlying viewer credential. That session authenticates the caller, while the deployed manifest's mode selects the viewer or app Owner's assignment for the app and slug. For viewer-mode requirements, a viewer using the same account as the CLI uses the same saved assignment. Owner-mode requirements use the app Owner's configured account. Local access-token bindings are not included in production builds.
|
|
65
67
|
|
|
66
68
|
## Vite configuration
|
|
67
69
|
|
|
@@ -79,6 +81,6 @@ export default defineConfig((env) => ({
|
|
|
79
81
|
}))
|
|
80
82
|
```
|
|
81
83
|
|
|
82
|
-
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 Tools and Viewer service bindings. At development startup, the CLI reads the app's Git origin
|
|
84
|
+
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 Tools and Viewer service bindings. At development startup, the CLI reads the app's Git origin, saved ContextLayer login, and validated manifest snapshot. The restart prerequisites are described under [Local login and assignment](#local-login-and-assignment). Production builds exclude local credentials and the auxiliary Worker.
|
|
83
85
|
|
|
84
86
|
The app retains its routes, `public/slate.json`, and thin Worker/configuration files. `@usecontextlayer/sdk/worker` owns the React Router request handler and Tools/Viewer context setup.
|
package/dist/local.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ import { z } from "zod";
|
|
|
5
5
|
declare const schema: z.ZodObject<{
|
|
6
6
|
CTX_ACCESS_TOKEN: z.ZodString;
|
|
7
7
|
CTX_APP_ID: z.ZodUUID;
|
|
8
|
+
CTX_APP_MANIFEST: z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
9
|
+
connections: Record<string, {
|
|
10
|
+
mode: "owner" | "viewer";
|
|
11
|
+
toolkit: string;
|
|
12
|
+
}>;
|
|
13
|
+
secrets: Record<string, {
|
|
14
|
+
mode: "owner" | "viewer";
|
|
15
|
+
}>;
|
|
16
|
+
}, string>>;
|
|
8
17
|
CTX_AUTH_ISSUER: z.ZodURL;
|
|
9
18
|
CTX_PLATFORM_URL: z.ZodURL;
|
|
10
19
|
}, z.core.$strip>;
|
package/dist/local.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","names":[],"sources":["../env.ts","../local.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"local.d.ts","names":[],"sources":["../env.ts","../local.ts"],"mappings":";;;;cAGM,QAAM,EAAA;;;;;;;;;;;;;;GAMV,EAAA,KAAA;KACU,WAAW,EAAE,aAAa;;;qBCEzB,cAAc,iBAAiB,qBAAqB;EAC1D,KAAK,cAAc,kBAAkB,MAAM,0BAAuB;;;;;qBAyB5D,eAAe,iBAAiB,qBAAqB;EAC3D,kBAAc"}
|
package/dist/local.js
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import { WorkerEntrypoint } from "cloudflare:workers";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
//#region ../shared/dist/slate.mjs
|
|
4
|
+
const credentialModeSchema = z.enum(["viewer", "owner"]);
|
|
5
|
+
const connectionRequirementSchema = z.strictObject({
|
|
6
|
+
mode: credentialModeSchema,
|
|
7
|
+
toolkit: z.string().min(1)
|
|
8
|
+
});
|
|
9
|
+
const secretNameSchema = z.string().regex(/^[A-Z_][A-Z0-9_]*$/);
|
|
10
|
+
const secretRequirementSchema = z.strictObject({ mode: credentialModeSchema });
|
|
11
|
+
const slateSchema = z.strictObject({
|
|
12
|
+
connections: z.record(z.string().min(1), connectionRequirementSchema),
|
|
13
|
+
secrets: z.record(secretNameSchema, secretRequirementSchema).default({})
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
3
16
|
//#region env.ts
|
|
4
17
|
const schema = z.object({
|
|
5
18
|
CTX_ACCESS_TOKEN: z.string().min(1),
|
|
6
19
|
CTX_APP_ID: z.uuid(),
|
|
20
|
+
CTX_APP_MANIFEST: z.string().transform((value) => slateSchema.parse(JSON.parse(value))),
|
|
7
21
|
CTX_AUTH_ISSUER: z.url(),
|
|
8
22
|
CTX_PLATFORM_URL: z.url()
|
|
9
23
|
});
|
|
@@ -28,6 +42,7 @@ var Tools = class extends WorkerEntrypoint {
|
|
|
28
42
|
const response = await fetch(new URL(`/api/apps/${env.CTX_APP_ID}/tools/call`, env.CTX_PLATFORM_URL), {
|
|
29
43
|
body: JSON.stringify({
|
|
30
44
|
arguments: args,
|
|
45
|
+
manifest: env.CTX_APP_MANIFEST,
|
|
31
46
|
slug,
|
|
32
47
|
tool: toolSlug
|
|
33
48
|
}),
|
package/dist/local.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","names":[],"sources":["../env.ts","../viewer.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_AUTH_ISSUER: z.url(),\n\tCTX_PLATFORM_URL: z.url(),\n})\nexport type Bindings = z.input<typeof schema>\nexport const parseEnv = (bindings: Bindings) => schema.parse(bindings)\n","import { z } from \"zod\"\n\nexport const userSchema = z.object({\n\tid: z.string().min(1),\n\timage: z.string().nullable(),\n\tname: z.string(),\n})\n\nexport type User = z.infer<typeof userSchema>\n\nexport interface Viewer {\n\tgetCurrentUser(): Promise<User | null>\n}\n","import { WorkerEntrypoint } from \"cloudflare:workers\"\nimport { z } from \"zod\"\nimport { type Bindings, parseEnv } from \"@/env\"\nimport type { Tools as ToolsContract } from \"@/index\"\nimport { userSchema, type Viewer as ViewerContract } from \"@/viewer\"\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({
|
|
1
|
+
{"version":3,"file":"local.js","names":[],"sources":["../../shared/dist/slate.mjs","../env.ts","../viewer.ts","../local.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 slateSchema = z.strictObject({\n\tconnections: z.record(z.string().min(1), connectionRequirementSchema),\n\tsecrets: z.record(secretNameSchema, secretRequirementSchema).default({})\n});\n\n//#endregion\nexport { connectionRequirementSchema, credentialModeSchema, secretNameSchema, secretRequirementSchema, slateSchema };","import { slateSchema } from \"@usecontextlayer/shared/slate\"\nimport { z } from \"zod\"\n\nconst schema = z.object({\n\tCTX_ACCESS_TOKEN: z.string().min(1),\n\tCTX_APP_ID: z.uuid(),\n\tCTX_APP_MANIFEST: z.string().transform((value) => slateSchema.parse(JSON.parse(value))),\n\tCTX_AUTH_ISSUER: z.url(),\n\tCTX_PLATFORM_URL: z.url(),\n})\nexport type Bindings = z.input<typeof schema>\nexport const parseEnv = (bindings: Bindings) => schema.parse(bindings)\n","import { z } from \"zod\"\n\nexport const userSchema = z.object({\n\tid: z.string().min(1),\n\timage: z.string().nullable(),\n\tname: z.string(),\n})\n\nexport type User = z.infer<typeof userSchema>\n\nexport interface Viewer {\n\tgetCurrentUser(): Promise<User | null>\n}\n","import { WorkerEntrypoint } from \"cloudflare:workers\"\nimport { z } from \"zod\"\nimport { type Bindings, parseEnv } from \"@/env\"\nimport type { Tools as ToolsContract } from \"@/index\"\nimport { userSchema, type Viewer as ViewerContract } from \"@/viewer\"\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({\n\t\t\t\t\targuments: args,\n\t\t\t\t\tmanifest: env.CTX_APP_MANIFEST,\n\t\t\t\t\tslug,\n\t\t\t\t\ttool: toolSlug,\n\t\t\t\t}),\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\nexport class Viewer extends WorkerEntrypoint<Bindings> implements ViewerContract {\n\tasync getCurrentUser() {\n\t\tconst env = parseEnv(this.env)\n\t\tconst response = await fetch(new URL(\"/api/me\", env.CTX_AUTH_ISSUER), {\n\t\t\theaders: { authorization: `Bearer ${env.CTX_ACCESS_TOKEN}` },\n\t\t})\n\t\tif (response.status === 401) return null\n\t\tif (!response.ok) throw new Error(`Identity request failed: HTTP ${response.status}`)\n\t\treturn userSchema.parse(await response.json())\n\t}\n}\n"],"mappings":";;;AAGA,MAAM,uBAAuB,EAAE,KAAK,CAAC,UAAU,OAAO,CAAC;AACvD,MAAM,8BAA8B,EAAE,aAAa;CAClD,MAAM;CACN,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;AAC1B,CAAC;AACD,MAAM,mBAAmB,EAAE,OAAO,CAAC,CAAC,MAAM,oBAAoB;AAC9D,MAAM,0BAA0B,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC7E,MAAM,cAAc,EAAE,aAAa;CAClC,aAAa,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,2BAA2B;CACpE,SAAS,EAAE,OAAO,kBAAkB,uBAAuB,CAAC,CAAC,QAAQ,CAAC,CAAC;AACxE,CAAC;;;ACVD,MAAM,SAAS,EAAE,OAAO;CACvB,kBAAkB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CAClC,YAAY,EAAE,KAAK;CACnB,kBAAkB,EAAE,OAAO,CAAC,CAAC,WAAW,UAAU,YAAY,MAAM,KAAK,MAAM,KAAK,CAAC,CAAC;CACtF,iBAAiB,EAAE,IAAI;CACvB,kBAAkB,EAAE,IAAI;AACzB,CAAC;AAED,MAAa,YAAY,aAAuB,OAAO,MAAM,QAAQ;;;ACTrE,MAAa,aAAa,EAAE,OAAO;CAClC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACpB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;CAC3B,MAAM,EAAE,OAAO;AAChB,CAAC;;;ACAD,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;IACpB,WAAW;IACX,UAAU,IAAI;IACd;IACA,MAAM;GACP,CAAC;GACD,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;AAEA,IAAa,SAAb,cAA4B,iBAAqD;CAChF,MAAM,iBAAiB;EACtB,MAAM,MAAM,SAAS,KAAK,GAAG;EAC7B,MAAM,WAAW,MAAM,MAAM,IAAI,IAAI,WAAW,IAAI,eAAe,GAAG,EACrE,SAAS,EAAE,eAAe,UAAU,IAAI,mBAAmB,EAC5D,CAAC;EACD,IAAI,SAAS,WAAW,KAAK,OAAO;EACpC,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,iCAAiC,SAAS,QAAQ;EACpF,OAAO,WAAW,MAAM,MAAM,SAAS,KAAK,CAAC;CAC9C;AACD"}
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"tailwindcss": "^4.3.3",
|
|
9
9
|
"tw-animate-css": "^1.4.0",
|
|
10
10
|
"zod": "^4.4.3",
|
|
11
|
-
"@usecontextlayer/cli": "0.
|
|
11
|
+
"@usecontextlayer/cli": "0.14.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@cloudflare/vite-plugin": "^1.62.4",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"react-router": "^8.4.0",
|
|
22
22
|
"tsdown": "latest",
|
|
23
23
|
"typescript": "latest",
|
|
24
|
-
"vite": "^8.3.2"
|
|
24
|
+
"vite": "^8.3.2",
|
|
25
|
+
"@usecontextlayer/shared": "0.14.0"
|
|
25
26
|
},
|
|
26
27
|
"exports": {
|
|
27
28
|
".": {
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"vite": "^8.3.2"
|
|
61
62
|
},
|
|
62
63
|
"type": "module",
|
|
63
|
-
"version": "0.
|
|
64
|
+
"version": "0.14.0",
|
|
64
65
|
"scripts": {
|
|
65
66
|
"build": "tsdown",
|
|
66
67
|
"dev:watch": "tsdown --watch",
|