@tscircuit/fake-snippets 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +2 -5
- package/bun-tests/fake-snippets-api/routes/package_files/create.test.ts +375 -0
- package/bun-tests/fake-snippets-api/routes/package_files/download.test.ts +248 -0
- package/bun-tests/fake-snippets-api/routes/package_files/get.test.ts +220 -0
- package/bun-tests/fake-snippets-api/routes/package_files/list.test.ts +204 -0
- package/bun-tests/fake-snippets-api/routes/package_releases/get.test.ts +0 -1
- package/bun-tests/fake-snippets-api/routes/packages/{list.test.ts → list-1.test.ts} +3 -55
- package/bun-tests/fake-snippets-api/routes/packages/list-2.test.ts +59 -0
- package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +34 -1
- package/bun.lock +100 -73
- package/dist/bundle.js +729 -273
- package/fake-snippets-api/lib/db/db-client.ts +58 -50
- package/fake-snippets-api/lib/db/schema.ts +15 -6
- package/fake-snippets-api/lib/package_file/get-package-file-id-from-file-descriptor.ts +168 -0
- package/fake-snippets-api/lib/package_release/find-package-release-id.ts +122 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package.ts +9 -2
- package/fake-snippets-api/routes/api/package_files/create.ts +132 -0
- package/fake-snippets-api/routes/api/package_files/download.ts +70 -153
- package/fake-snippets-api/routes/api/package_files/get.ts +24 -5
- package/fake-snippets-api/routes/api/package_files/list.ts +16 -28
- package/fake-snippets-api/routes/api/snippets/create.ts +123 -29
- package/index.html +12 -1
- package/package.json +10 -9
- package/playwright-tests/profile-page.spec.ts +59 -0
- package/playwright-tests/snapshots/profile-page.spec.ts-profile-page-before-delete.png +0 -0
- package/playwright-tests/snapshots/profile-page.spec.ts-profile-page-delete-dialog.png +0 -0
- package/playwright-tests/snapshots/profile-page.spec.ts-profile-page-dropdown-open.png +0 -0
- package/scripts/generate-image-sizes.ts +0 -1
- package/scripts/generate_bundle_stats.js +22 -6
- package/src/components/AiChatInterface.tsx +8 -0
- package/src/components/Analytics.tsx +1 -1
- package/src/components/CodeAndPreview.tsx +9 -3
- package/src/components/CreateNewSnippetWithAiHero.tsx +6 -2
- package/src/components/EditorNav.tsx +4 -0
- package/src/components/Footer.tsx +1 -1
- package/src/components/Header.tsx +7 -10
- package/src/components/HeaderLogin.tsx +1 -1
- package/src/components/PreviewContent.tsx +4 -1
- package/src/components/SnippetList.tsx +71 -0
- package/src/lib/templates/blinking-led-board-template.ts +2 -1
- package/src/pages/dashboard.tsx +19 -44
- package/src/pages/editor.tsx +1 -1
- package/src/pages/landing.tsx +8 -16
- package/src/pages/quickstart.tsx +9 -9
- package/src/pages/user-profile.tsx +50 -3
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as zt from "fake-snippets-api/lib/db/schema"
|
|
2
|
+
import { findPackageReleaseId } from "fake-snippets-api/lib/package_release/find-package-release-id"
|
|
3
|
+
import { withRouteSpec } from "fake-snippets-api/lib/with-winter-spec"
|
|
4
|
+
import { z } from "zod"
|
|
5
|
+
|
|
6
|
+
const routeSpec = {
|
|
7
|
+
methods: ["POST"],
|
|
8
|
+
auth: "none",
|
|
9
|
+
jsonBody: z
|
|
10
|
+
.object({
|
|
11
|
+
file_path: z.string(),
|
|
12
|
+
is_release_tarball: z.boolean().optional().default(false),
|
|
13
|
+
content_mimetype: z.string().optional(),
|
|
14
|
+
content_text: z.string().optional(),
|
|
15
|
+
content_base64: z.string().optional(),
|
|
16
|
+
package_release_id: z.string().optional(),
|
|
17
|
+
package_name_with_version: z.string().optional(),
|
|
18
|
+
npm_pack_output: z.any().optional(),
|
|
19
|
+
})
|
|
20
|
+
.refine((v) => {
|
|
21
|
+
if (v.package_release_id) return true
|
|
22
|
+
if (v.package_name_with_version) return true
|
|
23
|
+
return false
|
|
24
|
+
}, "Must specify either package_release_id or package_name_with_version")
|
|
25
|
+
.refine((v) => {
|
|
26
|
+
if (v.package_release_id && v.package_name_with_version) return false
|
|
27
|
+
return true
|
|
28
|
+
}, "Cannot specify both package_release_id and package_name_with_version")
|
|
29
|
+
.refine((v) => {
|
|
30
|
+
if (v.content_base64 && v.content_text) return false
|
|
31
|
+
if (!v.content_base64 && !v.content_text) return false
|
|
32
|
+
return true
|
|
33
|
+
}, "Either content_base64 or content_text is required"),
|
|
34
|
+
jsonResponse: z.object({
|
|
35
|
+
ok: z.boolean(),
|
|
36
|
+
package_file: zt.packageFileSchema,
|
|
37
|
+
}),
|
|
38
|
+
} as const
|
|
39
|
+
|
|
40
|
+
export default withRouteSpec(routeSpec)(async (req, ctx) => {
|
|
41
|
+
const {
|
|
42
|
+
file_path,
|
|
43
|
+
content_mimetype: providedContentMimetype,
|
|
44
|
+
content_base64,
|
|
45
|
+
content_text,
|
|
46
|
+
is_release_tarball,
|
|
47
|
+
npm_pack_output,
|
|
48
|
+
} = req.jsonBody
|
|
49
|
+
|
|
50
|
+
if (is_release_tarball && !npm_pack_output) {
|
|
51
|
+
return ctx.error(400, {
|
|
52
|
+
error_code: "missing_options",
|
|
53
|
+
message: "npm_pack_output is required for release tarballs",
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!is_release_tarball && npm_pack_output) {
|
|
58
|
+
return ctx.error(404, {
|
|
59
|
+
error_code: "invalid_options",
|
|
60
|
+
message: "npm_pack_output is only valid for release tarballs",
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let packageReleaseId = req.jsonBody.package_release_id
|
|
65
|
+
|
|
66
|
+
if (!packageReleaseId && req.jsonBody.package_name_with_version) {
|
|
67
|
+
const foundPackageReleaseId = await findPackageReleaseId(
|
|
68
|
+
req.jsonBody.package_name_with_version,
|
|
69
|
+
ctx,
|
|
70
|
+
)
|
|
71
|
+
if (foundPackageReleaseId) {
|
|
72
|
+
packageReleaseId = foundPackageReleaseId
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!packageReleaseId) {
|
|
77
|
+
return ctx.error(404, {
|
|
78
|
+
error_code: "package_release_not_found",
|
|
79
|
+
message: "Package release not found",
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Verify the package release exists
|
|
84
|
+
const packageRelease = ctx.db.packageReleases.find(
|
|
85
|
+
(pr) => pr.package_release_id === packageReleaseId,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if (!packageRelease) {
|
|
89
|
+
return ctx.error(404, {
|
|
90
|
+
error_code: "package_release_not_found",
|
|
91
|
+
message: "Package release not found",
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Determine content mimetype
|
|
96
|
+
const contentMimetype =
|
|
97
|
+
providedContentMimetype ||
|
|
98
|
+
(file_path.endsWith(".ts") || file_path.endsWith(".tsx")
|
|
99
|
+
? "text/typescript"
|
|
100
|
+
: null) ||
|
|
101
|
+
(file_path.endsWith(".js") ? "application/javascript" : null) ||
|
|
102
|
+
(file_path.endsWith(".json") ? "application/json" : null) ||
|
|
103
|
+
(file_path.endsWith(".md") ? "text/markdown" : null) ||
|
|
104
|
+
(file_path.endsWith(".html") ? "text/html" : null) ||
|
|
105
|
+
(file_path.endsWith(".css") ? "text/css" : null) ||
|
|
106
|
+
"application/octet-stream"
|
|
107
|
+
|
|
108
|
+
// Create the package file
|
|
109
|
+
const newPackageFile = {
|
|
110
|
+
package_file_id: crypto.randomUUID(),
|
|
111
|
+
package_release_id: packageReleaseId,
|
|
112
|
+
file_path,
|
|
113
|
+
content_text:
|
|
114
|
+
content_text ||
|
|
115
|
+
(content_base64
|
|
116
|
+
? Buffer.from(content_base64, "base64").toString()
|
|
117
|
+
: null),
|
|
118
|
+
content_mimetype: contentMimetype,
|
|
119
|
+
is_directory: false,
|
|
120
|
+
is_release_tarball: is_release_tarball || false,
|
|
121
|
+
npm_pack_output: npm_pack_output || null,
|
|
122
|
+
created_at: new Date().toISOString(),
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Add to the test database
|
|
126
|
+
ctx.db.addPackageFile(newPackageFile)
|
|
127
|
+
|
|
128
|
+
return ctx.json({
|
|
129
|
+
ok: true,
|
|
130
|
+
package_file: newPackageFile,
|
|
131
|
+
})
|
|
132
|
+
})
|
|
@@ -1,170 +1,87 @@
|
|
|
1
|
+
import { getPackageFileIdFromFileDescriptor } from "fake-snippets-api/lib/package_file/get-package-file-id-from-file-descriptor"
|
|
2
|
+
import { findPackageReleaseId } from "fake-snippets-api/lib/package_release/find-package-release-id"
|
|
1
3
|
import { withRouteSpec } from "fake-snippets-api/lib/with-winter-spec"
|
|
2
4
|
import { z } from "zod"
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
methods: ["GET"],
|
|
6
|
+
const routeSpec = {
|
|
7
|
+
methods: ["GET", "POST"],
|
|
6
8
|
auth: "none",
|
|
7
|
-
queryParams: z
|
|
8
|
-
|
|
9
|
-
.
|
|
10
|
-
.optional()
|
|
11
|
-
.transform((v) => v === "true"),
|
|
12
|
-
jsdelivr_path: z.string(),
|
|
13
|
-
}),
|
|
14
|
-
jsonResponse: z.any(),
|
|
15
|
-
})(async (req, ctx) => {
|
|
16
|
-
const { jsdelivr_path, jsdelivr_resolve } = req.query
|
|
17
|
-
|
|
18
|
-
// Parse the file path
|
|
19
|
-
const [owner, packageWithVersion, ...rest] = jsdelivr_path.split("/")
|
|
20
|
-
if (!packageWithVersion) {
|
|
21
|
-
return ctx.error(400, {
|
|
22
|
-
error_code: "invalid_path",
|
|
23
|
-
message: "Invalid path",
|
|
9
|
+
queryParams: z
|
|
10
|
+
.object({
|
|
11
|
+
package_file_id: z.string(),
|
|
24
12
|
})
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
.or(
|
|
14
|
+
z.object({
|
|
15
|
+
package_name_with_version: z.string(),
|
|
16
|
+
file_path: z.string(),
|
|
17
|
+
}),
|
|
18
|
+
),
|
|
19
|
+
jsonResponse: z.any(), // Using any because we're returning binary data
|
|
20
|
+
} as const
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
export default withRouteSpec(routeSpec)(async (req, ctx) => {
|
|
23
|
+
let packageFileId: string | undefined
|
|
24
|
+
const params = req.query
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// })
|
|
37
|
-
// }
|
|
26
|
+
if ("package_file_id" in params) {
|
|
27
|
+
packageFileId = params.package_file_id
|
|
28
|
+
} else if ("package_name_with_version" in params) {
|
|
29
|
+
const { package_name_with_version, file_path } = params
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// latest: "0.0.1",
|
|
44
|
-
// },
|
|
45
|
-
// versions: ["0.0.1"],
|
|
46
|
-
// }),
|
|
47
|
-
// {
|
|
48
|
-
// status: 200,
|
|
49
|
-
// headers: { "Content-Type": "application/json" },
|
|
50
|
-
// },
|
|
51
|
-
// )
|
|
52
|
-
// }
|
|
31
|
+
const packageReleaseId = await findPackageReleaseId(
|
|
32
|
+
package_name_with_version,
|
|
33
|
+
ctx,
|
|
34
|
+
)
|
|
53
35
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// status: 200,
|
|
61
|
-
// headers: { "Content-Type": "application/json" },
|
|
62
|
-
// },
|
|
63
|
-
// )
|
|
64
|
-
// }
|
|
36
|
+
if (!packageReleaseId) {
|
|
37
|
+
return ctx.error(404, {
|
|
38
|
+
error_code: "not_found",
|
|
39
|
+
message: "Package release not found",
|
|
40
|
+
})
|
|
41
|
+
}
|
|
65
42
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
43
|
+
try {
|
|
44
|
+
packageFileId = await getPackageFileIdFromFileDescriptor(
|
|
45
|
+
{
|
|
46
|
+
package_release_id: packageReleaseId,
|
|
47
|
+
file_path: file_path,
|
|
48
|
+
},
|
|
49
|
+
ctx,
|
|
50
|
+
)
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return ctx.error(404, {
|
|
53
|
+
error_code: "not_found",
|
|
54
|
+
message: "Package file not found",
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
}
|
|
79
58
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// hash: "placeholder_hash",
|
|
87
|
-
// time: snippet.updated_at,
|
|
88
|
-
// size: snippet.code?.length ?? 0,
|
|
89
|
-
// },
|
|
90
|
-
// {
|
|
91
|
-
// type: "file",
|
|
92
|
-
// name: "index.d.ts",
|
|
93
|
-
// hash: "placeholder_hash",
|
|
94
|
-
// time: snippet.updated_at,
|
|
95
|
-
// size: dtsFile?.content_text?.length ?? 0,
|
|
96
|
-
// },
|
|
97
|
-
// {
|
|
98
|
-
// type: "file",
|
|
99
|
-
// name: "package.json",
|
|
100
|
-
// hash: "placeholder_hash",
|
|
101
|
-
// time: snippet.updated_at,
|
|
102
|
-
// size: JSON.stringify({
|
|
103
|
-
// name: `@tsci/${owner}.${packageName}`,
|
|
104
|
-
// version: version || "0.0.1",
|
|
105
|
-
// main: "index.ts",
|
|
106
|
-
// types: "index.d.ts",
|
|
107
|
-
// }).length,
|
|
108
|
-
// },
|
|
109
|
-
// ]
|
|
59
|
+
if (!packageFileId) {
|
|
60
|
+
return ctx.error(400, {
|
|
61
|
+
error_code: "bad_request",
|
|
62
|
+
message: "Could not determine package_file_id",
|
|
63
|
+
})
|
|
64
|
+
}
|
|
110
65
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// fileName === "flat"
|
|
115
|
-
// ? files.map((f) => ({
|
|
116
|
-
// name: `/${f.name}`,
|
|
117
|
-
// hash: f.hash,
|
|
118
|
-
// time: f.time,
|
|
119
|
-
// size: f.size,
|
|
120
|
-
// }))
|
|
121
|
-
// : [
|
|
122
|
-
// {
|
|
123
|
-
// type: "directory",
|
|
124
|
-
// name: ".",
|
|
125
|
-
// files: files,
|
|
126
|
-
// },
|
|
127
|
-
// ],
|
|
128
|
-
// }
|
|
66
|
+
const packageFile = ctx.db.packageFiles.find(
|
|
67
|
+
(pf) => pf.package_file_id === packageFileId,
|
|
68
|
+
)
|
|
129
69
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
70
|
+
if (!packageFile) {
|
|
71
|
+
return ctx.error(404, {
|
|
72
|
+
error_code: "not_found",
|
|
73
|
+
message: "Package file not found",
|
|
74
|
+
})
|
|
75
|
+
}
|
|
135
76
|
|
|
136
|
-
|
|
137
|
-
// let content: string
|
|
138
|
-
// switch (fileName) {
|
|
139
|
-
// case "index.ts":
|
|
140
|
-
// content = snippet.code ?? ""
|
|
141
|
-
// break
|
|
142
|
-
// case "index.d.ts":
|
|
143
|
-
// content = dtsFile?.content_text ?? ""
|
|
144
|
-
// break
|
|
145
|
-
// case "package.json":
|
|
146
|
-
// content = JSON.stringify(
|
|
147
|
-
// {
|
|
148
|
-
// name: `@tsci/${owner}.${packageName}`,
|
|
149
|
-
// version: version || "0.0.1",
|
|
150
|
-
// main: "index.ts",
|
|
151
|
-
// types: "index.d.ts",
|
|
152
|
-
// },
|
|
153
|
-
// null,
|
|
154
|
-
// 2,
|
|
155
|
-
// )
|
|
156
|
-
// break
|
|
157
|
-
// default:
|
|
158
|
-
// return ctx.error(404, {
|
|
159
|
-
// error_code: "file_not_found",
|
|
160
|
-
// message: "Requested file not found",
|
|
161
|
-
// })
|
|
162
|
-
// }
|
|
77
|
+
const contentType = "text/plain"
|
|
163
78
|
|
|
164
|
-
const
|
|
79
|
+
const headers = {
|
|
80
|
+
"Content-Type": contentType,
|
|
81
|
+
"Content-Disposition": `attachment; filename="${packageFile.file_path.split("/").pop()}"`,
|
|
82
|
+
"Cache-Control": "public, max-age=86400, stale-while-revalidate=604800",
|
|
83
|
+
Expires: new Date(Date.now() + 86400000).toUTCString(),
|
|
84
|
+
}
|
|
165
85
|
|
|
166
|
-
return new Response(
|
|
167
|
-
status: 200,
|
|
168
|
-
headers: { "Content-Type": "text/plain" },
|
|
169
|
-
})
|
|
86
|
+
return new Response(packageFile.content_text, { headers })
|
|
170
87
|
})
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { withRouteSpec } from "fake-snippets-api/lib/with-winter-spec"
|
|
2
2
|
import { z } from "zod"
|
|
3
3
|
import * as ZT from "fake-snippets-api/lib/db/schema"
|
|
4
|
-
import {
|
|
4
|
+
import { getPackageFileIdFromFileDescriptor } from "fake-snippets-api/lib/package_file/get-package-file-id-from-file-descriptor"
|
|
5
5
|
|
|
6
6
|
const routeSpec = {
|
|
7
7
|
methods: ["POST"],
|
|
8
8
|
auth: "none",
|
|
9
9
|
jsonBody: z
|
|
10
10
|
.object({
|
|
11
|
-
package_file_id: z.string()
|
|
11
|
+
package_file_id: z.string(),
|
|
12
12
|
})
|
|
13
13
|
.or(
|
|
14
14
|
z.object({
|
|
15
|
-
package_release_id: z.string()
|
|
15
|
+
package_release_id: z.string(),
|
|
16
16
|
file_path: z.string(),
|
|
17
17
|
}),
|
|
18
18
|
)
|
|
19
19
|
.or(
|
|
20
20
|
z.object({
|
|
21
|
-
package_id: z.string()
|
|
21
|
+
package_id: z.string(),
|
|
22
22
|
version: z.string().optional(),
|
|
23
23
|
file_path: z.string(),
|
|
24
24
|
}),
|
|
@@ -45,8 +45,27 @@ const routeSpec = {
|
|
|
45
45
|
} as const
|
|
46
46
|
|
|
47
47
|
export default withRouteSpec(routeSpec)(async (req, ctx) => {
|
|
48
|
+
const packageFileId = await getPackageFileIdFromFileDescriptor(
|
|
49
|
+
req.jsonBody,
|
|
50
|
+
ctx,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const packageFile = ctx.db.packageFiles.find(
|
|
54
|
+
(pf: ZT.PackageFile) => pf.package_file_id === packageFileId,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
if (!packageFile) {
|
|
58
|
+
return ctx.error(404, {
|
|
59
|
+
error_code: "package_file_not_found",
|
|
60
|
+
message: "Package file not found",
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
48
64
|
return ctx.json({
|
|
49
65
|
ok: true,
|
|
50
|
-
package_file:
|
|
66
|
+
package_file: {
|
|
67
|
+
...packageFile,
|
|
68
|
+
created_at: packageFile.created_at.toString(),
|
|
69
|
+
},
|
|
51
70
|
})
|
|
52
71
|
})
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { withRouteSpec } from "fake-snippets-api/lib/with-winter-spec"
|
|
2
2
|
import { z } from "zod"
|
|
3
3
|
import * as ZT from "fake-snippets-api/lib/db/schema"
|
|
4
|
+
import { findPackageReleaseId } from "fake-snippets-api/lib/package_release/find-package-release-id"
|
|
4
5
|
|
|
5
6
|
const routeSpec = {
|
|
6
7
|
methods: ["POST"],
|
|
7
8
|
auth: "none",
|
|
8
9
|
jsonBody: z
|
|
9
10
|
.object({
|
|
10
|
-
package_release_id: z.string()
|
|
11
|
+
package_release_id: z.string(),
|
|
11
12
|
})
|
|
12
13
|
.or(
|
|
13
14
|
z.object({
|
|
@@ -27,34 +28,21 @@ const routeSpec = {
|
|
|
27
28
|
} as const
|
|
28
29
|
|
|
29
30
|
export default withRouteSpec(routeSpec)(async (req, ctx) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// "file_path",
|
|
44
|
-
// "created_at",
|
|
45
|
-
// ])
|
|
46
|
-
// .where("package_release_id", "=", package_release_id)
|
|
47
|
-
// .where("file_path", "not like", ".tscircuit-internal/%")
|
|
48
|
-
// .execute()
|
|
49
|
-
// return ctx.json({
|
|
50
|
-
// ok: true,
|
|
51
|
-
// package_files: package_files.map((pf) => ({
|
|
52
|
-
// ...pf,
|
|
53
|
-
// created_at: pf.created_at.toISOString(),
|
|
54
|
-
// })),
|
|
55
|
-
// })
|
|
31
|
+
const packageReleaseId = await findPackageReleaseId(req.jsonBody, ctx)
|
|
32
|
+
|
|
33
|
+
if (!packageReleaseId) {
|
|
34
|
+
return ctx.error(404, {
|
|
35
|
+
error_code: "package_release_not_found",
|
|
36
|
+
message: "Package release not found",
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const packageFiles = ctx.db.packageFiles.filter(
|
|
41
|
+
(file) => file.package_release_id === packageReleaseId,
|
|
42
|
+
)
|
|
43
|
+
|
|
56
44
|
return ctx.json({
|
|
57
45
|
ok: true,
|
|
58
|
-
package_files:
|
|
46
|
+
package_files: packageFiles,
|
|
59
47
|
})
|
|
60
48
|
})
|
|
@@ -30,50 +30,144 @@ export default withRouteSpec({
|
|
|
30
30
|
} = req.jsonBody
|
|
31
31
|
|
|
32
32
|
if (!unscoped_name) {
|
|
33
|
-
|
|
33
|
+
// Count snippets of this type for this user
|
|
34
|
+
const userSnippets = ctx.db.packages.filter(
|
|
35
|
+
(p) =>
|
|
36
|
+
p.owner_github_username === ctx.auth.github_username &&
|
|
37
|
+
p.is_snippet === true &&
|
|
38
|
+
((p.is_board && snippet_type === "board") ||
|
|
39
|
+
(p.is_package && snippet_type === "package") ||
|
|
40
|
+
(p.is_model && snippet_type === "model") ||
|
|
41
|
+
(p.is_footprint && snippet_type === "footprint")),
|
|
42
|
+
)
|
|
43
|
+
unscoped_name = `untitled-${snippet_type}-${userSnippets.length + 1}`
|
|
34
44
|
}
|
|
35
45
|
|
|
36
|
-
const
|
|
37
|
-
(
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
const existingPackage = ctx.db.packages.find(
|
|
47
|
+
(pkg) =>
|
|
48
|
+
pkg.unscoped_name === unscoped_name &&
|
|
49
|
+
pkg.owner_github_username === ctx.auth.github_username,
|
|
40
50
|
)
|
|
41
51
|
|
|
42
|
-
if (
|
|
52
|
+
if (existingPackage) {
|
|
43
53
|
return ctx.error(400, {
|
|
44
54
|
error_code: "snippet_already_exists",
|
|
45
55
|
message: "You have already forked this snippet in your account.",
|
|
46
56
|
})
|
|
47
57
|
}
|
|
48
58
|
|
|
49
|
-
let newSnippet: Omit<
|
|
50
|
-
z.input<typeof snippetSchema>,
|
|
51
|
-
"snippet_id" | "package_release_id"
|
|
52
|
-
> = {
|
|
53
|
-
name: `${ctx.auth.github_username}/${unscoped_name}`,
|
|
54
|
-
unscoped_name,
|
|
55
|
-
owner_name: ctx.auth.github_username,
|
|
56
|
-
code,
|
|
57
|
-
created_at: new Date().toISOString(),
|
|
58
|
-
updated_at: new Date().toISOString(),
|
|
59
|
-
snippet_type,
|
|
60
|
-
description,
|
|
61
|
-
compiled_js,
|
|
62
|
-
circuit_json,
|
|
63
|
-
dts,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
59
|
try {
|
|
67
|
-
|
|
60
|
+
// Create the package directly (which will serve as our snippet)
|
|
61
|
+
const newPackage = {
|
|
62
|
+
package_id: `pkg_${Date.now()}`,
|
|
63
|
+
creator_account_id: ctx.auth.account_id,
|
|
64
|
+
owner_org_id: ctx.auth.personal_org_id,
|
|
65
|
+
owner_github_username: ctx.auth.github_username,
|
|
66
|
+
is_source_from_github: false,
|
|
67
|
+
description: description,
|
|
68
|
+
name: `${ctx.auth.github_username}/${unscoped_name}`,
|
|
69
|
+
unscoped_name: unscoped_name,
|
|
70
|
+
latest_version: "0.0.1",
|
|
71
|
+
license: null,
|
|
72
|
+
star_count: 0,
|
|
73
|
+
created_at: new Date().toISOString(),
|
|
74
|
+
updated_at: new Date().toISOString(),
|
|
75
|
+
ai_description: null,
|
|
76
|
+
is_snippet: true,
|
|
77
|
+
is_board: snippet_type === "board",
|
|
78
|
+
is_package: snippet_type === "package",
|
|
79
|
+
is_model: snippet_type === "model",
|
|
80
|
+
is_footprint: snippet_type === "footprint",
|
|
81
|
+
snippet_type: snippet_type,
|
|
82
|
+
is_private: false,
|
|
83
|
+
is_public: true,
|
|
84
|
+
is_unlisted: false,
|
|
85
|
+
latest_package_release_id: "",
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
ctx.db.addPackage(newPackage)
|
|
89
|
+
|
|
90
|
+
const newPackageRelease = {
|
|
91
|
+
package_release_id: `package_release_${Date.now()}`,
|
|
92
|
+
package_id: newPackage.package_id,
|
|
93
|
+
version: "0.0.1",
|
|
94
|
+
is_latest: true,
|
|
95
|
+
is_locked: false,
|
|
96
|
+
created_at: newPackage.created_at,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
ctx.db.addPackageRelease(newPackageRelease)
|
|
100
|
+
|
|
101
|
+
// Update the package with the release ID
|
|
102
|
+
newPackage.latest_package_release_id = newPackageRelease.package_release_id
|
|
103
|
+
|
|
104
|
+
// Add package files
|
|
105
|
+
// Add index.tsx file with the code content
|
|
106
|
+
ctx.db.addPackageFile({
|
|
107
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
108
|
+
file_path: "index.tsx",
|
|
109
|
+
content_text: code,
|
|
110
|
+
created_at: new Date().toISOString(),
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
// Add DTS file if provided
|
|
114
|
+
if (dts) {
|
|
115
|
+
ctx.db.addPackageFile({
|
|
116
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
117
|
+
file_path: "/dist/index.d.ts",
|
|
118
|
+
content_text: dts,
|
|
119
|
+
created_at: new Date().toISOString(),
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Add compiled JS if provided
|
|
124
|
+
if (compiled_js) {
|
|
125
|
+
ctx.db.addPackageFile({
|
|
126
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
127
|
+
file_path: "/dist/index.js",
|
|
128
|
+
content_text: compiled_js,
|
|
129
|
+
created_at: new Date().toISOString(),
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Add circuit JSON if provided
|
|
134
|
+
if (circuit_json) {
|
|
135
|
+
ctx.db.addPackageFile({
|
|
136
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
137
|
+
file_path: "/dist/circuit.json",
|
|
138
|
+
content_text: JSON.stringify(circuit_json),
|
|
139
|
+
created_at: new Date().toISOString(),
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Create the snippet response object
|
|
144
|
+
const snippetResponse = {
|
|
145
|
+
snippet_id: newPackage.package_id,
|
|
146
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
147
|
+
name: newPackage.name,
|
|
148
|
+
unscoped_name: newPackage.unscoped_name,
|
|
149
|
+
owner_name: ctx.auth.github_username,
|
|
150
|
+
code,
|
|
151
|
+
dts,
|
|
152
|
+
compiled_js,
|
|
153
|
+
star_count: 0,
|
|
154
|
+
created_at: newPackage.created_at,
|
|
155
|
+
updated_at: newPackage.updated_at,
|
|
156
|
+
snippet_type: snippet_type,
|
|
157
|
+
circuit_json: circuit_json,
|
|
158
|
+
description: description,
|
|
159
|
+
is_starred: false,
|
|
160
|
+
version: "0.0.1",
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return ctx.json({
|
|
164
|
+
ok: true,
|
|
165
|
+
snippet: snippetResponse,
|
|
166
|
+
})
|
|
68
167
|
} catch (error) {
|
|
69
168
|
return ctx.error(500, {
|
|
70
169
|
error_code: "snippet_creation_failed",
|
|
71
170
|
message: `Failed to create snippet: ${error}`,
|
|
72
171
|
})
|
|
73
172
|
}
|
|
74
|
-
|
|
75
|
-
return ctx.json({
|
|
76
|
-
ok: true,
|
|
77
|
-
snippet: newSnippet as any,
|
|
78
|
-
})
|
|
79
173
|
})
|