pilothub 0.0.1 → 0.0.2
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/LICENSE +1 -0
- package/README.md +36 -129
- package/dist/browserAuth.d.ts +20 -0
- package/dist/browserAuth.js +156 -0
- package/dist/browserAuth.js.map +1 -0
- package/dist/browserAuth.test.d.ts +1 -0
- package/dist/browserAuth.test.js +83 -0
- package/dist/browserAuth.test.js.map +1 -0
- package/dist/cli/buildInfo.d.ts +3 -0
- package/dist/cli/buildInfo.js +103 -0
- package/dist/cli/buildInfo.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +9 -0
- package/dist/cli/commands/auth.js +75 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/delete.d.ts +11 -0
- package/dist/cli/commands/delete.js +67 -0
- package/dist/cli/commands/delete.js.map +1 -0
- package/dist/cli/commands/delete.test.d.ts +1 -0
- package/dist/cli/commands/delete.test.js +52 -0
- package/dist/cli/commands/delete.test.js.map +1 -0
- package/dist/cli/commands/publish.d.ts +9 -0
- package/dist/cli/commands/publish.js +87 -0
- package/dist/cli/commands/publish.js.map +1 -0
- package/dist/cli/commands/publish.test.d.ts +1 -0
- package/dist/cli/commands/publish.test.js +104 -0
- package/dist/cli/commands/publish.test.js.map +1 -0
- package/dist/cli/commands/skills.d.ts +23 -0
- package/dist/cli/commands/skills.js +298 -0
- package/dist/cli/commands/skills.js.map +1 -0
- package/dist/cli/commands/skills.test.d.ts +1 -0
- package/dist/cli/commands/skills.test.js +156 -0
- package/dist/cli/commands/skills.test.js.map +1 -0
- package/dist/cli/commands/star.d.ts +8 -0
- package/dist/cli/commands/star.js +38 -0
- package/dist/cli/commands/star.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +3 -0
- package/dist/cli/commands/sync.js +160 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/sync.test.d.ts +1 -0
- package/dist/cli/commands/sync.test.js +277 -0
- package/dist/cli/commands/sync.test.js.map +1 -0
- package/dist/cli/commands/syncHelpers.d.ts +76 -0
- package/dist/cli/commands/syncHelpers.js +349 -0
- package/dist/cli/commands/syncHelpers.js.map +1 -0
- package/dist/cli/commands/syncHelpers.test.d.ts +1 -0
- package/dist/cli/commands/syncHelpers.test.js +22 -0
- package/dist/cli/commands/syncHelpers.test.js.map +1 -0
- package/dist/cli/commands/syncTypes.d.ts +24 -0
- package/dist/cli/commands/syncTypes.js +2 -0
- package/dist/cli/commands/syncTypes.js.map +1 -0
- package/dist/cli/commands/unstar.d.ts +8 -0
- package/dist/cli/commands/unstar.js +38 -0
- package/dist/cli/commands/unstar.js.map +1 -0
- package/dist/cli/helpStyle.d.ts +13 -0
- package/dist/cli/helpStyle.js +38 -0
- package/dist/cli/helpStyle.js.map +1 -0
- package/dist/cli/pilotbotConfig.d.ts +6 -0
- package/dist/cli/pilotbotConfig.js +110 -0
- package/dist/cli/pilotbotConfig.js.map +1 -0
- package/dist/cli/pilotbotConfig.test.d.ts +1 -0
- package/dist/cli/pilotbotConfig.test.js +133 -0
- package/dist/cli/pilotbotConfig.test.js.map +1 -0
- package/dist/cli/registry.d.ts +7 -0
- package/dist/cli/registry.js +42 -0
- package/dist/cli/registry.js.map +1 -0
- package/dist/cli/registry.test.d.ts +1 -0
- package/dist/cli/registry.test.js +48 -0
- package/dist/cli/registry.test.js.map +1 -0
- package/dist/cli/scanSkills.d.ts +7 -0
- package/dist/cli/scanSkills.js +75 -0
- package/dist/cli/scanSkills.js.map +1 -0
- package/dist/cli/scanSkills.test.d.ts +1 -0
- package/dist/cli/scanSkills.test.js +60 -0
- package/dist/cli/scanSkills.test.js.map +1 -0
- package/dist/cli/slug.d.ts +2 -0
- package/dist/cli/slug.js +16 -0
- package/dist/cli/slug.js.map +1 -0
- package/dist/cli/types.d.ts +15 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/ui.d.ts +7 -0
- package/dist/cli/ui.js +72 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +268 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts +5 -0
- package/dist/discovery.js +21 -0
- package/dist/discovery.js.map +1 -0
- package/dist/discovery.test.d.ts +1 -0
- package/dist/discovery.test.js +46 -0
- package/dist/discovery.test.js.map +1 -0
- package/dist/http.d.ts +32 -0
- package/dist/http.js +261 -0
- package/dist/http.js.map +1 -0
- package/dist/http.test.d.ts +1 -0
- package/dist/http.test.js +135 -0
- package/dist/http.test.js.map +1 -0
- package/dist/schema/ark.js.map +1 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/routes.js.map +1 -0
- package/{packages/schema/dist → dist/schema}/schemas.d.ts +0 -39
- package/{packages/schema/dist → dist/schema}/schemas.js +0 -22
- package/dist/schema/schemas.js.map +1 -0
- package/dist/schema/textFiles.js.map +1 -0
- package/dist/schema/textFiles.test.d.ts +1 -0
- package/dist/schema/textFiles.test.js +20 -0
- package/dist/schema/textFiles.test.js.map +1 -0
- package/dist/skills.d.ts +43 -0
- package/dist/skills.js +163 -0
- package/dist/skills.js.map +1 -0
- package/dist/skills.test.d.ts +1 -0
- package/dist/skills.test.js +144 -0
- package/dist/skills.test.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +27 -70
- package/.env.local.example +0 -19
- package/.github/workflows/ci.yml +0 -40
- package/.oxlintrc.json +0 -3
- package/AGENTS.md +0 -45
- package/CHANGELOG.md +0 -138
- package/DEPRECATIONS.md +0 -7
- package/biome.json +0 -41
- package/convex/_generated/api.d.ts +0 -153
- package/convex/_generated/api.js +0 -23
- package/convex/_generated/dataModel.d.ts +0 -60
- package/convex/_generated/server.d.ts +0 -143
- package/convex/_generated/server.js +0 -93
- package/convex/auth.config.ts +0 -8
- package/convex/auth.ts +0 -19
- package/convex/comments.ts +0 -88
- package/convex/crons.ts +0 -34
- package/convex/devSeed.ts +0 -459
- package/convex/devSeedExtra.ts +0 -541
- package/convex/downloads.ts +0 -78
- package/convex/githubBackups.ts +0 -170
- package/convex/githubBackupsNode.ts +0 -183
- package/convex/githubImport.ts +0 -317
- package/convex/githubSoulBackups.ts +0 -170
- package/convex/githubSoulBackupsNode.ts +0 -186
- package/convex/http.ts +0 -194
- package/convex/httpApi.handlers.test.ts +0 -488
- package/convex/httpApi.test.ts +0 -70
- package/convex/httpApi.ts +0 -305
- package/convex/httpApiV1.handlers.test.ts +0 -584
- package/convex/httpApiV1.ts +0 -1172
- package/convex/leaderboards.ts +0 -39
- package/convex/lib/access.ts +0 -36
- package/convex/lib/apiTokenAuth.ts +0 -36
- package/convex/lib/badges.ts +0 -50
- package/convex/lib/changelog.test.ts +0 -34
- package/convex/lib/changelog.ts +0 -278
- package/convex/lib/embeddings.ts +0 -38
- package/convex/lib/githubBackup.ts +0 -443
- package/convex/lib/githubImport.test.ts +0 -247
- package/convex/lib/githubImport.ts +0 -425
- package/convex/lib/githubSoulBackup.ts +0 -443
- package/convex/lib/leaderboards.ts +0 -103
- package/convex/lib/moderation.ts +0 -42
- package/convex/lib/public.ts +0 -89
- package/convex/lib/searchText.test.ts +0 -46
- package/convex/lib/searchText.ts +0 -27
- package/convex/lib/skillBackfill.test.ts +0 -34
- package/convex/lib/skillBackfill.ts +0 -67
- package/convex/lib/skillPublish.test.ts +0 -28
- package/convex/lib/skillPublish.ts +0 -284
- package/convex/lib/skillStats.ts +0 -80
- package/convex/lib/skills.test.ts +0 -197
- package/convex/lib/skills.ts +0 -273
- package/convex/lib/soulChangelog.ts +0 -273
- package/convex/lib/soulPublish.ts +0 -236
- package/convex/lib/tokens.test.ts +0 -33
- package/convex/lib/tokens.ts +0 -51
- package/convex/lib/webhooks.test.ts +0 -91
- package/convex/lib/webhooks.ts +0 -112
- package/convex/maintenance.test.ts +0 -270
- package/convex/maintenance.ts +0 -840
- package/convex/rateLimits.ts +0 -50
- package/convex/schema.ts +0 -472
- package/convex/search.test.ts +0 -12
- package/convex/search.ts +0 -254
- package/convex/seed.test.ts +0 -37
- package/convex/seed.ts +0 -254
- package/convex/seedSouls.ts +0 -111
- package/convex/skillStatEvents.ts +0 -568
- package/convex/skills.ts +0 -1606
- package/convex/soulComments.ts +0 -88
- package/convex/soulDownloads.ts +0 -14
- package/convex/soulStars.ts +0 -71
- package/convex/souls.ts +0 -570
- package/convex/stars.ts +0 -108
- package/convex/statsMaintenance.ts +0 -205
- package/convex/telemetry.ts +0 -434
- package/convex/tokens.ts +0 -88
- package/convex/tsconfig.json +0 -7
- package/convex/uploads.ts +0 -20
- package/convex/users.ts +0 -122
- package/convex/webhooks.ts +0 -50
- package/convex.json +0 -3
- package/docs/README.md +0 -32
- package/docs/api.md +0 -51
- package/docs/architecture.md +0 -61
- package/docs/auth.md +0 -54
- package/docs/cli.md +0 -117
- package/docs/deploy.md +0 -78
- package/docs/diffing.md +0 -84
- package/docs/github-import.md +0 -171
- package/docs/http-api.md +0 -187
- package/docs/manual-testing.md +0 -64
- package/docs/mintlify.md +0 -43
- package/docs/quickstart.md +0 -120
- package/docs/skill-format.md +0 -58
- package/docs/soul-format.md +0 -37
- package/docs/spec.md +0 -177
- package/docs/telemetry.md +0 -91
- package/docs/troubleshooting.md +0 -49
- package/docs/webhook.md +0 -51
- package/e2e/menu-smoke.pw.test.ts +0 -49
- package/e2e/pilothub.e2e.test.ts +0 -494
- package/e2e/search-exact.pw.test.ts +0 -97
- package/packages/pilothub/LICENSE +0 -22
- package/packages/pilothub/README.md +0 -57
- package/packages/pilothub/package.json +0 -41
- package/packages/pilothub/src/browserAuth.test.ts +0 -96
- package/packages/pilothub/src/browserAuth.ts +0 -174
- package/packages/pilothub/src/cli/buildInfo.ts +0 -94
- package/packages/pilothub/src/cli/commands/auth.ts +0 -97
- package/packages/pilothub/src/cli/commands/delete.test.ts +0 -73
- package/packages/pilothub/src/cli/commands/delete.ts +0 -83
- package/packages/pilothub/src/cli/commands/publish.test.ts +0 -122
- package/packages/pilothub/src/cli/commands/publish.ts +0 -108
- package/packages/pilothub/src/cli/commands/skills.test.ts +0 -191
- package/packages/pilothub/src/cli/commands/skills.ts +0 -380
- package/packages/pilothub/src/cli/commands/star.ts +0 -46
- package/packages/pilothub/src/cli/commands/sync.test.ts +0 -310
- package/packages/pilothub/src/cli/commands/sync.ts +0 -200
- package/packages/pilothub/src/cli/commands/syncHelpers.test.ts +0 -26
- package/packages/pilothub/src/cli/commands/syncHelpers.ts +0 -427
- package/packages/pilothub/src/cli/commands/syncTypes.ts +0 -27
- package/packages/pilothub/src/cli/commands/unstar.ts +0 -48
- package/packages/pilothub/src/cli/helpStyle.ts +0 -45
- package/packages/pilothub/src/cli/pilotbotConfig.test.ts +0 -159
- package/packages/pilothub/src/cli/pilotbotConfig.ts +0 -147
- package/packages/pilothub/src/cli/registry.test.ts +0 -63
- package/packages/pilothub/src/cli/registry.ts +0 -43
- package/packages/pilothub/src/cli/scanSkills.test.ts +0 -64
- package/packages/pilothub/src/cli/scanSkills.ts +0 -84
- package/packages/pilothub/src/cli/slug.ts +0 -16
- package/packages/pilothub/src/cli/types.ts +0 -12
- package/packages/pilothub/src/cli/ui.ts +0 -75
- package/packages/pilothub/src/cli.ts +0 -311
- package/packages/pilothub/src/config.ts +0 -36
- package/packages/pilothub/src/discovery.test.ts +0 -75
- package/packages/pilothub/src/discovery.ts +0 -19
- package/packages/pilothub/src/http.test.ts +0 -156
- package/packages/pilothub/src/http.ts +0 -301
- package/packages/pilothub/src/schema/ark.ts +0 -29
- package/packages/pilothub/src/schema/index.ts +0 -5
- package/packages/pilothub/src/schema/routes.ts +0 -22
- package/packages/pilothub/src/schema/schemas.ts +0 -260
- package/packages/pilothub/src/schema/textFiles.test.ts +0 -23
- package/packages/pilothub/src/schema/textFiles.ts +0 -66
- package/packages/pilothub/src/skills.test.ts +0 -191
- package/packages/pilothub/src/skills.ts +0 -172
- package/packages/pilothub/src/types.ts +0 -10
- package/packages/pilothub/tsconfig.json +0 -14
- package/packages/schema/README.md +0 -3
- package/packages/schema/dist/ark.js.map +0 -1
- package/packages/schema/dist/index.js.map +0 -1
- package/packages/schema/dist/routes.js.map +0 -1
- package/packages/schema/dist/schemas.js.map +0 -1
- package/packages/schema/dist/textFiles.js.map +0 -1
- package/packages/schema/package.json +0 -26
- package/packages/schema/src/ark.ts +0 -29
- package/packages/schema/src/index.ts +0 -5
- package/packages/schema/src/routes.ts +0 -22
- package/packages/schema/src/schemas.test.ts +0 -123
- package/packages/schema/src/schemas.ts +0 -287
- package/packages/schema/src/textFiles.test.ts +0 -23
- package/packages/schema/src/textFiles.ts +0 -66
- package/packages/schema/tsconfig.json +0 -15
- package/pilothub +0 -46
- package/playwright.config.ts +0 -33
- package/public/.well-known/pilothub.json +0 -6
- package/public/api/v1/openapi.json +0 -379
- package/public/favicon.ico +0 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +0 -25
- package/public/og.png +0 -0
- package/public/og.svg +0 -98
- package/public/pilot-logo.png +0 -0
- package/public/pilot-mark.png +0 -0
- package/public/robots.txt +0 -3
- package/public/tanstack-circle-logo.png +0 -0
- package/public/tanstack-word-logo-white.svg +0 -1
- package/scripts/check-peer-deps.ts +0 -56
- package/scripts/docs-list.ts +0 -148
- package/scripts/run-playwright-local.sh +0 -14
- package/server/og/fetchSkillOgMeta.ts +0 -27
- package/server/og/fetchSoulOgMeta.ts +0 -27
- package/server/og/ogAssets.ts +0 -80
- package/server/og/skillOgSvg.test.ts +0 -59
- package/server/og/skillOgSvg.ts +0 -258
- package/server/og/soulOgSvg.ts +0 -209
- package/server/routes/og/skill.png.ts +0 -103
- package/server/routes/og/soul.png.ts +0 -111
- package/src/__tests__/skill-detail-page.test.tsx +0 -86
- package/src/__tests__/skills-index.test.tsx +0 -145
- package/src/__tests__/upload.route.test.tsx +0 -228
- package/src/components/AppProviders.tsx +0 -19
- package/src/components/ClientOnly.tsx +0 -18
- package/src/components/Footer.tsx +0 -29
- package/src/components/Header.tsx +0 -295
- package/src/components/InstallSwitcher.tsx +0 -53
- package/src/components/SkillCard.tsx +0 -36
- package/src/components/SkillDetailPage.tsx +0 -817
- package/src/components/SkillDiffCard.tsx +0 -485
- package/src/components/SoulCard.tsx +0 -19
- package/src/components/SoulDetailPage.tsx +0 -263
- package/src/components/UserBootstrap.tsx +0 -18
- package/src/components/ui/dropdown-menu.tsx +0 -67
- package/src/components/ui/toggle-group.tsx +0 -35
- package/src/convex/client.ts +0 -3
- package/src/lib/badges.ts +0 -29
- package/src/lib/diffing.test.ts +0 -163
- package/src/lib/diffing.ts +0 -106
- package/src/lib/gravatar.test.ts +0 -9
- package/src/lib/gravatar.ts +0 -158
- package/src/lib/og.test.ts +0 -142
- package/src/lib/og.ts +0 -156
- package/src/lib/publicUser.ts +0 -39
- package/src/lib/roles.ts +0 -19
- package/src/lib/site.test.ts +0 -130
- package/src/lib/site.ts +0 -84
- package/src/lib/theme-transition.test.ts +0 -134
- package/src/lib/theme-transition.ts +0 -134
- package/src/lib/theme.test.tsx +0 -88
- package/src/lib/theme.ts +0 -43
- package/src/lib/uploadFiles.jsdom.test.ts +0 -33
- package/src/lib/uploadFiles.test.ts +0 -123
- package/src/lib/uploadFiles.ts +0 -245
- package/src/lib/uploadUtils.test.ts +0 -78
- package/src/lib/uploadUtils.ts +0 -93
- package/src/lib/useAuthStatus.ts +0 -12
- package/src/lib/utils.test.ts +0 -9
- package/src/lib/utils.ts +0 -6
- package/src/logo.svg +0 -12
- package/src/routeTree.gen.ts +0 -345
- package/src/router.tsx +0 -17
- package/src/routes/$owner/$slug.tsx +0 -55
- package/src/routes/__root.tsx +0 -136
- package/src/routes/admin.tsx +0 -11
- package/src/routes/cli/auth.tsx +0 -168
- package/src/routes/dashboard.tsx +0 -97
- package/src/routes/import.tsx +0 -415
- package/src/routes/index.tsx +0 -252
- package/src/routes/management.tsx +0 -529
- package/src/routes/settings.tsx +0 -203
- package/src/routes/skills/index.tsx +0 -422
- package/src/routes/souls/$slug.tsx +0 -55
- package/src/routes/souls/index.tsx +0 -243
- package/src/routes/stars.tsx +0 -68
- package/src/routes/u/$handle.tsx +0 -307
- package/src/routes/upload/utils.ts +0 -81
- package/src/routes/upload.tsx +0 -499
- package/src/styles.css +0 -2718
- package/tsconfig.json +0 -24
- package/tsconfig.oxlint.json +0 -16
- package/vercel.json +0 -8
- package/vite.config.ts +0 -48
- package/vitest.config.ts +0 -47
- package/vitest.e2e.config.ts +0 -11
- package/vitest.setup.ts +0 -1
- /package/{packages/pilothub/bin → bin}/pilothub.js +0 -0
- /package/{packages/schema/dist → dist/schema}/ark.d.ts +0 -0
- /package/{packages/schema/dist → dist/schema}/ark.js +0 -0
- /package/{packages/schema/dist → dist/schema}/index.d.ts +0 -0
- /package/{packages/schema/dist → dist/schema}/index.js +0 -0
- /package/{packages/schema/dist → dist/schema}/routes.d.ts +0 -0
- /package/{packages/schema/dist → dist/schema}/routes.js +0 -0
- /package/{packages/schema/dist → dist/schema}/textFiles.d.ts +0 -0
- /package/{packages/schema/dist → dist/schema}/textFiles.js +0 -0
package/convex/leaderboards.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { v } from 'convex/values'
|
|
2
|
-
import { internalMutation } from './_generated/server'
|
|
3
|
-
import { buildTrendingLeaderboard } from './lib/leaderboards'
|
|
4
|
-
|
|
5
|
-
const MAX_TRENDING_LIMIT = 200
|
|
6
|
-
const KEEP_LEADERBOARD_ENTRIES = 3
|
|
7
|
-
|
|
8
|
-
export const rebuildTrendingLeaderboardInternal = internalMutation({
|
|
9
|
-
args: { limit: v.optional(v.number()) },
|
|
10
|
-
handler: async (ctx, args) => {
|
|
11
|
-
const limit = clampInt(args.limit ?? MAX_TRENDING_LIMIT, 1, MAX_TRENDING_LIMIT)
|
|
12
|
-
const now = Date.now()
|
|
13
|
-
const { startDay, endDay, items } = await buildTrendingLeaderboard(ctx, { limit, now })
|
|
14
|
-
|
|
15
|
-
await ctx.db.insert('skillLeaderboards', {
|
|
16
|
-
kind: 'trending',
|
|
17
|
-
generatedAt: now,
|
|
18
|
-
rangeStartDay: startDay,
|
|
19
|
-
rangeEndDay: endDay,
|
|
20
|
-
items,
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const recent = await ctx.db
|
|
24
|
-
.query('skillLeaderboards')
|
|
25
|
-
.withIndex('by_kind', (q) => q.eq('kind', 'trending'))
|
|
26
|
-
.order('desc')
|
|
27
|
-
.take(KEEP_LEADERBOARD_ENTRIES + 5)
|
|
28
|
-
|
|
29
|
-
for (const entry of recent.slice(KEEP_LEADERBOARD_ENTRIES)) {
|
|
30
|
-
await ctx.db.delete(entry._id)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return { ok: true as const, count: items.length }
|
|
34
|
-
},
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
function clampInt(value: number, min: number, max: number) {
|
|
38
|
-
return Math.min(Math.max(value, min), max)
|
|
39
|
-
}
|
package/convex/lib/access.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { getAuthUserId } from '@convex-dev/auth/server'
|
|
2
|
-
import { internal } from '../_generated/api'
|
|
3
|
-
import type { Doc } from '../_generated/dataModel'
|
|
4
|
-
import type { ActionCtx, MutationCtx, QueryCtx } from '../_generated/server'
|
|
5
|
-
|
|
6
|
-
export type Role = 'admin' | 'moderator' | 'user'
|
|
7
|
-
|
|
8
|
-
export async function requireUser(ctx: MutationCtx | QueryCtx) {
|
|
9
|
-
const userId = await getAuthUserId(ctx)
|
|
10
|
-
if (!userId) throw new Error('Unauthorized')
|
|
11
|
-
const user = await ctx.db.get(userId)
|
|
12
|
-
if (!user || user.deletedAt) throw new Error('User not found')
|
|
13
|
-
return { userId, user }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function requireUserFromAction(ctx: ActionCtx) {
|
|
17
|
-
const userId = await getAuthUserId(ctx)
|
|
18
|
-
if (!userId) throw new Error('Unauthorized')
|
|
19
|
-
const user = await ctx.runQuery(internal.users.getByIdInternal, { userId })
|
|
20
|
-
if (!user || user.deletedAt) throw new Error('User not found')
|
|
21
|
-
return { userId, user: user as Doc<'users'> }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function assertRole(user: Doc<'users'>, allowed: Role[]) {
|
|
25
|
-
if (!user.role || !allowed.includes(user.role as Role)) {
|
|
26
|
-
throw new Error('Forbidden')
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function assertAdmin(user: Doc<'users'>) {
|
|
31
|
-
assertRole(user, ['admin'])
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function assertModerator(user: Doc<'users'>) {
|
|
35
|
-
assertRole(user, ['admin', 'moderator'])
|
|
36
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { ConvexError } from 'convex/values'
|
|
2
|
-
import { internal } from '../_generated/api'
|
|
3
|
-
import type { Doc } from '../_generated/dataModel'
|
|
4
|
-
import type { ActionCtx } from '../_generated/server'
|
|
5
|
-
import { hashToken } from './tokens'
|
|
6
|
-
|
|
7
|
-
type TokenAuthResult = { user: Doc<'users'>; userId: Doc<'users'>['_id'] }
|
|
8
|
-
|
|
9
|
-
export async function requireApiTokenUser(
|
|
10
|
-
ctx: ActionCtx,
|
|
11
|
-
request: Request,
|
|
12
|
-
): Promise<TokenAuthResult> {
|
|
13
|
-
const header = request.headers.get('authorization') ?? request.headers.get('Authorization')
|
|
14
|
-
const token = parseBearerToken(header)
|
|
15
|
-
if (!token) throw new ConvexError('Unauthorized')
|
|
16
|
-
|
|
17
|
-
const tokenHash = await hashToken(token)
|
|
18
|
-
const apiToken = await ctx.runQuery(internal.tokens.getByHashInternal, { tokenHash })
|
|
19
|
-
if (!apiToken || apiToken.revokedAt) throw new ConvexError('Unauthorized')
|
|
20
|
-
|
|
21
|
-
const user = await ctx.runQuery(internal.tokens.getUserForTokenInternal, {
|
|
22
|
-
tokenId: apiToken._id,
|
|
23
|
-
})
|
|
24
|
-
if (!user || user.deletedAt) throw new ConvexError('Unauthorized')
|
|
25
|
-
|
|
26
|
-
await ctx.runMutation(internal.tokens.touchInternal, { tokenId: apiToken._id })
|
|
27
|
-
return { user, userId: user._id }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function parseBearerToken(header: string | null) {
|
|
31
|
-
if (!header) return null
|
|
32
|
-
const trimmed = header.trim()
|
|
33
|
-
if (!trimmed.toLowerCase().startsWith('bearer ')) return null
|
|
34
|
-
const token = trimmed.slice(7).trim()
|
|
35
|
-
return token || null
|
|
36
|
-
}
|
package/convex/lib/badges.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { Doc, Id } from '../_generated/dataModel'
|
|
2
|
-
import type { QueryCtx } from '../_generated/server'
|
|
3
|
-
|
|
4
|
-
type BadgeKind = Doc<'skillBadges'>['kind']
|
|
5
|
-
|
|
6
|
-
export type SkillBadgeMap = Partial<Record<BadgeKind, { byUserId: Id<'users'>; at: number }>>
|
|
7
|
-
|
|
8
|
-
export type SkillBadgeSource = { badges?: SkillBadgeMap | null }
|
|
9
|
-
|
|
10
|
-
type BadgeCtx = Pick<QueryCtx, 'db'>
|
|
11
|
-
|
|
12
|
-
export function isSkillHighlighted(skill: SkillBadgeSource) {
|
|
13
|
-
return Boolean(skill.badges?.highlighted)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function isSkillOfficial(skill: SkillBadgeSource) {
|
|
17
|
-
return Boolean(skill.badges?.official)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function isSkillDeprecated(skill: SkillBadgeSource) {
|
|
21
|
-
return Boolean(skill.badges?.deprecated)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function buildBadgeMap(records: Doc<'skillBadges'>[]): SkillBadgeMap {
|
|
25
|
-
return records.reduce<SkillBadgeMap>((acc, record) => {
|
|
26
|
-
acc[record.kind] = { byUserId: record.byUserId, at: record.at }
|
|
27
|
-
return acc
|
|
28
|
-
}, {})
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function getSkillBadgeMap(
|
|
32
|
-
ctx: BadgeCtx,
|
|
33
|
-
skillId: Id<'skills'>,
|
|
34
|
-
): Promise<SkillBadgeMap> {
|
|
35
|
-
const records = await ctx.db
|
|
36
|
-
.query('skillBadges')
|
|
37
|
-
.withIndex('by_skill', (q) => q.eq('skillId', skillId))
|
|
38
|
-
.collect()
|
|
39
|
-
return buildBadgeMap(records)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export async function getSkillBadgeMaps(
|
|
43
|
-
ctx: BadgeCtx,
|
|
44
|
-
skillIds: Array<Id<'skills'>>,
|
|
45
|
-
): Promise<Map<Id<'skills'>, SkillBadgeMap>> {
|
|
46
|
-
const entries = await Promise.all(
|
|
47
|
-
skillIds.map(async (skillId) => [skillId, await getSkillBadgeMap(ctx, skillId)] as const),
|
|
48
|
-
)
|
|
49
|
-
return new Map(entries)
|
|
50
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { __test } from './changelog'
|
|
3
|
-
|
|
4
|
-
describe('changelog utils', () => {
|
|
5
|
-
it('summarizes file diffs', () => {
|
|
6
|
-
const diff = __test.summarizeFileDiff(
|
|
7
|
-
[
|
|
8
|
-
{ path: 'a.txt', sha256: 'aaa' },
|
|
9
|
-
{ path: 'b.txt', sha256: 'bbb' },
|
|
10
|
-
],
|
|
11
|
-
[
|
|
12
|
-
{ path: 'a.txt', sha256: 'aaa' },
|
|
13
|
-
{ path: 'b.txt', sha256: 'ccc' },
|
|
14
|
-
{ path: 'c.txt', sha256: 'ddd' },
|
|
15
|
-
],
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
expect(diff.added).toEqual(['c.txt'])
|
|
19
|
-
expect(diff.removed).toEqual([])
|
|
20
|
-
expect(diff.changed).toEqual(['b.txt'])
|
|
21
|
-
expect(__test.formatDiffSummary(diff)).toBe('1 added, 1 changed')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('generates a fallback initial release note', () => {
|
|
25
|
-
const text = __test.generateFallback({
|
|
26
|
-
slug: 'demo',
|
|
27
|
-
version: '1.0.0',
|
|
28
|
-
oldReadme: null,
|
|
29
|
-
nextReadme: 'hi',
|
|
30
|
-
fileDiff: null,
|
|
31
|
-
})
|
|
32
|
-
expect(text).toMatch(/Initial release/i)
|
|
33
|
-
})
|
|
34
|
-
})
|
package/convex/lib/changelog.ts
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import { internal } from '../_generated/api'
|
|
2
|
-
import type { Doc, Id } from '../_generated/dataModel'
|
|
3
|
-
import type { ActionCtx } from '../_generated/server'
|
|
4
|
-
|
|
5
|
-
const CHANGELOG_MODEL = process.env.OPENAI_CHANGELOG_MODEL ?? 'gpt-4.1'
|
|
6
|
-
const MAX_README_CHARS = 8_000
|
|
7
|
-
const MAX_PATHS_IN_PROMPT = 30
|
|
8
|
-
|
|
9
|
-
type FileMeta = { path: string; sha256?: string }
|
|
10
|
-
|
|
11
|
-
type FileDiffSummary = {
|
|
12
|
-
added: string[]
|
|
13
|
-
removed: string[]
|
|
14
|
-
changed: string[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function clampText(value: string, maxChars: number) {
|
|
18
|
-
const trimmed = value.trim()
|
|
19
|
-
if (trimmed.length <= maxChars) return trimmed
|
|
20
|
-
return `${trimmed.slice(0, maxChars).trimEnd()}\n…`
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function summarizeFileDiff(oldFiles: FileMeta[], nextFiles: FileMeta[]): FileDiffSummary {
|
|
24
|
-
const oldByPath = new Map(oldFiles.map((f) => [f.path, f] as const))
|
|
25
|
-
const nextByPath = new Map(nextFiles.map((f) => [f.path, f] as const))
|
|
26
|
-
|
|
27
|
-
const added: string[] = []
|
|
28
|
-
const removed: string[] = []
|
|
29
|
-
const changed: string[] = []
|
|
30
|
-
|
|
31
|
-
for (const [path, file] of nextByPath.entries()) {
|
|
32
|
-
const prev = oldByPath.get(path)
|
|
33
|
-
if (!prev) {
|
|
34
|
-
added.push(path)
|
|
35
|
-
continue
|
|
36
|
-
}
|
|
37
|
-
if (file.sha256 && prev.sha256 && file.sha256 !== prev.sha256) changed.push(path)
|
|
38
|
-
}
|
|
39
|
-
for (const path of oldByPath.keys()) {
|
|
40
|
-
if (!nextByPath.has(path)) removed.push(path)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
added.sort()
|
|
44
|
-
removed.sort()
|
|
45
|
-
changed.sort()
|
|
46
|
-
return { added, removed, changed }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function formatDiffSummary(diff: FileDiffSummary) {
|
|
50
|
-
const parts: string[] = []
|
|
51
|
-
if (diff.added.length) parts.push(`${diff.added.length} added`)
|
|
52
|
-
if (diff.changed.length) parts.push(`${diff.changed.length} changed`)
|
|
53
|
-
if (diff.removed.length) parts.push(`${diff.removed.length} removed`)
|
|
54
|
-
return parts.join(', ') || 'no file changes detected'
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function pickPaths(values: string[]) {
|
|
58
|
-
if (values.length <= MAX_PATHS_IN_PROMPT) return values
|
|
59
|
-
return values.slice(0, MAX_PATHS_IN_PROMPT)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function extractResponseText(payload: unknown) {
|
|
63
|
-
if (!payload || typeof payload !== 'object') return null
|
|
64
|
-
const output = (payload as { output?: unknown }).output
|
|
65
|
-
if (!Array.isArray(output)) return null
|
|
66
|
-
const chunks: string[] = []
|
|
67
|
-
for (const item of output) {
|
|
68
|
-
if (!item || typeof item !== 'object') continue
|
|
69
|
-
if ((item as { type?: unknown }).type !== 'message') continue
|
|
70
|
-
const content = (item as { content?: unknown }).content
|
|
71
|
-
if (!Array.isArray(content)) continue
|
|
72
|
-
for (const part of content) {
|
|
73
|
-
if (!part || typeof part !== 'object') continue
|
|
74
|
-
if ((part as { type?: unknown }).type !== 'output_text') continue
|
|
75
|
-
const text = (part as { text?: unknown }).text
|
|
76
|
-
if (typeof text === 'string' && text.trim()) chunks.push(text)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
const joined = chunks.join('\n').trim()
|
|
80
|
-
return joined || null
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function generateWithOpenAI(args: {
|
|
84
|
-
slug: string
|
|
85
|
-
version: string
|
|
86
|
-
oldReadme: string | null
|
|
87
|
-
nextReadme: string
|
|
88
|
-
fileDiff: FileDiffSummary | null
|
|
89
|
-
}) {
|
|
90
|
-
const apiKey = process.env.OPENAI_API_KEY
|
|
91
|
-
if (!apiKey) return null
|
|
92
|
-
|
|
93
|
-
const oldReadme = args.oldReadme ? clampText(args.oldReadme, MAX_README_CHARS) : ''
|
|
94
|
-
const nextReadme = clampText(args.nextReadme, MAX_README_CHARS)
|
|
95
|
-
|
|
96
|
-
const fileDiff = args.fileDiff
|
|
97
|
-
const diffSummary = fileDiff ? formatDiffSummary(fileDiff) : 'unknown'
|
|
98
|
-
const changedPaths = fileDiff ? pickPaths(fileDiff.changed) : []
|
|
99
|
-
const addedPaths = fileDiff ? pickPaths(fileDiff.added) : []
|
|
100
|
-
const removedPaths = fileDiff ? pickPaths(fileDiff.removed) : []
|
|
101
|
-
|
|
102
|
-
const input = [
|
|
103
|
-
`Skill: ${args.slug}`,
|
|
104
|
-
`Version: ${args.version}`,
|
|
105
|
-
`File changes: ${diffSummary}`,
|
|
106
|
-
changedPaths.length ? `Changed files (sample): ${changedPaths.join(', ')}` : null,
|
|
107
|
-
addedPaths.length ? `Added files (sample): ${addedPaths.join(', ')}` : null,
|
|
108
|
-
removedPaths.length ? `Removed files (sample): ${removedPaths.join(', ')}` : null,
|
|
109
|
-
oldReadme ? `Previous SKILL.md:\n${oldReadme}` : null,
|
|
110
|
-
`New SKILL.md:\n${nextReadme}`,
|
|
111
|
-
]
|
|
112
|
-
.filter(Boolean)
|
|
113
|
-
.join('\n\n')
|
|
114
|
-
|
|
115
|
-
const response = await fetch('https://api.openai.com/v1/responses', {
|
|
116
|
-
method: 'POST',
|
|
117
|
-
headers: {
|
|
118
|
-
'Content-Type': 'application/json',
|
|
119
|
-
Authorization: `Bearer ${apiKey}`,
|
|
120
|
-
},
|
|
121
|
-
body: JSON.stringify({
|
|
122
|
-
model: CHANGELOG_MODEL,
|
|
123
|
-
instructions:
|
|
124
|
-
'Write a concise changelog for this skill version. Audience: everyone. Output plain text. Prefer 2–6 bullet points. If it is a big change, include a short 1-line summary first, then bullets. Don’t mention that you are AI. Don’t invent details; only use the inputs.',
|
|
125
|
-
input,
|
|
126
|
-
max_output_tokens: 220,
|
|
127
|
-
}),
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
if (!response.ok) return null
|
|
131
|
-
const payload = (await response.json()) as unknown
|
|
132
|
-
return extractResponseText(payload)
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function generateFallback(args: {
|
|
136
|
-
slug: string
|
|
137
|
-
version: string
|
|
138
|
-
oldReadme: string | null
|
|
139
|
-
nextReadme: string
|
|
140
|
-
fileDiff: FileDiffSummary | null
|
|
141
|
-
}) {
|
|
142
|
-
const lines: string[] = []
|
|
143
|
-
if (!args.oldReadme) {
|
|
144
|
-
lines.push(`- Initial release.`)
|
|
145
|
-
return lines.join('\n')
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const diff = args.fileDiff
|
|
149
|
-
if (diff) {
|
|
150
|
-
const parts: string[] = []
|
|
151
|
-
if (diff.added.length) parts.push(`added ${diff.added.length}`)
|
|
152
|
-
if (diff.changed.length) parts.push(`updated ${diff.changed.length}`)
|
|
153
|
-
if (diff.removed.length) parts.push(`removed ${diff.removed.length}`)
|
|
154
|
-
if (parts.length) lines.push(`- ${parts.join(', ')} file(s).`)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
lines.push(`- Updated SKILL.md and bundle contents.`)
|
|
158
|
-
return lines.join('\n')
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export async function generateChangelogForPublish(
|
|
162
|
-
ctx: ActionCtx,
|
|
163
|
-
args: { slug: string; version: string; readmeText: string; files: FileMeta[] },
|
|
164
|
-
): Promise<string> {
|
|
165
|
-
try {
|
|
166
|
-
const skill = (await ctx.runQuery(internal.skills.getSkillBySlugInternal, {
|
|
167
|
-
slug: args.slug,
|
|
168
|
-
})) as Doc<'skills'> | null
|
|
169
|
-
const previous: Doc<'skillVersions'> | null =
|
|
170
|
-
skill?.latestVersionId && !skill.softDeletedAt
|
|
171
|
-
? ((await ctx.runQuery(internal.skills.getVersionByIdInternal, {
|
|
172
|
-
versionId: skill.latestVersionId,
|
|
173
|
-
})) as Doc<'skillVersions'> | null)
|
|
174
|
-
: null
|
|
175
|
-
|
|
176
|
-
const oldReadmeText: string | null = previous
|
|
177
|
-
? await readReadmeFromVersion(ctx, previous)
|
|
178
|
-
: null
|
|
179
|
-
const oldFiles = previous
|
|
180
|
-
? previous.files.map((file) => ({ path: file.path, sha256: file.sha256 }))
|
|
181
|
-
: []
|
|
182
|
-
const fileDiff = previous ? summarizeFileDiff(oldFiles, args.files) : null
|
|
183
|
-
|
|
184
|
-
const ai = await generateWithOpenAI({
|
|
185
|
-
slug: args.slug,
|
|
186
|
-
version: args.version,
|
|
187
|
-
oldReadme: oldReadmeText,
|
|
188
|
-
nextReadme: args.readmeText,
|
|
189
|
-
fileDiff,
|
|
190
|
-
}).catch(() => null)
|
|
191
|
-
|
|
192
|
-
return (
|
|
193
|
-
ai ??
|
|
194
|
-
generateFallback({
|
|
195
|
-
slug: args.slug,
|
|
196
|
-
version: args.version,
|
|
197
|
-
oldReadme: oldReadmeText,
|
|
198
|
-
nextReadme: args.readmeText,
|
|
199
|
-
fileDiff,
|
|
200
|
-
})
|
|
201
|
-
)
|
|
202
|
-
} catch {
|
|
203
|
-
return '- Updated skill.'
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export async function generateChangelogPreview(
|
|
208
|
-
ctx: ActionCtx,
|
|
209
|
-
args: {
|
|
210
|
-
slug: string
|
|
211
|
-
version: string
|
|
212
|
-
readmeText: string
|
|
213
|
-
filePaths?: string[]
|
|
214
|
-
},
|
|
215
|
-
): Promise<string> {
|
|
216
|
-
try {
|
|
217
|
-
const skill = (await ctx.runQuery(internal.skills.getSkillBySlugInternal, {
|
|
218
|
-
slug: args.slug,
|
|
219
|
-
})) as Doc<'skills'> | null
|
|
220
|
-
const previous: Doc<'skillVersions'> | null =
|
|
221
|
-
skill?.latestVersionId && !skill.softDeletedAt
|
|
222
|
-
? ((await ctx.runQuery(internal.skills.getVersionByIdInternal, {
|
|
223
|
-
versionId: skill.latestVersionId,
|
|
224
|
-
})) as Doc<'skillVersions'> | null)
|
|
225
|
-
: null
|
|
226
|
-
|
|
227
|
-
const oldReadmeText: string | null = previous
|
|
228
|
-
? await readReadmeFromVersion(ctx, previous)
|
|
229
|
-
: null
|
|
230
|
-
const fileDiff =
|
|
231
|
-
previous && args.filePaths
|
|
232
|
-
? summarizeFileDiff(
|
|
233
|
-
previous.files.map((file) => ({ path: file.path, sha256: file.sha256 })),
|
|
234
|
-
args.filePaths.map((path) => ({ path })),
|
|
235
|
-
)
|
|
236
|
-
: null
|
|
237
|
-
|
|
238
|
-
const ai = await generateWithOpenAI({
|
|
239
|
-
slug: args.slug,
|
|
240
|
-
version: args.version,
|
|
241
|
-
oldReadme: oldReadmeText,
|
|
242
|
-
nextReadme: args.readmeText,
|
|
243
|
-
fileDiff,
|
|
244
|
-
}).catch(() => null)
|
|
245
|
-
|
|
246
|
-
return (
|
|
247
|
-
ai ??
|
|
248
|
-
generateFallback({
|
|
249
|
-
slug: args.slug,
|
|
250
|
-
version: args.version,
|
|
251
|
-
oldReadme: oldReadmeText,
|
|
252
|
-
nextReadme: args.readmeText,
|
|
253
|
-
fileDiff,
|
|
254
|
-
})
|
|
255
|
-
)
|
|
256
|
-
} catch {
|
|
257
|
-
return '- Updated skill.'
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
async function readReadmeFromVersion(ctx: ActionCtx, version: Doc<'skillVersions'>) {
|
|
262
|
-
const readmeFile = version.files.find((file) => {
|
|
263
|
-
const lower = file.path.toLowerCase()
|
|
264
|
-
return lower === 'skill.md' || lower === 'skills.md'
|
|
265
|
-
})
|
|
266
|
-
if (!readmeFile) return null
|
|
267
|
-
const blob = await ctx.storage.get(readmeFile.storageId as Id<'_storage'>)
|
|
268
|
-
if (!blob) return null
|
|
269
|
-
return blob.text()
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export const __test = {
|
|
273
|
-
clampText,
|
|
274
|
-
extractResponseText,
|
|
275
|
-
formatDiffSummary,
|
|
276
|
-
summarizeFileDiff,
|
|
277
|
-
generateFallback,
|
|
278
|
-
}
|
package/convex/lib/embeddings.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export const EMBEDDING_MODEL = 'text-embedding-3-small'
|
|
2
|
-
export const EMBEDDING_DIMENSIONS = 1536
|
|
3
|
-
|
|
4
|
-
function emptyEmbedding() {
|
|
5
|
-
return Array.from({ length: EMBEDDING_DIMENSIONS }, () => 0)
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export async function generateEmbedding(text: string) {
|
|
9
|
-
const apiKey = process.env.OPENAI_API_KEY
|
|
10
|
-
if (!apiKey) {
|
|
11
|
-
console.warn('OPENAI_API_KEY is not configured; using zero embeddings')
|
|
12
|
-
return emptyEmbedding()
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const response = await fetch('https://api.openai.com/v1/embeddings', {
|
|
16
|
-
method: 'POST',
|
|
17
|
-
headers: {
|
|
18
|
-
'Content-Type': 'application/json',
|
|
19
|
-
Authorization: `Bearer ${apiKey}`,
|
|
20
|
-
},
|
|
21
|
-
body: JSON.stringify({
|
|
22
|
-
model: EMBEDDING_MODEL,
|
|
23
|
-
input: text,
|
|
24
|
-
}),
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
if (!response.ok) {
|
|
28
|
-
const message = await response.text()
|
|
29
|
-
throw new Error(`Embedding failed: ${message}`)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const payload = (await response.json()) as {
|
|
33
|
-
data?: Array<{ embedding: number[] }>
|
|
34
|
-
}
|
|
35
|
-
const embedding = payload.data?.[0]?.embedding
|
|
36
|
-
if (!embedding) throw new Error('Embedding missing from response')
|
|
37
|
-
return embedding
|
|
38
|
-
}
|