@hitch42/applet 0.1.0-beta.10 → 0.1.0-beta.11

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 (34) hide show
  1. package/dist/applet.js +11 -11
  2. package/dist/{build-BlmLiKro.js → build-BRpYQ9Lk.js} +1 -1
  3. package/dist/build-CypJADhV.js +2 -0
  4. package/dist/{ci-0Q2mUh53.js → ci-C2CL-0sj.js} +2 -2
  5. package/dist/client.d.ts +2 -2
  6. package/dist/{contract-QUvEGiRI.d.ts → contract-CsUpTBe0.d.ts} +1 -1
  7. package/dist/{deploy-BbL3GObV.js → deploy-CdQQQ5HG.js} +131 -80
  8. package/dist/{generate-XB-72Fzj.js → generate-BDHb2kjw.js} +7 -4
  9. package/dist/generate-Cai2X9z1.js +2 -0
  10. package/dist/index.d.ts +3 -2
  11. package/dist/index.js +2 -1
  12. package/dist/{init-DwsXRUk-.js → init-CpVfJQbv.js} +4 -4
  13. package/dist/{load-config-OKZU3UKn.js → load-config-DI-e1Ool.js} +1 -1
  14. package/dist/{logs-XvK6Zs5Y.js → logs-CffdKMRd.js} +2 -2
  15. package/dist/{manifest-I-9s8R36.d.ts → manifest-C6_F4bL8.d.ts} +3 -1
  16. package/dist/{manifest-4ZAc6HUk.js → manifest-CJSL9GuC.js} +6 -1
  17. package/dist/{project-B0qNXnFu.js → project-D-hX59RS.js} +4 -1
  18. package/dist/react.d.ts +2 -1
  19. package/dist/react.js +57 -37
  20. package/dist/{schedules-BkWZsbSs.js → schedules-DIIowhD3.js} +1 -1
  21. package/dist/server.d.ts +2 -2
  22. package/dist/telephony.d.ts +24 -4
  23. package/dist/telephony.js +135 -16
  24. package/dist/{variables-0tjnAeut.js → variables-Bzl2ZLQN.js} +1 -1
  25. package/dist/vite.d.ts +1 -1
  26. package/dist/vite.js +17 -6
  27. package/package.json +3 -1
  28. package/scaffold/.agents/skills/hitch-applets/SKILL.md +1 -1
  29. package/scaffold/.agents/skills/hitch-applets/references/markdown.md +2 -0
  30. package/scaffold/.agents/skills/hitch-theory/SKILL.md +1 -1
  31. package/scaffold/.github/workflows/hitch.yml +1 -1
  32. package/scaffold/applet/src/client/styles/globals.css +2 -0
  33. package/dist/build-CcT-wNN9.js +0 -2
  34. package/dist/generate-wIN3IYqL.js +0 -2
package/dist/applet.js CHANGED
@@ -99,23 +99,23 @@ async function main() {
99
99
  const noLogFlags = values.run === void 0 && values.filter === void 0 && values.level === void 0 && values.limit === void 0 && values.live === void 0 && values.search === void 0 && values.since === void 0;
100
100
  const noModeFlags = values["client-only"] === void 0 && values["server-only"] === void 0;
101
101
  if (positionals.length === 1 && positionals[0] === "bootstrap" && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
102
- await (await import("./init-DwsXRUk-.js")).runBootstrap({ install: values["no-install"] !== true });
102
+ await (await import("./init-CpVfJQbv.js")).runBootstrap({ install: values["no-install"] !== true });
103
103
  return;
104
104
  }
105
105
  if (positionals.length === 1 && positionals[0] === "generate" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
106
- await (await import("./generate-wIN3IYqL.js")).runGenerate({});
106
+ await (await import("./generate-Cai2X9z1.js")).runGenerate({});
107
107
  return;
108
108
  }
109
109
  if (positionals.length === 1 && positionals[0] === "build" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
110
- await (await import("./build-CcT-wNN9.js")).runBuild();
110
+ await (await import("./build-CypJADhV.js")).runBuild();
111
111
  return;
112
112
  }
113
113
  if (positionals.length === 1 && positionals[0] === "deploy" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
114
- await (await import("./deploy-BbL3GObV.js")).runDeploy({});
114
+ await (await import("./deploy-CdQQQ5HG.js")).runDeploy({});
115
115
  return;
116
116
  }
117
117
  if (positionals.length === 2 && positionals[0] === "init" && noModeFlags && noVariableFlags && noLogFlags) {
118
- await (await import("./init-DwsXRUk-.js")).runInit(positionals[1], {
118
+ await (await import("./init-CpVfJQbv.js")).runInit(positionals[1], {
119
119
  commit: values["no-commit"] !== true,
120
120
  git: values["no-git"] !== true,
121
121
  install: values["no-install"] !== true
@@ -123,7 +123,7 @@ async function main() {
123
123
  return;
124
124
  }
125
125
  if (positionals.length === 2 && positionals[0] === "new" && noGitFlags && noVariableFlags && noLogFlags) {
126
- await (await import("./init-DwsXRUk-.js")).runNew({
126
+ await (await import("./init-CpVfJQbv.js")).runNew({
127
127
  code: positionals[1],
128
128
  clientOnly: values["client-only"],
129
129
  install: values["no-install"] !== true,
@@ -132,7 +132,7 @@ async function main() {
132
132
  return;
133
133
  }
134
134
  if ((positionals.length === 1 || positionals.length === 2) && positionals[0] === "logs" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags) {
135
- await (await import("./logs-XvK6Zs5Y.js")).runLogs({
135
+ await (await import("./logs-CffdKMRd.js")).runLogs({
136
136
  code: positionals[1],
137
137
  filter: values.filter,
138
138
  run: values.run,
@@ -145,14 +145,14 @@ async function main() {
145
145
  return;
146
146
  }
147
147
  if (positionals.length === 3 && positionals[0] === "schedules" && positionals[1] === "run" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noLogFlags && values.secret === void 0) {
148
- await (await import("./schedules-BkWZsbSs.js")).runSchedule({
148
+ await (await import("./schedules-DIIowhD3.js")).runSchedule({
149
149
  code: positionals[2],
150
150
  yes: values.yes
151
151
  });
152
152
  return;
153
153
  }
154
154
  if ((positionals.length === 3 || positionals.length === 4) && positionals[0] === "variables" && positionals[1] === "set" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noLogFlags) {
155
- await (await import("./variables-0tjnAeut.js")).runVariablesSet({
155
+ await (await import("./variables-Bzl2ZLQN.js")).runVariablesSet({
156
156
  key: positionals[2],
157
157
  secret: values.secret,
158
158
  value: positionals[3],
@@ -161,11 +161,11 @@ async function main() {
161
161
  return;
162
162
  }
163
163
  if (positionals.length === 2 && positionals[0] === "variables" && positionals[1] === "list" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
164
- await (await import("./variables-0tjnAeut.js")).runVariablesList({});
164
+ await (await import("./variables-Bzl2ZLQN.js")).runVariablesList({});
165
165
  return;
166
166
  }
167
167
  if (positionals.length === 3 && positionals[0] === "variables" && positionals[1] === "delete" && values["no-install"] === void 0 && noModeFlags && noGitFlags && values.secret === void 0 && noLogFlags) {
168
- await (await import("./variables-0tjnAeut.js")).runVariablesDelete({
168
+ await (await import("./variables-Bzl2ZLQN.js")).runVariablesDelete({
169
169
  key: positionals[2],
170
170
  yes: values.yes
171
171
  });
@@ -1,4 +1,4 @@
1
- import { i as prepareAppletProjects, r as prepareAppletProject } from "./project-B0qNXnFu.js";
1
+ import { i as prepareAppletProjects, r as prepareAppletProject } from "./project-D-hX59RS.js";
2
2
  import { rm } from "node:fs/promises";
3
3
  import { resolve } from "node:path";
4
4
  import { spawn } from "node:child_process";
@@ -0,0 +1,2 @@
1
+ import { i as runBuild } from "./build-BRpYQ9Lk.js";
2
+ export { runBuild };
@@ -56,11 +56,11 @@ async function loadGitHubActionsSources(context, options) {
56
56
  const body = await response.json();
57
57
  if (body === null || typeof body !== "object" || !("data" in body) || !Array.isArray(body.data)) throw new Error("The CI applets response must contain a data array.");
58
58
  return body.data.map((source) => {
59
- if (source === null || typeof source !== "object" || !("code" in source) || typeof source.code !== "string" || !("source_directory" in source) || typeof source.source_directory !== "string" || !("git_sha" in source) || source.git_sha !== null && typeof source.git_sha !== "string") throw new Error("Each CI applet must contain code, source_directory, and git_sha fields.");
59
+ if (source === null || typeof source !== "object" || !("code" in source) || typeof source.code !== "string" || !("source_directory" in source) || typeof source.source_directory !== "string" || !("source_hash" in source) || source.source_hash !== null && typeof source.source_hash !== "string") throw new Error("Each CI applet must contain code, source_directory, and source_hash fields.");
60
60
  return {
61
61
  code: source.code,
62
62
  sourceDirectory: source.source_directory,
63
- gitSha: source.git_sha
63
+ sourceHash: source.source_hash
64
64
  };
65
65
  });
66
66
  }
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { f as RegisteredContract, m as RegisteredRouter, p as RegisteredManifest } from "./manifest-I-9s8R36.js";
2
- import { t as NarrowContract } from "./contract-QUvEGiRI.js";
1
+ import { f as RegisteredContract, m as RegisteredRouter, p as RegisteredManifest } from "./manifest-C6_F4bL8.js";
2
+ import { t as NarrowContract } from "./contract-CsUpTBe0.js";
3
3
  import { t as WithBatchRecorder } from "./batch-Qa4B4-Yp.js";
4
4
  import { o as WithFilesUpload } from "./upload-DKZzz5kW.js";
5
5
  import { RouterClient } from "@orpc/server";
@@ -1,4 +1,4 @@
1
- import { n as AppletManifest } from "./manifest-I-9s8R36.js";
1
+ import { n as AppletManifest } from "./manifest-C6_F4bL8.js";
2
2
  import { AnyContractRouter } from "@orpc/contract";
3
3
  //#region src/hitch/contract.d.ts
4
4
  type ManifestObjectFor<Manifest, Code> = Manifest extends {
@@ -1,11 +1,12 @@
1
1
  import { i as readWorkspaceConfig, n as fetchWithOrgAuth } from "./workspace-DruAZPmV.js";
2
- import { a as loadGitHubActionsSources, n as githubActionsContext, r as hitchResponseError, t as fetchWithGitHubActions } from "./ci-0Q2mUh53.js";
3
- import { n as buildPreparedApplet, r as prepareWorkspaceBuild, t as buildApplet } from "./build-BlmLiKro.js";
2
+ import { a as loadGitHubActionsSources, n as githubActionsContext, r as hitchResponseError, t as fetchWithGitHubActions } from "./ci-C2CL-0sj.js";
3
+ import { n as buildPreparedApplet, r as prepareWorkspaceBuild, t as buildApplet } from "./build-BRpYQ9Lk.js";
4
4
  import { createRequire } from "node:module";
5
+ import { createHash } from "node:crypto";
5
6
  import { existsSync } from "node:fs";
6
- import { readFile, readdir } from "node:fs/promises";
7
- import { relative, resolve, sep } from "node:path";
8
- import { execFile } from "node:child_process";
7
+ import { lstat, readFile, readdir, readlink } from "node:fs/promises";
8
+ import { dirname, relative, resolve, sep } from "node:path";
9
+ import { execFile, spawn } from "node:child_process";
9
10
  import { promisify } from "node:util";
10
11
  import { createGzip } from "node:zlib";
11
12
  //#region \0rolldown/runtime.js
@@ -2307,11 +2308,112 @@ var require_pack = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2307
2308
  }
2308
2309
  }));
2309
2310
  //#endregion
2310
- //#region src/deploy.ts
2311
+ //#region src/source-hash.ts
2311
2312
  var import_tar_stream = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports) => {
2312
2313
  exports.extract = require_extract();
2313
2314
  exports.pack = require_pack();
2314
2315
  })))(), 1);
2316
+ const execFileAsync$1 = promisify(execFile);
2317
+ function gitEnvironment() {
2318
+ return Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith("GIT_")));
2319
+ }
2320
+ var SourceHashUnavailableError = class extends Error {
2321
+ constructor() {
2322
+ super("Git is unavailable or the applet is outside a git repository.");
2323
+ }
2324
+ };
2325
+ function isMissingPath(error) {
2326
+ return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
2327
+ }
2328
+ async function hashFiles(topLevel, paths, env) {
2329
+ if (paths.length === 0) return [];
2330
+ return new Promise((resolveHashes, reject) => {
2331
+ const child = spawn("git", ["hash-object", "--stdin-paths"], {
2332
+ cwd: topLevel,
2333
+ env
2334
+ });
2335
+ const stdout = [];
2336
+ const stderr = [];
2337
+ child.stdout.on("data", (chunk) => stdout.push(chunk));
2338
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
2339
+ child.stdin.on("error", reject);
2340
+ child.on("error", reject);
2341
+ child.on("close", (code) => {
2342
+ if (code !== 0) {
2343
+ reject(/* @__PURE__ */ new Error(`git hash-object failed (${code}): ${Buffer.concat(stderr).toString("utf8").trim()}`));
2344
+ return;
2345
+ }
2346
+ const hashes = Buffer.concat(stdout).toString("utf8").trimEnd().split("\n");
2347
+ if (hashes.length !== paths.length || hashes.some((hash) => !/^[0-9a-f]{40,64}$/.test(hash))) {
2348
+ reject(/* @__PURE__ */ new Error("git hash-object returned an unexpected number of hashes."));
2349
+ return;
2350
+ }
2351
+ resolveHashes(hashes);
2352
+ });
2353
+ child.stdin.end(paths.map((path) => `"${path.split("").map((character) => character < " " || character === "" || character === "\"" || character === "\\" ? `\\${character.charCodeAt(0).toString(8).padStart(3, "0")}` : character).join("")}"\n`).join(""));
2354
+ });
2355
+ }
2356
+ async function sourceHashes(appletRoots) {
2357
+ if (appletRoots.length === 0) return /* @__PURE__ */ new Map();
2358
+ const env = gitEnvironment();
2359
+ const workspaceRoot = dirname(dirname(appletRoots[0]));
2360
+ let topLevel;
2361
+ try {
2362
+ const { stdout } = await execFileAsync$1("git", ["rev-parse", "--show-toplevel"], {
2363
+ cwd: workspaceRoot,
2364
+ env
2365
+ });
2366
+ topLevel = stdout.trim();
2367
+ } catch (error) {
2368
+ if (isMissingPath(error) || error instanceof Error && error.message.includes("not a git repository")) throw new SourceHashUnavailableError();
2369
+ throw error;
2370
+ }
2371
+ const { stdout } = await execFileAsync$1("git", [
2372
+ "ls-files",
2373
+ "-z",
2374
+ "--cached",
2375
+ "--others",
2376
+ "--exclude-standard"
2377
+ ], {
2378
+ cwd: topLevel,
2379
+ env,
2380
+ maxBuffer: 67108864
2381
+ });
2382
+ const paths = [...new Set(stdout.split("\0").filter(Boolean))];
2383
+ const present = (await Promise.all(paths.map(async (path) => {
2384
+ const absolutePath = resolve(topLevel, path);
2385
+ try {
2386
+ const stat = await lstat(absolutePath);
2387
+ if (stat.isFile()) return {
2388
+ path,
2389
+ kind: "file"
2390
+ };
2391
+ if (stat.isSymbolicLink()) return {
2392
+ path,
2393
+ kind: "link",
2394
+ contentId: await readlink(absolutePath)
2395
+ };
2396
+ return;
2397
+ } catch (error) {
2398
+ if (isMissingPath(error)) return void 0;
2399
+ throw error;
2400
+ }
2401
+ }))).filter((entry) => entry !== void 0);
2402
+ const regularPaths = present.filter((entry) => entry.kind === "file").map((entry) => entry.path);
2403
+ const hashes = await hashFiles(topLevel, regularPaths, env);
2404
+ const contentIds = /* @__PURE__ */ new Map();
2405
+ present.filter((entry) => entry.kind === "link").forEach((entry) => contentIds.set(entry.path, entry.contentId));
2406
+ regularPaths.forEach((path, index) => contentIds.set(path, hashes[index]));
2407
+ const appletsDirectory = relative(topLevel, resolve(workspaceRoot, "applets")).split(sep).join("/");
2408
+ return new Map(appletRoots.map((appletRoot) => {
2409
+ const appletDirectory = relative(topLevel, appletRoot).split(sep).join("/");
2410
+ const digest = createHash("sha256");
2411
+ [...contentIds.entries()].filter(([path]) => path !== appletsDirectory && !path.startsWith(`${appletsDirectory}/`) || path.startsWith(`${appletDirectory}/`)).sort(([left], [right]) => Buffer.compare(Buffer.from(left), Buffer.from(right))).forEach(([path, contentId]) => digest.update(`${path}\0${contentId}\n`));
2412
+ return [appletRoot, digest.digest("hex")];
2413
+ }));
2414
+ }
2415
+ //#endregion
2416
+ //#region src/deploy.ts
2315
2417
  const execFileAsync = promisify(execFile);
2316
2418
  var WorkspaceDeployError = class extends Error {
2317
2419
  constructor(failedApplets) {
@@ -2363,9 +2465,6 @@ async function createBundle(distDir) {
2363
2465
  body.set(bundle);
2364
2466
  return body;
2365
2467
  }
2366
- function gitEnvironment() {
2367
- return Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith("GIT_")));
2368
- }
2369
2468
  async function readGitInfo(appletRoot) {
2370
2469
  const env = gitEnvironment();
2371
2470
  try {
@@ -2399,13 +2498,14 @@ function releaseForm(manifest, bundle) {
2399
2498
  body.set("bundle", new File([bundle], "bundle.tar.gz", { type: "application/gzip" }));
2400
2499
  return body;
2401
2500
  }
2402
- async function deployWithOrgAuth(appletRoot, distDir, manifest, options) {
2501
+ async function deployWithOrgAuth(appletRoot, distDir, manifest, options, sourceHash) {
2403
2502
  const fetcher = options.fetch ?? globalThis.fetch;
2404
2503
  const [bundle, git] = await Promise.all([createBundle(distDir), readGitInfo(appletRoot)]);
2405
2504
  return fetchWithOrgAuth(manifest.org, options, (instanceUrl, accessToken) => {
2406
2505
  const body = releaseForm(manifest, bundle);
2407
2506
  body.set("gitDirty", String(git.gitDirty));
2408
2507
  if (git.gitSha !== void 0) body.set("gitSha", git.gitSha);
2508
+ if (sourceHash !== void 0) body.set("sourceHash", sourceHash);
2409
2509
  return fetcher(`${instanceUrl}/api/v1/applets/${manifest.code}/releases`, {
2410
2510
  method: "POST",
2411
2511
  headers: { Authorization: `Bearer ${accessToken}` },
@@ -2413,12 +2513,13 @@ async function deployWithOrgAuth(appletRoot, distDir, manifest, options) {
2413
2513
  });
2414
2514
  });
2415
2515
  }
2416
- async function deployWithGitHubActions(context, appletRoot, distDir, manifest, options) {
2516
+ async function deployWithGitHubActions(context, appletRoot, distDir, manifest, options, sourceHash) {
2417
2517
  const fetcher = options.fetch ?? globalThis.fetch;
2418
2518
  const [bundle, sourceDirectory] = await Promise.all([createBundle(distDir), repositoryDirectory(appletRoot)]);
2419
2519
  return fetchWithGitHubActions(context, options, (instanceUrl, accessToken) => {
2420
2520
  const body = releaseForm(manifest, bundle);
2421
2521
  body.set("source_directory", sourceDirectory);
2522
+ if (sourceHash !== void 0) body.set("source_hash", sourceHash);
2422
2523
  return fetcher(`${instanceUrl}/api/ci/v1/applets/${manifest.code}/releases`, {
2423
2524
  method: "POST",
2424
2525
  headers: { Authorization: `Bearer ${accessToken}` },
@@ -2426,12 +2527,13 @@ async function deployWithGitHubActions(context, appletRoot, distDir, manifest, o
2426
2527
  });
2427
2528
  });
2428
2529
  }
2429
- async function deployApplet(appletRoot, options, logPrefix = "") {
2530
+ async function deployApplet(appletRoot, options, logPrefix = "", sourceHash) {
2430
2531
  const github = githubActionsContext(options.store?.env ?? process.env);
2532
+ sourceHash ??= (await computeSourceHash([appletRoot], github !== void 0)).get(appletRoot);
2431
2533
  if (options.dist === void 0) await buildApplet(appletRoot);
2432
2534
  const distDir = resolve(appletRoot, options.dist ?? ".hitch/dist");
2433
2535
  const manifest = await readManifest(distDir);
2434
- const response = github === void 0 ? await deployWithOrgAuth(appletRoot, distDir, manifest, options) : await deployWithGitHubActions(github, appletRoot, distDir, manifest, options);
2536
+ const response = github === void 0 ? await deployWithOrgAuth(appletRoot, distDir, manifest, options, sourceHash) : await deployWithGitHubActions(github, appletRoot, distDir, manifest, options, sourceHash);
2435
2537
  if (!response.ok) throw await hitchResponseError(response, "Deploy failed");
2436
2538
  const result = await response.json();
2437
2539
  console.log(`${logPrefix}Deployed release ${result.data.id} (${result.promoted ? "promoted" : "not promoted"}).`);
@@ -2452,84 +2554,32 @@ async function workspaceAppletRoots(workspaceRoot) {
2452
2554
  if (roots.length === 0) throw new Error(`No applets were found under ${appletsDir}.`);
2453
2555
  return roots;
2454
2556
  }
2455
- async function gitChanged(topLevel, base, pathspecs, env) {
2557
+ async function computeSourceHash(appletRoots, required) {
2456
2558
  try {
2457
- await execFileAsync("git", [
2458
- "diff",
2459
- "--quiet",
2460
- base,
2461
- "HEAD",
2462
- "--",
2463
- ...pathspecs
2464
- ], {
2465
- cwd: topLevel,
2466
- env
2467
- });
2468
- return false;
2559
+ return await sourceHashes(appletRoots);
2469
2560
  } catch (error) {
2470
- if (error instanceof Error && "code" in error && error.code === 1) return true;
2561
+ if (!required && error instanceof SourceHashUnavailableError) return /* @__PURE__ */ new Map();
2471
2562
  throw error;
2472
2563
  }
2473
2564
  }
2474
- async function hasCommit(topLevel, sha, env) {
2475
- const git = (args) => execFileAsync("git", args, {
2476
- cwd: topLevel,
2477
- env
2478
- });
2479
- return git([
2480
- "cat-file",
2481
- "-e",
2482
- `${sha}^{commit}`
2483
- ]).catch(() => git([
2484
- "fetch",
2485
- "--depth=1",
2486
- "origin",
2487
- sha
2488
- ])).then(() => true, () => false);
2489
- }
2490
- async function ciDeployDecisions(github, workspaceRoot, appletRoots, options) {
2491
- const env = gitEnvironment();
2492
- const [sources, { stdout: topLevelOutput }, directories] = await Promise.all([
2493
- loadGitHubActionsSources(github, options),
2494
- execFileAsync("git", ["rev-parse", "--show-toplevel"], {
2495
- cwd: workspaceRoot,
2496
- env
2497
- }),
2498
- Promise.all(appletRoots.map((appletRoot) => repositoryDirectory(appletRoot)))
2499
- ]);
2500
- const topLevel = topLevelOutput.trim();
2501
- const appletsDirectory = relative(topLevel, resolve(workspaceRoot, "applets")).split(sep).join("/");
2502
- const baseByDirectory = new Map(sources.map((source) => [source.sourceDirectory, source.gitSha]));
2503
- const bases = new Set(directories.flatMap((directory) => baseByDirectory.get(directory) ?? []));
2504
- const sharedChanges = /* @__PURE__ */ new Map();
2505
- for (const base of bases) sharedChanges.set(base, await hasCommit(topLevel, base, env) ? await gitChanged(topLevel, base, [`:(exclude)${appletsDirectory}`], env) : void 0);
2506
- const decisions = await Promise.all(appletRoots.map(async (appletRoot, index) => {
2507
- const directory = directories[index];
2508
- const base = baseByDirectory.get(directory) ?? null;
2509
- if (base === null) return [appletRoot, {
2510
- deploy: true,
2511
- reason: "no CI release to compare"
2512
- }];
2513
- const short = base.slice(0, 7);
2514
- const sharedChanged = sharedChanges.get(base);
2515
- if (sharedChanged === void 0) return [appletRoot, {
2516
- deploy: true,
2517
- reason: `commit ${short} is not in the repository`
2518
- }];
2519
- if (await gitChanged(topLevel, base, [directory], env)) return [appletRoot, {
2565
+ async function ciDeployDecisions(github, appletRoots, hashes, options) {
2566
+ const [sources, directories] = await Promise.all([loadGitHubActionsSources(github, options), Promise.all(appletRoots.map((appletRoot) => repositoryDirectory(appletRoot)))]);
2567
+ const hashByDirectory = new Map(sources.map((source) => [source.sourceDirectory, source.sourceHash]));
2568
+ return new Map(appletRoots.map((appletRoot, index) => {
2569
+ const sourceHash = hashByDirectory.get(directories[index]);
2570
+ if (sourceHash === null || sourceHash === void 0) return [appletRoot, {
2520
2571
  deploy: true,
2521
- reason: `${directory} changed since ${short}`
2572
+ reason: "no release with a source hash to compare"
2522
2573
  }];
2523
- if (sharedChanged) return [appletRoot, {
2574
+ if (sourceHash !== hashes.get(appletRoot)) return [appletRoot, {
2524
2575
  deploy: true,
2525
- reason: `files outside ${appletsDirectory} changed since ${short}`
2576
+ reason: "files changed since the current release"
2526
2577
  }];
2527
2578
  return [appletRoot, {
2528
2579
  deploy: false,
2529
- reason: `no changes since ${short}`
2580
+ reason: "no changes since the current release"
2530
2581
  }];
2531
2582
  }));
2532
- return new Map(decisions);
2533
2583
  }
2534
2584
  async function runDeploy(options) {
2535
2585
  const root = process.cwd();
@@ -2540,7 +2590,8 @@ async function runDeploy(options) {
2540
2590
  }
2541
2591
  if (readWorkspaceConfig(root) === void 0) throw new Error("Run applet deploy in an applet folder or in the workspace root.");
2542
2592
  const appletRoots = await workspaceAppletRoots(root);
2543
- const decisions = github === void 0 ? void 0 : await ciDeployDecisions(github, root, appletRoots, options);
2593
+ const hashes = await computeSourceHash(appletRoots, github !== void 0);
2594
+ const decisions = github === void 0 ? void 0 : await ciDeployDecisions(github, appletRoots, hashes, options);
2544
2595
  const selectedRoots = appletRoots.filter((appletRoot) => {
2545
2596
  const name = relative(root, appletRoot);
2546
2597
  const decision = decisions?.get(appletRoot);
@@ -2561,7 +2612,7 @@ async function runDeploy(options) {
2561
2612
  await deployApplet(appletRoot, {
2562
2613
  ...options,
2563
2614
  dist: options.dist ?? ".hitch/dist"
2564
- }, logPrefix);
2615
+ }, logPrefix, hashes.get(appletRoot));
2565
2616
  };
2566
2617
  if (interactive) {
2567
2618
  for (const appletRoot of selectedRoots) await deploy(appletRoot);
@@ -1,7 +1,7 @@
1
1
  import { f as resolveInstanceUrl, l as organizationInstanceUrl, n as fetchWithOrgAuth } from "./workspace-DruAZPmV.js";
2
- import { i as loadGitHubActionsBuildInputs, n as githubActionsContext } from "./ci-0Q2mUh53.js";
3
- import { r as prepareAppletProject } from "./project-B0qNXnFu.js";
4
- import { t as loadAppletConfig } from "./load-config-OKZU3UKn.js";
2
+ import { i as loadGitHubActionsBuildInputs, n as githubActionsContext } from "./ci-C2CL-0sj.js";
3
+ import { r as prepareAppletProject } from "./project-D-hX59RS.js";
4
+ import { t as loadAppletConfig } from "./load-config-DI-e1Ool.js";
5
5
  import { createRequire } from "node:module";
6
6
  import { existsSync } from "node:fs";
7
7
  import { access, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
@@ -479,7 +479,10 @@ export type * from "./zod.gen.ts";
479
479
  `);
480
480
  }
481
481
  async function syncContract(outDir, manifest, options = {}) {
482
- await writeContractFiles(outDir, manifest, await loadAuthenticatedSpec(manifest, options));
482
+ await writeContractFiles(outDir, manifest, manifest.objects.length === 0 ? {
483
+ paths: {},
484
+ components: { schemas: {} }
485
+ } : await loadAuthenticatedSpec(manifest, options));
483
486
  }
484
487
  async function runGenerate(options) {
485
488
  await prepareAppletProject();
@@ -0,0 +1,2 @@
1
+ import { n as runGenerate } from "./generate-BDHb2kjw.js";
2
+ export { runGenerate };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { _ as RegisteredWorkflows, a as AppletSourceDefinition, c as appletManifestSchema, d as RegisteredCatalog, f as RegisteredContract, g as RegisteredVariables, h as RegisteredVariableKeys, i as AppletPackages, l as appletSourceDefinitionSchema, m as RegisteredRouter, n as AppletManifest, o as RegisteredAppletSourceDefinition, p as RegisteredManifest, r as AppletManifestObject, s as appletDefinitionSchema, t as AppletDefinition, u as HitchRegister, v as registerHitchContract } from "./manifest-I-9s8R36.js";
2
- import { n as pruneContract, t as NarrowContract } from "./contract-QUvEGiRI.js";
1
+ import { _ as RegisteredWorkflows, a as AppletSourceDefinition, c as appletManifestSchema, d as RegisteredCatalog, f as RegisteredContract, g as RegisteredVariables, h as RegisteredVariableKeys, i as AppletPackages, l as appletSourceDefinitionSchema, m as RegisteredRouter, n as AppletManifest, o as RegisteredAppletSourceDefinition, p as RegisteredManifest, r as AppletManifestObject, s as appletDefinitionSchema, t as AppletDefinition, u as HitchRegister, v as registerHitchContract } from "./manifest-C6_F4bL8.js";
2
+ import { n as pruneContract, t as NarrowContract } from "./contract-CsUpTBe0.js";
3
3
  import { a as UploadedHitchFile, c as createFileOutputSchema, d as getFileOutputSchema, i as UploadProgress, l as fileSchema, n as FilesUpload, r as UploadFileOptions, s as uploadFile, t as FilesClient, u as filesContract } from "./upload-DKZzz5kW.js";
4
4
  import { a as createEmailPixelOutputSchema, c as emailTagsSchema, d as listEmailTrackersInputSchema, f as listEmailTrackersOutputSchema, i as createEmailPixelInputSchema, l as emailTrackerSchema, m as markEmailTrackerSentInputSchema, n as EmailTracker, o as emailContract, r as ListEmailTrackersOutput, s as emailTagKeySchema, t as TelephonyMessageReceivedEvent, u as getEmailTrackerInputSchema } from "./telephony-protocol-D-nf3Gca.js";
5
5
  import { ContractProcedure, Meta } from "@orpc/contract";
@@ -47,6 +47,7 @@ type HitchPhoneNumber = {
47
47
  e164: string;
48
48
  label: string;
49
49
  enabled: boolean;
50
+ assignedTo: string | null;
50
51
  canRead: boolean;
51
52
  canSend: boolean;
52
53
  canCall: boolean;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { i as registerHitchContract, t as uploadFile } from "./upload-DRbVhuDm.js";
2
2
  import { a as emailTagsSchema, c as listEmailTrackersInputSchema, d as markEmailTrackerSentInputSchema, i as emailTagKeySchema, l as listEmailTrackersOutputSchema, n as createEmailPixelOutputSchema, o as emailTrackerSchema, r as emailContract, s as getEmailTrackerInputSchema, t as createEmailPixelInputSchema } from "./email-DBTVhNB_.js";
3
3
  import { n as meSchema, t as meContract } from "./me-BW7Paary.js";
4
- import { n as appletManifestSchema, r as appletSourceDefinitionSchema, t as appletDefinitionSchema } from "./manifest-4ZAc6HUk.js";
4
+ import { n as appletManifestSchema, r as appletSourceDefinitionSchema, t as appletDefinitionSchema } from "./manifest-CJSL9GuC.js";
5
5
  import { oc } from "@orpc/contract";
6
6
  import { z } from "zod";
7
7
  //#region src/hitch/contract.ts
@@ -86,6 +86,7 @@ const hitchPhoneNumberSchema = z.object({
86
86
  e164: z.string(),
87
87
  label: z.string(),
88
88
  enabled: z.boolean(),
89
+ assignedTo: z.uuid().nullable(),
89
90
  canRead: z.boolean(),
90
91
  canSend: z.boolean(),
91
92
  canCall: z.boolean(),
@@ -1,8 +1,8 @@
1
- import { a as ORG_CODE_PATTERN, i as APPLET_CODE_PATTERN } from "./manifest-4ZAc6HUk.js";
1
+ import { a as ORG_CODE_PATTERN, i as APPLET_CODE_PATTERN } from "./manifest-CJSL9GuC.js";
2
2
  import { d as resolveAuthForOrg, f as resolveInstanceUrl, i as readWorkspaceConfig } from "./workspace-DruAZPmV.js";
3
- import { n as runGenerate } from "./generate-XB-72Fzj.js";
4
- import { a as writeAppletSupport, n as loadCliManifest, o as writeWorkspaceSupport, t as assertWorkspaceCli } from "./project-B0qNXnFu.js";
5
- import { n as loadAppletSourceDefinition } from "./load-config-OKZU3UKn.js";
3
+ import { n as runGenerate } from "./generate-BDHb2kjw.js";
4
+ import { a as writeAppletSupport, n as loadCliManifest, o as writeWorkspaceSupport, t as assertWorkspaceCli } from "./project-D-hX59RS.js";
5
+ import { n as loadAppletSourceDefinition } from "./load-config-DI-e1Ool.js";
6
6
  import { access, cp, mkdir, readdir, writeFile } from "node:fs/promises";
7
7
  import { relative, resolve } from "node:path";
8
8
  import { spawn } from "node:child_process";
@@ -1,4 +1,4 @@
1
- import { r as appletSourceDefinitionSchema } from "./manifest-4ZAc6HUk.js";
1
+ import { r as appletSourceDefinitionSchema } from "./manifest-CJSL9GuC.js";
2
2
  import { t as resolveWorkspaceOrg } from "./workspace-DruAZPmV.js";
3
3
  import { existsSync } from "node:fs";
4
4
  import { resolve } from "node:path";
@@ -1,6 +1,6 @@
1
- import { i as APPLET_CODE_PATTERN } from "./manifest-4ZAc6HUk.js";
1
+ import { i as APPLET_CODE_PATTERN } from "./manifest-CJSL9GuC.js";
2
2
  import { i as readWorkspaceConfig, n as fetchWithOrgAuth, t as resolveWorkspaceOrg } from "./workspace-DruAZPmV.js";
3
- import { t as loadAppletConfig } from "./load-config-OKZU3UKn.js";
3
+ import { t as loadAppletConfig } from "./load-config-DI-e1Ool.js";
4
4
  import { z } from "zod";
5
5
  //#region src/logs.ts
6
6
  const LOG_LEVELS = [
@@ -35,7 +35,9 @@ interface AppletManifest {
35
35
  /** This code needs the schema as of this changeset. */
36
36
  requiresChangeset?: string;
37
37
  telephony?: {
38
- events: readonly "message.received"[];
38
+ read?: boolean;
39
+ send?: boolean;
40
+ events?: readonly "message.received"[];
39
41
  };
40
42
  schedules?: readonly {
41
43
  code: string;
@@ -73,7 +73,11 @@ const appletManifestShape = {
73
73
  name: nameSchema,
74
74
  code: codeSchema,
75
75
  requiresChangeset: z.uuid().optional(),
76
- telephony: z.strictObject({ events: z.array(z.literal("message.received")).min(1).refine((events) => new Set(events).size === events.length).readonly() }).optional(),
76
+ telephony: z.strictObject({
77
+ read: z.boolean().optional(),
78
+ send: z.boolean().optional(),
79
+ events: z.array(z.literal("message.received")).min(1).refine((events) => new Set(events).size === events.length).readonly().optional()
80
+ }).refine((telephony) => telephony.events === void 0 || telephony.read === true, "telephony.events needs telephony.read").optional(),
77
81
  schedules: appletManifestSchedulesSchema.optional(),
78
82
  variables: appletManifestVariablesSchema.optional(),
79
83
  objects: appletManifestObjectsSchema
@@ -113,6 +117,7 @@ const appletDefinitionSchema = z.strictObject({
113
117
  }).superRefine(checkDuplicateCodes);
114
118
  const packageVersionsSchema = z.record(z.string().min(1), z.string().min(1)).readonly();
115
119
  const RESERVED_APPLET_PACKAGES = /* @__PURE__ */ new Set([
120
+ "@fontsource-variable/geist-mono",
116
121
  "@fontsource-variable/inter",
117
122
  "@hitch42/applet",
118
123
  "@orpc/contract",
@@ -1,5 +1,5 @@
1
1
  import { i as readWorkspaceConfig, l as organizationInstanceUrl, s as DEFAULT_INSTANCE_URL } from "./workspace-DruAZPmV.js";
2
- import { n as loadAppletSourceDefinition } from "./load-config-OKZU3UKn.js";
2
+ import { n as loadAppletSourceDefinition } from "./load-config-DI-e1Ool.js";
3
3
  import { z } from "zod";
4
4
  import { existsSync } from "node:fs";
5
5
  import { cp, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
@@ -74,6 +74,7 @@ const cliManifestSchema = z.object({
74
74
  name: cliManifestValueSchema,
75
75
  version: cliManifestValueSchema,
76
76
  dependencies: z.object({
77
+ "@fontsource-variable/geist-mono": cliManifestValueSchema,
77
78
  "@fontsource-variable/inter": cliManifestValueSchema,
78
79
  "@orpc/contract": cliManifestValueSchema,
79
80
  "@tiptap/core": cliManifestValueSchema,
@@ -158,6 +159,7 @@ function workspaceFile(cli) {
158
159
  - applets/*
159
160
  catalog:
160
161
  "@hitch42/applet": npm:${cli.name}@${cli.version}
162
+ "@fontsource-variable/geist-mono": "${cli.dependencies["@fontsource-variable/geist-mono"]}"
161
163
  "@fontsource-variable/inter": "${cli.dependencies["@fontsource-variable/inter"]}"
162
164
  "@orpc/contract": "${cli.dependencies["@orpc/contract"]}"
163
165
  "@orpc/server": "${cli.peerDependencies["@orpc/server"]}"
@@ -381,6 +383,7 @@ function appletPackage(definition, options) {
381
383
  zod: "catalog:",
382
384
  ...options.hasServer ? { "@orpc/server": "catalog:" } : {},
383
385
  ...options.hasClient ? {
386
+ "@fontsource-variable/geist-mono": "catalog:",
384
387
  "@fontsource-variable/inter": "catalog:",
385
388
  "@tanstack/react-query": "catalog:",
386
389
  "@tanstack/react-router": "catalog:",
package/dist/react.d.ts CHANGED
@@ -29,9 +29,10 @@ type MarkdownEditorProps = {
29
29
  minLength?: number;
30
30
  maxLength?: number;
31
31
  disabled?: boolean;
32
+ autoFocus?: boolean;
32
33
  className?: string;
33
34
  onUploadError?: (error: unknown, file: File) => void;
34
35
  };
35
- declare function MarkdownEditor({ value, onChange, files, id, placeholder, required, minLength, maxLength, disabled, className, onUploadError }: MarkdownEditorProps): ReactElement;
36
+ declare function MarkdownEditor({ value, onChange, files, id, placeholder, required, minLength, maxLength, disabled, autoFocus, className, onUploadError }: MarkdownEditorProps): ReactElement;
36
37
  //#endregion
37
38
  export { Markdown, MarkdownEditor, type MarkdownEditorFiles, type MarkdownEditorProps, type MarkdownFiles, type MarkdownProps };