@hitch42/applet 0.1.1-beta.8 → 0.1.1-beta.9

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 (167) hide show
  1. package/dist/_internal/client.js +120 -11
  2. package/dist/_internal/log-context.d.ts +34 -0
  3. package/dist/_internal/log-context.js +2 -0
  4. package/dist/_internal/server.d.ts +1 -1
  5. package/dist/_internal/server.js +112 -57
  6. package/dist/applet.js +12 -12
  7. package/dist/build-Bh_S5BUv.js +2 -0
  8. package/dist/{build-DANx9Hgg.js → build-CEfFoIZZ.js} +1 -1
  9. package/dist/{ci-5qWl7lT3.js → ci-BKw14X2h.js} +14 -13
  10. package/dist/client.d.ts +3 -3
  11. package/dist/{contract-rP_eV9PK.d.ts → contract-CsUpTBe0.d.ts} +1 -1
  12. package/dist/{deploy-MQWLG2EA.js → deploy-wGYjwXrx.js} +139 -88
  13. package/dist/{generate-BxYHdoAQ.js → generate-BEIYs17x.js} +65 -28
  14. package/dist/generate-Dox-OYt6.js +2 -0
  15. package/dist/headers-DkNr9MLJ.js +17 -0
  16. package/dist/index.d.ts +23 -22
  17. package/dist/index.js +2 -1
  18. package/dist/{init-jDEgYIXg.js → init-6oGPM46R.js} +15 -17
  19. package/dist/{load-config-BYSxDVAl.js → load-config-xEdTXs0y.js} +2 -2
  20. package/dist/log-context-zu8U9Sjm.js +73 -0
  21. package/dist/{login-C7RKmmTe.js → login-CUx3TmFQ.js} +1 -1
  22. package/dist/{logs-DgjgAxj2.js → logs-DSjuEN0Q.js} +20 -22
  23. package/dist/{manifest-DD_SGkS6.d.ts → manifest-C6_F4bL8.d.ts} +5 -1
  24. package/dist/{manifest-Bp87Uz0a.js → manifest-CJSL9GuC.js} +20 -4
  25. package/dist/{project-CbYPtpPq.js → project-BRZGd6xq.js} +199 -18
  26. package/dist/query-cache-CXmAyLv3.js +82 -0
  27. package/dist/react.d.ts +3 -2
  28. package/dist/react.js +98 -80
  29. package/dist/{schedules-dhU1yyFr.js → schedules-C8_Svr4h.js} +1 -1
  30. package/dist/server.d.ts +9 -4
  31. package/dist/server.js +29 -8
  32. package/dist/{telephony-protocol-DRgiYjqQ.d.ts → telephony-protocol-D-nf3Gca.d.ts} +15 -13
  33. package/dist/telephony.d.ts +24 -4
  34. package/dist/telephony.js +135 -16
  35. package/dist/{upload-YbRKEqR6.d.ts → upload-DKZzz5kW.d.ts} +6 -6
  36. package/dist/{variables-Bwnr7oxf.js → variables-DT5RyHdH.js} +13 -13
  37. package/dist/vite.d.ts +3 -60
  38. package/dist/vite.js +50 -15
  39. package/dist/{workflow-engine-MogejNfF.js → workflow-engine-BOTzURKM.js} +1 -7
  40. package/dist/{workspace-XVtM12ZC.js → workspace-D0dnnlxL.js} +33 -38
  41. package/package.json +13 -5
  42. package/scaffold/.agents/skills/hitch-applets/SKILL.md +30 -4
  43. package/scaffold/.agents/skills/hitch-applets/references/manifest.md +8 -0
  44. package/scaffold/.agents/skills/hitch-applets/references/markdown.md +2 -0
  45. package/scaffold/.agents/skills/hitch-applets/references/records.md +23 -1
  46. package/scaffold/.agents/skills/hitch-data/SKILL.md +2 -1
  47. package/scaffold/.agents/skills/hitch-data/references/attributes.md +7 -1
  48. package/scaffold/.agents/skills/hitch-data/references/limits.md +13 -13
  49. package/scaffold/.agents/skills/hitch-theory/SKILL.md +3 -2
  50. package/scaffold/.agents/skills/react-best-practices/SKILL.md +127 -0
  51. package/scaffold/.agents/skills/react-best-practices/rules/advanced-effect-event-deps.md +50 -0
  52. package/scaffold/.agents/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  53. package/scaffold/.agents/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  54. package/scaffold/.agents/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  55. package/scaffold/.agents/skills/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
  56. package/scaffold/.agents/skills/react-best-practices/rules/async-defer-await.md +82 -0
  57. package/scaffold/.agents/skills/react-best-practices/rules/async-dependencies.md +48 -0
  58. package/scaffold/.agents/skills/react-best-practices/rules/async-parallel.md +24 -0
  59. package/scaffold/.agents/skills/react-best-practices/rules/bundle-analyzable-paths.md +42 -0
  60. package/scaffold/.agents/skills/react-best-practices/rules/bundle-barrel-imports.md +39 -0
  61. package/scaffold/.agents/skills/react-best-practices/rules/bundle-conditional.md +35 -0
  62. package/scaffold/.agents/skills/react-best-practices/rules/bundle-defer-third-party.md +46 -0
  63. package/scaffold/.agents/skills/react-best-practices/rules/bundle-dynamic-imports.md +38 -0
  64. package/scaffold/.agents/skills/react-best-practices/rules/bundle-preload.md +40 -0
  65. package/scaffold/.agents/skills/react-best-practices/rules/client-event-listeners.md +78 -0
  66. package/scaffold/.agents/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
  67. package/scaffold/.agents/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  68. package/scaffold/.agents/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
  69. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-function-results.md +58 -0
  70. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  71. package/scaffold/.agents/skills/react-best-practices/rules/js-cache-storage.md +56 -0
  72. package/scaffold/.agents/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  73. package/scaffold/.agents/skills/react-best-practices/rules/js-early-exit.md +50 -0
  74. package/scaffold/.agents/skills/react-best-practices/rules/js-flatmap-filter.md +51 -0
  75. package/scaffold/.agents/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  76. package/scaffold/.agents/skills/react-best-practices/rules/js-index-maps.md +37 -0
  77. package/scaffold/.agents/skills/react-best-practices/rules/js-length-check-first.md +50 -0
  78. package/scaffold/.agents/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  79. package/scaffold/.agents/skills/react-best-practices/rules/js-request-idle-callback.md +104 -0
  80. package/scaffold/.agents/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  81. package/scaffold/.agents/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  82. package/scaffold/.agents/skills/react-best-practices/rules/rendering-activity.md +26 -0
  83. package/scaffold/.agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
  84. package/scaffold/.agents/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
  85. package/scaffold/.agents/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  86. package/scaffold/.agents/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
  87. package/scaffold/.agents/skills/react-best-practices/rules/rendering-resource-hints.md +81 -0
  88. package/scaffold/.agents/skills/react-best-practices/rules/rendering-script-defer-async.md +36 -0
  89. package/scaffold/.agents/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  90. package/scaffold/.agents/skills/react-best-practices/rules/rendering-usetransition-loading.md +43 -0
  91. package/scaffold/.agents/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  92. package/scaffold/.agents/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  93. package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  94. package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  95. package/scaffold/.agents/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
  96. package/scaffold/.agents/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
  97. package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
  98. package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo.md +44 -0
  99. package/scaffold/.agents/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  100. package/scaffold/.agents/skills/react-best-practices/rules/rerender-no-inline-components.md +75 -0
  101. package/scaffold/.agents/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  102. package/scaffold/.agents/skills/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
  103. package/scaffold/.agents/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  104. package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
  105. package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  106. package/scaffold/.agents/skills/tanstack-query/SKILL.md +136 -0
  107. package/scaffold/.agents/skills/tanstack-query/references/compositions/automatic-invalidation-after-mutations.md +124 -0
  108. package/scaffold/.agents/skills/tanstack-query/references/compositions/broadcast-realtime-and-multi-tab-synchronization.md +150 -0
  109. package/scaffold/.agents/skills/tanstack-query/references/compositions/compose-query-with-tanstack-router-and-start.md +248 -0
  110. package/scaffold/.agents/skills/tanstack-query/references/compositions/enforce-query-best-practices-with-eslint.md +167 -0
  111. package/scaffold/.agents/skills/tanstack-query/references/compositions/persist-offline-and-restore-caches.md +181 -0
  112. package/scaffold/.agents/skills/tanstack-query/references/compositions/query-data-and-forms.md +156 -0
  113. package/scaffold/.agents/skills/tanstack-query/references/core/build-query-abstractions.md +130 -0
  114. package/scaffold/.agents/skills/tanstack-query/references/core/cancel-queries-and-consume-abort-signals.md +176 -0
  115. package/scaffold/.agents/skills/tanstack-query/references/core/concurrent-optimistic-updates.md +135 -0
  116. package/scaffold/.agents/skills/tanstack-query/references/core/coordinate-query-execution.md +188 -0
  117. package/scaffold/.agents/skills/tanstack-query/references/core/design-query-keys-and-options.md +182 -0
  118. package/scaffold/.agents/skills/tanstack-query/references/core/fetch-and-observe-queries.md +193 -0
  119. package/scaffold/.agents/skills/tanstack-query/references/core/implement-optimistic-updates-and-cache-writes.md +168 -0
  120. package/scaffold/.agents/skills/tanstack-query/references/core/paginate-and-build-infinite-queries.md +188 -0
  121. package/scaffold/.agents/skills/tanstack-query/references/core/seed-placeholder-select-and-transform-data.md +188 -0
  122. package/scaffold/.agents/skills/tanstack-query/references/core/selectors-and-derived-state.md +145 -0
  123. package/scaffold/.agents/skills/tanstack-query/references/core/tune-defaults-freshness-retries-and-refetching.md +172 -0
  124. package/scaffold/.agents/skills/tanstack-query/references/core/understand-query-internals-and-observers.md +104 -0
  125. package/scaffold/.agents/skills/tanstack-query/references/core/write-mutations-and-invalidate-related-queries.md +183 -0
  126. package/scaffold/.agents/skills/tanstack-query/references/framework/debug-with-devtools.md +169 -0
  127. package/scaffold/.agents/skills/tanstack-query/references/framework/handle-status-and-errors.md +119 -0
  128. package/scaffold/.agents/skills/tanstack-query/references/framework/shape-data-and-render-efficiently.md +184 -0
  129. package/scaffold/.agents/skills/tanstack-query/references/framework/use-framework-adapter-reactivity.md +185 -0
  130. package/scaffold/.agents/skills/tanstack-query/references/framework/use-suspense-and-error-boundaries.md +208 -0
  131. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/migrate-major-versions-and-codemods.md +169 -0
  132. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/prefetch-and-remove-request-waterfalls.md +228 -0
  133. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/setup-query-client-and-providers.md +161 -0
  134. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/ssr-hydration-and-streaming.md +209 -0
  135. package/scaffold/.agents/skills/tanstack-query/references/lifecycle/test-query-code.md +160 -0
  136. package/scaffold/.agents/skills/tanstack-router/SKILL.md +134 -0
  137. package/scaffold/.agents/skills/tanstack-router/references/compositions/router-query.md +412 -0
  138. package/scaffold/.agents/skills/tanstack-router/references/react-router.md +495 -0
  139. package/scaffold/.agents/skills/tanstack-router/references/router-core/auth-and-guards.md +495 -0
  140. package/scaffold/.agents/skills/tanstack-router/references/router-core/code-splitting.md +318 -0
  141. package/scaffold/.agents/skills/tanstack-router/references/router-core/data-loading.md +490 -0
  142. package/scaffold/.agents/skills/tanstack-router/references/router-core/index.md +158 -0
  143. package/scaffold/.agents/skills/tanstack-router/references/router-core/navigation.md +433 -0
  144. package/scaffold/.agents/skills/tanstack-router/references/router-core/not-found-and-errors.md +436 -0
  145. package/scaffold/.agents/skills/tanstack-router/references/router-core/path-params.md +383 -0
  146. package/scaffold/.agents/skills/tanstack-router/references/router-core/search-params.md +343 -0
  147. package/scaffold/.agents/skills/tanstack-router/references/router-core/ssr.md +462 -0
  148. package/scaffold/.agents/skills/tanstack-router/references/router-core/type-safety.md +493 -0
  149. package/scaffold/.agents/skills/tanstack-router/references/router-plugin.md +250 -0
  150. package/scaffold/.agents/skills/tanstack-router/references/virtual-file-routes.md +215 -0
  151. package/scaffold/.agents/skills/web-design-guidelines/SKILL.md +184 -0
  152. package/scaffold/.github/workflows/hitch.yml +1 -1
  153. package/scaffold/AGENTS.md +2 -2
  154. package/scaffold/applet/src/client/components/ui/alert.tsx +1 -1
  155. package/scaffold/applet/src/client/components/ui/button.tsx +1 -1
  156. package/scaffold/applet/src/client/components/ui/checkbox.tsx +1 -1
  157. package/scaffold/applet/src/client/components/ui/dialog.tsx +2 -2
  158. package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +2 -2
  159. package/scaffold/applet/src/client/components/ui/input-group.tsx +2 -2
  160. package/scaffold/applet/src/client/components/ui/select.tsx +2 -2
  161. package/scaffold/applet/src/client/components/ui/sheet.tsx +2 -2
  162. package/scaffold/applet/src/client/components/ui/spinner.tsx +2 -1
  163. package/scaffold/applet/src/client/components/ui/tabs.tsx +1 -1
  164. package/scaffold/applet/src/client/lib/utils.ts +1 -6
  165. package/scaffold/applet/src/client/styles/globals.css +2 -0
  166. package/dist/build-CFCKKMn7.js +0 -2
  167. package/dist/generate-CQ07Hdpo.js +0 -2
package/dist/telephony.js CHANGED
@@ -28,9 +28,12 @@ const createTelephonyApi = (baseUrl = location.origin) => {
28
28
  return response.json();
29
29
  };
30
30
  return {
31
- token: (deviceKey) => request("voice/token", {
31
+ token: (deviceKey, acceptsCalls) => request("voice/token", {
32
32
  method: "POST",
33
- body: JSON.stringify({ deviceKey })
33
+ body: JSON.stringify({
34
+ deviceKey,
35
+ acceptsCalls
36
+ })
34
37
  }),
35
38
  startCall: (numberId, to) => request("calls", {
36
39
  method: "POST",
@@ -165,14 +168,18 @@ const DEVICE_KEY = "hitch:telephony:device";
165
168
  let singleton;
166
169
  var Phone = class {
167
170
  state = {
171
+ owner: false,
168
172
  status: "off",
169
173
  error: null,
174
+ incoming: null,
170
175
  active: null
171
176
  };
172
177
  listeners = /* @__PURE__ */ new Set();
173
178
  api;
174
179
  client = null;
175
180
  currentCall = null;
181
+ incomingCall = null;
182
+ acceptsCalls;
176
183
  connectPromise = null;
177
184
  releaseLock = null;
178
185
  lockAbortController = null;
@@ -186,8 +193,11 @@ var Phone = class {
186
193
  audio = null;
187
194
  firstLogin = true;
188
195
  callStarting = false;
196
+ reconnectOnPageShow = false;
197
+ connectionRequested = false;
189
198
  constructor(options = {}) {
190
199
  this.api = createTelephonyApi(options.baseUrl);
200
+ this.acceptsCalls = options.acceptsCalls ?? false;
191
201
  }
192
202
  subscribe = (listener) => {
193
203
  this.listeners.add(listener);
@@ -248,6 +258,7 @@ var Phone = class {
248
258
  };
249
259
  }
250
260
  connect = () => {
261
+ this.connectionRequested = true;
251
262
  this.connectPromise ??= this.connectInternal().finally(() => {
252
263
  this.connectPromise = null;
253
264
  });
@@ -255,6 +266,8 @@ var Phone = class {
255
266
  };
256
267
  async connectInternal() {
257
268
  if (this.state.status === "ready") return;
269
+ window.addEventListener("pagehide", this.pageHide);
270
+ window.addEventListener("pageshow", this.pageShow);
258
271
  this.channel ??= new BroadcastChannel("hitch:telephony");
259
272
  this.channel.onmessage = this.onChannelMessage;
260
273
  this.update({
@@ -275,8 +288,10 @@ var Phone = class {
275
288
  });
276
289
  this.ownsPhone = true;
277
290
  this.update({
291
+ owner: true,
278
292
  status: "connecting",
279
293
  error: null,
294
+ incoming: null,
280
295
  active: null
281
296
  });
282
297
  await this.connectOwned();
@@ -297,6 +312,7 @@ var Phone = class {
297
312
  return;
298
313
  }
299
314
  this.ownsPhone = true;
315
+ this.update({ owner: true });
300
316
  await this.connectOwned();
301
317
  }
302
318
  async connectOwned() {
@@ -311,7 +327,7 @@ var Phone = class {
311
327
  8e3
312
328
  ]) {
313
329
  if (delay) await new Promise((resolve) => setTimeout(resolve, delay));
314
- const { token } = await this.api.token(deviceKey);
330
+ const { token } = await this.api.token(deviceKey, this.acceptsCalls);
315
331
  const { TelnyxRTC: Client } = await import("@telnyx/webrtc");
316
332
  const client = new Client({
317
333
  login_token: token,
@@ -320,15 +336,35 @@ var Phone = class {
320
336
  this.client = client;
321
337
  client.on("telnyx.notification", ({ type, call }) => {
322
338
  if (type !== "callUpdate" || !call) return;
323
- if (call.direction === "inbound") {
324
- call.hangup();
339
+ if (call === this.currentCall) {
340
+ this.onCallUpdate(call);
341
+ return;
342
+ }
343
+ if (call.direction !== "inbound") return;
344
+ if ([
345
+ "hangup",
346
+ "destroy",
347
+ "purge"
348
+ ].includes(call.state)) {
349
+ if (call === this.incomingCall) {
350
+ this.incomingCall = null;
351
+ this.update({ incoming: null });
352
+ }
353
+ return;
354
+ }
355
+ if (!this.acceptsCalls || this.currentCall || this.callStarting || this.incomingCall && this.incomingCall !== call) {
356
+ call.hangup().catch((error) => console.error("Call decline failed", error));
325
357
  return;
326
358
  }
327
- if (call === this.currentCall) this.onCallUpdate(call);
359
+ this.incomingCall = call;
360
+ if (call.state === "ringing") this.update({ incoming: {
361
+ id: call.id,
362
+ from: call.options.remoteCallerNumber ?? ""
363
+ } });
328
364
  });
329
365
  client.on("telnyx.warning", (warning) => {
330
366
  if (Number(warning.warning.code) !== 34001) return;
331
- this.api.token(deviceKey).then(({ token: nextToken }) => client.login({ creds: { login_token: nextToken } })).catch((error) => {
367
+ this.api.token(deviceKey, this.acceptsCalls).then(({ token: nextToken }) => client.login({ creds: { login_token: nextToken } })).catch((error) => {
332
368
  console.error("Phone token renewal failed", error);
333
369
  this.update({ error: String(error) });
334
370
  });
@@ -341,7 +377,6 @@ var Phone = class {
341
377
  });
342
378
  this.firstLogin = false;
343
379
  this.update({ status: "ready" });
344
- window.addEventListener("pagehide", this.disconnect);
345
380
  return;
346
381
  } catch (error) {
347
382
  await client.disconnect().catch((disconnectError) => console.error("Phone disconnect failed", disconnectError));
@@ -351,6 +386,7 @@ var Phone = class {
351
386
  }
352
387
  } catch (error) {
353
388
  this.update({
389
+ owner: false,
354
390
  status: "error",
355
391
  error: error instanceof Error ? error.message : String(error)
356
392
  });
@@ -360,13 +396,16 @@ var Phone = class {
360
396
  }
361
397
  }
362
398
  disconnect = () => {
399
+ this.connectionRequested = false;
363
400
  this.lockAbortController?.abort();
364
401
  this.lockAbortController = null;
365
402
  this.connectResolve?.();
366
403
  this.connectResolve = null;
367
404
  if (this.pollTimer) clearTimeout(this.pollTimer);
368
405
  this.pollTimer = null;
369
- window.removeEventListener("pagehide", this.disconnect);
406
+ window.removeEventListener("pagehide", this.pageHide);
407
+ window.removeEventListener("pageshow", this.pageShow);
408
+ this.reconnectOnPageShow = false;
370
409
  window.removeEventListener("beforeunload", this.beforeUnload);
371
410
  this.client?.disconnect().catch((error) => console.error("Phone disconnect failed", error));
372
411
  this.client = null;
@@ -377,20 +416,35 @@ var Phone = class {
377
416
  this.pendingCommands.clear();
378
417
  this.releaseLock?.();
379
418
  this.releaseLock = null;
419
+ this.currentCall = null;
420
+ this.incomingCall = null;
380
421
  this.update({
422
+ owner: false,
381
423
  status: "off",
424
+ incoming: null,
382
425
  active: null
383
426
  });
384
427
  this.ownsPhone = false;
385
428
  this.channel?.close();
386
429
  this.channel = null;
387
430
  };
431
+ pageHide = () => {
432
+ const reconnect = this.connectionRequested;
433
+ this.disconnect();
434
+ this.reconnectOnPageShow = reconnect;
435
+ if (reconnect) window.addEventListener("pageshow", this.pageShow);
436
+ };
437
+ pageShow = (event) => {
438
+ if (!event.persisted || !this.reconnectOnPageShow) return;
439
+ this.reconnectOnPageShow = false;
440
+ this.connect();
441
+ };
388
442
  beforeUnload = (event) => {
389
443
  event.preventDefault();
390
444
  event.returnValue = "";
391
445
  };
392
446
  call = async ({ numberId, to }) => {
393
- if (this.callStarting || this.state.active) throw new Error("A call is already in progress.");
447
+ if (this.callStarting || this.state.active || this.incomingCall || this.state.incoming) throw new Error("A call is already in progress.");
394
448
  if (this.state.status !== "ready") throw new Error("The phone is not ready.");
395
449
  if (!this.ownsPhone) return this.sendCommand("call", {
396
450
  numberId,
@@ -417,6 +471,7 @@ var Phone = class {
417
471
  this.update({
418
472
  error: null,
419
473
  active: {
474
+ direction: "outbound",
420
475
  callId,
421
476
  to,
422
477
  from: callerNumber,
@@ -432,6 +487,62 @@ var Phone = class {
432
487
  this.callStarting = false;
433
488
  }
434
489
  };
490
+ answer = async () => {
491
+ if (!this.state.incoming) throw new Error("There is no incoming call.");
492
+ if (!this.ownsPhone) return this.sendCommand("answer", this.state.incoming.id);
493
+ const call = this.incomingCall;
494
+ if (!call) throw new Error("There is no incoming call.");
495
+ if (!this.client) throw new Error("The phone is not ready.");
496
+ this.audio ??= document.createElement("audio");
497
+ this.audio.autoplay = true;
498
+ this.audio.hidden = true;
499
+ if (!this.audio.isConnected) document.body.append(this.audio);
500
+ this.client.remoteElement = this.audio;
501
+ call.options.remoteElement = this.audio;
502
+ this.currentCall = call;
503
+ this.incomingCall = null;
504
+ this.update({
505
+ incoming: null,
506
+ error: null,
507
+ active: {
508
+ direction: "inbound",
509
+ from: this.state.incoming.from,
510
+ state: "connecting",
511
+ muted: false,
512
+ startedAt: Date.now(),
513
+ recording: false
514
+ }
515
+ });
516
+ window.addEventListener("beforeunload", this.beforeUnload);
517
+ try {
518
+ await call.answer();
519
+ } catch (error) {
520
+ if (this.currentCall === call) {
521
+ this.currentCall = null;
522
+ this.incomingCall = call;
523
+ this.update({
524
+ active: null,
525
+ incoming: {
526
+ id: call.id,
527
+ from: call.options.remoteCallerNumber ?? ""
528
+ }
529
+ });
530
+ window.removeEventListener("beforeunload", this.beforeUnload);
531
+ }
532
+ throw error;
533
+ }
534
+ };
535
+ decline = async () => {
536
+ if (!this.state.incoming) throw new Error("There is no incoming call.");
537
+ if (!this.ownsPhone) return this.sendCommand("decline", this.state.incoming.id);
538
+ const call = this.incomingCall;
539
+ if (!call) throw new Error("There is no incoming call.");
540
+ await call.hangup();
541
+ if (this.incomingCall === call) {
542
+ this.incomingCall = null;
543
+ this.update({ incoming: null });
544
+ }
545
+ };
435
546
  sendCommand(action, value) {
436
547
  const id = crypto.randomUUID();
437
548
  return new Promise((resolve, reject) => {
@@ -462,7 +573,10 @@ var Phone = class {
462
573
  else if (data.type === "state" && !this.ownsPhone && "state" in data) {
463
574
  const state = data.state;
464
575
  if (typeof state !== "object" || state === null || !("status" in state)) return;
465
- this.state = state;
576
+ this.state = {
577
+ ...state,
578
+ owner: false
579
+ };
466
580
  this.listeners.forEach((listener) => listener());
467
581
  this.connectResolve?.();
468
582
  this.connectResolve = null;
@@ -483,6 +597,10 @@ var Phone = class {
483
597
  }));
484
598
  };
485
599
  async runCommand(data) {
600
+ if (data.action === "answer" || data.action === "decline") {
601
+ if (!this.incomingCall || data.value !== this.incomingCall.id) throw new Error("That call is no longer ringing.");
602
+ return data.action === "answer" ? this.answer() : this.decline();
603
+ }
486
604
  if (data.action === "call") {
487
605
  const value = data.value;
488
606
  if (!value || typeof value !== "object" || !("numberId" in value) || !("to" in value) || typeof value.numberId !== "string" || typeof value.to !== "string") throw new Error("Invalid call command.");
@@ -518,7 +636,7 @@ var Phone = class {
518
636
  }
519
637
  }
520
638
  async pollCall(callId) {
521
- if (this.state.active?.callId !== callId || this.state.active.state === "active") return;
639
+ if (this.state.active?.direction !== "outbound" || this.state.active.callId !== callId || this.state.active.state === "active") return;
522
640
  try {
523
641
  const { status } = await this.api.getCall(callId);
524
642
  if ([
@@ -533,7 +651,8 @@ var Phone = class {
533
651
  } catch (error) {
534
652
  console.error("Call status check failed", error);
535
653
  }
536
- if (this.getSnapshot().active?.callId === callId) this.pollTimer = setTimeout(() => void this.pollCall(callId), 1e4);
654
+ const active = this.getSnapshot().active;
655
+ if (active?.direction === "outbound" && active.callId === callId) this.pollTimer = setTimeout(() => void this.pollCall(callId), 1e4);
537
656
  }
538
657
  onCallUpdate(call) {
539
658
  const active = this.state.active;
@@ -562,15 +681,15 @@ var Phone = class {
562
681
  return;
563
682
  }
564
683
  const mapped = state === "active" ? "active" : state === "held" ? "held" : state === "ringing" ? "ringing" : "connecting";
565
- if (mapped === "active" && active.recording && !this.stopRecording && !this.recordingPromise) {
684
+ if (mapped === "active" && active.direction === "outbound" && active.recording && !this.stopRecording && !this.recordingPromise) {
566
685
  this.recordingPromise = startRecording(active.callId, call, this.api, (error) => {
567
686
  console.error("Call recording failed", error);
568
- if (this.state.active?.callId === active.callId) this.update({ active: {
687
+ if (this.state.active?.direction === "outbound" && this.state.active.callId === active.callId) this.update({ active: {
569
688
  ...this.state.active,
570
689
  recording: false
571
690
  } });
572
691
  }).then((stop) => {
573
- if (this.state.active?.callId === active.callId) this.stopRecording = stop;
692
+ if (this.state.active?.direction === "outbound" && this.state.active.callId === active.callId) this.stopRecording = stop;
574
693
  return stop;
575
694
  });
576
695
  this.recordingPromise.catch((error) => {
@@ -36,13 +36,13 @@ type FileOutput = {
36
36
  data: HitchFile;
37
37
  downloadUrl: string;
38
38
  };
39
- declare const fileSchema: z.ZodType<HitchFile>;
40
- declare const createFileOutputSchema: z.ZodType<CreateFileOutput>;
41
- declare const getFileOutputSchema: z.ZodType<FileOutput>;
39
+ declare const fileSchema: z.ZodType<HitchFile, HitchFile>;
40
+ declare const createFileOutputSchema: z.ZodType<CreateFileOutput, CreateFileOutput>;
41
+ declare const getFileOutputSchema: z.ZodType<FileOutput, FileOutput>;
42
42
  type FilesContract = {
43
- create: ContractProcedure<z.ZodType<CreateFileInput>, z.ZodType<CreateFileOutput>, Record<never, never>, Meta>;
44
- confirm: ContractProcedure<z.ZodType<FileIdInput>, z.ZodType<FileOutput>, Record<never, never>, Meta>;
45
- get: ContractProcedure<z.ZodType<FileIdInput>, z.ZodType<FileOutput>, Record<never, never>, Meta>;
43
+ create: ContractProcedure<z.ZodType<CreateFileInput, CreateFileInput>, z.ZodType<CreateFileOutput, CreateFileOutput>, Record<never, never>, Meta>;
44
+ confirm: ContractProcedure<z.ZodType<FileIdInput, FileIdInput>, z.ZodType<FileOutput, FileOutput>, Record<never, never>, Meta>;
45
+ get: ContractProcedure<z.ZodType<FileIdInput, FileIdInput>, z.ZodType<FileOutput, FileOutput>, Record<never, never>, Meta>;
46
46
  };
47
47
  declare const filesContract: FilesContract;
48
48
  //#endregion
@@ -1,5 +1,5 @@
1
- import { n as fetchWithOrgAuth } from "./workspace-XVtM12ZC.js";
2
- import { t as loadAppletConfig } from "./load-config-BYSxDVAl.js";
1
+ import { n as fetchWithOrgAuth } from "./workspace-D0dnnlxL.js";
2
+ import { t as loadAppletConfig } from "./load-config-xEdTXs0y.js";
3
3
  import { t as question } from "./prompt-ChS-grYO.js";
4
4
  import { z } from "zod";
5
5
  //#region src/variables.ts
@@ -14,12 +14,12 @@ const variableResponseSchema = z.object({ data: variableRowSchema });
14
14
  const variablesResponseSchema = z.object({ data: z.array(variableRowSchema) });
15
15
  async function getValue(options) {
16
16
  if (options.value !== void 0) return options.value;
17
- if (!(options.stdinIsTTY ?? process.stdin.isTTY === true)) throw new Error("A value is required when stdin is not a TTY.");
17
+ if (process.stdin.isTTY !== true) throw new Error("A value is required when stdin is not a TTY.");
18
18
  return question("Value: ", true);
19
19
  }
20
20
  async function confirmLiveChange(code, options) {
21
21
  if (options.yes === true) return;
22
- if (!(options.stdinIsTTY ?? process.stdin.isTTY === true)) throw new Error("Confirmation requires a TTY. Pass -y to continue.");
22
+ if (process.stdin.isTTY !== true) throw new Error("Confirmation requires a TTY. Pass -y to continue.");
23
23
  const answer = await question(`This modifies the live applet "${code}". Continue? [y/N] `);
24
24
  if (!["y", "yes"].includes(answer.trim().toLowerCase())) throw new Error("Variable change cancelled.");
25
25
  }
@@ -45,19 +45,19 @@ function variablesError(status, code, message) {
45
45
  const details = [code, message].filter((value) => value !== void 0).join(": ");
46
46
  return /* @__PURE__ */ new Error(`Variables request failed (${status})${details ? `: ${details}` : ""}.`);
47
47
  }
48
- async function requestForApplet(options, request) {
48
+ async function requestForApplet(request) {
49
49
  const { code, org } = await loadAppletConfig(process.cwd());
50
50
  return {
51
51
  code,
52
- response: await fetchWithOrgAuth(org, options, (instanceUrl, accessToken) => request(instanceUrl, accessToken, code))
52
+ response: await fetchWithOrgAuth(org, (instanceUrl, accessToken) => request(instanceUrl, accessToken, code))
53
53
  };
54
54
  }
55
55
  async function runVariablesSet(options) {
56
56
  const value = await getValue(options);
57
57
  const manifest = await loadAppletConfig(process.cwd());
58
58
  await confirmLiveChange(manifest.code, options);
59
- const fetcher = options.fetch ?? globalThis.fetch;
60
- const response = await fetchWithOrgAuth(manifest.org, options, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
59
+ const fetcher = globalThis.fetch;
60
+ const response = await fetchWithOrgAuth(manifest.org, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
61
61
  method: "PUT",
62
62
  headers: {
63
63
  Authorization: `Bearer ${accessToken}`,
@@ -75,9 +75,9 @@ async function runVariablesSet(options) {
75
75
  const { data } = variableResponseSchema.parse(await response.json());
76
76
  console.log(`Set ${data.key} ${data.secret ? "(secret)" : data.value ?? value} for applet "${manifest.code}".`);
77
77
  }
78
- async function runVariablesList(options) {
79
- const fetcher = options.fetch ?? globalThis.fetch;
80
- const { code, response } = await requestForApplet(options, (instanceUrl, accessToken, appletCode) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(appletCode)}/variables`, { headers: { Authorization: `Bearer ${accessToken}` } }));
78
+ async function runVariablesList() {
79
+ const fetcher = globalThis.fetch;
80
+ const { code, response } = await requestForApplet((instanceUrl, accessToken, appletCode) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(appletCode)}/variables`, { headers: { Authorization: `Bearer ${accessToken}` } }));
81
81
  if (!response.ok) {
82
82
  const { code: errorCode, message } = await readErrorDetails(response);
83
83
  throw variablesError(response.status, errorCode, message);
@@ -92,8 +92,8 @@ async function runVariablesList(options) {
92
92
  async function runVariablesDelete(options) {
93
93
  const manifest = await loadAppletConfig(process.cwd());
94
94
  await confirmLiveChange(manifest.code, options);
95
- const fetcher = options.fetch ?? globalThis.fetch;
96
- const response = await fetchWithOrgAuth(manifest.org, options, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
95
+ const fetcher = globalThis.fetch;
96
+ const response = await fetchWithOrgAuth(manifest.org, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
97
97
  method: "DELETE",
98
98
  headers: { Authorization: `Bearer ${accessToken}` }
99
99
  }));
package/dist/vite.d.ts CHANGED
@@ -1,63 +1,6 @@
1
- import { o as RegisteredAppletSourceDefinition } from "./manifest-DD_SGkS6.js";
1
+ import { o as RegisteredAppletSourceDefinition } from "./manifest-C6_F4bL8.js";
2
2
  import { PluginOption } from "vite";
3
- //#region ../shared/auth/src/store.d.mts
4
- interface SessionCredentials {
5
- type: "session";
6
- accessToken: string;
7
- expiresAt?: number;
8
- organizationId: string;
9
- orgCode: string;
10
- }
11
- interface StoreOptions {
12
- env?: NodeJS.ProcessEnv;
13
- homeDir?: string;
14
- }
15
- //#endregion
16
- //#region ../shared/auth/src/device.d.mts
17
- interface MeResponse {
18
- memberships: Array<{
19
- code: string;
20
- name: string;
21
- orgId: string;
22
- }>;
23
- organization: {
24
- code: string;
25
- id: string;
26
- } | null;
27
- person: {
28
- email: string;
29
- firstName: string;
30
- id: string;
31
- lastName: string;
32
- };
33
- }
34
- interface DeviceLoginOptions {
35
- expectedOrg?: string;
36
- fetch?: typeof fetch;
37
- noBrowser?: boolean;
38
- now?: () => number;
39
- openUrl?: (url: string) => void | Promise<void>;
40
- print?: (message: string) => void;
41
- sleep?: (milliseconds: number) => Promise<void>;
42
- store?: StoreOptions;
43
- }
44
- interface DeviceLoginResult {
45
- credentials: SessionCredentials;
46
- me: MeResponse;
47
- membership: MeResponse["memberships"][number];
48
- }
49
- declare function loginWithDevice(instanceUrl: string, options?: DeviceLoginOptions): Promise<DeviceLoginResult>;
50
- //#endregion
51
- //#region src/auth.d.ts
52
- interface OrgAuthOptions {
53
- fetch?: typeof fetch;
54
- login?: typeof loginWithDevice;
55
- stdinIsTTY?: boolean;
56
- store?: StoreOptions;
57
- }
58
- //#endregion
59
3
  //#region src/vite.d.ts
60
- type AppletOptions = OrgAuthOptions;
61
- declare function applet<const M extends RegisteredAppletSourceDefinition>(sourceDefinition: M, options?: AppletOptions): PluginOption[];
4
+ declare function applet<const M extends RegisteredAppletSourceDefinition>(sourceDefinition: M): PluginOption[];
62
5
  //#endregion
63
- export { AppletOptions, applet };
6
+ export { applet };
package/dist/vite.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { n as meSchema } from "./me-BW7Paary.js";
2
- import { i as APPLET_CODE_PATTERN, n as appletManifestSchema, r as appletSourceDefinitionSchema } from "./manifest-Bp87Uz0a.js";
3
- import { a as workflowOutcomeSchema, c as HITCH_SESSION_HEADER, l as HITCH_USER_HEADER, n as runWorkflowJournal } from "./workflow-engine-MogejNfF.js";
4
- import { c as organizationInstanceUrl, d as resolveInstanceUrl, l as rejectEnvironmentKey, s as bearerToken, t as resolveWorkspaceOrg, u as resolveAuthForOrg } from "./workspace-XVtM12ZC.js";
5
- import { c as writeClientEntry, i as writeRegisterDeclaration, l as writeManifestGen, r as syncContract, s as writeAppletRoot, u as writeServerEntry } from "./generate-BxYHdoAQ.js";
2
+ import { i as APPLET_CODE_PATTERN, n as appletManifestSchema, r as appletSourceDefinitionSchema } from "./manifest-CJSL9GuC.js";
3
+ import { a as openQueryCacheDatabase } from "./query-cache-CXmAyLv3.js";
4
+ import { d as HITCH_USER_HEADER, u as HITCH_SESSION_HEADER } from "./headers-DkNr9MLJ.js";
5
+ import { a as workflowOutcomeSchema, n as runWorkflowJournal } from "./workflow-engine-BOTzURKM.js";
6
+ import { c as bearerToken, d as resolveAuthForOrg, f as resolveInstanceUrl, l as organizationInstanceUrl, t as resolveWorkspaceOrg, u as rejectEnvironmentKey } from "./workspace-D0dnnlxL.js";
7
+ import { c as writeClientEntry, i as writeRegisterDeclaration, l as writeManifestGen, r as syncContract, s as writeAppletRoot, u as writeServerEntry } from "./generate-BEIYs17x.js";
6
8
  import { randomUUID } from "node:crypto";
7
9
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
10
  import { appendFile, readdir, rm, writeFile } from "node:fs/promises";
@@ -52,7 +54,7 @@ function createDevProxy(options) {
52
54
  [...headers.keys()].filter((name) => REQUEST_DROP.has(name) || name.startsWith("x-hitch-")).forEach((name) => headers.delete(name));
53
55
  headers.set("authorization", `Bearer ${options.token}`);
54
56
  const url = new URL(request.url);
55
- const upstream = await (options.fetch ?? globalThis.fetch)(`${options.orgUrl}${url.pathname}${url.search}`, {
57
+ const upstream = await globalThis.fetch(`${options.orgUrl}${url.pathname}${url.search}`, {
56
58
  method: request.method,
57
59
  headers,
58
60
  body: request.body,
@@ -317,6 +319,20 @@ function clientBootstrapScript(parentOrigin, appletCode) {
317
319
  : null
318
320
  });
319
321
 
322
+ // Opened here so it is ready by the time the applet module restores its
323
+ // query cache. A failure is reported when the module reads the promise.
324
+ Object.defineProperty(window, "__hitchCacheDatabase", {
325
+ configurable: false,
326
+ writable: false,
327
+ value: window.parent !== window && parentOrigin !== null
328
+ ? (function () {
329
+ var database = (${openQueryCacheDatabase.toString()})();
330
+ database.catch(function () {});
331
+ return database;
332
+ })()
333
+ : null
334
+ });
335
+
320
336
  function applyTheme(theme) {
321
337
  document.documentElement.classList.toggle("dark", theme === "dark");
322
338
  }
@@ -421,7 +437,7 @@ function clientBootstrapScript(parentOrigin, appletCode) {
421
437
  });
422
438
  })();`;
423
439
  }
424
- function applet(sourceDefinition, options = {}) {
440
+ function applet(sourceDefinition) {
425
441
  const parsedSourceDefinition = appletSourceDefinitionSchema.safeParse(sourceDefinition);
426
442
  if (!parsedSourceDefinition.success) {
427
443
  const raw = sourceDefinition;
@@ -458,7 +474,7 @@ function applet(sourceDefinition, options = {}) {
458
474
  const routesDirectory = resolve(resolvedRoot, "src/client/routes");
459
475
  const hasClient = existsSync(routesDirectory);
460
476
  const hasServer = existsSync(resolve(resolvedRoot, "src/server/main.ts"));
461
- if (!hasServer && parsedDefinition.data.telephony?.events.length) throw new Error("An applet with telephony events must have src/server/main.ts.");
477
+ if (!hasServer && parsedDefinition.data.telephony?.events?.length) throw new Error("An applet with telephony events must have src/server/main.ts.");
462
478
  if (!hasServer && (parsedDefinition.data.schedules?.length ?? 0) > 0) throw new Error("An applet with schedules must have src/server/main.ts.");
463
479
  const legacyMain = resolve(resolvedRoot, "src/client/main.tsx");
464
480
  const indexHtml = resolve(resolvedRoot, "index.html");
@@ -489,6 +505,11 @@ function applet(sourceDefinition, options = {}) {
489
505
  org: resolveWorkspaceOrg(callerRoot),
490
506
  ...parsedDefinition.data
491
507
  });
508
+ const clsxFromCn = {
509
+ name: "hitch-clsx",
510
+ resolveId: (id) => id === "clsx" ? "\0hitch:clsx" : void 0,
511
+ load: (id) => id === "\0hitch:clsx" ? "export { clsx, clsx as default } from \"cn\";" : void 0
512
+ };
492
513
  const orchestrator = {
493
514
  name: "hitch-applet",
494
515
  enforce: "pre",
@@ -508,9 +529,9 @@ function applet(sourceDefinition, options = {}) {
508
529
  });
509
530
  clearedOutDir = true;
510
531
  }
511
- if (environment.command === "build") themeStylesheetUrl = `${organizationInstanceUrl(await resolveInstanceUrl(void 0, options.store), manifest.org)}/theme.css`;
512
- if (environment.command === "build" && manifest.objects.length > 0) {
513
- contractSync ??= syncContract(resolve(root, ".hitch"), manifest, options);
532
+ if (environment.command === "build") themeStylesheetUrl = `${organizationInstanceUrl(await resolveInstanceUrl(), manifest.org)}/theme.css`;
533
+ if (environment.command === "build") {
534
+ contractSync ??= syncContract(resolve(root, ".hitch"), manifest);
514
535
  await contractSync;
515
536
  }
516
537
  const hasHitchGen = existsSync(resolve(root, ".hitch/index.ts"));
@@ -526,12 +547,12 @@ function applet(sourceDefinition, options = {}) {
526
547
  hasHitchGen ? void 0 : writeRegisterDeclaration(resolve(root, ".hitch"))
527
548
  ]);
528
549
  if (environment.command === "serve" && environment.mode !== "test" && environment.isPreview !== true) {
529
- const instanceUrl = await resolveInstanceUrl(void 0, options.store);
550
+ const instanceUrl = await resolveInstanceUrl();
530
551
  const orgUrl = organizationInstanceUrl(instanceUrl, manifest.org);
531
- const auth = await resolveAuthForOrg(instanceUrl, manifest.org, options.store);
552
+ const auth = await resolveAuthForOrg(instanceUrl, manifest.org);
532
553
  if (auth === void 0) throw new Error("Not logged in. Run applet login.");
533
554
  const token = bearerToken(auth);
534
- const meResponse = await (options.fetch ?? globalThis.fetch)(`${orgUrl}/api/v1/me`, { headers: { authorization: `Bearer ${token}` } });
555
+ const meResponse = await globalThis.fetch(`${orgUrl}/api/v1/me`, { headers: { authorization: `Bearer ${token}` } });
535
556
  rejectEnvironmentKey(meResponse, auth);
536
557
  if (meResponse.status === 401) throw new Error("Your login expired. Run applet login.");
537
558
  if (!meResponse.ok) throw new Error(`Hitch returned ${meResponse.status} for /api/v1/me.`);
@@ -540,7 +561,6 @@ function applet(sourceDefinition, options = {}) {
540
561
  orgUrl,
541
562
  token,
542
563
  source: auth.source,
543
- fetch: options.fetch,
544
564
  warn: (message) => devLogger?.warn(message),
545
565
  intercept: (request) => devWorkflows?.handle(request)
546
566
  });
@@ -585,8 +605,18 @@ function applet(sourceDefinition, options = {}) {
585
605
  }
586
606
  }
587
607
  }
608
+ if (environment.mode === "test") {
609
+ const colocated = (await readdir(resolve(root, "src"), { recursive: true })).filter((path) => /\.(test|spec)\.[cm]?[jt]sx?$/.test(path));
610
+ if (colocated.length > 0) throw new Error(`Applet tests run only from the test folder. Move ${colocated.map((path) => `src/${path}`).join(", ")} to test/.`);
611
+ }
588
612
  return {
589
613
  base: `/${manifest.code}/`,
614
+ test: { include: ["test/**/*.test.{ts,tsx}"] },
615
+ resolve: { alias: {
616
+ "clsx/lite": "cn/lite",
617
+ "tailwind-merge": "cn"
618
+ } },
619
+ optimizeDeps: { rolldownOptions: { plugins: [clsxFromCn] } },
590
620
  ...hasServer && { environments: { worker: { build: { rollupOptions: { output: { codeSplitting: false } } } } } }
591
621
  };
592
622
  },
@@ -777,9 +807,14 @@ function applet(sourceDefinition, options = {}) {
777
807
  ...plugin,
778
808
  apply: ((_config, { mode }) => mode !== "test")
779
809
  }));
810
+ const hasClientSource = existsSync(resolve("src/client/routes"));
780
811
  return [
781
812
  orchestrator,
782
- ...existsSync(resolve("src/client/routes")) ? [tanstackRouter({
813
+ {
814
+ ...clsxFromCn,
815
+ enforce: "pre"
816
+ },
817
+ ...hasClientSource ? [tanstackRouter({
783
818
  generatedRouteTree: ".hitch/routeTree.gen.ts",
784
819
  routesDirectory: "src/client/routes",
785
820
  routeFileIgnorePattern: "__root",
@@ -1,10 +1,4 @@
1
1
  import { z } from "zod";
2
- //#region src/headers.ts
3
- const HITCH_USER_HEADER = "x-hitch-user";
4
- const HITCH_SESSION_HEADER = "x-hitch-session";
5
- const HITCH_APPLET_HEADER = "x-hitch-applet";
6
- const HITCH_APPLET_TOKEN_HEADER = "x-hitch-applet-token";
7
- //#endregion
8
2
  //#region src/server/workflow-protocol.ts
9
3
  const journalEntrySchema = z.discriminatedUnion("kind", [
10
4
  z.object({
@@ -114,4 +108,4 @@ async function runWorkflowJournal(engine, invoke) {
114
108
  }
115
109
  }
116
110
  //#endregion
117
- export { workflowOutcomeSchema as a, HITCH_SESSION_HEADER as c, workflowInvocationRequestSchema as i, HITCH_USER_HEADER as l, runWorkflowJournal as n, HITCH_APPLET_HEADER as o, journalEntrySchema as r, HITCH_APPLET_TOKEN_HEADER as s, WorkflowFailedError as t };
111
+ export { workflowOutcomeSchema as a, workflowInvocationRequestSchema as i, runWorkflowJournal as n, journalEntrySchema as r, WorkflowFailedError as t };