@tscircuit/fake-snippets 0.0.8 → 0.0.10
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/routes/packages/list-1.test.ts +0 -3
- package/bun-tests/fake-snippets-api/routes/packages/update.test.ts +161 -0
- package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +32 -27
- 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 +145 -569
- package/dist/bundle.js +905 -248
- package/fake-snippets-api/lib/db/db-client.ts +748 -108
- package/fake-snippets-api/lib/db/schema.ts +12 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package.ts +2 -1
- package/fake-snippets-api/routes/api/packages/list.ts +4 -1
- package/fake-snippets-api/routes/api/packages/update.ts +91 -0
- package/fake-snippets-api/routes/api/snippets/add_star.ts +30 -8
- package/fake-snippets-api/routes/api/snippets/create.ts +16 -16
- 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 +3 -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
|
@@ -5,7 +5,7 @@ import { createStore } from "zustand/vanilla"
|
|
|
5
5
|
import { combine } from "zustand/middleware"
|
|
6
6
|
import {
|
|
7
7
|
type Account,
|
|
8
|
-
type
|
|
8
|
+
type AccountPackage,
|
|
9
9
|
type LoginPage,
|
|
10
10
|
type Order,
|
|
11
11
|
type OrderFile,
|
|
@@ -15,9 +15,8 @@ import {
|
|
|
15
15
|
type Session,
|
|
16
16
|
type Snippet,
|
|
17
17
|
databaseSchema,
|
|
18
|
-
packageReleaseSchema,
|
|
19
18
|
type packageSchema,
|
|
20
|
-
snippetSchema,
|
|
19
|
+
type snippetSchema,
|
|
21
20
|
} from "./schema.ts"
|
|
22
21
|
import { seed as seedFn } from "./seed"
|
|
23
22
|
|
|
@@ -87,50 +86,252 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
87
86
|
|
|
88
87
|
return newAccount
|
|
89
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
|
+
},
|
|
90
136
|
addSnippet: (
|
|
91
137
|
snippet: Omit<
|
|
92
138
|
z.input<typeof snippetSchema>,
|
|
93
139
|
"snippet_id" | "package_release_id"
|
|
94
140
|
>,
|
|
95
141
|
): Snippet => {
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
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,
|
|
100
180
|
version: "0.0.1",
|
|
101
|
-
is_locked: false,
|
|
102
181
|
is_latest: true,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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++}`,
|
|
109
194
|
package_release_id: newPackageRelease.package_release_id,
|
|
195
|
+
file_path: "index.tsx",
|
|
196
|
+
content_text: snippet.code || "",
|
|
197
|
+
created_at: currentTime,
|
|
110
198
|
})
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
+
}
|
|
119
261
|
},
|
|
120
262
|
getNewestSnippets: (limit: number): Snippet[] => {
|
|
121
263
|
const state = get()
|
|
122
|
-
|
|
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
|
+
)
|
|
123
324
|
.map((snippet) => ({
|
|
124
325
|
...snippet,
|
|
125
|
-
|
|
126
|
-
(as) => as.snippet_id === snippet.snippet_id && as.has_starred,
|
|
127
|
-
).length,
|
|
326
|
+
description: snippet.description || "",
|
|
128
327
|
}))
|
|
129
328
|
.sort(
|
|
130
329
|
(a, b) =>
|
|
131
330
|
new Date(b.created_at).getTime() - new Date(a.created_at).getTime(),
|
|
132
331
|
)
|
|
133
332
|
.slice(0, limit)
|
|
333
|
+
|
|
334
|
+
return snippetPackages
|
|
134
335
|
},
|
|
135
336
|
getTrendingSnippets: (limit: number, since: string): Snippet[] => {
|
|
136
337
|
const state = get()
|
|
@@ -138,32 +339,68 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
138
339
|
|
|
139
340
|
// Get star counts within time period
|
|
140
341
|
const recentStars = new Map<string, number>()
|
|
141
|
-
state.
|
|
142
|
-
if (
|
|
342
|
+
state.accountPackages.forEach((ap) => {
|
|
343
|
+
if (ap.is_starred && new Date(ap.created_at).getTime() >= sinceDate) {
|
|
143
344
|
recentStars.set(
|
|
144
|
-
|
|
145
|
-
(recentStars.get(
|
|
345
|
+
ap.package_id,
|
|
346
|
+
(recentStars.get(ap.package_id) || 0) + 1,
|
|
146
347
|
)
|
|
147
348
|
}
|
|
148
349
|
})
|
|
149
350
|
|
|
150
|
-
|
|
151
|
-
.map((
|
|
152
|
-
...
|
|
153
|
-
star_count: recentStars.get(
|
|
351
|
+
const packagesWithStarCount = [...state.packages]
|
|
352
|
+
.map((pkg) => ({
|
|
353
|
+
...pkg,
|
|
354
|
+
star_count: recentStars.get(pkg.package_id) || 0,
|
|
154
355
|
}))
|
|
155
356
|
.sort((a, b) => b.star_count - a.star_count)
|
|
156
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[]
|
|
157
394
|
},
|
|
158
|
-
|
|
395
|
+
getPackagesByAuthor: (authorName?: string): Package[] => {
|
|
159
396
|
const state = get()
|
|
160
|
-
const
|
|
161
|
-
? state.
|
|
162
|
-
: state.
|
|
163
|
-
return
|
|
164
|
-
...
|
|
165
|
-
star_count: state.
|
|
166
|
-
(
|
|
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,
|
|
167
404
|
).length,
|
|
168
405
|
}))
|
|
169
406
|
},
|
|
@@ -172,63 +409,393 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
172
409
|
snippetName: string,
|
|
173
410
|
): Snippet | undefined => {
|
|
174
411
|
const state = get()
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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,
|
|
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",
|
|
178
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
|
+
}
|
|
179
469
|
},
|
|
180
470
|
updateSnippet: (
|
|
181
471
|
snippetId: string,
|
|
182
472
|
updates: Partial<Snippet>,
|
|
183
473
|
): Snippet | undefined => {
|
|
184
|
-
let updatedSnippet: Snippet | undefined
|
|
185
474
|
set((state) => {
|
|
186
|
-
const
|
|
187
|
-
(
|
|
475
|
+
const packageIndex = state.packages.findIndex(
|
|
476
|
+
(pkg) => pkg.package_id === snippetId && pkg.is_snippet === true,
|
|
188
477
|
)
|
|
189
|
-
if (
|
|
478
|
+
if (packageIndex === -1) {
|
|
190
479
|
return state
|
|
191
480
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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,
|
|
197
590
|
}
|
|
198
|
-
updatedSnippets[snippetIndex] = updatedSnippet
|
|
199
|
-
return { ...state, snippets: updatedSnippets }
|
|
200
591
|
})
|
|
201
|
-
|
|
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
|
+
}
|
|
202
643
|
},
|
|
203
644
|
getSnippetById: (snippetId: string): Snippet | undefined => {
|
|
204
645
|
const state = get()
|
|
205
|
-
|
|
206
|
-
|
|
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,
|
|
207
649
|
)
|
|
208
|
-
if (!
|
|
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",
|
|
668
|
+
)
|
|
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
|
|
209
676
|
return {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
+
: [],
|
|
214
704
|
}
|
|
215
705
|
},
|
|
216
706
|
searchSnippets: (query: string): Snippet[] => {
|
|
217
707
|
const state = get()
|
|
218
708
|
const lowercaseQuery = query.toLowerCase()
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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)
|
|
232
799
|
},
|
|
233
800
|
deleteSnippet: (snippetId: string): boolean => {
|
|
234
801
|
let deleted = false
|
|
@@ -324,58 +891,119 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
324
891
|
}))
|
|
325
892
|
return newSession
|
|
326
893
|
},
|
|
327
|
-
addStar: (accountId: string,
|
|
894
|
+
addStar: (accountId: string, packageId: string): AccountPackage => {
|
|
328
895
|
const now = new Date().toISOString()
|
|
329
|
-
const
|
|
896
|
+
const accountPackage = {
|
|
897
|
+
account_package_id: `ap_${Date.now()}`,
|
|
330
898
|
account_id: accountId,
|
|
331
|
-
|
|
332
|
-
|
|
899
|
+
package_id: packageId,
|
|
900
|
+
is_starred: true,
|
|
333
901
|
created_at: now,
|
|
334
902
|
updated_at: now,
|
|
335
903
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
|
340
930
|
},
|
|
341
|
-
removeStar: (accountId: string,
|
|
342
|
-
set((state) =>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
+
})
|
|
347
963
|
},
|
|
348
|
-
hasStarred: (accountId: string,
|
|
964
|
+
hasStarred: (accountId: string, packageId: string): boolean => {
|
|
349
965
|
const state = get()
|
|
350
|
-
return state.
|
|
351
|
-
(
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
966
|
+
return state.accountPackages.some(
|
|
967
|
+
(ap) =>
|
|
968
|
+
ap.account_id === accountId &&
|
|
969
|
+
ap.package_id === packageId &&
|
|
970
|
+
ap.is_starred,
|
|
355
971
|
)
|
|
356
972
|
},
|
|
357
973
|
addPackage: (
|
|
358
974
|
_package: Omit<z.input<typeof packageSchema>, "package_id">,
|
|
359
975
|
): Package => {
|
|
976
|
+
const timestamp = Date.now()
|
|
360
977
|
const newPackage = {
|
|
361
|
-
package_id: `package_${
|
|
978
|
+
package_id: `package_${timestamp}`,
|
|
362
979
|
..._package,
|
|
363
980
|
}
|
|
364
|
-
const packageRelease = packageReleaseSchema.parse({
|
|
365
|
-
package_release_id: `package_release_${Date.now()}`,
|
|
366
|
-
package_id: newPackage.package_id,
|
|
367
|
-
version: "0.0.1",
|
|
368
|
-
is_locked: false,
|
|
369
|
-
is_latest: true,
|
|
370
|
-
created_at: new Date().toISOString(),
|
|
371
|
-
updated_at: new Date().toISOString(),
|
|
372
|
-
})
|
|
373
|
-
newPackage.latest_package_release_id = packageRelease.package_release_id
|
|
374
981
|
set((state) => ({
|
|
375
982
|
packages: [...state.packages, newPackage as Package],
|
|
376
983
|
}))
|
|
377
984
|
return newPackage as Package
|
|
378
985
|
},
|
|
986
|
+
updatePackage: (
|
|
987
|
+
packageId: string,
|
|
988
|
+
updates: Partial<Package>,
|
|
989
|
+
): Package | undefined => {
|
|
990
|
+
let updatedPackage: Package | undefined
|
|
991
|
+
set((state) => {
|
|
992
|
+
const packageIndex = state.packages.findIndex(
|
|
993
|
+
(pkg) => pkg.package_id === packageId,
|
|
994
|
+
)
|
|
995
|
+
if (packageIndex === -1) return state
|
|
996
|
+
|
|
997
|
+
const updatedPackages = [...state.packages]
|
|
998
|
+
updatedPackages[packageIndex] = {
|
|
999
|
+
...updatedPackages[packageIndex],
|
|
1000
|
+
...updates,
|
|
1001
|
+
}
|
|
1002
|
+
updatedPackage = updatedPackages[packageIndex]
|
|
1003
|
+
return { ...state, packages: updatedPackages }
|
|
1004
|
+
})
|
|
1005
|
+
return updatedPackage
|
|
1006
|
+
},
|
|
379
1007
|
getPackageById: (packageId: string): Package | undefined => {
|
|
380
1008
|
const state = get()
|
|
381
1009
|
const pkg = state.packages.find((pkg) => pkg.package_id === packageId)
|
|
@@ -425,4 +1053,16 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
425
1053
|
}))
|
|
426
1054
|
return newPackageFile
|
|
427
1055
|
},
|
|
1056
|
+
getStarCount: (packageId: string): number => {
|
|
1057
|
+
const state = get()
|
|
1058
|
+
return state.accountPackages.filter(
|
|
1059
|
+
(ap) => ap.package_id === packageId && ap.is_starred,
|
|
1060
|
+
).length
|
|
1061
|
+
},
|
|
1062
|
+
getPackageFilesByReleaseId: (packageReleaseId: string): PackageFile[] => {
|
|
1063
|
+
const state = get()
|
|
1064
|
+
return state.packageFiles.filter(
|
|
1065
|
+
(pf) => pf.package_release_id === packageReleaseId,
|
|
1066
|
+
)
|
|
1067
|
+
},
|
|
428
1068
|
}))
|