@tscircuit/fake-snippets 0.0.7 → 0.0.9
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/packages/{list.test.ts → list-1.test.ts} +0 -55
- package/bun-tests/fake-snippets-api/routes/packages/list-2.test.ts +59 -0
- package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +32 -27
- package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +34 -1
- package/bun-tests/fake-snippets-api/routes/snippets/get.test.ts +114 -0
- package/bun-tests/fake-snippets-api/routes/snippets/get_image.test.ts +10 -6
- package/bun-tests/fake-snippets-api/routes/snippets/images.test.ts +8 -6
- package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +2 -2
- package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +10 -10
- package/bun-tests/fake-snippets-api/routes/snippets/remove_star.test.ts +8 -6
- package/bun-tests/fake-snippets-api/routes/snippets/search.test.ts +1 -1
- package/bun-tests/fake-snippets-api/routes/snippets/star-count.test.ts +19 -12
- package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +57 -16
- package/bun.lock +148 -569
- package/dist/bundle.js +844 -194
- package/fake-snippets-api/lib/db/db-client.ts +761 -147
- package/fake-snippets-api/lib/db/schema.ts +27 -6
- package/fake-snippets-api/lib/public-mapping/public-map-package.ts +8 -0
- package/fake-snippets-api/routes/api/packages/list.ts +4 -1
- package/fake-snippets-api/routes/api/snippets/add_star.ts +30 -8
- package/fake-snippets-api/routes/api/snippets/create.ts +123 -29
- package/fake-snippets-api/routes/api/snippets/delete.ts +5 -5
- package/fake-snippets-api/routes/api/snippets/download.ts +24 -10
- package/fake-snippets-api/routes/api/snippets/get.ts +46 -13
- package/fake-snippets-api/routes/api/snippets/list.ts +37 -2
- package/fake-snippets-api/routes/api/snippets/update.ts +36 -14
- package/package.json +4 -5
- package/src/components/CodeAndPreview.tsx +13 -48
- package/src/components/CodeEditor.tsx +10 -7
- package/src/components/EditorNav.tsx +0 -21
- package/src/components/PreviewContent.tsx +2 -2
- package/src/components/ViewSnippetHeader.tsx +4 -0
- package/src/hooks/use-global-store.ts +0 -5
- package/src/hooks/use-package-as-snippet.ts +78 -0
- package/src/hooks/use-run-tsx/index.tsx +4 -0
- package/src/lib/jlc-parts-engine.ts +4 -2
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { z } from "zod"
|
|
1
|
+
import type { z } from "zod"
|
|
2
|
+
import { hoist } from "zustand-hoist"
|
|
3
|
+
import { createStore } from "zustand/vanilla"
|
|
5
4
|
|
|
5
|
+
import { combine } from "zustand/middleware"
|
|
6
6
|
import {
|
|
7
|
+
type Account,
|
|
8
|
+
type AccountPackage,
|
|
9
|
+
type LoginPage,
|
|
10
|
+
type Order,
|
|
11
|
+
type OrderFile,
|
|
12
|
+
type Package,
|
|
13
|
+
type PackageFile,
|
|
14
|
+
type PackageRelease,
|
|
15
|
+
type Session,
|
|
16
|
+
type Snippet,
|
|
7
17
|
databaseSchema,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
LoginPage,
|
|
11
|
-
Account,
|
|
12
|
-
type DatabaseSchema,
|
|
13
|
-
snippetSchema,
|
|
14
|
-
Order,
|
|
15
|
-
OrderFile,
|
|
16
|
-
AccountSnippet,
|
|
17
|
-
packageReleaseSchema,
|
|
18
|
-
packageSchema,
|
|
19
|
-
Package,
|
|
20
|
-
PackageRelease,
|
|
21
|
-
PackageFile,
|
|
18
|
+
type packageSchema,
|
|
19
|
+
type snippetSchema,
|
|
22
20
|
} from "./schema.ts"
|
|
23
|
-
import { combine } from "zustand/middleware"
|
|
24
21
|
import { seed as seedFn } from "./seed"
|
|
25
22
|
|
|
26
23
|
export const createDatabase = ({ seed }: { seed?: boolean } = {}) => {
|
|
@@ -35,7 +32,7 @@ export type DbClient = ReturnType<typeof createDatabase>
|
|
|
35
32
|
|
|
36
33
|
const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
37
34
|
addOrder: (order: Omit<Order, "order_id">): Order => {
|
|
38
|
-
|
|
35
|
+
const newOrder = { order_id: `order_${get().idCounter + 1}`, ...order }
|
|
39
36
|
set((state) => {
|
|
40
37
|
return {
|
|
41
38
|
orders: [...state.orders, newOrder],
|
|
@@ -89,50 +86,252 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
89
86
|
|
|
90
87
|
return newAccount
|
|
91
88
|
},
|
|
89
|
+
addAccountPackage: (
|
|
90
|
+
accountPackage: Omit<AccountPackage, "account_package_id">,
|
|
91
|
+
): AccountPackage => {
|
|
92
|
+
const newAccountPackage = {
|
|
93
|
+
account_package_id: `ap_${get().idCounter + 1}`,
|
|
94
|
+
...accountPackage,
|
|
95
|
+
}
|
|
96
|
+
set((state) => {
|
|
97
|
+
return {
|
|
98
|
+
accountPackages: [...state.accountPackages, newAccountPackage],
|
|
99
|
+
idCounter: state.idCounter + 1,
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
return newAccountPackage
|
|
103
|
+
},
|
|
104
|
+
getAccountPackageById: (
|
|
105
|
+
accountPackageId: string,
|
|
106
|
+
): AccountPackage | undefined => {
|
|
107
|
+
const state = get()
|
|
108
|
+
return state.accountPackages.find(
|
|
109
|
+
(ap) => ap.account_package_id === accountPackageId,
|
|
110
|
+
)
|
|
111
|
+
},
|
|
112
|
+
updateAccountPackage: (
|
|
113
|
+
accountPackageId: string,
|
|
114
|
+
updates: Partial<AccountPackage>,
|
|
115
|
+
): void => {
|
|
116
|
+
set((state) => ({
|
|
117
|
+
accountPackages: state.accountPackages.map((ap) =>
|
|
118
|
+
ap.account_package_id === accountPackageId ? { ...ap, ...updates } : ap,
|
|
119
|
+
),
|
|
120
|
+
}))
|
|
121
|
+
},
|
|
122
|
+
deleteAccountPackage: (accountPackageId: string): boolean => {
|
|
123
|
+
let deleted = false
|
|
124
|
+
set((state) => {
|
|
125
|
+
const index = state.accountPackages.findIndex(
|
|
126
|
+
(ap) => ap.account_package_id === accountPackageId,
|
|
127
|
+
)
|
|
128
|
+
if (index !== -1) {
|
|
129
|
+
state.accountPackages.splice(index, 1)
|
|
130
|
+
deleted = true
|
|
131
|
+
}
|
|
132
|
+
return state
|
|
133
|
+
})
|
|
134
|
+
return deleted
|
|
135
|
+
},
|
|
92
136
|
addSnippet: (
|
|
93
137
|
snippet: Omit<
|
|
94
138
|
z.input<typeof snippetSchema>,
|
|
95
139
|
"snippet_id" | "package_release_id"
|
|
96
140
|
>,
|
|
97
141
|
): Snippet => {
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
142
|
+
const timestamp = Date.now()
|
|
143
|
+
const currentTime = new Date(timestamp).toISOString()
|
|
144
|
+
|
|
145
|
+
const newState = get()
|
|
146
|
+
const nextId = newState.idCounter + 1
|
|
147
|
+
|
|
148
|
+
// Create the package that will serve as our snippet
|
|
149
|
+
const newPackage = {
|
|
150
|
+
package_id: `pkg_${nextId}`,
|
|
151
|
+
creator_account_id: snippet.owner_name, // Using owner_name as account_id since we don't have context
|
|
152
|
+
owner_org_id: "", // Empty string instead of null to match type
|
|
153
|
+
owner_github_username: snippet.owner_name,
|
|
154
|
+
is_source_from_github: false,
|
|
155
|
+
description: snippet.description || "",
|
|
156
|
+
name: `${snippet.owner_name}/${snippet.unscoped_name}`,
|
|
157
|
+
unscoped_name: snippet.unscoped_name,
|
|
158
|
+
latest_version: "0.0.1",
|
|
159
|
+
license: null,
|
|
160
|
+
star_count: 0,
|
|
161
|
+
created_at: currentTime,
|
|
162
|
+
updated_at: currentTime,
|
|
163
|
+
ai_description: null,
|
|
164
|
+
is_snippet: true,
|
|
165
|
+
is_board: snippet.snippet_type === "board",
|
|
166
|
+
is_package: snippet.snippet_type === "package",
|
|
167
|
+
is_model: snippet.snippet_type === "model",
|
|
168
|
+
is_footprint: snippet.snippet_type === "footprint",
|
|
169
|
+
snippet_type: snippet.snippet_type,
|
|
170
|
+
is_private: false,
|
|
171
|
+
is_public: true,
|
|
172
|
+
is_unlisted: false,
|
|
173
|
+
latest_package_release_id: `package_release_${nextId}`,
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Create package release
|
|
177
|
+
const newPackageRelease = {
|
|
178
|
+
package_release_id: `package_release_${nextId}`,
|
|
179
|
+
package_id: newPackage.package_id,
|
|
102
180
|
version: "0.0.1",
|
|
103
|
-
is_locked: false,
|
|
104
181
|
is_latest: true,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
182
|
+
is_locked: false,
|
|
183
|
+
created_at: currentTime,
|
|
184
|
+
updated_at: currentTime,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Add all the files
|
|
188
|
+
const packageFiles: PackageFile[] = []
|
|
189
|
+
let fileIdCounter = nextId
|
|
190
|
+
|
|
191
|
+
// Add main code file
|
|
192
|
+
packageFiles.push({
|
|
193
|
+
package_file_id: `package_file_${fileIdCounter++}`,
|
|
111
194
|
package_release_id: newPackageRelease.package_release_id,
|
|
195
|
+
file_path: "index.tsx",
|
|
196
|
+
content_text: snippet.code || "",
|
|
197
|
+
created_at: currentTime,
|
|
112
198
|
})
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
199
|
+
|
|
200
|
+
// Add DTS file if provided
|
|
201
|
+
if (snippet.dts) {
|
|
202
|
+
packageFiles.push({
|
|
203
|
+
package_file_id: `package_file_${fileIdCounter++}`,
|
|
204
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
205
|
+
file_path: "/dist/index.d.ts",
|
|
206
|
+
content_text: snippet.dts,
|
|
207
|
+
created_at: currentTime,
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Add compiled JS if provided
|
|
212
|
+
if (snippet.compiled_js) {
|
|
213
|
+
packageFiles.push({
|
|
214
|
+
package_file_id: `package_file_${fileIdCounter++}`,
|
|
215
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
216
|
+
file_path: "/dist/index.js",
|
|
217
|
+
content_text: snippet.compiled_js,
|
|
218
|
+
created_at: currentTime,
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Add circuit JSON if provided
|
|
223
|
+
if (snippet.circuit_json && snippet.circuit_json.length > 0) {
|
|
224
|
+
packageFiles.push({
|
|
225
|
+
package_file_id: `package_file_${fileIdCounter++}`,
|
|
226
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
227
|
+
file_path: "/dist/circuit.json",
|
|
228
|
+
content_text: JSON.stringify(snippet.circuit_json),
|
|
229
|
+
created_at: currentTime,
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Update the database state atomically
|
|
234
|
+
set((state) => ({
|
|
235
|
+
...state,
|
|
236
|
+
packages: [...state.packages, newPackage],
|
|
237
|
+
packageReleases: [...state.packageReleases, newPackageRelease],
|
|
238
|
+
packageFiles: [...state.packageFiles, ...packageFiles],
|
|
239
|
+
idCounter: fileIdCounter,
|
|
240
|
+
}))
|
|
241
|
+
|
|
242
|
+
// Return in the same format as create endpoint
|
|
243
|
+
return {
|
|
244
|
+
snippet_id: newPackage.package_id,
|
|
245
|
+
package_release_id: newPackageRelease.package_release_id,
|
|
246
|
+
name: newPackage.name,
|
|
247
|
+
unscoped_name: newPackage.unscoped_name,
|
|
248
|
+
owner_name: snippet.owner_name,
|
|
249
|
+
code: snippet.code || "",
|
|
250
|
+
dts: snippet.dts,
|
|
251
|
+
compiled_js: snippet.compiled_js,
|
|
252
|
+
star_count: 0,
|
|
253
|
+
created_at: currentTime,
|
|
254
|
+
updated_at: currentTime,
|
|
255
|
+
snippet_type: snippet.snippet_type,
|
|
256
|
+
circuit_json: snippet.circuit_json || [],
|
|
257
|
+
description: snippet.description || "",
|
|
258
|
+
is_starred: false,
|
|
259
|
+
version: "0.0.1",
|
|
260
|
+
}
|
|
121
261
|
},
|
|
122
262
|
getNewestSnippets: (limit: number): Snippet[] => {
|
|
123
263
|
const state = get()
|
|
124
|
-
|
|
264
|
+
|
|
265
|
+
// Get all packages that are snippets
|
|
266
|
+
const snippetPackages = state.packages
|
|
267
|
+
.filter((pkg) => pkg.is_snippet === true)
|
|
268
|
+
.map((pkg) => {
|
|
269
|
+
// Get the package release
|
|
270
|
+
const packageRelease = state.packageReleases.find(
|
|
271
|
+
(pr) =>
|
|
272
|
+
pr.package_release_id === pkg.latest_package_release_id &&
|
|
273
|
+
pr.is_latest === true,
|
|
274
|
+
)
|
|
275
|
+
if (!packageRelease) return null
|
|
276
|
+
|
|
277
|
+
// Get the package files
|
|
278
|
+
const packageFiles = state.packageFiles.filter(
|
|
279
|
+
(file) =>
|
|
280
|
+
file.package_release_id === packageRelease.package_release_id,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
// Get the code file
|
|
284
|
+
const codeFile = packageFiles.find(
|
|
285
|
+
(file) =>
|
|
286
|
+
file.file_path === "index.ts" || file.file_path === "index.tsx",
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
// Check if starred
|
|
290
|
+
const isStarred = state.accountPackages.some(
|
|
291
|
+
(ap) => ap.package_id === pkg.package_id && ap.is_starred,
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
// Convert to snippet format
|
|
295
|
+
return {
|
|
296
|
+
snippet_id: pkg.package_id,
|
|
297
|
+
package_release_id: pkg.latest_package_release_id || "",
|
|
298
|
+
unscoped_name: pkg.unscoped_name,
|
|
299
|
+
name: pkg.name,
|
|
300
|
+
owner_name: pkg.owner_github_username || "",
|
|
301
|
+
description: pkg.description || "",
|
|
302
|
+
snippet_type: pkg.snippet_type || "board",
|
|
303
|
+
code: codeFile?.content_text || "",
|
|
304
|
+
dts:
|
|
305
|
+
packageFiles.find((file) => file.file_path === "/dist/index.d.ts")
|
|
306
|
+
?.content_text || "",
|
|
307
|
+
compiled_js:
|
|
308
|
+
packageFiles.find((file) => file.file_path === "/dist/index.js")
|
|
309
|
+
?.content_text || "",
|
|
310
|
+
created_at: pkg.created_at,
|
|
311
|
+
updated_at: pkg.updated_at,
|
|
312
|
+
star_count: pkg.star_count || 0,
|
|
313
|
+
is_starred: isStarred,
|
|
314
|
+
version: pkg.latest_version || "0.0.1",
|
|
315
|
+
circuit_json:
|
|
316
|
+
packageFiles
|
|
317
|
+
.filter((file) => file.file_path === "/dist/circuit.json")
|
|
318
|
+
.flatMap((file) => JSON.parse(file.content_text || "[]")) || [],
|
|
319
|
+
}
|
|
320
|
+
})
|
|
321
|
+
.filter(
|
|
322
|
+
(snippet): snippet is NonNullable<typeof snippet> => snippet !== null,
|
|
323
|
+
)
|
|
125
324
|
.map((snippet) => ({
|
|
126
325
|
...snippet,
|
|
127
|
-
|
|
128
|
-
(as) => as.snippet_id === snippet.snippet_id && as.has_starred,
|
|
129
|
-
).length,
|
|
326
|
+
description: snippet.description || "",
|
|
130
327
|
}))
|
|
131
328
|
.sort(
|
|
132
329
|
(a, b) =>
|
|
133
330
|
new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),
|
|
134
331
|
)
|
|
135
332
|
.slice(0, limit)
|
|
333
|
+
|
|
334
|
+
return snippetPackages
|
|
136
335
|
},
|
|
137
336
|
getTrendingSnippets: (limit: number, since: string): Snippet[] => {
|
|
138
337
|
const state = get()
|
|
@@ -140,32 +339,68 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
140
339
|
|
|
141
340
|
// Get star counts within time period
|
|
142
341
|
const recentStars = new Map<string, number>()
|
|
143
|
-
state.
|
|
144
|
-
if (
|
|
342
|
+
state.accountPackages.forEach((ap) => {
|
|
343
|
+
if (ap.is_starred && new Date(ap.created_at).getTime() >= sinceDate) {
|
|
145
344
|
recentStars.set(
|
|
146
|
-
|
|
147
|
-
(recentStars.get(
|
|
345
|
+
ap.package_id,
|
|
346
|
+
(recentStars.get(ap.package_id) || 0) + 1,
|
|
148
347
|
)
|
|
149
348
|
}
|
|
150
349
|
})
|
|
151
350
|
|
|
152
|
-
|
|
153
|
-
.map((
|
|
154
|
-
...
|
|
155
|
-
star_count: recentStars.get(
|
|
351
|
+
const packagesWithStarCount = [...state.packages]
|
|
352
|
+
.map((pkg) => ({
|
|
353
|
+
...pkg,
|
|
354
|
+
star_count: recentStars.get(pkg.package_id) || 0,
|
|
156
355
|
}))
|
|
157
356
|
.sort((a, b) => b.star_count - a.star_count)
|
|
158
357
|
.slice(0, limit)
|
|
358
|
+
|
|
359
|
+
const trendingSnippets = packagesWithStarCount
|
|
360
|
+
.map((pkg) => {
|
|
361
|
+
const packageRelease = state.packageReleases.find(
|
|
362
|
+
(pr) =>
|
|
363
|
+
pr.package_release_id === pkg.latest_package_release_id &&
|
|
364
|
+
pr.is_latest === true,
|
|
365
|
+
)
|
|
366
|
+
if (!packageRelease) return null
|
|
367
|
+
|
|
368
|
+
const packageFiles = state.packageFiles.filter(
|
|
369
|
+
(file) =>
|
|
370
|
+
file.package_release_id === packageRelease.package_release_id,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
const codeFile = packageFiles.find(
|
|
374
|
+
(file) =>
|
|
375
|
+
file.file_path === "index.ts" || file.file_path === "index.tsx",
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
return {
|
|
379
|
+
snippet_id: pkg.package_id,
|
|
380
|
+
package_release_id: pkg.latest_package_release_id || "",
|
|
381
|
+
unscoped_name: pkg.unscoped_name,
|
|
382
|
+
name: pkg.name,
|
|
383
|
+
owner_name: pkg.owner_github_username || "",
|
|
384
|
+
code: codeFile ? codeFile.content_text || "" : "",
|
|
385
|
+
created_at: pkg.created_at,
|
|
386
|
+
updated_at: pkg.updated_at,
|
|
387
|
+
snippet_type: pkg.is_snippet ? "board" : "package",
|
|
388
|
+
star_count: pkg.star_count,
|
|
389
|
+
}
|
|
390
|
+
})
|
|
391
|
+
.filter((snippet) => snippet !== null)
|
|
392
|
+
|
|
393
|
+
return trendingSnippets as Snippet[]
|
|
159
394
|
},
|
|
160
|
-
|
|
395
|
+
getPackagesByAuthor: (authorName?: string): Package[] => {
|
|
161
396
|
const state = get()
|
|
162
|
-
const
|
|
163
|
-
? state.
|
|
164
|
-
: state.
|
|
165
|
-
return
|
|
166
|
-
...
|
|
167
|
-
star_count: state.
|
|
168
|
-
(
|
|
397
|
+
const packages = authorName
|
|
398
|
+
? state.packages.filter((pkg) => pkg.owner_github_username === authorName)
|
|
399
|
+
: state.packages
|
|
400
|
+
return packages.map((pkg) => ({
|
|
401
|
+
...pkg,
|
|
402
|
+
star_count: state.accountPackages.filter(
|
|
403
|
+
(ap) => ap.package_id === pkg.package_id && ap.is_starred,
|
|
169
404
|
).length,
|
|
170
405
|
}))
|
|
171
406
|
},
|
|
@@ -174,68 +409,398 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
174
409
|
snippetName: string,
|
|
175
410
|
): Snippet | undefined => {
|
|
176
411
|
const state = get()
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
412
|
+
// Look for the package that represents this snippet with case-insensitive matching
|
|
413
|
+
const _package = state.packages.find(
|
|
414
|
+
(pkg) =>
|
|
415
|
+
pkg.owner_github_username?.toLowerCase() === authorName.toLowerCase() &&
|
|
416
|
+
pkg.name.toLowerCase() === snippetName.toLowerCase() &&
|
|
417
|
+
pkg.is_snippet === true,
|
|
418
|
+
)
|
|
419
|
+
if (!_package) return undefined
|
|
420
|
+
|
|
421
|
+
// Get the package release
|
|
422
|
+
const packageRelease = state.packageReleases.find(
|
|
423
|
+
(pr) =>
|
|
424
|
+
pr.package_release_id === _package.latest_package_release_id &&
|
|
425
|
+
pr.is_latest === true,
|
|
180
426
|
)
|
|
427
|
+
if (!packageRelease) return undefined
|
|
428
|
+
|
|
429
|
+
// Get the package files
|
|
430
|
+
const packageFiles = state.packageFiles.filter(
|
|
431
|
+
(file) => file.package_release_id === packageRelease.package_release_id,
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
// Get the code file (index.ts or index.tsx)
|
|
435
|
+
const codeFile = packageFiles.find(
|
|
436
|
+
(file) => file.file_path === "index.ts" || file.file_path === "index.tsx",
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
// Map the package data to match the Snippet structure
|
|
440
|
+
return {
|
|
441
|
+
snippet_id: _package.package_id,
|
|
442
|
+
package_release_id: _package.latest_package_release_id || "",
|
|
443
|
+
unscoped_name: _package.unscoped_name,
|
|
444
|
+
name: _package.name,
|
|
445
|
+
owner_name: _package.owner_github_username || "",
|
|
446
|
+
description: _package.description || "",
|
|
447
|
+
snippet_type: _package.snippet_type || "board",
|
|
448
|
+
code: codeFile?.content_text || "",
|
|
449
|
+
dts:
|
|
450
|
+
packageFiles.find((file) => file.file_path === "/dist/index.d.ts")
|
|
451
|
+
?.content_text || "",
|
|
452
|
+
compiled_js:
|
|
453
|
+
packageFiles.find((file) => file.file_path === "/dist/index.js")
|
|
454
|
+
?.content_text || "",
|
|
455
|
+
created_at: _package.created_at,
|
|
456
|
+
updated_at: _package.updated_at,
|
|
457
|
+
star_count: _package.star_count || 0,
|
|
458
|
+
is_starred: false,
|
|
459
|
+
version: _package.latest_version || "0.0.1",
|
|
460
|
+
circuit_json: packageFiles.find(
|
|
461
|
+
(file) => file.file_path === "/dist/circuit.json",
|
|
462
|
+
)?.content_text
|
|
463
|
+
? JSON.parse(
|
|
464
|
+
packageFiles.find((file) => file.file_path === "/dist/circuit.json")
|
|
465
|
+
?.content_text || "[]",
|
|
466
|
+
)
|
|
467
|
+
: [],
|
|
468
|
+
}
|
|
181
469
|
},
|
|
182
470
|
updateSnippet: (
|
|
183
|
-
|
|
471
|
+
snippetId: string,
|
|
184
472
|
updates: Partial<Snippet>,
|
|
185
473
|
): Snippet | undefined => {
|
|
186
|
-
let updatedSnippet: Snippet | undefined
|
|
187
474
|
set((state) => {
|
|
188
|
-
const
|
|
189
|
-
(
|
|
475
|
+
const packageIndex = state.packages.findIndex(
|
|
476
|
+
(pkg) => pkg.package_id === snippetId && pkg.is_snippet === true,
|
|
190
477
|
)
|
|
191
|
-
if (
|
|
478
|
+
if (packageIndex === -1) {
|
|
192
479
|
return state
|
|
193
480
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
481
|
+
|
|
482
|
+
const timestamp = Date.now()
|
|
483
|
+
const currentTime = new Date(timestamp).toISOString()
|
|
484
|
+
|
|
485
|
+
// Update the package
|
|
486
|
+
const updatedPackages = [...state.packages]
|
|
487
|
+
const currentPackage = updatedPackages[packageIndex]
|
|
488
|
+
updatedPackages[packageIndex] = {
|
|
489
|
+
...currentPackage,
|
|
490
|
+
description: updates.description || currentPackage.description,
|
|
491
|
+
updated_at: currentTime,
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Get the current package release
|
|
495
|
+
const packageRelease = state.packageReleases.find(
|
|
496
|
+
(pr) =>
|
|
497
|
+
pr.package_release_id === currentPackage.latest_package_release_id,
|
|
498
|
+
)
|
|
499
|
+
if (!packageRelease) return state
|
|
500
|
+
|
|
501
|
+
// Update package files if code/dts/js changed
|
|
502
|
+
const updatedFiles = [...state.packageFiles]
|
|
503
|
+
const packageFiles = updatedFiles.filter(
|
|
504
|
+
(file) => file.package_release_id === packageRelease.package_release_id,
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
if (updates.code !== undefined) {
|
|
508
|
+
const codeFileIndex = packageFiles.findIndex(
|
|
509
|
+
(file) =>
|
|
510
|
+
file.file_path === "index.tsx" || file.file_path === "index.ts",
|
|
511
|
+
)
|
|
512
|
+
if (codeFileIndex >= 0) {
|
|
513
|
+
updatedFiles[codeFileIndex] = {
|
|
514
|
+
...packageFiles[codeFileIndex],
|
|
515
|
+
content_text: updates.code,
|
|
516
|
+
created_at: currentTime,
|
|
517
|
+
}
|
|
518
|
+
} else {
|
|
519
|
+
updatedFiles.push({
|
|
520
|
+
package_file_id: `package_file_${timestamp}`,
|
|
521
|
+
package_release_id: packageRelease.package_release_id,
|
|
522
|
+
file_path: "index.tsx",
|
|
523
|
+
content_text: updates.code,
|
|
524
|
+
created_at: currentTime,
|
|
525
|
+
})
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (updates.dts !== undefined) {
|
|
530
|
+
const dtsFileIndex = packageFiles.findIndex(
|
|
531
|
+
(file) => file.file_path === "/dist/index.d.ts",
|
|
532
|
+
)
|
|
533
|
+
if (dtsFileIndex >= 0) {
|
|
534
|
+
updatedFiles[dtsFileIndex] = {
|
|
535
|
+
...packageFiles[dtsFileIndex],
|
|
536
|
+
content_text: updates.dts,
|
|
537
|
+
created_at: currentTime,
|
|
538
|
+
}
|
|
539
|
+
} else {
|
|
540
|
+
updatedFiles.push({
|
|
541
|
+
package_file_id: `package_file_${timestamp}`,
|
|
542
|
+
package_release_id: packageRelease.package_release_id,
|
|
543
|
+
file_path: "/dist/index.d.ts",
|
|
544
|
+
content_text: updates.dts,
|
|
545
|
+
created_at: currentTime,
|
|
546
|
+
})
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (updates.compiled_js !== undefined) {
|
|
551
|
+
const jsFileIndex = packageFiles.findIndex(
|
|
552
|
+
(file) => file.file_path === "/dist/index.js",
|
|
553
|
+
)
|
|
554
|
+
if (jsFileIndex >= 0) {
|
|
555
|
+
updatedFiles[jsFileIndex] = {
|
|
556
|
+
...packageFiles[jsFileIndex],
|
|
557
|
+
content_text: updates.compiled_js,
|
|
558
|
+
created_at: currentTime,
|
|
559
|
+
}
|
|
560
|
+
} else {
|
|
561
|
+
updatedFiles.push({
|
|
562
|
+
package_file_id: `package_file_${timestamp}`,
|
|
563
|
+
package_release_id: packageRelease.package_release_id,
|
|
564
|
+
file_path: "/dist/index.js",
|
|
565
|
+
content_text: updates.compiled_js,
|
|
566
|
+
created_at: currentTime,
|
|
567
|
+
})
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Update circuit JSON if provided
|
|
572
|
+
if (updates.circuit_json !== undefined) {
|
|
573
|
+
const circuitFileIndex = packageFiles.findIndex(
|
|
574
|
+
(file) => file.file_path === "/dist/circuit.json",
|
|
575
|
+
)
|
|
576
|
+
if (circuitFileIndex >= 0) {
|
|
577
|
+
updatedFiles[circuitFileIndex] = {
|
|
578
|
+
...packageFiles[circuitFileIndex],
|
|
579
|
+
content_text: JSON.stringify(updates.circuit_json),
|
|
580
|
+
created_at: new Date().toISOString(),
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Return updated state
|
|
586
|
+
return {
|
|
587
|
+
...state,
|
|
588
|
+
packages: updatedPackages,
|
|
589
|
+
packageFiles: updatedFiles,
|
|
199
590
|
}
|
|
200
|
-
updatedSnippets[snippetIndex] = updatedSnippet
|
|
201
|
-
return { ...state, snippets: updatedSnippets }
|
|
202
591
|
})
|
|
203
|
-
|
|
592
|
+
|
|
593
|
+
// Get the updated snippet to return
|
|
594
|
+
const updatedPackage = get().packages.find(
|
|
595
|
+
(pkg) => pkg.package_id === snippetId,
|
|
596
|
+
)
|
|
597
|
+
if (!updatedPackage) return undefined
|
|
598
|
+
|
|
599
|
+
const packageRelease = get().packageReleases.find(
|
|
600
|
+
(pr) =>
|
|
601
|
+
pr.package_release_id === updatedPackage.latest_package_release_id,
|
|
602
|
+
)
|
|
603
|
+
if (!packageRelease) return undefined
|
|
604
|
+
|
|
605
|
+
const packageFiles = get().packageFiles.filter(
|
|
606
|
+
(file) => file.package_release_id === packageRelease.package_release_id,
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
const codeFile = packageFiles.find(
|
|
610
|
+
(file) => file.file_path === "index.ts" || file.file_path === "index.tsx",
|
|
611
|
+
)
|
|
612
|
+
const dtsFile = packageFiles.find(
|
|
613
|
+
(file) => file.file_path === "/dist/index.d.ts",
|
|
614
|
+
)
|
|
615
|
+
const jsFile = packageFiles.find(
|
|
616
|
+
(file) => file.file_path === "/dist/index.js",
|
|
617
|
+
)
|
|
618
|
+
const circuitFile = packageFiles.find(
|
|
619
|
+
(file) => file.file_path === "/dist/circuit.json",
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
// Return in snippet format
|
|
623
|
+
return {
|
|
624
|
+
snippet_id: updatedPackage.package_id,
|
|
625
|
+
package_release_id: updatedPackage.latest_package_release_id || "",
|
|
626
|
+
unscoped_name: updatedPackage.unscoped_name,
|
|
627
|
+
name: updatedPackage.name,
|
|
628
|
+
owner_name: updatedPackage.owner_github_username || "",
|
|
629
|
+
description: updatedPackage.description || "",
|
|
630
|
+
snippet_type: updatedPackage.snippet_type || "board",
|
|
631
|
+
code: codeFile?.content_text || "",
|
|
632
|
+
dts: dtsFile?.content_text || "",
|
|
633
|
+
compiled_js: jsFile?.content_text || "",
|
|
634
|
+
created_at: updatedPackage.created_at,
|
|
635
|
+
updated_at: updatedPackage.updated_at,
|
|
636
|
+
star_count: updatedPackage.star_count || 0,
|
|
637
|
+
is_starred: false,
|
|
638
|
+
version: updatedPackage.latest_version || "0.0.1",
|
|
639
|
+
circuit_json: circuitFile
|
|
640
|
+
? JSON.parse(circuitFile.content_text || "[]")
|
|
641
|
+
: [],
|
|
642
|
+
}
|
|
204
643
|
},
|
|
205
|
-
getSnippetById: (
|
|
644
|
+
getSnippetById: (snippetId: string): Snippet | undefined => {
|
|
206
645
|
const state = get()
|
|
207
|
-
|
|
208
|
-
|
|
646
|
+
// Look for the package that represents this snippet
|
|
647
|
+
const _package = state.packages.find(
|
|
648
|
+
(pkg) => pkg.package_id === snippetId && pkg.is_snippet === true,
|
|
649
|
+
)
|
|
650
|
+
if (!_package) return undefined
|
|
651
|
+
|
|
652
|
+
// Get the package release
|
|
653
|
+
const packageRelease = state.packageReleases.find(
|
|
654
|
+
(pr) =>
|
|
655
|
+
pr.package_release_id === _package.latest_package_release_id &&
|
|
656
|
+
pr.is_latest === true,
|
|
657
|
+
)
|
|
658
|
+
if (!packageRelease) return undefined
|
|
659
|
+
|
|
660
|
+
// Get the package files
|
|
661
|
+
const packageFiles = state.packageFiles.filter(
|
|
662
|
+
(file) => file.package_release_id === packageRelease.package_release_id,
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
// Get the code file (index.ts or index.tsx)
|
|
666
|
+
const codeFile = packageFiles.find(
|
|
667
|
+
(file) => file.file_path === "index.ts" || file.file_path === "index.tsx",
|
|
209
668
|
)
|
|
210
|
-
|
|
669
|
+
|
|
670
|
+
// Check if the current user has starred this snippet
|
|
671
|
+
const isStarred = state.accountPackages.some(
|
|
672
|
+
(ap) => ap.package_id === snippetId && ap.is_starred,
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
// Map the package data to match the Snippet structure
|
|
211
676
|
return {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
677
|
+
snippet_id: _package.package_id,
|
|
678
|
+
package_release_id: _package.latest_package_release_id || "",
|
|
679
|
+
unscoped_name: _package.unscoped_name,
|
|
680
|
+
name: _package.name,
|
|
681
|
+
owner_name: _package.owner_github_username || "",
|
|
682
|
+
description: _package.description || "",
|
|
683
|
+
snippet_type: _package.snippet_type || "board",
|
|
684
|
+
code: codeFile?.content_text || "",
|
|
685
|
+
dts:
|
|
686
|
+
packageFiles.find((file) => file.file_path === "/dist/index.d.ts")
|
|
687
|
+
?.content_text || "",
|
|
688
|
+
compiled_js:
|
|
689
|
+
packageFiles.find((file) => file.file_path === "/dist/index.js")
|
|
690
|
+
?.content_text || "",
|
|
691
|
+
created_at: _package.created_at,
|
|
692
|
+
updated_at: _package.updated_at,
|
|
693
|
+
star_count: _package.star_count || 0,
|
|
694
|
+
is_starred: isStarred,
|
|
695
|
+
version: _package.latest_version || "0.0.1",
|
|
696
|
+
circuit_json: packageFiles.find(
|
|
697
|
+
(file) => file.file_path === "/dist/circuit.json",
|
|
698
|
+
)?.content_text
|
|
699
|
+
? JSON.parse(
|
|
700
|
+
packageFiles.find((file) => file.file_path === "/dist/circuit.json")
|
|
701
|
+
?.content_text || "[]",
|
|
702
|
+
)
|
|
703
|
+
: [],
|
|
216
704
|
}
|
|
217
705
|
},
|
|
218
706
|
searchSnippets: (query: string): Snippet[] => {
|
|
219
707
|
const state = get()
|
|
220
708
|
const lowercaseQuery = query.toLowerCase()
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
709
|
+
|
|
710
|
+
// Get all packages that are snippets
|
|
711
|
+
const packages = state.packages.filter((pkg) => pkg.is_snippet === true)
|
|
712
|
+
|
|
713
|
+
// Find packages that match by name or description
|
|
714
|
+
const matchingPackagesByMetadata = packages.filter(
|
|
715
|
+
(pkg) =>
|
|
716
|
+
pkg.name.toLowerCase().includes(lowercaseQuery) ||
|
|
717
|
+
pkg.description?.toLowerCase().includes(lowercaseQuery),
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
// Find packages that match by code content in any file
|
|
721
|
+
const matchingFilesByContent = state.packageFiles.filter(
|
|
722
|
+
(file) =>
|
|
723
|
+
file.content_text?.toLowerCase().includes(lowercaseQuery) ?? false,
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
// Get the packages for matching files
|
|
727
|
+
const matchingPackagesByContent = matchingFilesByContent
|
|
728
|
+
.map((file) => {
|
|
729
|
+
// Find the package release for this file
|
|
730
|
+
const packageRelease = state.packageReleases.find(
|
|
731
|
+
(pr) => pr.package_release_id === file.package_release_id,
|
|
732
|
+
)
|
|
733
|
+
if (!packageRelease) return null
|
|
734
|
+
|
|
735
|
+
// Find the package for this release
|
|
736
|
+
return packages.find(
|
|
737
|
+
(pkg) =>
|
|
738
|
+
pkg.latest_package_release_id === packageRelease.package_release_id,
|
|
739
|
+
)
|
|
740
|
+
})
|
|
741
|
+
.filter((pkg): pkg is NonNullable<typeof pkg> => pkg !== null)
|
|
742
|
+
|
|
743
|
+
// Combine both sets of matching packages and remove duplicates
|
|
744
|
+
const matchingPackages = [
|
|
745
|
+
...new Set([...matchingPackagesByMetadata, ...matchingPackagesByContent]),
|
|
746
|
+
]
|
|
747
|
+
|
|
748
|
+
// Convert matching packages to snippet format
|
|
749
|
+
return matchingPackages
|
|
750
|
+
.map((pkg) => {
|
|
751
|
+
const packageRelease = state.packageReleases.find(
|
|
752
|
+
(pr) =>
|
|
753
|
+
pr.package_release_id === pkg.latest_package_release_id &&
|
|
754
|
+
pr.is_latest === true,
|
|
755
|
+
)
|
|
756
|
+
if (!packageRelease) return null
|
|
757
|
+
|
|
758
|
+
const packageFiles = state.packageFiles.filter(
|
|
759
|
+
(file) =>
|
|
760
|
+
file.package_release_id === packageRelease.package_release_id,
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
const codeFile = packageFiles.find(
|
|
764
|
+
(file) =>
|
|
765
|
+
file.file_path === "index.ts" || file.file_path === "index.tsx",
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
const isStarred = state.accountPackages.some(
|
|
769
|
+
(ap) => ap.package_id === pkg.package_id && ap.is_starred,
|
|
770
|
+
)
|
|
771
|
+
|
|
772
|
+
return {
|
|
773
|
+
snippet_id: pkg.package_id,
|
|
774
|
+
package_release_id: pkg.latest_package_release_id || "",
|
|
775
|
+
unscoped_name: pkg.unscoped_name,
|
|
776
|
+
name: pkg.name,
|
|
777
|
+
owner_name: pkg.owner_github_username || "",
|
|
778
|
+
description: pkg.description || "",
|
|
779
|
+
snippet_type: pkg.snippet_type || "board",
|
|
780
|
+
code: codeFile?.content_text || "",
|
|
781
|
+
dts:
|
|
782
|
+
packageFiles.find((file) => file.file_path === "/dist/index.d.ts")
|
|
783
|
+
?.content_text || "",
|
|
784
|
+
compiled_js:
|
|
785
|
+
packageFiles.find((file) => file.file_path === "/dist/index.js")
|
|
786
|
+
?.content_text || "",
|
|
787
|
+
created_at: pkg.created_at,
|
|
788
|
+
updated_at: pkg.updated_at,
|
|
789
|
+
star_count: pkg.star_count || 0,
|
|
790
|
+
is_starred: isStarred,
|
|
791
|
+
version: pkg.latest_version || "0.0.1",
|
|
792
|
+
circuit_json:
|
|
793
|
+
packageFiles
|
|
794
|
+
.filter((file) => file.file_path === "/dist/circuit.json")
|
|
795
|
+
.flatMap((file) => JSON.parse(file.content_text || "[]")) || [],
|
|
796
|
+
} as Snippet
|
|
797
|
+
})
|
|
798
|
+
.filter((snippet): snippet is Snippet => snippet !== null)
|
|
234
799
|
},
|
|
235
|
-
deleteSnippet: (
|
|
800
|
+
deleteSnippet: (snippetId: string): boolean => {
|
|
236
801
|
let deleted = false
|
|
237
802
|
set((state) => {
|
|
238
|
-
const index = state.snippets.findIndex((s) => s.snippet_id ===
|
|
803
|
+
const index = state.snippets.findIndex((s) => s.snippet_id === snippetId)
|
|
239
804
|
if (index !== -1) {
|
|
240
805
|
state.snippets.splice(index, 1)
|
|
241
806
|
deleted = true
|
|
@@ -277,32 +842,29 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
277
842
|
}))
|
|
278
843
|
return newLoginPage
|
|
279
844
|
},
|
|
280
|
-
getLoginPage: (
|
|
845
|
+
getLoginPage: (loginPageId: string): LoginPage | undefined => {
|
|
281
846
|
const state = get()
|
|
282
|
-
return state.loginPages.find((lp) => lp.login_page_id ===
|
|
847
|
+
return state.loginPages.find((lp) => lp.login_page_id === loginPageId)
|
|
283
848
|
},
|
|
284
|
-
updateLoginPage: (
|
|
285
|
-
login_page_id: string,
|
|
286
|
-
updates: Partial<LoginPage>,
|
|
287
|
-
): void => {
|
|
849
|
+
updateLoginPage: (loginPageId: string, updates: Partial<LoginPage>): void => {
|
|
288
850
|
set((state) => ({
|
|
289
851
|
loginPages: state.loginPages.map((lp) =>
|
|
290
|
-
lp.login_page_id ===
|
|
852
|
+
lp.login_page_id === loginPageId ? { ...lp, ...updates } : lp,
|
|
291
853
|
),
|
|
292
854
|
}))
|
|
293
855
|
},
|
|
294
|
-
getAccount: (
|
|
856
|
+
getAccount: (accountId: string): Account | undefined => {
|
|
295
857
|
const state = get()
|
|
296
|
-
return state.accounts.find((account) => account.account_id ===
|
|
858
|
+
return state.accounts.find((account) => account.account_id === accountId)
|
|
297
859
|
},
|
|
298
860
|
updateAccount: (
|
|
299
|
-
|
|
861
|
+
accountId: string,
|
|
300
862
|
updates: Partial<Account>,
|
|
301
863
|
): Account | undefined => {
|
|
302
864
|
let updatedAccount: Account | undefined
|
|
303
865
|
set((state) => {
|
|
304
866
|
const accountIndex = state.accounts.findIndex(
|
|
305
|
-
(account) => account.account_id ===
|
|
867
|
+
(account) => account.account_id === accountId,
|
|
306
868
|
)
|
|
307
869
|
if (accountIndex !== -1) {
|
|
308
870
|
updatedAccount = { ...state.accounts[accountIndex] }
|
|
@@ -329,72 +891,112 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
329
891
|
}))
|
|
330
892
|
return newSession
|
|
331
893
|
},
|
|
332
|
-
addStar: (
|
|
894
|
+
addStar: (accountId: string, packageId: string): AccountPackage => {
|
|
333
895
|
const now = new Date().toISOString()
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
896
|
+
const accountPackage = {
|
|
897
|
+
account_package_id: `ap_${Date.now()}`,
|
|
898
|
+
account_id: accountId,
|
|
899
|
+
package_id: packageId,
|
|
900
|
+
is_starred: true,
|
|
338
901
|
created_at: now,
|
|
339
902
|
updated_at: now,
|
|
340
903
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
904
|
+
|
|
905
|
+
// Update the package's star count
|
|
906
|
+
set((state) => {
|
|
907
|
+
// Find the package and increment its star count
|
|
908
|
+
const packageIndex = state.packages.findIndex(
|
|
909
|
+
(pkg) => pkg.package_id === packageId,
|
|
910
|
+
)
|
|
911
|
+
if (packageIndex >= 0) {
|
|
912
|
+
const updatedPackages = [...state.packages]
|
|
913
|
+
updatedPackages[packageIndex] = {
|
|
914
|
+
...updatedPackages[packageIndex],
|
|
915
|
+
star_count: (updatedPackages[packageIndex].star_count || 0) + 1,
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
return {
|
|
919
|
+
packages: updatedPackages,
|
|
920
|
+
accountPackages: [...state.accountPackages, accountPackage],
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return {
|
|
925
|
+
accountPackages: [...state.accountPackages, accountPackage],
|
|
926
|
+
}
|
|
927
|
+
})
|
|
928
|
+
|
|
929
|
+
return accountPackage
|
|
345
930
|
},
|
|
346
|
-
removeStar: (
|
|
347
|
-
set((state) =>
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
931
|
+
removeStar: (accountId: string, packageId: string): void => {
|
|
932
|
+
set((state) => {
|
|
933
|
+
// Find the package and decrement its star count
|
|
934
|
+
const packageIndex = state.packages.findIndex(
|
|
935
|
+
(pkg) => pkg.package_id === packageId,
|
|
936
|
+
)
|
|
937
|
+
|
|
938
|
+
if (packageIndex >= 0) {
|
|
939
|
+
const updatedPackages = [...state.packages]
|
|
940
|
+
updatedPackages[packageIndex] = {
|
|
941
|
+
...updatedPackages[packageIndex],
|
|
942
|
+
star_count: Math.max(
|
|
943
|
+
0,
|
|
944
|
+
(updatedPackages[packageIndex].star_count || 0) - 1,
|
|
945
|
+
),
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
return {
|
|
949
|
+
packages: updatedPackages,
|
|
950
|
+
accountPackages: state.accountPackages.filter(
|
|
951
|
+
(ap) =>
|
|
952
|
+
!(ap.account_id === accountId && ap.package_id === packageId),
|
|
953
|
+
),
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return {
|
|
958
|
+
accountPackages: state.accountPackages.filter(
|
|
959
|
+
(ap) => !(ap.account_id === accountId && ap.package_id === packageId),
|
|
960
|
+
),
|
|
961
|
+
}
|
|
962
|
+
})
|
|
352
963
|
},
|
|
353
|
-
hasStarred: (
|
|
964
|
+
hasStarred: (accountId: string, packageId: string): boolean => {
|
|
354
965
|
const state = get()
|
|
355
|
-
return state.
|
|
356
|
-
(
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
966
|
+
return state.accountPackages.some(
|
|
967
|
+
(ap) =>
|
|
968
|
+
ap.account_id === accountId &&
|
|
969
|
+
ap.package_id === packageId &&
|
|
970
|
+
ap.is_starred,
|
|
360
971
|
)
|
|
361
972
|
},
|
|
362
973
|
addPackage: (
|
|
363
974
|
_package: Omit<z.input<typeof packageSchema>, "package_id">,
|
|
364
975
|
): Package => {
|
|
976
|
+
const timestamp = Date.now()
|
|
365
977
|
const newPackage = {
|
|
366
|
-
package_id: `package_${
|
|
978
|
+
package_id: `package_${timestamp}`,
|
|
367
979
|
..._package,
|
|
368
980
|
}
|
|
369
|
-
const packageRelease = packageReleaseSchema.parse({
|
|
370
|
-
package_release_id: `package_release_${Date.now()}`,
|
|
371
|
-
package_id: newPackage.package_id,
|
|
372
|
-
version: "0.0.1",
|
|
373
|
-
is_locked: false,
|
|
374
|
-
is_latest: true,
|
|
375
|
-
created_at: new Date().toISOString(),
|
|
376
|
-
updated_at: new Date().toISOString(),
|
|
377
|
-
})
|
|
378
|
-
newPackage.latest_package_release_id = packageRelease.package_release_id
|
|
379
981
|
set((state) => ({
|
|
380
|
-
packages: [...state.packages, newPackage],
|
|
982
|
+
packages: [...state.packages, newPackage as Package],
|
|
381
983
|
}))
|
|
382
|
-
return newPackage
|
|
984
|
+
return newPackage as Package
|
|
383
985
|
},
|
|
384
|
-
getPackageById: (
|
|
986
|
+
getPackageById: (packageId: string): Package | undefined => {
|
|
385
987
|
const state = get()
|
|
386
|
-
const pkg = state.packages.find((pkg) => pkg.package_id ===
|
|
988
|
+
const pkg = state.packages.find((pkg) => pkg.package_id === packageId)
|
|
387
989
|
if (!pkg) return undefined
|
|
388
990
|
return {
|
|
389
991
|
...pkg,
|
|
390
992
|
}
|
|
391
993
|
},
|
|
392
994
|
getPackageReleaseById: (
|
|
393
|
-
|
|
995
|
+
packageReleaseId: string,
|
|
394
996
|
): PackageRelease | undefined => {
|
|
395
997
|
const state = get()
|
|
396
998
|
return state.packageReleases.find(
|
|
397
|
-
(pr) => pr.package_release_id ===
|
|
999
|
+
(pr) => pr.package_release_id === packageReleaseId,
|
|
398
1000
|
)
|
|
399
1001
|
},
|
|
400
1002
|
addPackageRelease: (
|
|
@@ -430,4 +1032,16 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
430
1032
|
}))
|
|
431
1033
|
return newPackageFile
|
|
432
1034
|
},
|
|
1035
|
+
getStarCount: (packageId: string): number => {
|
|
1036
|
+
const state = get()
|
|
1037
|
+
return state.accountPackages.filter(
|
|
1038
|
+
(ap) => ap.package_id === packageId && ap.is_starred,
|
|
1039
|
+
).length
|
|
1040
|
+
},
|
|
1041
|
+
getPackageFilesByReleaseId: (packageReleaseId: string): PackageFile[] => {
|
|
1042
|
+
const state = get()
|
|
1043
|
+
return state.packageFiles.filter(
|
|
1044
|
+
(pf) => pf.package_release_id === packageReleaseId,
|
|
1045
|
+
)
|
|
1046
|
+
},
|
|
433
1047
|
}))
|