@chatpanel/events 0.290.0 → 0.295.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/entitlement.js +1 -1
- package/kokoro-text.js +1 -1
- package/link-protocol.js +1 -1
- package/link-sync.js +5 -0
- package/note-merge.js +9 -9
- package/package.json +3 -1
package/entitlement.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
class S extends Error{constructor(t){super(t),this.name="EntitlementError"}}const m=Object.freeze(["free","pro","team"]),l=Object.freeze({free:0,pro:1,team:2}),u="https://api.chatpanel.net",C=Object.freeze({verify:`${u}/license/verify`,entitlement:`${u}/entitlement`,claim:`${u}/entitlement/claim`,entitlementChallenge:`${u}/entitlement/challenge`,release:`${u}/entitlement/release`,restore:`${u}/restore`}),h=Object.freeze({kty:"EC",crv:"P-256",x:"CmgKLC4e3xDMvwhbjVqF7jbDe1JhC1KKQi8JN3qVX_4",y:"r40l6fQiyCcJYqW-SvB4VoSyn4F36yhSt82ZAOSo78E"}),O="https://chatpanel.net/#pricing";function _(e="pro",t="",n=""){const r=new URL("https://chatpanel.net/");return t&&r.searchParams.set("install_id",t),e&&r.searchParams.set("plan",e),n&&r.searchParams.set("client",n),r.hash="pricing",r.toString()}const y=Object.freeze({localAgents:"free",byoModels:"free",urlContext:"free",liveMeetings:"free",multiTab:"pro",unlimitedAgents:"pro",customSkills:"pro",customAgents:"pro",advancedAgent:"pro",unlimitedNotes:"pro",unlimitedMeetings:"pro",structuredInsert:"pro",exportChats:"pro",autoBackup:"pro",promptLibrary:"pro",fileAttachments:"pro",watch:"pro",link:"pro",unlimitedPoolAgents:"pro",unlimitedTeams:"pro",unlimitedTeamRuns:"pro",unlimitedProjects:"pro",unlimitedBoardPosts:"pro",fullObservability:"pro",unlimitedRecipes:"pro",unlimitedSkills:"pro",unlimitedWidgets:"pro",unlimitedMcpTools:"pro",cloudSync:"team",sharedLibrary:"team",hostedBridge:"team",sso:"team"}),R=Object.freeze({unlimitedNotes:"Unlimited notes — Free keeps your first 10",unlimitedMeetings:"Unlimited meetings — Free keeps your first 10",multiTab:"Attach several tabs at once",unlimitedAgents:"Unlimited custom agents",customSkills:"Create & edit your own skills",advancedAgent:"Per-agent system prompts & working directories",structuredInsert:"Clean diagrams on Excalidraw, draw.io & tldraw — shapes placed as data, not pixel-drawn",exportChats:"Export conversations as Markdown",autoBackup:"Automatic daily backup of all your data to disk",watch:"Watch a page & act on changes — the agent reacts as the page updates",link:"ChatPanel Link — your phone reaches your computer's agents and models, and both keep the same chats, notes and meetings",unlimitedPoolAgents:"Unlimited agents in your roster — Free keeps 2 of your own",unlimitedTeams:"Unlimited agent teams and runs — Free keeps 1 team, 3 runs a day",unlimitedProjects:"Unlimited projects — Free keeps 1",fullObservability:"The whole run history in Observe — Free sees the last 24 hours",unlimitedRecipes:"Unlimited saved recipes — Free keeps 2",unlimitedSkills:"Unlimited skills — Free uses 3 at a time",unlimitedWidgets:"Unlimited widgets — Free keeps 3",unlimitedMcpTools:"Unlimited MCP tools — Free enables 10"}),U=Object.freeze({cloudSync:"Sync chats across your devices",sharedLibrary:"Shared team agents & skills",hostedBridge:"Hosted agents — no local bridge to run",sso:"SSO & admin controls"}),p=Object.freeze({notes:10,meetings:10,apiEndpoints:1,bridgeAgents:1,customAgents:1,attachmentsPerMessage:1,mcpServers:1,gatewayDestinations:1,webSearchEngines:3,webSearchesPerDay:50,fullRedactions:25,poolAgents:2,teams:1,teamRunsPerDay:3,projects:1,boardPostsPerDay:10,observeDays:1,recipes:2,skills:3,widgets:3,mcpTools:10}),g=Object.freeze({unlimitedAgents:"customAgents",customSkills:"skills",unlimitedPoolAgents:"poolAgents",unlimitedTeams:"teams",unlimitedTeamRuns:"teamRunsPerDay",unlimitedProjects:"projects",unlimitedBoardPosts:"boardPostsPerDay",unlimitedRecipes:"recipes",unlimitedSkills:"skills",unlimitedWidgets:"widgets",unlimitedMcpTools:"mcpTools"});function c(e,t=Date.now()){return!e||!m.includes(e.plan)||e.expiresAt&&t>e.expiresAt?"free":e.plan}function x(e,t=Date.now()){return{free:"Free",pro:"Pro",team:"Team"}[c(e,t)]}function b(e,t=Date.now()){return l[c(e,t)]>=l.pro}function j(e,t=Date.now()){return c(e,t)==="team"}function F(e,t,n=0,r=Date.now()){const i=c(e,r),o=g[t];if(o&&l[i]<l.pro)return n<p[o];const a=y[t]||"free";return l[i]>=l[a]}function M(e){const t=g[e];return t?p[t]:null}function N(e,t=Date.now()){return b(e,t)?0:t-p.observeDays*864e5}function L(e){return y[e]||"free"}function B(e,t,n,r=Date.now()){if(b(e,r))return!0;const i=p[t];return typeof i!="number"||n<i}function d(e){const t="=".repeat((4-String(e).length%4)%4),n=String(e).replace(/-/g,"+").replace(/_/g,"/")+t;if(typeof Buffer<"u")return new Uint8Array(Buffer.from(n,"base64"));const r=atob(n),i=new Uint8Array(r.length);for(let o=0;o<r.length;o++)i[o]=r.charCodeAt(o);return i}function A(e){try{return JSON.parse(new TextDecoder().decode(d(e)))}catch{return null}}let f=null;async function E(e){const t=e||globalThis.crypto?.subtle;if(!t)throw new S("no WebCrypto available on this runtime");return e?t.importKey("jwk",h,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"]):(f||(f=t.importKey("jwk",h,{name:"ECDSA",namedCurve:"P-256"},!1,["verify"])),f)}const T="ent";async function K(e,{typ:t=null,subtle:n=null,now:r=Date.now()}={}){if(!e||typeof e!="string"||e.indexOf(".")<0)return null;const[i,o]=e.split(".");if(!i||!o)return null;let a=!1;try{a=await(n||globalThis.crypto?.subtle).verify({name:"ECDSA",hash:"SHA-256"},await E(n),d(o),new TextEncoder().encode(i))}catch{return null}if(!a)return null;const s=A(i);return!s||t&&s.typ!==t||s.exp&&r>Number(s.exp)?null:s}async function P(e,t,{subtle:n=null,now:r=Date.now()}={}){if(!e||typeof e!="string"||e.indexOf(".")<0)return null;const[i,o]=e.split(".");if(!i||!o)return null;let a=!1;try{a=await(n||globalThis.crypto?.subtle).verify({name:"ECDSA",hash:"SHA-256"},await E(n),d(o),new TextEncoder().encode(i))}catch{return null}if(!a)return null;const s=A(i);return!s||s.typ!==T||s.exp&&r>Number(s.exp)||!s.install_id||t&&s.install_id!==t||!m.includes(s.plan)?null:s}function D(e,{at:t=Date.now(),expiresAt:n=0}={}){return e?{plan:e.plan,trial:!!e.trial,expiresAt:Number(n)||0,tokenExp:Number(e.exp)||0,installId:e.install_id||"",sub:e.sub||null,checkedAt:t,source:"entitlement"}:{plan:"free"}}const v=720*60*1e3;function z(e,{now:t=Date.now(),interval:n=v}={}){if(!e||!e.checkedAt||t-e.checkedAt>n)return!0;const r=1440*60*1e3;return!!(e.expiresAt&&e.expiresAt-t<r||e.tokenExp&&e.tokenExp-t<r)}async function I(e,{installId:t="",token:n="",subtle:r=null,now:i=Date.now()}={}){const o={plan:"free",status:"inactive"};if(!e||typeof e!="object")return o;if(!m.includes(e.plan)||e.plan==="free")return{...e,plan:"free"};const a=await P(n||e.token||"",t,{subtle:r,now:i});return a?{...e,...D(a,{at:e.checkedAt||i,expiresAt:e.expiresAt||0})}:{...o,status:"lapsed",source:e.source||""}}function w(e,t=Date.now()){return!!(e&&e.trial)&&c(e,t)!=="free"}function W(e,t=Date.now()){return w(e,t)?`${x(e,t)} trial`:x(e,t)}function $(e,t=Date.now()){return!w(e,t)||!e.expiresAt?null:Math.max(0,Math.ceil((e.expiresAt-t)/864e5))}export{u as API_BASE,g as COUNTED,C as ENDPOINTS,h as ENTITLEMENT_PUBLIC_JWK,S as EntitlementError,y as FEATURE_TIER,p as FREE_LIMITS,m as PLANS,R as PRO_FEATURES,v as RECHECK_INTERVAL_MS,U as TEAM_FEATURES,T as TOKEN_TYPE,O as UPGRADE_URL,F as can,_ as checkoutUrl,M as freeCap,b as isPro,j as isTeam,w as isTrial,D as licenseFromPayload,z as needsRecheck,N as observeSince,W as planBadge,x as planLabel,c as planOf,L as tierFor,$ as trialDaysLeft,I as trustedLicense,P as verifyEntitlement,K as verifySignedToken,B as withinFreeLimit};
|
package/kokoro-text.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const u=Object.freeze({id:"onnx-community/Kokoro-82M-v1.0-ONNX",revision:"1939ad2a8e416c0acfeecc08a694d14ef25f2231",license:"Apache-2.0",file:"onnx/model_quantized.onnx",bytes:92361116,sha256:"fbae9257e1e05ffc727e951ef9b9c98418e6d79f1c9b6b13bd59f5c9028a1478",sampleRate:24e3,styleDim:256,maxTokens:510});function K(e){return`https://huggingface.co/${u.id}/resolve/${u.revision}/${e}`}const O=Object.freeze([{id:"af_heart",label:"Heart",accent:"US",gender:"female",grade:"A",sha256:"d583ccff3cdca2f7fae535cb998ac07e9fcb90f09737b9a41fa2734ec44a8f0b"},{id:"af_bella",label:"Bella",accent:"US",gender:"female",grade:"A-",sha256:"f69d836209b78eb8c66e75e3cda491e26ea838a3674257e9d4e5703cbaf55c8b"},{id:"bf_emma",label:"Emma",accent:"UK",gender:"female",grade:"B-",sha256:"669fe0647f9dd04fcab92f1439a40eeb4c8b4ab1f82e4996fe3d918ce4a63b73"},{id:"af_nicole",label:"Nicole",accent:"US",gender:"female",grade:"B-",sha256:"cd2191ab31b914ed7b318416b0e4440fdf392ddad9106a060819aa600a64f59a",note:"Recorded close to the mic — best on headphones."},{id:"af_aoede",label:"Aoede",accent:"US",gender:"female",grade:"C+",sha256:"4a004c33430762e2461eedb2013fad808ef4ab3121f5300f554476caf58d8361"},{id:"af_kore",label:"Kore",accent:"US",gender:"female",grade:"C+",sha256:"9be5221b6a941c04b561959b8ff0b06e809444dcc4ab7e75a7b23606f691819e"},{id:"af_sarah",label:"Sarah",accent:"US",gender:"female",grade:"C+",sha256:"4409fbc125afabacc615d94db5398d847006a737b0247d6892b7a9a0007a2f0a"},{id:"am_michael",label:"Michael",accent:"US",gender:"male",grade:"C+",sha256:"1d1f21dd8da39c30705cd4c75d039d265e9bc4a2a93ed09bc9e1b1225eb95ba1"},{id:"am_fenrir",label:"Fenrir",accent:"US",gender:"male",grade:"C+",sha256:"c27989f741f7ee34d273a39d8a595cc0837d35f5ced9a29b7cc162614616df43"},{id:"am_puck",label:"Puck",accent:"US",gender:"male",grade:"C+",sha256:"fcf73c989033e9233e0b98713eca600c8c74dcc1614b37009d5450ff4a2274a0"},{id:"af_nova",label:"Nova",accent:"US",gender:"female",grade:"C",sha256:"18778272caa0d0eebaea251c35fd635f038434f9eee5e691d02a174bd328414f"},{id:"af_alloy",label:"Alloy",accent:"US",gender:"female",grade:"C",sha256:"c4a6b876047fd7fb472edf4ebd63cfac7c3b958a7cae7c106e8f038ca6308c45"},{id:"bf_isabella",label:"Isabella",accent:"UK",gender:"female",grade:"C",sha256:"3754352c4aaa46d17f27654ab7518d65b62ad6163a0f55a5f4330c2da2c4e94f"},{id:"bm_george",label:"George",accent:"UK",gender:"male",grade:"C",sha256:"c4b235a4c1f2cd3b939fed08b899ce9385638b763f7b73a59616c4fc9bd6c9bc"},{id:"bm_fable",label:"Fable",accent:"UK",gender:"male",grade:"C",sha256:"f889083196807b4adb15e9204252165f503b8d33d3982e681c52443c49d798f1"}].map(Object.freeze)),z="af_heart";function N(e){return O.find(a=>a.id===e)||null}function E(e){return String(e||"").startsWith("b")?"en":"en-us"}function S(e){if(e.includes("."))return e;if(e.includes(":")){const[c,o]=e.split(":").map(Number);return o===0?`${c} o'clock`:o<10?`${c} oh ${o}`:`${c} ${o}`}const a=parseInt(e.slice(0,4),10);if(a<1100||a%1e3<10)return e;const r=e.slice(0,2),l=parseInt(e.slice(2,4),10),t=e.endsWith("s")?"s":"";if(a%1e3>=100&&a%1e3<=999){if(l===0)return`${r} hundred${t}`;if(l<10)return`${r} oh ${l}${t}`}return`${r} ${l}${t}`}function x(e){const a=e[0]==="$"?"dollar":"pound";if(Number.isNaN(Number(e.slice(1))))return`${e.slice(1)} ${a}s`;if(!e.includes("."))return`${e.slice(1)} ${a}${e.slice(1)==="1"?"":"s"}`;const[r,l]=e.slice(1).split("."),t=parseInt(l.padEnd(2,"0"),10),c=e[0]==="$"?t===1?"cent":"cents":t===1?"penny":"pence";return`${r} ${a}${r==="1"?"":"s"} and ${t} ${c}`}const _=e=>{const[a,r]=e.split(".");return`${a} point ${r.split("").join(" ")}`};function A(e){return String(e||"").replace(/[‘’]/g,"'").replace(/«/g,"“").replace(/»/g,"”").replace(/[“”]/g,'"').replace(/\(/g,"«").replace(/\)/g,"»").replace(/、/g,", ").replace(/。/g,". ").replace(/!/g,"! ").replace(/,/g,", ").replace(/:/g,": ").replace(/;/g,"; ").replace(/?/g,"? ").replace(/[^\S \n]/g," ").replace(/ +/g," ").replace(/(?<=\n) +(?=\n)/g,"").replace(/\bD[Rr]\.(?= [A-Z])/g,"Doctor").replace(/\b(?:Mr\.|MR\.(?= [A-Z]))/g,"Mister").replace(/\b(?:Ms\.|MS\.(?= [A-Z]))/g,"Miss").replace(/\b(?:Mrs\.|MRS\.(?= [A-Z]))/g,"Mrs").replace(/\betc\.(?! [A-Z])/gi,"etc").replace(/\b(y)eah?\b/gi,"$1e'a").replace(/\d*\.\d+|\b\d{4}s?\b|(?<!:)\b(?:[1-9]|1[0-2]):[0-5]\d\b(?!:)/g,S).replace(/(?<=\d),(?=\d)/g,"").replace(/[$£]\d+(?:\.\d+)?(?: hundred| thousand| (?:[bm]|tr)illion)*\b|[$£]\d+\.\d\d?\b/gi,x).replace(/\d*\.\d+/g,_).replace(/(?<=\d)-(?=\d)/g," to ").replace(/(?<=\d)S/g," S").replace(/(?<=[BCDFGHJ-NP-TV-Z])'?s\b/g,"'S").replace(/(?<=X')S\b/g,"s").replace(/(?:[A-Za-z]\.){2,} [a-z]/g,a=>a.replace(/\./g,"-")).replace(/(?<=[A-Z])\.(?=[A-Z])/gi,"-").trim()}const M=/(\s*[;:,.!?¡¿—…"«»“”(){}[\]]+\s*)+/g;async function j(e,{lang:a="en-us",phonemize:r}){if(typeof r!="function")throw new Error("kokoroPhonemes needs a phonemize function");const l=A(e),t=[];let c=0;for(const s of l.matchAll(M))c<s.index&&t.push({mark:!1,text:l.slice(c,s.index)}),s[0].length&&t.push({mark:!0,text:s[0]}),c=s.index+s[0].length;c<l.length&&t.push({mark:!1,text:l.slice(c)});let o="";for(const s of t)o+=s.mark?s.text:[].concat(await r(s.text,a)).join(" ");let n=o.replace(/kəkˈoːɹoʊ/g,"kˈoʊkəɹoʊ").replace(/kəkˈɔːɹəʊ/g,"kˈəʊkəɹəʊ").replace(/ʲ/g,"j").replace(/r/g,"ɹ").replace(/x/g,"k").replace(/ɬ/g,"l").replace(/(?<=[a-zɹː])(?=hˈʌndɹɪd)/g," ").replace(/ z(?=[;:,.!?¡¿—…"«»“” ]|$)/g,"z");return a==="en-us"&&(n=n.replace(/(?<=nˈaɪn)ti(?!ː)/g,"di")),n.trim()}const C=';:,.!?—…"()“” ̃ʣʥʦʨᵝꭧAIOQSTWYᵊabcdefhijklmnopqrstuvwxyzɑɐɒæβɔɕçɖðʤəɚɛɜɟɡɥɨɪʝɯɰŋɳɲɴøɸθœɹɾɻʁɽʂʃʈʧʊʋʌɣɤχʎʒʔˈˌːʰʲ↓→↗↘ᵻ',U=[1,2,3,4,5,6,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,31,33,35,36,39,41,42,43,44,45,46,47,48,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,75,76,77,78,80,81,82,83,85,86,87,90,92,99,101,102,103,110,111,112,113,114,115,116,118,119,120,123,125,126,128,129,130,131,132,133,135,136,138,139,140,142,143,147,148,156,157,158,162,164,169,171,172,173,177],$=Object.freeze(Object.fromEntries([...C].map((e,a)=>[e,U[a]])));function w(e,{maxTokens:a=u.maxTokens}={}){const r=[],l=[];for(const o of String(e||"")){const n=$[o];n!==void 0&&(r.push(n),l.push(o))}const t=[];let c=0;for(;c<r.length;){let o=Math.min(c+a,r.length);if(o<r.length){const s=i=>{for(let d=o-1;d>c;d--)if(i.includes(l[d]))return d+1;return-1},g=[s(".!?…"),s(",;:—"),s(" ")].find(i=>i>c);g&&(o=g)}const n=r.slice(c,o);for(;n.length&&n[n.length-1]===$[" "];)n.pop();for(n.length&&t.push({ids:[0,...n,0],style:Math.min(n.length,a-1)}),c=o;c<r.length&&l[c]===" ";)c++}return t}const y=/([,;:—–…]|[.!?]+["”’')\]]*)(?=\s|$)/g;function k(e,a){const r=e.split(" "),l=[];let t="";for(const c of r)t&&(t+" "+c).length>a?(l.push(t),t=c):t=t?`${t} ${c}`:c;return t&&l.push(t),l}const I=Object.freeze({threshold:.01,leadMs:30,trailMs:60});function R(e){const a=String(e||"").trim();return/[.!?…]+["”’')\]]*$/.test(a)?300:/[;:—–]$/.test(a)?220:/,$/.test(a)?150:0}function D(e,{start:a=0,firstChars:r=32,firstMax:l=28,growth:t=1.5,maxChars:c=220}={}){const o=String(e||"").replace(/\s+/g," ").trim();if(!o)return[];const n=[];let s=0;for(const f of o.matchAll(y)){const b=f.index+f[1].length,m=o.slice(s,b).trim();m&&n.push(m),s=b}if(o.slice(s).trim()&&n.push(o.slice(s).trim()),a===0&&n.length&&n[0].length>l){const[f]=k(n[0],l);n[0].length-f.length-1>=12&&n.splice(0,1,f,n[0].slice(f.length+1))}const g=[];let i=a,d="";const p=()=>Math.min(c,Math.round(r*t**i)),h=()=>{d&&(g.push(d),i++,d="")};for(const f of n)for(const b of f.length>Math.max(2*p(),48)?k(f,Math.max(p(),24)):[f])d&&(d+" "+b).length>p()&&h(),d=d?`${d} ${b}`:b,d.length>=p()&&h();return h(),g}export{z as DEFAULT_KOKORO_VOICE,I as KOKORO_EDGES,u as KOKORO_MODEL,$ as KOKORO_VOCAB,O as KOKORO_VOICES,D as kokoroChunks,w as kokoroInputs,E as kokoroLang,R as kokoroPauseMs,j as kokoroPhonemes,K as kokoroUrl,N as kokoroVoice,A as normalizeForKokoro};
|
package/link-protocol.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{concatBytes as
|
|
1
|
+
import{concatBytes as F}from"./link-noise.js";const v=1,$="chatpanel-link",N=6e4,O=44e3,q=Object.freeze(["GET","POST","PUT","PATCH","DELETE"]),L=64,H=Object.freeze({bytesPerSecond:9e5,byteBurst:6e6,framesPerSecond:90,frameBurst:800});function J({bytesPerSecond:t,byteBurst:e,framesPerSecond:n,frameBurst:s}=H,{now:c=()=>Date.now(),sleep:a=l=>new Promise(w=>setTimeout(w,l))}={}){let l=e,w=s,S=c();return async b=>{for(;;){const p=c(),h=Math.max(0,p-S)/1e3;if(S=p,l=Math.min(e,l+h*t),w=Math.min(s,w+h*n),l>=b&&w>=1){l-=b,w-=1;return}const g=Math.max((b-l)/t,(1-w)/n)*1e3;await a(Math.max(1,Math.ceil(g)))}}}const x=new TextEncoder,I=new TextDecoder;function y(t){let e="";for(const n of t)e+=String.fromCharCode(n);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function Y(t){const e=String(t||"").replace(/-/g,"+").replace(/_/g,"/");if(!/^[A-Za-z0-9+/]*$/.test(e))throw new Error("link: not base64url");const n=atob(e+"=".repeat((4-e.length%4)%4));return Uint8Array.from(n,s=>s.charCodeAt(0))}const G=t=>{let e="";for(const n of t)e+=String.fromCharCode(n);return btoa(e)},V=t=>Uint8Array.from(atob(String(t||"")),e=>e.charCodeAt(0));function te({relay:t,room:e,key:n,secret:s,name:c=""}){const a=D({v:String(v),relay:t,room:y(e),key:y(n),psk:y(s),name:c}),l=new URLSearchParams({v:String(v),relay:a.relay,room:y(a.room),key:y(a.key),psk:y(a.secret)});return a.name&&l.set("name",a.name),`${$}:?${l.toString()}`}function re(t){const e=String(t||"").trim();if(!e.startsWith(`${$}:?`))throw new Error("link: not a ChatPanel pairing code");const n=new URLSearchParams(e.slice($.length+2));return D(Object.fromEntries(n.entries()))}function D(t){if(String(t.v)!==String(v))throw new Error(`link: pairing code version ${t.v} is not supported — update the app`);let e;try{e=new URL(String(t.relay||""))}catch{throw new Error("link: the pairing code has no relay address")}if(e.protocol!=="https:"||e.username||e.password)throw new Error("link: the relay must be an https address");const n=(c,a)=>{let l;try{l=Y(t[c])}catch{throw new Error(`link: ${c} is not readable`)}if(l.length!==a)throw new Error(`link: ${c} must be ${a} bytes`);return l},s=String(t.name||"").replace(/[\u0000-\u001f\u007f<>]/g,"").trim().slice(0,64);return{relay:e.origin,room:n("room",16),key:n("key",32),secret:n("psk",32),name:s}}async function ne(t,e,n,s=globalThis.crypto.subtle){if(n!=="laptop"&&n!=="phone")throw new Error("link: side is laptop or phone");const c=await s.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),a=await s.sign("HMAC",c,x.encode(`chatpanel-link admit v${v}|${y(e)}|${n}`));return y(new Uint8Array(a))}async function oe(t,e=globalThis.crypto.subtle){const n=new Uint8Array(await e.digest("SHA-256",x.encode(String(t))));return Array.from(n,s=>s.toString(16).padStart(2,"0")).join("")}const W=/^(authorization|cookie|set-cookie|www-authenticate|host|proxy-.*|x-forwarded-.*|forwarded|x-real-ip|cf-.*|tailscale-.*|x-chatpanel-device|x-chatpanel-token|content-length|connection|transfer-encoding|upgrade)$/i;function M(t={}){const e={};for(const[n,s]of Object.entries(t||{})){const c=String(n).toLowerCase();!/^[a-z0-9-]{1,64}$/.test(c)||W.test(c)||(e[c]=String(s).replace(/[\r\n]+/g," ").slice(0,2048))}return e}function B(t){const e=String(t||"");if(!e.startsWith("/v1/")||e.length>2048)return!1;const n=e.split("?")[0];return!/(^|\/)\.\.?(\/|$)|%2e|%2f|%5c|\\|\/\//i.test(n)}const X=new Set(["req","body","end","res","cancel","error","ping","pong"]);function Q(t){const e=x.encode(JSON.stringify(t));if(e.length>N)throw new Error("link: frame too large");return e}function Z(t){if(t.length>N)throw new Error("link: frame too large");let e;try{e=JSON.parse(I.decode(t))}catch{throw new Error("link: frame is not JSON")}if(!e||typeof e!="object"||!X.has(e.t))throw new Error("link: unknown frame");if(e.t!=="ping"&&e.t!=="pong"&&!(Number.isInteger(e.id)&&e.id>0))throw new Error("link: frame without an id");if(e.t==="req"){if(!q.includes(e.method))throw new Error("link: method not allowed");if(!B(e.path))throw new Error("link: path not allowed");e.headers=M(e.headers)}if(e.t==="res"&&!(Number.isInteger(e.status)&&e.status>=100&&e.status<600))throw new Error("link: bad status");if(e.t==="body"&&typeof e.data!="string")throw new Error("link: body without data");return e}function K(){const t=[];let e=null,n=!1,s=null;const c=()=>{const a=e;e=null,a?.()};return{push(a){t.push(a),c()},end(){n=!0,c()},fail(a){s=a,n=!0,c()},async*[Symbol.asyncIterator](){for(;;){if(t.length){yield t.shift();continue}if(s)throw s;if(n)return;await new Promise(a=>{e=a})}},async bytes(){const a=[];for await(const l of this)a.push(l);return F(...a)},async text(){return I.decode(await this.bytes())}}}function ie({transport:t,send:e,side:n,onRequest:s=null,onClose:c=()=>{},pace:a=H,now:l,sleep:w}={}){if(!t||typeof e!="function")throw new Error("link: transport and send are required");if(n!=="phone"&&n!=="laptop")throw new Error("link: side is phone or laptop");let S=n==="phone"?1:2;const b=i=>i%2===(n==="phone"?1:0);let p=null;const h=new Map,g=new Map;let T=Promise.resolve();const j=a?J(a,{...l?{now:l}:{},...w?{sleep:w}:{}}):null,m=i=>{if(p)return Promise.reject(new Error(`link: session closed (${p})`));const r=Q(i),o=T.then(async()=>{if(p)return;const u=await t.encrypt(r);j&&await j(u.length),p||e(u)});return T=o.catch(()=>{}),o},A=i=>{i?.catch?.(()=>{})};let C=Promise.resolve();const U=async(i,r)=>{for(let o=0;o<r.length;o+=O)await m({t:"body",id:i,data:G(r.subarray(o,o+O))})};function P(i="closed"){if(p)return;p=i;const r=new Error(`link: session closed (${i})`);for(const o of h.values())o.reject?.(r),o.body?.fail(r);for(const o of g.values())o.body.fail(r);h.clear(),g.clear(),c(i)}async function z(i){if(!s||g.size>=L){A(m({t:"error",id:i.id,message:s?"too many open requests":"this side serves nothing"}));return}const r=K(),o={body:r,cancelled:!1};g.set(i.id,o);let u=!1;const f={head:(d,_={})=>(u=!0,m({t:"res",id:i.id,status:d,headers:M(_)})),write:d=>o.cancelled?Promise.resolve():U(i.id,d instanceof Uint8Array?d:x.encode(String(d))),end:()=>(g.delete(i.id),o.cancelled?Promise.resolve():m({t:"end",id:i.id})),fail:d=>(g.delete(i.id),m({t:"error",id:i.id,message:String(d).slice(0,500)})),get cancelled(){return o.cancelled}};Promise.resolve().then(()=>s({method:i.method,path:i.path,headers:i.headers,body:r},f)).catch(d=>A(u?f.end():f.fail(d?.message||"the request failed")))}return{get closed(){return p},close:P,receive(i){const r=C.then(()=>this._receive(i)).catch(o=>P(`bad frame: ${o?.message||o}`));return C=r,r},async _receive(i){if(p)return;let r;try{r=Z(await t.decrypt(i))}catch(f){P(/decrypt|operation|tag/i.test(String(f?.message||f?.name))?"tampered":`bad frame: ${f?.message}`);return}if(r.t==="ping"){A(m({t:"pong"}));return}if(r.t==="pong")return;if(r.t==="req"){if(b(r.id)){P("bad frame: a request in our id space");return}await z(r);return}const o=b(r.id)?h.get(r.id):null,u=b(r.id)?null:g.get(r.id);if(r.t==="res"&&o)o.resolve({status:r.status,headers:r.headers||{},body:o.body});else if(r.t==="body"&&(o||u))(o||u).body.push(V(r.data));else if(r.t==="end"&&o)o.body.end(),h.delete(r.id);else if(r.t==="end"&&u)u.body.end();else if(r.t==="error"&&o){const f=new Error(r.message||"the request failed");o.reject(f),o.body.fail(f),h.delete(r.id)}else r.t==="cancel"&&u&&(u.cancelled=!0,u.body.fail(new Error("cancelled")),g.delete(r.id))},request({method:i="GET",path:r,headers:o={},body:u=null,signal:f=null}={}){if(!q.includes(i))return Promise.reject(new Error("link: method not allowed"));if(!B(r))return Promise.reject(new Error("link: path not allowed"));if(h.size>=L)return Promise.reject(new Error("link: too many open requests"));const d=S;S+=2;const _=K(),R=new Promise((E,k)=>h.set(d,{resolve:E,reject:k,body:_}));return f?.addEventListener?.("abort",()=>{const E=h.get(d);if(!E)return;h.delete(d);const k=new Error("aborted");E.reject(k),E.body.fail(k),m({t:"cancel",id:d}).catch(()=>{})},{once:!0}),(async()=>{await m({t:"req",id:d,method:i,path:r,headers:M(o)}),u!=null&&await U(d,u instanceof Uint8Array?u:x.encode(String(u))),await m({t:"end",id:d})})().catch(E=>{const k=h.get(d);k&&(k.reject(E),h.delete(d))}),R},ping:()=>m({t:"ping"})}}export{O as BODY_CHUNK_BYTES,q as LINK_METHODS,H as LINK_PACE,$ as LINK_SCHEME,v as LINK_VERSION,N as MAX_FRAME_BYTES,ne as admissionToken,oe as admissionVerifier,ie as createLinkSession,Z as decodeFrame,Q as encodeFrame,Y as fromB64url,J as linkPacer,B as linkPathAllowed,te as pairingUri,re as parsePairingUri,M as sanitizeLinkHeaders,y as toB64url};
|
package/link-sync.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{decide as O,stampOf as y}from"./sync-plan.js";import{mergeNoteRecords as w}from"./note-merge.js";const E=Object.freeze(["chat","note","meeting","brief"]),Y=Object.freeze({limit:50,bytes:1e6}),C=1e6,M=1e6,k=-1,L=0,T=["syncBase","syncBaseTitle","syncBaseTags"],n=t=>Number.isFinite(Number(t))?Number(t):0,p=t=>String(t?.kind||String(t?.id||"").split(":")[0]||""),B=t=>String(t?.body?.markdown??""),S=(t,i)=>(t instanceof Map?t.get(i):t?.[i])||null;function b(t){if(!t||typeof t.id!="string"||!t.id.includes(":")||!E.includes(p(t))||t.sealed)return!1;if(t.deletedAt)return!0;const i=t.meta||null;return!(t.lossy===!0||i?.lossy===!0||i?.origin==="warm")}function v(t){const{host:i,at:o,rev:s,...e}=t;return n(e.deletedAt)?{id:e.id,kind:p(e),updatedAt:n(e.updatedAt),deletedAt:n(e.deletedAt)}:e}function G(t,i={},o={}){const s=[],e=[],c=[],r=[],l={};let u=0,x=0;const m=(a,g)=>{l[a.id]={rev:n(a.rev),stamp:g}};for(const a of t||[]){if(!a?.id)continue;if(u=Math.max(u,n(a.rev)),!b(a)){x++;continue}const g=S(o,a.id);if(g&&n(g.rev)===n(a.rev))continue;const f=S(i,a.id),d=v(a),h=n(d.deletedAt)>0,A=!!f&&n(f.deletedAt)>0,N=()=>{if(!h){s.push(I(d)||d),m(a,y(d));return}f&&!A&&r.push({id:d.id,at:n(d.deletedAt)}),m(a,f?Math.max(n(f.updatedAt),n(A?f.deletedAt:d.deletedAt)):L)};if(!f){N();continue}if(!g){const _=O(f,d);_==="pull"?!h&&!A&&p(d)==="note"?e.push(d):N():m(a,_==="push"?k:y(f));continue}if(y(f)===n(g.stamp)){N();continue}h&&A?m(a,y(f)):h?m(a,k):A?N():p(d)==="note"?e.push(d):(c.push(d),m(a,y(d)))}return{put:s,merge:e,fork:c,remove:r,known:l,rev:u,skipped:x}}function P(t,i,{now:o=0}={}){const s=v(i),e=t?.meta||{},c=typeof e.syncBase=="string"?{markdown:e.syncBase,..."syncBaseTitle"in e?{title:e.syncBaseTitle}:{},..."syncBaseTags"in e?{tags:e.syncBaseTags}:{}}:null,{record:r,conflicts:l}=w({base:c,ours:{...t,meta:{}},theirs:s,now:0}),u=B(r)!==B(s)||String(r.title??"")!==String(s.title??"")||JSON.stringify(r.tags??[])!==JSON.stringify(s.tags??[]);return{record:{...r,id:s.id,kind:"note",meta:{...s.meta||{},syncBase:B(s),syncBaseTitle:s.title??"",syncBaseTags:s.tags??[],syncConflicts:l},updatedAt:u?Math.max(n(o),n(r.updatedAt)):n(s.updatedAt)},push:u}}function R(t,{newId:i,now:o=0,label:s="conflicted copy"}={}){if(typeof i!="function")throw new Error("conflictedCopy needs newId()");const e=p(t),c={...t.meta||{},conflictOf:t.id};for(const r of T)delete c[r];return{...t,id:`${e}:${i()}`,kind:e,title:`${t.title||"Untitled"} (${s})`,updatedAt:n(o)||n(t.updatedAt),meta:c}}function $(t,{known:i={}}={}){const o=[];let s=0;for(const e of t||[]){if(!b(e)){s++;continue}const c=S(i,e.id);if(c&&n(c.stamp)!==k&&n(c.stamp)===y(e)){s++;continue}const r=c?n(c.rev):0;if(n(e.deletedAt)){o.push({id:e.id,kind:p(e),updatedAt:n(e.updatedAt),deletedAt:n(e.deletedAt),baseRev:r});continue}const l={...e.meta||{}};for(const h of T)delete l[h];const{deletedAt:u,pinned:x,snippet:m,rev:a,host:g,at:f,...d}=e;o.push({...d,kind:p(e),meta:l,baseRev:r})}return{records:o,skipped:s}}function I(t){if(!t||p(t)!=="note"||n(t.deletedAt))return null;const i=B(t),o=t.meta||{};return o.syncBase===i&&o.syncBaseTitle===(t.title??"")&&JSON.stringify(o.syncBaseTags??[])===JSON.stringify(t.tags??[])?null:{...t,meta:{...o,syncBase:i,syncBaseTitle:t.title??"",syncBaseTags:t.tags??[]}}}function j(t,i=C){const o=new TextEncoder,s=[];let e=[],c=0;for(const r of t||[]){const l=o.encode(JSON.stringify(r)).byteLength+1;e.length&&c+l>i&&(s.push(e),e=[],c=0),e.push(r),c+=l}return e.length&&s.push(e),s}function z(t,i,o=M){const s=n(t)/Math.max(1,n(o))*1e3;return Math.max(0,Math.ceil(s-n(i)))}function H(t,i=0){return!t||t.event!=="records"&&t.event!=="hello"?!1:n(t.data?.rev)>n(i)}function W(t){const i=[];let o=String(t||"");for(;;){const s=o.indexOf(`
|
|
2
|
+
|
|
3
|
+
`);if(s<0)break;const e=o.slice(0,s);o=o.slice(s+2);let c="message";const r=[];for(const u of e.split(`
|
|
4
|
+
`))u.startsWith(":")||(u.startsWith("event:")?c=u.slice(6).trim():u.startsWith("data:")&&r.push(u.slice(5).replace(/^ /,"")));if(!r.length)continue;let l=null;try{l=JSON.parse(r.join(`
|
|
5
|
+
`))}catch{l=null}i.push({event:c,data:l})}return{events:i,rest:o}}export{C as LINK_SYNC_BATCH_BYTES,E as LINK_SYNC_KINDS,Y as LINK_SYNC_PAGE,M as LINK_SYNC_RATE,k as SEND,R as conflictedCopy,P as mergePulledNote,z as paceMs,G as planPull,$ as planPush,j as pushBatches,H as rings,W as sseEvents,b as syncable,I as withSyncBase};
|
package/note-merge.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const
|
|
1
|
+
const $="<!-- conflict:start -->",j="<!-- conflict:other -->",C="<!-- conflict:end -->",w=/<!-- conflict:start -->\n([\s\S]*?)\n<!-- conflict:other -->\n([\s\S]*?)\n<!-- conflict:end -->/g,v=4e3;function S(t){const s=String(t??"").replace(/\r\n?/g,`
|
|
2
2
|
`).split(`
|
|
3
|
-
`),
|
|
4
|
-
`)),
|
|
3
|
+
`),o=[];let e=[],n=null;const r=()=>{e.length&&(o.push(e.join(`
|
|
4
|
+
`)),e=[])};for(const c of s){const i=/^\s*(`{3,}|~{3,})/.exec(c);if(n){e.push(c),i&&i[1][0]===n[0]&&i[1].length>=n.length&&(n=null,r());continue}if(i){r(),n=i[1],e.push(c);continue}if(!c.trim()){r();continue}/^\s*(?:[-*+]|\d+[.)])\s+/.test(c)&&e.length&&r(),e.push(c)}return r(),o}const y=/^\s*(?:[-*+]|\d+[.)])\s+/,g=t=>t.reduce((s,o,e)=>e===0?o:`${s}${y.test(o)&&y.test(t[e-1])?`
|
|
5
5
|
`:`
|
|
6
6
|
|
|
7
|
-
`}${
|
|
8
|
-
${g(
|
|
9
|
-
${
|
|
10
|
-
${g(
|
|
11
|
-
${C}`;function N({base:
|
|
7
|
+
`}${o}`,"");function k(t,s){const o=t.length,e=s.length,n=Array.from({length:o+1},()=>new Uint32Array(e+1));for(let f=o-1;f>=0;f--)for(let a=e-1;a>=0;a--)n[f][a]=t[f]===s[a]?n[f+1][a+1]+1:Math.max(n[f+1][a],n[f][a+1]);const r=[];let c=0,i=0;for(;c<o&&i<e;)t[c]===s[i]?(r.push([c,i]),c++,i++):n[c+1][i]>=n[c][i+1]?c++:i++;return r}const A=(t,s)=>`${$}
|
|
8
|
+
${g(t)}
|
|
9
|
+
${j}
|
|
10
|
+
${g(s)}
|
|
11
|
+
${C}`;function N({base:t=null,ours:s="",theirs:o=""}={}){const e=String(s??""),n=String(o??"");if(e===n)return{markdown:e,conflicts:0,clean:!0};if(t!=null&&String(t)===e)return{markdown:n,conflicts:0,clean:!0};if(t!=null&&String(t)===n)return{markdown:e,conflicts:0,clean:!0};const r=S(e),c=S(n);return r.length>4e3||c.length>4e3?{markdown:A(r,c),conflicts:1,clean:!1}:t==null?L(r,c):I(S(t),r,c)}function L(t,s){const o=[];let e=0,n=0,r=0;for(const[c,i]of[...k(t,s),[t.length,s.length]]){const f=t.slice(n,c),a=s.slice(r,i);f.length&&a.length?(o.push(A(f,a)),e++):o.push(...f,...a),c<t.length&&o.push(t[c]),n=c+1,r=i+1}return{markdown:g(o),conflicts:e,clean:e===0}}function M(t,s){const o=[];let e=0,n=0;for(const[r,c]of[...k(t,s),[t.length,s.length]])(r>e||c>n)&&o.push({s:e,e:r,xs:n,xe:c}),e=r+1,n=c+1;return o}function I(t,s,o){const e=[...M(t,s).map(l=>({...l,side:"o"})),...M(t,o).map(l=>({...l,side:"t"}))].sort((l,u)=>l.s-u.s||l.e-u.e||(l.side==="o"?-1:1)),n=[];for(const l of e){const u=n[n.length-1];u&&(l.s<u.e||l.s===u.e&&l.s===l.e&&u.s===u.e)?(u.e=Math.max(u.e,l.e),u[l.side].push(l)):n.push({s:l.s,e:l.e,o:l.side==="o"?[l]:[],t:l.side==="t"?[l]:[]})}const r=(l,u,d,h)=>{const m=[];let x=u;for(const p of l)m.push(...t.slice(x,p.s),...h.slice(p.xs,p.xe)),x=p.e;return m.push(...t.slice(x,d)),m},c=(l,u)=>l.length===u.length&&l.every((d,h)=>d===u[h]),i=[];let f=0,a=0;for(const l of n){i.push(...t.slice(a,l.s));const u=r(l.o,l.s,l.e,s),d=r(l.t,l.s,l.e,o);l.t.length?l.o.length?c(u,d)?i.push(...u):l.s===l.e?i.push(...u,...d.filter(h=>!u.includes(h))):(i.push(A(u,d)),f++):i.push(...d):i.push(...u),a=l.e}return i.push(...t.slice(a)),{markdown:g(i),conflicts:f,clean:f===0}}function T(t,s,o,e){const n=(r,c)=>JSON.stringify(r??null)===JSON.stringify(c??null);return n(s,o)?s:t!==void 0&&n(t,s)?o:t!==void 0&&n(t,o)||e?s:o}function _(t,s,o){const e=Array.isArray(s)?s:[],n=Array.isArray(o)?o:[];if(!Array.isArray(t))return[...new Set([...n,...e])];const r=new Set(t.filter(c=>!e.includes(c)||!n.includes(c)));return[...new Set([...n,...e])].filter(c=>!r.has(c)||!t.includes(c))}function K({base:t=null,ours:s,theirs:o,now:e=0}={}){const n=u=>Number(u?.updatedAt)||0,r=n(s)>n(o),c=r?s:o,i=r?o:s,f=u=>String(u?.body?.markdown??""),a=t?N({base:String(t.markdown??""),ours:f(s),theirs:f(o)}):{markdown:f(c),conflicts:0};return{record:{...i,...c,title:T(t?t.title:void 0,s?.title,o?.title,r),tags:_(t?t.tags:void 0,s?.tags,o?.tags),body:{...i?.body||{},...c?.body||{},markdown:a.markdown},meta:{...i?.meta||{},...c?.meta||{}},updatedAt:Math.max(n(s),n(o),Number(e)||0)},conflicts:a.conflicts}}function D(t){return[...String(t??"").matchAll(w)].map((s,o)=>({index:o,ours:s[1],theirs:s[2]}))}function E(t,s,o="ours"){let e=-1;return String(t??"").replace(w,(n,r,c)=>(e++,e!==s?n:o==="theirs"?c:o==="both"?`${r}
|
|
12
12
|
|
|
13
|
-
${
|
|
13
|
+
${c}`:r))}function J({ours:t=null,theirs:s=null,base:o=null}={}){const e={text:String(t?.text??""),at:Number(t?.updatedAt)||0},n={text:String(s?.text??""),at:Number(s?.updatedAt)||0},r={text:n.text};if(e.text===n.text)return o?.text===n.text?null:{text:e.text,updatedAt:Math.max(e.at,n.at),base:r,conflicts:0};if(o&&typeof o.text=="string"){const c=N({base:o.text,ours:e.text,theirs:n.text});return{text:c.markdown,updatedAt:Math.max(e.at,n.at),base:r,conflicts:c.conflicts}}return n.at>e.at?{text:n.text,updatedAt:n.at,base:r,conflicts:0}:{text:e.text,updatedAt:e.at,base:r,conflicts:0}}export{v as MAX_BLOCKS,D as conflictsIn,N as mergeNote,K as mergeNoteRecords,E as resolveConflict,S as splitBlocks,J as syncNote};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatpanel/events",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.295.0",
|
|
4
4
|
"description": "The canonical ChatPanel event-log and capability contracts — typed durable facts, clock-free deterministic linearization, schema upcasting, and the invariants the replay harness asserts. Pure, dependency-free ESM shared by the ChatPanel extension, gateway and bridge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -125,6 +125,7 @@
|
|
|
125
125
|
"./stitch.js": "./stitch.js",
|
|
126
126
|
"./note-merge.js": "./note-merge.js",
|
|
127
127
|
"./link-connect.js": "./link-connect.js",
|
|
128
|
+
"./link-sync.js": "./link-sync.js",
|
|
128
129
|
"./qr.js": "./qr.js",
|
|
129
130
|
"./record-entities.js": "./record-entities.js",
|
|
130
131
|
"./decide-by-model.js": "./decide-by-model.js",
|
|
@@ -406,6 +407,7 @@
|
|
|
406
407
|
"stitch.js",
|
|
407
408
|
"note-merge.js",
|
|
408
409
|
"link-connect.js",
|
|
410
|
+
"link-sync.js",
|
|
409
411
|
"qr.js",
|
|
410
412
|
"record-entities.js",
|
|
411
413
|
"decide-by-model.js",
|