ai-ax 0.6.0 → 0.8.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 CHANGED
@@ -127,7 +127,7 @@ Browsers always connect to the alias room `my-room`, and the worker rewrites it
127
127
  | `ai-ax/react` | `useClient`, `Client`, `atom`, `setAtom`, `useAtomValue` | browser (React) |
128
128
  | `ai-ax/const` | protocol constants (paths, header names) | both |
129
129
 
130
- The worker expects a Durable Object binding named `v1` pointing at the exported `Server` class, and the environment needs `AUTH_SECRET`, the OAuth client credentials and `ANTHROPIC_API_KEY`. Config keys of `x(params, config)` and `hono(ai, extra)`:
130
+ The worker expects a Durable Object binding named `v1` pointing at the exported `Server` class, and the environment needs `AUTH_SECRET`, the OAuth client credentials and `ANTHROPIC_API_KEY`. Every environment-dependent value is a config resolver of the shape `(env) => string`, so the app decides which variable to read — `domain: (env) => env.AUTH_DOMAIN` is only a convention, not a requirement. `domain` returns the host tail that follows the service name (`.glre.dev` in production, `-dev.glre.dev` in staging) and shares the session cookie across every service of that environment: its first `.` onward becomes the cookie domain and the part before it becomes a per-environment cookie name suffix, so production and staging sessions never mix even under one apex. `apiKey` resolves the Claude API key the same way and has no built-in variable name at all; `secret` falls back to `AUTH_SECRET` only because Auth.js itself owns that convention (as it owns `AUTH_URL`). Config keys of `x(params, config)` and `hono(ai, extra)`:
131
131
 
132
132
  | key | type | default | meaning |
133
133
  | --------- | -------------------------- | ----------------------------------------- | ----------------------------------------------------- |
@@ -153,7 +153,9 @@ The worker expects a Durable Object binding named `v1` pointing at the exported
153
153
  | version | `string` | `'1.0.0'` | MCP server version string |
154
154
  | salt | `string` | `'authjs.mcp-token'` | grant jwt salt, separates services |
155
155
  | maxAge | `number` | `43200` (12h) | grant jwt lifetime in seconds |
156
- | cookie | `{ apex, services }` | none | services sharing a session cookie across subdomains |
157
156
  | providers | `any[]` | Google | Auth.js providers |
157
+ | domain | `(env) => string` | none | host tail after the service name, shares the cookie |
158
+ | apiKey | `(env) => string` | none | Claude API key resolver |
159
+ | secret | `(env) => string` | `env.AUTH_SECRET` | Auth.js / grant jwt secret resolver |
158
160
 
159
161
  The `x-user-sub` / `x-user-path` header names and the anthropic-version are internal protocol constants and intentionally not configurable, because both ends of each protocol must change together.
package/dist/client.d.ts CHANGED
@@ -1,2 +1,33 @@
1
- import { a as StreamSend, c as createStream, i as StreamItem, n as client, o as StreamTool, r as hydrate, s as StreamUpdate, t as Route } from "./client-DG7hCEbP.js";
2
- export { Route, type StreamItem, type StreamSend, type StreamTool, type StreamUpdate, client, createStream, hydrate };
1
+ import { Route } from "./types.js";
2
+ //#region src/client/stream.d.ts
3
+ interface StreamTool {
4
+ server: string;
5
+ name: string;
6
+ }
7
+ interface StreamItem {
8
+ text: string;
9
+ tools: StreamTool[];
10
+ error?: boolean;
11
+ }
12
+ interface StreamSend {
13
+ prompt: string;
14
+ path?: string;
15
+ model?: string;
16
+ messages?: any[];
17
+ headers?: Record<string, string>;
18
+ }
19
+ interface StreamUpdate {
20
+ items: StreamItem[];
21
+ delta: string;
22
+ raw: string;
23
+ }
24
+ declare const createStream: (endpoint?: string) => {
25
+ parse: (raw: string) => StreamItem[];
26
+ send: (input: StreamSend, update?: (u: StreamUpdate) => void) => Promise<StreamItem[]>;
27
+ };
28
+ //#endregion
29
+ //#region src/client.d.ts
30
+ declare const client: <T extends object>(ai: T, route?: Route) => T;
31
+ declare const hydrate: <T extends object>(ai: T, entries: Record<string, any>, wake?: (key: string, value: any) => any) => T;
32
+ //#endregion
33
+ export { type Route, type StreamItem, type StreamSend, type StreamTool, type StreamUpdate, client, createStream, hydrate };
package/dist/hono.js CHANGED
@@ -1,2 +1,2 @@
1
- import{PATH_HEADER as e,SUB_HEADER as t}from"./const.js";import{createMiddleware as n}from"hono/factory";import r from"@auth/core/providers/google";import{decode as i,encode as a}from"@auth/core/jwt";import{getAuthUser as o,initAuthConfig as s}from"@hono/auth-js";import{env as c}from"hono/adapter";import{streamText as l}from"hono/streaming";import{StreamableHTTPTransport as u}from"@hono/mcp";import{McpServer as d}from"@modelcontextprotocol/sdk/server/mcp.js";import{getServerByName as f,routePartykitRequest as p}from"partyserver";const m=`authjs.mcp-token`,h=e=>s(t=>{let n=new URL(t.req.url).host,i=!!e.cookie&&e.cookie.services.some(t=>n===`${t}.${e.cookie.apex}`),a={sessionToken:{options:{domain:`.${e.cookie?.apex}`}}},o=e.providers??[r({clientId:t.env.GOOGLE_CLIENT_ID,clientSecret:t.env.GOOGLE_CLIENT_SECRET})];return{...e.adapter?{adapter:e.adapter(t.env)}:{},providers:o,secret:t.env.AUTH_SECRET,session:{strategy:`jwt`},...i?{cookies:a}:{}}}),g=async e=>(await o(e))?.token?.sub??``,_=(e,t,n,r)=>a({token:{sub:t,path:n},secret:c(e).AUTH_SECRET,salt:r?.salt??m,maxAge:r?.maxAge??43200}),v=async(e,t)=>{let n=(e.req.header(`Authorization`)??``).replace(/^Bearer\s+/i,``);if(!n)return null;let r=await i({token:n,secret:c(e).AUTH_SECRET,salt:t?.salt??m}).catch(()=>null);return{sub:r?.sub??``,path:r?.path??``}},y=e=>e.startsWith(`data:`)?JSON.parse(e.slice(5)):null,b=(e,t,n)=>fetch(e.api,{method:`POST`,headers:{"x-api-key":e.key,"anthropic-version":`2023-06-01`,"anthropic-beta":`mcp-client-2025-11-20`,"content-type":`application/json`},body:JSON.stringify({model:e.model,max_tokens:e.maxTokens,stream:!0,cache_control:{type:`ephemeral`},system:e.system,mcp_servers:[{type:`url`,url:e.url,name:e.name,...t?{authorization_token:t}:{}}],tools:[{type:`mcp_toolset`,mcp_server_name:e.name}],messages:n})}),x=async(e,t)=>{let n=[],r=null,i=0,a=0,o=0,s=``,c=e.body.getReader(),l=new TextDecoder,u=``;for(;;){let{done:e,value:d}=await c.read();if(e)break;u+=l.decode(d,{stream:!0});let f=u.split(`
2
- `);u=f.pop()??``;for(let e of f){let c=y(e);if(c){if(c.type===`message_start`){let e=c.message?.usage??{};i+=(e.input_tokens??0)+(e.cache_creation_input_tokens??0)+(e.cache_read_input_tokens??0),a+=e.cache_read_input_tokens??0}c.type===`message_delta`&&(o=c.usage?.output_tokens??o,s=c.delta?.stop_reason??s),c.type===`content_block_start`&&(r={...c.content_block},n.push(r),r.type===`mcp_tool_use`&&await t(`\n[tool] ${r.server_name} ${r.name}\n`)),c.type===`content_block_delta`&&c.delta?.type===`text_delta`&&(r.text=(r.text??``)+c.delta.text,await t(c.delta.text)),c.type===`content_block_delta`&&c.delta?.type===`input_json_delta`&&(r.partial=(r.partial??``)+c.delta.partial_json),c.type===`content_block_delta`&&c.delta?.type===`thinking_delta`&&(r.thinking=(r.thinking??``)+c.delta.thinking),c.type===`content_block_delta`&&c.delta?.type===`signature_delta`&&(r.signature=(r.signature??``)+c.delta.signature),c.type===`content_block_stop`&&r?.partial!==void 0&&(r.input=r.partial?JSON.parse(r.partial):{},delete r.partial)}}}return{blocks:n,input:i,cached:a,output:o,stop:s}},S=async(e,t,n,r,i,a=10)=>{let o=r,s=0,c=0,l=0,u=``;for(let r=0;r<a;r++){let r=await x(o,i);if(s+=r.input,c+=r.cached,l+=r.output,u=r.stop||u,u!==`pause_turn`)break;if(n.push({role:`assistant`,content:r.blocks.filter(e=>e.type!==`thinking`||e.thinking||e.signature)}),o=await b(e,await t(),n),!o.ok){await i(`\n[error] ${(await o.text()).replace(/\n/g,` `)}\n`);break}}await i(`\n[usage] input ${s} (cache ${c}) / output ${l} tokens (${u})\n`)},C=e=>n(async t=>{let n=await g(t),{path:r=``,prompt:i,model:a=``,messages:o=[]}=await t.req.json(),s=!!e.lobby&&!r;if(!s&&!n)return t.text(`Unauthorized`,401);if(!s&&!await(e.own??(()=>``))({env:c(t),sub:n,path:r}))return t.text(`Forbidden`,403);let u=e.host??t.req.header(`x-original-host`)??t.req.header(`x-forwarded-host`)??new URL(t.req.url).host,d={key:c(t).ANTHROPIC_API_KEY,api:e.claude??`https://api.anthropic.com/v1/messages`,name:e.name??`aiax`,url:`https://${u}${e.endpoint??`/api/mcp`}`,model:a||e.model||`claude-sonnet-5`,system:e.system??``,maxTokens:e.maxTokens??32e3},f=()=>s?Promise.resolve(``):_(t,n,r,e),p=[...o,{role:`user`,content:i}],m=await b(d,await f(),p);return m.ok?l(t,t=>S(d,f,p,m,e=>t.write(e),e.maxTurns??10)):t.text(await m.text(),500)}),w=async(n,r,i,a,o)=>{let s=await f(n,r),c={[t]:i.sub,[e]:encodeURIComponent(i.path)};return(await s.fetch(`https://internal/act`,{method:`POST`,headers:c,body:JSON.stringify({name:a,input:o})})).json()},T=(e,t)=>n(async n=>{let r=await v(n,t),i=r?.sub??``,a=r?.path??``,o=t.lobby??``;if(r||!o){if(!i)return n.text(`Unauthorized`,401);if(o=await(t.own??(()=>``))({env:c(n),sub:i,path:a}),!o)return n.text(`Forbidden`,403)}let s=new d({name:t.name??`aiax`,version:t.version??`1.0.0`}),l=new u;return e.actions.forEach((e,r)=>s.registerTool(r,{description:e.description,inputSchema:{...e.input}},async e=>{let s=await w(c(n)[t.binding??`v1`],o,{sub:i,path:a},r,e);return{content:[{type:`text`,text:JSON.stringify(s)}]}})),await s.connect(l),l.handleRequest(n)}),E=async(n,r,i,a)=>{let o=new Headers(n.req.raw.headers);o.set(t,i),o.set(e,encodeURIComponent(a));let s=new URL(n.req.url),l=s.pathname.split(`/`);l[3]=encodeURIComponent(r),s.pathname=l.join(`/`);let u=new Request(s,new Request(n.req.raw,{headers:o}));return await p(u,c(n))??n.text(`Not Found`,404)},D=e=>n(async t=>{let n=decodeURIComponent(t.req.path.split(`/`)[3]??``),r=t.req.query(`path`)??``,i=await g(t);if(e.lobby&&n===e.lobby)return E(t,n,i,r);if(!i)return t.text(`Unauthorized`,401);let a=await(e.own??(()=>``))({env:c(t),sub:i,path:r});return!a||n!==a&&n!==(e.alias??`my-room`)?t.text(`Forbidden`,403):E(t,a,i,r)}),O=(e,t={})=>{let r=Object.assign(e.config,t),i={auth:h(r),party:D(r),mcp:T(e,r),llm:C(r)};return n(async(e,t)=>{let n=()=>e.req.path.startsWith(`/parties/`)?i.party(e,t):e.req.path===(r.endpoint??`/api/mcp`)?i.mcp(e,t):e.req.path===(r.relay??`/api/llm`)&&e.req.method===`POST`?i.llm(e,t):t(),a;if(await i.auth(e,async()=>void(a=await n())),a)return a})};export{O as hono};
1
+ import{PATH_HEADER as e,SUB_HEADER as t}from"./const.js";import{createMiddleware as n}from"hono/factory";import r from"@auth/core/providers/google";import{decode as i,encode as a}from"@auth/core/jwt";import{getAuthUser as o,initAuthConfig as s}from"@hono/auth-js";import{env as c}from"hono/adapter";import{streamText as l}from"hono/streaming";import{StreamableHTTPTransport as u}from"@hono/mcp";import{McpServer as d}from"@modelcontextprotocol/sdk/server/mcp.js";import{getServerByName as f,routePartykitRequest as p}from"partyserver";const m=`authjs.mcp-token`,h=e=>s(t=>{let n=String(e.domain?.(t.env)??``),i=n.indexOf(`.`),a=i>=0&&new URL(t.req.url).host.endsWith(n),o=n.slice(0,i),s={sessionToken:{...o?{name:`authjs.session-token${o}`}:{},options:{domain:n.slice(i)}}},c=e.providers??[r({clientId:t.env.GOOGLE_CLIENT_ID,clientSecret:t.env.GOOGLE_CLIENT_SECRET})];return{...e.adapter?{adapter:e.adapter(t.env)}:{},providers:c,secret:e.secret?.(t.env)??t.env.AUTH_SECRET,session:{strategy:`jwt`},...a?{cookies:s}:{}}}),g=async e=>(await o(e))?.token?.sub??``,_=(e,t,n,r)=>a({token:{sub:t,path:n},secret:r?.secret?.(c(e))??c(e).AUTH_SECRET,salt:r?.salt??m,maxAge:r?.maxAge??43200}),v=async(e,t)=>{let n=(e.req.header(`Authorization`)??``).replace(/^Bearer\s+/i,``);if(!n)return null;let r=await i({token:n,secret:t?.secret?.(c(e))??c(e).AUTH_SECRET,salt:t?.salt??m}).catch(()=>null);return{sub:r?.sub??``,path:r?.path??``}},y=e=>e.startsWith(`data:`)?JSON.parse(e.slice(5)):null,b=(e,t,n)=>fetch(e.api,{method:`POST`,headers:{"x-api-key":e.key,"anthropic-version":`2023-06-01`,"anthropic-beta":`mcp-client-2025-11-20`,"content-type":`application/json`},body:JSON.stringify({model:e.model,max_tokens:e.maxTokens,stream:!0,cache_control:{type:`ephemeral`},system:e.system,mcp_servers:[{type:`url`,url:e.url,name:e.name,...t?{authorization_token:t}:{}}],tools:[{type:`mcp_toolset`,mcp_server_name:e.name}],messages:n})}),x=async(e,t)=>{let n=[],r=null,i=0,a=0,o=0,s=``,c=e.body.getReader(),l=new TextDecoder,u=``;for(;;){let{done:e,value:d}=await c.read();if(e)break;u+=l.decode(d,{stream:!0});let f=u.split(`
2
+ `);u=f.pop()??``;for(let e of f){let c=y(e);if(c){if(c.type===`message_start`){let e=c.message?.usage??{};i+=(e.input_tokens??0)+(e.cache_creation_input_tokens??0)+(e.cache_read_input_tokens??0),a+=e.cache_read_input_tokens??0}c.type===`message_delta`&&(o=c.usage?.output_tokens??o,s=c.delta?.stop_reason??s),c.type===`content_block_start`&&(r={...c.content_block},n.push(r),r.type===`mcp_tool_use`&&await t(`\n[tool] ${r.server_name} ${r.name}\n`)),c.type===`content_block_delta`&&c.delta?.type===`text_delta`&&(r.text=(r.text??``)+c.delta.text,await t(c.delta.text)),c.type===`content_block_delta`&&c.delta?.type===`input_json_delta`&&(r.partial=(r.partial??``)+c.delta.partial_json),c.type===`content_block_delta`&&c.delta?.type===`thinking_delta`&&(r.thinking=(r.thinking??``)+c.delta.thinking),c.type===`content_block_delta`&&c.delta?.type===`signature_delta`&&(r.signature=(r.signature??``)+c.delta.signature),c.type===`content_block_stop`&&r?.partial!==void 0&&(r.input=r.partial?JSON.parse(r.partial):{},delete r.partial)}}}return{blocks:n,input:i,cached:a,output:o,stop:s}},S=async(e,t,n,r,i,a=10)=>{let o=r,s=0,c=0,l=0,u=``;for(let r=0;r<a;r++){let r=await x(o,i);if(s+=r.input,c+=r.cached,l+=r.output,u=r.stop||u,u!==`pause_turn`)break;if(n.push({role:`assistant`,content:r.blocks.filter(e=>e.type!==`thinking`||e.thinking||e.signature)}),o=await b(e,await t(),n),!o.ok){await i(`\n[error] ${(await o.text()).replace(/\n/g,` `)}\n`);break}}await i(`\n[usage] input ${s} (cache ${c}) / output ${l} tokens (${u})\n`)},C=e=>n(async t=>{let n=await g(t),{path:r=``,prompt:i,model:a=``,messages:o=[]}=await t.req.json(),s=!!e.lobby&&!r;if(!s&&!n)return t.text(`Unauthorized`,401);if(!s&&!await(e.own??(()=>``))({env:c(t),sub:n,path:r}))return t.text(`Forbidden`,403);let u=e.host??t.req.header(`x-original-host`)??t.req.header(`x-forwarded-host`)??new URL(t.req.url).host,d={key:e.apiKey?.(c(t))??``,api:e.claude??`https://api.anthropic.com/v1/messages`,name:e.name??`aiax`,url:`https://${u}${e.endpoint??`/api/mcp`}`,model:a||e.model||`claude-sonnet-5`,system:e.system??``,maxTokens:e.maxTokens??32e3},f=()=>s?Promise.resolve(``):_(t,n,r,e),p=[...o,{role:`user`,content:i}],m=await b(d,await f(),p);return m.ok?l(t,t=>S(d,f,p,m,e=>t.write(e),e.maxTurns??10)):t.text(await m.text(),500)}),w=async(n,r,i,a,o)=>{let s=await f(n,r),c={[t]:i.sub,[e]:encodeURIComponent(i.path)};return(await s.fetch(`https://internal/act`,{method:`POST`,headers:c,body:JSON.stringify({name:a,input:o})})).json()},T=(e,t)=>n(async n=>{let r=await v(n,t),i=r?.sub??``,a=r?.path??``,o=t.lobby??``;if(r||!o){if(!i)return n.text(`Unauthorized`,401);if(o=await(t.own??(()=>``))({env:c(n),sub:i,path:a}),!o)return n.text(`Forbidden`,403)}let s=new d({name:t.name??`aiax`,version:t.version??`1.0.0`}),l=new u;return e.actions.forEach((e,r)=>s.registerTool(r,{description:e.description,inputSchema:{...e.input}},async e=>{let s=await w(c(n)[t.binding??`v1`],o,{sub:i,path:a},r,e);return{content:[{type:`text`,text:JSON.stringify(s)}]}})),await s.connect(l),l.handleRequest(n)}),E=async(n,r,i,a)=>{let o=new Headers(n.req.raw.headers);o.set(t,i),o.set(e,encodeURIComponent(a));let s=new URL(n.req.url),l=s.pathname.split(`/`);l[3]=encodeURIComponent(r),s.pathname=l.join(`/`);let u=new Request(s,new Request(n.req.raw,{headers:o}));return await p(u,c(n))??n.text(`Not Found`,404)},D=e=>n(async t=>{let n=decodeURIComponent(t.req.path.split(`/`)[3]??``),r=t.req.query(`path`)??``,i=await g(t);if(e.lobby&&n===e.lobby)return E(t,n,i,r);if(!i)return t.text(`Unauthorized`,401);let a=await(e.own??(()=>``))({env:c(t),sub:i,path:r});return!a||n!==a&&n!==(e.alias??`my-room`)?t.text(`Forbidden`,403):E(t,a,i,r)}),O=(e,t={})=>{let r=Object.assign(e.config,t),i={auth:h(r),party:D(r),mcp:T(e,r),llm:C(r)};return n(async(e,t)=>{let n=()=>e.req.path.startsWith(`/parties/`)?i.party(e,t):e.req.path===(r.endpoint??`/api/mcp`)?i.mcp(e,t):e.req.path===(r.relay??`/api/llm`)&&e.req.method===`POST`?i.llm(e,t):t(),a;if(await i.auth(e,async()=>void(a=await n())),a)return a})};export{O as hono};
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { ActionDef, Ai, Config, Cookie, Define, Grant, Own, Peer, Saved, Side } from "./types.js";
1
+ import { ActionDef, Ai, Config, Define, Grant, Own, Peer, Saved, Side } from "./types.js";
2
2
  //#region src/index.d.ts
3
3
  declare const side: Side;
4
4
  declare function x<P extends object>(params: P, config?: Config): Ai<P>;
5
5
  declare function x<P extends object = {}>(params?: Partial<P>, config?: Config): Ai<P>;
6
6
  //#endregion
7
- export { type ActionDef, type Ai, type Config, type Cookie, type Define, type Grant, type Own, type Peer, type Saved, type Side, side, x };
7
+ export { type ActionDef, type Ai, type Config, type Define, type Grant, type Own, type Peer, type Saved, type Side, side, x };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import*as e from"yjs";const t=(t,n)=>{let r=t.ui??[],i=e=>r.some(t=>t.endsWith(`/`)?e.startsWith(t):e===t),a=new WeakMap,o=e=>{for(let t of e.changed.values())for(let e of t)if(e===null||!i(e))return!0;return!1};return{rows(e){let t=[];return n().forEach((n,r)=>r.startsWith(e)&&!r.slice(e.length).includes(`/`)&&t.push(n)),t.sort((e,t)=>(e?.pos??0)-(t?.pos??0))},history(r){let i=n();return a.has(i)||a.set(i,new e.UndoManager(i,{_captureTransaction:o,...t.history,...r})),a.get(i)},snapshot(){let t=new e.Doc,r=t.getMap(`tree`);return t.transact(()=>n().forEach((t,n)=>!i(n)&&r.set(n,t instanceof e.AbstractType?t.clone():t))),e.encodeStateAsUpdate(t)}}},n=(t,n)=>{let r=new e.Doc,i=new WeakSet,a=new WeakMap,o=new Map,s=(e,c)=>{e&&(r=e),c&&a.set(r,c);let l=r;if(i.has(l))return;i.add(l);let u=l.getMap(`act-req`),d=l.getMap(`act-res`),f=async e=>{let r=u.get(e),i=n.get(r?.name);if(!i||i.side!==t)return;u.delete(e);let o=a.get(l)??(e=>e());d.set(e,{value:await o(()=>(s(l),i.run(r.input)))})},p=e=>{let t=o.get(e);!t||!d.has(e)||(o.delete(e),t(d.get(e).value),d.delete(e))};u.observe(e=>e.keysChanged.forEach(f)),d.observe(e=>e.keysChanged.forEach(p))};return{open:s,data:(e=`tree`)=>r.getMap(e),call(e,i){let a=n.get(e);return a?a.side===t||a.side===`both`?(s(),Promise.resolve(a.run(i))):new Promise(t=>{let n=crypto.randomUUID();o.set(n,t),r.getMap(`act-req`).set(n,{name:e,input:i})}):Promise.reject(Error(`unknown action: ${e}`))}}},r=e=>!!e&&typeof e.parse==`function`,i=e=>r(e)?{value:e}:e,a=(e,t)=>r(e)&&t&&typeof t==`object`&&`value`in t?t.value:t,o=(e,t,n)=>{let r=[],o=(e,r)=>i=>{let a=t.get(e);return a?a(i,r,n()):r(i)};return{chain:o,missing:e=>()=>Promise.reject(Error(`not implemented: ${e}`)),describe(e,t){return t?(r=[...r,e],t(n()),r=r.slice(0,-1),n()):n()},define:t=>(s,...c)=>{let l=c.find(e=>typeof e==`string`)??``,u=c.find(e=>typeof e==`function`),d=c.find(e=>e&&typeof e==`object`),f=async e=>{let t=a(d,e),r=await u(t,n());return typeof r==`function`?r(t,n()):r&&r.default?r.default(t,n()):r},p=[...r,l].filter(Boolean).join(` `);return e.set(s,{name:s,description:p,side:t,input:i(d),run:o(s,f)}),n()}}},s=typeof window>`u`?`server`:`client`;function c(e={},r={}){let i=new Map,a=new Map,c=new Set,l=n(s,i),u=t(r,l.data),d=o(i,a,()=>m),f=async()=>{let e={};return l.data().forEach((t,n)=>e[n]=t),e},p={config:r,side:s,actions:i,action:d.define(`both`),client:d.define(`client`),server:d.define(`server`),describe:d.describe,abstract:e=>(c.add(e),m),override:(e,t)=>(a.set(e,t),m),data:l.data,open:(e,t)=>(l.open(e,t),m),call:l.call,rows:u.rows,scan:e=>{let t=[];return l.data().forEach((n,r)=>r.startsWith(e)&&t.push(n)),t},wipe:e=>{let t=[];l.data().forEach((n,r)=>r.startsWith(e)&&t.push(r)),t.forEach(e=>l.data().delete(e))},tx:(e,t)=>l.data().doc.transact(e,t),history:u.history,snapshot:u.snapshot};i.set(`get_tree`,{name:`get_tree`,description:r.tree??`Dump every key/value of the shared tree to observe the current state before acting`,side:`both`,run:d.chain(`get_tree`,f)});let m=new Proxy(p,{get(t,n){if(typeof n!=`string`||n in t)return t[n];if(i.has(n))return e=>l.call(n,e);if(c.has(n))return d.chain(n,d.missing(n));if(n!==`then`&&n!==`toJSON`)return l.data().get(n)??e[n]},set(e,t,n){return typeof t!=`string`||t in e?(e[t]=n,!0):(l.data().set(t,n),!0)},deleteProperty(e,t){return typeof t!=`string`||t in e||l.data().delete(t),!0}});return m}export{s as side,c as x};
1
+ import*as e from"yjs";const t=(t,n)=>{let r=t.ui??[],i=e=>r.some(t=>t.endsWith(`/`)?e.startsWith(t):e===t),a=new WeakMap,o=e=>{for(let t of e.changed.values())for(let e of t)if(e===null||!i(e))return!0;return!1};return{rows(e){let t=[];return n().forEach((n,r)=>r.startsWith(e)&&!r.slice(e.length).includes(`/`)&&t.push(n)),t.sort((e,t)=>(e?.pos??0)-(t?.pos??0))},history(r){let i=n();return a.has(i)||a.set(i,new e.UndoManager(i,{captureTransaction:o,...t.history,...r})),a.get(i)},snapshot(){let t=new e.Doc,r=t.getMap(`tree`);return t.transact(()=>n().forEach((t,n)=>!i(n)&&r.set(n,t instanceof e.AbstractType?t.clone():t))),e.encodeStateAsUpdate(t)}}},n=(t,n)=>{let r=null,i=()=>r??=new e.Doc,a=new WeakSet,o=new WeakMap,s=new Map,c=(e,l)=>{e&&(r=e),l&&o.set(i(),l);let u=i();if(a.has(u))return;a.add(u);let d=u.getMap(`act-req`),f=u.getMap(`act-res`),p=async e=>{let r=d.get(e),i=n.get(r?.name);if(!i||i.side!==t)return;d.delete(e);let a=o.get(u)??(e=>e());f.set(e,{value:await a(()=>(c(u),i.run(r.input)))})},m=e=>{let t=s.get(e);!t||!f.has(e)||(s.delete(e),t(f.get(e).value),f.delete(e))};d.observe(e=>e.keysChanged.forEach(p)),f.observe(e=>e.keysChanged.forEach(m))};return{open:c,data:(e=`tree`)=>i().getMap(e),call(e,r){let a=n.get(e);return a?a.side===t||a.side===`both`?(c(),Promise.resolve(a.run(r))):new Promise(t=>{let n=crypto.randomUUID();s.set(n,t),i().getMap(`act-req`).set(n,{name:e,input:r})}):Promise.reject(Error(`unknown action: ${e}`))}}},r=e=>!!e&&typeof e.parse==`function`,i=e=>r(e)?{value:e}:e,a=(e,t)=>r(e)&&t&&typeof t==`object`&&`value`in t?t.value:t,o=(e,t,n)=>{let r=[],o=(e,r)=>i=>{let a=t.get(e);return a?a(i,r,n()):r(i)};return{chain:o,missing:e=>()=>Promise.reject(Error(`not implemented: ${e}`)),describe(e,t){return t?(r=[...r,e],t(n()),r=r.slice(0,-1),n()):n()},define:t=>(s,...c)=>{let l=c.find(e=>typeof e==`string`)??``,u=c.find(e=>typeof e==`function`),d=c.find(e=>e&&typeof e==`object`),f=async e=>{let t=a(d,e),r=await u(t,n());return typeof r==`function`?r(t,n()):r&&r.default?r.default(t,n()):r},p=[...r,l].filter(Boolean).join(` `);return e.set(s,{name:s,description:p,side:t,input:i(d),run:o(s,f)}),n()}}},s=typeof window>`u`?`server`:`client`;function c(e={},r={}){let i=new Map,a=new Map,c=new Set,l=n(s,i),u=t(r,l.data),d=o(i,a,()=>m),f=async()=>{let e={};return l.data().forEach((t,n)=>e[n]=t),e},p={config:r,side:s,actions:i,action:d.define(`both`),client:d.define(`client`),server:d.define(`server`),describe:d.describe,abstract:e=>(c.add(e),m),override:(e,t)=>(a.set(e,t),m),data:l.data,open:(e,t)=>(l.open(e,t),m),call:l.call,rows:u.rows,scan:e=>{let t=[];return l.data().forEach((n,r)=>r.startsWith(e)&&t.push(n)),t},wipe:e=>{let t=[];l.data().forEach((n,r)=>r.startsWith(e)&&t.push(r)),t.forEach(e=>l.data().delete(e))},tx:(e,t)=>l.data().doc.transact(e,t),history:u.history,snapshot:u.snapshot};i.set(`get_tree`,{name:`get_tree`,description:r.tree??`Dump every key/value of the shared tree to observe the current state before acting`,side:`both`,run:d.chain(`get_tree`,f)});let m=new Proxy(p,{get(t,n){if(typeof n!=`string`||n in t)return t[n];if(i.has(n))return e=>l.call(n,e);if(c.has(n))return d.chain(n,d.missing(n));if(n!==`then`&&n!==`toJSON`)return l.data().get(n)??e[n]},set(e,t,n){return typeof t!=`string`||t in e?(e[t]=n,!0):(l.data().set(t,n),!0)},deleteProperty(e,t){return typeof t!=`string`||t in e||l.data().delete(t),!0}});return m}export{s as side,c as x};
package/dist/react.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as Route } from "./client-DG7hCEbP.js";
1
+ import { Route } from "./types.js";
2
2
  import { ReactNode } from "react";
3
3
  //#region src/react.d.ts
4
4
  declare const atom: <T>(initial: T) => {
package/dist/types.d.ts CHANGED
@@ -22,9 +22,12 @@ interface Saved extends Peer {
22
22
  room: string;
23
23
  }
24
24
  type Own = (at: Peer) => Promise<string> | string;
25
- interface Cookie {
26
- apex: string;
27
- services: string[];
25
+ interface Route {
26
+ room?: string;
27
+ path?: string;
28
+ host?: string;
29
+ party?: string;
30
+ synced?: () => void;
28
31
  }
29
32
  interface Config {
30
33
  name?: string;
@@ -45,8 +48,10 @@ interface Config {
45
48
  version?: string;
46
49
  salt?: string;
47
50
  maxAge?: number;
48
- cookie?: Cookie;
49
51
  providers?: any[];
52
+ domain?: (env: any) => string;
53
+ apiKey?: (env: any) => string;
54
+ secret?: (env: any) => string;
50
55
  ui?: string[];
51
56
  history?: object;
52
57
  load?: (at: Saved) => Promise<any>;
@@ -89,4 +94,4 @@ type Ai<T extends object = {}> = T & {
89
94
  snapshot(): Uint8Array;
90
95
  };
91
96
  //#endregion
92
- export { ActionDef, Ai, Config, Cookie, Define, Grant, Own, Peer, Saved, Side };
97
+ export { ActionDef, Ai, Config, Define, Grant, Own, Peer, Route, Saved, Side };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-ax",
3
3
  "author": "tseijp",
4
- "version": "0.6.0",
4
+ "version": "0.8.0",
5
5
  "license": "MIT",
6
6
  "description": "AI Agent Experience (AI/AX) library for Hono + Cloudflare. One act surface for both human UI/UX and LLM MCP tools, with authentication, authorization, realtime sync and Claude API relay.",
7
7
  "keywords": [