@kazzle/app 0.1.821 → 0.1.823

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -8,16 +8,23 @@ export declare function componentUrlEnvName(componentName: string): string;
8
8
  * a wrong/empty address makes cross-component calls fail silently.
9
9
  */
10
10
  export declare function componentUrl(componentName: string): string;
11
- /** Extract the install identity Authorization header from an incoming tool request. */
12
- export declare function installAuthHeader(req: Request): string;
11
+ /** Header Kazzle sets to carry the verified install identity into the app. */
12
+ export declare const KAZZLE_IDENTITY_HEADER = "x-kazzle-identity";
13
13
  /**
14
- * Client scoped to one install, built from the identity header on an incoming
14
+ * Extract the install identity token from an incoming tool request. Kazzle
15
+ * delivers it in `X-Kazzle-Identity`; the app's own `Authorization` header is
16
+ * left untouched for the app's own use.
17
+ */
18
+ export declare function installIdentityToken(req: Request): string;
19
+ /**
20
+ * Client scoped to one install, built from the identity token on an incoming
15
21
  * tool request. Use it to persist and read per-install runtime secrets.
16
22
  */
17
23
  export declare class KazzleInstallClient {
18
- private readonly auth;
24
+ private readonly token;
19
25
  private readonly apiUrl;
20
- constructor(reqOrAuthHeader: Request | string);
26
+ constructor(reqOrIdentityToken: Request | string);
27
+ private authHeader;
21
28
  /** Read a per-install secret by fixed name. Returns null when not set yet (404). */
22
29
  getSecret(name: string): Promise<string | null>;
23
30
  /** Write a per-install secret by fixed name. */
package/dist/client.js CHANGED
@@ -4,10 +4,12 @@
4
4
  // comments in the templates:
5
5
  //
6
6
  // 1. Per-install secrets. When the AI calls an app tool, Kazzle POSTs the
7
- // request with `Authorization: Bearer <install identity>`. The app reads
8
- // or writes runtime secrets by calling Kazzle back with that SAME header;
9
- // Kazzle scopes the secret to this install. Use a fixed secret name — never
10
- // key by user yourself.
7
+ // request with the install identity in the `X-Kazzle-Identity` header
8
+ // (Kazzle owns that header; your app's own `Authorization` is never
9
+ // touched). The app reads or writes runtime secrets by calling Kazzle back
10
+ // with that identity as `Authorization: Bearer <identity>`; Kazzle scopes
11
+ // the secret to this install. Use a fixed secret name — never key by user
12
+ // yourself.
11
13
  // 2. Sibling component URLs. A component reaches another component in the same
12
14
  // app via the injected `KAZZLE_APP_COMPONENT_<NAME>_URL` env var. That URL
13
15
  // is server-to-server only — never expose it to the browser.
@@ -42,29 +44,38 @@ export function componentUrl(componentName) {
42
44
  }
43
45
  return url;
44
46
  }
45
- /** Extract the install identity Authorization header from an incoming tool request. */
46
- export function installAuthHeader(req) {
47
- const auth = req.headers.get('authorization');
48
- if (!auth) {
49
- throw new Error('Missing Authorization header — expected the install identity from a Kazzle tool call.');
47
+ /** Header Kazzle sets to carry the verified install identity into the app. */
48
+ export const KAZZLE_IDENTITY_HEADER = 'x-kazzle-identity';
49
+ /**
50
+ * Extract the install identity token from an incoming tool request. Kazzle
51
+ * delivers it in `X-Kazzle-Identity`; the app's own `Authorization` header is
52
+ * left untouched for the app's own use.
53
+ */
54
+ export function installIdentityToken(req) {
55
+ const token = req.headers.get(KAZZLE_IDENTITY_HEADER);
56
+ if (!token) {
57
+ throw new Error(`Missing ${KAZZLE_IDENTITY_HEADER} header — expected the install identity from a Kazzle tool call.`);
50
58
  }
51
- return auth;
59
+ return token;
52
60
  }
53
61
  /**
54
- * Client scoped to one install, built from the identity header on an incoming
62
+ * Client scoped to one install, built from the identity token on an incoming
55
63
  * tool request. Use it to persist and read per-install runtime secrets.
56
64
  */
57
65
  export class KazzleInstallClient {
58
- auth;
66
+ token;
59
67
  apiUrl;
60
- constructor(reqOrAuthHeader) {
61
- this.auth = typeof reqOrAuthHeader === 'string' ? reqOrAuthHeader : installAuthHeader(reqOrAuthHeader);
68
+ constructor(reqOrIdentityToken) {
69
+ this.token = typeof reqOrIdentityToken === 'string' ? reqOrIdentityToken : installIdentityToken(reqOrIdentityToken);
62
70
  this.apiUrl = kazzleApiUrl();
63
71
  }
72
+ authHeader() {
73
+ return `Bearer ${this.token}`;
74
+ }
64
75
  /** Read a per-install secret by fixed name. Returns null when not set yet (404). */
65
76
  async getSecret(name) {
66
77
  const res = await fetch(`${this.apiUrl}/apps/secrets/${encodeURIComponent(name)}`, {
67
- headers: { authorization: this.auth },
78
+ headers: { authorization: this.authHeader() },
68
79
  });
69
80
  if (res.status === 404)
70
81
  return null;
@@ -77,7 +88,7 @@ export class KazzleInstallClient {
77
88
  async setSecret(name, value) {
78
89
  const res = await fetch(`${this.apiUrl}/apps/secrets/${encodeURIComponent(name)}`, {
79
90
  method: 'PUT',
80
- headers: { authorization: this.auth, 'content-type': 'application/json' },
91
+ headers: { authorization: this.authHeader(), 'content-type': 'application/json' },
81
92
  body: JSON.stringify({ value }),
82
93
  });
83
94
  if (!res.ok)
package/dist/tools.js CHANGED
@@ -18,7 +18,8 @@
18
18
  // If you change this contract, update that compiler and its tests together.
19
19
  //
20
20
  // Tool handlers (POST /tools/...) receive:
21
- // - `Authorization: Bearer <install identity>` — scope secrets via KazzleInstallClient
21
+ // - `X-Kazzle-Identity: <install identity>` — scope secrets via KazzleInstallClient
22
+ // (your app's own `Authorization` header is never touched by Kazzle)
22
23
  // - `Kazzle-Tool-Context: <json>` — thread vs Tools API (`toolContext(req)`)
23
24
  // Handlers may return plain text, `{ content }`, or `{ type: "action_required", ... }`
24
25
  // to pause the thread until the user acts (see documents/tool-required-action.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kazzle/app",
3
- "version": "0.1.821",
3
+ "version": "0.1.823",
4
4
  "description": "Contracts, tool helpers, Vite helper, and templates for building Kazzle apps.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -110,8 +110,9 @@ const server = Bun.serve({
110
110
  //
111
111
  // Each tool declared in skills/tools/tools.ts is backed by a route here.
112
112
  // When the AI calls `save_bookmark`, Kazzle POSTs the tool input to this path
113
- // with the app identity as `Authorization: Bearer <token>`. Return either
114
- // plain text or JSON { content } — that becomes the tool result the AI sees.
113
+ // with the app identity in the `X-Kazzle-Identity` header (your app's own
114
+ // `Authorization` header is never touched). Return either plain text or JSON
115
+ // { content } — that becomes the tool result the AI sees.
115
116
  //
116
117
  // To add a tool: add it to tools.ts (name + Zod input + path), then add
117
118
  // its matching `POST <path>` route below.
@@ -119,24 +120,20 @@ const server = Bun.serve({
119
120
  const input = await req.json().catch(() => ({}));
120
121
  const parsed = SaveBookmarkInput.safeParse(input);
121
122
  if (!parsed.success) {
122
- return Response.json({ content: parsed.error.issues.map(issue => issue.message).join('; ') }, { status: 400 });
123
+ return Response.json({ content: parsed.error.issues.map(issue => `${issue.path.join('.') || 'input'}: ${issue.message}`).join('; ') }, { status: 400 });
123
124
  }
124
125
  const toolInput = parsed.data;
125
126
  // Do the real work here (write to your DB, call an API, etc.).
126
127
  //
127
128
  // Per-install runtime secrets (e.g. a connected user's OAuth token) are
128
- // saved/read by calling Kazzle back with the SAME identity header this
129
- // tool call arrived with — Kazzle scopes them to this install. Use a
129
+ // saved/read via KazzleInstallClient, which reads the `X-Kazzle-Identity`
130
+ // header from this request and scopes the secret to this install. Use a
130
131
  // fixed name; never key by user yourself:
131
132
  //
132
- // const auth = req.headers.get('authorization')!;
133
- // const api = process.env.KAZZLE_API_URL;
134
- // await fetch(`${api}/apps/secrets/gmail_token`, {
135
- // method: 'PUT', headers: { authorization: auth, 'content-type': 'application/json' },
136
- // body: JSON.stringify({ value: accessToken }),
137
- // });
138
- // const res = await fetch(`${api}/apps/secrets/gmail_token`, { headers: { authorization: auth } });
139
- // const token = res.ok ? (await res.json()).value : null; // 404 → not connected yet
133
+ // import { KazzleInstallClient } from '@kazzle/app/client';
134
+ // const kazzle = new KazzleInstallClient(req);
135
+ // await kazzle.setSecret('gmail_token', accessToken);
136
+ // const token = await kazzle.getSecret('gmail_token'); // null → not connected yet
140
137
  console.log(`[{{APP_NAME}}] save_bookmark:`, toolInput.title ?? '(untitled)', toolInput.url);
141
138
  return Response.json({ content: `Saved bookmark: ${toolInput.title ?? toolInput.url}` });
142
139
  }