@gigamusic/links 0.1.0 → 0.2.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gigamusic/links",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Editable Linktree-style link pages for gigamusic artist sites. Ships a Prisma fragment, public + admin React components, admin API handler factories, and platform-detection helpers.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,10 +38,10 @@
38
38
  "access": "public"
39
39
  },
40
40
  "dependencies": {
41
- "@gigamusic/config": "0.1.0",
42
- "@gigamusic/core": "0.1.0",
43
- "@gigamusic/db": "0.1.0",
44
- "@gigamusic/ui": "0.1.0"
41
+ "@gigamusic/core": "0.2.0",
42
+ "@gigamusic/ui": "0.2.0",
43
+ "@gigamusic/config": "0.2.0",
44
+ "@gigamusic/db": "0.2.0"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@prisma/client": ">=6",
@@ -1,6 +1,5 @@
1
1
  import { revalidateTag } from "next/cache";
2
2
  import type { LinkPageQueries } from "../types";
3
- import { verifyAdminSession } from "./auth";
4
3
  import {
5
4
  INVALID_SLUG_MESSAGE,
6
5
  RESERVED_SLUGS,
@@ -22,9 +21,14 @@ export type RouteHandler<Params = Record<string, string>> = (
22
21
  ctx: { params: Promise<Params> },
23
22
  ) => Promise<Response> | Response;
24
23
 
24
+ /**
25
+ * Deps for the admin-side link-page handler factories.
26
+ *
27
+ * Auth: the package assumes the request has been gated by the consumer's
28
+ * `proxy.ts` / middleware. These handlers don't verify a session.
29
+ */
25
30
  export interface LinkPagesAdminDeps {
26
31
  queries: LinkPageQueries;
27
- adminSessionSecret: string;
28
32
  }
29
33
 
30
34
  function json(body: unknown, init?: ResponseInit): Response {
@@ -37,14 +41,6 @@ function json(body: unknown, init?: ResponseInit): Response {
37
41
  });
38
42
  }
39
43
 
40
- async function requireAdmin(
41
- req: Request,
42
- secret: string,
43
- ): Promise<Response | null> {
44
- if (await verifyAdminSession(req, secret)) return null;
45
- return json({ error: "Unauthorized" }, { status: 401 });
46
- }
47
-
48
44
  interface LinkPageBody {
49
45
  title?: string;
50
46
  slug?: string;
@@ -73,16 +69,12 @@ export function createAdminLinkPagesHandlers(deps: LinkPagesAdminDeps): {
73
69
  } {
74
70
  return {
75
71
  GET: async (req) => {
76
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
77
- if (unauth) return unauth;
78
- const pages = await deps.queries.listAllLinkPages();
72
+ const pages = await deps.queries.listAllLinkPages();
79
73
  return json(pages);
80
74
  },
81
75
 
82
76
  POST: async (req) => {
83
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
84
- if (unauth) return unauth;
85
- const body = (await req.json()) as LinkPageBody;
77
+ const body = (await req.json()) as LinkPageBody;
86
78
  const title = body.title?.trim();
87
79
  const slug = body.slug?.trim().toLowerCase();
88
80
 
@@ -122,9 +114,7 @@ export function createAdminLinkPageByIdHandlers(deps: LinkPagesAdminDeps): {
122
114
  } {
123
115
  return {
124
116
  GET: async (req, { params }) => {
125
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
126
- if (unauth) return unauth;
127
- const { id: idParam } = await params;
117
+ const { id: idParam } = await params;
128
118
  const id = Number(idParam);
129
119
  if (!Number.isFinite(id)) return json({ error: "Not found" }, { status: 404 });
130
120
  const page = await deps.queries.getLinkPageById(id);
@@ -133,9 +123,7 @@ export function createAdminLinkPageByIdHandlers(deps: LinkPagesAdminDeps): {
133
123
  },
134
124
 
135
125
  PUT: async (req, { params }) => {
136
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
137
- if (unauth) return unauth;
138
- const { id: idParam } = await params;
126
+ const { id: idParam } = await params;
139
127
  const id = Number(idParam);
140
128
  if (!Number.isFinite(id)) return json({ error: "Not found" }, { status: 404 });
141
129
  const body = (await req.json()) as LinkPageBody;
@@ -171,9 +159,7 @@ export function createAdminLinkPageByIdHandlers(deps: LinkPagesAdminDeps): {
171
159
  },
172
160
 
173
161
  DELETE: async (req, { params }) => {
174
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
175
- if (unauth) return unauth;
176
- const { id: idParam } = await params;
162
+ const { id: idParam } = await params;
177
163
  const id = Number(idParam);
178
164
  if (!Number.isFinite(id)) return json({ error: "Not found" }, { status: 404 });
179
165
  await deps.queries.deleteLinkPage(id);
@@ -207,9 +193,7 @@ export function createAdminLinkPageItemsHandlers(
207
193
  } {
208
194
  return {
209
195
  POST: async (req, { params }) => {
210
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
211
- if (unauth) return unauth;
212
- const { id: pageIdParam } = await params;
196
+ const { id: pageIdParam } = await params;
213
197
  const pageId = Number(pageIdParam);
214
198
  if (!Number.isFinite(pageId)) {
215
199
  return json({ error: "Not found" }, { status: 404 });
@@ -227,9 +211,7 @@ export function createAdminLinkPageItemsHandlers(
227
211
  },
228
212
 
229
213
  PUT: async (req) => {
230
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
231
- if (unauth) return unauth;
232
- const body = (await req.json()) as LinkPageItemBody;
214
+ const body = (await req.json()) as LinkPageItemBody;
233
215
  if (body.itemId == null) {
234
216
  return json({ error: "itemId is required" }, { status: 400 });
235
217
  }
@@ -248,9 +230,7 @@ export function createAdminLinkPageItemsHandlers(
248
230
  },
249
231
 
250
232
  DELETE: async (req) => {
251
- const unauth = await requireAdmin(req, deps.adminSessionSecret);
252
- if (unauth) return unauth;
253
- const { searchParams } = new URL(req.url);
233
+ const { searchParams } = new URL(req.url);
254
234
  const itemIdRaw = searchParams.get("itemId");
255
235
  if (!itemIdRaw) {
256
236
  return json({ error: "itemId is required" }, { status: 400 });
package/src/api/auth.ts DELETED
@@ -1,34 +0,0 @@
1
- import { verifyAdminSessionToken } from "@gigamusic/core";
2
-
3
- const ADMIN_SESSION_COOKIE = "admin_session";
4
-
5
- /**
6
- * Stateless cookie verification for route handlers. Mirrors
7
- * `@gigamusic/admin`'s `verifyAdminSession` so consumers can wire both
8
- * packages to the same session secret without coupling them at the package
9
- * level.
10
- */
11
- export async function verifyAdminSession(
12
- req: Request,
13
- adminSessionSecret: string,
14
- ): Promise<boolean> {
15
- const header = req.headers.get("cookie");
16
- if (!header) return false;
17
- const token = parseCookieHeader(header, ADMIN_SESSION_COOKIE);
18
- if (!token) return false;
19
- try {
20
- await verifyAdminSessionToken(token, adminSessionSecret);
21
- return true;
22
- } catch {
23
- return false;
24
- }
25
- }
26
-
27
- function parseCookieHeader(header: string, name: string): string | null {
28
- for (const raw of header.split(";")) {
29
- const trimmed = raw.trim();
30
- if (!trimmed.startsWith(`${name}=`)) continue;
31
- return decodeURIComponent(trimmed.slice(name.length + 1));
32
- }
33
- return null;
34
- }