@hitch42/applet 0.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/dist/_internal/client.d.ts +7 -0
  3. package/dist/_internal/client.js +60 -0
  4. package/dist/_internal/server.d.ts +79 -0
  5. package/dist/_internal/server.js +232 -0
  6. package/dist/applet.d.ts +1 -0
  7. package/dist/applet.js +160 -0
  8. package/dist/auth-DaVK0k5R.js +350 -0
  9. package/dist/batch-Qa4B4-Yp.d.ts +30 -0
  10. package/dist/build-BRkmrUcj.js +74 -0
  11. package/dist/build-CMluoV6q.js +2 -0
  12. package/dist/client.d.ts +48 -0
  13. package/dist/client.js +38 -0
  14. package/dist/contract-DMrpbaLJ.d.ts +23 -0
  15. package/dist/deploy-DKB-Tef7.js +2416 -0
  16. package/dist/generate-BFmIzHaR.js +484 -0
  17. package/dist/generate-CefnB-bp.js +2 -0
  18. package/dist/index.d.ts +74 -0
  19. package/dist/index.js +136 -0
  20. package/dist/init-CQRsnd3i.js +240 -0
  21. package/dist/lazy-client-x0DCI98S.js +64 -0
  22. package/dist/load-config-BnxocLAQ.js +56 -0
  23. package/dist/logs-m00pzr_O.js +183 -0
  24. package/dist/manifest-BQCAxATS.d.ts +81 -0
  25. package/dist/manifest-DyoJ1MIL.js +174 -0
  26. package/dist/project-CEmDnlKa.js +346 -0
  27. package/dist/react.d.ts +37 -0
  28. package/dist/react.js +517 -0
  29. package/dist/server.d.ts +46 -0
  30. package/dist/server.js +104 -0
  31. package/dist/upload-DRbVhuDm.js +114 -0
  32. package/dist/upload-YbRKEqR6.d.ts +112 -0
  33. package/dist/variables-CP7Ce3Np.js +133 -0
  34. package/dist/vite.d.ts +63 -0
  35. package/dist/vite.js +358 -0
  36. package/dist/workflow-CTo2kZF1.js +51 -0
  37. package/dist/workflow-DurM6Fwx.d.ts +28 -0
  38. package/package.json +104 -0
  39. package/scaffold/.agents/skills/hitch-applets/SKILL.md +137 -0
  40. package/scaffold/.agents/skills/hitch-applets/references/client.md +73 -0
  41. package/scaffold/.agents/skills/hitch-applets/references/files.md +109 -0
  42. package/scaffold/.agents/skills/hitch-applets/references/manifest.md +171 -0
  43. package/scaffold/.agents/skills/hitch-applets/references/markdown.md +37 -0
  44. package/scaffold/.agents/skills/hitch-applets/references/records.md +152 -0
  45. package/scaffold/.agents/skills/hitch-applets/references/schedules.md +86 -0
  46. package/scaffold/.agents/skills/hitch-applets/references/server.md +98 -0
  47. package/scaffold/.agents/skills/hitch-applets/references/workflows.md +73 -0
  48. package/scaffold/AGENTS.md +38 -0
  49. package/scaffold/applet/components.json +25 -0
  50. package/scaffold/applet/src/client/components/ui/alert.tsx +73 -0
  51. package/scaffold/applet/src/client/components/ui/avatar.tsx +100 -0
  52. package/scaffold/applet/src/client/components/ui/badge.tsx +55 -0
  53. package/scaffold/applet/src/client/components/ui/button.tsx +90 -0
  54. package/scaffold/applet/src/client/components/ui/card.tsx +85 -0
  55. package/scaffold/applet/src/client/components/ui/checkbox.tsx +35 -0
  56. package/scaffold/applet/src/client/components/ui/dialog.tsx +164 -0
  57. package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +235 -0
  58. package/scaffold/applet/src/client/components/ui/input-group.tsx +144 -0
  59. package/scaffold/applet/src/client/components/ui/input.tsx +22 -0
  60. package/scaffold/applet/src/client/components/ui/label.tsx +29 -0
  61. package/scaffold/applet/src/client/components/ui/popover.tsx +74 -0
  62. package/scaffold/applet/src/client/components/ui/select.tsx +243 -0
  63. package/scaffold/applet/src/client/components/ui/separator.tsx +25 -0
  64. package/scaffold/applet/src/client/components/ui/sheet.tsx +177 -0
  65. package/scaffold/applet/src/client/components/ui/skeleton.tsx +13 -0
  66. package/scaffold/applet/src/client/components/ui/spinner.tsx +16 -0
  67. package/scaffold/applet/src/client/components/ui/switch.tsx +41 -0
  68. package/scaffold/applet/src/client/components/ui/table.tsx +114 -0
  69. package/scaffold/applet/src/client/components/ui/tabs.tsx +78 -0
  70. package/scaffold/applet/src/client/components/ui/textarea.tsx +23 -0
  71. package/scaffold/applet/src/client/lib/utils.ts +6 -0
  72. package/scaffold/applet/src/client/styles/globals.css +136 -0
@@ -0,0 +1,81 @@
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
+ schedules?: readonly {
36
+ code: string;
37
+ name: string;
38
+ cron: string;
39
+ path: string;
40
+ }[];
41
+ variables?: Readonly<Record<string, {
42
+ secret?: boolean;
43
+ optional?: boolean;
44
+ }>>;
45
+ objects: readonly {
46
+ code: string;
47
+ canCreate: boolean;
48
+ canDelete: boolean;
49
+ readOnly: readonly string[];
50
+ readWrite: readonly string[];
51
+ }[];
52
+ }
53
+ type AppletDefinition = Omit<AppletManifest, "org">;
54
+ type AppletManifestObject = AppletManifest["objects"][number];
55
+ interface AppletPackages {
56
+ dependencies?: Readonly<Record<string, string>>;
57
+ devDependencies?: Readonly<Record<string, string>>;
58
+ }
59
+ type AppletSourceDefinition = AppletDefinition & AppletPackages;
60
+ declare const appletManifestSchema: z.ZodType<AppletManifest>;
61
+ declare const appletDefinitionSchema: z.ZodType<AppletDefinition>;
62
+ declare const appletSourceDefinitionSchema: z.ZodType<AppletSourceDefinition>;
63
+ type RegisteredAppletManifestObject = { [Code in keyof RegisteredCatalog]: Omit<AppletManifestObject, "code" | "readOnly" | "readWrite"> & {
64
+ code: Code;
65
+ readOnly: readonly RegisteredCatalog[Code][];
66
+ readWrite: readonly RegisteredCatalog[Code][];
67
+ }; }[keyof RegisteredCatalog];
68
+ 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];
69
+ type RegisteredSchedulePath = HitchRegister extends {
70
+ router: infer R extends AnyRouter;
71
+ } ? RouterSchedulePaths<R> : string;
72
+ type RegisteredAppletManifest = Omit<AppletManifest, "objects" | "schedules"> & {
73
+ schedules?: readonly (Omit<NonNullable<AppletManifest["schedules"]>[number], "path"> & {
74
+ path: RegisteredSchedulePath;
75
+ })[];
76
+ objects: readonly RegisteredAppletManifestObject[];
77
+ };
78
+ type RegisteredAppletDefinition = Omit<RegisteredAppletManifest, "org">;
79
+ type RegisteredAppletSourceDefinition = RegisteredAppletDefinition & AppletPackages;
80
+ //#endregion
81
+ 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,174 @@
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
+ }).superRefine((object, context) => {
36
+ const overlap = object.readOnly.find((code) => object.readWrite.includes(code));
37
+ if (overlap !== void 0) context.addIssue({
38
+ code: "custom",
39
+ message: `readOnly and readWrite both contain "${overlap}".`
40
+ });
41
+ });
42
+ const appletManifestObjectsSchema = z.array(appletManifestObjectSchema).readonly();
43
+ const appletManifestSchedulesSchema = z.array(z.strictObject({
44
+ code: codeSchema,
45
+ name: nameSchema,
46
+ cron: z.string().refine((value) => {
47
+ if (value.trim().split(/\s+/).length !== 5) return false;
48
+ try {
49
+ new Cron(value);
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
54
+ }, "must be a valid 5-field cron expression (minute hour day-of-month month day-of-week)"),
55
+ path: z.string().startsWith("/", "must start with \"/\"").refine((path) => !path.startsWith("//"), "must not start with \"//\"").refine((path) => !/\s/.test(path), "must not contain whitespace")
56
+ })).readonly();
57
+ 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);
58
+ const appletManifestVariablesSchema = z.record(appletVariableKeySchema, z.strictObject({
59
+ secret: z.boolean().optional(),
60
+ optional: z.boolean().optional()
61
+ })).readonly();
62
+ const appletManifestShape = {
63
+ 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"),
64
+ name: nameSchema,
65
+ code: codeSchema,
66
+ schedules: appletManifestSchedulesSchema.optional(),
67
+ variables: appletManifestVariablesSchema.optional(),
68
+ objects: appletManifestObjectsSchema
69
+ };
70
+ const checkDuplicateCodes = (manifest, context) => {
71
+ const duplicateIndex = manifest.objects.findIndex(({ code }, index) => manifest.objects.findIndex((object) => object.code === code) !== index);
72
+ if (duplicateIndex !== -1) context.addIssue({
73
+ code: "custom",
74
+ message: `Duplicate object code "${manifest.objects[duplicateIndex]?.code}".`,
75
+ path: [
76
+ "objects",
77
+ duplicateIndex,
78
+ "code"
79
+ ]
80
+ });
81
+ const schedules = manifest.schedules ?? [];
82
+ const duplicateScheduleIndex = schedules.findIndex(({ code }, index) => schedules.findIndex((schedule) => schedule.code === code) !== index);
83
+ if (duplicateScheduleIndex !== -1) context.addIssue({
84
+ code: "custom",
85
+ message: `Duplicate schedule code "${schedules[duplicateScheduleIndex]?.code}".`,
86
+ path: [
87
+ "schedules",
88
+ duplicateScheduleIndex,
89
+ "code"
90
+ ]
91
+ });
92
+ };
93
+ const appletManifestSchema = z.strictObject(appletManifestShape).superRefine(checkDuplicateCodes);
94
+ const appletDefinitionSchema = z.strictObject({
95
+ name: appletManifestShape.name,
96
+ code: appletManifestShape.code,
97
+ schedules: appletManifestShape.schedules,
98
+ variables: appletManifestShape.variables,
99
+ objects: appletManifestShape.objects
100
+ }).superRefine(checkDuplicateCodes);
101
+ const packageVersionsSchema = z.record(z.string().min(1), z.string().min(1)).readonly();
102
+ const RESERVED_APPLET_PACKAGES = /* @__PURE__ */ new Set([
103
+ "@fontsource-variable/inter",
104
+ "@hitch42/applet",
105
+ "@orpc/contract",
106
+ "@orpc/server",
107
+ "@tailwindcss/vite",
108
+ "@tanstack/react-query",
109
+ "@tanstack/react-router",
110
+ "@tiptap/core",
111
+ "@tiptap/extension-image",
112
+ "@tiptap/extension-list",
113
+ "@tiptap/extension-table",
114
+ "@tiptap/extensions",
115
+ "@tiptap/markdown",
116
+ "@tiptap/react",
117
+ "@tiptap/starter-kit",
118
+ "@types/node",
119
+ "@types/react",
120
+ "@types/react-dom",
121
+ "class-variance-authority",
122
+ "clsx",
123
+ "lucide-react",
124
+ "react",
125
+ "react-aria-components",
126
+ "react-dom",
127
+ "shadcn",
128
+ "streamdown",
129
+ "tailwind-merge",
130
+ "tailwindcss",
131
+ "tw-animate-css",
132
+ "typescript",
133
+ "vite",
134
+ "vitest",
135
+ "zod"
136
+ ]);
137
+ const checkSourcePackages = (manifest, context) => {
138
+ const dependencies = Object.keys(manifest.dependencies ?? {});
139
+ const devDependencies = new Set(Object.keys(manifest.devDependencies ?? {}));
140
+ [{
141
+ field: "dependencies",
142
+ names: dependencies
143
+ }, {
144
+ field: "devDependencies",
145
+ names: [...devDependencies]
146
+ }].forEach(({ field, names }) => names.forEach((name) => {
147
+ if (RESERVED_APPLET_PACKAGES.has(name)) context.addIssue({
148
+ code: "custom",
149
+ message: `Package "${name}" is managed by the applet CLI.`,
150
+ path: [field, name]
151
+ });
152
+ }));
153
+ dependencies.filter((name) => devDependencies.has(name)).forEach((name) => {
154
+ context.addIssue({
155
+ code: "custom",
156
+ message: `Package "${name}" cannot be in both dependencies and devDependencies.`,
157
+ path: ["devDependencies", name]
158
+ });
159
+ });
160
+ };
161
+ const appletSourceDefinitionSchema = z.strictObject({
162
+ name: appletManifestShape.name,
163
+ code: appletManifestShape.code,
164
+ schedules: appletManifestShape.schedules,
165
+ variables: appletManifestShape.variables,
166
+ objects: appletManifestShape.objects,
167
+ dependencies: packageVersionsSchema.optional(),
168
+ devDependencies: packageVersionsSchema.optional()
169
+ }).superRefine((manifest, context) => {
170
+ checkDuplicateCodes(manifest, context);
171
+ checkSourcePackages(manifest, context);
172
+ });
173
+ //#endregion
174
+ export { ORG_CODE_PATTERN as a, APPLET_CODE_PATTERN as i, appletManifestSchema as n, appletSourceDefinitionSchema as r, appletDefinitionSchema as t };
@@ -0,0 +1,346 @@
1
+ import { n as loadAppletSourceDefinition, r as readWorkspaceConfig } from "./load-config-BnxocLAQ.js";
2
+ import { z } from "zod";
3
+ import { existsSync } from "node:fs";
4
+ import { cp, mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
5
+ import { dirname, relative, resolve } from "node:path";
6
+ //#region src/project.ts
7
+ const PACKAGE_MANAGER = "pnpm@11.18.0+sha512.33d83c77da82f49fba836925c6f1b841181ec3132b670639bd012f7075f5c7cf634c5f870147c19aae7478fac01df09d8892e880454896edd23ee9b33757563c";
8
+ const cliManifestValueSchema = z.string().min(1, "must be a non-empty string");
9
+ const cliManifestSchema = z.object({
10
+ name: cliManifestValueSchema,
11
+ version: cliManifestValueSchema,
12
+ dependencies: z.object({
13
+ "@fontsource-variable/inter": cliManifestValueSchema,
14
+ "@orpc/contract": cliManifestValueSchema,
15
+ "@tiptap/core": cliManifestValueSchema,
16
+ "@tiptap/extension-image": cliManifestValueSchema,
17
+ "@tiptap/extension-list": cliManifestValueSchema,
18
+ "@tiptap/extension-table": cliManifestValueSchema,
19
+ "@tiptap/extensions": cliManifestValueSchema,
20
+ "@tiptap/markdown": cliManifestValueSchema,
21
+ "@tiptap/react": cliManifestValueSchema,
22
+ "@tiptap/starter-kit": cliManifestValueSchema,
23
+ "@tailwindcss/vite": cliManifestValueSchema,
24
+ "@tanstack/router-cli": cliManifestValueSchema,
25
+ "class-variance-authority": cliManifestValueSchema,
26
+ clsx: cliManifestValueSchema,
27
+ "lucide-react": cliManifestValueSchema,
28
+ "react-aria-components": cliManifestValueSchema,
29
+ shadcn: cliManifestValueSchema,
30
+ streamdown: cliManifestValueSchema,
31
+ "tailwind-merge": cliManifestValueSchema,
32
+ tailwindcss: cliManifestValueSchema,
33
+ "tw-animate-css": cliManifestValueSchema,
34
+ vite: cliManifestValueSchema,
35
+ vitest: cliManifestValueSchema,
36
+ zod: cliManifestValueSchema
37
+ }),
38
+ peerDependencies: z.object({
39
+ "@orpc/server": cliManifestValueSchema,
40
+ "@tanstack/react-query": cliManifestValueSchema,
41
+ "@tanstack/react-router": cliManifestValueSchema,
42
+ "@types/node": cliManifestValueSchema,
43
+ "@types/react": cliManifestValueSchema,
44
+ "@types/react-dom": cliManifestValueSchema,
45
+ react: cliManifestValueSchema,
46
+ "react-dom": cliManifestValueSchema,
47
+ typescript: cliManifestValueSchema
48
+ })
49
+ });
50
+ async function loadCliManifest(options) {
51
+ const result = cliManifestSchema.safeParse(JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")));
52
+ if (!result.success) {
53
+ const issue = result.error.issues[0];
54
+ if (issue === void 0) throw new Error("Invalid CLI package manifest.");
55
+ throw new Error(`Invalid CLI package manifest field "${issue.path.join(".")}": ${issue.message}.`);
56
+ }
57
+ 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:"));
58
+ if (catalogEntry !== void 0) {
59
+ if (options?.allowDevelopment === true) return void 0;
60
+ throw new Error(`Invalid CLI package manifest field "${catalogEntry[0]}": "catalog:" identifies an unpublished development build. Run the published @hitch42/applet CLI instead.`);
61
+ }
62
+ return result.data;
63
+ }
64
+ function assertWorkspaceCli(config, cli) {
65
+ const runningCli = `${cli.name}@${cli.version}`;
66
+ if (config.sdk !== runningCli) throw new Error(`This workspace requires ${config.sdk}, but this command uses ${runningCli}. Run pnpm dlx ${config.sdk} bootstrap.`);
67
+ }
68
+ function workspacePackage(org) {
69
+ return {
70
+ name: `${org.replaceAll("_", "-")}-applets`,
71
+ private: true,
72
+ type: "module",
73
+ devDependencies: {
74
+ "@hitch42/applet": "catalog:",
75
+ typescript: "catalog:",
76
+ vite: "catalog:",
77
+ vitest: "catalog:"
78
+ },
79
+ packageManager: PACKAGE_MANAGER
80
+ };
81
+ }
82
+ function workspaceFile(cli) {
83
+ return `packages:
84
+ - applets/*
85
+ catalog:
86
+ "@hitch42/applet": npm:${cli.name}@${cli.version}
87
+ "@fontsource-variable/inter": "${cli.dependencies["@fontsource-variable/inter"]}"
88
+ "@orpc/contract": "${cli.dependencies["@orpc/contract"]}"
89
+ "@orpc/server": "${cli.peerDependencies["@orpc/server"]}"
90
+ "@tiptap/core": "${cli.dependencies["@tiptap/core"]}"
91
+ "@tiptap/extension-image": "${cli.dependencies["@tiptap/extension-image"]}"
92
+ "@tiptap/extension-list": "${cli.dependencies["@tiptap/extension-list"]}"
93
+ "@tiptap/extension-table": "${cli.dependencies["@tiptap/extension-table"]}"
94
+ "@tiptap/extensions": "${cli.dependencies["@tiptap/extensions"]}"
95
+ "@tiptap/markdown": "${cli.dependencies["@tiptap/markdown"]}"
96
+ "@tiptap/react": "${cli.dependencies["@tiptap/react"]}"
97
+ "@tiptap/starter-kit": "${cli.dependencies["@tiptap/starter-kit"]}"
98
+ "@tanstack/react-query": "${cli.peerDependencies["@tanstack/react-query"]}"
99
+ "@tanstack/react-router": "${cli.peerDependencies["@tanstack/react-router"]}"
100
+ "@tanstack/router-cli": "${cli.dependencies["@tanstack/router-cli"]}"
101
+ "@types/node": "${cli.peerDependencies["@types/node"]}"
102
+ "@types/react": "${cli.peerDependencies["@types/react"]}"
103
+ "@types/react-dom": "${cli.peerDependencies["@types/react-dom"]}"
104
+ "@tailwindcss/vite": "${cli.dependencies["@tailwindcss/vite"]}"
105
+ class-variance-authority: "${cli.dependencies["class-variance-authority"]}"
106
+ clsx: "${cli.dependencies.clsx}"
107
+ lucide-react: "${cli.dependencies["lucide-react"]}"
108
+ react: "${cli.peerDependencies.react}"
109
+ react-aria-components: "${cli.dependencies["react-aria-components"]}"
110
+ react-dom: "${cli.peerDependencies["react-dom"]}"
111
+ shadcn: "${cli.dependencies.shadcn}"
112
+ streamdown: "${cli.dependencies.streamdown}"
113
+ tailwind-merge: "${cli.dependencies["tailwind-merge"]}"
114
+ tailwindcss: "${cli.dependencies.tailwindcss}"
115
+ tw-animate-css: "${cli.dependencies["tw-animate-css"]}"
116
+ typescript: "${cli.peerDependencies.typescript}"
117
+ vite: "${cli.dependencies.vite}"
118
+ vitest: "${cli.dependencies.vitest}"
119
+ zod: "${cli.dependencies.zod}"
120
+ allowBuilds:
121
+ esbuild: false
122
+ workerd: true
123
+ minimumReleaseAge: 4320
124
+ minimumReleaseAgeExclude:
125
+ - "@hitch42/*"
126
+ `;
127
+ }
128
+ const GITIGNORE_START = "# BEGIN Hitch generated files";
129
+ const GITIGNORE_END = "# END Hitch generated files";
130
+ const GITIGNORE = `${GITIGNORE_START}
131
+ /.agents/skills/hitch-applets/
132
+ /.node-version
133
+ /AGENTS.md
134
+ /CLAUDE.md
135
+ /package.json
136
+ /pnpm-lock.yaml
137
+ /pnpm-workspace.yaml
138
+ /applets/**/components.json
139
+ /applets/**/index.html
140
+ /applets/**/package.json
141
+ /applets/**/tsconfig.json
142
+ /applets/**/tsr.config.json
143
+ /applets/**/vite.config.ts
144
+ **/.hitch/
145
+ **/.hitch.tmp-*/
146
+ **/.tanstack/
147
+ **/.wrangler/
148
+ **/dist/
149
+ **/node_modules/
150
+ ${GITIGNORE_END}
151
+ `;
152
+ async function writeGitignore(root) {
153
+ const path = resolve(root, ".gitignore");
154
+ if (!existsSync(path)) {
155
+ await writeFile(path, `${GITIGNORE}\n# Add custom rules below.\n`);
156
+ return;
157
+ }
158
+ const current = await readFile(path, "utf8");
159
+ const start = current.indexOf(GITIGNORE_START);
160
+ const end = current.indexOf(GITIGNORE_END, start);
161
+ if (start >= 0 && end >= 0) {
162
+ const suffix = current.slice(end + 27).replace(/^\r?\n/, "");
163
+ await writeFile(path, `${current.slice(0, start)}${GITIGNORE}${suffix}`);
164
+ return;
165
+ }
166
+ await writeFile(path, `${GITIGNORE}\n${current}`);
167
+ }
168
+ async function writeWorkspaceSupport(root, config, cli) {
169
+ const resolvedCli = cli ?? await loadCliManifest();
170
+ if (resolvedCli === void 0) throw new Error("The CLI package manifest is not published.");
171
+ assertWorkspaceCli(config, resolvedCli);
172
+ const skillTarget = resolve(root, ".agents/skills/hitch-applets");
173
+ const agents = await readFile(new URL("../scaffold/AGENTS.md", import.meta.url), "utf8");
174
+ await Promise.all([mkdir(resolve(root, ".agents/skills"), { recursive: true }), rm(skillTarget, {
175
+ force: true,
176
+ recursive: true
177
+ })]);
178
+ await Promise.all([
179
+ cp(new URL("../scaffold/.agents/skills/hitch-applets", import.meta.url), skillTarget, { recursive: true }),
180
+ writeFile(resolve(root, "package.json"), `${JSON.stringify(workspacePackage(config.org), null, 2)}\n`),
181
+ writeFile(resolve(root, "pnpm-workspace.yaml"), workspaceFile(resolvedCli)),
182
+ writeFile(resolve(root, ".node-version"), "24\n"),
183
+ writeGitignore(root),
184
+ writeFile(resolve(root, "AGENTS.md"), agents)
185
+ ]);
186
+ await rm(resolve(root, "CLAUDE.md"), { force: true });
187
+ await symlink("AGENTS.md", resolve(root, "CLAUDE.md"));
188
+ }
189
+ function appletPackage(definition, options) {
190
+ return {
191
+ name: definition.code.replaceAll("_", "-"),
192
+ private: true,
193
+ type: "module",
194
+ scripts: {
195
+ dev: "vite",
196
+ build: "applet build",
197
+ generate: "applet generate",
198
+ deploy: "applet deploy",
199
+ test: "vitest run",
200
+ typecheck: "tsc --noEmit"
201
+ },
202
+ dependencies: {
203
+ "@hitch42/applet": "catalog:",
204
+ "@orpc/contract": "catalog:",
205
+ zod: "catalog:",
206
+ ...options.hasServer ? { "@orpc/server": "catalog:" } : {},
207
+ ...options.hasClient ? {
208
+ "@fontsource-variable/inter": "catalog:",
209
+ "@tanstack/react-query": "catalog:",
210
+ "@tanstack/react-router": "catalog:",
211
+ "@tiptap/core": "catalog:",
212
+ "@tiptap/extension-image": "catalog:",
213
+ "@tiptap/extension-list": "catalog:",
214
+ "@tiptap/extension-table": "catalog:",
215
+ "@tiptap/extensions": "catalog:",
216
+ "@tiptap/markdown": "catalog:",
217
+ "@tiptap/react": "catalog:",
218
+ "@tiptap/starter-kit": "catalog:",
219
+ "class-variance-authority": "catalog:",
220
+ clsx: "catalog:",
221
+ "lucide-react": "catalog:",
222
+ react: "catalog:",
223
+ "react-aria-components": "catalog:",
224
+ "react-dom": "catalog:",
225
+ shadcn: "catalog:",
226
+ streamdown: "catalog:",
227
+ "tailwind-merge": "catalog:",
228
+ "tw-animate-css": "catalog:"
229
+ } : {},
230
+ ...definition.dependencies
231
+ },
232
+ devDependencies: {
233
+ "@types/node": "catalog:",
234
+ typescript: "catalog:",
235
+ vite: "catalog:",
236
+ vitest: "catalog:",
237
+ ...options.hasClient ? {
238
+ "@tailwindcss/vite": "catalog:",
239
+ "@types/react": "catalog:",
240
+ "@types/react-dom": "catalog:",
241
+ tailwindcss: "catalog:"
242
+ } : {},
243
+ ...definition.devDependencies
244
+ }
245
+ };
246
+ }
247
+ async function writeAppletSupport(root, definition) {
248
+ const hasClient = existsSync(resolve(root, "src/client/routes"));
249
+ const hasAuthorRoot = existsSync(resolve(root, "src/client/routes/__root.tsx"));
250
+ const hasServer = existsSync(resolve(root, "src/server/main.ts"));
251
+ if (!hasClient && !hasServer) throw new Error("An applet must have client routes, a server entry, or both.");
252
+ if (!hasServer && (definition.schedules?.length ?? 0) > 0) throw new Error("An applet with schedules must have src/server/main.ts.");
253
+ await Promise.all(hasClient ? [] : [rm(resolve(root, "index.html"), { force: true }), rm(resolve(root, "components.json"), { force: true })]);
254
+ await Promise.all([
255
+ writeFile(resolve(root, "package.json"), `${JSON.stringify(appletPackage(definition, {
256
+ hasClient,
257
+ hasServer
258
+ }), null, 2)}\n`),
259
+ writeFile(resolve(root, "vite.config.ts"), `import { resolve } from "node:path";
260
+
261
+ import { applet } from "@hitch42/applet/vite";
262
+ ${hasClient ? "import tailwindcss from \"@tailwindcss/vite\";\n" : ""}import { defineConfig } from "vite";
263
+
264
+ import manifest from "./applet.manifest.ts";
265
+
266
+ export default defineConfig({
267
+ plugins: [applet(manifest)${hasClient ? ", tailwindcss()" : ""}],
268
+ resolve: {
269
+ alias: { "@": resolve(import.meta.dirname, "./src") },
270
+ },
271
+ });
272
+ `),
273
+ hasClient ? writeFile(resolve(root, "tsr.config.json"), `${JSON.stringify({
274
+ routesDirectory: "./src/client/routes",
275
+ generatedRouteTree: "./.hitch/routeTree.gen.ts",
276
+ routeFileIgnorePattern: "__root",
277
+ virtualRouteConfig: {
278
+ type: "root",
279
+ file: hasAuthorRoot ? "__root.tsx" : relative(resolve(root, "src/client/routes"), resolve(root, ".hitch/appletRoot.gen.tsx")),
280
+ children: [{
281
+ type: "physical",
282
+ directory: ".",
283
+ pathPrefix: definition.code
284
+ }]
285
+ }
286
+ }, null, 2)}\n`) : rm(resolve(root, "tsr.config.json"), { force: true }),
287
+ hasClient ? writeFile(resolve(root, "index.html"), `<!doctype html>
288
+ <html lang="en">
289
+ <head>
290
+ <meta charset="UTF-8" />
291
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
292
+ <link rel="stylesheet" href="/theme.css" vite-ignore />
293
+ <title>${definition.name}</title>
294
+ </head>
295
+ <body>
296
+ <div id="root"></div>
297
+ <script type="module" src="/.hitch/entry.gen.tsx"><\/script>
298
+ </body>
299
+ </html>
300
+ `) : void 0,
301
+ writeFile(resolve(root, "tsconfig.json"), `{
302
+ "compilerOptions": {
303
+ "noEmit": true,
304
+ "strict": true,
305
+ "noUncheckedIndexedAccess": true,
306
+ "skipLibCheck": true,
307
+ "target": "ES2022",
308
+ "module": "preserve",
309
+ "moduleDetection": "force",
310
+ "isolatedModules": true,
311
+ "verbatimModuleSyntax": true,
312
+ "resolveJsonModule": true,
313
+ "allowImportingTsExtensions": true,
314
+ "jsx": "react-jsx",
315
+ "types": ["vite/client", "node"],
316
+ "paths": {
317
+ "@/*": ["./src/*"]
318
+ }
319
+ },
320
+ "include": [
321
+ "./vite.config.ts",
322
+ "./applet.manifest.ts",
323
+ "./.hitch/*.ts",
324
+ "./.hitch/*.tsx",
325
+ "./src/**/*.ts",
326
+ "./src/**/*.tsx"
327
+ ]
328
+ }
329
+ `),
330
+ hasClient ? writeFile(resolve(root, "components.json"), await readFile(new URL("../scaffold/applet/components.json", import.meta.url), "utf8")) : void 0
331
+ ]);
332
+ }
333
+ async function prepareAppletProject(appletRoot = process.cwd()) {
334
+ const definition = await loadAppletSourceDefinition(appletRoot);
335
+ const workspaceRoot = dirname(dirname(resolve(appletRoot)));
336
+ const workspace = readWorkspaceConfig(workspaceRoot);
337
+ if (workspace === void 0) throw new Error(`No Hitch workspace found for ${appletRoot}.`);
338
+ const cli = await loadCliManifest({ allowDevelopment: true });
339
+ await Promise.all([cli === void 0 ? void 0 : writeWorkspaceSupport(workspaceRoot, workspace, cli), writeAppletSupport(appletRoot, definition)]);
340
+ return {
341
+ definition,
342
+ workspaceRoot
343
+ };
344
+ }
345
+ //#endregion
346
+ export { writeWorkspaceSupport as a, writeAppletSupport as i, loadCliManifest as n, prepareAppletProject as r, assertWorkspaceCli as t };
@@ -0,0 +1,37 @@
1
+ import { a as UploadedHitchFile } from "./upload-YbRKEqR6.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 };