@hitch42/applet 0.1.0-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/LICENSE +21 -0
- package/dist/_internal/client.d.ts +7 -0
- package/dist/_internal/client.js +169 -0
- package/dist/_internal/server.d.ts +92 -0
- package/dist/_internal/server.js +181 -0
- package/dist/applet.d.ts +1 -0
- package/dist/applet.js +184 -0
- package/dist/batch-Qa4B4-Yp.d.ts +30 -0
- package/dist/build-BlmLiKro.js +90 -0
- package/dist/build-CcT-wNN9.js +2 -0
- package/dist/ci-0Q2mUh53.js +68 -0
- package/dist/client.d.ts +48 -0
- package/dist/client.js +38 -0
- package/dist/contract-QUvEGiRI.d.ts +23 -0
- package/dist/deploy-BbL3GObV.js +2579 -0
- package/dist/email-DBTVhNB_.js +62 -0
- package/dist/generate-XB-72Fzj.js +537 -0
- package/dist/generate-wIN3IYqL.js +2 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.js +251 -0
- package/dist/init-DwsXRUk-.js +244 -0
- package/dist/lazy-client-x0DCI98S.js +64 -0
- package/dist/load-config-OKZU3UKn.js +27 -0
- package/dist/login-BBO74hPC.js +12 -0
- package/dist/logs-XvK6Zs5Y.js +183 -0
- package/dist/manifest-4ZAc6HUk.js +191 -0
- package/dist/manifest-I-9s8R36.d.ts +88 -0
- package/dist/me-BW7Paary.js +32 -0
- package/dist/project-B0qNXnFu.js +536 -0
- package/dist/prompt-ChS-grYO.js +29 -0
- package/dist/query-cache-CXmAyLv3.js +82 -0
- package/dist/react.d.ts +37 -0
- package/dist/react.js +515 -0
- package/dist/schedules-BkWZsbSs.js +42 -0
- package/dist/server.d.ts +46 -0
- package/dist/server.js +104 -0
- package/dist/telephony-protocol-D-nf3Gca.d.ts +76 -0
- package/dist/telephony.d.ts +77 -0
- package/dist/telephony.js +607 -0
- package/dist/upload-DKZzz5kW.d.ts +112 -0
- package/dist/upload-DRbVhuDm.js +114 -0
- package/dist/variables-0tjnAeut.js +108 -0
- package/dist/vite.d.ts +63 -0
- package/dist/vite.js +816 -0
- package/dist/workflow-CTo2kZF1.js +51 -0
- package/dist/workflow-DurM6Fwx.d.ts +28 -0
- package/dist/workflow-engine-MogejNfF.js +117 -0
- package/dist/workspace-DruAZPmV.js +390 -0
- package/package.json +112 -0
- package/scaffold/.agents/skills/hitch-applets/SKILL.md +163 -0
- package/scaffold/.agents/skills/hitch-applets/references/client.md +73 -0
- package/scaffold/.agents/skills/hitch-applets/references/email-tracking.md +49 -0
- package/scaffold/.agents/skills/hitch-applets/references/files.md +109 -0
- package/scaffold/.agents/skills/hitch-applets/references/manifest.md +198 -0
- package/scaffold/.agents/skills/hitch-applets/references/markdown.md +37 -0
- package/scaffold/.agents/skills/hitch-applets/references/performance.md +74 -0
- package/scaffold/.agents/skills/hitch-applets/references/records.md +176 -0
- package/scaffold/.agents/skills/hitch-applets/references/schedules.md +91 -0
- package/scaffold/.agents/skills/hitch-applets/references/server.md +95 -0
- package/scaffold/.agents/skills/hitch-applets/references/workflows.md +81 -0
- 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 +38 -0
- package/scaffold/applet/components.json +25 -0
- package/scaffold/applet/src/client/components/ui/alert.tsx +73 -0
- package/scaffold/applet/src/client/components/ui/avatar.tsx +100 -0
- package/scaffold/applet/src/client/components/ui/badge.tsx +55 -0
- package/scaffold/applet/src/client/components/ui/button.tsx +90 -0
- package/scaffold/applet/src/client/components/ui/card.tsx +85 -0
- package/scaffold/applet/src/client/components/ui/checkbox.tsx +35 -0
- package/scaffold/applet/src/client/components/ui/dialog.tsx +164 -0
- package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +235 -0
- package/scaffold/applet/src/client/components/ui/input-group.tsx +144 -0
- package/scaffold/applet/src/client/components/ui/input.tsx +22 -0
- package/scaffold/applet/src/client/components/ui/label.tsx +29 -0
- package/scaffold/applet/src/client/components/ui/popover.tsx +74 -0
- package/scaffold/applet/src/client/components/ui/select.tsx +243 -0
- package/scaffold/applet/src/client/components/ui/separator.tsx +25 -0
- package/scaffold/applet/src/client/components/ui/sheet.tsx +177 -0
- package/scaffold/applet/src/client/components/ui/skeleton.tsx +13 -0
- package/scaffold/applet/src/client/components/ui/spinner.tsx +17 -0
- package/scaffold/applet/src/client/components/ui/switch.tsx +41 -0
- package/scaffold/applet/src/client/components/ui/table.tsx +114 -0
- package/scaffold/applet/src/client/components/ui/tabs.tsx +78 -0
- package/scaffold/applet/src/client/components/ui/textarea.tsx +23 -0
- package/scaffold/applet/src/client/lib/utils.ts +1 -0
- package/scaffold/applet/src/client/styles/globals.css +136 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { isContractProcedure } from "@orpc/contract";
|
|
2
|
+
//#region src/hitch/batch.ts
|
|
3
|
+
const BATCH_VERBS = [
|
|
4
|
+
"create",
|
|
5
|
+
"update",
|
|
6
|
+
"delete",
|
|
7
|
+
"updateWhere"
|
|
8
|
+
];
|
|
9
|
+
function withBatchRecorder(target, contract) {
|
|
10
|
+
if (isContractProcedure(contract)) return target;
|
|
11
|
+
const batchContract = Reflect.get(contract, "batch");
|
|
12
|
+
if (!isContractProcedure(batchContract)) return target;
|
|
13
|
+
return new Proxy(target, { get(inner, property, receiver) {
|
|
14
|
+
const value = Reflect.get(inner, property, receiver);
|
|
15
|
+
if (property !== "batch") return value;
|
|
16
|
+
return (...args) => {
|
|
17
|
+
const [input, options] = args;
|
|
18
|
+
if (typeof input !== "function") return Reflect.apply(value, receiver, args);
|
|
19
|
+
return (async () => {
|
|
20
|
+
const requests = [];
|
|
21
|
+
let active = true;
|
|
22
|
+
const records = Reflect.get(contract, "records");
|
|
23
|
+
const tx = Object.fromEntries(Object.entries(records).map(([code, procedures]) => [code, Object.fromEntries(BATCH_VERBS.filter((verb) => typeof procedures === "object" && procedures !== null && isContractProcedure(Reflect.get(procedures, verb))).map((verb) => [verb, (procedureInput) => {
|
|
24
|
+
if (!active) throw new Error("The batch was already sent.");
|
|
25
|
+
const body = Reflect.get(procedureInput, "body");
|
|
26
|
+
const id = verb === "update" || verb === "delete" ? Reflect.get(Reflect.get(procedureInput, "params"), "id") : void 0;
|
|
27
|
+
requests.push({
|
|
28
|
+
method: verb === "create" || verb === "updateWhere" ? "POST" : verb === "update" ? "PATCH" : "DELETE",
|
|
29
|
+
path: verb === "create" ? `/v1/${code}` : verb === "updateWhere" ? `/v1/${code}/update` : `/v1/${code}/${String(id)}`,
|
|
30
|
+
...verb === "delete" ? {} : { body }
|
|
31
|
+
});
|
|
32
|
+
}]))]));
|
|
33
|
+
try {
|
|
34
|
+
await Reflect.apply(input, void 0, [tx]);
|
|
35
|
+
} finally {
|
|
36
|
+
active = false;
|
|
37
|
+
}
|
|
38
|
+
const recorderOptions = options;
|
|
39
|
+
return Reflect.apply(value, receiver, [{
|
|
40
|
+
body: {
|
|
41
|
+
requests,
|
|
42
|
+
...recorderOptions?.dryRun ? { dry_run: true } : {}
|
|
43
|
+
},
|
|
44
|
+
...recorderOptions?.idempotencyKey ? { headers: { "Idempotency-Key": recorderOptions.idempotencyKey } } : {}
|
|
45
|
+
}]);
|
|
46
|
+
})();
|
|
47
|
+
};
|
|
48
|
+
} });
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/lazy-client.ts
|
|
52
|
+
function createLazyClientProxy(build) {
|
|
53
|
+
let client;
|
|
54
|
+
const at = (path) => new Proxy(() => void 0, {
|
|
55
|
+
get: (_target, property) => at([...path, property]),
|
|
56
|
+
apply: (_target, _thisArg, args) => {
|
|
57
|
+
client ??= build();
|
|
58
|
+
return path.reduce((value, property) => value[property], client)(...args);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return at([]);
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { withBatchRecorder as n, createLazyClientProxy as t };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { r as appletSourceDefinitionSchema } from "./manifest-4ZAc6HUk.js";
|
|
2
|
+
import { t as resolveWorkspaceOrg } from "./workspace-DruAZPmV.js";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import { loadConfigFromFile } from "vite";
|
|
6
|
+
//#region src/typegen/load-config.ts
|
|
7
|
+
async function loadAppletSourceDefinition(root) {
|
|
8
|
+
const path = resolve(root, "applet.manifest.ts");
|
|
9
|
+
if (!existsSync(path)) throw new Error(`No applet manifest found at ${path}.`);
|
|
10
|
+
const loaded = await loadConfigFromFile({
|
|
11
|
+
command: "build",
|
|
12
|
+
mode: "production"
|
|
13
|
+
}, path, root);
|
|
14
|
+
if (loaded === null) throw new Error(`No applet manifest found at ${path}.`);
|
|
15
|
+
const parsed = appletSourceDefinitionSchema.safeParse(loaded.config);
|
|
16
|
+
if (!parsed.success) throw new Error(`Invalid applet manifest at ${loaded.path}: ${parsed.error.message}`);
|
|
17
|
+
return parsed.data;
|
|
18
|
+
}
|
|
19
|
+
async function loadAppletConfig(root) {
|
|
20
|
+
const { dependencies: _dependencies, devDependencies: _devDependencies, ...definition } = await loadAppletSourceDefinition(root);
|
|
21
|
+
return {
|
|
22
|
+
org: resolveWorkspaceOrg(root),
|
|
23
|
+
...definition
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { loadAppletSourceDefinition as n, loadAppletConfig as t };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { a as loginWithDevice, f as resolveInstanceUrl, o as AuthenticationError, r as findWorkspaceConfig } from "./workspace-DruAZPmV.js";
|
|
2
|
+
//#region src/login.ts
|
|
3
|
+
async function runLogin(options) {
|
|
4
|
+
if (process.env.HITCH_API_KEY !== void 0) throw new AuthenticationError("HITCH_API_KEY is set — unset it to manage stored logins.");
|
|
5
|
+
const { me, membership } = await loginWithDevice(await resolveInstanceUrl(), {
|
|
6
|
+
expectedOrg: findWorkspaceConfig(process.cwd())?.org,
|
|
7
|
+
noBrowser: options.noBrowser
|
|
8
|
+
});
|
|
9
|
+
console.log(`Signed in as ${me.person.email} to ${membership.name}.`);
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { runLogin };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { i as APPLET_CODE_PATTERN } from "./manifest-4ZAc6HUk.js";
|
|
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";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/logs.ts
|
|
6
|
+
const LOG_LEVELS = [
|
|
7
|
+
"debug",
|
|
8
|
+
"log",
|
|
9
|
+
"info",
|
|
10
|
+
"warn",
|
|
11
|
+
"error"
|
|
12
|
+
];
|
|
13
|
+
const MAX_RANGE_MS = 6048e5;
|
|
14
|
+
const LIVE_OVERLAP_MS = 1e4;
|
|
15
|
+
const POLL_INTERVAL_MS = 2e3;
|
|
16
|
+
const MAX_SEEN_IDS = 5e3;
|
|
17
|
+
const logSchema = z.object({
|
|
18
|
+
id: z.string(),
|
|
19
|
+
timestamp: z.number(),
|
|
20
|
+
level: z.string(),
|
|
21
|
+
message: z.string(),
|
|
22
|
+
releaseId: z.string(),
|
|
23
|
+
type: z.string().optional(),
|
|
24
|
+
runId: z.string().optional(),
|
|
25
|
+
workflow: z.string().optional(),
|
|
26
|
+
invocation: z.number().optional(),
|
|
27
|
+
outcome: z.string().optional(),
|
|
28
|
+
eventType: z.string().optional(),
|
|
29
|
+
statusCode: z.number().optional(),
|
|
30
|
+
cpuTimeMs: z.number().optional(),
|
|
31
|
+
wallTimeMs: z.number().optional()
|
|
32
|
+
});
|
|
33
|
+
const logsResponseSchema = z.object({ data: z.array(logSchema) });
|
|
34
|
+
function parseSince(value = "1h") {
|
|
35
|
+
const match = /^(\d+)(s|m|h|d)$/.exec(value);
|
|
36
|
+
if (!match) throw new Error("--since must use a duration such as \"30m\", \"1h\", or \"2d\".");
|
|
37
|
+
const duration = Number(match[1]) * {
|
|
38
|
+
s: 1e3,
|
|
39
|
+
m: 6e4,
|
|
40
|
+
h: 36e5,
|
|
41
|
+
d: 864e5
|
|
42
|
+
}[match[2]];
|
|
43
|
+
if (!Number.isSafeInteger(duration) || duration < 1e3 || duration > MAX_RANGE_MS) throw new Error("--since must be between 1s and 7d.");
|
|
44
|
+
return duration;
|
|
45
|
+
}
|
|
46
|
+
function parseLimit(value = "100") {
|
|
47
|
+
const limit = Number(value);
|
|
48
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) throw new Error("--limit must be an integer from 1 to 100.");
|
|
49
|
+
return limit;
|
|
50
|
+
}
|
|
51
|
+
function parseLevel(value) {
|
|
52
|
+
if (value === void 0) return void 0;
|
|
53
|
+
const parsed = z.enum(LOG_LEVELS).safeParse(value);
|
|
54
|
+
if (!parsed.success) throw new Error("--level must be debug, log, info, warn, or error.");
|
|
55
|
+
return parsed.data;
|
|
56
|
+
}
|
|
57
|
+
function parseFilter(value) {
|
|
58
|
+
if (value === void 0) return void 0;
|
|
59
|
+
try {
|
|
60
|
+
const filter = JSON.parse(value);
|
|
61
|
+
if (filter === null || typeof filter !== "object" || Array.isArray(filter)) throw new Error();
|
|
62
|
+
return filter;
|
|
63
|
+
} catch {
|
|
64
|
+
throw new Error("--filter must be a JSON object.");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function parseSearch(value) {
|
|
68
|
+
if (value === void 0) return void 0;
|
|
69
|
+
const search = value.trim();
|
|
70
|
+
if (search.length === 0 || search.length > 1e3) throw new Error("--search must contain from 1 to 1000 characters.");
|
|
71
|
+
return search;
|
|
72
|
+
}
|
|
73
|
+
async function resolveTarget(code) {
|
|
74
|
+
if (code === void 0) {
|
|
75
|
+
const manifest = await loadAppletConfig(process.cwd());
|
|
76
|
+
return {
|
|
77
|
+
code: manifest.code,
|
|
78
|
+
org: manifest.org
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (!APPLET_CODE_PATTERN.test(code)) throw new Error(`Invalid applet code "${code}".`);
|
|
82
|
+
return {
|
|
83
|
+
code,
|
|
84
|
+
org: readWorkspaceConfig(process.cwd())?.org ?? resolveWorkspaceOrg(process.cwd())
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
async function readErrorDetails(response) {
|
|
88
|
+
try {
|
|
89
|
+
const body = await response.json();
|
|
90
|
+
if (body !== null && typeof body === "object") return ["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(": ");
|
|
91
|
+
} catch {
|
|
92
|
+
return "";
|
|
93
|
+
}
|
|
94
|
+
return "";
|
|
95
|
+
}
|
|
96
|
+
function waitForPoll(signal) {
|
|
97
|
+
if (signal?.aborted === true) return Promise.resolve(false);
|
|
98
|
+
return new Promise((resolve) => {
|
|
99
|
+
const timeout = setTimeout(() => {
|
|
100
|
+
signal?.removeEventListener("abort", onAbort);
|
|
101
|
+
resolve(true);
|
|
102
|
+
}, POLL_INTERVAL_MS);
|
|
103
|
+
const onAbort = () => {
|
|
104
|
+
clearTimeout(timeout);
|
|
105
|
+
resolve(false);
|
|
106
|
+
};
|
|
107
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function printLog(log) {
|
|
111
|
+
const details = log.type === "invocation" ? [
|
|
112
|
+
log.statusCode === void 0 ? void 0 : `status=${log.statusCode}`,
|
|
113
|
+
log.outcome === void 0 ? void 0 : `outcome=${log.outcome}`,
|
|
114
|
+
log.wallTimeMs === void 0 ? void 0 : `wall=${log.wallTimeMs}ms`,
|
|
115
|
+
log.cpuTimeMs === void 0 ? void 0 : `cpu=${log.cpuTimeMs}ms`
|
|
116
|
+
].filter((value) => value !== void 0) : [];
|
|
117
|
+
console.log(`${new Date(log.timestamp).toISOString()} ${log.level.toUpperCase().padEnd(5)} ${log.type === "workflow" ? `[${log.workflow} ${log.runId?.slice(0, 8)}#${log.invocation}] ` : ""}${log.message}${details.length === 0 ? "" : ` [${details.join(" ")}]`}`);
|
|
118
|
+
}
|
|
119
|
+
async function runLogs(options) {
|
|
120
|
+
const [{ code, org }, since, limit, level, userFilter, search] = await Promise.all([
|
|
121
|
+
resolveTarget(options.code),
|
|
122
|
+
Promise.resolve(parseSince(options.since)),
|
|
123
|
+
Promise.resolve(parseLimit(options.limit)),
|
|
124
|
+
Promise.resolve(parseLevel(options.level)),
|
|
125
|
+
Promise.resolve(parseFilter(options.filter)),
|
|
126
|
+
Promise.resolve(parseSearch(options.search))
|
|
127
|
+
]);
|
|
128
|
+
const runFilter = options.run === void 0 ? void 0 : { runId: { $eq: options.run } };
|
|
129
|
+
const filter = runFilter === void 0 ? userFilter : userFilter === void 0 ? runFilter : { $and: [runFilter, userFilter] };
|
|
130
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
131
|
+
const startedAt = Date.now();
|
|
132
|
+
const requestLogs = async (from, to) => {
|
|
133
|
+
const response = await fetchWithOrgAuth(org, options, (instanceUrl, accessToken) => {
|
|
134
|
+
const url = new URL(`/api/v1/applets/${encodeURIComponent(code)}/logs/query`, `${instanceUrl}/`);
|
|
135
|
+
const levelFilter = level === void 0 ? void 0 : { level: { $in: LOG_LEVELS.slice(LOG_LEVELS.indexOf(level)) } };
|
|
136
|
+
return fetcher(url, {
|
|
137
|
+
method: "POST",
|
|
138
|
+
headers: {
|
|
139
|
+
Authorization: `Bearer ${accessToken}`,
|
|
140
|
+
"content-type": "application/json"
|
|
141
|
+
},
|
|
142
|
+
body: JSON.stringify({
|
|
143
|
+
from,
|
|
144
|
+
to,
|
|
145
|
+
limit,
|
|
146
|
+
...search === void 0 ? {} : { search },
|
|
147
|
+
...levelFilter === void 0 && filter === void 0 ? {} : { filter: levelFilter === void 0 ? filter : filter === void 0 ? levelFilter : { $and: [levelFilter, filter] } }
|
|
148
|
+
})
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
const details = await readErrorDetails(response);
|
|
153
|
+
throw new Error(`Logs request failed (${response.status})${details ? `: ${details}` : ""}.`);
|
|
154
|
+
}
|
|
155
|
+
return logsResponseSchema.parse(await response.json()).data;
|
|
156
|
+
};
|
|
157
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
158
|
+
const seenIdQueue = [];
|
|
159
|
+
const printNewLogs = (logs) => {
|
|
160
|
+
logs.forEach((log) => {
|
|
161
|
+
if (seenIds.has(log.id)) return;
|
|
162
|
+
seenIds.add(log.id);
|
|
163
|
+
seenIdQueue.push(log.id);
|
|
164
|
+
if (seenIdQueue.length > MAX_SEEN_IDS) seenIds.delete(seenIdQueue.shift());
|
|
165
|
+
printLog(log);
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
const initialLogs = await requestLogs(startedAt - since, startedAt);
|
|
169
|
+
printNewLogs(initialLogs);
|
|
170
|
+
if (options.live !== true) {
|
|
171
|
+
if (initialLogs.length === 0) console.log(`No logs found for "${code}".`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
let lastTimestamp = initialLogs.at(-1)?.timestamp ?? startedAt;
|
|
175
|
+
while (await waitForPoll(options.signal)) {
|
|
176
|
+
const to = Date.now();
|
|
177
|
+
const logs = await requestLogs(Math.max(startedAt - since, lastTimestamp - LIVE_OVERLAP_MS), to);
|
|
178
|
+
printNewLogs(logs);
|
|
179
|
+
lastTimestamp = Math.max(lastTimestamp, ...logs.map(({ timestamp }) => timestamp));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
export { runLogs };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Cron } from "croner";
|
|
3
|
+
//#region src/manifest-patterns.ts
|
|
4
|
+
const APPLET_CODE_PATTERN = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
|
|
5
|
+
const ORG_CODE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/manifest.ts
|
|
8
|
+
const RESERVED_ATTRIBUTE_CODES = /* @__PURE__ */ new Set([
|
|
9
|
+
"id",
|
|
10
|
+
"name",
|
|
11
|
+
"expected_version"
|
|
12
|
+
]);
|
|
13
|
+
const codeSchema = z.string().regex(APPLET_CODE_PATTERN, "must start with a lowercase letter, end with a letter or number, and contain only lowercase letters, numbers, and non-consecutive underscores");
|
|
14
|
+
const nameSchema = z.string().trim().min(1).max(120);
|
|
15
|
+
const attributeCodeSchema = codeSchema.superRefine((code, context) => {
|
|
16
|
+
if (RESERVED_ATTRIBUTE_CODES.has(code)) context.addIssue({
|
|
17
|
+
code: "custom",
|
|
18
|
+
message: `Reserved record field code "${code}" is not allowed.`
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
const attributeCodesSchema = z.array(attributeCodeSchema).superRefine((codes, context) => {
|
|
22
|
+
const duplicateIndex = codes.findIndex((code, index) => codes.indexOf(code) !== index);
|
|
23
|
+
if (duplicateIndex !== -1) context.addIssue({
|
|
24
|
+
code: "custom",
|
|
25
|
+
message: `Duplicate attribute code "${codes[duplicateIndex]}".`,
|
|
26
|
+
path: [duplicateIndex]
|
|
27
|
+
});
|
|
28
|
+
}).readonly();
|
|
29
|
+
const appletManifestObjectSchema = z.strictObject({
|
|
30
|
+
code: codeSchema,
|
|
31
|
+
canCreate: z.boolean(),
|
|
32
|
+
canDelete: z.boolean(),
|
|
33
|
+
readOnly: attributeCodesSchema,
|
|
34
|
+
readWrite: attributeCodesSchema,
|
|
35
|
+
optional: z.boolean().optional(),
|
|
36
|
+
optionalAttributes: attributeCodesSchema.optional()
|
|
37
|
+
}).superRefine((object, context) => {
|
|
38
|
+
const overlap = object.readOnly.find((code) => object.readWrite.includes(code));
|
|
39
|
+
if (overlap !== void 0) context.addIssue({
|
|
40
|
+
code: "custom",
|
|
41
|
+
message: `readOnly and readWrite both contain "${overlap}".`
|
|
42
|
+
});
|
|
43
|
+
object.optionalAttributes?.forEach((code, index) => {
|
|
44
|
+
if (!object.readOnly.includes(code) && !object.readWrite.includes(code)) context.addIssue({
|
|
45
|
+
code: "custom",
|
|
46
|
+
message: `optionalAttributes contains undeclared attribute code "${code}".`,
|
|
47
|
+
path: ["optionalAttributes", index]
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
const appletManifestObjectsSchema = z.array(appletManifestObjectSchema).readonly();
|
|
52
|
+
const appletManifestSchedulesSchema = z.array(z.strictObject({
|
|
53
|
+
code: codeSchema,
|
|
54
|
+
name: nameSchema,
|
|
55
|
+
cron: z.string().refine((value) => {
|
|
56
|
+
if (value.trim().split(/\s+/).length !== 5) return false;
|
|
57
|
+
try {
|
|
58
|
+
new Cron(value);
|
|
59
|
+
return true;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}, "must be a valid 5-field cron expression (minute hour day-of-month month day-of-week)"),
|
|
64
|
+
path: z.string().startsWith("/", "must start with \"/\"").refine((path) => !path.startsWith("//"), "must not start with \"//\"").refine((path) => !/\s/.test(path), "must not contain whitespace")
|
|
65
|
+
})).readonly();
|
|
66
|
+
const appletVariableKeySchema = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).refine((key) => !/^hitch_/i.test(key), { message: "Keys with the HITCH_ prefix are reserved." }).max(128);
|
|
67
|
+
const appletManifestVariablesSchema = z.record(appletVariableKeySchema, z.strictObject({
|
|
68
|
+
secret: z.boolean().optional(),
|
|
69
|
+
optional: z.boolean().optional()
|
|
70
|
+
})).readonly();
|
|
71
|
+
const appletManifestShape = {
|
|
72
|
+
org: z.string().regex(ORG_CODE_PATTERN, "must start with a lowercase letter, end with a letter or number, and contain only lowercase letters, numbers, and non-consecutive hyphens"),
|
|
73
|
+
name: nameSchema,
|
|
74
|
+
code: codeSchema,
|
|
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(),
|
|
77
|
+
schedules: appletManifestSchedulesSchema.optional(),
|
|
78
|
+
variables: appletManifestVariablesSchema.optional(),
|
|
79
|
+
objects: appletManifestObjectsSchema
|
|
80
|
+
};
|
|
81
|
+
const checkDuplicateCodes = (manifest, context) => {
|
|
82
|
+
const duplicateIndex = manifest.objects.findIndex(({ code }, index) => manifest.objects.findIndex((object) => object.code === code) !== index);
|
|
83
|
+
if (duplicateIndex !== -1) context.addIssue({
|
|
84
|
+
code: "custom",
|
|
85
|
+
message: `Duplicate object code "${manifest.objects[duplicateIndex]?.code}".`,
|
|
86
|
+
path: [
|
|
87
|
+
"objects",
|
|
88
|
+
duplicateIndex,
|
|
89
|
+
"code"
|
|
90
|
+
]
|
|
91
|
+
});
|
|
92
|
+
const schedules = manifest.schedules ?? [];
|
|
93
|
+
const duplicateScheduleIndex = schedules.findIndex(({ code }, index) => schedules.findIndex((schedule) => schedule.code === code) !== index);
|
|
94
|
+
if (duplicateScheduleIndex !== -1) context.addIssue({
|
|
95
|
+
code: "custom",
|
|
96
|
+
message: `Duplicate schedule code "${schedules[duplicateScheduleIndex]?.code}".`,
|
|
97
|
+
path: [
|
|
98
|
+
"schedules",
|
|
99
|
+
duplicateScheduleIndex,
|
|
100
|
+
"code"
|
|
101
|
+
]
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
const appletManifestSchema = z.strictObject(appletManifestShape).superRefine(checkDuplicateCodes);
|
|
105
|
+
const appletDefinitionSchema = z.strictObject({
|
|
106
|
+
name: appletManifestShape.name,
|
|
107
|
+
code: appletManifestShape.code,
|
|
108
|
+
requiresChangeset: appletManifestShape.requiresChangeset,
|
|
109
|
+
telephony: appletManifestShape.telephony,
|
|
110
|
+
schedules: appletManifestShape.schedules,
|
|
111
|
+
variables: appletManifestShape.variables,
|
|
112
|
+
objects: appletManifestShape.objects
|
|
113
|
+
}).superRefine(checkDuplicateCodes);
|
|
114
|
+
const packageVersionsSchema = z.record(z.string().min(1), z.string().min(1)).readonly();
|
|
115
|
+
const RESERVED_APPLET_PACKAGES = /* @__PURE__ */ new Set([
|
|
116
|
+
"@fontsource-variable/inter",
|
|
117
|
+
"@hitch42/applet",
|
|
118
|
+
"@orpc/contract",
|
|
119
|
+
"@orpc/server",
|
|
120
|
+
"@tailwindcss/vite",
|
|
121
|
+
"@tanstack/react-query",
|
|
122
|
+
"@tanstack/react-router",
|
|
123
|
+
"@tiptap/core",
|
|
124
|
+
"@tiptap/extension-image",
|
|
125
|
+
"@tiptap/extension-list",
|
|
126
|
+
"@tiptap/extension-table",
|
|
127
|
+
"@tiptap/extensions",
|
|
128
|
+
"@tiptap/markdown",
|
|
129
|
+
"@tiptap/react",
|
|
130
|
+
"@tiptap/starter-kit",
|
|
131
|
+
"@types/node",
|
|
132
|
+
"@types/react",
|
|
133
|
+
"@types/react-dom",
|
|
134
|
+
"class-variance-authority",
|
|
135
|
+
"cn",
|
|
136
|
+
"lucide-react",
|
|
137
|
+
"oxfmt",
|
|
138
|
+
"oxlint",
|
|
139
|
+
"oxlint-tsgolint",
|
|
140
|
+
"react",
|
|
141
|
+
"react-aria-components",
|
|
142
|
+
"react-dom",
|
|
143
|
+
"shadcn",
|
|
144
|
+
"streamdown",
|
|
145
|
+
"tailwindcss",
|
|
146
|
+
"tw-animate-css",
|
|
147
|
+
"typescript",
|
|
148
|
+
"vite",
|
|
149
|
+
"vitest",
|
|
150
|
+
"zod"
|
|
151
|
+
]);
|
|
152
|
+
const checkSourcePackages = (manifest, context) => {
|
|
153
|
+
const dependencies = Object.keys(manifest.dependencies ?? {});
|
|
154
|
+
const devDependencies = new Set(Object.keys(manifest.devDependencies ?? {}));
|
|
155
|
+
[{
|
|
156
|
+
field: "dependencies",
|
|
157
|
+
names: dependencies
|
|
158
|
+
}, {
|
|
159
|
+
field: "devDependencies",
|
|
160
|
+
names: [...devDependencies]
|
|
161
|
+
}].forEach(({ field, names }) => names.forEach((name) => {
|
|
162
|
+
if (RESERVED_APPLET_PACKAGES.has(name)) context.addIssue({
|
|
163
|
+
code: "custom",
|
|
164
|
+
message: `Package "${name}" is managed by the applet CLI.`,
|
|
165
|
+
path: [field, name]
|
|
166
|
+
});
|
|
167
|
+
}));
|
|
168
|
+
dependencies.filter((name) => devDependencies.has(name)).forEach((name) => {
|
|
169
|
+
context.addIssue({
|
|
170
|
+
code: "custom",
|
|
171
|
+
message: `Package "${name}" cannot be in both dependencies and devDependencies.`,
|
|
172
|
+
path: ["devDependencies", name]
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
const appletSourceDefinitionSchema = z.strictObject({
|
|
177
|
+
name: appletManifestShape.name,
|
|
178
|
+
code: appletManifestShape.code,
|
|
179
|
+
requiresChangeset: appletManifestShape.requiresChangeset,
|
|
180
|
+
telephony: appletManifestShape.telephony,
|
|
181
|
+
schedules: appletManifestShape.schedules,
|
|
182
|
+
variables: appletManifestShape.variables,
|
|
183
|
+
objects: appletManifestShape.objects,
|
|
184
|
+
dependencies: packageVersionsSchema.optional(),
|
|
185
|
+
devDependencies: packageVersionsSchema.optional()
|
|
186
|
+
}).superRefine((manifest, context) => {
|
|
187
|
+
checkDuplicateCodes(manifest, context);
|
|
188
|
+
checkSourcePackages(manifest, context);
|
|
189
|
+
});
|
|
190
|
+
//#endregion
|
|
191
|
+
export { ORG_CODE_PATTERN as a, APPLET_CODE_PATTERN as i, appletManifestSchema as n, appletSourceDefinitionSchema as r, appletDefinitionSchema as t };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { t as AnyWorkflowDefinition } from "./workflow-DurM6Fwx.js";
|
|
2
|
+
import { AnyProcedure, AnyRouter, Lazy } from "@orpc/server";
|
|
3
|
+
import { AnyContractRouter } from "@orpc/contract";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/hitch/registry.d.ts
|
|
6
|
+
interface HitchRegister {}
|
|
7
|
+
type RegisteredCatalog = HitchRegister extends {
|
|
8
|
+
catalog: infer C;
|
|
9
|
+
} ? C : Record<string, string>;
|
|
10
|
+
type RegisteredContract = HitchRegister extends {
|
|
11
|
+
contract: infer C extends AnyContractRouter;
|
|
12
|
+
} ? C : AnyContractRouter;
|
|
13
|
+
type RegisteredManifest = HitchRegister extends {
|
|
14
|
+
manifest: infer M extends AppletManifest;
|
|
15
|
+
} ? M : AppletManifest;
|
|
16
|
+
type RegisteredVariables = HitchRegister extends {
|
|
17
|
+
manifest: infer M extends AppletManifest;
|
|
18
|
+
} ? M extends {
|
|
19
|
+
readonly variables: infer Variables extends NonNullable<AppletManifest["variables"]>;
|
|
20
|
+
} ? Variables : {} : {};
|
|
21
|
+
type RegisteredVariableKeys = keyof RegisteredVariables;
|
|
22
|
+
type RegisteredRouter = HitchRegister extends {
|
|
23
|
+
router: infer R extends AnyRouter;
|
|
24
|
+
} ? R : AnyRouter;
|
|
25
|
+
type RegisteredWorkflows = HitchRegister extends {
|
|
26
|
+
workflows: infer W extends Record<string, AnyWorkflowDefinition>;
|
|
27
|
+
} ? W : Record<string, AnyWorkflowDefinition>;
|
|
28
|
+
declare function registerHitchContract(contract: AnyContractRouter): void;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/manifest.d.ts
|
|
31
|
+
interface AppletManifest {
|
|
32
|
+
org: string;
|
|
33
|
+
name: string;
|
|
34
|
+
code: string;
|
|
35
|
+
/** This code needs the schema as of this changeset. */
|
|
36
|
+
requiresChangeset?: string;
|
|
37
|
+
telephony?: {
|
|
38
|
+
events: readonly "message.received"[];
|
|
39
|
+
};
|
|
40
|
+
schedules?: readonly {
|
|
41
|
+
code: string;
|
|
42
|
+
name: string;
|
|
43
|
+
cron: string;
|
|
44
|
+
path: string;
|
|
45
|
+
}[];
|
|
46
|
+
variables?: Readonly<Record<string, {
|
|
47
|
+
secret?: boolean;
|
|
48
|
+
optional?: boolean;
|
|
49
|
+
}>>;
|
|
50
|
+
objects: readonly {
|
|
51
|
+
code: string;
|
|
52
|
+
canCreate: boolean;
|
|
53
|
+
canDelete: boolean;
|
|
54
|
+
readOnly: readonly string[];
|
|
55
|
+
readWrite: readonly string[];
|
|
56
|
+
optional?: boolean;
|
|
57
|
+
optionalAttributes?: readonly string[];
|
|
58
|
+
}[];
|
|
59
|
+
}
|
|
60
|
+
type AppletDefinition = Omit<AppletManifest, "org">;
|
|
61
|
+
type AppletManifestObject = AppletManifest["objects"][number];
|
|
62
|
+
interface AppletPackages {
|
|
63
|
+
dependencies?: Readonly<Record<string, string>>;
|
|
64
|
+
devDependencies?: Readonly<Record<string, string>>;
|
|
65
|
+
}
|
|
66
|
+
type AppletSourceDefinition = AppletDefinition & AppletPackages;
|
|
67
|
+
declare const appletManifestSchema: z.ZodType<AppletManifest>;
|
|
68
|
+
declare const appletDefinitionSchema: z.ZodType<AppletDefinition>;
|
|
69
|
+
declare const appletSourceDefinitionSchema: z.ZodType<AppletSourceDefinition>;
|
|
70
|
+
type RegisteredAppletManifestObject = { [Code in keyof RegisteredCatalog]: Omit<AppletManifestObject, "code" | "readOnly" | "readWrite"> & {
|
|
71
|
+
code: Code;
|
|
72
|
+
readOnly: readonly RegisteredCatalog[Code][];
|
|
73
|
+
readWrite: readonly RegisteredCatalog[Code][];
|
|
74
|
+
}; }[keyof RegisteredCatalog];
|
|
75
|
+
type RouterSchedulePaths<R, Prefix extends string = ""> = R extends AnyProcedure ? Prefix : R extends Lazy<infer U> ? RouterSchedulePaths<U, Prefix> : { [K in keyof R & string]: RouterSchedulePaths<R[K], `${Prefix}/${K}`>; }[keyof R & string];
|
|
76
|
+
type RegisteredSchedulePath = HitchRegister extends {
|
|
77
|
+
router: infer R extends AnyRouter;
|
|
78
|
+
} ? RouterSchedulePaths<R> : string;
|
|
79
|
+
type RegisteredAppletManifest = Omit<AppletManifest, "objects" | "schedules"> & {
|
|
80
|
+
schedules?: readonly (Omit<NonNullable<AppletManifest["schedules"]>[number], "path"> & {
|
|
81
|
+
path: RegisteredSchedulePath;
|
|
82
|
+
})[];
|
|
83
|
+
objects: readonly RegisteredAppletManifestObject[];
|
|
84
|
+
};
|
|
85
|
+
type RegisteredAppletDefinition = Omit<RegisteredAppletManifest, "org">;
|
|
86
|
+
type RegisteredAppletSourceDefinition = RegisteredAppletDefinition & AppletPackages;
|
|
87
|
+
//#endregion
|
|
88
|
+
export { RegisteredWorkflows as _, AppletSourceDefinition as a, appletManifestSchema as c, RegisteredCatalog as d, RegisteredContract as f, RegisteredVariables as g, RegisteredVariableKeys as h, AppletPackages as i, appletSourceDefinitionSchema as l, RegisteredRouter as m, AppletManifest as n, RegisteredAppletSourceDefinition as o, RegisteredManifest as p, AppletManifestObject as r, appletDefinitionSchema as s, AppletDefinition as t, HitchRegister as u, registerHitchContract as v };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { oc } from "@orpc/contract";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/hitch/me.ts
|
|
4
|
+
const personSchema = z.object({
|
|
5
|
+
id: z.uuid(),
|
|
6
|
+
firstName: z.string(),
|
|
7
|
+
lastName: z.string(),
|
|
8
|
+
email: z.email()
|
|
9
|
+
});
|
|
10
|
+
const membershipSchema = z.object({
|
|
11
|
+
orgId: z.uuid(),
|
|
12
|
+
code: z.string(),
|
|
13
|
+
name: z.string(),
|
|
14
|
+
iconFileId: z.uuid().nullable(),
|
|
15
|
+
role: z.enum(["member", "owner"]),
|
|
16
|
+
capabilities: z.array(z.string())
|
|
17
|
+
});
|
|
18
|
+
const meSchema = z.object({
|
|
19
|
+
person: personSchema,
|
|
20
|
+
memberships: z.array(membershipSchema),
|
|
21
|
+
organization: z.object({
|
|
22
|
+
id: z.uuid(),
|
|
23
|
+
code: z.string()
|
|
24
|
+
}).nullable(),
|
|
25
|
+
multiOrg: z.boolean()
|
|
26
|
+
});
|
|
27
|
+
const meContract = { get: oc.route({
|
|
28
|
+
method: "GET",
|
|
29
|
+
path: "/v1/me"
|
|
30
|
+
}).input(z.void()).output(meSchema) };
|
|
31
|
+
//#endregion
|
|
32
|
+
export { meSchema as n, meContract as t };
|