@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,536 @@
|
|
|
1
|
+
import { i as readWorkspaceConfig, l as organizationInstanceUrl, s as DEFAULT_INSTANCE_URL } from "./workspace-DruAZPmV.js";
|
|
2
|
+
import { n as loadAppletSourceDefinition } from "./load-config-OKZU3UKn.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { cp, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
6
|
+
import { dirname, relative, resolve } from "node:path";
|
|
7
|
+
import { TomlError, parse, stringify } from "smol-toml";
|
|
8
|
+
//#region src/agent-support.ts
|
|
9
|
+
var AgentConfigError = class extends Error {};
|
|
10
|
+
async function ensureAgentConfigs(root, org) {
|
|
11
|
+
const servers = {
|
|
12
|
+
hitch: {
|
|
13
|
+
type: "http",
|
|
14
|
+
url: `${organizationInstanceUrl(DEFAULT_INSTANCE_URL, org)}/mcp`
|
|
15
|
+
},
|
|
16
|
+
"chrome-devtools": {
|
|
17
|
+
type: "stdio",
|
|
18
|
+
command: "pnpx",
|
|
19
|
+
args: ["chrome-devtools-mcp@latest", "--headless"]
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const configs = await Promise.all([{
|
|
23
|
+
path: resolve(root, ".mcp.json"),
|
|
24
|
+
format: "json",
|
|
25
|
+
key: "mcpServers"
|
|
26
|
+
}, {
|
|
27
|
+
path: resolve(root, ".codex/config.toml"),
|
|
28
|
+
format: "toml",
|
|
29
|
+
key: "mcp_servers"
|
|
30
|
+
}].map(async ({ path, format, key }) => {
|
|
31
|
+
const current = existsSync(path) ? await readFile(path, "utf8") : void 0;
|
|
32
|
+
let config;
|
|
33
|
+
let additions;
|
|
34
|
+
try {
|
|
35
|
+
config = z.record(z.string(), z.unknown()).parse(current === void 0 ? {} : format === "json" ? JSON.parse(current) : parse(current, { integersAsBigInt: true }));
|
|
36
|
+
const existing = config[key] === void 0 ? {} : z.record(z.string(), z.unknown()).parse(config[key]);
|
|
37
|
+
const missing = Object.entries(servers).filter(([name]) => !Object.hasOwn(existing, name));
|
|
38
|
+
if (current !== void 0 && missing.length === 0) return void 0;
|
|
39
|
+
additions = Object.fromEntries(missing.map(([name, server]) => [name, format === "json" ? server : Object.fromEntries(Object.entries(server).filter(([field]) => field !== "type"))]));
|
|
40
|
+
config[key] = {
|
|
41
|
+
...existing,
|
|
42
|
+
...additions
|
|
43
|
+
};
|
|
44
|
+
} catch (cause) {
|
|
45
|
+
throw new AgentConfigError(`Invalid agent configuration in ${path}.`, { cause });
|
|
46
|
+
}
|
|
47
|
+
if (format === "json") return {
|
|
48
|
+
path,
|
|
49
|
+
contents: `${JSON.stringify(config, null, 2)}\n`
|
|
50
|
+
};
|
|
51
|
+
const contents = `${current ?? ""}${current ? "\n" : ""}${stringify({ [key]: additions })}`;
|
|
52
|
+
try {
|
|
53
|
+
parse(contents, { integersAsBigInt: true });
|
|
54
|
+
return {
|
|
55
|
+
path,
|
|
56
|
+
contents
|
|
57
|
+
};
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (!(error instanceof TomlError)) throw error;
|
|
60
|
+
return {
|
|
61
|
+
path,
|
|
62
|
+
contents: stringify(config, { numbersAsFloat: true })
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
await mkdir(resolve(root, ".codex"), { recursive: true });
|
|
67
|
+
await Promise.all(configs.filter((config) => config !== void 0).map(({ path, contents }) => writeFile(path, contents)));
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/project.ts
|
|
71
|
+
const PACKAGE_MANAGER = "pnpm@11.18.0+sha512.33d83c77da82f49fba836925c6f1b841181ec3132b670639bd012f7075f5c7cf634c5f870147c19aae7478fac01df09d8892e880454896edd23ee9b33757563c";
|
|
72
|
+
const cliManifestValueSchema = z.string().min(1, "must be a non-empty string");
|
|
73
|
+
const cliManifestSchema = z.object({
|
|
74
|
+
name: cliManifestValueSchema,
|
|
75
|
+
version: cliManifestValueSchema,
|
|
76
|
+
dependencies: z.object({
|
|
77
|
+
"@fontsource-variable/inter": cliManifestValueSchema,
|
|
78
|
+
"@orpc/contract": cliManifestValueSchema,
|
|
79
|
+
"@tiptap/core": cliManifestValueSchema,
|
|
80
|
+
"@tiptap/extension-image": cliManifestValueSchema,
|
|
81
|
+
"@tiptap/extension-list": cliManifestValueSchema,
|
|
82
|
+
"@tiptap/extension-table": cliManifestValueSchema,
|
|
83
|
+
"@tiptap/extensions": cliManifestValueSchema,
|
|
84
|
+
"@tiptap/markdown": cliManifestValueSchema,
|
|
85
|
+
"@tiptap/react": cliManifestValueSchema,
|
|
86
|
+
"@tiptap/starter-kit": cliManifestValueSchema,
|
|
87
|
+
"@tailwindcss/vite": cliManifestValueSchema,
|
|
88
|
+
"@tanstack/router-cli": cliManifestValueSchema,
|
|
89
|
+
"class-variance-authority": cliManifestValueSchema,
|
|
90
|
+
cn: cliManifestValueSchema,
|
|
91
|
+
"lucide-react": cliManifestValueSchema,
|
|
92
|
+
oxfmt: cliManifestValueSchema,
|
|
93
|
+
oxlint: cliManifestValueSchema,
|
|
94
|
+
"oxlint-tsgolint": cliManifestValueSchema,
|
|
95
|
+
"react-aria-components": cliManifestValueSchema,
|
|
96
|
+
shadcn: cliManifestValueSchema,
|
|
97
|
+
streamdown: cliManifestValueSchema,
|
|
98
|
+
tailwindcss: cliManifestValueSchema,
|
|
99
|
+
"tw-animate-css": cliManifestValueSchema,
|
|
100
|
+
vite: cliManifestValueSchema,
|
|
101
|
+
vitest: cliManifestValueSchema,
|
|
102
|
+
zod: cliManifestValueSchema
|
|
103
|
+
}),
|
|
104
|
+
peerDependencies: z.object({
|
|
105
|
+
"@orpc/server": cliManifestValueSchema,
|
|
106
|
+
"@tanstack/react-query": cliManifestValueSchema,
|
|
107
|
+
"@tanstack/react-router": cliManifestValueSchema,
|
|
108
|
+
"@types/node": cliManifestValueSchema,
|
|
109
|
+
"@types/react": cliManifestValueSchema,
|
|
110
|
+
"@types/react-dom": cliManifestValueSchema,
|
|
111
|
+
react: cliManifestValueSchema,
|
|
112
|
+
"react-dom": cliManifestValueSchema,
|
|
113
|
+
typescript: cliManifestValueSchema
|
|
114
|
+
})
|
|
115
|
+
});
|
|
116
|
+
async function loadCliManifest(options) {
|
|
117
|
+
const result = cliManifestSchema.safeParse(JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")));
|
|
118
|
+
if (!result.success) {
|
|
119
|
+
const issue = result.error.issues.at(0);
|
|
120
|
+
if (issue === void 0) throw new Error("Invalid CLI package manifest.");
|
|
121
|
+
throw new Error(`Invalid CLI package manifest field "${issue.path.join(".")}": ${issue.message}.`);
|
|
122
|
+
}
|
|
123
|
+
const catalogEntry = [...Object.entries(result.data.dependencies).map(([name, value]) => [`dependencies.${name}`, value]), ...Object.entries(result.data.peerDependencies).map(([name, value]) => [`peerDependencies.${name}`, value])].find(([, value]) => value.startsWith("catalog:"));
|
|
124
|
+
if (catalogEntry !== void 0) {
|
|
125
|
+
if (options?.allowDevelopment === true) return void 0;
|
|
126
|
+
throw new Error(`Invalid CLI package manifest field "${catalogEntry[0]}": "catalog:" identifies an unpublished development build. Run the published @hitch42/applet CLI instead.`);
|
|
127
|
+
}
|
|
128
|
+
return result.data;
|
|
129
|
+
}
|
|
130
|
+
function assertWorkspaceCli(config, cli) {
|
|
131
|
+
const runningCli = `${cli.name}@${cli.version}`;
|
|
132
|
+
if (config.sdk !== runningCli) throw new Error(`This workspace requires ${config.sdk}, but this command uses ${runningCli}. Run pnpm dlx ${config.sdk} bootstrap.`);
|
|
133
|
+
}
|
|
134
|
+
function workspacePackage(org) {
|
|
135
|
+
return {
|
|
136
|
+
name: `${org.replaceAll("_", "-")}-applets`,
|
|
137
|
+
private: true,
|
|
138
|
+
type: "module",
|
|
139
|
+
scripts: {
|
|
140
|
+
lint: "oxlint",
|
|
141
|
+
fmt: "oxfmt",
|
|
142
|
+
check: "oxfmt --check && oxlint"
|
|
143
|
+
},
|
|
144
|
+
devDependencies: {
|
|
145
|
+
"@hitch42/applet": "catalog:",
|
|
146
|
+
oxfmt: "catalog:",
|
|
147
|
+
oxlint: "catalog:",
|
|
148
|
+
"oxlint-tsgolint": "catalog:",
|
|
149
|
+
typescript: "catalog:",
|
|
150
|
+
vite: "catalog:",
|
|
151
|
+
vitest: "catalog:"
|
|
152
|
+
},
|
|
153
|
+
packageManager: PACKAGE_MANAGER
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function workspaceFile(cli) {
|
|
157
|
+
return `packages:
|
|
158
|
+
- applets/*
|
|
159
|
+
catalog:
|
|
160
|
+
"@hitch42/applet": npm:${cli.name}@${cli.version}
|
|
161
|
+
"@fontsource-variable/inter": "${cli.dependencies["@fontsource-variable/inter"]}"
|
|
162
|
+
"@orpc/contract": "${cli.dependencies["@orpc/contract"]}"
|
|
163
|
+
"@orpc/server": "${cli.peerDependencies["@orpc/server"]}"
|
|
164
|
+
"@tiptap/core": "${cli.dependencies["@tiptap/core"]}"
|
|
165
|
+
"@tiptap/extension-image": "${cli.dependencies["@tiptap/extension-image"]}"
|
|
166
|
+
"@tiptap/extension-list": "${cli.dependencies["@tiptap/extension-list"]}"
|
|
167
|
+
"@tiptap/extension-table": "${cli.dependencies["@tiptap/extension-table"]}"
|
|
168
|
+
"@tiptap/extensions": "${cli.dependencies["@tiptap/extensions"]}"
|
|
169
|
+
"@tiptap/markdown": "${cli.dependencies["@tiptap/markdown"]}"
|
|
170
|
+
"@tiptap/react": "${cli.dependencies["@tiptap/react"]}"
|
|
171
|
+
"@tiptap/starter-kit": "${cli.dependencies["@tiptap/starter-kit"]}"
|
|
172
|
+
"@tanstack/react-query": "${cli.peerDependencies["@tanstack/react-query"]}"
|
|
173
|
+
"@tanstack/react-router": "${cli.peerDependencies["@tanstack/react-router"]}"
|
|
174
|
+
"@tanstack/router-cli": "${cli.dependencies["@tanstack/router-cli"]}"
|
|
175
|
+
"@types/node": "${cli.peerDependencies["@types/node"]}"
|
|
176
|
+
"@types/react": "${cli.peerDependencies["@types/react"]}"
|
|
177
|
+
"@types/react-dom": "${cli.peerDependencies["@types/react-dom"]}"
|
|
178
|
+
"@tailwindcss/vite": "${cli.dependencies["@tailwindcss/vite"]}"
|
|
179
|
+
class-variance-authority: "${cli.dependencies["class-variance-authority"]}"
|
|
180
|
+
cn: "${cli.dependencies.cn}"
|
|
181
|
+
lucide-react: "${cli.dependencies["lucide-react"]}"
|
|
182
|
+
oxfmt: "${cli.dependencies.oxfmt}"
|
|
183
|
+
oxlint: "${cli.dependencies.oxlint}"
|
|
184
|
+
oxlint-tsgolint: "${cli.dependencies["oxlint-tsgolint"]}"
|
|
185
|
+
react: "${cli.peerDependencies.react}"
|
|
186
|
+
react-aria-components: "${cli.dependencies["react-aria-components"]}"
|
|
187
|
+
react-dom: "${cli.peerDependencies["react-dom"]}"
|
|
188
|
+
shadcn: "${cli.dependencies.shadcn}"
|
|
189
|
+
streamdown: "${cli.dependencies.streamdown}"
|
|
190
|
+
tailwindcss: "${cli.dependencies.tailwindcss}"
|
|
191
|
+
tw-animate-css: "${cli.dependencies["tw-animate-css"]}"
|
|
192
|
+
typescript: "${cli.peerDependencies.typescript}"
|
|
193
|
+
vite: "${cli.dependencies.vite}"
|
|
194
|
+
vitest: "${cli.dependencies.vitest}"
|
|
195
|
+
zod: "${cli.dependencies.zod}"
|
|
196
|
+
allowBuilds:
|
|
197
|
+
esbuild: false
|
|
198
|
+
workerd: true
|
|
199
|
+
minimumReleaseAge: 4320
|
|
200
|
+
minimumReleaseAgeExclude:
|
|
201
|
+
- "@hitch42/*"
|
|
202
|
+
`;
|
|
203
|
+
}
|
|
204
|
+
const OXLINT_CONFIG = `{
|
|
205
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
206
|
+
"plugins": ["eslint", "typescript", "unicorn", "import", "node"],
|
|
207
|
+
"options": { "typeAware": true, "typeCheck": true },
|
|
208
|
+
"env": { "node": true },
|
|
209
|
+
"overrides": [
|
|
210
|
+
{
|
|
211
|
+
"files": ["applets/*/src/client/**"],
|
|
212
|
+
"plugins": ["eslint", "typescript", "unicorn", "import", "react", "react-perf"],
|
|
213
|
+
"env": { "node": false, "browser": true },
|
|
214
|
+
"rules": {
|
|
215
|
+
"react/capitalized-calls": "error",
|
|
216
|
+
"react/error-boundaries": "error",
|
|
217
|
+
"react/exhaustive-effect-dependencies": "error",
|
|
218
|
+
"react/globals": "error",
|
|
219
|
+
"react/hooks": "error",
|
|
220
|
+
"react/immutability": "error",
|
|
221
|
+
"react/incompatible-library": "error",
|
|
222
|
+
"react/invariant": "error",
|
|
223
|
+
"react/memo-dependencies": "error",
|
|
224
|
+
"react/no-deriving-state-in-effects": "error",
|
|
225
|
+
"react/preserve-manual-memoization": "error",
|
|
226
|
+
"react/purity": "error",
|
|
227
|
+
"react/refs": "error",
|
|
228
|
+
"react/rule-suppression": "error",
|
|
229
|
+
"react/set-state-in-effect": "error",
|
|
230
|
+
"react/set-state-in-render": "error",
|
|
231
|
+
"react/static-components": "error",
|
|
232
|
+
"react/syntax": "error",
|
|
233
|
+
"react/todo": "error",
|
|
234
|
+
"react/unsupported-syntax": "error",
|
|
235
|
+
"react/use-memo": "error",
|
|
236
|
+
"react/void-use-memo": "error"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"files": ["applets/*/test/**"],
|
|
241
|
+
"plugins": ["eslint", "typescript", "unicorn", "import", "vitest"],
|
|
242
|
+
"rules": {
|
|
243
|
+
"vitest/expect-expect": [
|
|
244
|
+
"warn",
|
|
245
|
+
{ "assertFunctionNames": ["expect", "expect*", "assert", "assert.*", "assert*"] }
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
`;
|
|
252
|
+
async function oxfmtConfig(root) {
|
|
253
|
+
const appletsRoot = resolve(root, "applets");
|
|
254
|
+
const overrides = (existsSync(appletsRoot) ? await readdir(appletsRoot) : []).filter((code) => existsSync(resolve(appletsRoot, code, "src/client/styles/globals.css"))).sort().map((code) => `
|
|
255
|
+
{
|
|
256
|
+
"files": ["applets/${code}/**"],
|
|
257
|
+
"options": {
|
|
258
|
+
"sortTailwindcss": {
|
|
259
|
+
"stylesheet": "applets/${code}/src/client/styles/globals.css",
|
|
260
|
+
"functions": ["cn", "cva"]
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}`);
|
|
264
|
+
return `{
|
|
265
|
+
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
|
266
|
+
"sortImports": true,
|
|
267
|
+
"overrides": [${overrides.join(",")}${overrides.length > 0 ? "\n " : ""}]
|
|
268
|
+
}
|
|
269
|
+
`;
|
|
270
|
+
}
|
|
271
|
+
const GITIGNORE_START = "# BEGIN Hitch generated files";
|
|
272
|
+
const GITIGNORE_END = "# END Hitch generated files";
|
|
273
|
+
const SKILLS = [
|
|
274
|
+
"hitch-applets",
|
|
275
|
+
"hitch-cli",
|
|
276
|
+
"hitch-data",
|
|
277
|
+
"hitch-theory",
|
|
278
|
+
"react-best-practices",
|
|
279
|
+
"tanstack-query",
|
|
280
|
+
"tanstack-router",
|
|
281
|
+
"web-design-guidelines"
|
|
282
|
+
];
|
|
283
|
+
const GITIGNORE = `${GITIGNORE_START}
|
|
284
|
+
${SKILLS.map((skill) => `/.agents/skills/${skill}/`).join("\n")}
|
|
285
|
+
${SKILLS.map((skill) => `/.claude/skills/${skill}`).join("\n")}
|
|
286
|
+
/.node-version
|
|
287
|
+
/.oxfmtrc.json
|
|
288
|
+
/.oxlintrc.json
|
|
289
|
+
/AGENTS.md
|
|
290
|
+
/CLAUDE.md
|
|
291
|
+
/package.json
|
|
292
|
+
/pnpm-lock.yaml
|
|
293
|
+
/pnpm-workspace.yaml
|
|
294
|
+
/applets/**/components.json
|
|
295
|
+
/applets/**/index.html
|
|
296
|
+
/applets/**/package.json
|
|
297
|
+
/applets/**/tsconfig.json
|
|
298
|
+
/applets/**/tsr.config.json
|
|
299
|
+
/applets/**/vite.config.ts
|
|
300
|
+
**/.hitch/
|
|
301
|
+
**/.hitch.tmp-*/
|
|
302
|
+
**/.tanstack/
|
|
303
|
+
**/.wrangler/
|
|
304
|
+
**/dist/
|
|
305
|
+
**/node_modules/
|
|
306
|
+
${GITIGNORE_END}
|
|
307
|
+
`;
|
|
308
|
+
async function writeGitignore(root) {
|
|
309
|
+
const path = resolve(root, ".gitignore");
|
|
310
|
+
if (!existsSync(path)) {
|
|
311
|
+
await writeFile(path, `${GITIGNORE}\n# Add custom rules below.\n`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const current = await readFile(path, "utf8");
|
|
315
|
+
const start = current.indexOf(GITIGNORE_START);
|
|
316
|
+
const end = current.indexOf(GITIGNORE_END, start);
|
|
317
|
+
if (start >= 0 && end >= 0) {
|
|
318
|
+
const suffix = current.slice(end + 27).replace(/^\r?\n/, "");
|
|
319
|
+
await writeFile(path, `${current.slice(0, start)}${GITIGNORE}${suffix}`);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
await writeFile(path, `${GITIGNORE}\n${current}`);
|
|
323
|
+
}
|
|
324
|
+
async function writeWorkspaceSupport(root, config, cli) {
|
|
325
|
+
const resolvedCli = cli ?? await loadCliManifest();
|
|
326
|
+
if (resolvedCli === void 0) throw new Error("The CLI package manifest is not published.");
|
|
327
|
+
assertWorkspaceCli(config, resolvedCli);
|
|
328
|
+
await ensureAgentConfigs(root, config.org);
|
|
329
|
+
const deployWorkflowTarget = resolve(root, ".github/workflows/hitch.yml");
|
|
330
|
+
const agents = await readFile(new URL("../scaffold/AGENTS.md", import.meta.url), "utf8");
|
|
331
|
+
await Promise.all([
|
|
332
|
+
mkdir(resolve(root, ".agents/skills"), { recursive: true }),
|
|
333
|
+
mkdir(resolve(root, ".claude/skills"), { recursive: true }),
|
|
334
|
+
config.githubWorkflow === false ? void 0 : mkdir(resolve(root, ".github/workflows"), { recursive: true }),
|
|
335
|
+
...SKILLS.map((skill) => rm(resolve(root, ".agents/skills", skill), {
|
|
336
|
+
force: true,
|
|
337
|
+
recursive: true
|
|
338
|
+
}))
|
|
339
|
+
]);
|
|
340
|
+
await Promise.all([
|
|
341
|
+
...SKILLS.map((skill) => cp(new URL(`../scaffold/.agents/skills/${skill}`, import.meta.url), resolve(root, ".agents/skills", skill), { recursive: true })),
|
|
342
|
+
writeFile(resolve(root, "package.json"), `${JSON.stringify(workspacePackage(config.org), null, 2)}\n`),
|
|
343
|
+
writeFile(resolve(root, "pnpm-workspace.yaml"), workspaceFile(resolvedCli)),
|
|
344
|
+
config.githubWorkflow === false || existsSync(deployWorkflowTarget) ? void 0 : cp(new URL("../scaffold/.github/workflows/hitch.yml", import.meta.url), deployWorkflowTarget),
|
|
345
|
+
writeFile(resolve(root, ".node-version"), "24\n"),
|
|
346
|
+
writeFile(resolve(root, ".oxlintrc.json"), OXLINT_CONFIG),
|
|
347
|
+
oxfmtConfig(root).then((config) => writeFile(resolve(root, ".oxfmtrc.json"), config)),
|
|
348
|
+
writeGitignore(root),
|
|
349
|
+
writeFile(resolve(root, "AGENTS.md"), agents)
|
|
350
|
+
]);
|
|
351
|
+
await rm(resolve(root, "CLAUDE.md"), { force: true });
|
|
352
|
+
await symlink("AGENTS.md", resolve(root, "CLAUDE.md"));
|
|
353
|
+
await Promise.all(SKILLS.map(async (skill) => {
|
|
354
|
+
const target = resolve(root, ".claude/skills", skill);
|
|
355
|
+
await rm(target, { force: true });
|
|
356
|
+
await symlink(`../../.agents/skills/${skill}`, target, "dir");
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
function sortedByName(packages) {
|
|
360
|
+
return Object.fromEntries(Object.entries(packages).sort(([a], [b]) => a < b ? -1 : 1));
|
|
361
|
+
}
|
|
362
|
+
function appletPackage(definition, options) {
|
|
363
|
+
return {
|
|
364
|
+
name: definition.code.replaceAll("_", "-"),
|
|
365
|
+
private: true,
|
|
366
|
+
type: "module",
|
|
367
|
+
scripts: {
|
|
368
|
+
dev: "vite",
|
|
369
|
+
build: "applet build",
|
|
370
|
+
generate: "applet generate",
|
|
371
|
+
deploy: "applet deploy",
|
|
372
|
+
test: "vitest run",
|
|
373
|
+
typecheck: "tsc --noEmit",
|
|
374
|
+
lint: "oxlint",
|
|
375
|
+
fmt: "oxfmt",
|
|
376
|
+
check: "oxfmt --check && oxlint"
|
|
377
|
+
},
|
|
378
|
+
dependencies: sortedByName({
|
|
379
|
+
"@hitch42/applet": "catalog:",
|
|
380
|
+
"@orpc/contract": "catalog:",
|
|
381
|
+
zod: "catalog:",
|
|
382
|
+
...options.hasServer ? { "@orpc/server": "catalog:" } : {},
|
|
383
|
+
...options.hasClient ? {
|
|
384
|
+
"@fontsource-variable/inter": "catalog:",
|
|
385
|
+
"@tanstack/react-query": "catalog:",
|
|
386
|
+
"@tanstack/react-router": "catalog:",
|
|
387
|
+
"@tiptap/core": "catalog:",
|
|
388
|
+
"@tiptap/extension-image": "catalog:",
|
|
389
|
+
"@tiptap/extension-list": "catalog:",
|
|
390
|
+
"@tiptap/extension-table": "catalog:",
|
|
391
|
+
"@tiptap/extensions": "catalog:",
|
|
392
|
+
"@tiptap/markdown": "catalog:",
|
|
393
|
+
"@tiptap/react": "catalog:",
|
|
394
|
+
"@tiptap/starter-kit": "catalog:",
|
|
395
|
+
"class-variance-authority": "catalog:",
|
|
396
|
+
cn: "catalog:",
|
|
397
|
+
"lucide-react": "catalog:",
|
|
398
|
+
react: "catalog:",
|
|
399
|
+
"react-aria-components": "catalog:",
|
|
400
|
+
"react-dom": "catalog:",
|
|
401
|
+
shadcn: "catalog:",
|
|
402
|
+
streamdown: "catalog:",
|
|
403
|
+
"tw-animate-css": "catalog:"
|
|
404
|
+
} : {},
|
|
405
|
+
...definition.dependencies
|
|
406
|
+
}),
|
|
407
|
+
devDependencies: sortedByName({
|
|
408
|
+
"@types/node": "catalog:",
|
|
409
|
+
typescript: "catalog:",
|
|
410
|
+
vite: "catalog:",
|
|
411
|
+
vitest: "catalog:",
|
|
412
|
+
...options.hasClient ? {
|
|
413
|
+
"@tailwindcss/vite": "catalog:",
|
|
414
|
+
"@types/react": "catalog:",
|
|
415
|
+
"@types/react-dom": "catalog:",
|
|
416
|
+
tailwindcss: "catalog:"
|
|
417
|
+
} : {},
|
|
418
|
+
...definition.devDependencies
|
|
419
|
+
})
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const LEGACY_CN_HELPER = `import { clsx, type ClassValue } from "clsx";
|
|
423
|
+
import { twMerge } from "tailwind-merge";
|
|
424
|
+
|
|
425
|
+
export function cn(...inputs: ClassValue[]) {
|
|
426
|
+
return twMerge(clsx(inputs));
|
|
427
|
+
}
|
|
428
|
+
`;
|
|
429
|
+
async function replaceLegacyCnHelper(root) {
|
|
430
|
+
const path = resolve(root, "src/client/lib/utils.ts");
|
|
431
|
+
if (!existsSync(path) || await readFile(path, "utf8") !== LEGACY_CN_HELPER) return;
|
|
432
|
+
await cp(new URL("../scaffold/applet/src/client/lib/utils.ts", import.meta.url), path);
|
|
433
|
+
}
|
|
434
|
+
async function writeAppletSupport(root, definition) {
|
|
435
|
+
const hasClient = existsSync(resolve(root, "src/client/routes"));
|
|
436
|
+
const hasAuthorRoot = existsSync(resolve(root, "src/client/routes/__root.tsx"));
|
|
437
|
+
const hasServer = existsSync(resolve(root, "src/server/main.ts"));
|
|
438
|
+
if (!hasClient && !hasServer) throw new Error("An applet must have client routes, a server entry, or both.");
|
|
439
|
+
if (!hasServer && (definition.schedules?.length ?? 0) > 0) throw new Error("An applet with schedules must have src/server/main.ts.");
|
|
440
|
+
await Promise.all(hasClient ? [] : [rm(resolve(root, "index.html"), { force: true }), rm(resolve(root, "components.json"), { force: true })]);
|
|
441
|
+
await Promise.all([
|
|
442
|
+
replaceLegacyCnHelper(root),
|
|
443
|
+
writeFile(resolve(root, "package.json"), `${JSON.stringify(appletPackage(definition, {
|
|
444
|
+
hasClient,
|
|
445
|
+
hasServer
|
|
446
|
+
}), null, 2)}\n`),
|
|
447
|
+
writeFile(resolve(root, "vite.config.ts"), `import { resolve } from "node:path";
|
|
448
|
+
|
|
449
|
+
import { applet } from "@hitch42/applet/vite";
|
|
450
|
+
${hasClient ? "import tailwindcss from \"@tailwindcss/vite\";\n" : ""}import { defineConfig } from "vite";
|
|
451
|
+
|
|
452
|
+
import manifest from "./applet.manifest.ts";
|
|
453
|
+
|
|
454
|
+
export default defineConfig({
|
|
455
|
+
plugins: [applet(manifest)${hasClient ? ", tailwindcss()" : ""}],
|
|
456
|
+
resolve: {
|
|
457
|
+
alias: { "@": resolve(import.meta.dirname, "./src") },
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
`),
|
|
461
|
+
hasClient ? writeFile(resolve(root, "tsr.config.json"), `${JSON.stringify({
|
|
462
|
+
routesDirectory: "./src/client/routes",
|
|
463
|
+
generatedRouteTree: "./.hitch/routeTree.gen.ts",
|
|
464
|
+
routeFileIgnorePattern: "__root",
|
|
465
|
+
virtualRouteConfig: {
|
|
466
|
+
type: "root",
|
|
467
|
+
file: hasAuthorRoot ? "__root.tsx" : relative(resolve(root, "src/client/routes"), resolve(root, ".hitch/appletRoot.gen.tsx")),
|
|
468
|
+
children: [{
|
|
469
|
+
type: "physical",
|
|
470
|
+
directory: ".",
|
|
471
|
+
pathPrefix: definition.code
|
|
472
|
+
}]
|
|
473
|
+
}
|
|
474
|
+
}, null, 2)}\n`) : rm(resolve(root, "tsr.config.json"), { force: true }),
|
|
475
|
+
hasClient ? writeFile(resolve(root, "index.html"), `<!doctype html>
|
|
476
|
+
<html lang="en">
|
|
477
|
+
<head>
|
|
478
|
+
<meta charset="UTF-8" />
|
|
479
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
480
|
+
<link rel="stylesheet" href="/theme.css" vite-ignore />
|
|
481
|
+
<title>${definition.name}</title>
|
|
482
|
+
</head>
|
|
483
|
+
<body>
|
|
484
|
+
<div id="root"></div>
|
|
485
|
+
<script type="module" src="/.hitch/entry.gen.tsx"><\/script>
|
|
486
|
+
</body>
|
|
487
|
+
</html>
|
|
488
|
+
`) : void 0,
|
|
489
|
+
writeFile(resolve(root, "tsconfig.json"), `{
|
|
490
|
+
"compilerOptions": {
|
|
491
|
+
"noEmit": true,
|
|
492
|
+
"strict": true,
|
|
493
|
+
"noUncheckedIndexedAccess": true,
|
|
494
|
+
"skipLibCheck": true,
|
|
495
|
+
"target": "ES2022",
|
|
496
|
+
"module": "preserve",
|
|
497
|
+
"moduleDetection": "force",
|
|
498
|
+
"isolatedModules": true,
|
|
499
|
+
"verbatimModuleSyntax": true,
|
|
500
|
+
"resolveJsonModule": true,
|
|
501
|
+
"allowImportingTsExtensions": true,
|
|
502
|
+
"jsx": "react-jsx",
|
|
503
|
+
"types": ["vite/client", "node"],
|
|
504
|
+
"paths": {
|
|
505
|
+
"@/*": ["./src/*"]
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
"include": [
|
|
509
|
+
"./vite.config.ts",
|
|
510
|
+
"./applet.manifest.ts",
|
|
511
|
+
"./.hitch/*.ts",
|
|
512
|
+
"./.hitch/*.tsx",
|
|
513
|
+
"./src/**/*.ts",
|
|
514
|
+
"./src/**/*.tsx",
|
|
515
|
+
"./test/**/*.ts",
|
|
516
|
+
"./test/**/*.tsx"
|
|
517
|
+
]
|
|
518
|
+
}
|
|
519
|
+
`),
|
|
520
|
+
hasClient ? writeFile(resolve(root, "components.json"), await readFile(new URL("../scaffold/applet/components.json", import.meta.url), "utf8")) : void 0
|
|
521
|
+
]);
|
|
522
|
+
}
|
|
523
|
+
async function prepareAppletProjects(workspaceRoot, appletRoots) {
|
|
524
|
+
const definitions = await Promise.all(appletRoots.map((root) => loadAppletSourceDefinition(root)));
|
|
525
|
+
const workspace = readWorkspaceConfig(workspaceRoot);
|
|
526
|
+
if (workspace === void 0) throw new Error(`No Hitch workspace found at ${workspaceRoot}.`);
|
|
527
|
+
const cli = await loadCliManifest({ allowDevelopment: true });
|
|
528
|
+
await Promise.all([cli === void 0 ? void 0 : writeWorkspaceSupport(workspaceRoot, workspace, cli), ...appletRoots.map((root, index) => writeAppletSupport(root, definitions[index]))]);
|
|
529
|
+
}
|
|
530
|
+
async function prepareAppletProject(appletRoot = process.cwd()) {
|
|
531
|
+
const workspaceRoot = dirname(dirname(resolve(appletRoot)));
|
|
532
|
+
await prepareAppletProjects(workspaceRoot, [appletRoot]);
|
|
533
|
+
return workspaceRoot;
|
|
534
|
+
}
|
|
535
|
+
//#endregion
|
|
536
|
+
export { writeAppletSupport as a, prepareAppletProjects as i, loadCliManifest as n, writeWorkspaceSupport as o, prepareAppletProject as r, assertWorkspaceCli as t };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Writable } from "node:stream";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
//#region src/prompt.ts
|
|
4
|
+
function question(prompt, hidden = false) {
|
|
5
|
+
return new Promise((resolveAnswer, rejectAnswer) => {
|
|
6
|
+
let muted = false;
|
|
7
|
+
const output = hidden ? new Writable({ write(chunk, encoding, callback) {
|
|
8
|
+
if (!muted) process.stdout.write(chunk, encoding);
|
|
9
|
+
callback();
|
|
10
|
+
} }) : process.stdout;
|
|
11
|
+
const readline = createInterface({
|
|
12
|
+
input: process.stdin,
|
|
13
|
+
output,
|
|
14
|
+
terminal: true
|
|
15
|
+
});
|
|
16
|
+
readline.once("error", rejectAnswer);
|
|
17
|
+
if (hidden) {
|
|
18
|
+
process.stdout.write(prompt);
|
|
19
|
+
muted = true;
|
|
20
|
+
}
|
|
21
|
+
readline.question(hidden ? "" : prompt, (answer) => {
|
|
22
|
+
readline.close();
|
|
23
|
+
if (hidden) process.stdout.write("\n");
|
|
24
|
+
resolveAnswer(answer);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { question as t };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/internal/query-cache.ts
|
|
2
|
+
const STORE = "clients";
|
|
3
|
+
const TIMESTAMP_INDEX = "timestamp";
|
|
4
|
+
const TAB_KEY = "hitch:query-tab";
|
|
5
|
+
const SAVE_INTERVAL = 1e3;
|
|
6
|
+
function openQueryCacheDatabase() {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const open = indexedDB.open("hitch-query-cache", 1);
|
|
9
|
+
open.onupgradeneeded = () => {
|
|
10
|
+
open.result.createObjectStore("clients").createIndex("timestamp", "timestamp");
|
|
11
|
+
};
|
|
12
|
+
open.onblocked = () => reject(/* @__PURE__ */ new Error("The query cache is open in an older tab."));
|
|
13
|
+
open.onsuccess = () => {
|
|
14
|
+
open.result.onversionchange = () => open.result.close();
|
|
15
|
+
resolve(open.result);
|
|
16
|
+
};
|
|
17
|
+
open.onerror = () => reject(open.error);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
let database;
|
|
21
|
+
function openCacheDatabase() {
|
|
22
|
+
database ??= window.__hitchCacheDatabase ?? openQueryCacheDatabase();
|
|
23
|
+
return database;
|
|
24
|
+
}
|
|
25
|
+
async function inStore(mode, run) {
|
|
26
|
+
const transaction = (await openCacheDatabase()).transaction(STORE, mode);
|
|
27
|
+
const request = run(transaction.objectStore(STORE));
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
transaction.oncomplete = () => resolve(request.result);
|
|
30
|
+
transaction.onabort = () => reject(transaction.error ?? request.error);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function cacheTabId() {
|
|
34
|
+
const existing = sessionStorage.getItem(TAB_KEY);
|
|
35
|
+
if (existing) return existing;
|
|
36
|
+
const id = crypto.randomUUID();
|
|
37
|
+
sessionStorage.setItem(TAB_KEY, id);
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
function indexedDbPersister(key) {
|
|
41
|
+
let pending;
|
|
42
|
+
let throttled = false;
|
|
43
|
+
const save = (client) => inStore("readwrite", (store) => store.put(client, key)).then(() => void 0, (error) => console.error("Could not persist the applet query cache.", error));
|
|
44
|
+
const release = () => {
|
|
45
|
+
if (!pending) {
|
|
46
|
+
throttled = false;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
save(pending);
|
|
50
|
+
pending = void 0;
|
|
51
|
+
setTimeout(release, SAVE_INTERVAL);
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
persistClient: (client) => {
|
|
55
|
+
if (throttled) {
|
|
56
|
+
pending = client;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
throttled = true;
|
|
60
|
+
setTimeout(release, SAVE_INTERVAL);
|
|
61
|
+
return save(client);
|
|
62
|
+
},
|
|
63
|
+
restoreClient: () => inStore("readonly", (store) => store.get(key)),
|
|
64
|
+
removeClient: () => inStore("readwrite", (store) => store.delete(key))
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function sweepExpiredQueryCaches(maxAge) {
|
|
68
|
+
return inStore("readwrite", (store) => {
|
|
69
|
+
const cursor = store.index(TIMESTAMP_INDEX).openKeyCursor(IDBKeyRange.upperBound(Date.now() - maxAge));
|
|
70
|
+
cursor.onsuccess = () => {
|
|
71
|
+
if (!cursor.result) return;
|
|
72
|
+
store.delete(cursor.result.primaryKey);
|
|
73
|
+
cursor.result.continue();
|
|
74
|
+
};
|
|
75
|
+
return cursor;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function clearAppletQueryCaches(appletCode) {
|
|
79
|
+
return inStore("readwrite", (store) => store.delete(IDBKeyRange.bound(`${appletCode}:`, `${appletCode}:\uffff`)));
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { openQueryCacheDatabase as a, openCacheDatabase as i, clearAppletQueryCaches as n, sweepExpiredQueryCaches as o, indexedDbPersister as r, cacheTabId as t };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { a as UploadedHitchFile } from "./upload-DKZzz5kW.js";
|
|
2
|
+
import { ReactElement } from "react";
|
|
3
|
+
import "@tiptap/core";
|
|
4
|
+
//#region src/react/markdown.d.ts
|
|
5
|
+
type MarkdownFiles = {
|
|
6
|
+
download: (id: string) => Promise<Pick<UploadedHitchFile, "downloadUrl">>;
|
|
7
|
+
};
|
|
8
|
+
type MarkdownProps = {
|
|
9
|
+
children: string;
|
|
10
|
+
files?: MarkdownFiles;
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
declare function Markdown({ children, files, className }: MarkdownProps): ReactElement;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/react/markdown-editor-extensions.d.ts
|
|
16
|
+
type MarkdownEditorFiles = {
|
|
17
|
+
upload: (file: File) => Promise<Pick<UploadedHitchFile, "id" | "downloadUrl">>;
|
|
18
|
+
download: (id: string) => Promise<Pick<UploadedHitchFile, "downloadUrl">>;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/react/markdown-editor.d.ts
|
|
22
|
+
type MarkdownEditorProps = {
|
|
23
|
+
value: string;
|
|
24
|
+
onChange: (value: string) => void;
|
|
25
|
+
files?: MarkdownEditorFiles;
|
|
26
|
+
id?: string;
|
|
27
|
+
placeholder?: string;
|
|
28
|
+
required?: boolean;
|
|
29
|
+
minLength?: number;
|
|
30
|
+
maxLength?: number;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
className?: string;
|
|
33
|
+
onUploadError?: (error: unknown, file: File) => void;
|
|
34
|
+
};
|
|
35
|
+
declare function MarkdownEditor({ value, onChange, files, id, placeholder, required, minLength, maxLength, disabled, className, onUploadError }: MarkdownEditorProps): ReactElement;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { Markdown, MarkdownEditor, type MarkdownEditorFiles, type MarkdownEditorProps, type MarkdownFiles, type MarkdownProps };
|