@drawcall/design 0.1.0

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.
@@ -0,0 +1,16 @@
1
+ import { createORPCClient } from "@orpc/client";
2
+ import { OpenAPILink } from "@orpc/openapi-client/fetch";
3
+ import { contract } from "./contract.js";
4
+ import { httpUrlSchema } from "./schemas.js";
5
+ export const DEFAULT_BASE_URL = "https://design.drawcall.ai";
6
+ export function createClient(options = {}) {
7
+ const baseUrl = httpUrlSchema.parse(options.baseUrl ?? DEFAULT_BASE_URL);
8
+ const link = new OpenAPILink(contract, {
9
+ url: new URL("/api/v1", baseUrl).href,
10
+ fetch: options.fetch ?? ((input, init) => globalThis.fetch(input, init)),
11
+ ...(options.authToken
12
+ ? { headers: { authorization: `Bearer ${options.authToken}` } }
13
+ : {}),
14
+ });
15
+ return createORPCClient(link);
16
+ }
@@ -0,0 +1,196 @@
1
+ import { z } from "zod";
2
+ export declare const contract: {
3
+ user: {
4
+ me: import("@orpc/contract").ContractProcedureBuilderWithOutput<import("@orpc/contract").Schema<unknown, unknown>, z.ZodObject<{
5
+ id: z.ZodString;
6
+ name: z.ZodString;
7
+ email: z.ZodString;
8
+ image: z.ZodNullable<z.ZodString>;
9
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
10
+ };
11
+ project: {
12
+ list: import("@orpc/contract").ContractProcedureBuilderWithOutput<import("@orpc/contract").Schema<unknown, unknown>, z.ZodArray<z.ZodObject<{
13
+ id: z.ZodString;
14
+ name: z.ZodString;
15
+ createdAt: z.ZodString;
16
+ updatedAt: z.ZodString;
17
+ }, z.core.$strip>>, Record<never, never>, Record<never, never>>;
18
+ create: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
19
+ name: z.ZodString;
20
+ }, z.core.$strip>, z.ZodObject<{
21
+ id: z.ZodString;
22
+ name: z.ZodString;
23
+ createdAt: z.ZodString;
24
+ updatedAt: z.ZodString;
25
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
26
+ delete: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
27
+ project: z.ZodString;
28
+ }, z.core.$strip>, z.ZodObject<{
29
+ id: z.ZodString;
30
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
31
+ };
32
+ frame: {
33
+ list: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
34
+ project: z.ZodString;
35
+ }, z.core.$strip>, z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
36
+ id: z.ZodString;
37
+ projectId: z.ZodString;
38
+ name: z.ZodString;
39
+ x: z.ZodNumber;
40
+ y: z.ZodNumber;
41
+ width: z.ZodNumber;
42
+ height: z.ZodNumber;
43
+ createdAt: z.ZodString;
44
+ updatedAt: z.ZodString;
45
+ kind: z.ZodLiteral<"code">;
46
+ viewUrl: z.ZodString;
47
+ }, z.core.$strip>, z.ZodObject<{
48
+ id: z.ZodString;
49
+ projectId: z.ZodString;
50
+ name: z.ZodString;
51
+ x: z.ZodNumber;
52
+ y: z.ZodNumber;
53
+ width: z.ZodNumber;
54
+ height: z.ZodNumber;
55
+ createdAt: z.ZodString;
56
+ updatedAt: z.ZodString;
57
+ kind: z.ZodLiteral<"image">;
58
+ contentUrl: z.ZodString;
59
+ }, z.core.$strip>], "kind">>, Record<never, never>, Record<never, never>>;
60
+ create: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodDiscriminatedUnion<[z.ZodObject<{
61
+ project: z.ZodString;
62
+ name: z.ZodString;
63
+ width: z.ZodNumber;
64
+ height: z.ZodNumber;
65
+ x: z.ZodOptional<z.ZodNumber>;
66
+ y: z.ZodOptional<z.ZodNumber>;
67
+ kind: z.ZodLiteral<"code">;
68
+ source: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
69
+ }, z.core.$strip>, z.ZodObject<{
70
+ project: z.ZodString;
71
+ name: z.ZodString;
72
+ width: z.ZodNumber;
73
+ height: z.ZodNumber;
74
+ x: z.ZodOptional<z.ZodNumber>;
75
+ y: z.ZodOptional<z.ZodNumber>;
76
+ kind: z.ZodLiteral<"image">;
77
+ image: z.ZodUnion<readonly [z.ZodFile, z.ZodString]>;
78
+ }, z.core.$strip>], "kind">, z.ZodDiscriminatedUnion<[z.ZodObject<{
79
+ id: z.ZodString;
80
+ projectId: z.ZodString;
81
+ name: z.ZodString;
82
+ x: z.ZodNumber;
83
+ y: z.ZodNumber;
84
+ width: z.ZodNumber;
85
+ height: z.ZodNumber;
86
+ createdAt: z.ZodString;
87
+ updatedAt: z.ZodString;
88
+ kind: z.ZodLiteral<"code">;
89
+ viewUrl: z.ZodString;
90
+ }, z.core.$strip>, z.ZodObject<{
91
+ id: z.ZodString;
92
+ projectId: z.ZodString;
93
+ name: z.ZodString;
94
+ x: z.ZodNumber;
95
+ y: z.ZodNumber;
96
+ width: z.ZodNumber;
97
+ height: z.ZodNumber;
98
+ createdAt: z.ZodString;
99
+ updatedAt: z.ZodString;
100
+ kind: z.ZodLiteral<"image">;
101
+ contentUrl: z.ZodString;
102
+ }, z.core.$strip>], "kind">, Record<never, never>, Record<never, never>>;
103
+ rename: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
104
+ project: z.ZodString;
105
+ frame: z.ZodString;
106
+ name: z.ZodString;
107
+ }, z.core.$strip>, z.ZodDiscriminatedUnion<[z.ZodObject<{
108
+ id: z.ZodString;
109
+ projectId: z.ZodString;
110
+ name: z.ZodString;
111
+ x: z.ZodNumber;
112
+ y: z.ZodNumber;
113
+ width: z.ZodNumber;
114
+ height: z.ZodNumber;
115
+ createdAt: z.ZodString;
116
+ updatedAt: z.ZodString;
117
+ kind: z.ZodLiteral<"code">;
118
+ viewUrl: z.ZodString;
119
+ }, z.core.$strip>, z.ZodObject<{
120
+ id: z.ZodString;
121
+ projectId: z.ZodString;
122
+ name: z.ZodString;
123
+ x: z.ZodNumber;
124
+ y: z.ZodNumber;
125
+ width: z.ZodNumber;
126
+ height: z.ZodNumber;
127
+ createdAt: z.ZodString;
128
+ updatedAt: z.ZodString;
129
+ kind: z.ZodLiteral<"image">;
130
+ contentUrl: z.ZodString;
131
+ }, z.core.$strip>], "kind">, Record<never, never>, Record<never, never>>;
132
+ delete: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
133
+ project: z.ZodString;
134
+ frame: z.ZodString;
135
+ }, z.core.$strip>, z.ZodObject<{
136
+ id: z.ZodString;
137
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
138
+ screenshot: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
139
+ project: z.ZodString;
140
+ frame: z.ZodString;
141
+ }, z.core.$strip>, z.ZodObject<{
142
+ url: z.ZodString;
143
+ width: z.ZodNumber;
144
+ height: z.ZodNumber;
145
+ mediaType: z.ZodLiteral<"image/png">;
146
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
147
+ source: {
148
+ list: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
149
+ project: z.ZodString;
150
+ frame: z.ZodString;
151
+ }, z.core.$strip>, z.ZodObject<{
152
+ paths: z.ZodArray<z.ZodString>;
153
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
154
+ read: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
155
+ project: z.ZodString;
156
+ frame: z.ZodString;
157
+ path: z.ZodString;
158
+ }, z.core.$strip>, z.ZodObject<{
159
+ path: z.ZodString;
160
+ code: z.ZodString;
161
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
162
+ write: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
163
+ project: z.ZodString;
164
+ frame: z.ZodString;
165
+ path: z.ZodString;
166
+ code: z.ZodString;
167
+ }, z.core.$strip>, z.ZodObject<{
168
+ paths: z.ZodArray<z.ZodString>;
169
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
170
+ edit: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
171
+ project: z.ZodString;
172
+ frame: z.ZodString;
173
+ path: z.ZodString;
174
+ oldText: z.ZodString;
175
+ newText: z.ZodString;
176
+ }, z.core.$strip>, z.ZodObject<{
177
+ paths: z.ZodArray<z.ZodString>;
178
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
179
+ replace: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
180
+ project: z.ZodString;
181
+ frame: z.ZodString;
182
+ files: z.ZodRecord<z.ZodString, z.ZodString>;
183
+ }, z.core.$strip>, z.ZodObject<{
184
+ paths: z.ZodArray<z.ZodString>;
185
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
186
+ delete: import("@orpc/contract").ContractProcedureBuilderWithInputOutput<z.ZodObject<{
187
+ project: z.ZodString;
188
+ frame: z.ZodString;
189
+ paths: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"*">]>>;
190
+ }, z.core.$strip>, z.ZodObject<{
191
+ paths: z.ZodArray<z.ZodString>;
192
+ }, z.core.$strip>, Record<never, never>, Record<never, never>>;
193
+ };
194
+ };
195
+ };
196
+ export type V1Contract = typeof contract;
@@ -0,0 +1,99 @@
1
+ import { oc } from "@orpc/contract";
2
+ import { z } from "zod";
3
+ import { createFrameSchema, frameNameSchema, frameSchema, projectNameSchema, projectSchema, screenshotSchema, sourceCodeSchema, sourceDeletePathsSchema, sourceFileSchema, sourceFilesSchema, sourceListSchema, sourceMutationSchema, sourcePathSchema, userSchema, } from "./schemas.js";
4
+ const projectInputSchema = z.object({ project: projectNameSchema });
5
+ const frameInputSchema = projectInputSchema.extend({ frame: frameNameSchema });
6
+ const sourceFileInputSchema = frameInputSchema.extend({
7
+ path: sourcePathSchema,
8
+ });
9
+ const deletedSchema = z.object({ id: z.string().min(1) });
10
+ export const contract = {
11
+ user: {
12
+ me: oc.route({ method: "GET", path: "/me" }).output(userSchema),
13
+ },
14
+ project: {
15
+ list: oc
16
+ .route({ method: "GET", path: "/projects" })
17
+ .output(z.array(projectSchema)),
18
+ create: oc
19
+ .route({ method: "POST", path: "/projects" })
20
+ .input(z.object({ name: projectNameSchema }))
21
+ .output(projectSchema),
22
+ delete: oc
23
+ .route({ method: "DELETE", path: "/projects/{project}" })
24
+ .input(projectInputSchema)
25
+ .output(deletedSchema),
26
+ },
27
+ frame: {
28
+ list: oc
29
+ .route({ method: "GET", path: "/projects/{project}/frames" })
30
+ .input(projectInputSchema)
31
+ .output(z.array(frameSchema)),
32
+ create: oc
33
+ .route({ method: "POST", path: "/projects/{project}/frames" })
34
+ .input(createFrameSchema)
35
+ .output(frameSchema),
36
+ rename: oc
37
+ .route({ method: "PATCH", path: "/projects/{project}/frames/{frame}" })
38
+ .input(frameInputSchema.extend({ name: frameNameSchema }))
39
+ .output(frameSchema),
40
+ delete: oc
41
+ .route({ method: "DELETE", path: "/projects/{project}/frames/{frame}" })
42
+ .input(frameInputSchema)
43
+ .output(deletedSchema),
44
+ screenshot: oc
45
+ .route({
46
+ method: "POST",
47
+ path: "/projects/{project}/frames/{frame}/screenshot",
48
+ })
49
+ .input(frameInputSchema)
50
+ .output(screenshotSchema),
51
+ source: {
52
+ list: oc
53
+ .route({
54
+ method: "GET",
55
+ path: "/projects/{project}/frames/{frame}/source",
56
+ })
57
+ .input(frameInputSchema)
58
+ .output(sourceListSchema),
59
+ read: oc
60
+ .route({
61
+ method: "GET",
62
+ path: "/projects/{project}/frames/{frame}/source/{path}",
63
+ })
64
+ .input(sourceFileInputSchema)
65
+ .output(sourceFileSchema),
66
+ write: oc
67
+ .route({
68
+ method: "PUT",
69
+ path: "/projects/{project}/frames/{frame}/source/{path}",
70
+ })
71
+ .input(sourceFileInputSchema.extend({ code: sourceCodeSchema }))
72
+ .output(sourceMutationSchema),
73
+ edit: oc
74
+ .route({
75
+ method: "PATCH",
76
+ path: "/projects/{project}/frames/{frame}/source/{path}",
77
+ })
78
+ .input(sourceFileInputSchema.extend({
79
+ oldText: sourceCodeSchema.min(1),
80
+ newText: sourceCodeSchema,
81
+ }))
82
+ .output(sourceMutationSchema),
83
+ replace: oc
84
+ .route({
85
+ method: "PUT",
86
+ path: "/projects/{project}/frames/{frame}/source",
87
+ })
88
+ .input(frameInputSchema.extend({ files: sourceFilesSchema }))
89
+ .output(sourceMutationSchema),
90
+ delete: oc
91
+ .route({
92
+ method: "DELETE",
93
+ path: "/projects/{project}/frames/{frame}/source",
94
+ })
95
+ .input(frameInputSchema.extend({ paths: sourceDeletePathsSchema }))
96
+ .output(sourceMutationSchema),
97
+ },
98
+ },
99
+ };
@@ -0,0 +1,3 @@
1
+ export { contract, type V1Contract } from "./contract.js";
2
+ export { createClient, DEFAULT_BASE_URL, type DesignV1Client, type DesignV1ClientOptions, } from "./client.js";
3
+ export * from "./schemas.js";
@@ -0,0 +1,3 @@
1
+ export { contract } from "./contract.js";
2
+ export { createClient, DEFAULT_BASE_URL, } from "./client.js";
3
+ export * from "./schemas.js";
@@ -0,0 +1,146 @@
1
+ import { z } from "zod";
2
+ export declare const MAX_FRAME_DIMENSION = 4096;
3
+ export declare const MAX_SOURCE_FILE_COUNT = 64;
4
+ export declare const MAX_SOURCE_FILE_LENGTH = 512000;
5
+ export declare const MAX_SOURCE_TOTAL_LENGTH = 4000000;
6
+ export declare const projectNameSchema: z.ZodString;
7
+ export declare const frameNameSchema: z.ZodString;
8
+ export declare const frameSizeSchema: z.ZodNumber;
9
+ export declare const framePositionSchema: z.ZodNumber;
10
+ export declare const httpUrlSchema: z.ZodString;
11
+ export declare const imageUrlSchema: z.ZodString;
12
+ export declare const sourcePathSchema: z.ZodString;
13
+ export declare const sourceCodeSchema: z.ZodString;
14
+ export declare const sourceFilesSchema: z.ZodRecord<z.ZodString, z.ZodString>;
15
+ export declare const sourceDeletePathsSchema: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<"*">]>>;
16
+ export declare const userSchema: z.ZodObject<{
17
+ id: z.ZodString;
18
+ name: z.ZodString;
19
+ email: z.ZodString;
20
+ image: z.ZodNullable<z.ZodString>;
21
+ }, z.core.$strip>;
22
+ export declare const projectSchema: z.ZodObject<{
23
+ id: z.ZodString;
24
+ name: z.ZodString;
25
+ createdAt: z.ZodString;
26
+ updatedAt: z.ZodString;
27
+ }, z.core.$strip>;
28
+ export declare const codeFrameSchema: z.ZodObject<{
29
+ id: z.ZodString;
30
+ projectId: z.ZodString;
31
+ name: z.ZodString;
32
+ x: z.ZodNumber;
33
+ y: z.ZodNumber;
34
+ width: z.ZodNumber;
35
+ height: z.ZodNumber;
36
+ createdAt: z.ZodString;
37
+ updatedAt: z.ZodString;
38
+ kind: z.ZodLiteral<"code">;
39
+ viewUrl: z.ZodString;
40
+ }, z.core.$strip>;
41
+ export declare const imageFrameSchema: z.ZodObject<{
42
+ id: z.ZodString;
43
+ projectId: z.ZodString;
44
+ name: z.ZodString;
45
+ x: z.ZodNumber;
46
+ y: z.ZodNumber;
47
+ width: z.ZodNumber;
48
+ height: z.ZodNumber;
49
+ createdAt: z.ZodString;
50
+ updatedAt: z.ZodString;
51
+ kind: z.ZodLiteral<"image">;
52
+ contentUrl: z.ZodString;
53
+ }, z.core.$strip>;
54
+ export declare const frameSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
55
+ id: z.ZodString;
56
+ projectId: z.ZodString;
57
+ name: z.ZodString;
58
+ x: z.ZodNumber;
59
+ y: z.ZodNumber;
60
+ width: z.ZodNumber;
61
+ height: z.ZodNumber;
62
+ createdAt: z.ZodString;
63
+ updatedAt: z.ZodString;
64
+ kind: z.ZodLiteral<"code">;
65
+ viewUrl: z.ZodString;
66
+ }, z.core.$strip>, z.ZodObject<{
67
+ id: z.ZodString;
68
+ projectId: z.ZodString;
69
+ name: z.ZodString;
70
+ x: z.ZodNumber;
71
+ y: z.ZodNumber;
72
+ width: z.ZodNumber;
73
+ height: z.ZodNumber;
74
+ createdAt: z.ZodString;
75
+ updatedAt: z.ZodString;
76
+ kind: z.ZodLiteral<"image">;
77
+ contentUrl: z.ZodString;
78
+ }, z.core.$strip>], "kind">;
79
+ export declare const createCodeFrameSchema: z.ZodObject<{
80
+ project: z.ZodString;
81
+ name: z.ZodString;
82
+ width: z.ZodNumber;
83
+ height: z.ZodNumber;
84
+ x: z.ZodOptional<z.ZodNumber>;
85
+ y: z.ZodOptional<z.ZodNumber>;
86
+ kind: z.ZodLiteral<"code">;
87
+ source: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
88
+ }, z.core.$strip>;
89
+ export declare const createImageFrameSchema: z.ZodObject<{
90
+ project: z.ZodString;
91
+ name: z.ZodString;
92
+ width: z.ZodNumber;
93
+ height: z.ZodNumber;
94
+ x: z.ZodOptional<z.ZodNumber>;
95
+ y: z.ZodOptional<z.ZodNumber>;
96
+ kind: z.ZodLiteral<"image">;
97
+ image: z.ZodUnion<readonly [z.ZodFile, z.ZodString]>;
98
+ }, z.core.$strip>;
99
+ export declare const createFrameSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
100
+ project: z.ZodString;
101
+ name: z.ZodString;
102
+ width: z.ZodNumber;
103
+ height: z.ZodNumber;
104
+ x: z.ZodOptional<z.ZodNumber>;
105
+ y: z.ZodOptional<z.ZodNumber>;
106
+ kind: z.ZodLiteral<"code">;
107
+ source: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
108
+ }, z.core.$strip>, z.ZodObject<{
109
+ project: z.ZodString;
110
+ name: z.ZodString;
111
+ width: z.ZodNumber;
112
+ height: z.ZodNumber;
113
+ x: z.ZodOptional<z.ZodNumber>;
114
+ y: z.ZodOptional<z.ZodNumber>;
115
+ kind: z.ZodLiteral<"image">;
116
+ image: z.ZodUnion<readonly [z.ZodFile, z.ZodString]>;
117
+ }, z.core.$strip>], "kind">;
118
+ export declare const sourceListSchema: z.ZodObject<{
119
+ paths: z.ZodArray<z.ZodString>;
120
+ }, z.core.$strip>;
121
+ export declare const sourceFileSchema: z.ZodObject<{
122
+ path: z.ZodString;
123
+ code: z.ZodString;
124
+ }, z.core.$strip>;
125
+ export declare const sourceMutationSchema: z.ZodObject<{
126
+ paths: z.ZodArray<z.ZodString>;
127
+ }, z.core.$strip>;
128
+ export declare const screenshotSchema: z.ZodObject<{
129
+ url: z.ZodString;
130
+ width: z.ZodNumber;
131
+ height: z.ZodNumber;
132
+ mediaType: z.ZodLiteral<"image/png">;
133
+ }, z.core.$strip>;
134
+ export type User = z.infer<typeof userSchema>;
135
+ export type Project = z.infer<typeof projectSchema>;
136
+ export type CodeFrame = z.infer<typeof codeFrameSchema>;
137
+ export type ImageFrame = z.infer<typeof imageFrameSchema>;
138
+ export type Frame = z.infer<typeof frameSchema>;
139
+ export type CreateCodeFrame = z.infer<typeof createCodeFrameSchema>;
140
+ export type CreateImageFrame = z.infer<typeof createImageFrameSchema>;
141
+ export type CreateFrame = z.infer<typeof createFrameSchema>;
142
+ export type SourceFiles = z.infer<typeof sourceFilesSchema>;
143
+ export type SourceList = z.infer<typeof sourceListSchema>;
144
+ export type SourceFile = z.infer<typeof sourceFileSchema>;
145
+ export type SourceMutation = z.infer<typeof sourceMutationSchema>;
146
+ export type Screenshot = z.infer<typeof screenshotSchema>;
@@ -0,0 +1,143 @@
1
+ import { z } from "zod";
2
+ export const MAX_FRAME_DIMENSION = 4_096;
3
+ export const MAX_SOURCE_FILE_COUNT = 64;
4
+ export const MAX_SOURCE_FILE_LENGTH = 512_000;
5
+ export const MAX_SOURCE_TOTAL_LENGTH = 4_000_000;
6
+ export const projectNameSchema = z
7
+ .string()
8
+ .trim()
9
+ .min(1)
10
+ .max(80)
11
+ .refine((name) => !name.includes("/"), "Project names cannot contain /");
12
+ export const frameNameSchema = z
13
+ .string()
14
+ .trim()
15
+ .min(1)
16
+ .max(80)
17
+ .refine((name) => !name.includes("/"), "Frame names cannot contain /");
18
+ export const frameSizeSchema = z.number().int().min(1).max(MAX_FRAME_DIMENSION);
19
+ export const framePositionSchema = z.number().finite();
20
+ export const httpUrlSchema = z
21
+ .string()
22
+ .url()
23
+ .refine(isHttpUrl, "URLs must use HTTP or HTTPS");
24
+ export const imageUrlSchema = httpUrlSchema;
25
+ export const sourcePathSchema = z.string().max(1_024).refine(isSourcePath, {
26
+ message: "Source paths must be absolute and cannot contain empty, . or .. segments",
27
+ });
28
+ export const sourceCodeSchema = z.string().max(MAX_SOURCE_FILE_LENGTH);
29
+ export const sourceFilesSchema = z
30
+ .record(sourcePathSchema, sourceCodeSchema)
31
+ .superRefine((files, context) => {
32
+ const entries = Object.entries(files);
33
+ if (entries.length > MAX_SOURCE_FILE_COUNT) {
34
+ context.addIssue({
35
+ code: "custom",
36
+ message: `Source cannot contain more than ${MAX_SOURCE_FILE_COUNT} files`,
37
+ });
38
+ }
39
+ const totalLength = entries.reduce((total, [, code]) => total + code.length, 0);
40
+ if (totalLength > MAX_SOURCE_TOTAL_LENGTH) {
41
+ context.addIssue({
42
+ code: "custom",
43
+ message: `Source cannot exceed ${MAX_SOURCE_TOTAL_LENGTH} characters`,
44
+ });
45
+ }
46
+ })
47
+ .refine((files) => !("/index.js" in files && "/index.ts" in files), {
48
+ message: "A frame cannot contain both /index.js and /index.ts",
49
+ });
50
+ export const sourceDeletePathsSchema = z
51
+ .array(z.union([sourcePathSchema, z.literal("*")]))
52
+ .min(1)
53
+ .refine((paths) => !paths.includes("*") || paths.length === 1, {
54
+ message: "* must be the only delete path",
55
+ });
56
+ export const userSchema = z.object({
57
+ id: z.string().min(1),
58
+ name: z.string(),
59
+ email: z.string().email(),
60
+ image: z.string().url().nullable(),
61
+ });
62
+ export const projectSchema = z.object({
63
+ id: z.string().min(1),
64
+ name: projectNameSchema,
65
+ createdAt: z.string().datetime(),
66
+ updatedAt: z.string().datetime(),
67
+ });
68
+ const frameBaseSchema = z.object({
69
+ id: z.string().uuid(),
70
+ projectId: z.string().min(1),
71
+ name: frameNameSchema,
72
+ x: framePositionSchema,
73
+ y: framePositionSchema,
74
+ width: frameSizeSchema,
75
+ height: frameSizeSchema,
76
+ createdAt: z.string().datetime(),
77
+ updatedAt: z.string().datetime(),
78
+ });
79
+ export const codeFrameSchema = frameBaseSchema.extend({
80
+ kind: z.literal("code"),
81
+ viewUrl: httpUrlSchema,
82
+ });
83
+ export const imageFrameSchema = frameBaseSchema.extend({
84
+ kind: z.literal("image"),
85
+ contentUrl: httpUrlSchema,
86
+ });
87
+ export const frameSchema = z.discriminatedUnion("kind", [
88
+ codeFrameSchema,
89
+ imageFrameSchema,
90
+ ]);
91
+ const createFrameBaseSchema = z.object({
92
+ project: projectNameSchema,
93
+ name: frameNameSchema,
94
+ width: frameSizeSchema,
95
+ height: frameSizeSchema,
96
+ x: framePositionSchema.optional(),
97
+ y: framePositionSchema.optional(),
98
+ });
99
+ export const createCodeFrameSchema = createFrameBaseSchema.extend({
100
+ kind: z.literal("code"),
101
+ source: sourceFilesSchema.optional(),
102
+ });
103
+ export const createImageFrameSchema = createFrameBaseSchema.extend({
104
+ kind: z.literal("image"),
105
+ image: z.union([
106
+ z.file().mime(["image/png", "image/jpeg", "image/webp"]),
107
+ imageUrlSchema,
108
+ ]),
109
+ });
110
+ export const createFrameSchema = z.discriminatedUnion("kind", [
111
+ createCodeFrameSchema,
112
+ createImageFrameSchema,
113
+ ]);
114
+ export const sourceListSchema = z.object({
115
+ paths: z.array(sourcePathSchema),
116
+ });
117
+ export const sourceFileSchema = z.object({
118
+ path: sourcePathSchema,
119
+ code: z.string(),
120
+ });
121
+ export const sourceMutationSchema = sourceListSchema;
122
+ export const screenshotSchema = z.object({
123
+ url: httpUrlSchema,
124
+ width: frameSizeSchema,
125
+ height: frameSizeSchema,
126
+ mediaType: z.literal("image/png"),
127
+ });
128
+ function isSourcePath(path) {
129
+ if (!path.startsWith("/") || path === "/" || path.endsWith("/"))
130
+ return false;
131
+ if (path.includes("\\") || path.includes("\0"))
132
+ return false;
133
+ return path
134
+ .slice(1)
135
+ .split("/")
136
+ .every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
137
+ }
138
+ function isHttpUrl(value) {
139
+ if (!URL.canParse(value))
140
+ return false;
141
+ const protocol = new URL(value).protocol;
142
+ return protocol === "http:" || protocol === "https:";
143
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@drawcall/design",
3
+ "version": "0.1.0",
4
+ "description": "Typed API and remote CLI for Drawcall Design",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/drawcall-ai/cloud-design",
8
+ "directory": "packages/design"
9
+ },
10
+ "type": "module",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "skills"
21
+ ],
22
+ "bin": {
23
+ "design": "./dist/cli.js"
24
+ },
25
+ "dependencies": {
26
+ "@orpc/client": "^1.14.13",
27
+ "@orpc/contract": "^1.14.13",
28
+ "@orpc/openapi-client": "^1.14.13",
29
+ "commander": "^14.0.3",
30
+ "openid-client": "^6.8.4",
31
+ "open": "^10.1.0",
32
+ "zod": "^4.3.6"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^25.6.0",
36
+ "prettier": "^3.6.2",
37
+ "tsx": "^4.21.0",
38
+ "typescript": "^5.9.3"
39
+ },
40
+ "engines": {
41
+ "node": ">=20"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "scripts": {
47
+ "generate": "node scripts/generate-skill.mjs",
48
+ "build": "pnpm run generate && rm -rf dist && tsc -p tsconfig.build.json",
49
+ "dev": "tsx src/cli.ts",
50
+ "pretest": "pnpm run generate",
51
+ "test": "tsx --test tests/*.test.ts",
52
+ "pretypecheck": "pnpm run generate",
53
+ "typecheck": "tsc --noEmit"
54
+ }
55
+ }