@hitch42/applet 0.1.1-beta.1

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-CEku1lyb.js +2 -0
  11. package/dist/build-Rk3xDZV7.js +74 -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-D3BGDqgC.js +2416 -0
  16. package/dist/generate-6Nbt7uii.js +2 -0
  17. package/dist/generate-CH0VQmUi.js +484 -0
  18. package/dist/index.d.ts +74 -0
  19. package/dist/index.js +136 -0
  20. package/dist/init-BS1Y-eNL.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-CxN-Dtc7.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,2 @@
1
+ import { n as runGenerate } from "./generate-CH0VQmUi.js";
2
+ export { runGenerate };
@@ -0,0 +1,484 @@
1
+ import { i as resolveInstanceUrl, n as organizationInstanceUrl, t as fetchWithOrgAuth } from "./auth-DaVK0k5R.js";
2
+ import { t as loadAppletConfig } from "./load-config-BnxocLAQ.js";
3
+ import { r as prepareAppletProject } from "./project-CxN-Dtc7.js";
4
+ import { createRequire } from "node:module";
5
+ import { existsSync } from "node:fs";
6
+ import { access, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
7
+ import { dirname, resolve } from "node:path";
8
+ import { execFile } from "node:child_process";
9
+ import { promisify } from "node:util";
10
+ import { createClient } from "@hey-api/openapi-ts";
11
+ //#region src/generated.ts
12
+ const GENERATED_HEADER = "// Generated by @hitch42/applet — do not edit";
13
+ async function writeGenerated(path, source) {
14
+ await mkdir(dirname(path), { recursive: true });
15
+ await writeFile(path, source);
16
+ }
17
+ async function writeManifestGen(outDir, manifest) {
18
+ await writeGenerated(resolve(outDir, "manifest.gen.ts"), `${GENERATED_HEADER}\nexport default ${JSON.stringify(manifest, null, 2)} as const;\n`);
19
+ }
20
+ async function writeAppletRoot(root) {
21
+ await writeGenerated(resolve(root, ".hitch/appletRoot.gen.tsx"), `${GENERATED_HEADER}
22
+ import { QueryClient } from "@tanstack/react-query";
23
+ import { createRootRouteWithContext, Outlet } from "@tanstack/react-router";
24
+
25
+ export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
26
+ component: () => <Outlet />,
27
+ });
28
+ `);
29
+ }
30
+ async function writeClientEntry(root, options) {
31
+ const hitchGenImport = options.hasHitchGen ? "import \"./index.ts\";\n" : "";
32
+ const routerSetup = options.hasRouter ? `import { getRouter } from "../src/client/router.tsx";
33
+
34
+ const router = getRouter({ routeTree });` : `import { QueryClient } from "@tanstack/react-query";
35
+ import { createRouter } from "@tanstack/react-router";
36
+
37
+ const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 30_000 } } });
38
+ const router = createRouter({ routeTree, context: { queryClient } });`;
39
+ await writeGenerated(resolve(root, ".hitch/entry.gen.tsx"), `${GENERATED_HEADER}
40
+ ${hitchGenImport}import { mountApplet } from "@hitch42/applet/_internal/client";
41
+ import { routeTree } from "./routeTree.gen.ts";
42
+ ${routerSetup}
43
+
44
+ mountApplet(router, ${JSON.stringify(options.appletCode)});
45
+ `);
46
+ }
47
+ async function writeServerEntry(root, hasHitchGen, appletCode) {
48
+ await writeGenerated(resolve(root, ".hitch/entry.server.gen.ts"), `${GENERATED_HEADER}
49
+ ${hasHitchGen ? "import \"./index.ts\";\n" : ""}import server from "../src/server/main.ts";
50
+ import { createWorkerEntry } from "@hitch42/applet/_internal/server";
51
+
52
+ export default createWorkerEntry(server, { code: ${JSON.stringify(appletCode)} });
53
+ `);
54
+ }
55
+ //#endregion
56
+ //#region src/typegen/operations.ts
57
+ const RECORD_ROUTE = /^\/v1\/([^/]+)(?:\/(\{id\}|query|update|aggregate))?$/;
58
+ const COMPONENT_REF_PREFIX$1 = "#/components/schemas/";
59
+ const BATCH_PATH = "/v1/batch";
60
+ const BATCH_ITEM_PATH = "paths./v1/batch.post.requestBody.content.application/json.schema.properties.requests.items";
61
+ const BATCH_ID_PATH = /^\^\/v1\/([^/]+)\/\[0-9a-fA-F-\]\{36\}\$$/;
62
+ const VERBS = {
63
+ "get:": "list",
64
+ "post:": "create",
65
+ "get:{id}": "get",
66
+ "patch:{id}": "update",
67
+ "delete:{id}": "delete",
68
+ "post:query": "query",
69
+ "post:update": "updateWhere",
70
+ "post:aggregate": "aggregate"
71
+ };
72
+ const COMPONENT_RESPONSE_STATUS = {
73
+ list: "200",
74
+ create: "201",
75
+ get: "200",
76
+ update: "200",
77
+ query: "200"
78
+ };
79
+ function isObject$2(value) {
80
+ return value !== null && typeof value === "object" && !Array.isArray(value);
81
+ }
82
+ function recordOperation(path, method) {
83
+ const match = RECORD_ROUTE.exec(path);
84
+ const objectCode = match?.[1];
85
+ if (objectCode === void 0 || objectCode === "batch") return void 0;
86
+ const key = `${method.toLowerCase()}:${match?.at(2) ?? ""}`;
87
+ if (!Object.hasOwn(VERBS, key)) return void 0;
88
+ return {
89
+ objectCode,
90
+ verb: VERBS[key]
91
+ };
92
+ }
93
+ function recordObjectCode(path) {
94
+ const match = RECORD_ROUTE.exec(path);
95
+ return match?.[1] === "batch" ? void 0 : match?.[1];
96
+ }
97
+ function withRecordOperationId(path, method, operation) {
98
+ const record = recordOperation(path, method);
99
+ return record ? {
100
+ ...operation,
101
+ operationId: `${record.objectCode}.${record.verb}`
102
+ } : void 0;
103
+ }
104
+ function batchEntry(entry, index) {
105
+ const properties = isObject$2(entry) && isObject$2(entry.properties) ? entry.properties : void 0;
106
+ const method = isObject$2(properties?.method) ? properties.method.enum : void 0;
107
+ const path = isObject$2(properties?.path) ? properties.path : void 0;
108
+ const methodValue = Array.isArray(method) && method.length === 1 ? method[0] : void 0;
109
+ const enumPath = Array.isArray(path?.enum) && path.enum.length === 1 ? path.enum[0] : void 0;
110
+ if (Array.isArray(method) && method.length !== 1 || Array.isArray(path?.enum) && path.enum.length !== 1) throw new Error(`${BATCH_ITEM_PATH}.oneOf[${index}] expected a create, update, delete, or updateWhere batch entry, found ${describeValue$1(entry)}`);
111
+ if (methodValue === "POST" && typeof enumPath === "string") {
112
+ const updateWhere = /^\/v1\/([^/]+)\/update$/.exec(enumPath);
113
+ if (updateWhere?.[1] !== void 0) return {
114
+ objectCode: updateWhere[1],
115
+ verb: "updateWhere"
116
+ };
117
+ const create = /^\/v1\/([^/]+)$/.exec(enumPath);
118
+ if (create?.[1] !== void 0 && create[1] !== "batch") return {
119
+ objectCode: create[1],
120
+ verb: "create"
121
+ };
122
+ }
123
+ const idPath = typeof path?.pattern === "string" ? BATCH_ID_PATH.exec(path.pattern) : void 0;
124
+ if (idPath?.[1] !== void 0 && (methodValue === "PATCH" || methodValue === "DELETE")) return {
125
+ objectCode: idPath[1],
126
+ verb: methodValue === "PATCH" ? "update" : "delete"
127
+ };
128
+ throw new Error(`${BATCH_ITEM_PATH}.oneOf[${index}] expected a create, update, delete, or updateWhere batch entry, found ${describeValue$1(entry)}`);
129
+ }
130
+ function prepareBatchOperation(operation, manifest) {
131
+ if (!isObject$2(operation)) throw new Error(`paths.${BATCH_PATH}.post expected an object, found ${describeValue$1(operation)}`);
132
+ const requestBody = isObject$2(operation.requestBody) ? operation.requestBody : void 0;
133
+ const content = isObject$2(requestBody?.content) ? requestBody.content : void 0;
134
+ const mediaType = isObject$2(content?.["application/json"]) ? content["application/json"] : void 0;
135
+ const schema = isObject$2(mediaType?.schema) ? mediaType.schema : void 0;
136
+ const properties = isObject$2(schema?.properties) ? schema.properties : void 0;
137
+ const requests = isObject$2(properties?.requests) ? properties.requests : void 0;
138
+ const items = isObject$2(requests?.items) ? requests.items : void 0;
139
+ if (items === void 0) throw new Error(`${BATCH_ITEM_PATH} expected an object, found ${describeValue$1(items)}`);
140
+ if (items.oneOf === void 0) {
141
+ if (items.type === "object" && Object.keys(items).length === 1) return void 0;
142
+ throw new Error(`${BATCH_ITEM_PATH}.oneOf expected a non-empty array, found ${describeValue$1(items.oneOf)}`);
143
+ }
144
+ if (!Array.isArray(items.oneOf)) throw new Error(`${BATCH_ITEM_PATH}.oneOf expected an array, found ${describeValue$1(items.oneOf)}`);
145
+ if (items.oneOf.length === 0) throw new Error(`${BATCH_ITEM_PATH}.oneOf expected a non-empty array, found an empty array`);
146
+ const entries = items.oneOf.filter((entry, index) => {
147
+ const { objectCode, verb } = batchEntry(entry, index);
148
+ if (manifest === void 0) return true;
149
+ const object = manifest.objects.find(({ code }) => code === objectCode);
150
+ if (object === void 0) return false;
151
+ if (verb === "create") return object.canCreate;
152
+ if (verb === "delete") return object.canDelete;
153
+ if (verb === "update" || verb === "updateWhere") return object.readWrite.length > 0;
154
+ return true;
155
+ });
156
+ if (entries.length === 0) return void 0;
157
+ items.oneOf = entries;
158
+ return {
159
+ ...operation,
160
+ operationId: "batch"
161
+ };
162
+ }
163
+ function prepareRecordSpec(spec, manifest) {
164
+ if (!isObject$2(spec) || !isObject$2(spec.paths)) throw new Error("spec: expected an OpenAPI document with paths");
165
+ const prepared = structuredClone(spec);
166
+ prepared.paths = Object.fromEntries(Object.entries(prepared.paths).flatMap(([path, pathItem]) => {
167
+ if (path === BATCH_PATH) {
168
+ if (!isObject$2(pathItem) || pathItem.post === void 0) return [];
169
+ const operation = prepareBatchOperation(pathItem.post, manifest);
170
+ return operation === void 0 ? [] : [[path, { post: operation }]];
171
+ }
172
+ const objectCode = recordObjectCode(path);
173
+ if (!isObject$2(pathItem)) {
174
+ if (objectCode === void 0) return [];
175
+ throw new Error(`object "${objectCode}": paths.${path} expected an object, found ${describeValue$1(pathItem)}`);
176
+ }
177
+ const operations = Object.entries(pathItem).flatMap(([method, operation]) => {
178
+ const record = recordOperation(path, method);
179
+ if (record === void 0) return [];
180
+ if (!isObject$2(operation)) throw new Error(`object "${record.objectCode}": paths.${path}.${method} expected an object, found ${describeValue$1(operation)}`);
181
+ if (record.verb in COMPONENT_RESPONSE_STATUS) {
182
+ const status = COMPONENT_RESPONSE_STATUS[record.verb];
183
+ const responses = isObject$2(operation.responses) ? operation.responses : void 0;
184
+ const response = isObject$2(responses?.[status]) ? responses[status] : void 0;
185
+ const content = isObject$2(response?.content) ? response.content : void 0;
186
+ const mediaType = isObject$2(content?.["application/json"]) ? content["application/json"] : void 0;
187
+ const schema = isObject$2(mediaType) ? mediaType.schema : void 0;
188
+ const ref = isObject$2(schema) ? schema.$ref : void 0;
189
+ if (typeof ref !== "string" || !ref.startsWith(COMPONENT_REF_PREFIX$1) || ref.slice(21).length === 0 || ref.slice(21).includes("/")) throw new Error(`object "${record.objectCode}": paths.${path}.${method}.responses.${status}.content.application/json.schema expected a component schema $ref, found ${describeValue$1(schema, true)}`);
190
+ }
191
+ const prepared = withRecordOperationId(path, method, operation);
192
+ return prepared ? [[method, prepared]] : [];
193
+ });
194
+ return operations.length > 0 ? [[path, Object.fromEntries(operations)]] : [];
195
+ }));
196
+ return prepared;
197
+ }
198
+ function describeValue$1(value, expectedRef = false) {
199
+ if (value === void 0) return "undefined";
200
+ if (value === null) return "null";
201
+ if (Array.isArray(value)) return "an array";
202
+ if (typeof value === "object") return expectedRef ? "an object without a valid $ref" : "an object";
203
+ return `${typeof value} ${JSON.stringify(value)}`;
204
+ }
205
+ //#endregion
206
+ //#region src/typegen/catalog.ts
207
+ const COMPONENT_REF_PREFIX = "#/components/schemas/";
208
+ const RESERVED_ATTRIBUTE_CODES = /* @__PURE__ */ new Set([
209
+ "id",
210
+ "name",
211
+ "expected_version"
212
+ ]);
213
+ function isObject$1(value) {
214
+ return value !== null && typeof value === "object" && !Array.isArray(value);
215
+ }
216
+ function describeValue(value, objectDescription = "an object") {
217
+ if (value === void 0) return "undefined";
218
+ if (value === null) return "null";
219
+ if (Array.isArray(value)) return "an array";
220
+ if (typeof value === "object") return objectDescription;
221
+ return `${typeof value} ${JSON.stringify(value)}`;
222
+ }
223
+ function componentName(value, path, objectCode) {
224
+ const ref = isObject$1(value) ? value.$ref : void 0;
225
+ if (typeof ref !== "string" || !ref.startsWith(COMPONENT_REF_PREFIX)) throw new Error(`object "${objectCode}": ${path} expected a component schema $ref, found ${describeValue(value, "an object without a $ref")}`);
226
+ const name = ref.slice(21);
227
+ if (name.length === 0 || name.includes("/")) throw new Error(`object "${objectCode}": ${path} expected a direct component schema $ref, found ${JSON.stringify(ref)}`);
228
+ return name;
229
+ }
230
+ function catalogFromSpec(spec) {
231
+ if (!isObject$1(spec) || !isObject$1(spec.paths) || !isObject$1(spec.components)) throw new Error("spec: expected an OpenAPI document with paths and components");
232
+ const schemas = spec.components.schemas;
233
+ if (!isObject$1(schemas)) throw new Error("spec.components.schemas: expected an object");
234
+ return Object.fromEntries(Object.entries(spec.paths).flatMap(([path, pathItem]) => {
235
+ const operation = recordOperation(path, "post");
236
+ if (operation?.verb !== "create") return [];
237
+ if (!isObject$1(pathItem)) throw new Error(`object "${operation.objectCode}": paths.${path} expected an object, found ${describeValue(pathItem)}`);
238
+ if (pathItem.post === void 0) return [];
239
+ if (!isObject$1(pathItem.post)) throw new Error(`object "${operation.objectCode}": paths.${path}.post expected an object, found ${describeValue(pathItem.post)}`);
240
+ const requestSchema = isObject$1(pathItem.post.requestBody) ? pathItem.post.requestBody : void 0;
241
+ const content = isObject$1(requestSchema?.content) ? requestSchema.content : void 0;
242
+ const schemaName = componentName((isObject$1(content?.["application/json"]) ? content["application/json"] : void 0)?.schema, `paths.${path}.post.requestBody.content.application/json.schema`, operation.objectCode);
243
+ const response = isObject$1(pathItem.post.responses) ? pathItem.post.responses["201"] : void 0;
244
+ const responseContent = isObject$1(response) && isObject$1(response.content) ? response.content["application/json"] : void 0;
245
+ const responseName = componentName(isObject$1(responseContent) ? responseContent.schema : void 0, `paths.${path}.post.responses.201.content.application/json.schema`, operation.objectCode);
246
+ const schema = schemas[schemaName];
247
+ if (!isObject$1(schema) || !isObject$1(schema.properties)) throw new Error(`object "${operation.objectCode}": components.schemas.${schemaName} expected request properties, found ${describeValue(schema, "an object without properties")}`);
248
+ if (!isObject$1(schemas[responseName])) throw new Error(`object "${operation.objectCode}": components.schemas.${responseName} expected an object, found ${describeValue(schemas[responseName])}`);
249
+ return [[operation.objectCode, Object.keys(schema.properties).filter((code) => !RESERVED_ATTRIBUTE_CODES.has(code))]];
250
+ }));
251
+ }
252
+ //#endregion
253
+ //#region src/typegen/guard.ts
254
+ function isObject(value) {
255
+ return value !== null && typeof value === "object" && !Array.isArray(value);
256
+ }
257
+ function guardManifestForSpec(spec, manifest) {
258
+ if (!isObject(spec) || !isObject(spec.paths)) throw new Error("spec: expected an OpenAPI document with paths");
259
+ const stamp = isObject(spec.info) ? spec.info["x-hitch-org"] : void 0;
260
+ if (stamp !== void 0 && stamp !== manifest.org) throw new Error(`manifest targets org "${manifest.org}" but the fetched spec belongs to org "${typeof stamp === "string" ? stamp : JSON.stringify(stamp)}". Check HITCH_API_URL and your login.`);
261
+ const available = [...new Set(Object.keys(spec.paths).flatMap((path) => {
262
+ const objectCode = recordObjectCode(path);
263
+ return objectCode === void 0 ? [] : [objectCode];
264
+ }))].sort();
265
+ const missing = manifest.objects.find(({ code }) => !available.includes(code));
266
+ if (missing !== void 0) throw new Error(`object "${missing.code}" not found in org spec (available: ${available.join(", ")})`);
267
+ }
268
+ //#endregion
269
+ //#region src/typegen/register.ts
270
+ function registerFile(catalog, options) {
271
+ const catalogType = catalog === void 0 ? "type Catalog = Record<string, string>;" : `type Catalog = {
272
+ ${Object.entries(catalog).map(([objectCode, attributeCodes]) => ` ${JSON.stringify(objectCode)}: ${attributeCodes.map((code) => JSON.stringify(code)).join(" | ") || "never"};`).join("\n")}
273
+ };`;
274
+ return `// Generated by @hitch42/applet — do not edit.
275
+ import type manifest from "./manifest.gen.ts";
276
+ ${options.hasServer ? "import type server from \"../src/server/main.ts\";\nimport type * as serverModule from \"../src/server/main.ts\";\n" : ""}${options.hasClient ? "import type { Route as indexRoute } from \"../src/client/routes/index.tsx\";\n" : ""}${options.hasServer ? "import type { AnyRouter } from \"@orpc/server\";\n" : ""}${options.hasClient ? "import type { AnyRoute } from \"@tanstack/react-router\";\n" : ""}${options.hasServer ? "import type { WorkflowDefinition } from \"@hitch42/applet/server\";\n" : ""}
277
+ ${catalogType}
278
+
279
+ type Expect<T extends true> = T;
280
+ ${options.hasServer ? `type ServerWorkflows = typeof serverModule extends {
281
+ workflows: infer Workflows extends Record<string, WorkflowDefinition<any, any>>;
282
+ }
283
+ ? Workflows
284
+ : {};
285
+ type _SrcServerMainMustDefaultExportRouterAndValidWorkflows = Expect<
286
+ typeof server extends {
287
+ router: AnyRouter;
288
+ workflows?: Record<string, WorkflowDefinition<any, any>>;
289
+ }
290
+ ? true
291
+ : false
292
+ >;
293
+ type _SrcServerWorkflowsMustBeNamedExport = Expect<
294
+ typeof server extends { workflows: infer Workflows }
295
+ ? typeof serverModule extends { workflows: Workflows }
296
+ ? true
297
+ : false
298
+ : true
299
+ >;
300
+ ` : ""}${options.hasClient ? `type _SrcClientRoutesIndexMustExportARoute = Expect<
301
+ typeof indexRoute extends AnyRoute ? true : false
302
+ >;
303
+ ` : ""}
304
+ declare module "@hitch42/applet" {
305
+ interface HitchRegister {
306
+ catalog: Catalog;
307
+ manifest: typeof manifest;
308
+ ${options.hasServer ? ` router: (typeof server)["router"];
309
+ workflows: ServerWorkflows;
310
+ ` : ""} }
311
+ }
312
+ `;
313
+ }
314
+ async function writeRegisterDeclaration(outDir, catalog) {
315
+ await mkdir(resolve(outDir), { recursive: true });
316
+ await writeFile(resolve(outDir, "register.ts"), registerFile(catalog, {
317
+ hasClient: existsSync(resolve(outDir, "../src/client/routes/index.tsx")),
318
+ hasServer: existsSync(resolve(outDir, "../src/server/main.ts"))
319
+ }));
320
+ }
321
+ //#endregion
322
+ //#region src/typegen/generate.ts
323
+ const execFileAsync = promisify(execFile);
324
+ const require = createRequire(import.meta.url);
325
+ async function generateRouteTree(root) {
326
+ await execFileAsync(process.execPath, [resolve(dirname(require.resolve("@tanstack/router-cli/package.json")), "bin/tsr.cjs"), "generate"], { cwd: root });
327
+ }
328
+ async function addTypeScriptImportExtensions(outDir) {
329
+ await Promise.all((await readdir(outDir, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".ts")).map(async ({ name }) => {
330
+ const path = resolve(outDir, name);
331
+ const source = await readFile(path, "utf8");
332
+ await writeFile(path, source.replace(/(["'])(\.\.?\/[^"']+)\1/g, (match, quote, specifier) => /(?:\.[cm]?[jt]sx?|json|node)$/i.test(specifier) ? match : `${quote}${specifier}.ts${quote}`));
333
+ }));
334
+ }
335
+ function isErrno(error, code) {
336
+ return error instanceof Error && "code" in error && error.code === code;
337
+ }
338
+ async function fileExists(path) {
339
+ try {
340
+ await access(path);
341
+ return true;
342
+ } catch (error) {
343
+ if (isErrno(error, "ENOENT")) return false;
344
+ throw error;
345
+ }
346
+ }
347
+ async function responseJson(response) {
348
+ try {
349
+ return await response.json();
350
+ } catch (error) {
351
+ throw new Error("Failed to parse the organization's OpenAPI spec.", { cause: error });
352
+ }
353
+ }
354
+ async function loadAuthenticatedSpec(orgCode, options) {
355
+ const fetcher = options.fetch ?? globalThis.fetch;
356
+ const response = await fetchWithOrgAuth(orgCode, options, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/v1/openapi.json${options.changesetId === void 0 ? "" : `?changeset_id=${encodeURIComponent(options.changesetId)}`}`, { headers: { Authorization: `Bearer ${accessToken}` } }));
357
+ if (!response.ok) throw new Error(`Failed to load the organization's OpenAPI spec (${response.status}).`);
358
+ return responseJson(response);
359
+ }
360
+ async function loadThemeStylesheet(orgCode, options) {
361
+ const fetcher = options.fetch ?? globalThis.fetch;
362
+ const instanceUrl = await resolveInstanceUrl(void 0, options.store);
363
+ const response = await fetcher(`${organizationInstanceUrl(instanceUrl, orgCode)}/theme.css`);
364
+ if (!response.ok) throw new Error(`Failed to load the organization's theme (${response.status}).`);
365
+ return response.text();
366
+ }
367
+ async function generateContract(spec, outDir) {
368
+ await mkdir(outDir, { recursive: true });
369
+ const paths = spec !== null && typeof spec === "object" && "paths" in spec ? spec.paths : void 0;
370
+ if (!(paths !== null && typeof paths === "object" && !Array.isArray(paths) && Object.keys(paths).length === 0)) {
371
+ const themePath = resolve(outDir, "theme.css");
372
+ const existingTheme = await readFile(themePath, "utf8").catch((error) => {
373
+ if (isErrno(error, "ENOENT")) return void 0;
374
+ throw error;
375
+ });
376
+ try {
377
+ await createClient({
378
+ input: spec,
379
+ logs: { level: "silent" },
380
+ output: outDir,
381
+ plugins: ["zod", {
382
+ name: "orpc",
383
+ contracts: {
384
+ strategy: "single",
385
+ nesting: "operationId",
386
+ segmentName: { casing: "preserve" }
387
+ }
388
+ }]
389
+ });
390
+ } finally {
391
+ if (existingTheme !== void 0) await writeFile(themePath, existingTheme);
392
+ }
393
+ await addTypeScriptImportExtensions(outDir);
394
+ }
395
+ const orpcPath = resolve(outDir, "orpc.gen.ts");
396
+ if (!await fileExists(orpcPath)) await Promise.all([writeFile(orpcPath, "// Generated by applet generate — no operations in spec.\nexport const contract = {} as const;\n"), fileExists(resolve(outDir, "zod.gen.ts")).then((exists) => exists ? void 0 : writeFile(resolve(outDir, "zod.gen.ts"), "// Generated by applet generate — no schemas in spec.\nexport {};\n"))]);
397
+ }
398
+ async function writeContractFiles(outDir, manifest, spec) {
399
+ guardManifestForSpec(spec, manifest);
400
+ const catalog = catalogFromSpec(spec);
401
+ const preparedSpec = prepareRecordSpec(spec, manifest);
402
+ await generateContract(preparedSpec, outDir);
403
+ await writeManifestGen(outDir, manifest);
404
+ await writeRegisterDeclaration(outDir, catalog);
405
+ await writeFile(resolve(outDir, "index.ts"), `// Generated by applet generate — do not edit.
406
+ import { filesContract as files, meContract as me, pruneContract, registerHitchContract, teamsContract as teams } from "@hitch42/applet";
407
+ import manifest from "./manifest.gen.ts";
408
+
409
+ ${Object.hasOwn(preparedSpec.paths, "/v1/batch") ? `import { contract as generated } from "./orpc.gen.ts";
410
+
411
+ const { batch, ...records } = generated;
412
+
413
+ export const contract = { records, batch, files, me, teams } as const;` : `import { contract as records } from "./orpc.gen.ts";
414
+
415
+ export const contract = { records, files, me, teams } as const;`}
416
+ registerHitchContract(pruneContract(contract, manifest));
417
+
418
+ declare module "@hitch42/applet" {
419
+ interface HitchRegister {
420
+ contract: typeof contract;
421
+ }
422
+ }
423
+
424
+ export type * from "./zod.gen.ts";
425
+ `);
426
+ }
427
+ async function syncContract(outDir, manifest, options = {}) {
428
+ await writeContractFiles(outDir, manifest, await loadAuthenticatedSpec(manifest.org, options));
429
+ }
430
+ async function runGenerate(options) {
431
+ await prepareAppletProject();
432
+ const root = process.cwd();
433
+ const outDir = resolve("./.hitch");
434
+ const manifest = await loadAppletConfig(process.cwd());
435
+ const spec = await loadAuthenticatedSpec(manifest.org, options);
436
+ const themeStylesheet = await loadThemeStylesheet(manifest.org, options);
437
+ const stagedDir = await mkdtemp(resolve("./.hitch.tmp-"));
438
+ const backupDir = `${stagedDir}.backup`;
439
+ let staged = true;
440
+ let backedUp = false;
441
+ try {
442
+ await writeContractFiles(stagedDir, manifest, spec);
443
+ await writeFile(resolve(stagedDir, "theme.css"), themeStylesheet);
444
+ if (await fileExists(outDir)) {
445
+ await rename(outDir, backupDir);
446
+ backedUp = true;
447
+ }
448
+ let installed = false;
449
+ try {
450
+ await rename(stagedDir, outDir);
451
+ staged = false;
452
+ installed = true;
453
+ if (await fileExists(resolve(root, "src/client/routes"))) {
454
+ if (!await fileExists(resolve(root, "src/client/routes/__root.tsx"))) await writeAppletRoot(root);
455
+ await generateRouteTree(root);
456
+ }
457
+ } catch (error) {
458
+ if (installed) await rm(outDir, {
459
+ force: true,
460
+ recursive: true
461
+ });
462
+ if (backedUp) {
463
+ await rename(backupDir, outDir);
464
+ backedUp = false;
465
+ }
466
+ throw error;
467
+ }
468
+ if (backedUp) {
469
+ await rm(backupDir, {
470
+ force: true,
471
+ recursive: true
472
+ });
473
+ backedUp = false;
474
+ }
475
+ } finally {
476
+ if (staged) await rm(stagedDir, {
477
+ force: true,
478
+ recursive: true
479
+ });
480
+ if (backedUp && !await fileExists(outDir)) await rename(backupDir, outDir);
481
+ }
482
+ }
483
+ //#endregion
484
+ export { prepareRecordSpec as a, writeClientEntry as c, writeRegisterDeclaration as i, writeManifestGen as l, runGenerate as n, recordOperation as o, syncContract as r, writeAppletRoot as s, generateContract as t, writeServerEntry as u };
@@ -0,0 +1,74 @@
1
+ import { _ as RegisteredWorkflows, a as AppletSourceDefinition, c as appletManifestSchema, d as RegisteredCatalog, f as RegisteredContract, g as RegisteredVariables, h as RegisteredVariableKeys, i as AppletPackages, l as appletSourceDefinitionSchema, m as RegisteredRouter, n as AppletManifest, o as RegisteredAppletSourceDefinition, p as RegisteredManifest, r as AppletManifestObject, s as appletDefinitionSchema, t as AppletDefinition, u as HitchRegister, v as registerHitchContract } from "./manifest-BQCAxATS.js";
2
+ import { n as pruneContract, t as NarrowContract } from "./contract-DMrpbaLJ.js";
3
+ import { a as UploadedHitchFile, c as createFileOutputSchema, d as getFileOutputSchema, i as UploadProgress, l as fileSchema, n as FilesUpload, r as UploadFileOptions, s as uploadFile, t as FilesClient, u as filesContract } from "./upload-YbRKEqR6.js";
4
+ import { ContractProcedure, Meta } from "@orpc/contract";
5
+ import { z } from "zod";
6
+ //#region src/workspace.d.ts
7
+ interface HitchConfig {
8
+ sdk: string;
9
+ org: string;
10
+ }
11
+ //#endregion
12
+ //#region src/hitch/me.d.ts
13
+ type HitchPerson = {
14
+ id: string;
15
+ firstName: string;
16
+ lastName: string;
17
+ email: string;
18
+ };
19
+ type HitchMembership = {
20
+ orgId: string;
21
+ code: string;
22
+ name: string;
23
+ iconFileId: string | null;
24
+ role: "member" | "owner";
25
+ capabilities: string[];
26
+ };
27
+ type HitchMe = {
28
+ person: HitchPerson;
29
+ memberships: HitchMembership[];
30
+ organization: {
31
+ id: string;
32
+ code: string;
33
+ } | null;
34
+ multiOrg: boolean;
35
+ };
36
+ declare const meSchema: z.ZodType<HitchMe>;
37
+ type MeContract = {
38
+ get: ContractProcedure<z.ZodType<void>, z.ZodType<HitchMe>, Record<never, never>, Meta>;
39
+ };
40
+ declare const meContract: MeContract;
41
+ //#endregion
42
+ //#region src/hitch/teams.d.ts
43
+ type HitchTeam = {
44
+ id: string;
45
+ name: string;
46
+ };
47
+ type HitchTeamMember = {
48
+ userId: string;
49
+ firstName: string;
50
+ lastName: string;
51
+ email: string;
52
+ };
53
+ type TeamIdInput = {
54
+ params: {
55
+ id: string;
56
+ };
57
+ };
58
+ type TeamsOutput = {
59
+ data: HitchTeam[];
60
+ };
61
+ type TeamMembersOutput = {
62
+ data: HitchTeamMember[];
63
+ };
64
+ declare const teamSchema: z.ZodType<HitchTeam>;
65
+ declare const teamMemberSchema: z.ZodType<HitchTeamMember>;
66
+ type TeamsContract = {
67
+ list: ContractProcedure<z.ZodType<void>, z.ZodType<TeamsOutput>, Record<never, never>, Meta>;
68
+ members: {
69
+ list: ContractProcedure<z.ZodType<TeamIdInput>, z.ZodType<TeamMembersOutput>, Record<never, never>, Meta>;
70
+ };
71
+ };
72
+ declare const teamsContract: TeamsContract;
73
+ //#endregion
74
+ export { type AppletDefinition, type AppletManifest, type AppletManifestObject, type AppletPackages, type AppletSourceDefinition, type FilesClient, type FilesUpload, type HitchConfig, type HitchMe, type HitchRegister, type HitchTeam, type HitchTeamMember, type NarrowContract, type RegisteredAppletSourceDefinition, type RegisteredCatalog, type RegisteredContract, type RegisteredManifest, type RegisteredRouter, type RegisteredVariableKeys, type RegisteredVariables, type RegisteredWorkflows, type UploadFileOptions, type UploadProgress, type UploadedHitchFile, appletDefinitionSchema, appletManifestSchema, appletSourceDefinitionSchema, createFileOutputSchema, fileSchema, filesContract, getFileOutputSchema, meContract, meSchema, pruneContract, registerHitchContract, teamMemberSchema, teamSchema, teamsContract, uploadFile };