@harperfast/harper-pro 5.1.0-beta.3 → 5.1.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.
Files changed (59) hide show
  1. package/core/DESIGN.md +24 -0
  2. package/core/bin/copyDb.ts +16 -3
  3. package/core/package-lock.json +44 -54
  4. package/core/resources/Table.ts +41 -4
  5. package/core/resources/databases.ts +134 -42
  6. package/core/resources/graphql.ts +3 -0
  7. package/core/resources/replayLogs.ts +114 -42
  8. package/core/resources/replayLogsGuards.ts +58 -9
  9. package/core/server/nodeName.ts +9 -3
  10. package/core/server/operationsServer.ts +17 -0
  11. package/core/utility/install/installer.ts +12 -5
  12. package/dist/core/bin/copyDb.js +16 -3
  13. package/dist/core/bin/copyDb.js.map +1 -1
  14. package/dist/core/resources/Table.js +43 -4
  15. package/dist/core/resources/Table.js.map +1 -1
  16. package/dist/core/resources/databases.js +135 -41
  17. package/dist/core/resources/databases.js.map +1 -1
  18. package/dist/core/resources/graphql.js +3 -0
  19. package/dist/core/resources/graphql.js.map +1 -1
  20. package/dist/core/resources/replayLogs.js +100 -40
  21. package/dist/core/resources/replayLogs.js.map +1 -1
  22. package/dist/core/resources/replayLogsGuards.js +50 -10
  23. package/dist/core/resources/replayLogsGuards.js.map +1 -1
  24. package/dist/core/server/nodeName.js +9 -3
  25. package/dist/core/server/nodeName.js.map +1 -1
  26. package/dist/core/server/operationsServer.js +20 -0
  27. package/dist/core/server/operationsServer.js.map +1 -1
  28. package/dist/core/utility/install/installer.js +12 -6
  29. package/dist/core/utility/install/installer.js.map +1 -1
  30. package/dist/replication/knownNodes.js +106 -17
  31. package/dist/replication/knownNodes.js.map +1 -1
  32. package/dist/replication/replicator.js +6 -3
  33. package/dist/replication/replicator.js.map +1 -1
  34. package/npm-shrinkwrap.json +43 -52
  35. package/package.json +3 -3
  36. package/replication/knownNodes.ts +104 -14
  37. package/replication/replicator.ts +7 -3
  38. package/studio/web/assets/{Chat-BdFickL8.js → Chat-DMBW4pI2.js} +2 -2
  39. package/studio/web/assets/{Chat-BdFickL8.js.map → Chat-DMBW4pI2.js.map} +1 -1
  40. package/studio/web/assets/{FloatingChat-CaAoco8I.js → FloatingChat-DTmhPsrm.js} +4 -4
  41. package/studio/web/assets/{FloatingChat-CaAoco8I.js.map → FloatingChat-DTmhPsrm.js.map} +1 -1
  42. package/studio/web/assets/{applications-C3y3xwyG.js → applications-CigxJarn.js} +2 -2
  43. package/studio/web/assets/{applications-C3y3xwyG.js.map → applications-CigxJarn.js.map} +1 -1
  44. package/studio/web/assets/{index-Cd3Zh3nK.js → index-oRZw5GW3.js} +6 -6
  45. package/studio/web/assets/index-oRZw5GW3.js.map +1 -0
  46. package/studio/web/assets/{index.lazy-0hLbh5Fo.js → index.lazy-DY3VcR86.js} +4 -4
  47. package/studio/web/assets/{index.lazy-0hLbh5Fo.js.map → index.lazy-DY3VcR86.js.map} +1 -1
  48. package/studio/web/assets/{profile-CwBWGuVt.js → profile-DiV60L50.js} +2 -2
  49. package/studio/web/assets/{profile-CwBWGuVt.js.map → profile-DiV60L50.js.map} +1 -1
  50. package/studio/web/assets/{setComponentFile-Dhrmd8eR.js → setComponentFile-Bz6WI4jy.js} +2 -2
  51. package/studio/web/assets/{setComponentFile-Dhrmd8eR.js.map → setComponentFile-Bz6WI4jy.js.map} +1 -1
  52. package/studio/web/assets/{status-Bykq6QcD.js → status-fW6PBpPM.js} +2 -2
  53. package/studio/web/assets/{status-Bykq6QcD.js.map → status-fW6PBpPM.js.map} +1 -1
  54. package/studio/web/assets/{swagger-ui-react-CF94s29D.js → swagger-ui-react-DRYf7G3J.js} +2 -2
  55. package/studio/web/assets/{swagger-ui-react-CF94s29D.js.map → swagger-ui-react-DRYf7G3J.js.map} +1 -1
  56. package/studio/web/assets/{useEntityRestURL-D7vuaG2W.js → useEntityRestURL-14jWKu9J.js} +2 -2
  57. package/studio/web/assets/{useEntityRestURL-D7vuaG2W.js.map → useEntityRestURL-14jWKu9J.js.map} +1 -1
  58. package/studio/web/index.html +1 -1
  59. package/studio/web/assets/index-Cd3Zh3nK.js.map +0 -1
@@ -129,22 +129,12 @@ export async function runNodeUpdateWatcher(listener: (node: any, id: string) =>
129
129
  }
130
130
  /**
131
131
  * Raw existence check for an hdb_nodes record that does NOT decode the stored value.
132
- * A decode failure (e.g. stale msgpackr shared-structures, harper#1163) must not be
133
- * misread as the record being absent: `primaryStore.get()` would throw/return undefined
134
- * for an undecodable-but-present row, so we probe at the bytes level instead.
132
+ * A decode failure (e.g. stale msgpackr shared-structures, harper#1163 / harper-pro#352) must not
133
+ * be misread as the record being absent: `primaryStore.get()` would throw/return undefined for an
134
+ * undecodable-but-present row, so we probe via the scan path (`getKeys`) instead.
135
135
  */
136
136
  export function nodeRecordPhysicallyExists(name: string): boolean {
137
- const store: any = getHDBNodeTable().primaryStore;
138
- if (typeof store.doesExist === 'function') return store.doesExist(name);
139
- // getBinaryFast returns the raw value bytes (or undefined when the key is absent).
140
- if (typeof store.getBinaryFast === 'function') return store.getBinaryFast(name) != null;
141
- // Last-resort fallback: a present-but-undecodable record will still throw here, so be
142
- // conservative and treat a throw as "present" (don't let it look like a deletion).
143
- try {
144
- return store.get(name) != null;
145
- } catch {
146
- return true;
147
- }
137
+ return storeRecordRangeVisible(getHDBNodeTable().primaryStore, name);
148
138
  }
149
139
 
150
140
  /**
@@ -179,6 +169,106 @@ export function isValidNodeRecord(record: unknown): boolean {
179
169
  );
180
170
  }
181
171
 
172
+ /**
173
+ * Resolve an hdb_nodes record for the replication auth path (cert common-name / IP lookup).
174
+ *
175
+ * Root cause of harper-pro#352 (field variant #345): during a rolling in-place v4→v5 upgrade, a
176
+ * freshly-flipped node's replication auth path reads a peer's `hdb_nodes` row via the POINT lookup
177
+ * (`primaryStore.get()`) very early at boot. A v5-era msgpackr *shared-structure* row can
178
+ * transiently misread through that point-lookup path — yielding `[]` / a non-record (it does not
179
+ * necessarily throw) — even though the row is present on disk and the table's shared structures are
180
+ * present too. (Diagnosis: on the wedged node the local log replay had already completed and the
181
+ * read-path structures key `[Symbol.for('structures'), 'hdb_nodes']` was present and valid; the
182
+ * point decode simply loses a race with the `hdb_nodes` base-copy resync that re-encodes the row
183
+ * against local structures and heals it within seconds. The SCAN path lists the key reliably the
184
+ * whole time.) `isValidNodeRecord` then (correctly) refuses the misread — but on a replication
185
+ * socket the "require credentials" fallback can never succeed, so the peer is rejected with cycling
186
+ * 1008 Unauthorized and its post-flip writes strand at origin.
187
+ *
188
+ * The information the auth decision actually needs is the peer's `name`, which is the table's
189
+ * primary key — and the SCAN path (`getKeys`/`getRange`) lists that key reliably even while the
190
+ * point decode transiently fails. So when the point lookup yields no valid record but the key is
191
+ * range-visible (a known peer), reconstruct a minimal node descriptor from the key. This is safe:
192
+ * the connection's certificate is independently validated by TLS and `verifyCertificate` in
193
+ * replicator.ts before this record is consulted, and the hostname must already be a range-visible
194
+ * known node to be reconstructed at all — we are not inventing a peer, we are recovering the
195
+ * identity of one whose descriptor transiently failed to decode; the full record self-heals on the
196
+ * next decodable update.
197
+ *
198
+ * Note: keying the reconstruction off range-visibility (not the point-lookup `doesExist`/`get`) is
199
+ * deliberate — the point lookup is exactly the path that misreads, so depending on it would leave
200
+ * the wedge open in the observed failure shape.
201
+ *
202
+ * (Separate, latent: `replayLogs` persists replication-applied structure updates under the plain
203
+ * key `Symbol.for('structures')`, which the RocksDB decode path — composite `[Symbol.for('structures'),
204
+ * name]` — never reads. Not the proximate trigger here, tracked separately.)
205
+ *
206
+ * Returns a valid node record, or `undefined` when the hostname is genuinely unknown (not range-
207
+ * visible and no route). `isValidNodeRecord` is retained as defense-in-depth at the call sites.
208
+ */
209
+ export function readNodeForAuth(name: string, routeRecord?: any): any {
210
+ return resolveNodeForAuth(getHDBNodeTable().primaryStore, name, routeRecord);
211
+ }
212
+
213
+ /**
214
+ * Pure resolution logic for {@link readNodeForAuth}, taking the store explicitly so it can be
215
+ * unit-tested against a real (or fake) store without standing up a server. See readNodeForAuth
216
+ * for the full root-cause rationale (harper-pro#352).
217
+ */
218
+ export function resolveNodeForAuth(store: any, name: string, routeRecord?: any): any {
219
+ let record: any;
220
+ try {
221
+ record = store.get(name);
222
+ } catch {
223
+ // A present-but-undecodable row throws here (missing shared structure); fall through to
224
+ // the physical-existence check below rather than treating the peer as unknown.
225
+ record = undefined;
226
+ }
227
+ if (isValidNodeRecord(record)) return record;
228
+ // A static-route record (from replication.routes config) is already a valid descriptor and
229
+ // carries fields the reconstructed minimal record cannot (e.g. revoked_certificates) — prefer it.
230
+ if (isValidNodeRecord(routeRecord)) return routeRecord;
231
+ // The point lookup yielded no valid record. If the key is RANGE-VISIBLE (the scan path reliably
232
+ // lists v5-era rows even while the point decode transiently misreads — harper-pro#352), this is
233
+ // a known peer: reconstruct its identity from the key so a cryptographically-validated peer is
234
+ // not stranded by a transiently-undecodable descriptor.
235
+ if (storeRecordRangeVisible(store, name)) {
236
+ logger.warn?.(
237
+ 'hdb_nodes record for',
238
+ name,
239
+ 'did not decode to a valid node descriptor on the point lookup but is range-visible (likely a v5-era shared-structure row transiently misreading at boot during an in-place upgrade; see harper-pro#352). Authorizing the peer by its certificate-validated name; the full record self-heals on the next decodable update.'
240
+ );
241
+ return { name };
242
+ }
243
+ return undefined;
244
+ }
245
+
246
+ /**
247
+ * Existence probe for an hdb_nodes key that prefers the RANGE/scan path. A v5-era shared-structure
248
+ * row can transiently misread to `[]`/null through the point lookup (`doesExist`/`get`) at early
249
+ * boot (harper-pro#352), but `getKeys` lists the key reliably because it never decodes the value.
250
+ * Falls back to point checks only if `getKeys` is unavailable.
251
+ */
252
+ function storeRecordRangeVisible(store: any, name: string): boolean {
253
+ if (typeof store.getKeys === 'function') {
254
+ try {
255
+ for (const key of store.getKeys({ start: name, limit: 1 })) {
256
+ return key === name;
257
+ }
258
+ return false;
259
+ } catch {
260
+ // fall through to point checks
261
+ }
262
+ }
263
+ if (typeof store.doesExist === 'function' && store.doesExist(name)) return true;
264
+ if (typeof store.getBinaryFast === 'function' && store.getBinaryFast(name) != null) return true;
265
+ try {
266
+ return store.get(name) != null;
267
+ } catch {
268
+ return true;
269
+ }
270
+ }
271
+
182
272
  async function processNodeUpdateEvent(event: any, listener: (node: any, id: string) => void) {
183
273
  // remove any nodes that have been updated or deleted
184
274
  const node_name = event?.value?.name || event?.id;
@@ -39,6 +39,7 @@ import {
39
39
  getReplicationSharedStatus,
40
40
  getNodeURL,
41
41
  isValidNodeRecord,
42
+ readNodeForAuth,
42
43
  } from './knownNodes.ts';
43
44
  import { CONFIG_PARAMS } from '../core/utility/hdbTerms.ts';
44
45
  import { exportIdMapping, getIdOfRemoteNode } from '../core/resources/nodeIdMapping.ts';
@@ -178,7 +179,10 @@ export function start(options) {
178
179
  let node: any;
179
180
  for (const hostname of hostnames) {
180
181
  if (!hostname) continue;
181
- const candidate = hdbNodesStore.get(hostname) || routeByHostname.get(hostname);
182
+ // readNodeForAuth decodes the hdb_nodes row (falling back to the static route record,
183
+ // then to a key-reconstructed identity for a present-but-undecodable row — the
184
+ // harper-pro#352 in-place-upgrade case). isValidNodeRecord stays as defense-in-depth.
185
+ const candidate = readNodeForAuth(hostname, routeByHostname.get(hostname));
182
186
  if (isValidNodeRecord(candidate)) {
183
187
  node = candidate;
184
188
  break;
@@ -226,8 +230,8 @@ export function start(options) {
226
230
  );
227
231
  }
228
232
  } else if (request.ip) {
229
- // try by IP address
230
- const candidate = hdbNodesStore.get(request.ip) || routeByHostname.get(request.ip);
233
+ // try by IP address (readNodeForAuth: same decode-then-reconstruct path as the cert lookup)
234
+ const candidate = readNodeForAuth(request.ip, routeByHostname.get(request.ip));
231
235
  if (isValidNodeRecord(candidate)) {
232
236
  request.user = candidate;
233
237
  } else if (!authorizationError) {
@@ -1,4 +1,4 @@
1
- import{a as e,t}from"./rolldown-runtime-Cyuzqnbw.js";import{h as n,t as r}from"./button-kCMf1ZBL.js";import{C as i,S as a,T as o,_ as s,a as c,b as l,c as u,d,h as f,i as p,l as m,m as h,r as g,s as _,t as v,u as ee,v as y,w as b,x,y as S}from"./vendor-core-BIhSIGPv.js";import{A as te,C as ne,M as re,P as ie}from"./vendor-tanstack-DmFvmRiZ.js";import{a as ae}from"./vendor-datadog-Bq_0f1ke.js";import{r as oe}from"./vendor-react-BqTNj-ZI.js";import{Tt as C}from"./vendor-ui-to0aD0Fq.js";import{t as w}from"./createLucideIcon-D6HmSa4x.js";import{l as se,t as ce}from"./proxy-BJ77EweZ.js";import{_ as le,b as ue,c as de,h as fe,i as pe,m as me,p as he,r as ge,t as _e,v as ve,y as ye}from"./setComponentFile-Dhrmd8eR.js";import{$t as be,A as xe,E as Se,Gt as Ce,It as we,Jt as Te,Kt as Ee,N as De,O as Oe,Pt as ke,Qt as Ae,Rt as je,Ut as Me,V as Ne,Vt as Pe,Wt as Fe,X as Ie,Yt as Le,_ as Re,a as ze,b as Be,cn as Ve,i as He,in as Ue,j as We,k as Ge,ln as Ke,nn as qe,o as Je,p as Ye,r as Xe,rn as Ze,t as Qe,un as $e}from"./index-Cd3Zh3nK.js";import{t as et}from"./useEntityRestURL-D7vuaG2W.js";import{n as tt}from"./getAnalytics-HqW0hniG.js";var nt=w(`between-horizontal-start`,[[`rect`,{width:`13`,height:`7`,x:`8`,y:`3`,rx:`1`,key:`pkso9a`}],[`path`,{d:`m2 9 3 3-3 3`,key:`1agib5`}],[`rect`,{width:`13`,height:`7`,x:`8`,y:`14`,rx:`1`,key:`1q5fc1`}]]),rt=w(`book`,[[`path`,{d:`M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20`,key:`k3hazp`}]]),it=w(`chart-area`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M7 11.207a.5.5 0 0 1 .146-.353l2-2a.5.5 0 0 1 .708 0l3.292 3.292a.5.5 0 0 0 .708 0l4.292-4.292a.5.5 0 0 1 .854.353V16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1z`,key:`q0gr47`}]]),at=w(`circle-x`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]]),ot=w(`file-pen`,[[`path`,{d:`M12.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v9.34`,key:`o6klzx`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10.378 12.622a1 1 0 0 1 3 3.003L8.36 20.637a2 2 0 0 1-.854.506l-2.867.837a.5.5 0 0 1-.62-.62l.836-2.869a2 2 0 0 1 .506-.853z`,key:`zhnas1`}]]),st=w(`logs`,[[`path`,{d:`M3 5h1`,key:`1mv5vm`}],[`path`,{d:`M3 12h1`,key:`lp3yf2`}],[`path`,{d:`M3 19h1`,key:`w6f3n9`}],[`path`,{d:`M8 5h1`,key:`1nxr5w`}],[`path`,{d:`M8 12h1`,key:`1con00`}],[`path`,{d:`M8 19h1`,key:`k7p10e`}],[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}]]),ct=w(`message-square-heart`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M7.5 9.5c0 .687.265 1.383.697 1.844l3.009 3.264a1.14 1.14 0 0 0 .407.314 1 1 0 0 0 .783-.004 1.14 1.14 0 0 0 .398-.31l3.008-3.264A2.77 2.77 0 0 0 16.5 9.5 2.5 2.5 0 0 0 12 8a2.5 2.5 0 0 0-4.5 1.5`,key:`1faxuh`}]]),lt=w(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]);async function ut(){await n.delete(`/Chat/Messages/`)}var T=e(ae(),1),E=oe();function dt({setMessages:e}){let[t,n]=(0,T.useState)(!1);return(0,E.jsxs)(`button`,{type:`button`,className:`clear-chat-button gap-1`,onClick:(0,T.useCallback)(async()=>{if(!t){n(!0);try{await ut(),e([])}catch(e){console.error(`Failed to clear chat:`,e)}finally{n(!1)}}},[t,e]),disabled:t,title:`Clear chat`,children:[t?(0,E.jsx)(Ae,{className:`animate-spin`,size:18}):(0,E.jsx)(Ee,{size:18}),`Clear`]})}async function ft(){let{data:e}=await n.get(`/Chat/Messages/`);return e}var pt=`vercel.ai.error`,mt=Symbol.for(pt),ht,gt,D=class e extends (gt=Error,ht=mt,gt){constructor({name:e,message:t,cause:n}){super(t),this[ht]=!0,this.name=e,this.cause=n}static isInstance(t){return e.hasMarker(t,pt)}static hasMarker(e,t){let n=Symbol.for(t);return typeof e==`object`&&!!e&&n in e&&typeof e[n]==`boolean`&&e[n]===!0}};function _t(e){return e==null?`unknown error`:typeof e==`string`?e:e instanceof Error?e.message:JSON.stringify(e)}var vt=`AI_InvalidArgumentError`,yt=`vercel.ai.error.${vt}`,bt=Symbol.for(yt),xt,St,Ct=class extends (St=D,xt=bt,St){constructor({message:e,cause:t,argument:n}){super({name:vt,message:e,cause:t}),this[xt]=!0,this.argument=n}static isInstance(e){return D.hasMarker(e,yt)}},wt=`AI_JSONParseError`,Tt=`vercel.ai.error.${wt}`,Et=Symbol.for(Tt),Dt,Ot,kt=class extends (Ot=D,Dt=Et,Ot){constructor({text:e,cause:t}){super({name:wt,message:`JSON parsing failed: Text: ${e}.
1
+ import{a as e,t}from"./rolldown-runtime-Cyuzqnbw.js";import{h as n,t as r}from"./button-kCMf1ZBL.js";import{C as i,S as a,T as o,_ as s,a as c,b as l,c as u,d,h as f,i as p,l as m,m as h,r as g,s as _,t as v,u as ee,v as y,w as b,x,y as S}from"./vendor-core-BIhSIGPv.js";import{A as te,C as ne,M as re,P as ie}from"./vendor-tanstack-DmFvmRiZ.js";import{a as ae}from"./vendor-datadog-Bq_0f1ke.js";import{r as oe}from"./vendor-react-BqTNj-ZI.js";import{Tt as C}from"./vendor-ui-to0aD0Fq.js";import{t as w}from"./createLucideIcon-D6HmSa4x.js";import{l as se,t as ce}from"./proxy-BJ77EweZ.js";import{_ as le,b as ue,c as de,h as fe,i as pe,m as me,p as he,r as ge,t as _e,v as ve,y as ye}from"./setComponentFile-Bz6WI4jy.js";import{$t as be,A as xe,E as Se,Gt as Ce,It as we,Jt as Te,Kt as Ee,N as De,O as Oe,Pt as ke,Qt as Ae,Rt as je,Ut as Me,V as Ne,Vt as Pe,Wt as Fe,X as Ie,Yt as Le,_ as Re,a as ze,b as Be,cn as Ve,i as He,in as Ue,j as We,k as Ge,ln as Ke,nn as qe,o as Je,p as Ye,r as Xe,rn as Ze,t as Qe,un as $e}from"./index-oRZw5GW3.js";import{t as et}from"./useEntityRestURL-14jWKu9J.js";import{n as tt}from"./getAnalytics-HqW0hniG.js";var nt=w(`between-horizontal-start`,[[`rect`,{width:`13`,height:`7`,x:`8`,y:`3`,rx:`1`,key:`pkso9a`}],[`path`,{d:`m2 9 3 3-3 3`,key:`1agib5`}],[`rect`,{width:`13`,height:`7`,x:`8`,y:`14`,rx:`1`,key:`1q5fc1`}]]),rt=w(`book`,[[`path`,{d:`M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20`,key:`k3hazp`}]]),it=w(`chart-area`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M7 11.207a.5.5 0 0 1 .146-.353l2-2a.5.5 0 0 1 .708 0l3.292 3.292a.5.5 0 0 0 .708 0l4.292-4.292a.5.5 0 0 1 .854.353V16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1z`,key:`q0gr47`}]]),at=w(`circle-x`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]]),ot=w(`file-pen`,[[`path`,{d:`M12.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v9.34`,key:`o6klzx`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10.378 12.622a1 1 0 0 1 3 3.003L8.36 20.637a2 2 0 0 1-.854.506l-2.867.837a.5.5 0 0 1-.62-.62l.836-2.869a2 2 0 0 1 .506-.853z`,key:`zhnas1`}]]),st=w(`logs`,[[`path`,{d:`M3 5h1`,key:`1mv5vm`}],[`path`,{d:`M3 12h1`,key:`lp3yf2`}],[`path`,{d:`M3 19h1`,key:`w6f3n9`}],[`path`,{d:`M8 5h1`,key:`1nxr5w`}],[`path`,{d:`M8 12h1`,key:`1con00`}],[`path`,{d:`M8 19h1`,key:`k7p10e`}],[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}]]),ct=w(`message-square-heart`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M7.5 9.5c0 .687.265 1.383.697 1.844l3.009 3.264a1.14 1.14 0 0 0 .407.314 1 1 0 0 0 .783-.004 1.14 1.14 0 0 0 .398-.31l3.008-3.264A2.77 2.77 0 0 0 16.5 9.5 2.5 2.5 0 0 0 12 8a2.5 2.5 0 0 0-4.5 1.5`,key:`1faxuh`}]]),lt=w(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]);async function ut(){await n.delete(`/Chat/Messages/`)}var T=e(ae(),1),E=oe();function dt({setMessages:e}){let[t,n]=(0,T.useState)(!1);return(0,E.jsxs)(`button`,{type:`button`,className:`clear-chat-button gap-1`,onClick:(0,T.useCallback)(async()=>{if(!t){n(!0);try{await ut(),e([])}catch(e){console.error(`Failed to clear chat:`,e)}finally{n(!1)}}},[t,e]),disabled:t,title:`Clear chat`,children:[t?(0,E.jsx)(Ae,{className:`animate-spin`,size:18}):(0,E.jsx)(Ee,{size:18}),`Clear`]})}async function ft(){let{data:e}=await n.get(`/Chat/Messages/`);return e}var pt=`vercel.ai.error`,mt=Symbol.for(pt),ht,gt,D=class e extends (gt=Error,ht=mt,gt){constructor({name:e,message:t,cause:n}){super(t),this[ht]=!0,this.name=e,this.cause=n}static isInstance(t){return e.hasMarker(t,pt)}static hasMarker(e,t){let n=Symbol.for(t);return typeof e==`object`&&!!e&&n in e&&typeof e[n]==`boolean`&&e[n]===!0}};function _t(e){return e==null?`unknown error`:typeof e==`string`?e:e instanceof Error?e.message:JSON.stringify(e)}var vt=`AI_InvalidArgumentError`,yt=`vercel.ai.error.${vt}`,bt=Symbol.for(yt),xt,St,Ct=class extends (St=D,xt=bt,St){constructor({message:e,cause:t,argument:n}){super({name:vt,message:e,cause:t}),this[xt]=!0,this.argument=n}static isInstance(e){return D.hasMarker(e,yt)}},wt=`AI_JSONParseError`,Tt=`vercel.ai.error.${wt}`,Et=Symbol.for(Tt),Dt,Ot,kt=class extends (Ot=D,Dt=Et,Ot){constructor({text:e,cause:t}){super({name:wt,message:`JSON parsing failed: Text: ${e}.
2
2
  Error message: ${_t(t)}`,cause:t}),this[Dt]=!0,this.text=e}static isInstance(e){return D.hasMarker(e,Tt)}},At=`AI_TypeValidationError`,jt=`vercel.ai.error.${At}`,Mt=Symbol.for(jt),Nt,Pt,O=class e extends (Pt=D,Nt=Mt,Pt){constructor({value:e,cause:t,context:n}){let r=`Type validation failed`;if(n?.field&&(r+=` for ${n.field}`),n?.entityName||n?.entityId){r+=` (`;let e=[];n.entityName&&e.push(n.entityName),n.entityId&&e.push(`id: "${n.entityId}"`),r+=e.join(`, `),r+=`)`}super({name:At,message:`${r}: Value: ${JSON.stringify(e)}.
3
3
  Error message: ${_t(t)}`,cause:t}),this[Nt]=!0,this.value=e,this.context=n}static isInstance(e){return D.hasMarker(e,jt)}static wrap({value:t,cause:n,context:r}){return e.isInstance(n)&&n.value===t&&n.context?.field===r?.field&&n.context?.entityName===r?.entityName&&n.context?.entityId===r?.entityId?n:new e({value:t,cause:n,context:r})}},Ft=class extends Error{constructor(e,t){super(e),this.name=`ParseError`,this.type=t.type,this.field=t.field,this.value=t.value,this.line=t.line}},It=10,Lt=13,k=32;function Rt(e){}function zt(e){if(typeof e==`function`)throw TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");let{onEvent:t=Rt,onError:n=Rt,onRetry:r=Rt,onComment:i,maxBufferSize:a}=e,o=[],s=0,c=!0,l,u=``,d=0,f,p=!1;function m(e){if(p)throw Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");if(c&&(c=!1,e.charCodeAt(0)===239&&e.charCodeAt(1)===187&&e.charCodeAt(2)===191&&(e=e.slice(3))),o.length===0){let t=g(e);t!==``&&(o.push(t),s=t.length),h();return}if(e.indexOf(`
4
4
  `)===-1&&e.indexOf(`\r`)===-1){o.push(e),s+=e.length,h();return}o.push(e);let t=o.join(``);o.length=0,s=0;let n=g(t);n!==``&&(o.push(n),s=n.length),h()}function h(){a!==void 0&&(s+u.length<=a||(p=!0,o.length=0,s=0,l=void 0,u=``,d=0,f=void 0,n(new Ft(`Buffered data exceeded max buffer size of ${a} characters`,{type:`max-buffer-size-exceeded`}))))}function g(e){let n=0;if(e.indexOf(`\r`)===-1){let r=e.indexOf(`
@@ -1698,4 +1698,4 @@ let results = Document.search({
1698
1698
  `},Xi={name:`readHarperSkill`,description:`Returns documentation for a Harper skill or best practice. Skills provide guidance on developing Harper applications.`,inputSchema:y({skill:g(Ji)})};async function Zi({input:{skill:e}}){return{success:!!Yi[e],message:Yi[e]||`No skill found with the name ${e}`}}var Qi={...Xi,icon:rt,execute:Zi},$i={name:`readLogs`,description:`Returns the matching logs from the server.`,inputSchema:y({log_name:g([`hdb.log`,`system.log`]).default(`hdb.log`),limit:x().or(c()).optional(),level:g([`notify`,`error`,`warn`,`info`,`debug`,`trace`,`undefined`]).or(c()).optional(),from:x().or(c()).optional(),until:x().or(c()).optional()})};async function ea({input:e,instanceClientParams:t}){try{return{success:!0,data:await Qe({...t,logFilters:e,replicated:t.entityType===`cluster`})}}catch(e){return{success:!1,message:`Error: ${e}`}}}var ta={...$i,icon:st,execute:ea},na={name:`readTableRecords`,description:`Retrieves some or all table records from a database on the server.`,inputSchema:y({database:x().trim(),table:x().trim(),pageIndex:s().default(0),pageSize:s().default(10),primaryKey:x(),conditions:u(y({search_attribute:x(),search_type:g([`between`,`eq`,`equals`,`greater_than`,`greater_than_equal`,`less_than`,`less_than_equal`,`ne`,`not_equal`,`starts_with`]),search_value:_()})),sort:y({attribute:x(),descending:m()})})};async function ra({input:{database:e,table:t,conditions:n,primaryKey:r,...i},instanceClientParams:a}){try{if(!n.length){let{data:n}=await Ge({...a,databaseName:e,tableName:t,onlyIfCached:!0,searchAttribute:r,...i});return{success:!0,data:n}}let{data:o}=await He({...a,databaseName:e,tableName:t,onlyIfCached:!0,conditions:n,...i});return{success:!0,data:o}}catch(e){return{success:!1,message:`Error: ${e}`}}}var ia={...na,icon:Le,execute:ra},aa={name:`restartHTTPService`,description:`Restarts the HTTP service on the server to allow schema and resource changes to be applied.`,inputSchema:y({})};async function oa({instanceClientParams:e,baseURL:t}){let n=C.loading(`Restarting HTTP service...`,{description:`This may take a bit.`,duration:3e5});try{await Se({...e,operation:`restart_service`,replicated:e.entityType===`cluster`})}catch(e){return{success:!1,message:`Error: ${e}`}}return C.success(`Done!`,{description:`HTTP Service restarted!`,id:n,duration:5e3}),{success:!0,message:`HTTP Service restarted!`,webURL:t}}var sa={...aa,icon:Ae,execute:oa,requiresApproval:!0},ca={name:`setComponentFile`,description:`Returns the contents of a component file by its full path (which was returned by getComponents)`,inputSchema:y({path:x().trim(),payload:x(),encoding:g([`utf8`,`ASCII`,`binary`,`hex`,`base64`,`utf16le`,`latin1`,`ucs2`])})};async function la({input:{path:e,encoding:t,payload:n},instanceClientParams:r}){try{let i=e.split(`/`),a=i.shift(),o=i.join(`/`),s=await _e({...r,file:o,project:a,payload:n,encoding:t});return await Pe.invalidateQueries({queryKey:[r.entityId,`get_component_file`,a,o]}),De(`ReloadApplicationRootEntries`,!0),{success:!0,data:s}}catch(e){return{success:!1,message:`Error: ${e}`}}}var ua={...ca,icon:ot,execute:la,requiresApproval:!0},da={name:`updateTableRecords`,description:`Updates records in a particular table in a particular database on the server.`,inputSchema:y({database:x().trim(),table:x().trim(),records:u(_())})};async function fa({input:{database:e,table:t,records:n},instanceClientParams:r,params:i}){try{let a=await Xe({...r,databaseName:e,tableName:t,records:n}),{databaseName:o,tableName:s}=i;return await Pe.invalidateQueries({queryKey:[r.entityId,o,s]}),{success:!0,data:a}}catch(e){return{success:!1,message:`Error: ${e}`}}}var pa={readHarperSkill:Qi,createApp:gi,readLogs:ta,getAnalytics:Ti,listAnalyticsMetrics:qi,restartHTTPService:sa,collectFeedback:pi,getUserContext:Bi,getComponentFile:Oi,getComponents:ji,setComponentFile:ua,dropComponentFile:Si,getDescribeAll:Pi,getDescribeTable:Li,insertTableRecords:Ui,readTableRecords:ia,updateTableRecords:{...da,icon:nt,execute:fa,requiresApproval:!0},deleteTableRecords:yi};function ma(e){return pa[e]}function ha({part:e,onApprove:t,onDeny:n,onAlwaysApprove:i,isApproving:a}){let[o,s]=(0,T.useState)(!1),[c,l]=(0,T.useState)(!1),u=Br(e),d=ma(u),f=d?.icon||Ze,p=d?.requiresApproval,m=(0,T.useMemo)(()=>e.input?typeof e.input==`object`?Object.keys(e.input).length===0:!1:!0,[e.input]),h=(0,T.useMemo)(()=>{let t=JSON.stringify(e.input,null,` `);return{json:t,lines:t?t.split(`
1699
1699
  `).length:0}},[e.input]),g=(0,T.useMemo)(()=>{let t=JSON.stringify(e.output,null,` `);return{json:t,lines:t?t.split(`
1700
1700
  `).length:0}},[e.output]);return(0,E.jsxs)(`div`,{className:`tool-invocation ${e.state}`,children:[(0,E.jsxs)(`div`,{className:`tool-info`,children:[(0,E.jsxs)(`div`,{className:`tool-name`,children:[(0,E.jsx)(f,{size:14}),(0,E.jsx)(`span`,{children:u})]}),(0,E.jsxs)(`div`,{className:`tool-status`,children:[e.state===`input-streaming`&&`Thinking...`,e.state===`input-available`&&(a?`Executing...`:p?`Awaiting Approval...`:`Executing...`),e.state===`output-available`&&(e.output?.error?(0,E.jsx)(at,{size:14,className:`text-destructive`}):(0,E.jsx)($e,{size:14}))]})]}),e.state!==`input-streaming`&&(0,E.jsxs)(`div`,{className:`tool-io`,children:[!m&&(0,E.jsxs)(`div`,{className:`tool-args`,children:[(0,E.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-1`,children:[(0,E.jsx)(`strong`,{children:`Input:`}),h.lines>3&&(0,E.jsx)(r,{type:`button`,variant:`ghost`,size:`sm`,className:`h-6 px-2 text-[10px] uppercase tracking-wider text-muted-foreground hover:text-foreground`,onClick:()=>s(!o),children:o?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(Ve,{size:12}),`Hide`]}):(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(Ke,{size:12}),`Show`]})})]}),(0,E.jsx)(`div`,{className:o?`whitespace-pre-wrap`:`line-clamp-3 overflow-hidden whitespace-pre-wrap`,children:h.json})]}),e.state===`input-available`&&p&&(0,E.jsxs)(`div`,{className:`flex gap-2 mt-3 pt-3 border-t`,children:[(0,E.jsxs)(r,{size:`sm`,className:`h-8 text-xs bg-green-600 hover:bg-green-700 text-white`,onClick:()=>t?.(e.toolCallId),disabled:a,children:[a?(0,E.jsx)(qe,{className:`mr-2 h-3 w-3 animate-spin`}):null,`Approve`]}),(0,E.jsx)(r,{type:`button`,size:`sm`,variant:`outline`,className:`h-8 text-xs`,onClick:()=>i?.(e.toolCallId),disabled:a,children:`Always Approve`}),(0,E.jsx)(r,{type:`button`,size:`sm`,variant:`outline`,className:`h-8 text-xs`,onClick:()=>n?.(e.toolCallId),disabled:a,children:`Deny`})]}),e.state===`output-available`&&(0,E.jsx)(E.Fragment,{children:d?.render?d.render(e):(0,E.jsxs)(`div`,{className:`tool-result`,children:[(0,E.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-1`,children:[(0,E.jsx)(`strong`,{children:`Result:`}),g.lines>3&&(0,E.jsx)(r,{type:`button`,variant:`ghost`,size:`sm`,className:`h-6 px-2 text-[10px] uppercase tracking-wider text-muted-foreground hover:text-foreground`,onClick:()=>l(!c),children:c?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(Ve,{size:12}),`Hide`]}):(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(Ke,{size:12}),`Show`]})})]}),(0,E.jsx)(`div`,{className:c?`whitespace-pre-wrap`:`line-clamp-3 overflow-hidden whitespace-pre-wrap`,children:g.json})]})})]})]})}function ga({message:e,onApprove:t,onDeny:n,onAlwaysApprove:r,approvingToolCallIds:i}){return(0,E.jsxs)(ce.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},className:`message-bubble ${e.role===`user`?`user`:`assistant`}`,children:[(0,E.jsx)(`div`,{className:`avatar`,children:e.role===`user`?(0,E.jsx)(Fe,{size:18}):(0,E.jsx)(se,{size:18})}),(0,E.jsx)(`div`,{className:`content`,children:e.parts?.map((e,a)=>Ir(e)?(0,E.jsx)(`div`,{className:`text-block`,children:e.text},a):K(e)?(0,E.jsx)(ha,{part:e,onApprove:t,onDeny:n,onAlwaysApprove:r,isApproving:i?.has(e.toolCallId)},a):null)})]},e.id)}function _a(e){return te({queryKey:[`getMyUsage`,e],queryFn:async()=>{let{data:t}=await n.get(`/Chat/Usage/${e}`);return t}})}function va(){let{organizationId:e}=ne({strict:!1});return re(_a(e))}function ya(){let{data:e,isLoading:t,error:n}=va();if(t||n||!e)return null;let{usageUSD:r,monthlyLimitUSD:i,usageBarPercent:a}=e,o=e=>new Intl.NumberFormat(`en-US`,{style:`currency`,currency:`USD`}).format(e);return(0,E.jsxs)(`div`,{className:`usage-container`,children:[(0,E.jsxs)(`div`,{className:`usage-info`,children:[(0,E.jsx)(`span`,{children:`Monthly Org Usage`}),(0,E.jsxs)(`span`,{children:[o(r),` / `,o(i)]}),(0,E.jsxs)(`span`,{children:[Math.round(a),`%`]})]}),(0,E.jsx)(`div`,{className:`usage-bar-bg`,children:(0,E.jsx)(`div`,{className:`usage-bar-fill`,style:{width:`${a}%`}})})]})}function ba({autoFocus:e,closeChat:t}){let n=ne({strict:!1}),{organizationId:r}=n,[i,a]=xe(`ApplicationChat`,``),[o,s]=(0,T.useState)(!0),[c,l]=(0,T.useState)({}),[u,d]=(0,T.useState)(new Set),[f,p]=je(we.ChatAlwaysApprovedTools,[]),m=new Set(f),h=et(),g=ke(),_=ie(),{messages:v,sendMessage:ee,status:y,addToolOutput:b,setMessages:x}=ci({transport:Xr(r),generateId:A(),sendAutomaticallyWhen:Yr,onFinish(){_.invalidateQueries({queryKey:[`getMyUsage`]})},async onToolCall({toolCall:e}){if(e.dynamic)return;let t=ma(e.toolName);if(t){if(t.requiresApproval&&!m.has(e.toolName)){let t={type:`tool-call`,toolCallId:e.toolCallId,toolName:e.toolName,input:e.input};l(n=>({...n,[e.toolCallId]:t}));return}let r=await t.execute({input:e.input,instanceClientParams:g,baseURL:h,params:n});b({tool:e.toolName,toolCallId:e.toolCallId,output:r})}}}),S=(0,T.useCallback)(async e=>{let t=c[e];if(t){d(t=>{let n=new Set(t);return n.add(e),n});try{let r=ma(t.toolName);if(r){let i=await r.execute({input:t.input,instanceClientParams:g,baseURL:h,params:n});b({tool:t.toolName,toolCallId:t.toolCallId,output:i}),l(t=>{let n={...t};return delete n[e],n})}}finally{d(t=>{let n=new Set(t);return n.delete(e),n})}}},[c,g,h,b,n]),te=(0,T.useCallback)(e=>{let t=c[e];t&&(b({tool:t.toolName,toolCallId:t.toolCallId,output:{error:`User denied the tool execution.`}}),l(t=>{let n={...t};return delete n[e],n}))},[c,b]),re=(0,T.useCallback)(async e=>{let t=c[e];t&&(p(e=>Oe([...e,t.toolName])),await S(e))},[c,p,S]);(0,T.useEffect)(()=>{(async()=>{try{let e=await ft();Array.isArray(e)&&x(e)}catch(e){console.error(`Failed to fetch initial messages:`,e)}finally{s(!1)}})()},[x]);let ae=y===`streaming`||y===`submitted`,oe=(0,T.useRef)(null);return(0,T.useEffect)(()=>{oe.current?.scrollIntoView({behavior:`smooth`})},[v]),(0,E.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,E.jsxs)(`div`,{className:`flex items-start justify-between gap-6 px-4 py-2.5 border-b border-border bg-card`,children:[(0,E.jsxs)(`div`,{className:`flex flex-col gap-1 min-w-0 flex-1`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,E.jsx)(se,{className:`text-primary`,size:20}),(0,E.jsx)(`span`,{className:`font-semibold text-foreground`,children:`Harper Agent`})]}),(0,E.jsx)(ya,{})]}),(0,E.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,E.jsx)(dt,{setMessages:x}),(0,E.jsx)(`button`,{onClick:t,className:`p-1 hover:bg-accent rounded-md transition-colors text-muted-foreground hover:text-foreground`,title:`Close chat`,children:(0,E.jsx)(Me,{size:20})})]})]}),(0,E.jsx)(`div`,{className:`flex-1 overflow-hidden`,children:(0,E.jsxs)(`div`,{className:`chat-interface h-full w-full`,children:[(0,E.jsxs)(`div`,{className:`messages-area`,children:[o&&(0,E.jsx)(ui,{}),!o&&v.length===0&&(0,E.jsxs)(`div`,{className:`empty-state`,children:[(0,E.jsx)(se,{size:48}),(0,E.jsx)(`p`,{children:`Ask me to create a Harper app!`})]}),v.map(e=>(0,E.jsx)(ga,{message:e,onApprove:S,onDeny:te,onAlwaysApprove:re,approvingToolCallIds:u},e.id)),(0,E.jsx)(`div`,{ref:oe})]}),(0,E.jsx)(li,{input:i,setInput:a,onSubmit:e=>{e.preventDefault(),i.trim()&&!ae&&!o&&(ee({text:i}),a(``))},disabled:o,autoFocus:e})]})})]})}export{ba as Chat};
1701
- //# sourceMappingURL=Chat-BdFickL8.js.map
1701
+ //# sourceMappingURL=Chat-DMBW4pI2.js.map