Skip to content

Commit

Permalink
feat: new jsr api
Browse files Browse the repository at this point in the history
  • Loading branch information
flamrdevs committed May 28, 2024
1 parent 27e52c7 commit 10ab11f
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 3 deletions.
3 changes: 3 additions & 0 deletions public/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ await FETCH.GET('/npm/l/@klass/core', 200);
await FETCH.GET('/npm/dw/@klass/core', 200);
await FETCH.GET('/npm/dm/@klass/core', 200);

await FETCH.GET('/jsr/api/item/@hono/hono', 200);
await FETCH.GET('/jsr/v/@hono/hono', 200);

await FETCH.GET('/ui/badge', 200);
await FETCH.GET('/ui/badge/lucide', 200);
await FETCH.GET('/ui/badge/simple', 200);
Expand Down
1 change: 1 addition & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ app
.route('/bundlejs', routes.bundlejs)
.route('/github', routes.github)
.route('/npm', routes.npm)
.route('/jsr', routes.jsr)
.route('/ui', routes.ui);

app
Expand Down
4 changes: 2 additions & 2 deletions src/libs/@internal/ftch/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { HTTPException } from 'hono/http-exception';

type Method = 'GET';

const json = async <M extends Method>(method: M, input: RequestInfo) => {
const res = await fetch(input, { method });
const json = async <M extends Method>(method: M, input: RequestInfo, headers: HeadersInit = {}) => {
const res = await fetch(input, { method, headers });
if (res.ok) return await res.json();
throw new HTTPException(500, { message: 'Fetch failed' });
};
Expand Down
2 changes: 1 addition & 1 deletion src/libs/@internal/ftch/get.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as _ from './core';

const json = async <T = unknown>(url: string) => (await _.json('GET', url)) as T;
const json = async <T = unknown>(url: string, headers?: HeadersInit) => (await _.json('GET', url, headers)) as T;

export { json };
1 change: 1 addition & 0 deletions src/libs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export const bundlejs = () => import('./bundlejs');
export const github = () => import('./github');

export const npm = () => import('./npm');
export const jsr = () => import('./jsr');
26 changes: 26 additions & 0 deletions src/libs/jsr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as v from 'valibot';

import { ftch, memo, url } from './@internal';

const PackageNameSchema = v.pipe(v.string(), v.regex(/^@[a-z0-9-~][a-z0-9-._~]*\/[a-z0-9-~][a-z0-9-._~]*$/), v.regex(/^(?!.*-$)[\s\S]*$/));

const getValidPackageNameParam = (param: Record<string, string>, key: string = 'name') => v.parse(PackageNameSchema, param[key]);

type PackageItem = v.InferOutput<typeof PackageItemSchema>;

const PackageItemSchema = v.looseObject({
scope: v.string(),
name: v.string(),
latest: v.string(),
});

const loadPackageItem = memo<PackageItem>();

const registry = url('https://jsr.io');

const getPackageItem = (name: string): Promise<PackageItem> => loadPackageItem(name, async () => v.parse(PackageItemSchema, await ftch.get.json(registry`/${name}/meta.json`, { Accept: 'json' })));

export type { PackageItem };
export { PackageNameSchema };
export { getPackageItem };
export { getValidPackageNameParam };
1 change: 1 addition & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as bundlejs } from './bundlejs';
export { default as github } from './github';
export { default as npm } from './npm';
export { default as jsr } from './jsr';
export { default as ui } from './ui';
40 changes: 40 additions & 0 deletions src/routes/jsr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Hono } from 'hono';

import { jsr } from '~/libs';

import { getValidColorQuery, getValidThemeQuery, core } from '~/ui';

import * as response from '~/utils/response';

export default new Hono()

/**
* api
*/
.route(
'/api',
new Hono().get('/item/:name{.+$}', async (ctx) => {
const { getPackageItem, getValidPackageNameParam } = await jsr();

return ctx.json(await getPackageItem(getValidPackageNameParam(ctx.req.param())));
})
)

/**
* version
*/
.get('/v/:name{.+$}', async (ctx) => {
const { getPackageItem, getValidPackageNameParam } = await jsr();

const param = ctx.req.param();
const query = ctx.req.query();

const n = getValidPackageNameParam(param);

const c = getValidColorQuery(query);
const t = getValidThemeQuery(query);

const v = (await getPackageItem(n)).latest;

return await response.svg(ctx, async () => core.Badge({ c, t, w: core.calcBadgeWidth(v), children: v }));
});

0 comments on commit 10ab11f

Please sign in to comment.