@hitch42/applet 0.1.1-beta.1 → 0.1.1-beta.10
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.
- package/dist/_internal/client.js +120 -11
- package/dist/_internal/log-context.d.ts +34 -0
- package/dist/_internal/log-context.js +2 -0
- package/dist/_internal/server.d.ts +14 -1
- package/dist/_internal/server.js +122 -118
- package/dist/applet.js +53 -29
- package/dist/build-Bh_S5BUv.js +2 -0
- package/dist/{build-Rk3xDZV7.js → build-CEfFoIZZ.js} +30 -14
- package/dist/ci-BKw14X2h.js +69 -0
- package/dist/client.d.ts +3 -3
- package/dist/{contract-DMrpbaLJ.d.ts → contract-CsUpTBe0.d.ts} +1 -1
- package/dist/{deploy-D3BGDqgC.js → deploy-wGYjwXrx.js} +249 -35
- package/dist/email-DBTVhNB_.js +62 -0
- package/dist/{generate-CH0VQmUi.js → generate-BEIYs17x.js} +79 -25
- package/dist/generate-Dox-OYt6.js +2 -0
- package/dist/headers-DkNr9MLJ.js +17 -0
- package/dist/index.d.ts +123 -11
- package/dist/index.js +142 -26
- package/dist/{init-BS1Y-eNL.js → init-6oGPM46R.js} +17 -18
- package/dist/load-config-xEdTXs0y.js +27 -0
- package/dist/log-context-zu8U9Sjm.js +73 -0
- package/dist/login-CUx3TmFQ.js +12 -0
- package/dist/{logs-m00pzr_O.js → logs-DSjuEN0Q.js} +20 -22
- package/dist/{manifest-BQCAxATS.d.ts → manifest-C6_F4bL8.d.ts} +9 -0
- package/dist/{manifest-DyoJ1MIL.js → manifest-CJSL9GuC.js} +25 -3
- package/dist/me-BW7Paary.js +32 -0
- package/dist/{project-CxN-Dtc7.js → project-BRZGd6xq.js} +227 -34
- package/dist/prompt-ChS-grYO.js +29 -0
- package/dist/query-cache-CXmAyLv3.js +82 -0
- package/dist/react.d.ts +3 -2
- package/dist/react.js +98 -80
- package/dist/schedules-C8_Svr4h.js +42 -0
- package/dist/server.d.ts +9 -4
- package/dist/server.js +29 -8
- package/dist/telephony-protocol-D-nf3Gca.d.ts +76 -0
- package/dist/telephony.d.ts +97 -0
- package/dist/telephony.js +726 -0
- package/dist/{upload-YbRKEqR6.d.ts → upload-DKZzz5kW.d.ts} +6 -6
- package/dist/{variables-CP7Ce3Np.js → variables-DT5RyHdH.js} +14 -39
- package/dist/vite.d.ts +3 -60
- package/dist/vite.js +503 -34
- package/dist/workflow-engine-BOTzURKM.js +111 -0
- package/dist/{auth-DaVK0k5R.js → workspace-D0dnnlxL.js} +75 -40
- package/package.json +19 -6
- package/scaffold/.agents/skills/hitch-applets/SKILL.md +60 -15
- package/scaffold/.agents/skills/hitch-applets/references/email-tracking.md +49 -0
- package/scaffold/.agents/skills/hitch-applets/references/files.md +3 -3
- package/scaffold/.agents/skills/hitch-applets/references/manifest.md +29 -2
- package/scaffold/.agents/skills/hitch-applets/references/markdown.md +2 -0
- package/scaffold/.agents/skills/hitch-applets/references/performance.md +74 -0
- package/scaffold/.agents/skills/hitch-applets/references/records.md +32 -8
- package/scaffold/.agents/skills/hitch-applets/references/schedules.md +7 -2
- package/scaffold/.agents/skills/hitch-applets/references/server.md +0 -3
- package/scaffold/.agents/skills/hitch-applets/references/workflows.md +11 -3
- package/scaffold/.agents/skills/hitch-cli/SKILL.md +129 -0
- package/scaffold/.agents/skills/hitch-data/SKILL.md +52 -0
- package/scaffold/.agents/skills/hitch-data/references/attributes.md +127 -0
- package/scaffold/.agents/skills/hitch-data/references/limits.md +64 -0
- package/scaffold/.agents/skills/hitch-theory/SKILL.md +151 -0
- package/scaffold/.agents/skills/react-best-practices/SKILL.md +127 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-effect-event-deps.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-defer-await.md +82 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-dependencies.md +48 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-parallel.md +24 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-analyzable-paths.md +42 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-barrel-imports.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-conditional.md +35 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-defer-third-party.md +46 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-dynamic-imports.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-preload.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-event-listeners.md +78 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-function-results.md +58 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-storage.md +56 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-flatmap-filter.md +51 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-length-check-first.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-request-idle-callback.md +104 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-resource-hints.md +81 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-script-defer-async.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-usetransition-loading.md +43 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-no-inline-components.md +75 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/scaffold/.agents/skills/tanstack-query/SKILL.md +136 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/automatic-invalidation-after-mutations.md +124 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/broadcast-realtime-and-multi-tab-synchronization.md +150 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/compose-query-with-tanstack-router-and-start.md +248 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/enforce-query-best-practices-with-eslint.md +167 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/persist-offline-and-restore-caches.md +181 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/query-data-and-forms.md +156 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/build-query-abstractions.md +130 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/cancel-queries-and-consume-abort-signals.md +176 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/concurrent-optimistic-updates.md +135 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/coordinate-query-execution.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/design-query-keys-and-options.md +182 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/fetch-and-observe-queries.md +193 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/implement-optimistic-updates-and-cache-writes.md +168 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/paginate-and-build-infinite-queries.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/seed-placeholder-select-and-transform-data.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/selectors-and-derived-state.md +145 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/tune-defaults-freshness-retries-and-refetching.md +172 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/understand-query-internals-and-observers.md +104 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/write-mutations-and-invalidate-related-queries.md +183 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/debug-with-devtools.md +169 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/handle-status-and-errors.md +119 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/shape-data-and-render-efficiently.md +184 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/use-framework-adapter-reactivity.md +185 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/use-suspense-and-error-boundaries.md +208 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/migrate-major-versions-and-codemods.md +169 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/prefetch-and-remove-request-waterfalls.md +228 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/setup-query-client-and-providers.md +161 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/ssr-hydration-and-streaming.md +209 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/test-query-code.md +160 -0
- package/scaffold/.agents/skills/tanstack-router/SKILL.md +134 -0
- package/scaffold/.agents/skills/tanstack-router/references/compositions/router-query.md +412 -0
- package/scaffold/.agents/skills/tanstack-router/references/react-router.md +495 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/auth-and-guards.md +495 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/code-splitting.md +318 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/data-loading.md +490 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/index.md +158 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/navigation.md +433 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/not-found-and-errors.md +436 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/path-params.md +383 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/search-params.md +343 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/ssr.md +462 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/type-safety.md +493 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-plugin.md +250 -0
- package/scaffold/.agents/skills/tanstack-router/references/virtual-file-routes.md +215 -0
- package/scaffold/.agents/skills/web-design-guidelines/SKILL.md +184 -0
- package/scaffold/.github/workflows/hitch.yml +15 -0
- package/scaffold/AGENTS.md +2 -2
- package/scaffold/applet/src/client/components/ui/alert.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/button.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/checkbox.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/dialog.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/input-group.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/select.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/sheet.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/spinner.tsx +2 -1
- package/scaffold/applet/src/client/components/ui/tabs.tsx +1 -1
- package/scaffold/applet/src/client/lib/utils.ts +1 -6
- package/scaffold/applet/src/client/styles/globals.css +2 -0
- package/dist/build-CEku1lyb.js +0 -2
- package/dist/generate-6Nbt7uii.js +0 -2
- package/dist/load-config-BnxocLAQ.js +0 -56
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { r as prepareAppletProject } from "./project-
|
|
1
|
+
import { i as prepareAppletProjects, r as prepareAppletProject } from "./project-BRZGd6xq.js";
|
|
2
2
|
import { rm } from "node:fs/promises";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
+
import { createInterface } from "node:readline";
|
|
5
6
|
//#region src/build.ts
|
|
6
7
|
function isMissingFile(error) {
|
|
7
8
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
@@ -11,7 +12,8 @@ async function runPnpm(args, cwd) {
|
|
|
11
12
|
let finished = false;
|
|
12
13
|
const child = spawn("pnpm", args, {
|
|
13
14
|
cwd,
|
|
14
|
-
stdio: "inherit"
|
|
15
|
+
stdio: "inherit",
|
|
16
|
+
shell: process.platform === "win32"
|
|
15
17
|
});
|
|
16
18
|
child.once("error", (error) => {
|
|
17
19
|
finished = true;
|
|
@@ -28,14 +30,19 @@ async function runPnpm(args, cwd) {
|
|
|
28
30
|
});
|
|
29
31
|
});
|
|
30
32
|
}
|
|
31
|
-
async function buildApplet(
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
async function buildApplet(appletRoot, outDir = ".hitch/dist") {
|
|
34
|
+
await runPnpm(["install"], await prepareAppletProject(appletRoot));
|
|
35
|
+
await buildPreparedApplet(appletRoot, outDir);
|
|
36
|
+
}
|
|
37
|
+
async function prepareWorkspaceBuild(workspaceRoot, appletRoots) {
|
|
38
|
+
await prepareAppletProjects(workspaceRoot, appletRoots);
|
|
39
|
+
await runPnpm(["install"], workspaceRoot);
|
|
40
|
+
}
|
|
41
|
+
async function buildPreparedApplet(appletRoot, outDir = ".hitch/dist", logPrefix = "") {
|
|
34
42
|
await rm(resolve(appletRoot, ".hitch"), {
|
|
35
43
|
force: true,
|
|
36
44
|
recursive: true
|
|
37
45
|
});
|
|
38
|
-
await runPnpm(["install"], workspaceRoot);
|
|
39
46
|
await new Promise((resolveBuild, rejectBuild) => {
|
|
40
47
|
let finished = false;
|
|
41
48
|
const child = spawn("pnpm", [
|
|
@@ -46,12 +53,21 @@ async function buildApplet(changesetId, outDir = ".hitch/dist") {
|
|
|
46
53
|
outDir
|
|
47
54
|
], {
|
|
48
55
|
cwd: appletRoot,
|
|
49
|
-
stdio: "inherit"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
stdio: logPrefix === "" ? "inherit" : [
|
|
57
|
+
"ignore",
|
|
58
|
+
"pipe",
|
|
59
|
+
"pipe"
|
|
60
|
+
],
|
|
61
|
+
shell: process.platform === "win32"
|
|
54
62
|
});
|
|
63
|
+
if (child.stdout) createInterface({
|
|
64
|
+
input: child.stdout,
|
|
65
|
+
crlfDelay: Infinity
|
|
66
|
+
}).on("line", (line) => console.log(`${logPrefix}${line}`));
|
|
67
|
+
if (child.stderr) createInterface({
|
|
68
|
+
input: child.stderr,
|
|
69
|
+
crlfDelay: Infinity
|
|
70
|
+
}).on("line", (line) => console.error(`${logPrefix}${line}`));
|
|
55
71
|
child.once("error", (error) => {
|
|
56
72
|
finished = true;
|
|
57
73
|
rejectBuild(isMissingFile(error) ? /* @__PURE__ */ new Error("pnpm was not found. Install pnpm, then run applet build again.") : error);
|
|
@@ -67,8 +83,8 @@ async function buildApplet(changesetId, outDir = ".hitch/dist") {
|
|
|
67
83
|
});
|
|
68
84
|
});
|
|
69
85
|
}
|
|
70
|
-
async function runBuild(
|
|
71
|
-
await buildApplet(
|
|
86
|
+
async function runBuild() {
|
|
87
|
+
await buildApplet(process.cwd());
|
|
72
88
|
}
|
|
73
89
|
//#endregion
|
|
74
|
-
export { runBuild as n, buildApplet as t };
|
|
90
|
+
export { runBuild as i, buildPreparedApplet as n, prepareWorkspaceBuild as r, buildApplet as t };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { f as resolveInstanceUrl } from "./workspace-D0dnnlxL.js";
|
|
2
|
+
//#region src/ci.ts
|
|
3
|
+
function githubActionsContext() {
|
|
4
|
+
const env = process.env;
|
|
5
|
+
if (env.GITHUB_ACTIONS !== "true" || env.HITCH_API_KEY) return void 0;
|
|
6
|
+
const requestUrl = env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
|
7
|
+
const requestToken = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
|
8
|
+
if (!requestUrl || !requestToken) throw new Error("GitHub Actions did not provide an OIDC token. Grant the job the id-token: write permission, or set HITCH_API_KEY.");
|
|
9
|
+
return {
|
|
10
|
+
requestUrl,
|
|
11
|
+
requestToken
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function hitchResponseError(response, summary) {
|
|
15
|
+
let details = "";
|
|
16
|
+
try {
|
|
17
|
+
const body = await response.json();
|
|
18
|
+
if (body !== null && typeof body === "object") details = ["code" in body && typeof body.code === "string" ? body.code : void 0, "message" in body && typeof body.message === "string" ? body.message : void 0].filter((value) => value !== void 0).join(": ");
|
|
19
|
+
} catch {
|
|
20
|
+
details = "";
|
|
21
|
+
}
|
|
22
|
+
return /* @__PURE__ */ new Error(`${summary} (${response.status})${details ? `: ${details}` : ""}.`);
|
|
23
|
+
}
|
|
24
|
+
async function githubActionsToken(context, instanceUrl, fetcher) {
|
|
25
|
+
const url = new URL(context.requestUrl);
|
|
26
|
+
url.searchParams.set("audience", new URL(instanceUrl).origin);
|
|
27
|
+
const response = await fetcher(url, { headers: { Authorization: `bearer ${context.requestToken}` } });
|
|
28
|
+
if (!response.ok) throw new Error(`GitHub did not issue an OIDC token (${response.status}).`);
|
|
29
|
+
const body = await response.json();
|
|
30
|
+
if (body === null || typeof body !== "object" || !("value" in body)) throw new Error("GitHub returned an OIDC token response without a value.");
|
|
31
|
+
if (typeof body.value !== "string") throw new Error("GitHub returned an OIDC token response without a value.");
|
|
32
|
+
return body.value;
|
|
33
|
+
}
|
|
34
|
+
async function fetchWithGitHubActions(context, request) {
|
|
35
|
+
const instanceUrl = await resolveInstanceUrl();
|
|
36
|
+
return request(instanceUrl, await githubActionsToken(context, instanceUrl, globalThis.fetch));
|
|
37
|
+
}
|
|
38
|
+
async function loadGitHubActionsBuildInputs(context, requiresChangeset) {
|
|
39
|
+
const fetcher = globalThis.fetch;
|
|
40
|
+
const query = requiresChangeset === void 0 ? "" : `?changeset_id=${encodeURIComponent(requiresChangeset)}`;
|
|
41
|
+
const response = await fetchWithGitHubActions(context, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/ci/v1/build-inputs${query}`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
44
|
+
}));
|
|
45
|
+
if (!response.ok) throw await hitchResponseError(response, "Failed to load the CI build inputs");
|
|
46
|
+
const body = await response.json();
|
|
47
|
+
if (body === null || typeof body !== "object" || !("openapi" in body) || !("theme" in body) || typeof body.theme !== "string") throw new Error("The CI build inputs must contain an openapi document and a theme string.");
|
|
48
|
+
return {
|
|
49
|
+
openapi: body.openapi,
|
|
50
|
+
theme: body.theme
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async function loadGitHubActionsSources(context) {
|
|
54
|
+
const fetcher = globalThis.fetch;
|
|
55
|
+
const response = await fetchWithGitHubActions(context, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/ci/v1/applets`, { headers: { Authorization: `Bearer ${accessToken}` } }));
|
|
56
|
+
if (!response.ok) throw await hitchResponseError(response, "Failed to load the CI applets");
|
|
57
|
+
const body = await response.json();
|
|
58
|
+
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.");
|
|
59
|
+
return body.data.map((source) => {
|
|
60
|
+
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.");
|
|
61
|
+
return {
|
|
62
|
+
code: source.code,
|
|
63
|
+
sourceDirectory: source.source_directory,
|
|
64
|
+
sourceHash: source.source_hash
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { loadGitHubActionsSources as a, loadGitHubActionsBuildInputs as i, githubActionsContext as n, hitchResponseError as r, fetchWithGitHubActions as t };
|
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { f as RegisteredContract, m as RegisteredRouter, p as RegisteredManifest } from "./manifest-
|
|
2
|
-
import { t as NarrowContract } from "./contract-
|
|
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
|
-
import { o as WithFilesUpload } from "./upload-
|
|
4
|
+
import { o as WithFilesUpload } from "./upload-DKZzz5kW.js";
|
|
5
5
|
import { RouterClient } from "@orpc/server";
|
|
6
6
|
import { ContractRouterClient } from "@orpc/contract";
|
|
7
7
|
import { NestedClient } from "@orpc/client";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as AppletManifest } from "./manifest-
|
|
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,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
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-CEfFoIZZ.js";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
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";
|
|
7
10
|
import { promisify } from "node:util";
|
|
8
11
|
import { createGzip } from "node:zlib";
|
|
9
12
|
//#region \0rolldown/runtime.js
|
|
@@ -2305,12 +2308,119 @@ var require_pack = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
2305
2308
|
}
|
|
2306
2309
|
}));
|
|
2307
2310
|
//#endregion
|
|
2308
|
-
//#region src/
|
|
2311
|
+
//#region src/source-hash.ts
|
|
2309
2312
|
var import_tar_stream = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
2310
2313
|
exports.extract = require_extract();
|
|
2311
2314
|
exports.pack = require_pack();
|
|
2312
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
|
|
2313
2417
|
const execFileAsync = promisify(execFile);
|
|
2418
|
+
var WorkspaceDeployError = class extends Error {
|
|
2419
|
+
constructor(failedApplets) {
|
|
2420
|
+
super(`Failed to deploy: ${failedApplets.join(", ")}. See the applet logs above.`);
|
|
2421
|
+
this.name = "WorkspaceDeployError";
|
|
2422
|
+
}
|
|
2423
|
+
};
|
|
2314
2424
|
function isErrno(error, code) {
|
|
2315
2425
|
return error instanceof Error && "code" in error && error.code === code;
|
|
2316
2426
|
}
|
|
@@ -2355,14 +2465,14 @@ async function createBundle(distDir) {
|
|
|
2355
2465
|
body.set(bundle);
|
|
2356
2466
|
return body;
|
|
2357
2467
|
}
|
|
2358
|
-
async function readGitInfo() {
|
|
2359
|
-
const env =
|
|
2468
|
+
async function readGitInfo(appletRoot) {
|
|
2469
|
+
const env = gitEnvironment();
|
|
2360
2470
|
try {
|
|
2361
2471
|
const [{ stdout: status }, { stdout: sha }] = await Promise.all([execFileAsync("git", ["status", "--porcelain"], {
|
|
2362
|
-
cwd:
|
|
2472
|
+
cwd: appletRoot,
|
|
2363
2473
|
env
|
|
2364
2474
|
}), execFileAsync("git", ["rev-parse", "HEAD"], {
|
|
2365
|
-
cwd:
|
|
2475
|
+
cwd: appletRoot,
|
|
2366
2476
|
env
|
|
2367
2477
|
})]);
|
|
2368
2478
|
return {
|
|
@@ -2373,44 +2483,148 @@ async function readGitInfo() {
|
|
|
2373
2483
|
return { gitDirty: false };
|
|
2374
2484
|
}
|
|
2375
2485
|
}
|
|
2376
|
-
async function
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
return /* @__PURE__ */ new Error(`Deploy failed (${response.status})${details ? `: ${details}` : ""}.`);
|
|
2486
|
+
async function repositoryDirectory(appletRoot) {
|
|
2487
|
+
const { stdout } = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
|
|
2488
|
+
cwd: appletRoot,
|
|
2489
|
+
env: gitEnvironment()
|
|
2490
|
+
});
|
|
2491
|
+
const directory = relative(stdout.trim(), appletRoot).split(sep).join("/") || ".";
|
|
2492
|
+
if (directory === ".." || directory.startsWith("../")) throw new Error(`${appletRoot} is outside its git repository ${stdout.trim()}.`);
|
|
2493
|
+
return directory;
|
|
2385
2494
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2495
|
+
function releaseForm(manifest, bundle) {
|
|
2496
|
+
const body = new FormData();
|
|
2497
|
+
body.set("manifest", manifest.raw);
|
|
2498
|
+
body.set("bundle", new File([bundle], "bundle.tar.gz", { type: "application/gzip" }));
|
|
2499
|
+
return body;
|
|
2500
|
+
}
|
|
2501
|
+
async function deployWithOrgAuth(appletRoot, distDir, manifest, sourceHash) {
|
|
2502
|
+
const fetcher = globalThis.fetch;
|
|
2503
|
+
const [bundle, git] = await Promise.all([createBundle(distDir), readGitInfo(appletRoot)]);
|
|
2504
|
+
return fetchWithOrgAuth(manifest.org, (instanceUrl, accessToken) => {
|
|
2505
|
+
const body = releaseForm(manifest, bundle);
|
|
2396
2506
|
body.set("gitDirty", String(git.gitDirty));
|
|
2397
2507
|
if (git.gitSha !== void 0) body.set("gitSha", git.gitSha);
|
|
2398
|
-
if (
|
|
2508
|
+
if (sourceHash !== void 0) body.set("sourceHash", sourceHash);
|
|
2399
2509
|
return fetcher(`${instanceUrl}/api/v1/applets/${manifest.code}/releases`, {
|
|
2400
2510
|
method: "POST",
|
|
2401
2511
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
2402
2512
|
body
|
|
2403
2513
|
});
|
|
2404
2514
|
});
|
|
2405
|
-
|
|
2515
|
+
}
|
|
2516
|
+
async function deployWithGitHubActions(context, appletRoot, distDir, manifest, sourceHash) {
|
|
2517
|
+
const fetcher = globalThis.fetch;
|
|
2518
|
+
const [bundle, sourceDirectory] = await Promise.all([createBundle(distDir), repositoryDirectory(appletRoot)]);
|
|
2519
|
+
return fetchWithGitHubActions(context, (instanceUrl, accessToken) => {
|
|
2520
|
+
const body = releaseForm(manifest, bundle);
|
|
2521
|
+
body.set("source_directory", sourceDirectory);
|
|
2522
|
+
if (sourceHash !== void 0) body.set("source_hash", sourceHash);
|
|
2523
|
+
return fetcher(`${instanceUrl}/api/ci/v1/applets/${manifest.code}/releases`, {
|
|
2524
|
+
method: "POST",
|
|
2525
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
2526
|
+
body
|
|
2527
|
+
});
|
|
2528
|
+
});
|
|
2529
|
+
}
|
|
2530
|
+
async function deployApplet(appletRoot, options, logPrefix = "", sourceHash) {
|
|
2531
|
+
const github = githubActionsContext();
|
|
2532
|
+
sourceHash ??= (await computeSourceHash([appletRoot], github !== void 0)).get(appletRoot);
|
|
2533
|
+
if (options.dist === void 0) await buildApplet(appletRoot);
|
|
2534
|
+
const distDir = resolve(appletRoot, options.dist ?? ".hitch/dist");
|
|
2535
|
+
const manifest = await readManifest(distDir);
|
|
2536
|
+
const response = github === void 0 ? await deployWithOrgAuth(appletRoot, distDir, manifest, sourceHash) : await deployWithGitHubActions(github, appletRoot, distDir, manifest, sourceHash);
|
|
2537
|
+
if (!response.ok) throw await hitchResponseError(response, "Deploy failed");
|
|
2406
2538
|
const result = await response.json();
|
|
2407
|
-
console.log(
|
|
2539
|
+
console.log(`${logPrefix}Deployed release ${result.data.id} (${result.promoted ? "promoted" : "not promoted"}).`);
|
|
2540
|
+
if (result.changeset_id !== void 0) console.log(`${logPrefix}The release goes live when changeset ${result.changeset_id} applies.`);
|
|
2408
2541
|
if (result.warnings?.length) {
|
|
2409
|
-
for (const warning of result.warnings) console.warn(
|
|
2410
|
-
console.warn(
|
|
2542
|
+
for (const warning of result.warnings) console.warn(`${logPrefix}Warning: ${warning.message}`);
|
|
2543
|
+
console.warn(`${logPrefix}Changeset ${result.changeset_id} cannot apply until the applet and the schema agree.`);
|
|
2411
2544
|
}
|
|
2412
|
-
if (result.unset_variables?.length) console.warn(
|
|
2545
|
+
if (result.unset_variables?.length) console.warn(`${logPrefix}Warning: declared variables not set: ${result.unset_variables.join(", ")}. Set them with applet variables set.`);
|
|
2413
2546
|
return result;
|
|
2414
2547
|
}
|
|
2548
|
+
async function workspaceAppletRoots(workspaceRoot) {
|
|
2549
|
+
const appletsDir = resolve(workspaceRoot, "applets");
|
|
2550
|
+
const roots = (await readdir(appletsDir, { withFileTypes: true }).catch((error) => {
|
|
2551
|
+
if (isErrno(error, "ENOENT")) return [];
|
|
2552
|
+
throw error;
|
|
2553
|
+
})).filter((entry) => entry.isDirectory()).map((entry) => resolve(appletsDir, entry.name)).filter((root) => existsSync(resolve(root, "applet.manifest.ts"))).sort();
|
|
2554
|
+
if (roots.length === 0) throw new Error(`No applets were found under ${appletsDir}.`);
|
|
2555
|
+
return roots;
|
|
2556
|
+
}
|
|
2557
|
+
async function computeSourceHash(appletRoots, required) {
|
|
2558
|
+
try {
|
|
2559
|
+
return await sourceHashes(appletRoots);
|
|
2560
|
+
} catch (error) {
|
|
2561
|
+
if (!required && error instanceof SourceHashUnavailableError) return /* @__PURE__ */ new Map();
|
|
2562
|
+
throw error;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
async function ciDeployDecisions(github, appletRoots, hashes) {
|
|
2566
|
+
const [sources, directories] = await Promise.all([loadGitHubActionsSources(github), 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, {
|
|
2571
|
+
deploy: true,
|
|
2572
|
+
reason: "no release with a source hash to compare"
|
|
2573
|
+
}];
|
|
2574
|
+
if (sourceHash !== hashes.get(appletRoot)) return [appletRoot, {
|
|
2575
|
+
deploy: true,
|
|
2576
|
+
reason: "files changed since the current release"
|
|
2577
|
+
}];
|
|
2578
|
+
return [appletRoot, {
|
|
2579
|
+
deploy: false,
|
|
2580
|
+
reason: "no changes since the current release"
|
|
2581
|
+
}];
|
|
2582
|
+
}));
|
|
2583
|
+
}
|
|
2584
|
+
async function runDeploy(options) {
|
|
2585
|
+
const root = process.cwd();
|
|
2586
|
+
const github = githubActionsContext();
|
|
2587
|
+
if (existsSync(resolve(root, "applet.manifest.ts"))) {
|
|
2588
|
+
await deployApplet(root, options);
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
if (readWorkspaceConfig(root) === void 0) throw new Error("Run applet deploy in an applet folder or in the workspace root.");
|
|
2592
|
+
const appletRoots = await workspaceAppletRoots(root);
|
|
2593
|
+
const hashes = await computeSourceHash(appletRoots, github !== void 0);
|
|
2594
|
+
const decisions = github === void 0 ? void 0 : await ciDeployDecisions(github, appletRoots, hashes);
|
|
2595
|
+
const selectedRoots = appletRoots.filter((appletRoot) => {
|
|
2596
|
+
const name = relative(root, appletRoot);
|
|
2597
|
+
const decision = decisions?.get(appletRoot);
|
|
2598
|
+
if (decision === void 0) console.log(`Deploying ${name}...`);
|
|
2599
|
+
else if (decision.deploy) console.log(`Deploying ${name}: ${decision.reason}.`);
|
|
2600
|
+
else {
|
|
2601
|
+
console.log(`Skipping ${name}: ${decision.reason}.`);
|
|
2602
|
+
return false;
|
|
2603
|
+
}
|
|
2604
|
+
return true;
|
|
2605
|
+
});
|
|
2606
|
+
if (selectedRoots.length === 0) return;
|
|
2607
|
+
if (options.dist === void 0) await prepareWorkspaceBuild(root, appletRoots);
|
|
2608
|
+
const interactive = github === void 0 && process.stdin.isTTY === true;
|
|
2609
|
+
const deploy = async (appletRoot) => {
|
|
2610
|
+
const logPrefix = `[${relative(root, appletRoot)}] `;
|
|
2611
|
+
if (options.dist === void 0) await buildPreparedApplet(appletRoot, ".hitch/dist", interactive ? "" : logPrefix);
|
|
2612
|
+
await deployApplet(appletRoot, {
|
|
2613
|
+
...options,
|
|
2614
|
+
dist: options.dist ?? ".hitch/dist"
|
|
2615
|
+
}, logPrefix, hashes.get(appletRoot));
|
|
2616
|
+
};
|
|
2617
|
+
if (interactive) {
|
|
2618
|
+
for (const appletRoot of selectedRoots) await deploy(appletRoot);
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2621
|
+
const failedApplets = (await Promise.allSettled(selectedRoots.map(deploy))).flatMap((result, index) => {
|
|
2622
|
+
if (result.status === "fulfilled") return [];
|
|
2623
|
+
const name = relative(root, selectedRoots[index]);
|
|
2624
|
+
console.error(`[${name}] ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`);
|
|
2625
|
+
return [name];
|
|
2626
|
+
});
|
|
2627
|
+
if (failedApplets.length > 0) throw new WorkspaceDeployError(failedApplets);
|
|
2628
|
+
}
|
|
2415
2629
|
//#endregion
|
|
2416
2630
|
export { runDeploy };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/hitch/email.ts
|
|
4
|
+
const emailTagKeySchema = z.string().regex(/^[A-Za-z][A-Za-z0-9_]{0,63}$/);
|
|
5
|
+
const emailTagsSchema = z.record(emailTagKeySchema, z.string().min(1).max(200)).refine((tags) => Object.keys(tags).length <= 10);
|
|
6
|
+
const createEmailPixelInputSchema = z.object({ tags: emailTagsSchema.optional() }).strict();
|
|
7
|
+
const createEmailPixelOutputSchema = z.object({
|
|
8
|
+
id: z.uuid(),
|
|
9
|
+
url: z.url()
|
|
10
|
+
});
|
|
11
|
+
const getEmailTrackerInputSchema = z.object({ id: z.uuid() });
|
|
12
|
+
const markEmailTrackerSentInputSchema = z.object({
|
|
13
|
+
id: z.uuid(),
|
|
14
|
+
sentAt: z.iso.datetime({ offset: true }).optional()
|
|
15
|
+
}).strict();
|
|
16
|
+
const markEmailTrackerSentBodySchema = z.object({ sentAt: z.iso.datetime({ offset: true }).optional() }).strict();
|
|
17
|
+
const emailTrackerSchema = z.object({
|
|
18
|
+
id: z.uuid(),
|
|
19
|
+
url: z.url(),
|
|
20
|
+
tags: emailTagsSchema,
|
|
21
|
+
createdAt: z.iso.datetime(),
|
|
22
|
+
sentAt: z.iso.datetime().nullable(),
|
|
23
|
+
firstHitAt: z.iso.datetime().nullable(),
|
|
24
|
+
lastHitAt: z.iso.datetime().nullable()
|
|
25
|
+
});
|
|
26
|
+
const listEmailTrackersInputSchema = z.object({
|
|
27
|
+
filter: emailTagsSchema.optional(),
|
|
28
|
+
sentAt: z.object({
|
|
29
|
+
$gte: z.iso.datetime({ offset: true }).optional(),
|
|
30
|
+
$lt: z.iso.datetime({ offset: true }).optional()
|
|
31
|
+
}).strict().optional(),
|
|
32
|
+
cursor: z.uuid().optional(),
|
|
33
|
+
limit: z.number().int().min(1).max(200).optional()
|
|
34
|
+
}).strict();
|
|
35
|
+
const listEmailTrackersOutputSchema = z.object({
|
|
36
|
+
trackers: z.array(emailTrackerSchema),
|
|
37
|
+
nextCursor: z.uuid().nullable()
|
|
38
|
+
});
|
|
39
|
+
function emailContract(appletCode) {
|
|
40
|
+
const path = `/v1/applets/${encodeURIComponent(appletCode)}/email/tracking`;
|
|
41
|
+
return { tracking: {
|
|
42
|
+
createPixel: oc.route({
|
|
43
|
+
method: "POST",
|
|
44
|
+
path: `${path}/pixels`,
|
|
45
|
+
successStatus: 201
|
|
46
|
+
}).input(createEmailPixelInputSchema.optional()).output(createEmailPixelOutputSchema),
|
|
47
|
+
markSent: oc.route({
|
|
48
|
+
method: "POST",
|
|
49
|
+
path: `${path}/{id}/sent`
|
|
50
|
+
}).input(markEmailTrackerSentInputSchema).output(emailTrackerSchema),
|
|
51
|
+
get: oc.route({
|
|
52
|
+
method: "GET",
|
|
53
|
+
path: `${path}/{id}`
|
|
54
|
+
}).input(getEmailTrackerInputSchema).output(emailTrackerSchema),
|
|
55
|
+
list: oc.route({
|
|
56
|
+
method: "POST",
|
|
57
|
+
path: `${path}/list`
|
|
58
|
+
}).input(listEmailTrackersInputSchema.optional()).output(listEmailTrackersOutputSchema)
|
|
59
|
+
} };
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { emailTagsSchema as a, listEmailTrackersInputSchema as c, markEmailTrackerSentInputSchema as d, emailTagKeySchema as i, listEmailTrackersOutputSchema as l, createEmailPixelOutputSchema as n, emailTrackerSchema as o, emailContract as r, getEmailTrackerInputSchema as s, createEmailPixelInputSchema as t, markEmailTrackerSentBodySchema as u };
|