@hitch42/applet 0.1.1-beta.19 → 0.1.1-beta.21

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 (96) hide show
  1. package/dist/_internal/client.d.ts +0 -2
  2. package/dist/_internal/client.js +3 -5
  3. package/dist/_internal/log-context.d.ts +0 -2
  4. package/dist/_internal/log-context.js +1 -2
  5. package/dist/_internal/server.d.ts +2 -10
  6. package/dist/_internal/server.js +9 -14
  7. package/dist/applet.js +64 -23
  8. package/dist/auth-DuMRqSGe.js +49 -0
  9. package/dist/{batch-_ZjAg-Kk.js → batch-CiLZ177G.js} +3 -4
  10. package/dist/build-C7hi2yg4.js +1 -0
  11. package/dist/{build-DkKTiIu7.js → build-FAQSHJgm.js} +4 -3
  12. package/dist/{ci-B5-mH-YW.js → ci-oWlUJKm9.js} +10 -6
  13. package/dist/client/hitch/client.d.ts +1 -1
  14. package/dist/client/hitch/client.js +1 -2
  15. package/dist/client/hitch/phone.d.ts +1 -1
  16. package/dist/client/hitch/phone.js +1 -2
  17. package/dist/client/hitch.d.ts +2 -2
  18. package/dist/client/hitch.js +2 -2
  19. package/dist/client/react/markdown-editor.d.ts +1 -1
  20. package/dist/client/react/markdown-editor.js +1 -2
  21. package/dist/client/react/markdown.d.ts +1 -1
  22. package/dist/client/react/markdown.js +1 -2
  23. package/dist/client/react.d.ts +2 -2
  24. package/dist/client/react.js +2 -2
  25. package/dist/client.d.ts +2 -4
  26. package/dist/client.js +3 -5
  27. package/dist/{contract-CJv-n1l3.d.ts → contract-CUc0B2rl.d.ts} +1 -3
  28. package/dist/{contract-BeKz1Qcs.js → contract-D9LCNGjD.js} +1 -2
  29. package/dist/create-BJqLT8Uq.d.ts +68 -0
  30. package/dist/{deploy-DODTE8ri.js → deploy-BM55ZoSp.js} +160 -152
  31. package/dist/{device-BgIfytaR.js → device-CZWWckCq.js} +54 -34
  32. package/dist/{email-protocol-B9u_dh2p.d.ts → email-protocol-CEqzASSx.d.ts} +0 -6
  33. package/dist/{generate-8yyxKRSz.js → generate-48pqFh5M.js} +57 -39
  34. package/dist/generate-BYK4aNud.js +1 -0
  35. package/dist/generated-agents-BUnJ0FQA.js +215 -0
  36. package/dist/git-credential-CU7-Erzs.js +24 -0
  37. package/dist/git-deploy-C12nMNB6.js +290 -0
  38. package/dist/git-deploy-CNz6mxiF.js +1 -0
  39. package/dist/git-migration-CIq-sN61.js +629 -0
  40. package/dist/git-safety-Ck3X7jvA.js +13 -0
  41. package/dist/{headers-CeRX-Xji.js → headers-BcEMIVCo.js} +1 -2
  42. package/dist/hitch-client-D33JOEOi.d.ts +22 -0
  43. package/dist/{hitch-client-Cw-WZ_8v.js → hitch-client-Dph_kzDd.js} +5 -7
  44. package/dist/{hitch-file-url-BPKj9zVG.js → hitch-file-url--AMjDOzP.js} +1 -2
  45. package/dist/index.d.ts +8 -15
  46. package/dist/index.js +32 -37
  47. package/dist/{init-DT0faD-q.js → init-Bb6WT8UB.js} +70 -18
  48. package/dist/{lazy-client-CwIzYAoE.js → lazy-client--QCL0wiu.js} +1 -2
  49. package/dist/{load-config-BYrBjPlr.js → load-config-Cffvj-aM.js} +27 -26
  50. package/dist/{log-context-DWznGjfz.js → log-context-BepwdjrR.js} +1 -2
  51. package/dist/login-BWZKo7Ui.js +21 -0
  52. package/dist/{logs-CEIikWzV.js → logs-glCVHI-8.js} +6 -6
  53. package/dist/{manifest-BBHD_EY9.d.ts → manifest-CpghlaJc.d.ts} +6 -7
  54. package/dist/manifest-patterns-BfxqImlp.js +4 -0
  55. package/dist/{markdown-CwlqzBtP.js → markdown-BA_XzFxq.js} +2 -3
  56. package/dist/{markdown-DSHOQIOb.d.ts → markdown-BXt65dDo.d.ts} +1 -3
  57. package/dist/{markdown-editor-BmEaBzd7.d.ts → markdown-editor-CB_nWLzj.d.ts} +1 -5
  58. package/dist/{markdown-editor-C5mLHGqu.js → markdown-editor-CaUuphfc.js} +3 -5
  59. package/dist/parent-D52Kxp8U.js +1 -0
  60. package/dist/parent-Zx8Eg1Ki.js +75 -0
  61. package/dist/{project-CWVwic2C.js → project-DZGk765E.js} +74 -58
  62. package/dist/{prompt-ChS-grYO.js → prompt-CW98R-Un.js} +1 -2
  63. package/dist/{query-cache-CXmAyLv3.js → query-cache-DQJy45RT.js} +1 -2
  64. package/dist/{query-utils-zz9pVjgp.d.ts → query-utils-okxIoKM3.d.ts} +0 -2
  65. package/dist/{schedules-B7xNl9oy.js → schedules-CSUb84e2.js} +5 -5
  66. package/dist/server.d.ts +6 -14
  67. package/dist/server.js +17 -20
  68. package/dist/source-hash-BbvtRaus.js +107 -0
  69. package/dist/store-E5NhITHl.js +448 -0
  70. package/dist/{upload-D_kkmne_.d.ts → upload-DXZyjZSS.d.ts} +6 -10
  71. package/dist/{upload-DRbVhuDm.js → upload-DtMavo8Q.js} +4 -6
  72. package/dist/{use-phone-ug4B5gQp.js → use-phone-CB_idmrz.js} +9 -13
  73. package/dist/{use-phone-M7c_HsB7.d.ts → use-phone-DBAkasPq.d.ts} +0 -4
  74. package/dist/{variables-DCbLJBr0.js → variables-CgZstC7I.js} +7 -8
  75. package/dist/vite.d.ts +1 -3
  76. package/dist/vite.js +42 -51
  77. package/dist/{workflow-DurM6Fwx.d.ts → workflow-BnBrJIzu.d.ts} +0 -2
  78. package/dist/{workflow-engine-BOTzURKM.js → workflow-engine-CyyaVENo.js} +2 -4
  79. package/dist/{workflow-CTo2kZF1.js → workflow-l2SlVePB.js} +2 -4
  80. package/dist/workspace-CtIKSgMD.js +76 -0
  81. package/package.json +6 -5
  82. package/scaffold/.agents/skills/hitch-applets/SKILL.md +28 -10
  83. package/scaffold/.agents/skills/hitch-applets/references/files.md +2 -2
  84. package/scaffold/.agents/skills/hitch-applets/references/manifest.md +8 -6
  85. package/scaffold/.agents/skills/hitch-applets/references/performance.md +2 -2
  86. package/scaffold/.agents/skills/hitch-applets/references/records.md +24 -9
  87. package/scaffold/.agents/skills/hitch-cli/SKILL.md +52 -43
  88. package/scaffold/AGENTS.md +6 -0
  89. package/dist/auth-D3CrCtZq.js +0 -21
  90. package/dist/batch-Qa4B4-Yp.d.ts +0 -30
  91. package/dist/build-DpkWOvd2.js +0 -2
  92. package/dist/generate-Df29-UJm.js +0 -2
  93. package/dist/hitch-client--qZVa2KM.d.ts +0 -23
  94. package/dist/login-CceGvlMi.js +0 -14
  95. package/dist/store-B8N_8JIN.js +0 -196
  96. package/dist/workspace-8yqXsvce.js +0 -31
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useSyncExternalStore } from "react";
2
- //#region src/telephony/api.ts
2
+ // src/telephony/api.ts
3
3
  var TelephonyApiError = class extends Error {
4
4
  code;
5
5
  status;
@@ -14,7 +14,7 @@ const createTelephonyApi = (baseUrl = location.origin) => {
14
14
  const request = async (path, init) => {
15
15
  const headers = new Headers(init?.headers);
16
16
  if (init?.body) headers.set("content-type", "application/json");
17
- const response = await fetch(`${baseUrl.replace(/\/$/, "")}/api/v1/telephony/${path}`, {
17
+ const response = await fetch(`${baseUrl.replace(/\/$/, "")}/api/${path}`, {
18
18
  credentials: "include",
19
19
  ...init,
20
20
  headers
@@ -28,29 +28,28 @@ const createTelephonyApi = (baseUrl = location.origin) => {
28
28
  return response.json();
29
29
  };
30
30
  return {
31
- token: (deviceKey, acceptsCalls) => request("voice/token", {
31
+ token: (deviceKey, acceptsCalls) => request("applet/v1/telephony/voice/token", {
32
32
  method: "POST",
33
33
  body: JSON.stringify({
34
34
  deviceKey,
35
35
  acceptsCalls
36
36
  })
37
37
  }),
38
- startCall: (numberId, to) => request("calls", {
38
+ startCall: (numberId, to) => request("applet/v1/telephony/calls", {
39
39
  method: "POST",
40
40
  body: JSON.stringify({
41
41
  numberId,
42
42
  to
43
43
  })
44
44
  }),
45
- getCall: (callId) => request(`calls/${encodeURIComponent(callId)}`),
46
- uploadUrl: (callId) => request(`calls/${encodeURIComponent(callId)}/recording`, {
45
+ getCall: (callId) => request(`resource/v1/telephony/calls/${encodeURIComponent(callId)}`),
46
+ uploadUrl: (callId) => request(`applet/v1/telephony/calls/${encodeURIComponent(callId)}/recording`, {
47
47
  method: "POST",
48
48
  body: "{}"
49
49
  })
50
50
  };
51
51
  };
52
- //#endregion
53
- //#region src/telephony/recorder.ts
52
+ // src/telephony/recorder.ts
54
53
  const DB_NAME = "hitch-telephony";
55
54
  const STORE = "recordings";
56
55
  const openDatabase = () => new Promise((resolve, reject) => {
@@ -162,8 +161,7 @@ const startRecording = async (callId, call, api, onError) => {
162
161
  throw error;
163
162
  }
164
163
  };
165
- //#endregion
166
- //#region src/telephony/phone.ts
164
+ // src/telephony/phone.ts
167
165
  const DEVICE_KEY = "hitch:telephony:device";
168
166
  let singleton;
169
167
  var Phone = class {
@@ -708,8 +706,7 @@ var Phone = class {
708
706
  }
709
707
  };
710
708
  const createPhone = (options = {}) => singleton ??= new Phone(options);
711
- //#endregion
712
- //#region src/telephony/use-phone.ts
709
+ // src/telephony/use-phone.ts
713
710
  const usePhone = () => {
714
711
  const phone = createPhone();
715
712
  const state = useSyncExternalStore(phone.subscribe, phone.getSnapshot);
@@ -722,5 +719,4 @@ const usePhone = () => {
722
719
  active: phone.active
723
720
  };
724
721
  };
725
- //#endregion
726
722
  export { createPhone as n, usePhone as t };
@@ -1,4 +1,3 @@
1
- //#region src/telephony/phone.d.ts
2
1
  type PhoneState = {
3
2
  owner: boolean;
4
3
  status: "off" | "connecting" | "ready" | "error";
@@ -86,12 +85,9 @@ declare const createPhone: (options?: {
86
85
  baseUrl?: string;
87
86
  acceptsCalls?: boolean;
88
87
  }) => Phone;
89
- //#endregion
90
- //#region src/telephony/use-phone.d.ts
91
88
  declare const usePhone: () => {
92
89
  state: PhoneState;
93
90
  call: Phone["call"];
94
91
  active: Phone["active"];
95
92
  };
96
- //#endregion
97
93
  export { createPhone as i, Phone as n, PhoneState as r, usePhone as t };
@@ -1,8 +1,8 @@
1
- import { t as fetchWithOrgAuth } from "./auth-D3CrCtZq.js";
2
- import { t as loadAppletConfig } from "./load-config-BYrBjPlr.js";
3
- import { t as question } from "./prompt-ChS-grYO.js";
1
+ import { n as fetchWithOrgAuth } from "./auth-DuMRqSGe.js";
2
+ import { t as loadAppletConfig } from "./load-config-Cffvj-aM.js";
3
+ import { t as question } from "./prompt-CW98R-Un.js";
4
4
  import { z } from "zod";
5
- //#region src/variables.ts
5
+ // src/variables.ts
6
6
  const variableRowSchema = z.object({
7
7
  key: z.string(),
8
8
  secret: z.boolean(),
@@ -57,7 +57,7 @@ async function runVariablesSet(options) {
57
57
  const manifest = await loadAppletConfig(process.cwd());
58
58
  await confirmLiveChange(manifest.code, options);
59
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)}`, {
60
+ const response = await fetchWithOrgAuth(manifest.org, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/manage/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
61
61
  method: "PUT",
62
62
  headers: {
63
63
  Authorization: `Bearer ${accessToken}`,
@@ -77,7 +77,7 @@ async function runVariablesSet(options) {
77
77
  }
78
78
  async function runVariablesList() {
79
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}` } }));
80
+ const { code, response } = await requestForApplet((instanceUrl, accessToken, appletCode) => fetcher(`${instanceUrl}/api/manage/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);
@@ -93,7 +93,7 @@ async function runVariablesDelete(options) {
93
93
  const manifest = await loadAppletConfig(process.cwd());
94
94
  await confirmLiveChange(manifest.code, options);
95
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)}`, {
96
+ const response = await fetchWithOrgAuth(manifest.org, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/manage/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
97
97
  method: "DELETE",
98
98
  headers: { Authorization: `Bearer ${accessToken}` }
99
99
  }));
@@ -104,5 +104,4 @@ async function runVariablesDelete(options) {
104
104
  }
105
105
  console.log(`Deleted ${options.key} from applet "${manifest.code}".`);
106
106
  }
107
- //#endregion
108
107
  export { runVariablesDelete, runVariablesList, runVariablesSet };
package/dist/vite.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- import { o as RegisteredAppletSourceDefinition } from "./manifest-BBHD_EY9.js";
1
+ import { o as RegisteredAppletSourceDefinition } from "./manifest-CpghlaJc.js";
2
2
  import { PluginOption } from "vite";
3
- //#region src/vite.d.ts
4
3
  declare function applet<const M extends RegisteredAppletSourceDefinition>(sourceDefinition: M): PluginOption[];
5
- //#endregion
6
4
  export { applet };
package/dist/vite.js CHANGED
@@ -1,17 +1,20 @@
1
- import { t as pruneContract } from "./contract-BeKz1Qcs.js";
2
- import { a as openQueryCacheDatabase } from "./query-cache-CXmAyLv3.js";
3
- import { d as HITCH_SESSION_HEADER, f as HITCH_USER_HEADER } from "./headers-CeRX-Xji.js";
4
- import { a as workflowOutcomeSchema, n as runWorkflowJournal } from "./workflow-engine-BOTzURKM.js";
5
- import { a as organizationInstanceUrl, c as resolveInstanceUrl, o as rejectEnvironmentKey, r as bearerToken, s as resolveAuthForOrg } from "./store-B8N_8JIN.js";
6
- import { a as writeRegisterDeclaration, c as writeAppletRoot, d as writeServerEntry, i as syncContract, l as writeClientEntry, n as routesModuleSource, u as writeManifestGen } from "./generate-8yyxKRSz.js";
7
- import { a as appletSourceDefinitionSchema, i as appletManifestSchema, o as APPLET_CODE_PATTERN, r as resolveWorkspaceOrg } from "./load-config-BYrBjPlr.js";
1
+ import { t as pruneContract } from "./contract-D9LCNGjD.js";
2
+ import { a as openQueryCacheDatabase } from "./query-cache-DQJy45RT.js";
3
+ import { d as HITCH_SESSION_HEADER, f as HITCH_USER_HEADER } from "./headers-BcEMIVCo.js";
4
+ import { a as workflowOutcomeSchema, n as runWorkflowJournal } from "./workflow-engine-CyyaVENo.js";
5
+ import { r as writeGeneratedAgents } from "./generated-agents-BUnJ0FQA.js";
6
+ import { d as rejectEnvironmentKey, i as bearerToken, l as organizationInstanceUrl, m as resolveInstanceUrl, p as resolveAuthForOrg } from "./store-E5NhITHl.js";
7
+ import { c as validateRootManifest, o as isRootLayout } from "./workspace-CtIKSgMD.js";
8
+ import { a as appletSourceDefinitionSchema, i as appletReleaseManifest, o as resolveWorkspaceOrg, r as appletMountPath } from "./load-config-Cffvj-aM.js";
9
+ import { a as writeRegisterDeclaration, c as writeAppletRoot, d as writeServerEntry, i as syncContract, l as writeClientEntry, n as routesModuleSource, u as writeManifestGen } from "./generate-48pqFh5M.js";
10
+ import { t as APPLET_CODE_PATTERN } from "./manifest-patterns-BfxqImlp.js";
8
11
  import { z } from "zod";
9
12
  import { randomUUID } from "node:crypto";
13
+ import { pathToFileURL } from "node:url";
10
14
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
11
15
  import { appendFile, readdir, rm, writeFile } from "node:fs/promises";
12
- import { createServer } from "node:http";
13
16
  import { basename, dirname, relative, resolve } from "node:path";
14
- import { pathToFileURL } from "node:url";
17
+ import { createServer } from "node:http";
15
18
  import { cloudflare } from "@cloudflare/vite-plugin";
16
19
  import optimizeLocales from "@react-aria/optimize-locales-plugin";
17
20
  import { tanstackRouter } from "@tanstack/router-plugin/vite";
@@ -19,7 +22,7 @@ import react from "@vitejs/plugin-react";
19
22
  import { normalizePath } from "vite";
20
23
  import { Readable } from "node:stream";
21
24
  import { pipeline } from "node:stream/promises";
22
- //#region src/dev-proxy.ts
25
+ // src/dev-proxy.ts
23
26
  const REQUEST_DROP = /* @__PURE__ */ new Set([
24
27
  "host",
25
28
  "connection",
@@ -56,7 +59,8 @@ function createDevProxy(options) {
56
59
  if (intercepted !== void 0) return intercepted;
57
60
  const headers = new Headers(request.headers);
58
61
  [...headers.keys()].filter((name) => REQUEST_DROP.has(name) || name.startsWith("x-hitch-")).forEach((name) => headers.delete(name));
59
- headers.set("authorization", `Bearer ${options.token}`);
62
+ const token = typeof options.token === "string" ? options.token : await options.token();
63
+ headers.set("authorization", `Bearer ${token}`);
60
64
  const url = new URL(request.url);
61
65
  const upstream = await globalThis.fetch(`${options.orgUrl}${url.pathname}${url.search}`, {
62
66
  method: request.method,
@@ -112,8 +116,7 @@ async function serveDevProxy(request, response, handler) {
112
116
  response.off("close", onClose);
113
117
  }
114
118
  }
115
- //#endregion
116
- //#region src/dev-workflows.ts
119
+ // src/dev-workflows.ts
117
120
  const RUN_STATUSES = [
118
121
  "in_progress",
119
122
  "sleeping",
@@ -228,10 +231,10 @@ function createDevWorkflows(options) {
228
231
  };
229
232
  const handle = (request) => {
230
233
  const url = new URL(request.url);
231
- const prefix = `/api/v1/applets/${encodeURIComponent(options.appletCode)}`;
232
- if (!url.pathname.startsWith(`${prefix}/`)) return void 0;
233
- const path = url.pathname.slice(prefix.length);
234
- const startMatch = /^\/workflows\/([^/]+)\/runs$/.exec(path);
234
+ const applet = `/applets/${encodeURIComponent(options.appletCode)}`;
235
+ const startPrefix = `/api/applet/v1${applet}/workflows/`;
236
+ const runsPath = `/api/applet/v1${applet}/workflow-runs`;
237
+ const startMatch = url.pathname.startsWith(startPrefix) ? /^([^/]+)\/runs$/.exec(url.pathname.slice(startPrefix.length)) : null;
235
238
  if (request.method === "POST" && startMatch !== null) return (async () => {
236
239
  let body;
237
240
  try {
@@ -257,27 +260,23 @@ function createDevWorkflows(options) {
257
260
  status: "in_progress"
258
261
  } }, { status: 201 });
259
262
  })();
260
- const getMatch = /^\/workflows\/([^/]+)\/runs\/([^/]+)$/.exec(path);
263
+ const getMatch = url.pathname.startsWith(`${runsPath}/`) ? /^([^/]+)$/.exec(url.pathname.slice(runsPath.length + 1)) : null;
261
264
  if (request.method === "GET" && getMatch !== null) {
262
- let workflow;
263
265
  let id;
264
266
  try {
265
- workflow = decodeURIComponent(getMatch[1]);
266
- id = decodeURIComponent(getMatch[2]);
267
+ id = decodeURIComponent(getMatch[1]);
267
268
  } catch (error) {
268
269
  if (error instanceof URIError) return Promise.resolve(badRequest(error.message));
269
270
  throw error;
270
271
  }
271
- const codeError = workflowCodeError(workflow);
272
- if (codeError !== void 0) return Promise.resolve(codeError);
273
272
  if (!UUID_PATTERN.test(id)) return Promise.resolve(badRequest("The run id must be a uuid."));
274
273
  const run = runs.get(id);
275
- return Promise.resolve(run?.workflow === workflow ? Response.json({ data: run }) : Response.json({
274
+ return Promise.resolve(run ? Response.json({ data: run }) : Response.json({
276
275
  code: "workflow_run_not_found",
277
276
  message: "The workflow run does not exist."
278
277
  }, { status: 404 }));
279
278
  }
280
- if (request.method === "GET" && path === "/workflow-runs") {
279
+ if (request.method === "GET" && url.pathname === runsPath) {
281
280
  const status = url.searchParams.get("status");
282
281
  const limitValue = url.searchParams.get("limit");
283
282
  const limit = limitValue === null ? 50 : Number(limitValue);
@@ -295,8 +294,7 @@ function createDevWorkflows(options) {
295
294
  stop: () => controller.abort()
296
295
  };
297
296
  }
298
- //#endregion
299
- //#region src/lazy-client-react.ts
297
+ // src/lazy-client-react.ts
300
298
  const CLIENT_REACT = "@hitch42/applet/client/react";
301
299
  const lazyClientReact = {
302
300
  name: "hitch-lazy-client-react",
@@ -307,8 +305,7 @@ const lazyClientReact = {
307
305
  return this.resolve(`${CLIENT_REACT}?lazy`, importer, { skipSelf: true });
308
306
  }
309
307
  };
310
- //#endregion
311
- //#region src/hitch/me-schemas.ts
308
+ // src/hitch/me-schemas.ts
312
309
  const personSchema = z.object({
313
310
  id: z.uuid(),
314
311
  firstName: z.string(),
@@ -332,8 +329,7 @@ const meSchema = z.object({
332
329
  }).nullable(),
333
330
  multiOrg: z.boolean()
334
331
  });
335
- //#endregion
336
- //#region src/vite.ts
332
+ // src/vite.ts
337
333
  const APPLET_COMPATIBILITY_DATE = "2026-07-14";
338
334
  const APPLET_COMPATIBILITY_FLAGS = ["nodejs_compat"];
339
335
  let activeDevListener;
@@ -565,14 +561,10 @@ function clientBootstrapScript(parentOrigin, appletCode, cacheQueries) {
565
561
  }
566
562
  function applet(sourceDefinition) {
567
563
  const parsedSourceDefinition = appletSourceDefinitionSchema.safeParse(sourceDefinition);
568
- if (!parsedSourceDefinition.success) {
569
- const raw = sourceDefinition;
570
- const orgMessage = typeof raw === "object" && raw !== null && "org" in raw ? " org now lives in hitch.config.ts, not in applet.manifest.ts." : "";
571
- throw new Error(`applet(): ${parsedSourceDefinition.error.message}${orgMessage}`);
572
- }
573
- const { dependencies: _dependencies, devDependencies: _devDependencies, ...definition } = parsedSourceDefinition.data;
564
+ if (!parsedSourceDefinition.success) throw new Error(`applet(): ${parsedSourceDefinition.error.message}`);
565
+ const { dependencies: _dependencies, devDependencies: _devDependencies, sdk: _sdk, org: _org, ...definition } = parsedSourceDefinition.data;
574
566
  const parsedDefinition = { data: definition };
575
- const mountPath = definition.public ? `app/${definition.code}` : definition.code;
567
+ const mountPath = appletMountPath(definition);
576
568
  let appletConfig;
577
569
  let buildRootOutDir;
578
570
  let clearedOutDir = false;
@@ -597,7 +589,8 @@ function applet(sourceDefinition) {
597
589
  const resolvedRoot = resolve(root);
598
590
  if (appletConfig?.root === resolvedRoot) return appletConfig;
599
591
  const directoryCode = basename(resolvedRoot);
600
- if (directoryCode !== parsedDefinition.data.code) throw new Error(`Applet directory "${directoryCode}" does not match code "${parsedDefinition.data.code}". Rename the directory or change the code.`);
592
+ if (!isRootLayout(resolvedRoot) && directoryCode !== parsedDefinition.data.code) throw new Error(`Applet directory "${directoryCode}" does not match code "${parsedDefinition.data.code}". Rename the directory or change the code.`);
593
+ if (isRootLayout(resolvedRoot)) validateRootManifest(sourceDefinition);
601
594
  const org = resolveWorkspaceOrg(resolvedRoot);
602
595
  const routesDirectory = resolve(resolvedRoot, "src/client/routes");
603
596
  const hasClient = existsSync(routesDirectory);
@@ -611,10 +604,7 @@ function applet(sourceDefinition) {
611
604
  if (hasClient && !existsSync(indexHtml)) throw new Error(`Missing index.html at ${indexHtml}. Create it with <div id="root"></div> and <script type="module" src="/.hitch/entry.gen.tsx"><\/script>.`);
612
605
  appletConfig = {
613
606
  root: resolvedRoot,
614
- manifest: appletManifestSchema.parse({
615
- org,
616
- ...parsedDefinition.data
617
- }),
607
+ manifest: appletReleaseManifest(parsedSourceDefinition.data, org),
618
608
  routesDirectory,
619
609
  hasClient,
620
610
  hasAuthorRoot: hasClient && existsSync(resolve(routesDirectory, "__root.tsx")),
@@ -630,10 +620,7 @@ function applet(sourceDefinition) {
630
620
  };
631
621
  let apiManifest;
632
622
  const callerRoot = resolve(".");
633
- if (basename(callerRoot) === parsedDefinition.data.code && basename(resolve(callerRoot, "..")) === "applets") apiManifest = appletManifestSchema.parse({
634
- org: resolveWorkspaceOrg(callerRoot),
635
- ...parsedDefinition.data
636
- });
623
+ if (basename(callerRoot) === parsedDefinition.data.code && (basename(resolve(callerRoot, "..")) === "applets" || isRootLayout(callerRoot))) apiManifest = appletReleaseManifest(parsedSourceDefinition.data, resolveWorkspaceOrg(callerRoot));
637
624
  const clsxFromCn = {
638
625
  name: "hitch-clsx",
639
626
  resolveId: (id) => id === "clsx" ? "\0hitch:clsx" : void 0,
@@ -650,6 +637,7 @@ function applet(sourceDefinition) {
650
637
  async config(config, environment) {
651
638
  buildRoutes = environment.command === "build" && environment.mode !== "test";
652
639
  const { root, manifest, hasClient, hasAuthorRoot, hasServer, hasRouter } = resolveAppletConfig(config.root ?? resolve("."));
640
+ if (isRootLayout(root)) await writeGeneratedAgents(root);
653
641
  apiManifest = manifest;
654
642
  buildRootOutDir = resolve(root, config.build?.outDir ?? "dist");
655
643
  if (environment.command === "build" && !clearedOutDir) {
@@ -682,14 +670,18 @@ function applet(sourceDefinition) {
682
670
  const auth = await resolveAuthForOrg(instanceUrl, manifest.org);
683
671
  if (auth === void 0) throw new Error("Not logged in. Run applet login.");
684
672
  const token = bearerToken(auth);
685
- const meResponse = await globalThis.fetch(`${orgUrl}/api/v1/me`, { headers: { authorization: `Bearer ${token}` } });
673
+ const meResponse = await globalThis.fetch(`${orgUrl}/api/me/v1`, { headers: { authorization: `Bearer ${token}` } });
686
674
  rejectEnvironmentKey(meResponse, auth);
687
675
  if (meResponse.status === 401) throw new Error("Your login expired. Run applet login.");
688
- if (!meResponse.ok) throw new Error(`Hitch returned ${meResponse.status} for /api/v1/me.`);
676
+ if (!meResponse.ok) throw new Error(`Hitch returned ${meResponse.status} for /api/me/v1.`);
689
677
  const { person } = meSchema.parse(await meResponse.json());
690
678
  const proxy = createDevProxy({
691
679
  orgUrl,
692
- token,
680
+ token: async () => {
681
+ const current = await resolveAuthForOrg(instanceUrl, manifest.org);
682
+ if (current === void 0) throw new Error("Not logged in. Run applet login.");
683
+ return bearerToken(current);
684
+ },
693
685
  source: auth.source,
694
686
  warn: (message) => devLogger?.warn(message),
695
687
  intercept: (request) => devWorkflows?.handle(request)
@@ -950,5 +942,4 @@ function applet(sourceDefinition) {
950
942
  cloudflarePlugins
951
943
  ];
952
944
  }
953
- //#endregion
954
945
  export { applet };
@@ -1,5 +1,4 @@
1
1
  import { z } from "zod";
2
- //#region src/server/workflow.d.ts
3
2
  type WorkflowDuration = {
4
3
  milliseconds?: number;
5
4
  seconds?: number;
@@ -24,5 +23,4 @@ type WorkflowDefinition<Payload, Result> = {
24
23
  };
25
24
  type AnyWorkflowDefinition = WorkflowDefinition<any, any>;
26
25
  declare function createWorkflow<Payload, Result>(run: (step: WorkflowStep, payload: Payload) => Promise<Result>): WorkflowDefinition<Payload, Result>;
27
- //#endregion
28
26
  export { createWorkflow as a, WorkflowStep as i, WorkflowDefinition as n, WorkflowDuration as r, AnyWorkflowDefinition as t };
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- //#region src/server/workflow-protocol.ts
2
+ // src/server/workflow-protocol.ts
3
3
  const journalEntrySchema = z.discriminatedUnion("kind", [
4
4
  z.object({
5
5
  kind: z.literal("step"),
@@ -67,8 +67,7 @@ const workflowOutcomeSchema = z.discriminatedUnion("kind", [
67
67
  message: z.string()
68
68
  })
69
69
  ]);
70
- //#endregion
71
- //#region src/server/workflow-engine.ts
70
+ // src/server/workflow-engine.ts
72
71
  var WorkflowFailedError = class extends Error {};
73
72
  async function runWorkflowJournal(engine, invoke) {
74
73
  const journal = [];
@@ -107,5 +106,4 @@ async function runWorkflowJournal(engine, invoke) {
107
106
  }
108
107
  }
109
108
  }
110
- //#endregion
111
109
  export { workflowOutcomeSchema as a, workflowInvocationRequestSchema as i, runWorkflowJournal as n, journalEntrySchema as r, WorkflowFailedError as t };
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { AsyncLocalStorage } from "node:async_hooks";
3
- //#region src/server/identity.ts
3
+ // src/server/identity.ts
4
4
  const requestContext = new AsyncLocalStorage();
5
5
  function runWithRequestContext(context, fn) {
6
6
  return requestContext.run(context, fn);
@@ -16,8 +16,7 @@ function getRequestContext() {
16
16
  function getIdentityBearer(identity) {
17
17
  return identity.kind === "user" ? identity.sessionToken : identity.token;
18
18
  }
19
- //#endregion
20
- //#region src/server/workflow.ts
19
+ // src/server/workflow.ts
21
20
  const DURATION_MULTIPLIERS = {
22
21
  milliseconds: 1,
23
22
  seconds: 1e3,
@@ -47,5 +46,4 @@ function toMilliseconds(duration) {
47
46
  function createWorkflow(run) {
48
47
  return { run };
49
48
  }
50
- //#endregion
51
49
  export { getRequestContext as a, getIdentityBearer as i, createWorkflow as n, runWithRequestContext as o, toMilliseconds as r, tryGetRequestContext as s, MAX_DURATION_MS as t };
@@ -0,0 +1,76 @@
1
+ import { createRequire, registerHooks } from "node:module";
2
+ import { pathToFileURL } from "node:url";
3
+ import fs from "node:fs";
4
+ import { basename, dirname, resolve } from "node:path";
5
+ // ../shared/auth/src/workspace.mts
6
+ const ORG_CODE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
7
+ const require = createRequire(import.meta.url);
8
+ var WorkspaceValidationError = class extends Error {};
9
+ const SDK_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?$/;
10
+ function validateRootManifest(value) {
11
+ if (value === null || typeof value !== "object" || !("org" in value) || typeof value.org !== "string" || !ORG_CODE_PATTERN.test(value.org)) throw new WorkspaceValidationError("Invalid applet manifest: \"org\" must be an organization code.");
12
+ if (!("sdk" in value) || typeof value.sdk !== "string" || !SDK_VERSION_PATTERN.test(value.sdk)) throw new WorkspaceValidationError("Invalid applet manifest: \"sdk\" must be an exact version, for example \"0.2.0\".");
13
+ return {
14
+ org: value.org,
15
+ sdk: `@hitch42/applet@${value.sdk}`,
16
+ githubWorkflow: false
17
+ };
18
+ }
19
+ function isRootLayout(dir) {
20
+ return fs.existsSync(resolve(dir, "applet.manifest.ts")) && !fs.existsSync(resolve(dir, "hitch.config.ts")) && !(basename(dirname(dir)) === "applets" && fs.existsSync(resolve(dir, "../../hitch.config.ts")));
21
+ }
22
+ function readWorkspaceConfig(dir) {
23
+ const rootLayout = isRootLayout(dir);
24
+ const path = resolve(dir, rootLayout ? "applet.manifest.ts" : "hitch.config.ts");
25
+ if (!fs.existsSync(path)) return void 0;
26
+ let module;
27
+ const configUrl = pathToFileURL(fs.realpathSync(path)).href;
28
+ const hooks = registerHooks({ load(url, context, nextLoad) {
29
+ return nextLoad(url, url === configUrl ? {
30
+ ...context,
31
+ format: "module-typescript"
32
+ } : context);
33
+ } });
34
+ try {
35
+ delete require.cache[require.resolve(path)];
36
+ module = require(path);
37
+ } catch (error) {
38
+ throw new Error(`Failed to load ${path}.`, { cause: error });
39
+ } finally {
40
+ hooks.deregister();
41
+ }
42
+ const config = module !== null && typeof module === "object" && "default" in module ? module.default : module;
43
+ if (rootLayout) return validateRootManifest(config);
44
+ if (config === null || typeof config !== "object" || !("sdk" in config) || typeof config.sdk !== "string" || config.sdk.length === 0 || !("org" in config) || typeof config.org !== "string" || !ORG_CODE_PATTERN.test(config.org)) throw new WorkspaceValidationError(`Invalid Hitch config in ${path}: "sdk" must be a package spec and "org" an organization code.`);
45
+ const githubWorkflow = "githubWorkflow" in config ? config.githubWorkflow : void 0;
46
+ if (githubWorkflow !== void 0 && typeof githubWorkflow !== "boolean") throw new WorkspaceValidationError(`Invalid Hitch config in ${path}: "githubWorkflow" must be a boolean.`);
47
+ return {
48
+ sdk: config.sdk,
49
+ org: config.org,
50
+ githubWorkflow
51
+ };
52
+ }
53
+ function findWorkspaceRoot(cwd) {
54
+ const dir = resolve(cwd);
55
+ if (fs.existsSync(resolve(dir, ".hitchroot"))) return void 0;
56
+ if (fs.existsSync(resolve(dir, "hitch.config.ts"))) return dir;
57
+ if (fs.existsSync(resolve(dir, "applet.manifest.ts"))) return basename(dirname(dir)) === "applets" && fs.existsSync(resolve(dir, "../../hitch.config.ts")) ? resolve(dir, "../..") : dir;
58
+ return dirname(dir) === dir ? void 0 : findWorkspaceRoot(dirname(dir));
59
+ }
60
+ function findAppletRoot(cwd) {
61
+ const dir = resolve(cwd);
62
+ if (fs.existsSync(resolve(dir, ".hitchroot"))) return void 0;
63
+ if (fs.existsSync(resolve(dir, "applet.manifest.ts"))) return dir;
64
+ if (fs.existsSync(resolve(dir, "hitch.config.ts")) || dirname(dir) === dir) return void 0;
65
+ return findAppletRoot(dirname(dir));
66
+ }
67
+ function findParentRoot(cwd) {
68
+ const dir = resolve(cwd);
69
+ if (fs.existsSync(resolve(dir, ".hitchroot"))) return dir;
70
+ return dirname(dir) === dir ? void 0 : findParentRoot(dirname(dir));
71
+ }
72
+ function findWorkspaceConfig(cwd) {
73
+ const root = findWorkspaceRoot(cwd);
74
+ return root === void 0 ? void 0 : readWorkspaceConfig(root);
75
+ }
76
+ export { findWorkspaceRoot as a, validateRootManifest as c, findWorkspaceConfig as i, findAppletRoot as n, isRootLayout as o, findParentRoot as r, readWorkspaceConfig as s, SDK_VERSION_PATTERN as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hitch42/applet",
3
- "version": "0.1.1-beta.19",
3
+ "version": "0.1.1-beta.21",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "applet": "./dist/applet.js"
@@ -59,6 +59,7 @@
59
59
  "@fontsource-variable/geist-mono": "^5.3.0",
60
60
  "@fontsource-variable/inter": "^5.3.0",
61
61
  "@hey-api/openapi-ts": "0.0.0-next-20260824173136",
62
+ "@napi-rs/keyring": "2.1.2",
62
63
  "@orpc/client": "^1.15.0",
63
64
  "@orpc/contract": "^1.15.0",
64
65
  "@orpc/openapi-client": "^1.15.0",
@@ -88,14 +89,14 @@
88
89
  "oxlint": "^1.87.0",
89
90
  "oxlint-tsgolint": "^7.0.2003",
90
91
  "react-aria-components": "^1.20.0",
91
- "shadcn": "^4.16.1",
92
+ "shadcn": "^4.23.0",
92
93
  "smol-toml": "^1.9.0",
93
94
  "streamdown": "^2.6.0",
94
95
  "tailwindcss": "^4.3.0",
95
96
  "tw-animate-css": "^1.4.0",
96
- "vite": "8.3.0",
97
- "vitest": "4.1.11",
98
- "zod": "^4.4.3"
97
+ "vite": "8.3.3",
98
+ "vitest": "4.1.12",
99
+ "zod": "^4.6.7"
99
100
  },
100
101
  "peerDependencies": {
101
102
  "@orpc/server": "^1.15.0",
@@ -11,7 +11,7 @@ Treat each applet as an isolated microfrontend. Keep it separate from the data s
11
11
 
12
12
  ## Public applets
13
13
 
14
- Set `public: true` for an applet that anonymous visitors can use. It is served at `https://{org}.hitch42.app/app/{code}`. It runs as the applet identity. Its manifest grants cap its access.
14
+ Set `public: true` for an applet that anonymous visitors can use. It is served at `https://{org}.hitch42.app/pages/{code}`. It runs as the applet identity. Its manifest grants cap its access.
15
15
 
16
16
  A public applet cannot use schedules, email, telephony, workflows, or `@hitch42/applet/client/hitch`. Client code calls its server procedures with `api` from `@hitch42/applet/client`.
17
17
 
@@ -40,11 +40,26 @@ Follow the Hitch applet rules for SDK-owned configuration, providers, and genera
40
40
 
41
41
  ## Work with the workspace
42
42
 
43
+ With Hitch git on, the applet is the repo root. Its manifest includes `org`
44
+ and an exact `sdk` version, such as `"0.2.0"`. There is no `hitch.config.ts`.
45
+ Run package scripts inside that root. In the legacy command examples below,
46
+ `applets/<code>` means the applet directory: `.` for a root applet or `<code>`
47
+ from a `.hitchroot` parent. The legacy layout stays for orgs with Hitch git off
48
+ and GitHub Actions.
49
+
50
+ A `.hitchroot` parent is local and has no git repo. Each child is one applet
51
+ repo. Parent deploy processes changed children in order. Parent bootstrap
52
+ prepares all children. Commit per child. Generated agent files live once in
53
+ the parent; children use gitignored links. Keep edited files when the CLI
54
+ reports them.
55
+
43
56
  - Run package commands with `pnpm`.
44
- - Run `pnpm exec applet login` from the workspace root or an applet directory to sign in. It uses the organization in `hitch.config.ts` and shares credentials with `hitch login`. Add `--no-browser` to print the sign-in URL without opening a browser.
57
+ - Run `pnpm exec applet login` from the workspace root or an applet directory to sign in. It uses the organization in `applet.manifest.ts` or legacy `hitch.config.ts` and shares credentials with `hitch login`. Add `--no-browser` to print the sign-in URL without opening a browser.
45
58
  - A server permission error is not a login request.
46
- - After a workspace is linked to a repository, deploy in two ways. Run `pnpm exec applet deploy` to release a change immediately. Push to the production branch to deploy through CI and keep releases in sync with the repository.
47
- - Run `pnpm exec applet new <code>` from the workspace root to create a full applet.
59
+ - Keep one applet in each repository. Run `pnpm exec applet deploy -m "<message>"` to commit changes and deploy through Hitch git.
60
+ - Run `pnpm exec applet clone <org>/<code> [dir]` to get an applet and its git history from Hitch.
61
+ - Run `pnpm exec applet rollback <release-id>` to make an earlier release live again.
62
+ - Run `pnpm exec applet new <code>` from a parent or workspace to create a full applet.
48
63
  - Add `--client-only` or `--server-only` when the applet needs only one part.
49
64
  - Use `--client-only` for a user interface that uses the current user's Hitch access and needs no server.
50
65
  - Use `--server-only` for an API or schedule that needs no user interface.
@@ -179,10 +194,13 @@ If missing packages block a check, stop package checks. Do not retry the check t
179
194
 
180
195
  If a command fails, report the exact blocker. Do not deploy as a verification step.
181
196
 
182
- ## Deploy from GitHub
197
+ ## Deploy through Hitch git
198
+
199
+ - Keep one applet per repository, with its manifest and source at the root.
200
+ - Let the SDK migrate old workspaces after its backup. Keep `.hitch-backup/`.
201
+ - Use `applet clone` for other copies after migration. Remove the old GitHub deploy workflow.
202
+ - Run `pnpm exec applet deploy -m "<message>"` from the workspace root or applet folder. The CLI commits changes, pushes the commit to Hitch, and moves `main` when the release goes live.
203
+ - Run `pnpm exec applet clone <org>/<code> [dir]` to work from the current Hitch history.
204
+ - Run `pnpm exec applet rollback <release-id>` to make an earlier release live again. Revert or reset local commits before the next deploy.
183
205
 
184
- - A push to the production branch runs `applet deploy` in the workspace root through GitHub Actions.
185
- - An applet deploys when its folder or a file outside `applets/` differs from its current release, including a local `applet deploy`. Uncommitted and untracked files count. Gitignored files do not count. An applet whose current release has no source hash always deploys.
186
- - The deploy skips other applets and logs the reason. A skip is expected, not a failure.
187
- - A schema change in Hitch alone does not trigger CI.
188
- - Do not import from a sibling applet folder. The change check does not follow such imports.
206
+ GitHub-linked applets still deploy through GitHub Actions CI until their organization moves to Hitch git.
@@ -77,7 +77,7 @@ Use the `get` query utilities when React needs file metadata as query state.
77
77
  ```ts
78
78
  const fileQuery = useQuery(
79
79
  hitch.files.get.queryOptions({
80
- input: { params: { id } },
80
+ input: { params: { file: id } },
81
81
  }),
82
82
  );
83
83
 
@@ -100,7 +100,7 @@ Store `uploaded.id` as the value of an attachment attribute. A multi-value attac
100
100
  const uploaded = await hitch.files.upload(file);
101
101
 
102
102
  await hitch.records.claims.update.call({
103
- params: { id: claimId },
103
+ params: { record: claimId },
104
104
  body: { receipt_id: uploaded.id }, // multi-value: [uploaded.id]
105
105
  });
106
106
  ```