dewee-webchat 0.2.0 → 0.4.1-beta.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.
@@ -0,0 +1,170 @@
1
+ /** Server-Sent Events emitted by `POST {basePath}/chat`. */
2
+ type ChatStreamEvent = {
3
+ type: "start";
4
+ runId?: string;
5
+ conversationId: string;
6
+ agent: string;
7
+ actionsHash?: string;
8
+ } | {
9
+ type: "thinking";
10
+ text: string;
11
+ } | {
12
+ type: "delta";
13
+ text: string;
14
+ } | {
15
+ type: "tool_call";
16
+ id: string;
17
+ name: string;
18
+ arguments?: unknown;
19
+ } | {
20
+ type: "tool_result";
21
+ id: string;
22
+ name: string;
23
+ isError: boolean;
24
+ result?: string;
25
+ } | {
26
+ type: "done";
27
+ content: string;
28
+ usage?: Record<string, number>;
29
+ } | {
30
+ type: "error";
31
+ message: string;
32
+ code?: string;
33
+ remediation?: Remediation;
34
+ retryAfterMs?: number;
35
+ };
36
+ /** The seven typed identity errors of the Dewee gateway, forwarded as `error.code` for signed-in users. */
37
+ declare const IDENTITY_ERROR_CODES: readonly ["IDENTITY_REQUIRED", "IDENTITY_LINK_REQUIRED", "IDENTITY_CONFLICT", "LINK_EXPIRED", "LINK_REVOKED", "PERMISSION_DENIED", "SOURCE_UNAVAILABLE"];
38
+ type IdentityErrorCode = (typeof IDENTITY_ERROR_CODES)[number];
39
+ /**
40
+ * Admission refusals of the gateway for `chat.send`, forwarded as `error.code`: `POLICY_DENIED` (the
41
+ * message is outside the policy, e.g. too long; not retryable) and `RATE_LIMITED` (rate limit, a run
42
+ * still answering the previous message, or the counter backend unavailable; carries `retryAfterMs`).
43
+ * `CHALLENGE_REQUIRED` is reserved for the gateway challenge protocol and carries no payload yet.
44
+ */
45
+ declare const ADMISSION_ERROR_CODES: readonly ["POLICY_DENIED", "RATE_LIMITED", "CHALLENGE_REQUIRED"];
46
+ type AdmissionErrorCode = (typeof ADMISSION_ERROR_CODES)[number];
47
+ declare function isAdmissionErrorCode(code: unknown): code is AdmissionErrorCode;
48
+ /** What to do about an identity error: `action` (e.g. `reauthenticate`, `retry_later`) and who acts (`end_user`, `operator`, `integrator`). */
49
+ interface Remediation {
50
+ action: string;
51
+ audience: string;
52
+ }
53
+ /**
54
+ * Error body of every JSON route. `remediation` is present for identity errors only, `retryAfterMs`
55
+ * for `RATE_LIMITED` refusals of the gateway (also sent as the `Retry-After` header, in seconds).
56
+ */
57
+ interface ErrorBody {
58
+ error: {
59
+ message: string;
60
+ code: string;
61
+ remediation?: Remediation;
62
+ retryAfterMs?: number;
63
+ };
64
+ }
65
+ interface AgentInfo {
66
+ id: string;
67
+ name?: string;
68
+ description?: string;
69
+ }
70
+ /** Response of `GET {basePath}/config` — safe to expose publicly. */
71
+ interface PublicConfig {
72
+ agents: AgentInfo[];
73
+ defaultAgent: string;
74
+ allowAgentSwitch: boolean;
75
+ allowClientCredentials: boolean;
76
+ turnstileSiteKey?: string;
77
+ maxMessageLength: number;
78
+ version: string;
79
+ /** Present (true) when the backend signs users in through Dewee: the widget then asks `/session` on every page load. */
80
+ identity?: boolean;
81
+ /**
82
+ * Present (true) when a returning visitor's `/session` refresh (a valid anonymous `token` in the
83
+ * body) needs no Turnstile token (ccp transport); only new visitors are challenged then. With
84
+ * `identity` the widget still challenges: a signed-in user's `/session` always needs a token.
85
+ */
86
+ refreshWithoutTurnstile?: boolean;
87
+ }
88
+ /** Response of `POST {basePath}/session`. */
89
+ interface SessionResponse {
90
+ visitorId: string;
91
+ token: string;
92
+ /**
93
+ * When the widget should come back to `/session` (refreshing with `token`). With the ccp transport
94
+ * this is when the CCP edge session sealed in the token ends, earlier than the token itself.
95
+ */
96
+ expiresAt: number;
97
+ /**
98
+ * Present (true) when the session carries a verified Dewee identity. Such sessions are short-lived and
99
+ * are used from memory only.
100
+ */
101
+ verified?: boolean;
102
+ /**
103
+ * ccp transport, verified sessions only: an opaque token that lets a later page load of this tab
104
+ * reuse the session instead of exchanging a new one. It is no bearer token (every route but
105
+ * `/session` refuses it), and `/session` uses it only for the user the host authenticates at that
106
+ * moment. The widget keeps it in `sessionStorage` and sends it back as `reuseHint`; it stores
107
+ * nothing when the answer has none (legacy gateway, PHP).
108
+ */
109
+ reuseHint?: string;
110
+ /**
111
+ * Verified sessions, and every session of the ccp transport: milliseconds until `expiresAt`, counted
112
+ * from when the response is received. The widget refreshes from this rather than `expiresAt`, so a
113
+ * skewed browser clock does not matter.
114
+ */
115
+ expiresIn?: number;
116
+ }
117
+ /** A chat account the proof code of a web-first link can be sent to. */
118
+ interface LinkTarget {
119
+ /** e.g. `telegram`, `discord`, `zalo`. */
120
+ channelType: string;
121
+ channelInstanceId: string;
122
+ name: string;
123
+ displayName?: string;
124
+ }
125
+ /** Response of `POST {basePath}/link`. */
126
+ interface LinkResponse {
127
+ /** Show it exactly as given; the user sends it in a direct chat from the account to link. */
128
+ proofCode: string;
129
+ /** Epoch ms. */
130
+ expiresAt: number;
131
+ deepLinks: LinkTarget[];
132
+ }
133
+ interface ToolCallView {
134
+ id: string;
135
+ name: string;
136
+ arguments?: unknown;
137
+ result?: string;
138
+ isError?: boolean;
139
+ status: "running" | "done" | "error";
140
+ }
141
+ /** A transcript message as returned by `GET {basePath}/history`. */
142
+ interface HistoryMessage {
143
+ role: "user" | "assistant";
144
+ content: string;
145
+ thinking?: string;
146
+ toolCalls?: ToolCallView[];
147
+ createdAt?: string;
148
+ }
149
+ /** How much an agent-invoked page action can change. `mutate`/`destructive` always need user approval. */
150
+ type ActionSensitivity = "read" | "navigate" | "mutate" | "destructive";
151
+ /** What the backend (and the agent) learns about a page action. Handlers never leave the browser. */
152
+ interface ActionManifestEntry {
153
+ name: string;
154
+ description: string;
155
+ /** JSON Schema subset describing `args` (object). */
156
+ parameters: Record<string, unknown>;
157
+ sensitivity: ActionSensitivity;
158
+ }
159
+ /** Body of `POST {basePath}/chat`. `actions`/`actionsHash`/`pageContext` are optional (page actions). */
160
+ interface ChatRequestBody {
161
+ message: string;
162
+ agent?: string;
163
+ conversationId?: string;
164
+ actions?: ActionManifestEntry[];
165
+ /** Hash from the `start` event of the last completed turn; the manifest is re-sent to the agent only when it differs. */
166
+ actionsHash?: string;
167
+ pageContext?: unknown;
168
+ }
169
+
170
+ export { type AgentInfo as A, type ChatStreamEvent as C, type ErrorBody as E, type HistoryMessage as H, type IdentityErrorCode as I, type LinkResponse as L, type PublicConfig as P, type Remediation as R, type SessionResponse as S, type ToolCallView as T, type ActionManifestEntry as a, type AdmissionErrorCode as b, ADMISSION_ERROR_CODES as c, type ActionSensitivity as d, type ChatRequestBody as e, type LinkTarget as f, isAdmissionErrorCode as i };
package/dist/react.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties } from 'react';
3
3
  import { DeweeChatConfig, ActionEventDetail, DeweeChatElement } from './index.js';
4
- export { ActionConfirmHook, PageAction, PageActionContext } from './index.js';
5
- import './protocol-B72Ry-fY.js';
4
+ export { ActionConfirmHook, PageAction, PageActionContext, RequestHeadersOption } from './index.js';
5
+ import './protocol-CLbGE9Ns.js';
6
6
 
7
7
  interface DeweeChatProps extends Partial<DeweeChatConfig> {
8
8
  className?: string;
package/dist/react.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  defineDeweeChat
3
- } from "./chunk-YV6PXYJZ.js";
4
- import "./chunk-JX6AH37X.js";
3
+ } from "./chunk-7WT3JK64.js";
4
+ import "./chunk-USXVB3AC.js";
5
5
 
6
6
  // src/react.ts
7
7
  import { createElement, forwardRef, useEffect, useImperativeHandle, useRef } from "react";
@@ -16,7 +16,7 @@ var EVENTS = {
16
16
  };
17
17
  var DeweeChat = forwardRef(function DeweeChat2(props, ref) {
18
18
  const el = useRef(null);
19
- const { className, style, onReady, onSend, onReply, onError, onOpen, onClose, onAction, actions, confirm, getPageContext, ...config } = props;
19
+ const { className, style, onReady, onSend, onReply, onError, onOpen, onClose, onAction, actions, confirm, getPageContext, headers, fetch, ...config } = props;
20
20
  const handlers = { onReady, onSend, onReply, onError, onOpen, onClose, onAction };
21
21
  const handlersRef = useRef(handlers);
22
22
  handlersRef.current = handlers;
@@ -28,7 +28,7 @@ var DeweeChat = forwardRef(function DeweeChat2(props, ref) {
28
28
  }, [configKey]);
29
29
  useEffect(() => {
30
30
  defineDeweeChat();
31
- el.current?.configure({ actions, confirm, getPageContext });
31
+ el.current?.configure({ actions, confirm, getPageContext, headers, fetch });
32
32
  });
33
33
  useEffect(() => {
34
34
  const node = el.current;
@@ -0,0 +1,6 @@
1
+ import { D as DeweeIdentitySdk } from './handler-DunrbnSD.js';
2
+ import './protocol-CLbGE9Ns.js';
3
+
4
+ declare const deweeIdentitySdk: DeweeIdentitySdk;
5
+
6
+ export { DeweeIdentitySdk, deweeIdentitySdk };
@@ -0,0 +1,6 @@
1
+ // src/server/identity.ts
2
+ import { createAssertion, exchangeSession, startLink } from "@dewee/identity";
3
+ var deweeIdentitySdk = { exchangeSession, startLink, createAssertion };
4
+ export {
5
+ deweeIdentitySdk
6
+ };
package/dist/server.d.ts CHANGED
@@ -1,74 +1,7 @@
1
- import { A as AgentInfo, H as HistoryMessage, C as ChatStreamEvent, a as ActionManifestEntry } from './protocol-B72Ry-fY.js';
2
- export { b as ActionSensitivity, c as ChatRequestBody, P as PublicConfig, S as SessionResponse } from './protocol-B72Ry-fY.js';
1
+ export { A as AuthenticatedUser, C as CcpError, a as CcpOptions, b as DeweeHandler, c as DeweeHandlerOptions, d as DeweeIdentityOptions, D as DeweeIdentitySdk, e as DeweeTransport, I as IdentityPrivateJwk, f as IdentitySigner, M as MemoryRateLimits, R as RateLimitBucket, g as RateLimiter, V as VisitorClaims, h as createDeweeHandler, m as memoryRateLimiter, o as optionsFromEnv, s as signVisitorToken, v as verifyVisitorToken } from './handler-DunrbnSD.js';
3
2
  import { IncomingMessage, ServerResponse } from 'node:http';
4
-
5
- interface VisitorClaims {
6
- /** Visitor id (random, 22 chars). */
7
- v: string;
8
- /** Expiry, epoch ms. */
9
- exp: number;
10
- }
11
- declare function signVisitorToken(secret: string, claims: VisitorClaims): Promise<string>;
12
- declare function verifyVisitorToken(secret: string, token: string): Promise<VisitorClaims | null>;
13
- /** Returns true when the key may proceed. Implementations may be async (KV, DO, Redis…). */
14
- type RateLimiter = (key: string, bucket: "session" | "chat") => boolean | Promise<boolean>;
15
- /**
16
- * Fixed-window in-memory limiter. Good enough for a single Node process; on serverless
17
- * runtimes each isolate keeps its own counters, so pass a shared limiter for hard limits.
18
- */
19
- declare function memoryRateLimiter(limits: {
20
- chat: [number, number];
21
- session: [number, number];
22
- }): RateLimiter;
23
-
24
- interface DeweeHandlerOptions {
25
- /** Gateway runtime origin. Required unless every request brings its own credentials. */
26
- gatewayUrl?: string;
27
- /** Gateway token or operator API key (server-side only). */
28
- token?: string;
29
- tenantId?: string;
30
- /** HMAC secret for visitor tokens (>= 32 random chars). */
31
- secret?: string;
32
- /** Agents visitors may talk to. The first is the default. `"*"` = every active agent. */
33
- agents?: Array<string | AgentInfo> | "*";
34
- defaultAgent?: string;
35
- /** Let the widget switch between allowed agents. Default: true when more than one agent. */
36
- allowAgentSwitch?: boolean;
37
- /** Cross-origin sites allowed to call this backend. Same-origin is always allowed. */
38
- allowedOrigins?: string[] | "*";
39
- /**
40
- * Let visitors bring their own gateway URL + token (sent per request, never stored).
41
- * Meant for playgrounds. `allowedHosts` restricts which gateways may be targeted.
42
- */
43
- allowClientCredentials?: boolean | {
44
- allowedHosts?: string[];
45
- };
46
- /** Cloudflare Turnstile. When set, issuing a visitor session requires a valid challenge. */
47
- turnstile?: {
48
- siteKey: string;
49
- secretKey: string;
50
- };
51
- /** Custom limiter, or false to disable. Default: in-memory 20 msgs/min, 10 sessions/10 min per IP. */
52
- rateLimit?: RateLimiter | false;
53
- maxMessageLength?: number;
54
- /** Prefix for the per-visitor gateway user id. */
55
- userIdPrefix?: string;
56
- sessionTtlMs?: number;
57
- /** Max duration of one agent run. */
58
- timeoutMs?: number;
59
- /** Observe traffic (logging/analytics). Errors thrown here are ignored. */
60
- onChat?: (info: {
61
- visitorId: string;
62
- agent: string;
63
- message: string;
64
- reply?: string;
65
- error?: string;
66
- }) => void;
67
- }
68
- type Handler = (request: Request) => Promise<Response>;
69
- declare function createDeweeHandler(options: DeweeHandlerOptions): Handler;
70
- /** Reads options from environment variables (process.env, Workers env, import.meta.env…). */
71
- declare function optionsFromEnv(env: Record<string, string | undefined>, overrides?: Partial<DeweeHandlerOptions>): DeweeHandlerOptions;
3
+ import { R as Remediation, H as HistoryMessage, A as AgentInfo, C as ChatStreamEvent, a as ActionManifestEntry, b as AdmissionErrorCode } from './protocol-CLbGE9Ns.js';
4
+ export { c as ADMISSION_ERROR_CODES, d as ActionSensitivity, e as ChatRequestBody, E as ErrorBody, I as IdentityErrorCode, L as LinkResponse, f as LinkTarget, P as PublicConfig, S as SessionResponse, i as isAdmissionErrorCode } from './protocol-CLbGE9Ns.js';
72
5
 
73
6
  type FetchHandler = (request: Request) => Promise<Response>;
74
7
  /** Wraps a fetch-style handler for `http.createServer`, Express (`app.all("/api/dewee/*", ...)`), etc. */
@@ -85,9 +18,19 @@ interface GatewayCredentials {
85
18
  /** Optional tenant id/slug for multi-tenant gateways. */
86
19
  tenantId?: string;
87
20
  }
21
+ /**
22
+ * Who a connection acts as: a gateway user id chosen by this server (anonymous visitors), or a Dewee
23
+ * identity session, in which case the gateway derives the user and no `user_id` is sent.
24
+ */
25
+ type GatewayActor = string | {
26
+ identitySession: string;
27
+ };
88
28
  declare class GatewayError extends Error {
89
29
  code?: string | undefined;
90
- constructor(message: string, code?: string | undefined);
30
+ remediation?: Remediation | undefined;
31
+ retryAfterMs?: unknown | undefined;
32
+ /** `retryAfterMs` is the gateway's raw value for retryable refusals (`RATE_LIMITED`), unvalidated. */
33
+ constructor(message: string, code?: string | undefined, remediation?: Remediation | undefined, retryAfterMs?: unknown | undefined);
91
34
  }
92
35
  /** One authenticated gateway connection. Short-lived: one per chat turn or lookup. */
93
36
  declare class GatewayConnection {
@@ -97,7 +40,7 @@ declare class GatewayConnection {
97
40
  private listeners;
98
41
  private closed;
99
42
  private constructor();
100
- static connect(creds: GatewayCredentials, userId: string, timeoutMs?: number): Promise<GatewayConnection>;
43
+ static connect(creds: GatewayCredentials, actor: GatewayActor, timeoutMs?: number): Promise<GatewayConnection>;
101
44
  call<T = any>(method: string, params: unknown, timeoutMs?: number): Promise<T>;
102
45
  onEvent(cb: (event: string, payload: any) => void): () => void;
103
46
  close(): void;
@@ -107,7 +50,12 @@ declare class GatewayConnection {
107
50
  declare function buildSessionKey(agent: string, conversationId: string): string;
108
51
  interface StreamChatOptions {
109
52
  creds: GatewayCredentials;
110
- userId: string;
53
+ /** Gateway user id (anonymous visitors). Ignored when `identitySession` or `connection` is set. */
54
+ userId?: string;
55
+ /** Dewee identity session: the gateway derives the user; no `user_id` is sent. */
56
+ identitySession?: string;
57
+ /** An already connected connection to use (and close) instead of opening one. */
58
+ connection?: GatewayConnection;
111
59
  agent: string;
112
60
  sessionKey: string;
113
61
  message: string;
@@ -117,7 +65,7 @@ interface StreamChatOptions {
117
65
  /** Runs one chat turn and yields normalized stream events until the run ends. */
118
66
  declare function streamChat(opts: StreamChatOptions): AsyncGenerator<ChatStreamEvent>;
119
67
  /** Fetches a session transcript and folds tool calls/results into assistant turns. */
120
- declare function fetchHistory(creds: GatewayCredentials, userId: string, agent: string, sessionKey: string): Promise<HistoryMessage[]>;
68
+ declare function fetchHistory(creds: GatewayCredentials, actor: GatewayActor, agent: string, sessionKey: string): Promise<HistoryMessage[]>;
121
69
  declare function foldHistory(raw: any[]): HistoryMessage[];
122
70
  /** Lists agents via the gateway REST API. */
123
71
  declare function listAgents(creds: GatewayCredentials): Promise<AgentInfo[]>;
@@ -146,4 +94,14 @@ declare function buildPageBlock(p: PageBlockInput): string;
146
94
  /** Removes a leading page block from a stored user message (history display). */
147
95
  declare function stripPageBlock(content: string): string;
148
96
 
149
- export { ACTION_LIMITS, ActionManifestEntry, AgentInfo, ChatStreamEvent, type DeweeHandlerOptions, GatewayConnection, type GatewayCredentials, GatewayError, HistoryMessage, type RateLimiter, type StreamChatOptions, buildPageBlock, buildSessionKey, createDeweeHandler, fetchHistory, foldHistory, hashManifest, listAgents, memoryRateLimiter, normalizeManifest, optionsFromEnv, signVisitorToken, streamChat, stripPageBlock, toNodeHandler, verifyVisitorToken };
97
+ /** Cooldown when a `RATE_LIMITED` refusal carries no usable `retryAfterMs`. */
98
+ declare const DEFAULT_RETRY_AFTER_MS = 5000;
99
+ /** Upper bound of the cooldown passed to the browser, so a bogus value cannot lock the widget for long. */
100
+ declare const MAX_RETRY_AFTER_MS = 600000;
101
+ type AdmissionErrorEvent = Extract<ChatStreamEvent, {
102
+ type: "error";
103
+ }>;
104
+ /** The SSE `error` event of an admission refusal. Only `RATE_LIMITED` carries `retryAfterMs`. */
105
+ declare function admissionErrorEvent(code: AdmissionErrorCode, retryAfterMs?: unknown, gatewayReason?: string): AdmissionErrorEvent;
106
+
107
+ export { ACTION_LIMITS, ActionManifestEntry, AdmissionErrorCode, AgentInfo, ChatStreamEvent, DEFAULT_RETRY_AFTER_MS, type GatewayActor, GatewayConnection, type GatewayCredentials, GatewayError, HistoryMessage, MAX_RETRY_AFTER_MS, Remediation, type StreamChatOptions, admissionErrorEvent, buildPageBlock, buildSessionKey, fetchHistory, foldHistory, hashManifest, listAgents, normalizeManifest, streamChat, stripPageBlock, toNodeHandler };