@hasna/shortlinks 0.1.19 → 0.1.20

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/dist/cli/index.js CHANGED
@@ -4138,6 +4138,9 @@ function getClientIp(request) {
4138
4138
  function isExpired(link) {
4139
4139
  return Boolean(link.expires_at && new Date(link.expires_at).getTime() <= Date.now());
4140
4140
  }
4141
+ function logRecordClickError(link) {
4142
+ console.error(`[shortlinks] Click analytics recording failed for ${link.hostname}/${link.slug}.`);
4143
+ }
4141
4144
  function createShortlinksHandler(options = {}) {
4142
4145
  const store = options.store || new ShortlinksStore(options.dbPath);
4143
4146
  const redirectStatus = options.redirectStatus || 302;
@@ -4176,16 +4179,28 @@ function createShortlinksHandler(options = {}) {
4176
4179
  if (isExpired(link))
4177
4180
  return json({ error: "Shortlink is expired.", slug, host }, 410);
4178
4181
  if (request.method === "GET") {
4179
- await store.recordClick(link, {
4180
- ip: getClientIp(request),
4181
- userAgent: request.headers.get("user-agent"),
4182
- referer: request.headers.get("referer"),
4183
- country: request.headers.get("cf-ipcountry"),
4184
- metadata: {
4185
- path: url.pathname,
4186
- query: url.search
4182
+ try {
4183
+ await store.recordClick(link, {
4184
+ ip: getClientIp(request),
4185
+ userAgent: request.headers.get("user-agent"),
4186
+ referer: request.headers.get("referer"),
4187
+ country: request.headers.get("cf-ipcountry"),
4188
+ metadata: {
4189
+ path: url.pathname,
4190
+ query: url.search
4191
+ }
4192
+ });
4193
+ } catch (error) {
4194
+ if (options.onRecordClickError) {
4195
+ try {
4196
+ await options.onRecordClickError(error, { link, request });
4197
+ } catch {
4198
+ logRecordClickError(link);
4199
+ }
4200
+ } else {
4201
+ logRecordClickError(link);
4187
4202
  }
4188
- });
4203
+ }
4189
4204
  }
4190
4205
  return Response.redirect(link.destination_url, redirectStatus);
4191
4206
  };
package/dist/index.js CHANGED
@@ -874,6 +874,9 @@ function getClientIp(request) {
874
874
  function isExpired(link) {
875
875
  return Boolean(link.expires_at && new Date(link.expires_at).getTime() <= Date.now());
876
876
  }
877
+ function logRecordClickError(link) {
878
+ console.error(`[shortlinks] Click analytics recording failed for ${link.hostname}/${link.slug}.`);
879
+ }
877
880
  function createShortlinksHandler(options = {}) {
878
881
  const store = options.store || new ShortlinksStore(options.dbPath);
879
882
  const redirectStatus = options.redirectStatus || 302;
@@ -912,16 +915,28 @@ function createShortlinksHandler(options = {}) {
912
915
  if (isExpired(link))
913
916
  return json({ error: "Shortlink is expired.", slug, host }, 410);
914
917
  if (request.method === "GET") {
915
- await store.recordClick(link, {
916
- ip: getClientIp(request),
917
- userAgent: request.headers.get("user-agent"),
918
- referer: request.headers.get("referer"),
919
- country: request.headers.get("cf-ipcountry"),
920
- metadata: {
921
- path: url.pathname,
922
- query: url.search
918
+ try {
919
+ await store.recordClick(link, {
920
+ ip: getClientIp(request),
921
+ userAgent: request.headers.get("user-agent"),
922
+ referer: request.headers.get("referer"),
923
+ country: request.headers.get("cf-ipcountry"),
924
+ metadata: {
925
+ path: url.pathname,
926
+ query: url.search
927
+ }
928
+ });
929
+ } catch (error) {
930
+ if (options.onRecordClickError) {
931
+ try {
932
+ await options.onRecordClickError(error, { link, request });
933
+ } catch {
934
+ logRecordClickError(link);
935
+ }
936
+ } else {
937
+ logRecordClickError(link);
923
938
  }
924
- });
939
+ }
925
940
  }
926
941
  return Response.redirect(link.destination_url, redirectStatus);
927
942
  };
package/dist/server.d.ts CHANGED
@@ -12,11 +12,16 @@ export interface ShortlinksRuntimeStore {
12
12
  resolve(hostname: string, slug: string): Link | null | Promise<Link | null>;
13
13
  recordClick(link: Link, input?: ClickInput): unknown | Promise<unknown>;
14
14
  }
15
+ export interface RecordClickErrorContext {
16
+ link: Link;
17
+ request: Request;
18
+ }
15
19
  export interface ShortlinksHandlerOptions {
16
20
  store?: ShortlinksRuntimeStore;
17
21
  dbPath?: string;
18
22
  defaultHost?: string;
19
23
  redirectStatus?: 301 | 302 | 307 | 308;
24
+ onRecordClickError?: (error: unknown, context: RecordClickErrorContext) => void | Promise<void>;
20
25
  }
21
26
  export declare function createShortlinksHandler(options?: ShortlinksHandlerOptions): (request: Request) => Response | Promise<Response>;
22
27
  export declare function serveShortlinks(options?: ShortlinksHandlerOptions & {
package/dist/server.js CHANGED
@@ -555,6 +555,9 @@ function getClientIp(request) {
555
555
  function isExpired(link) {
556
556
  return Boolean(link.expires_at && new Date(link.expires_at).getTime() <= Date.now());
557
557
  }
558
+ function logRecordClickError(link) {
559
+ console.error(`[shortlinks] Click analytics recording failed for ${link.hostname}/${link.slug}.`);
560
+ }
558
561
  function createShortlinksHandler(options = {}) {
559
562
  const store = options.store || new ShortlinksStore(options.dbPath);
560
563
  const redirectStatus = options.redirectStatus || 302;
@@ -593,16 +596,28 @@ function createShortlinksHandler(options = {}) {
593
596
  if (isExpired(link))
594
597
  return json({ error: "Shortlink is expired.", slug, host }, 410);
595
598
  if (request.method === "GET") {
596
- await store.recordClick(link, {
597
- ip: getClientIp(request),
598
- userAgent: request.headers.get("user-agent"),
599
- referer: request.headers.get("referer"),
600
- country: request.headers.get("cf-ipcountry"),
601
- metadata: {
602
- path: url.pathname,
603
- query: url.search
599
+ try {
600
+ await store.recordClick(link, {
601
+ ip: getClientIp(request),
602
+ userAgent: request.headers.get("user-agent"),
603
+ referer: request.headers.get("referer"),
604
+ country: request.headers.get("cf-ipcountry"),
605
+ metadata: {
606
+ path: url.pathname,
607
+ query: url.search
608
+ }
609
+ });
610
+ } catch (error) {
611
+ if (options.onRecordClickError) {
612
+ try {
613
+ await options.onRecordClickError(error, { link, request });
614
+ } catch {
615
+ logRecordClickError(link);
616
+ }
617
+ } else {
618
+ logRecordClickError(link);
604
619
  }
605
- });
620
+ }
606
621
  }
607
622
  return Response.redirect(link.destination_url, redirectStatus);
608
623
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/shortlinks",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "CLI-only shortlink manager for custom domains, click tracking, Cloudflare setup, and @hasna cloud sync",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",