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/src/lib/gravatar.test.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { gravatarUrl } from './gravatar'
|
|
3
|
-
|
|
4
|
-
describe('gravatarUrl', () => {
|
|
5
|
-
it('generates a stable hash', () => {
|
|
6
|
-
const url = gravatarUrl('MyEmailAddress@example.com ')
|
|
7
|
-
expect(url).toContain('0bc83cb571cd1c50ba6f3e8a78ef1346')
|
|
8
|
-
})
|
|
9
|
-
})
|
package/src/lib/gravatar.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
function md5cycle(x: number[], k: number[]) {
|
|
2
|
-
let [a, b, c, d] = x
|
|
3
|
-
|
|
4
|
-
a = ff(a, b, c, d, k[0], 7, -680876936)
|
|
5
|
-
d = ff(d, a, b, c, k[1], 12, -389564586)
|
|
6
|
-
c = ff(c, d, a, b, k[2], 17, 606105819)
|
|
7
|
-
b = ff(b, c, d, a, k[3], 22, -1044525330)
|
|
8
|
-
a = ff(a, b, c, d, k[4], 7, -176418897)
|
|
9
|
-
d = ff(d, a, b, c, k[5], 12, 1200080426)
|
|
10
|
-
c = ff(c, d, a, b, k[6], 17, -1473231341)
|
|
11
|
-
b = ff(b, c, d, a, k[7], 22, -45705983)
|
|
12
|
-
a = ff(a, b, c, d, k[8], 7, 1770035416)
|
|
13
|
-
d = ff(d, a, b, c, k[9], 12, -1958414417)
|
|
14
|
-
c = ff(c, d, a, b, k[10], 17, -42063)
|
|
15
|
-
b = ff(b, c, d, a, k[11], 22, -1990404162)
|
|
16
|
-
a = ff(a, b, c, d, k[12], 7, 1804603682)
|
|
17
|
-
d = ff(d, a, b, c, k[13], 12, -40341101)
|
|
18
|
-
c = ff(c, d, a, b, k[14], 17, -1502002290)
|
|
19
|
-
b = ff(b, c, d, a, k[15], 22, 1236535329)
|
|
20
|
-
|
|
21
|
-
a = gg(a, b, c, d, k[1], 5, -165796510)
|
|
22
|
-
d = gg(d, a, b, c, k[6], 9, -1069501632)
|
|
23
|
-
c = gg(c, d, a, b, k[11], 14, 643717713)
|
|
24
|
-
b = gg(b, c, d, a, k[0], 20, -373897302)
|
|
25
|
-
a = gg(a, b, c, d, k[5], 5, -701558691)
|
|
26
|
-
d = gg(d, a, b, c, k[10], 9, 38016083)
|
|
27
|
-
c = gg(c, d, a, b, k[15], 14, -660478335)
|
|
28
|
-
b = gg(b, c, d, a, k[4], 20, -405537848)
|
|
29
|
-
a = gg(a, b, c, d, k[9], 5, 568446438)
|
|
30
|
-
d = gg(d, a, b, c, k[14], 9, -1019803690)
|
|
31
|
-
c = gg(c, d, a, b, k[3], 14, -187363961)
|
|
32
|
-
b = gg(b, c, d, a, k[8], 20, 1163531501)
|
|
33
|
-
a = gg(a, b, c, d, k[13], 5, -1444681467)
|
|
34
|
-
d = gg(d, a, b, c, k[2], 9, -51403784)
|
|
35
|
-
c = gg(c, d, a, b, k[7], 14, 1735328473)
|
|
36
|
-
b = gg(b, c, d, a, k[12], 20, -1926607734)
|
|
37
|
-
|
|
38
|
-
a = hh(a, b, c, d, k[5], 4, -378558)
|
|
39
|
-
d = hh(d, a, b, c, k[8], 11, -2022574463)
|
|
40
|
-
c = hh(c, d, a, b, k[11], 16, 1839030562)
|
|
41
|
-
b = hh(b, c, d, a, k[14], 23, -35309556)
|
|
42
|
-
a = hh(a, b, c, d, k[1], 4, -1530992060)
|
|
43
|
-
d = hh(d, a, b, c, k[4], 11, 1272893353)
|
|
44
|
-
c = hh(c, d, a, b, k[7], 16, -155497632)
|
|
45
|
-
b = hh(b, c, d, a, k[10], 23, -1094730640)
|
|
46
|
-
a = hh(a, b, c, d, k[13], 4, 681279174)
|
|
47
|
-
d = hh(d, a, b, c, k[0], 11, -358537222)
|
|
48
|
-
c = hh(c, d, a, b, k[3], 16, -722521979)
|
|
49
|
-
b = hh(b, c, d, a, k[6], 23, 76029189)
|
|
50
|
-
a = hh(a, b, c, d, k[9], 4, -640364487)
|
|
51
|
-
d = hh(d, a, b, c, k[12], 11, -421815835)
|
|
52
|
-
c = hh(c, d, a, b, k[15], 16, 530742520)
|
|
53
|
-
b = hh(b, c, d, a, k[2], 23, -995338651)
|
|
54
|
-
|
|
55
|
-
a = ii(a, b, c, d, k[0], 6, -198630844)
|
|
56
|
-
d = ii(d, a, b, c, k[7], 10, 1126891415)
|
|
57
|
-
c = ii(c, d, a, b, k[14], 15, -1416354905)
|
|
58
|
-
b = ii(b, c, d, a, k[5], 21, -57434055)
|
|
59
|
-
a = ii(a, b, c, d, k[12], 6, 1700485571)
|
|
60
|
-
d = ii(d, a, b, c, k[3], 10, -1894986606)
|
|
61
|
-
c = ii(c, d, a, b, k[10], 15, -1051523)
|
|
62
|
-
b = ii(b, c, d, a, k[1], 21, -2054922799)
|
|
63
|
-
a = ii(a, b, c, d, k[8], 6, 1873313359)
|
|
64
|
-
d = ii(d, a, b, c, k[15], 10, -30611744)
|
|
65
|
-
c = ii(c, d, a, b, k[6], 15, -1560198380)
|
|
66
|
-
b = ii(b, c, d, a, k[13], 21, 1309151649)
|
|
67
|
-
a = ii(a, b, c, d, k[4], 6, -145523070)
|
|
68
|
-
d = ii(d, a, b, c, k[11], 10, -1120210379)
|
|
69
|
-
c = ii(c, d, a, b, k[2], 15, 718787259)
|
|
70
|
-
b = ii(b, c, d, a, k[9], 21, -343485551)
|
|
71
|
-
|
|
72
|
-
x[0] = add32(a, x[0])
|
|
73
|
-
x[1] = add32(b, x[1])
|
|
74
|
-
x[2] = add32(c, x[2])
|
|
75
|
-
x[3] = add32(d, x[3])
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function cmn(q: number, a: number, b: number, x: number, s: number, t: number) {
|
|
79
|
-
a = add32(add32(a, q), add32(x, t))
|
|
80
|
-
return add32((a << s) | (a >>> (32 - s)), b)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function ff(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
|
|
84
|
-
return cmn((b & c) | (~b & d), a, b, x, s, t)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function gg(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
|
|
88
|
-
return cmn((b & d) | (c & ~d), a, b, x, s, t)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function hh(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
|
|
92
|
-
return cmn(b ^ c ^ d, a, b, x, s, t)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function ii(a: number, b: number, c: number, d: number, x: number, s: number, t: number) {
|
|
96
|
-
return cmn(c ^ (b | ~d), a, b, x, s, t)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function md51(s: string) {
|
|
100
|
-
const n = s.length
|
|
101
|
-
const state = [1732584193, -271733879, -1732584194, 271733878]
|
|
102
|
-
let i = 0
|
|
103
|
-
for (i = 64; i <= n; i += 64) {
|
|
104
|
-
md5cycle(state, md5blk(s.substring(i - 64, i)))
|
|
105
|
-
}
|
|
106
|
-
s = s.substring(i - 64)
|
|
107
|
-
const tail = Array(16).fill(0) as number[]
|
|
108
|
-
for (i = 0; i < s.length; i += 1) {
|
|
109
|
-
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3)
|
|
110
|
-
}
|
|
111
|
-
tail[i >> 2] |= 0x80 << ((i % 4) << 3)
|
|
112
|
-
if (i > 55) {
|
|
113
|
-
md5cycle(state, tail)
|
|
114
|
-
for (let j = 0; j < 16; j += 1) tail[j] = 0
|
|
115
|
-
}
|
|
116
|
-
tail[14] = n * 8
|
|
117
|
-
md5cycle(state, tail)
|
|
118
|
-
return state
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function md5blk(s: string) {
|
|
122
|
-
const md5blks: number[] = []
|
|
123
|
-
for (let i = 0; i < 64; i += 4) {
|
|
124
|
-
md5blks[i >> 2] =
|
|
125
|
-
s.charCodeAt(i) +
|
|
126
|
-
(s.charCodeAt(i + 1) << 8) +
|
|
127
|
-
(s.charCodeAt(i + 2) << 16) +
|
|
128
|
-
(s.charCodeAt(i + 3) << 24)
|
|
129
|
-
}
|
|
130
|
-
return md5blks
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function rhex(n: number) {
|
|
134
|
-
const s = '0123456789abcdef'
|
|
135
|
-
let j = 0
|
|
136
|
-
let out = ''
|
|
137
|
-
for (; j < 4; j += 1) {
|
|
138
|
-
out += s.charAt((n >> (j * 8 + 4)) & 0x0f) + s.charAt((n >> (j * 8)) & 0x0f)
|
|
139
|
-
}
|
|
140
|
-
return out
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function hex(x: number[]) {
|
|
144
|
-
for (let i = 0; i < x.length; i += 1) {
|
|
145
|
-
x[i] = Number(x[i])
|
|
146
|
-
}
|
|
147
|
-
return x.map(rhex).join('')
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function add32(a: number, b: number) {
|
|
151
|
-
return (a + b) & 0xffffffff
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function gravatarUrl(email: string, size = 160) {
|
|
155
|
-
const normalized = email.trim().toLowerCase()
|
|
156
|
-
const hash = hex(md51(normalized))
|
|
157
|
-
return `https://www.gravatar.com/avatar/${hash}?d=identicon&s=${size}`
|
|
158
|
-
}
|
package/src/lib/og.test.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
-
import { buildSkillMeta, buildSoulMeta, fetchSkillMeta, fetchSoulMeta } from './og'
|
|
3
|
-
|
|
4
|
-
describe('og helpers', () => {
|
|
5
|
-
afterEach(() => {
|
|
6
|
-
vi.restoreAllMocks()
|
|
7
|
-
})
|
|
8
|
-
|
|
9
|
-
it('builds metadata with owner and summary', () => {
|
|
10
|
-
const meta = buildSkillMeta({
|
|
11
|
-
slug: 'weather',
|
|
12
|
-
owner: 'steipete',
|
|
13
|
-
displayName: 'Weather',
|
|
14
|
-
summary: 'Forecasts for your area.',
|
|
15
|
-
version: '1.2.3',
|
|
16
|
-
})
|
|
17
|
-
expect(meta.title).toBe('Weather — PilotHub')
|
|
18
|
-
expect(meta.description).toBe('Forecasts for your area.')
|
|
19
|
-
expect(meta.url).toContain('/steipete/weather')
|
|
20
|
-
expect(meta.owner).toBe('steipete')
|
|
21
|
-
expect(meta.image).toContain('/og/skill.png?')
|
|
22
|
-
expect(meta.image).toContain('v=5')
|
|
23
|
-
expect(meta.image).toContain('slug=weather')
|
|
24
|
-
expect(meta.image).toContain('owner=steipete')
|
|
25
|
-
expect(meta.image).toContain('version=1.2.3')
|
|
26
|
-
expect(meta.image).not.toContain('title=')
|
|
27
|
-
expect(meta.image).not.toContain('description=')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('builds soul metadata with summary', () => {
|
|
31
|
-
const meta = buildSoulMeta({
|
|
32
|
-
slug: 'north-star',
|
|
33
|
-
owner: 'someone',
|
|
34
|
-
displayName: 'North Star',
|
|
35
|
-
summary: 'Personal north star notes.',
|
|
36
|
-
version: '0.1.0',
|
|
37
|
-
})
|
|
38
|
-
expect(meta.title).toBe('North Star — SoulHub')
|
|
39
|
-
expect(meta.description).toBe('Personal north star notes.')
|
|
40
|
-
expect(meta.url).toContain('/souls/north-star')
|
|
41
|
-
expect(meta.owner).toBe('someone')
|
|
42
|
-
expect(meta.image).toContain('/og/soul.png?')
|
|
43
|
-
expect(meta.image).toContain('v=1')
|
|
44
|
-
expect(meta.image).toContain('slug=north-star')
|
|
45
|
-
expect(meta.image).toContain('owner=someone')
|
|
46
|
-
expect(meta.image).toContain('version=0.1.0')
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('uses defaults when owner and summary are missing', () => {
|
|
50
|
-
const meta = buildSkillMeta({ slug: 'parser' })
|
|
51
|
-
expect(meta.title).toBe('parser — PilotHub')
|
|
52
|
-
expect(meta.description).toMatch(/PilotHub — a fast skill registry/i)
|
|
53
|
-
expect(meta.url).toContain('/unknown/parser')
|
|
54
|
-
expect(meta.owner).toBeNull()
|
|
55
|
-
expect(meta.image).toContain('slug=parser')
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('uses soul defaults when owner and summary are missing', () => {
|
|
59
|
-
const meta = buildSoulMeta({ slug: 'signal' })
|
|
60
|
-
expect(meta.title).toBe('signal — SoulHub')
|
|
61
|
-
expect(meta.description).toMatch(/SoulHub — the home for SOUL.md/i)
|
|
62
|
-
expect(meta.url).toContain('/souls/signal')
|
|
63
|
-
expect(meta.owner).toBeNull()
|
|
64
|
-
expect(meta.image).toContain('slug=signal')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('truncates long descriptions', () => {
|
|
68
|
-
const longSummary = 'a'.repeat(240)
|
|
69
|
-
const meta = buildSkillMeta({ slug: 'long', summary: longSummary })
|
|
70
|
-
expect(meta.description.length).toBe(200)
|
|
71
|
-
expect(meta.description.endsWith('…')).toBe(true)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
it('fetches skill metadata when response is ok', async () => {
|
|
75
|
-
const fetchMock = vi.fn(async () => ({
|
|
76
|
-
ok: true,
|
|
77
|
-
json: async () => ({
|
|
78
|
-
skill: { displayName: 'Weather', summary: 'Forecasts' },
|
|
79
|
-
owner: { handle: 'steipete', userId: 'users:1' },
|
|
80
|
-
latestVersion: { version: '1.2.3' },
|
|
81
|
-
}),
|
|
82
|
-
}))
|
|
83
|
-
vi.stubGlobal('fetch', fetchMock)
|
|
84
|
-
|
|
85
|
-
const meta = await fetchSkillMeta('weather')
|
|
86
|
-
expect(meta).toEqual({
|
|
87
|
-
displayName: 'Weather',
|
|
88
|
-
summary: 'Forecasts',
|
|
89
|
-
owner: 'steipete',
|
|
90
|
-
ownerId: 'users:1',
|
|
91
|
-
version: '1.2.3',
|
|
92
|
-
})
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('fetches soul metadata when response is ok', async () => {
|
|
96
|
-
const fetchMock = vi.fn(async () => ({
|
|
97
|
-
ok: true,
|
|
98
|
-
json: async () => ({
|
|
99
|
-
soul: { displayName: 'North Star', summary: 'Signal' },
|
|
100
|
-
owner: { handle: 'steipete' },
|
|
101
|
-
latestVersion: { version: '0.1.0' },
|
|
102
|
-
}),
|
|
103
|
-
}))
|
|
104
|
-
vi.stubGlobal('fetch', fetchMock)
|
|
105
|
-
|
|
106
|
-
const meta = await fetchSoulMeta('north-star')
|
|
107
|
-
expect(meta).toEqual({
|
|
108
|
-
displayName: 'North Star',
|
|
109
|
-
summary: 'Signal',
|
|
110
|
-
owner: 'steipete',
|
|
111
|
-
version: '0.1.0',
|
|
112
|
-
})
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('returns null when response is not ok', async () => {
|
|
116
|
-
const fetchMock = vi.fn(async () => ({ ok: false }))
|
|
117
|
-
vi.stubGlobal('fetch', fetchMock)
|
|
118
|
-
|
|
119
|
-
const meta = await fetchSkillMeta('weather')
|
|
120
|
-
expect(meta).toBeNull()
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('returns null when fetch throws', async () => {
|
|
124
|
-
const fetchMock = vi.fn(async () => {
|
|
125
|
-
throw new Error('network')
|
|
126
|
-
})
|
|
127
|
-
vi.stubGlobal('fetch', fetchMock)
|
|
128
|
-
|
|
129
|
-
const meta = await fetchSkillMeta('weather')
|
|
130
|
-
expect(meta).toBeNull()
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('returns null when soul fetch throws', async () => {
|
|
134
|
-
const fetchMock = vi.fn(async () => {
|
|
135
|
-
throw new Error('network')
|
|
136
|
-
})
|
|
137
|
-
vi.stubGlobal('fetch', fetchMock)
|
|
138
|
-
|
|
139
|
-
const meta = await fetchSoulMeta('north-star')
|
|
140
|
-
expect(meta).toBeNull()
|
|
141
|
-
})
|
|
142
|
-
})
|
package/src/lib/og.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import { getPilotHubSiteUrl, getOnlyCrabsSiteUrl } from './site'
|
|
2
|
-
|
|
3
|
-
type SkillMetaSource = {
|
|
4
|
-
slug: string
|
|
5
|
-
owner?: string | null
|
|
6
|
-
ownerId?: string | null
|
|
7
|
-
displayName?: string | null
|
|
8
|
-
summary?: string | null
|
|
9
|
-
version?: string | null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
type SkillMeta = {
|
|
13
|
-
title: string
|
|
14
|
-
description: string
|
|
15
|
-
image: string
|
|
16
|
-
url: string
|
|
17
|
-
owner: string | null
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type SoulMetaSource = {
|
|
21
|
-
slug: string
|
|
22
|
-
owner?: string | null
|
|
23
|
-
displayName?: string | null
|
|
24
|
-
summary?: string | null
|
|
25
|
-
version?: string | null
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type SoulMeta = {
|
|
29
|
-
title: string
|
|
30
|
-
description: string
|
|
31
|
-
image: string
|
|
32
|
-
url: string
|
|
33
|
-
owner: string | null
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const DEFAULT_DESCRIPTION = 'PilotHub — a fast skill registry for agents, with vector search.'
|
|
37
|
-
const DEFAULT_SOUL_DESCRIPTION = 'SoulHub — the home for SOUL.md bundles and personal system lore.'
|
|
38
|
-
const OG_SKILL_IMAGE_LAYOUT_VERSION = '5'
|
|
39
|
-
const OG_SOUL_IMAGE_LAYOUT_VERSION = '1'
|
|
40
|
-
|
|
41
|
-
export function getSiteUrl() {
|
|
42
|
-
return getPilotHubSiteUrl()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function getSoulSiteUrl() {
|
|
46
|
-
return getOnlyCrabsSiteUrl()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function getApiBase() {
|
|
50
|
-
const explicit = import.meta.env.VITE_CONVEX_SITE_URL?.trim()
|
|
51
|
-
return explicit || getSiteUrl()
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export async function fetchSkillMeta(slug: string) {
|
|
55
|
-
try {
|
|
56
|
-
const apiBase = getApiBase()
|
|
57
|
-
const url = new URL(`/api/v1/skills/${encodeURIComponent(slug)}`, apiBase)
|
|
58
|
-
const response = await fetch(url.toString(), { headers: { Accept: 'application/json' } })
|
|
59
|
-
if (!response.ok) return null
|
|
60
|
-
const payload = (await response.json()) as {
|
|
61
|
-
skill?: { displayName?: string; summary?: string | null } | null
|
|
62
|
-
owner?: { handle?: string | null; userId?: string | null } | null
|
|
63
|
-
latestVersion?: { version?: string | null } | null
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
displayName: payload.skill?.displayName ?? null,
|
|
67
|
-
summary: payload.skill?.summary ?? null,
|
|
68
|
-
owner: payload.owner?.handle ?? null,
|
|
69
|
-
ownerId: payload.owner?.userId ?? null,
|
|
70
|
-
version: payload.latestVersion?.version ?? null,
|
|
71
|
-
}
|
|
72
|
-
} catch {
|
|
73
|
-
return null
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export async function fetchSoulMeta(slug: string) {
|
|
78
|
-
try {
|
|
79
|
-
const apiBase = getApiBase()
|
|
80
|
-
const url = new URL(`/api/v1/souls/${encodeURIComponent(slug)}`, apiBase)
|
|
81
|
-
const response = await fetch(url.toString(), { headers: { Accept: 'application/json' } })
|
|
82
|
-
if (!response.ok) return null
|
|
83
|
-
const payload = (await response.json()) as {
|
|
84
|
-
soul?: { displayName?: string; summary?: string | null } | null
|
|
85
|
-
owner?: { handle?: string | null } | null
|
|
86
|
-
latestVersion?: { version?: string | null } | null
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
displayName: payload.soul?.displayName ?? null,
|
|
90
|
-
summary: payload.soul?.summary ?? null,
|
|
91
|
-
owner: payload.owner?.handle ?? null,
|
|
92
|
-
version: payload.latestVersion?.version ?? null,
|
|
93
|
-
}
|
|
94
|
-
} catch {
|
|
95
|
-
return null
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function buildSkillMeta(source: SkillMetaSource): SkillMeta {
|
|
100
|
-
const siteUrl = getSiteUrl()
|
|
101
|
-
const owner = clean(source.owner)
|
|
102
|
-
const ownerId = clean(source.ownerId)
|
|
103
|
-
const displayName = clean(source.displayName) || clean(source.slug)
|
|
104
|
-
const summary = clean(source.summary)
|
|
105
|
-
const version = clean(source.version)
|
|
106
|
-
const title = `${displayName} — PilotHub`
|
|
107
|
-
const description =
|
|
108
|
-
summary || (owner ? `Agent skill by @${owner} on PilotHub.` : DEFAULT_DESCRIPTION)
|
|
109
|
-
const ownerPath = owner || ownerId || 'unknown'
|
|
110
|
-
const url = `${siteUrl}/${ownerPath}/${source.slug}`
|
|
111
|
-
const imageParams = new URLSearchParams()
|
|
112
|
-
imageParams.set('v', OG_SKILL_IMAGE_LAYOUT_VERSION)
|
|
113
|
-
imageParams.set('slug', source.slug)
|
|
114
|
-
if (owner) imageParams.set('owner', owner)
|
|
115
|
-
if (version) imageParams.set('version', version)
|
|
116
|
-
return {
|
|
117
|
-
title,
|
|
118
|
-
description: truncate(description, 200),
|
|
119
|
-
image: `${siteUrl}/og/skill.png?${imageParams.toString()}`,
|
|
120
|
-
url,
|
|
121
|
-
owner: owner || null,
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function buildSoulMeta(source: SoulMetaSource): SoulMeta {
|
|
126
|
-
const siteUrl = getSoulSiteUrl()
|
|
127
|
-
const owner = clean(source.owner)
|
|
128
|
-
const displayName = clean(source.displayName) || clean(source.slug)
|
|
129
|
-
const summary = clean(source.summary)
|
|
130
|
-
const version = clean(source.version)
|
|
131
|
-
const title = `${displayName} — SoulHub`
|
|
132
|
-
const description =
|
|
133
|
-
summary || (owner ? `Soul by @${owner} on SoulHub.` : DEFAULT_SOUL_DESCRIPTION)
|
|
134
|
-
const url = `${siteUrl}/souls/${source.slug}`
|
|
135
|
-
const imageParams = new URLSearchParams()
|
|
136
|
-
imageParams.set('v', OG_SOUL_IMAGE_LAYOUT_VERSION)
|
|
137
|
-
imageParams.set('slug', source.slug)
|
|
138
|
-
if (owner) imageParams.set('owner', owner)
|
|
139
|
-
if (version) imageParams.set('version', version)
|
|
140
|
-
return {
|
|
141
|
-
title,
|
|
142
|
-
description: truncate(description, 200),
|
|
143
|
-
image: `${siteUrl}/og/soul.png?${imageParams.toString()}`,
|
|
144
|
-
url,
|
|
145
|
-
owner: owner || null,
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function clean(value?: string | null) {
|
|
150
|
-
return value?.trim() ?? ''
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function truncate(value: string, max: number) {
|
|
154
|
-
if (value.length <= max) return value
|
|
155
|
-
return `${value.slice(0, max - 1).trim()}…`
|
|
156
|
-
}
|
package/src/lib/publicUser.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { Doc } from '../../convex/_generated/dataModel'
|
|
2
|
-
|
|
3
|
-
export type PublicUser = Pick<
|
|
4
|
-
Doc<'users'>,
|
|
5
|
-
'_id' | '_creationTime' | 'handle' | 'name' | 'displayName' | 'image' | 'bio'
|
|
6
|
-
>
|
|
7
|
-
|
|
8
|
-
export type PublicSkill = Pick<
|
|
9
|
-
Doc<'skills'>,
|
|
10
|
-
| '_id'
|
|
11
|
-
| '_creationTime'
|
|
12
|
-
| 'slug'
|
|
13
|
-
| 'displayName'
|
|
14
|
-
| 'summary'
|
|
15
|
-
| 'ownerUserId'
|
|
16
|
-
| 'canonicalSkillId'
|
|
17
|
-
| 'forkOf'
|
|
18
|
-
| 'latestVersionId'
|
|
19
|
-
| 'tags'
|
|
20
|
-
| 'badges'
|
|
21
|
-
| 'stats'
|
|
22
|
-
| 'createdAt'
|
|
23
|
-
| 'updatedAt'
|
|
24
|
-
>
|
|
25
|
-
|
|
26
|
-
export type PublicSoul = Pick<
|
|
27
|
-
Doc<'souls'>,
|
|
28
|
-
| '_id'
|
|
29
|
-
| '_creationTime'
|
|
30
|
-
| 'slug'
|
|
31
|
-
| 'displayName'
|
|
32
|
-
| 'summary'
|
|
33
|
-
| 'ownerUserId'
|
|
34
|
-
| 'latestVersionId'
|
|
35
|
-
| 'tags'
|
|
36
|
-
| 'stats'
|
|
37
|
-
| 'createdAt'
|
|
38
|
-
| 'updatedAt'
|
|
39
|
-
>
|
package/src/lib/roles.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Doc } from '../../convex/_generated/dataModel'
|
|
2
|
-
import type { PublicSkill } from './publicUser'
|
|
3
|
-
|
|
4
|
-
type User = Doc<'users'> | null | undefined
|
|
5
|
-
|
|
6
|
-
type Skill = PublicSkill | null | undefined
|
|
7
|
-
|
|
8
|
-
export function isAdmin(user: User) {
|
|
9
|
-
return user?.role === 'admin'
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function isModerator(user: User) {
|
|
13
|
-
return user?.role === 'admin' || user?.role === 'moderator'
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function canManageSkill(user: User, skill: Skill) {
|
|
17
|
-
if (!user || !skill) return false
|
|
18
|
-
return user._id === skill.ownerUserId || isModerator(user)
|
|
19
|
-
}
|
package/src/lib/site.test.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/* @vitest-environment node */
|
|
2
|
-
|
|
3
|
-
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
detectSiteMode,
|
|
7
|
-
detectSiteModeFromUrl,
|
|
8
|
-
getPilotHubSiteUrl,
|
|
9
|
-
getOnlyCrabsHost,
|
|
10
|
-
getOnlyCrabsSiteUrl,
|
|
11
|
-
getSiteDescription,
|
|
12
|
-
getSiteMode,
|
|
13
|
-
getSiteName,
|
|
14
|
-
getSiteUrlForMode,
|
|
15
|
-
} from './site'
|
|
16
|
-
|
|
17
|
-
function withMetaEnv<T>(values: Record<string, string | undefined>, run: () => T): T {
|
|
18
|
-
const env = import.meta.env as unknown as Record<string, unknown>
|
|
19
|
-
const previous = new Map<string, unknown>()
|
|
20
|
-
for (const [key, value] of Object.entries(values)) {
|
|
21
|
-
previous.set(key, env[key])
|
|
22
|
-
if (value === undefined) {
|
|
23
|
-
delete env[key]
|
|
24
|
-
} else {
|
|
25
|
-
env[key] = value
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
return run()
|
|
30
|
-
} finally {
|
|
31
|
-
for (const [key, value] of previous.entries()) {
|
|
32
|
-
if (value === undefined) delete env[key]
|
|
33
|
-
else env[key] = value
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
afterEach(() => {
|
|
39
|
-
vi.unstubAllGlobals()
|
|
40
|
-
vi.unstubAllEnvs()
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
describe('site helpers', () => {
|
|
44
|
-
it('returns default and env configured site URLs', () => {
|
|
45
|
-
expect(getPilotHubSiteUrl()).toBe('https://pilothub.com')
|
|
46
|
-
withMetaEnv({ VITE_SITE_URL: 'https://example.com' }, () => {
|
|
47
|
-
expect(getPilotHubSiteUrl()).toBe('https://example.com')
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('picks SoulHub URL from explicit env', () => {
|
|
52
|
-
withMetaEnv({ VITE_SOULHUB_SITE_URL: 'https://souls.example.com' }, () => {
|
|
53
|
-
expect(getOnlyCrabsSiteUrl()).toBe('https://souls.example.com')
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('derives SoulHub URL from local VITE_SITE_URL', () => {
|
|
58
|
-
withMetaEnv({ VITE_SITE_URL: 'http://localhost:3000' }, () => {
|
|
59
|
-
expect(getOnlyCrabsSiteUrl()).toBe('http://localhost:3000')
|
|
60
|
-
})
|
|
61
|
-
withMetaEnv({ VITE_SITE_URL: 'http://127.0.0.1:3000' }, () => {
|
|
62
|
-
expect(getOnlyCrabsSiteUrl()).toBe('http://127.0.0.1:3000')
|
|
63
|
-
})
|
|
64
|
-
withMetaEnv({ VITE_SITE_URL: 'http://0.0.0.0:3000' }, () => {
|
|
65
|
-
expect(getOnlyCrabsSiteUrl()).toBe('http://0.0.0.0:3000')
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('falls back to default SoulHub URL for invalid VITE_SITE_URL', () => {
|
|
70
|
-
withMetaEnv({ VITE_SITE_URL: 'not a url' }, () => {
|
|
71
|
-
expect(getOnlyCrabsSiteUrl()).toBe('https://onlycrabs.ai')
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('detects site mode from host and URLs', () => {
|
|
76
|
-
expect(detectSiteMode(null)).toBe('skills')
|
|
77
|
-
|
|
78
|
-
withMetaEnv({ VITE_SOULHUB_HOST: 'souls.example.com' }, () => {
|
|
79
|
-
expect(getOnlyCrabsHost()).toBe('souls.example.com')
|
|
80
|
-
expect(detectSiteMode('souls.example.com')).toBe('souls')
|
|
81
|
-
expect(detectSiteMode('sub.souls.example.com')).toBe('souls')
|
|
82
|
-
expect(detectSiteMode('pilothub.com')).toBe('skills')
|
|
83
|
-
|
|
84
|
-
expect(detectSiteModeFromUrl('https://souls.example.com/x')).toBe('souls')
|
|
85
|
-
expect(detectSiteModeFromUrl('souls.example.com')).toBe('souls')
|
|
86
|
-
expect(detectSiteModeFromUrl('https://pilothub.com')).toBe('skills')
|
|
87
|
-
})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('detects site mode from window when available', () => {
|
|
91
|
-
withMetaEnv({ VITE_SOULHUB_HOST: 'onlycrabs.ai' }, () => {
|
|
92
|
-
vi.stubGlobal('window', { location: { hostname: 'onlycrabs.ai' } } as unknown as Window)
|
|
93
|
-
expect(getSiteMode()).toBe('souls')
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('detects site mode from env on the server', () => {
|
|
98
|
-
withMetaEnv({ VITE_SITE_MODE: 'souls', VITE_SOULHUB_HOST: 'onlycrabs.ai' }, () => {
|
|
99
|
-
expect(getSiteMode()).toBe('souls')
|
|
100
|
-
})
|
|
101
|
-
withMetaEnv({ VITE_SITE_MODE: 'skills', VITE_SOULHUB_HOST: 'onlycrabs.ai' }, () => {
|
|
102
|
-
expect(getSiteMode()).toBe('skills')
|
|
103
|
-
})
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
it('detects site mode from VITE_SOULHUB_SITE_URL and SITE_URL fallback', () => {
|
|
107
|
-
withMetaEnv(
|
|
108
|
-
{ VITE_SITE_MODE: undefined, VITE_SOULHUB_SITE_URL: 'https://onlycrabs.ai' },
|
|
109
|
-
() => {
|
|
110
|
-
expect(getSiteMode()).toBe('souls')
|
|
111
|
-
},
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
withMetaEnv({ VITE_SOULHUB_SITE_URL: undefined, VITE_SITE_URL: undefined }, () => {
|
|
115
|
-
vi.stubEnv('SITE_URL', 'https://onlycrabs.ai')
|
|
116
|
-
expect(getSiteMode()).toBe('souls')
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('derives site metadata from mode', () => {
|
|
121
|
-
expect(getSiteName('skills')).toBe('PilotHub')
|
|
122
|
-
expect(getSiteName('souls')).toBe('SoulHub')
|
|
123
|
-
|
|
124
|
-
expect(getSiteDescription('skills')).toContain('PilotHub')
|
|
125
|
-
expect(getSiteDescription('souls')).toContain('SoulHub')
|
|
126
|
-
|
|
127
|
-
expect(getSiteUrlForMode('skills')).toBe('https://pilothub.com')
|
|
128
|
-
expect(getSiteUrlForMode('souls')).toBe('https://onlycrabs.ai')
|
|
129
|
-
})
|
|
130
|
-
})
|