@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,114 @@
1
+ import "@orpc/server";
2
+ //#region src/hitch/registry.ts
3
+ let registeredContract;
4
+ function registerHitchContract(contract) {
5
+ registeredContract = contract;
6
+ }
7
+ function getRegisteredHitchContract() {
8
+ return registeredContract;
9
+ }
10
+ //#endregion
11
+ //#region src/hitch/upload.ts
12
+ function abortError(signal) {
13
+ return signal?.reason ?? new DOMException("The upload was aborted.", "AbortError");
14
+ }
15
+ function putWithProgress(xhr, url, file, contentType, onProgress, signal) {
16
+ return new Promise((resolve, reject) => {
17
+ if (signal?.aborted) {
18
+ reject(abortError(signal));
19
+ return;
20
+ }
21
+ const onSignalAbort = () => xhr.abort();
22
+ const cleanup = () => {
23
+ xhr.upload.onprogress = null;
24
+ xhr.onload = null;
25
+ xhr.onerror = null;
26
+ xhr.onabort = null;
27
+ signal?.removeEventListener("abort", onSignalAbort);
28
+ };
29
+ xhr.open("PUT", url);
30
+ xhr.setRequestHeader("content-type", contentType);
31
+ xhr.upload.onprogress = (event) => {
32
+ if (event.lengthComputable) onProgress({
33
+ loaded: event.loaded,
34
+ total: event.total
35
+ });
36
+ };
37
+ xhr.onload = () => {
38
+ const status = xhr.status;
39
+ cleanup();
40
+ resolve(status);
41
+ };
42
+ xhr.onerror = () => {
43
+ cleanup();
44
+ reject(/* @__PURE__ */ new Error(`Upload of "${file.name}" failed before reaching storage.`));
45
+ };
46
+ xhr.onabort = () => {
47
+ const error = abortError(signal);
48
+ cleanup();
49
+ reject(error);
50
+ };
51
+ signal?.addEventListener("abort", onSignalAbort, { once: true });
52
+ try {
53
+ xhr.send(file);
54
+ } catch (error) {
55
+ cleanup();
56
+ reject(error);
57
+ }
58
+ });
59
+ }
60
+ async function putFile(file, url, contentType, options) {
61
+ if (options.onProgress && typeof XMLHttpRequest !== "undefined") return putWithProgress(new XMLHttpRequest(), url, file, contentType, options.onProgress, options.signal);
62
+ let response;
63
+ try {
64
+ response = await fetch(url, {
65
+ method: "PUT",
66
+ body: file,
67
+ headers: { "content-type": contentType },
68
+ signal: options.signal
69
+ });
70
+ } catch (error) {
71
+ if (options.signal?.aborted) throw error;
72
+ throw new Error(`Upload of "${file.name}" failed before reaching storage.`, { cause: error });
73
+ }
74
+ return response.status;
75
+ }
76
+ async function uploadFile(files, file, options = {}) {
77
+ const created = await files.create({ body: {
78
+ filename: file.name,
79
+ contentType: file.type === "" ? "application/octet-stream" : file.type
80
+ } }, { signal: options.signal });
81
+ const status = await putFile(file, created.uploadUrl, created.data.contentType, options);
82
+ if (status < 200 || status >= 300) throw new Error(`Upload of "${file.name}" failed with status ${status}.`);
83
+ const confirmed = await files.confirm({ params: { id: created.data.id } }, { signal: options.signal });
84
+ return {
85
+ ...confirmed.data,
86
+ downloadUrl: confirmed.downloadUrl
87
+ };
88
+ }
89
+ function withFilesUpload(target, files) {
90
+ let cachedFiles;
91
+ return new Proxy(target, { get(inner, property, receiver) {
92
+ const value = Reflect.get(inner, property, receiver);
93
+ if (property !== "files") return value;
94
+ if (cachedFiles?.raw === value) return cachedFiles.proxy;
95
+ const proxy = new Proxy(value, { get: (filesInner, filesProperty, filesReceiver) => {
96
+ if (filesProperty === "upload") return (file, options) => uploadFile(files(), file, options);
97
+ if (filesProperty === "download") return async (id, options) => {
98
+ const result = await files().get({ params: { id } }, options);
99
+ return {
100
+ ...result.data,
101
+ downloadUrl: result.downloadUrl
102
+ };
103
+ };
104
+ return Reflect.get(filesInner, filesProperty, filesReceiver);
105
+ } });
106
+ cachedFiles = {
107
+ raw: value,
108
+ proxy
109
+ };
110
+ return proxy;
111
+ } });
112
+ }
113
+ //#endregion
114
+ export { registerHitchContract as i, withFilesUpload as n, getRegisteredHitchContract as r, uploadFile as t };
@@ -0,0 +1,112 @@
1
+ import { ContractProcedure, Meta } from "@orpc/contract";
2
+ import { z } from "zod";
3
+ //#region src/hitch/files.d.ts
4
+ type HitchFile = {
5
+ id: string;
6
+ organizationId: string;
7
+ key: string;
8
+ filename: string;
9
+ contentType: string;
10
+ sizeBytes: number;
11
+ arrivedAt: string;
12
+ uploadedBy: string | null;
13
+ createdAt: string;
14
+ updatedAt: string;
15
+ };
16
+ type PendingHitchFile = Omit<HitchFile, "sizeBytes" | "arrivedAt"> & {
17
+ sizeBytes: null;
18
+ arrivedAt: null;
19
+ };
20
+ type CreateFileInput = {
21
+ body: {
22
+ filename: string;
23
+ contentType: string;
24
+ };
25
+ };
26
+ type CreateFileOutput = {
27
+ data: PendingHitchFile;
28
+ uploadUrl: string;
29
+ };
30
+ type FileIdInput = {
31
+ params: {
32
+ id: string;
33
+ };
34
+ };
35
+ type FileOutput = {
36
+ data: HitchFile;
37
+ downloadUrl: string;
38
+ };
39
+ declare const fileSchema: z.ZodType<HitchFile>;
40
+ declare const createFileOutputSchema: z.ZodType<CreateFileOutput>;
41
+ declare const getFileOutputSchema: z.ZodType<FileOutput>;
42
+ type FilesContract = {
43
+ create: ContractProcedure<z.ZodType<CreateFileInput>, z.ZodType<CreateFileOutput>, Record<never, never>, Meta>;
44
+ confirm: ContractProcedure<z.ZodType<FileIdInput>, z.ZodType<FileOutput>, Record<never, never>, Meta>;
45
+ get: ContractProcedure<z.ZodType<FileIdInput>, z.ZodType<FileOutput>, Record<never, never>, Meta>;
46
+ };
47
+ declare const filesContract: FilesContract;
48
+ //#endregion
49
+ //#region src/hitch/upload.d.ts
50
+ type FilesClient = {
51
+ create(input: {
52
+ body: {
53
+ filename: string;
54
+ contentType: string;
55
+ };
56
+ }, options?: {
57
+ signal?: AbortSignal;
58
+ }): Promise<{
59
+ data: {
60
+ id: string;
61
+ contentType: string;
62
+ };
63
+ uploadUrl: string;
64
+ }>;
65
+ confirm(input: {
66
+ params: {
67
+ id: string;
68
+ };
69
+ }, options?: {
70
+ signal?: AbortSignal;
71
+ }): Promise<{
72
+ data: HitchFile;
73
+ downloadUrl: string;
74
+ }>;
75
+ get(input: {
76
+ params: {
77
+ id: string;
78
+ };
79
+ }, options?: {
80
+ signal?: AbortSignal;
81
+ }): Promise<{
82
+ data: HitchFile;
83
+ downloadUrl: string;
84
+ }>;
85
+ };
86
+ type UploadedHitchFile = HitchFile & {
87
+ downloadUrl: string;
88
+ };
89
+ type UploadProgress = {
90
+ loaded: number;
91
+ total: number;
92
+ };
93
+ type UploadFileOptions = {
94
+ signal?: AbortSignal;
95
+ onProgress?: (progress: UploadProgress) => void;
96
+ };
97
+ type FilesUpload = {
98
+ upload: (file: File, options?: UploadFileOptions) => Promise<UploadedHitchFile>;
99
+ download: (id: string, options?: {
100
+ signal?: AbortSignal;
101
+ }) => Promise<UploadedHitchFile>;
102
+ };
103
+ declare function uploadFile(files: FilesClient, file: File, options?: UploadFileOptions): Promise<UploadedHitchFile>;
104
+ type WithFilesUpload<T> = T extends {
105
+ files: infer F;
106
+ } ? Omit<T, "files"> & {
107
+ files: Omit<F, "create" | "confirm"> & FilesUpload;
108
+ } : T & {
109
+ files: FilesUpload;
110
+ };
111
+ //#endregion
112
+ export { UploadedHitchFile as a, createFileOutputSchema as c, getFileOutputSchema as d, UploadProgress as i, fileSchema as l, FilesUpload as n, WithFilesUpload as o, UploadFileOptions as r, uploadFile as s, FilesClient as t, filesContract as u };
@@ -0,0 +1,133 @@
1
+ import { t as fetchWithOrgAuth } from "./auth-DaVK0k5R.js";
2
+ import { t as loadAppletConfig } from "./load-config-BnxocLAQ.js";
3
+ import { z } from "zod";
4
+ import { Writable } from "node:stream";
5
+ import { createInterface } from "node:readline";
6
+ //#region src/variables.ts
7
+ const variableRowSchema = z.object({
8
+ key: z.string(),
9
+ secret: z.boolean(),
10
+ createdAt: z.string(),
11
+ updatedAt: z.string(),
12
+ value: z.string().optional()
13
+ });
14
+ const variableResponseSchema = z.object({ data: variableRowSchema });
15
+ const variablesResponseSchema = z.object({ data: z.array(variableRowSchema) });
16
+ function question(prompt, hidden = false) {
17
+ return new Promise((resolveAnswer, rejectAnswer) => {
18
+ let muted = false;
19
+ const output = hidden ? new Writable({ write(chunk, encoding, callback) {
20
+ if (!muted) process.stdout.write(chunk, encoding);
21
+ callback();
22
+ } }) : process.stdout;
23
+ const readline = createInterface({
24
+ input: process.stdin,
25
+ output,
26
+ terminal: true
27
+ });
28
+ readline.once("error", rejectAnswer);
29
+ if (hidden) {
30
+ process.stdout.write(prompt);
31
+ muted = true;
32
+ }
33
+ readline.question(hidden ? "" : prompt, (answer) => {
34
+ readline.close();
35
+ if (hidden) process.stdout.write("\n");
36
+ resolveAnswer(answer);
37
+ });
38
+ });
39
+ }
40
+ async function getValue(options) {
41
+ if (options.value !== void 0) return options.value;
42
+ if (!(options.stdinIsTTY ?? process.stdin.isTTY === true)) throw new Error("A value is required when stdin is not a TTY.");
43
+ return question("Value: ", true);
44
+ }
45
+ async function confirmLiveChange(code, options) {
46
+ if (options.yes === true) return;
47
+ if (!(options.stdinIsTTY ?? process.stdin.isTTY === true)) throw new Error("Confirmation requires a TTY. Pass -y to continue.");
48
+ const answer = await question(`This modifies the live applet "${code}". Continue? [y/N] `);
49
+ if (!["y", "yes"].includes(answer.trim().toLowerCase())) throw new Error("Variable change cancelled.");
50
+ }
51
+ async function readErrorDetails(response) {
52
+ let code;
53
+ let message;
54
+ try {
55
+ const body = await response.json();
56
+ if (body !== null && typeof body === "object") {
57
+ code = "code" in body && typeof body.code === "string" ? body.code : void 0;
58
+ message = "message" in body && typeof body.message === "string" ? body.message : void 0;
59
+ }
60
+ } catch {
61
+ code = void 0;
62
+ message = void 0;
63
+ }
64
+ return {
65
+ code,
66
+ message
67
+ };
68
+ }
69
+ function variablesError(status, code, message) {
70
+ const details = [code, message].filter((value) => value !== void 0).join(": ");
71
+ return /* @__PURE__ */ new Error(`Variables request failed (${status})${details ? `: ${details}` : ""}.`);
72
+ }
73
+ async function requestForApplet(options, request) {
74
+ const { code, org } = await loadAppletConfig(process.cwd());
75
+ return {
76
+ code,
77
+ response: await fetchWithOrgAuth(org, options, (instanceUrl, accessToken) => request(instanceUrl, accessToken, code))
78
+ };
79
+ }
80
+ async function runVariablesSet(options) {
81
+ const value = await getValue(options);
82
+ const manifest = await loadAppletConfig(process.cwd());
83
+ await confirmLiveChange(manifest.code, options);
84
+ const fetcher = options.fetch ?? globalThis.fetch;
85
+ const response = await fetchWithOrgAuth(manifest.org, options, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
86
+ method: "PUT",
87
+ headers: {
88
+ Authorization: `Bearer ${accessToken}`,
89
+ "Content-Type": "application/json"
90
+ },
91
+ body: JSON.stringify({
92
+ value,
93
+ secret: options.secret ?? false
94
+ })
95
+ }));
96
+ if (!response.ok) {
97
+ const { code, message } = await readErrorDetails(response);
98
+ throw variablesError(response.status, code, message);
99
+ }
100
+ const { data } = variableResponseSchema.parse(await response.json());
101
+ console.log(`Set ${data.key} ${data.secret ? "(secret)" : data.value ?? value} for applet "${manifest.code}".`);
102
+ }
103
+ async function runVariablesList(options) {
104
+ const fetcher = options.fetch ?? globalThis.fetch;
105
+ const { code, response } = await requestForApplet(options, (instanceUrl, accessToken, appletCode) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(appletCode)}/variables`, { headers: { Authorization: `Bearer ${accessToken}` } }));
106
+ if (!response.ok) {
107
+ const { code: errorCode, message } = await readErrorDetails(response);
108
+ throw variablesError(response.status, errorCode, message);
109
+ }
110
+ const { data } = variablesResponseSchema.parse(await response.json());
111
+ if (data.length === 0) {
112
+ console.log(`No variables set for "${code}".`);
113
+ return;
114
+ }
115
+ data.forEach((variable) => console.log(`${variable.key}\t${variable.secret ? "secret" : variable.value ?? ""}\t${variable.updatedAt}`));
116
+ }
117
+ async function runVariablesDelete(options) {
118
+ const manifest = await loadAppletConfig(process.cwd());
119
+ await confirmLiveChange(manifest.code, options);
120
+ const fetcher = options.fetch ?? globalThis.fetch;
121
+ const response = await fetchWithOrgAuth(manifest.org, options, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/v1/applets/${encodeURIComponent(manifest.code)}/variables/${encodeURIComponent(options.key)}`, {
122
+ method: "DELETE",
123
+ headers: { Authorization: `Bearer ${accessToken}` }
124
+ }));
125
+ if (!response.ok) {
126
+ const { code, message } = await readErrorDetails(response);
127
+ if (response.status === 404 && code === "variable_not_found") throw new Error(`Variable "${options.key}" was not found for applet "${manifest.code}".`);
128
+ throw variablesError(response.status, code, message);
129
+ }
130
+ console.log(`Deleted ${options.key} from applet "${manifest.code}".`);
131
+ }
132
+ //#endregion
133
+ export { runVariablesDelete, runVariablesList, runVariablesSet };
package/dist/vite.d.ts ADDED
@@ -0,0 +1,63 @@
1
+ import { o as RegisteredAppletSourceDefinition } from "./manifest-BQCAxATS.js";
2
+ import { PluginOption } from "vite";
3
+ //#region ../shared/auth/src/store.d.mts
4
+ interface SessionCredentials {
5
+ type: "session";
6
+ accessToken: string;
7
+ expiresAt?: number;
8
+ organizationId: string;
9
+ orgCode: string;
10
+ }
11
+ interface StoreOptions {
12
+ env?: NodeJS.ProcessEnv;
13
+ homeDir?: string;
14
+ }
15
+ //#endregion
16
+ //#region ../shared/auth/src/device.d.mts
17
+ interface MeResponse {
18
+ memberships: Array<{
19
+ code: string;
20
+ name: string;
21
+ orgId: string;
22
+ }>;
23
+ organization: {
24
+ code: string;
25
+ id: string;
26
+ } | null;
27
+ person: {
28
+ email: string;
29
+ firstName: string;
30
+ id: string;
31
+ lastName: string;
32
+ };
33
+ }
34
+ interface DeviceLoginOptions {
35
+ expectedOrg?: string;
36
+ fetch?: typeof fetch;
37
+ noBrowser?: boolean;
38
+ now?: () => number;
39
+ openUrl?: (url: string) => void | Promise<void>;
40
+ print?: (message: string) => void;
41
+ sleep?: (milliseconds: number) => Promise<void>;
42
+ store?: StoreOptions;
43
+ }
44
+ interface DeviceLoginResult {
45
+ credentials: SessionCredentials;
46
+ me: MeResponse;
47
+ membership: MeResponse["memberships"][number];
48
+ }
49
+ declare function loginWithDevice(instanceUrl: string, options?: DeviceLoginOptions): Promise<DeviceLoginResult>;
50
+ //#endregion
51
+ //#region src/auth.d.ts
52
+ interface OrgAuthOptions {
53
+ fetch?: typeof fetch;
54
+ login?: typeof loginWithDevice;
55
+ stdinIsTTY?: boolean;
56
+ store?: StoreOptions;
57
+ }
58
+ //#endregion
59
+ //#region src/vite.d.ts
60
+ type AppletOptions = OrgAuthOptions;
61
+ declare function applet<const M extends RegisteredAppletSourceDefinition>(sourceDefinition: M, options?: AppletOptions): PluginOption[];
62
+ //#endregion
63
+ export { AppletOptions, applet };