@hitch42/applet 0.1.1-beta.15 → 0.1.1-beta.17

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 (55) hide show
  1. package/dist/_internal/log-context.d.ts +0 -2
  2. package/dist/_internal/log-context.js +1 -1
  3. package/dist/_internal/server.d.ts +10 -1
  4. package/dist/_internal/server.js +17 -3
  5. package/dist/applet.js +12 -12
  6. package/dist/auth-D3CrCtZq.js +21 -0
  7. package/dist/{build-BkhBHdMs.js → build-XHoa_sJL.js} +1 -1
  8. package/dist/build-ueR7XjZT.js +2 -0
  9. package/dist/{ci-BKw14X2h.js → ci-B5-mH-YW.js} +1 -1
  10. package/dist/client.d.ts +3 -3
  11. package/dist/contract-BbOj5EB7.js +23 -0
  12. package/dist/{contract-CZdT22tB.d.ts → contract-D9wEvxGI.d.ts} +1 -1
  13. package/dist/{deploy-D5SBBd-j.js → deploy-Da93able.js} +28 -4
  14. package/dist/device-BgIfytaR.js +135 -0
  15. package/dist/email-protocol-B9u_dh2p.d.ts +202 -0
  16. package/dist/{generate-MWjUbZnO.js → generate-BV_emZgy.js} +39 -13
  17. package/dist/generate-C9bWqdaB.js +2 -0
  18. package/dist/hitch-file-url-BPKj9zVG.js +25 -0
  19. package/dist/index.d.ts +15 -25
  20. package/dist/index.js +80 -192
  21. package/dist/{init-Dw7GEI5v.js → init-BGQ_bP44.js} +5 -5
  22. package/dist/{manifest-CuY3ICpN.js → load-config-Dkr2VxZN.js} +37 -2
  23. package/dist/{log-context-zu8U9Sjm.js → log-context-DWznGjfz.js} +1 -5
  24. package/dist/{login-CUx3TmFQ.js → login-CceGvlMi.js} +3 -1
  25. package/dist/{logs-BySh9fnH.js → logs-DOkT5ots.js} +3 -3
  26. package/dist/{manifest-ARAy2HP7.d.ts → manifest-BSUtHbu-.d.ts} +1 -4
  27. package/dist/markdown-CwlqzBtP.js +88 -0
  28. package/dist/markdown-DSHOQIOb.d.ts +14 -0
  29. package/dist/markdown-editor-BmEaBzd7.d.ts +27 -0
  30. package/dist/markdown-editor-C5mLHGqu.js +428 -0
  31. package/dist/{project-NcWw8SwL.js → project-CCVqCCgU.js} +3 -2
  32. package/dist/react/markdown-editor.d.ts +2 -0
  33. package/dist/react/markdown-editor.js +2 -0
  34. package/dist/react/markdown.d.ts +2 -0
  35. package/dist/react/markdown.js +2 -0
  36. package/dist/react.d.ts +2 -37
  37. package/dist/react.js +2 -534
  38. package/dist/{schedules-B_p9U-vM.js → schedules-D6-3v-Az.js} +1 -1
  39. package/dist/server.d.ts +3 -3
  40. package/dist/server.js +1 -1
  41. package/dist/store-B8N_8JIN.js +196 -0
  42. package/dist/{upload-DKZzz5kW.d.ts → upload-D_kkmne_.d.ts} +5 -9
  43. package/dist/{variables-D9nEFyOK.js → variables-BSFZnLxY.js} +2 -2
  44. package/dist/vite.d.ts +1 -1
  45. package/dist/vite.js +165 -35
  46. package/dist/workspace-8yqXsvce.js +31 -0
  47. package/package.json +13 -1
  48. package/scaffold/.agents/skills/hitch-applets/references/markdown.md +20 -2
  49. package/dist/build-D7FDW8iC.js +0 -2
  50. package/dist/email-WA4jnzZ0.js +0 -211
  51. package/dist/email-protocol-DqJ6YCiC.d.ts +0 -230
  52. package/dist/generate-WYS-jtPH.js +0 -2
  53. package/dist/load-config-BeQZ2yOa.js +0 -27
  54. package/dist/me-BW7Paary.js +0 -32
  55. package/dist/workspace-D0dnnlxL.js +0 -385
@@ -19,8 +19,6 @@ declare function cloudflareRequestFields(request: Request): {
19
19
  cfRay: string | undefined;
20
20
  traceparent: string | undefined;
21
21
  colo: string | undefined;
22
- country: string | undefined;
23
- asn: number | undefined;
24
22
  };
25
23
  type NoteLog = {
26
24
  set(fields: Record<string, unknown>): void;
@@ -1,2 +1,2 @@
1
- import { a as errorNote, c as requestIdFrom, i as createNoteLog, n as REQUEST_CONTEXT_CHANNEL, o as isUuid, r as cloudflareRequestFields, s as publishNote, t as APP_CONTEXT_CHANNEL } from "../log-context-zu8U9Sjm.js";
1
+ import { a as errorNote, c as requestIdFrom, i as createNoteLog, n as REQUEST_CONTEXT_CHANNEL, o as isUuid, r as cloudflareRequestFields, s as publishNote, t as APP_CONTEXT_CHANNEL } from "../log-context-DWznGjfz.js";
2
2
  export { APP_CONTEXT_CHANNEL, REQUEST_CONTEXT_CHANNEL, cloudflareRequestFields, createNoteLog, errorNote, isUuid, publishNote, requestIdFrom };
@@ -1,5 +1,5 @@
1
1
  import { t as AnyWorkflowDefinition } from "../workflow-DurM6Fwx.js";
2
- import { I as markEmailTrackerSentBodySchema, k as listEmailTrackersInputSchema, m as createEmailPixelInputSchema, n as TelephonyMessageReceivedEvent, t as EmailMessageReceivedEvent } from "../email-protocol-DqJ6YCiC.js";
2
+ import { d as ListEmailTrackersInput, n as TelephonyMessageReceivedEvent, r as CreateEmailPixelInput, t as EmailMessageReceivedEvent } from "../email-protocol-B9u_dh2p.js";
3
3
  import { z } from "zod";
4
4
  //#region src/server/entry.d.ts
5
5
  declare function createWorkerEntry(server: {
@@ -92,4 +92,13 @@ type Engine = {
92
92
  declare class WorkflowFailedError extends Error {}
93
93
  declare function runWorkflowJournal(engine: Engine, invoke: (journal: JournalEntry[]) => Promise<WorkflowOutcome>): Promise<unknown>;
94
94
  //#endregion
95
+ //#region src/hitch/email-schemas.d.ts
96
+ declare const createEmailPixelInputSchema: z.ZodType<CreateEmailPixelInput, CreateEmailPixelInput>;
97
+ declare const markEmailTrackerSentBodySchema: z.ZodType<{
98
+ sentAt?: string;
99
+ }, {
100
+ sentAt?: string;
101
+ }>;
102
+ declare const listEmailTrackersInputSchema: z.ZodType<ListEmailTrackersInput, ListEmailTrackersInput>;
103
+ //#endregion
95
104
  export { type Engine, type JournalEntry, WorkflowFailedError, type WorkflowInvocationRequest, type WorkflowOutcome, createEmailPixelInputSchema, createWorkerEntry, journalEntrySchema, listEmailTrackersInputSchema, markEmailTrackerSentBodySchema, runWorkflowJournal, workflowInvocationRequestSchema, workflowOutcomeSchema };
@@ -1,10 +1,9 @@
1
- import { C as markEmailTrackerSentBodySchema, g as listEmailTrackersInputSchema, t as createEmailPixelInputSchema } from "../email-WA4jnzZ0.js";
2
1
  import { a as HITCH_ORG_CODE_HEADER, c as HITCH_SCHEDULE_HEADER, d as HITCH_USER_HEADER, f as HITCH_WORKFLOW_HEADER, i as HITCH_ORGANIZATION_HEADER, l as HITCH_SCHEDULE_RUN_HEADER, m as HITCH_WORKFLOW_RUN_HEADER, n as HITCH_APPLET_HEADER, o as HITCH_RELEASE_HEADER, p as HITCH_WORKFLOW_INVOCATION_HEADER, r as HITCH_APPLET_TOKEN_HEADER, u as HITCH_SESSION_HEADER } from "../headers-DkNr9MLJ.js";
3
2
  import { a as getRequestContext, o as runWithRequestContext, r as toMilliseconds, t as MAX_DURATION_MS } from "../workflow-CTo2kZF1.js";
4
- import { a as errorNote, c as requestIdFrom, i as createNoteLog, r as cloudflareRequestFields, s as publishNote, t as APP_CONTEXT_CHANNEL } from "../log-context-zu8U9Sjm.js";
3
+ import { a as errorNote, c as requestIdFrom, i as createNoteLog, r as cloudflareRequestFields, s as publishNote, t as APP_CONTEXT_CHANNEL } from "../log-context-DWznGjfz.js";
5
4
  import { a as workflowOutcomeSchema, i as workflowInvocationRequestSchema, n as runWorkflowJournal, r as journalEntrySchema, t as WorkflowFailedError } from "../workflow-engine-BOTzURKM.js";
6
- import { z } from "zod";
7
5
  import { RPCHandler } from "@orpc/server/fetch";
6
+ import { z } from "zod";
8
7
  //#region src/server/telephony-protocol.ts
9
8
  const telephonyMessageReceivedEventSchema = z.object({
10
9
  eventId: z.string(),
@@ -258,4 +257,19 @@ function createWorkerEntry(server, options) {
258
257
  } };
259
258
  }
260
259
  //#endregion
260
+ //#region src/hitch/email-schemas.ts
261
+ const emailTagKeySchema = z.string().regex(/^[A-Za-z][A-Za-z0-9_]{0,63}$/);
262
+ const emailTagsSchema = z.record(emailTagKeySchema, z.string().min(1).max(200)).refine((tags) => Object.keys(tags).length <= 10);
263
+ const createEmailPixelInputSchema = z.object({ tags: emailTagsSchema.optional() }).strict();
264
+ const markEmailTrackerSentBodySchema = z.object({ sentAt: z.iso.datetime({ offset: true }).optional() }).strict();
265
+ const listEmailTrackersInputSchema = z.object({
266
+ filter: emailTagsSchema.optional(),
267
+ sentAt: z.object({
268
+ $gte: z.iso.datetime({ offset: true }).optional(),
269
+ $lt: z.iso.datetime({ offset: true }).optional()
270
+ }).strict().optional(),
271
+ cursor: z.uuid().optional(),
272
+ limit: z.number().int().min(1).max(200).optional()
273
+ }).strict();
274
+ //#endregion
261
275
  export { WorkflowFailedError, createEmailPixelInputSchema, createWorkerEntry, journalEntrySchema, listEmailTrackersInputSchema, markEmailTrackerSentBodySchema, runWorkflowJournal, workflowInvocationRequestSchema, workflowOutcomeSchema };
package/dist/applet.js CHANGED
@@ -90,7 +90,7 @@ async function main() {
90
90
  strict: true
91
91
  });
92
92
  if (positionals.length === 1 && positionals[0] === "login" && Object.keys(values).every((key) => key === "no-browser")) {
93
- await (await import("./login-CUx3TmFQ.js")).runLogin({ noBrowser: values["no-browser"] });
93
+ await (await import("./login-CceGvlMi.js")).runLogin({ noBrowser: values["no-browser"] });
94
94
  return;
95
95
  }
96
96
  if (values["no-browser"] !== void 0) throw new Error(usage);
@@ -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-Dw7GEI5v.js")).runBootstrap({ install: values["no-install"] !== true });
102
+ await (await import("./init-BGQ_bP44.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-WYS-jtPH.js")).runGenerate();
106
+ await (await import("./generate-C9bWqdaB.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-D7FDW8iC.js")).runBuild();
110
+ await (await import("./build-ueR7XjZT.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-D5SBBd-j.js")).runDeploy({});
114
+ await (await import("./deploy-Da93able.js")).runDeploy({});
115
115
  return;
116
116
  }
117
117
  if (positionals.length === 2 && positionals[0] === "init" && noModeFlags && noVariableFlags && noLogFlags) {
118
- await (await import("./init-Dw7GEI5v.js")).runInit(positionals[1], {
118
+ await (await import("./init-BGQ_bP44.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-Dw7GEI5v.js")).runNew({
126
+ await (await import("./init-BGQ_bP44.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-BySh9fnH.js")).runLogs({
135
+ await (await import("./logs-DOkT5ots.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-B_p9U-vM.js")).runSchedule({
148
+ await (await import("./schedules-D6-3v-Az.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-D9nEFyOK.js")).runVariablesSet({
155
+ await (await import("./variables-BSFZnLxY.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-D9nEFyOK.js")).runVariablesList();
164
+ await (await import("./variables-BSFZnLxY.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-D9nEFyOK.js")).runVariablesDelete({
168
+ await (await import("./variables-BSFZnLxY.js")).runVariablesDelete({
169
169
  key: positionals[2],
170
170
  yes: values.yes
171
171
  });
@@ -0,0 +1,21 @@
1
+ import { a as organizationInstanceUrl, c as resolveInstanceUrl, i as getCredentialsForOrg, o as rejectEnvironmentKey, r as bearerToken, s as resolveAuthForOrg, t as AuthenticationError } from "./store-B8N_8JIN.js";
2
+ import { t as loginWithDevice } from "./device-BgIfytaR.js";
3
+ import "./workspace-8yqXsvce.js";
4
+ //#region src/auth.ts
5
+ async function fetchWithOrgAuth(orgCode, request) {
6
+ const instanceUrl = await resolveInstanceUrl();
7
+ const organizationUrl = organizationInstanceUrl(instanceUrl, orgCode);
8
+ const auth = await resolveAuthForOrg(instanceUrl, orgCode);
9
+ if (auth !== void 0) {
10
+ const response = await request(organizationUrl, bearerToken(auth));
11
+ rejectEnvironmentKey(response, auth);
12
+ if (response.status !== 401) return response;
13
+ }
14
+ if (process.stdin.isTTY !== true) throw new AuthenticationError("Not logged in. Run applet login, or set HITCH_API_KEY.");
15
+ await loginWithDevice(instanceUrl, { expectedOrg: orgCode });
16
+ const credentials = await getCredentialsForOrg(instanceUrl, orgCode);
17
+ if (credentials === void 0) throw new Error(`login did not provide credentials for organization "${orgCode}"`);
18
+ return request(organizationUrl, bearerToken(credentials));
19
+ }
20
+ //#endregion
21
+ export { fetchWithOrgAuth as t };
@@ -1,4 +1,4 @@
1
- import { i as prepareAppletProjects, r as prepareAppletProject } from "./project-NcWw8SwL.js";
1
+ import { i as prepareAppletProjects, r as prepareAppletProject } from "./project-CCVqCCgU.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-XHoa_sJL.js";
2
+ export { runBuild };
@@ -1,4 +1,4 @@
1
- import { f as resolveInstanceUrl } from "./workspace-D0dnnlxL.js";
1
+ import { c as resolveInstanceUrl } from "./store-B8N_8JIN.js";
2
2
  //#region src/ci.ts
3
3
  function githubActionsContext() {
4
4
  const env = process.env;
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { f as RegisteredContract, m as RegisteredRouter, p as RegisteredManifest } from "./manifest-ARAy2HP7.js";
2
- import { t as NarrowContract } from "./contract-CZdT22tB.js";
1
+ import { d as RegisteredRouter, l as RegisteredContract, u as RegisteredManifest } from "./manifest-BSUtHbu-.js";
2
+ import { t as NarrowContract } from "./contract-D9wEvxGI.js";
3
3
  import { t as WithBatchRecorder } from "./batch-Qa4B4-Yp.js";
4
- import { o as WithFilesUpload } from "./upload-DKZzz5kW.js";
4
+ import { o as WithFilesUpload } from "./upload-D_kkmne_.js";
5
5
  import { RouterClient } from "@orpc/server";
6
6
  import { ContractRouterClient } from "@orpc/contract";
7
7
  import { NestedClient } from "@orpc/client";
@@ -0,0 +1,23 @@
1
+ //#region src/hitch/contract.ts
2
+ function isObject(value) {
3
+ return value !== null && typeof value === "object" && !Array.isArray(value);
4
+ }
5
+ function pruneContract(contract, manifest) {
6
+ if (!isObject(contract) || !isObject(contract.records)) throw new Error("Hitch contract must contain a \"records\" router.");
7
+ const contractRecords = contract.records;
8
+ const records = Object.fromEntries(manifest.objects.map((manifestObject) => {
9
+ const procedures = contractRecords[manifestObject.code];
10
+ if (!isObject(procedures)) throw new Error(`Hitch contract object "${manifestObject.code}" is missing.`);
11
+ const pruned = { ...procedures };
12
+ if (!manifestObject.canCreate) delete pruned.create;
13
+ if (!manifestObject.canDelete) delete pruned.delete;
14
+ if (manifestObject.readWrite.length === 0) {
15
+ delete pruned.update;
16
+ delete pruned.updateWhere;
17
+ }
18
+ return [manifestObject.code, pruned];
19
+ }));
20
+ return Object.assign({}, contract, { records });
21
+ }
22
+ //#endregion
23
+ export { pruneContract as t };
@@ -1,4 +1,4 @@
1
- import { n as AppletManifest } from "./manifest-ARAy2HP7.js";
1
+ import { n as AppletManifest } from "./manifest-BSUtHbu-.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,6 +1,7 @@
1
- import { i as readWorkspaceConfig, n as fetchWithOrgAuth } from "./workspace-D0dnnlxL.js";
2
- import { a as loadGitHubActionsSources, n as githubActionsContext, r as hitchResponseError, t as fetchWithGitHubActions } from "./ci-BKw14X2h.js";
3
- import { n as buildPreparedApplet, r as prepareWorkspaceBuild, t as buildApplet } from "./build-BkhBHdMs.js";
1
+ import { n as readWorkspaceConfig } from "./workspace-8yqXsvce.js";
2
+ import { t as fetchWithOrgAuth } from "./auth-D3CrCtZq.js";
3
+ import { a as loadGitHubActionsSources, n as githubActionsContext, r as hitchResponseError, t as fetchWithGitHubActions } from "./ci-B5-mH-YW.js";
4
+ import { n as buildPreparedApplet, r as prepareWorkspaceBuild, t as buildApplet } from "./build-XHoa_sJL.js";
4
5
  import { createRequire } from "node:module";
5
6
  import { createHash } from "node:crypto";
6
7
  import { existsSync } from "node:fs";
@@ -2545,6 +2546,28 @@ async function deployApplet(appletRoot, options, logPrefix = "", sourceHash) {
2545
2546
  if (result.unset_variables?.length) console.warn(`${logPrefix}Warning: declared variables not set: ${result.unset_variables.join(", ")}. Set them with applet variables set.`);
2546
2547
  return result;
2547
2548
  }
2549
+ function buildConcurrency() {
2550
+ const value = process.env.APPLET_BUILD_CONCURRENCY;
2551
+ if (value === void 0) return Infinity;
2552
+ if (/^[1-9]\d*$/.test(value)) return Number(value);
2553
+ console.warn(`Ignoring APPLET_BUILD_CONCURRENCY=${JSON.stringify(value)}: it must be a positive integer. Building every applet at once.`);
2554
+ return Infinity;
2555
+ }
2556
+ function semaphore(limit) {
2557
+ let active = 0;
2558
+ const waiting = [];
2559
+ return async (task) => {
2560
+ if (active < limit) active++;
2561
+ else await new Promise((resolve) => waiting.push(resolve));
2562
+ try {
2563
+ return await task();
2564
+ } finally {
2565
+ const next = waiting.shift();
2566
+ if (next === void 0) active--;
2567
+ else next();
2568
+ }
2569
+ };
2570
+ }
2548
2571
  async function workspaceAppletRoots(workspaceRoot) {
2549
2572
  const appletsDir = resolve(workspaceRoot, "applets");
2550
2573
  const roots = (await readdir(appletsDir, { withFileTypes: true }).catch((error) => {
@@ -2606,9 +2629,10 @@ async function runDeploy(options) {
2606
2629
  if (selectedRoots.length === 0) return;
2607
2630
  if (options.dist === void 0) await prepareWorkspaceBuild(root, appletRoots);
2608
2631
  const interactive = github === void 0 && process.stdin.isTTY === true;
2632
+ const buildSlot = semaphore(buildConcurrency());
2609
2633
  const deploy = async (appletRoot) => {
2610
2634
  const logPrefix = `[${relative(root, appletRoot)}] `;
2611
- if (options.dist === void 0) await buildPreparedApplet(appletRoot, ".hitch/dist", interactive ? "" : logPrefix);
2635
+ if (options.dist === void 0) await buildSlot(() => buildPreparedApplet(appletRoot, ".hitch/dist", interactive ? "" : logPrefix));
2612
2636
  await deployApplet(appletRoot, {
2613
2637
  ...options,
2614
2638
  dist: options.dist ?? ".hitch/dist"
@@ -0,0 +1,135 @@
1
+ import { l as setCredentials, o as rejectEnvironmentKey, t as AuthenticationError } from "./store-B8N_8JIN.js";
2
+ import { spawn } from "node:child_process";
3
+ //#region ../shared/auth/src/device.mts
4
+ const CLIENT_ID = "hitch-cli";
5
+ const DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
6
+ function defaultOpenUrl(url) {
7
+ try {
8
+ const child = spawn(process.platform === "darwin" ? "open" : "xdg-open", [url], {
9
+ detached: true,
10
+ stdio: "ignore"
11
+ });
12
+ child.on("error", () => void 0);
13
+ child.unref();
14
+ } catch {}
15
+ }
16
+ function requiredObject(value, message) {
17
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(message);
18
+ return value;
19
+ }
20
+ async function jsonResponse(response) {
21
+ try {
22
+ return requiredObject(await response.json(), "Expected a JSON object response.");
23
+ } catch (error) {
24
+ throw new Error(`Invalid JSON response from ${response.url || "Hitch"}.`, { cause: error });
25
+ }
26
+ }
27
+ async function postJson(fetcher, url, body) {
28
+ const response = await fetcher(url, {
29
+ method: "POST",
30
+ headers: { "content-type": "application/json" },
31
+ body: JSON.stringify(body)
32
+ });
33
+ return {
34
+ body: await jsonResponse(response),
35
+ response
36
+ };
37
+ }
38
+ function parseDeviceCode(value) {
39
+ if (typeof value.device_code !== "string" || typeof value.user_code !== "string" || typeof value.verification_uri !== "string" || typeof value.verification_uri_complete !== "string" || typeof value.expires_in !== "number" || value.interval !== void 0 && typeof value.interval !== "number") throw new AuthenticationError("Hitch returned an invalid device authorization response.");
40
+ return value;
41
+ }
42
+ function parseToken(value) {
43
+ return typeof value.access_token === "string" && typeof value.token_type === "string" ? value : void 0;
44
+ }
45
+ function parseDeviceOrganization(value) {
46
+ if (typeof value.organizationId !== "string" || typeof value.orgCode !== "string") throw new AuthenticationError("Hitch returned an invalid device organization response.");
47
+ return value;
48
+ }
49
+ function parseMe(value) {
50
+ const person = requiredObject(value.person, "Hitch returned an invalid identity response.");
51
+ if (typeof person.id !== "string" || typeof person.firstName !== "string" || typeof person.lastName !== "string" || typeof person.email !== "string" || !Array.isArray(value.memberships)) throw new Error("Hitch returned an invalid identity response.");
52
+ const organization = value.organization === void 0 || value.organization === null ? null : requiredObject(value.organization, "Hitch returned an invalid identity response.");
53
+ if (organization !== null && (typeof organization.id !== "string" || typeof organization.code !== "string")) throw new Error("Hitch returned an invalid identity response.");
54
+ return {
55
+ memberships: value.memberships.map((membership) => {
56
+ const item = requiredObject(membership, "Hitch returned an invalid membership.");
57
+ if (typeof item.orgId !== "string" || typeof item.code !== "string" || typeof item.name !== "string") throw new Error("Hitch returned an invalid membership.");
58
+ return item;
59
+ }),
60
+ organization,
61
+ person
62
+ };
63
+ }
64
+ async function fetchMe(fetcher, instanceUrl, auth) {
65
+ const response = await fetcher(`${instanceUrl}/api/v1/me`, { headers: { Authorization: `Bearer ${auth.accessToken}` } });
66
+ rejectEnvironmentKey(response, auth);
67
+ if (auth.credentialType === "apiKey" && response.status === 401) throw new AuthenticationError("API key rejected.");
68
+ const body = await jsonResponse(response);
69
+ if (!response.ok) throw new AuthenticationError(typeof body.message === "string" ? body.message : `Failed to load the signed-in identity (${response.status}).`);
70
+ return parseMe(body);
71
+ }
72
+ async function pollForToken(fetcher, instanceUrl, device, now, sleep) {
73
+ const deadline = now() + device.expires_in * 1e3;
74
+ let interval = (device.interval ?? 5) * 1e3;
75
+ while (now() < deadline) {
76
+ await sleep(Math.min(interval, deadline - now()));
77
+ if (now() >= deadline) break;
78
+ const { body, response } = await postJson(fetcher, `${instanceUrl}/api/auth/device/token`, {
79
+ grant_type: DEVICE_GRANT,
80
+ device_code: device.device_code,
81
+ client_id: CLIENT_ID
82
+ });
83
+ const token = parseToken(body);
84
+ if (response.ok && token !== void 0) return token;
85
+ switch (body.error) {
86
+ case "authorization_pending": break;
87
+ case "slow_down":
88
+ interval += 5e3;
89
+ break;
90
+ case "expired_token": throw new AuthenticationError("The sign-in request expired. Run hitch login again.");
91
+ case "access_denied": throw new AuthenticationError("Sign-in was denied.");
92
+ default: throw new AuthenticationError(typeof body.error_description === "string" ? body.error_description : `Sign-in failed (${response.status}).`);
93
+ }
94
+ }
95
+ throw new AuthenticationError("The sign-in request expired. Run hitch login again.");
96
+ }
97
+ async function loginWithDevice(instanceUrl, options = {}) {
98
+ const fetcher = globalThis.fetch;
99
+ const now = Date.now;
100
+ const { body, response } = await postJson(fetcher, `${instanceUrl}/api/auth/device/code`, { client_id: CLIENT_ID });
101
+ if (!response.ok) throw new AuthenticationError(typeof body.error_description === "string" ? body.error_description : `Could not start sign-in (${response.status}).`);
102
+ const device = parseDeviceCode(body);
103
+ const verificationUrl = options.expectedOrg === void 0 ? device.verification_uri_complete : `${device.verification_uri_complete}&org=${encodeURIComponent(options.expectedOrg)}`;
104
+ console.log(`Open ${verificationUrl} and confirm code ${device.user_code}.`);
105
+ if (!options.noBrowser) try {
106
+ defaultOpenUrl(verificationUrl);
107
+ } catch {}
108
+ const token = await pollForToken(fetcher, instanceUrl, device, now, (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
109
+ const { body: organizationBody, response: organizationResponse } = await postJson(fetcher, `${instanceUrl}/api/auth/device/organization`, { device_code: device.device_code });
110
+ if (!organizationResponse.ok) throw new AuthenticationError("The sign-in did not resolve an organization.");
111
+ const organization = parseDeviceOrganization(organizationBody);
112
+ const me = await fetchMe(fetcher, instanceUrl, {
113
+ accessToken: token.access_token,
114
+ credentialType: "session",
115
+ source: "store"
116
+ });
117
+ const membership = me.memberships.find(({ orgId }) => orgId === organization.organizationId);
118
+ if (membership === void 0) throw new AuthenticationError("The device session is not scoped to a Hitch organization.");
119
+ const credentials = {
120
+ type: "session",
121
+ accessToken: token.access_token,
122
+ expiresAt: token.expires_in === void 0 ? void 0 : now() + token.expires_in * 1e3,
123
+ organizationId: organization.organizationId,
124
+ orgCode: organization.orgCode
125
+ };
126
+ await setCredentials(instanceUrl, credentials);
127
+ if (options.expectedOrg !== void 0 && organization.orgCode !== options.expectedOrg) throw new AuthenticationError(`logged in to "${organization.orgCode}" but this applet targets "${options.expectedOrg}" — confirm the right organization on the device page`);
128
+ return {
129
+ credentials,
130
+ me,
131
+ membership
132
+ };
133
+ }
134
+ //#endregion
135
+ export { loginWithDevice as t };
@@ -0,0 +1,202 @@
1
+ import { ContractProcedure, Meta, Schema } from "@orpc/contract";
2
+ import { z } from "zod";
3
+ //#region src/hitch/email.d.ts
4
+ type EmailTags = Record<string, string>;
5
+ type CreateEmailPixelInput = {
6
+ tags?: EmailTags;
7
+ };
8
+ type CreateEmailPixelOutput = {
9
+ id: string;
10
+ url: string;
11
+ };
12
+ type GetEmailTrackerInput = {
13
+ id: string;
14
+ };
15
+ type MarkEmailTrackerSentInput = {
16
+ id: string;
17
+ sentAt?: string;
18
+ };
19
+ type EmailTracker = {
20
+ id: string;
21
+ url: string;
22
+ tags: EmailTags;
23
+ createdAt: string;
24
+ sentAt: string | null;
25
+ firstHitAt: string | null;
26
+ lastHitAt: string | null;
27
+ };
28
+ type ListEmailTrackersInput = {
29
+ filter?: EmailTags;
30
+ sentAt?: {
31
+ $gte?: string;
32
+ $lt?: string;
33
+ };
34
+ cursor?: string;
35
+ limit?: number;
36
+ };
37
+ type ListEmailTrackersOutput = {
38
+ trackers: EmailTracker[];
39
+ nextCursor: string | null;
40
+ };
41
+ type EmailContract = {
42
+ mailboxes: {
43
+ list: ContractProcedure<Schema<void, void>, Schema<HitchEmailMailboxesOutput, HitchEmailMailboxesOutput>, Record<never, never>, Meta>;
44
+ };
45
+ threads: {
46
+ list: ContractProcedure<Schema<ListHitchEmailThreadsInput, ListHitchEmailThreadsInput>, Schema<HitchEmailThreadsOutput, HitchEmailThreadsOutput>, Record<never, never>, Meta>;
47
+ get: ContractProcedure<Schema<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailThread, HitchEmailThread>, Record<never, never>, Meta>;
48
+ };
49
+ messages: {
50
+ /** Newest first. Pass threadId to page through one thread. */
51
+ list: ContractProcedure<Schema<ListHitchEmailMessagesInput, ListHitchEmailMessagesInput>, Schema<HitchEmailMessagesOutput, HitchEmailMessagesOutput>, Record<never, never>, Meta>;
52
+ get: ContractProcedure<Schema<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailMessage, HitchEmailMessage>, Record<never, never>, Meta>;
53
+ send: ContractProcedure<Schema<SendHitchEmailInput, SendHitchEmailInput>, Schema<HitchEmailMessage, HitchEmailMessage>, Record<never, never>, Meta>;
54
+ raw: ContractProcedure<Schema<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailRawOutput, HitchEmailRawOutput>, Record<never, never>, Meta>;
55
+ };
56
+ attachments: {
57
+ get: ContractProcedure<Schema<HitchEmailIdInput, HitchEmailIdInput>, Schema<HitchEmailAttachmentOutput, HitchEmailAttachmentOutput>, Record<never, never>, Meta>;
58
+ };
59
+ tracking: {
60
+ createPixel: ContractProcedure<Schema<CreateEmailPixelInput | undefined, CreateEmailPixelInput | undefined>, Schema<CreateEmailPixelOutput, CreateEmailPixelOutput>, Record<never, never>, Meta>;
61
+ markSent: ContractProcedure<Schema<MarkEmailTrackerSentInput, MarkEmailTrackerSentInput>, Schema<EmailTracker, EmailTracker>, Record<never, never>, Meta>;
62
+ get: ContractProcedure<Schema<GetEmailTrackerInput, GetEmailTrackerInput>, Schema<EmailTracker, EmailTracker>, Record<never, never>, Meta>;
63
+ list: ContractProcedure<Schema<ListEmailTrackersInput | undefined, ListEmailTrackersInput | undefined>, Schema<ListEmailTrackersOutput, ListEmailTrackersOutput>, Record<never, never>, Meta>;
64
+ };
65
+ };
66
+ declare function emailContract(appletCode: string): EmailContract;
67
+ type HitchEmailAddress = {
68
+ address: string;
69
+ name: string | null;
70
+ };
71
+ type HitchMailbox = {
72
+ id: string;
73
+ address: string;
74
+ label: string;
75
+ enabled: boolean;
76
+ receive: boolean;
77
+ canRead: boolean;
78
+ canSend: boolean;
79
+ };
80
+ type HitchEmailAttachment = {
81
+ id: string;
82
+ filename: string;
83
+ contentType: string;
84
+ sizeBytes: number;
85
+ contentId: string | null;
86
+ inline: boolean;
87
+ };
88
+ type HitchEmailMessage = {
89
+ id: string;
90
+ mailboxId: string;
91
+ threadId: string;
92
+ direction: "inbound" | "outbound";
93
+ status: "received" | "unknown" | "sent" | "failed";
94
+ messageId: string | null;
95
+ inReplyTo: string | null;
96
+ references: string[];
97
+ from: HitchEmailAddress;
98
+ to: HitchEmailAddress[];
99
+ cc: HitchEmailAddress[];
100
+ bcc: HitchEmailAddress[];
101
+ replyTo: HitchEmailAddress[];
102
+ subject: string;
103
+ text: string | null;
104
+ html: string | null;
105
+ sentAt: string | null;
106
+ automated: string | null;
107
+ authentication: {
108
+ spf: string | null;
109
+ dkim: string | null;
110
+ dmarc: string | null;
111
+ } | null;
112
+ parseError: string | null;
113
+ attachments: HitchEmailAttachment[];
114
+ userId: string | null;
115
+ appletId: string | null;
116
+ requestId: string | null;
117
+ errorDetail: string | null;
118
+ createdAt: string;
119
+ };
120
+ type HitchEmailThread = {
121
+ id: string;
122
+ mailboxId: string;
123
+ subject: string;
124
+ messageCount: number;
125
+ lastMessageAt: string;
126
+ createdAt: string;
127
+ };
128
+ type ListHitchEmailThreadsInput = {
129
+ mailboxId?: string;
130
+ cursor?: string;
131
+ limit?: number;
132
+ };
133
+ type ListHitchEmailMessagesInput = {
134
+ mailboxId?: string;
135
+ address?: string;
136
+ threadId?: string;
137
+ direction?: "inbound" | "outbound";
138
+ since?: string;
139
+ until?: string;
140
+ cursor?: string;
141
+ limit?: number;
142
+ };
143
+ type SendHitchEmailInput = {
144
+ mailboxId: string;
145
+ to?: string[];
146
+ cc?: string[];
147
+ bcc?: string[];
148
+ subject?: string;
149
+ text?: string;
150
+ html?: string;
151
+ replyToMessageId?: string;
152
+ attachmentFileIds?: string[];
153
+ requestId?: string;
154
+ };
155
+ type HitchEmailIdInput = {
156
+ id: string;
157
+ };
158
+ type HitchEmailMailboxesOutput = {
159
+ data: HitchMailbox[];
160
+ };
161
+ type HitchEmailThreadsOutput = {
162
+ data: HitchEmailThread[];
163
+ nextCursor: string | null;
164
+ };
165
+ type HitchEmailMessagesOutput = {
166
+ data: HitchEmailMessage[];
167
+ nextCursor: string | null;
168
+ };
169
+ type HitchEmailRawOutput = {
170
+ url: string;
171
+ };
172
+ type HitchEmailAttachmentOutput = {
173
+ url: string;
174
+ filename: string;
175
+ contentType: string;
176
+ sizeBytes: number;
177
+ };
178
+ //#endregion
179
+ //#region src/server/telephony-protocol.d.ts
180
+ /** Handle events at least once and without order. Use eventId for idempotency.
181
+ * Read the message with hitch.telephony.messages.get({ id: messageId }). */
182
+ type TelephonyMessageReceivedEvent = {
183
+ eventId: string;
184
+ type: "message.received";
185
+ messageId: string;
186
+ numberId: string;
187
+ occurredAt: string;
188
+ };
189
+ //#endregion
190
+ //#region src/server/email-protocol.d.ts
191
+ /** Handle events at least once and without order. Use eventId for idempotency.
192
+ * Read the message with hitch.email.messages.get({ id: messageId }). */
193
+ type EmailMessageReceivedEvent = {
194
+ eventId: string;
195
+ type: "message.received";
196
+ messageId: string;
197
+ mailboxId: string;
198
+ threadId: string;
199
+ occurredAt: string;
200
+ };
201
+ //#endregion
202
+ export { EmailTracker as a, HitchEmailMessage as c, ListEmailTrackersInput as d, ListEmailTrackersOutput as f, emailContract as g, SendHitchEmailInput as h, EmailContract as i, HitchEmailThread as l, ListHitchEmailThreadsInput as m, TelephonyMessageReceivedEvent as n, HitchEmailAddress as o, ListHitchEmailMessagesInput as p, CreateEmailPixelInput as r, HitchEmailAttachment as s, EmailMessageReceivedEvent as t, HitchMailbox as u };