@jam-comments/server-utilities 3.0.0-beta.0 → 3.1.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/dist/cjs/log.js CHANGED
@@ -1,12 +1,8 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.logError = exports.log = void 0;
7
- const chalk_1 = __importDefault(require("chalk"));
8
4
  const log = (message) => {
9
- console.log(`${chalk_1.default.magenta("JamComments:")} ${message}`);
5
+ console.log(`JamComments: ${message}`);
10
6
  };
11
7
  exports.log = log;
12
8
  const logError = (message) => {
@@ -1,23 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.markupFetcher = void 0;
4
+ const utils_1 = require("./utils");
4
5
  const markupFetcher = (platform, fetchImplementation = fetch) => {
5
- return async ({ path, domain, apiKey, baseUrl = 'https://go.jamcomments.com', environment = 'production' }) => {
6
+ return async ({ tz = undefined, path, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = "production", }) => {
7
+ if (tz && !(0, utils_1.isValidTimezone)(tz)) {
8
+ throw new Error(`The timezone passed to JamComments is invalid: ${tz}`);
9
+ }
6
10
  const params = new URLSearchParams({
7
11
  path: path || "/",
8
- domain
12
+ domain,
9
13
  });
10
- if (environment !== 'production') {
11
- params.set('stub', 'true');
14
+ if (tz) {
15
+ params.set("tz", tz);
16
+ }
17
+ if (environment !== "production") {
18
+ params.set("stub", "true");
12
19
  }
13
20
  const requestUrl = `${baseUrl}/api/v2/markup?${params}`;
14
21
  const response = await fetchImplementation(requestUrl, {
15
- method: 'GET',
22
+ method: "GET",
16
23
  headers: {
17
24
  Authorization: `Bearer ${apiKey}`,
18
- Accept: 'application/json',
19
- 'X-Platform': platform
20
- }
25
+ Accept: "application/json",
26
+ "X-Platform": platform,
27
+ },
21
28
  });
22
29
  if (response.status === 401) {
23
30
  throw new Error(`Unauthorized! Are your domain and JamComments API key set correctly?`);
@@ -8,22 +8,22 @@ const markupFetcher_1 = require("./markupFetcher");
8
8
  return {
9
9
  status: 200,
10
10
  ok: true,
11
- text: () => "results!"
11
+ text: () => "results!",
12
12
  };
13
13
  });
14
14
  const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
15
15
  const result = await fetcher({
16
16
  path: "/test",
17
17
  domain: "test.com",
18
- apiKey: "123abc"
18
+ apiKey: "123abc",
19
19
  });
20
- (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/markup?path=%2Ftest&domain=test.com", vitest_1.expect.objectContaining({
20
+ (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2Ftest&domain=test.com", vitest_1.expect.objectContaining({
21
21
  headers: vitest_1.expect.objectContaining({
22
22
  Accept: "application/json",
23
23
  Authorization: "Bearer 123abc",
24
- "X-Platform": "test"
24
+ "X-Platform": "test",
25
25
  }),
26
- method: "GET"
26
+ method: "GET",
27
27
  }));
28
28
  (0, vitest_1.expect)(result).toEqual("results!");
29
29
  });
@@ -32,7 +32,7 @@ const markupFetcher_1 = require("./markupFetcher");
32
32
  return {
33
33
  status: 200,
34
34
  ok: true,
35
- text: () => "results!"
35
+ text: () => "results!",
36
36
  };
37
37
  });
38
38
  const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
@@ -40,9 +40,9 @@ const markupFetcher_1 = require("./markupFetcher");
40
40
  path: "/test",
41
41
  domain: "test.com",
42
42
  apiKey: "123abc",
43
- environment: "development"
43
+ environment: "development",
44
44
  });
45
- (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/markup?path=%2Ftest&domain=test.com&stub=true", vitest_1.expect.anything());
45
+ (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2Ftest&domain=test.com&stub=true", vitest_1.expect.anything());
46
46
  (0, vitest_1.expect)(result).toEqual("results!");
47
47
  });
48
48
  (0, vitest_1.it)("uses different base URL", async () => {
@@ -50,7 +50,7 @@ const markupFetcher_1 = require("./markupFetcher");
50
50
  return {
51
51
  status: 200,
52
52
  ok: true,
53
- text: () => "results!"
53
+ text: () => "results!",
54
54
  };
55
55
  });
56
56
  const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
@@ -58,9 +58,9 @@ const markupFetcher_1 = require("./markupFetcher");
58
58
  path: "/test",
59
59
  domain: "test.com",
60
60
  apiKey: "123abc",
61
- baseUrl: "http://ur-mom.com"
61
+ baseUrl: "http://ur-mom.com",
62
62
  });
63
- (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/markup?path=%2Ftest&domain=test.com", vitest_1.expect.anything());
63
+ (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v2/markup?path=%2Ftest&domain=test.com", vitest_1.expect.anything());
64
64
  (0, vitest_1.expect)(result).toEqual("results!");
65
65
  });
66
66
  (0, vitest_1.it)("falls back to root path", async () => {
@@ -68,15 +68,15 @@ const markupFetcher_1 = require("./markupFetcher");
68
68
  return {
69
69
  status: 200,
70
70
  ok: true,
71
- text: () => "results!"
71
+ text: () => "results!",
72
72
  };
73
73
  });
74
74
  const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
75
75
  const result = await fetcher({
76
76
  path: null,
77
- domain: "test.com"
77
+ domain: "test.com",
78
78
  });
79
- (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/markup?path=%2F&domain=test.com", vitest_1.expect.anything());
79
+ (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2F&domain=test.com", vitest_1.expect.anything());
80
80
  (0, vitest_1.expect)(result).toEqual("results!");
81
81
  });
82
82
  (0, vitest_1.it)("credentials are invalid", async () => {
@@ -84,14 +84,14 @@ const markupFetcher_1 = require("./markupFetcher");
84
84
  return {
85
85
  status: 401,
86
86
  ok: false,
87
- text: () => "bad results!"
87
+ text: () => "bad results!",
88
88
  };
89
89
  });
90
90
  const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
91
91
  (0, vitest_1.expect)(fetcher({
92
92
  path: "/test",
93
93
  domain: "test.com",
94
- apiKey: "123abc"
94
+ apiKey: "123abc",
95
95
  })).rejects.toThrowError(/Unauthorized!/);
96
96
  });
97
97
  (0, vitest_1.it)("response isn't ok", async () => {
@@ -99,14 +99,44 @@ const markupFetcher_1 = require("./markupFetcher");
99
99
  return {
100
100
  status: 500,
101
101
  ok: false,
102
- text: () => "bad results!"
102
+ text: () => "bad results!",
103
103
  };
104
104
  });
105
105
  const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
106
106
  (0, vitest_1.expect)(fetcher({
107
107
  path: "/test",
108
108
  domain: "test.com",
109
- apiKey: "123abc"
109
+ apiKey: "123abc",
110
110
  })).rejects.toThrowError(/request failed! Status code: 500/);
111
111
  });
112
+ (0, vitest_1.describe)("timezone validation", () => {
113
+ (0, vitest_1.it)("throws error when invalid timezone is provided", async () => {
114
+ const fetchMock = vitest_1.vi.fn();
115
+ const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
116
+ (0, vitest_1.expect)(fetchMock).not.toHaveBeenCalled();
117
+ (0, vitest_1.expect)(fetcher({
118
+ path: "/test",
119
+ domain: "test.com",
120
+ apiKey: "123abc",
121
+ tz: "in/valid",
122
+ })).rejects.toThrowError("The timezone passed to JamComments is invalid: in/valid");
123
+ });
124
+ (0, vitest_1.it)("does not throw error when valid timezone is provided", async () => {
125
+ const fetchMock = vitest_1.vi.fn().mockImplementation(() => {
126
+ return {
127
+ status: 200,
128
+ ok: true,
129
+ text: () => "results!",
130
+ };
131
+ });
132
+ const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
133
+ const result = await fetcher({
134
+ path: null,
135
+ domain: "test.com",
136
+ tz: "America/New_York",
137
+ });
138
+ (0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2F&domain=test.com&tz=America%2FNew_York", vitest_1.expect.anything());
139
+ (0, vitest_1.expect)(result).toEqual("results!");
140
+ });
141
+ });
112
142
  });
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isValidTimezone = void 0;
4
+ function isValidTimezone(tz) {
5
+ try {
6
+ Intl.DateTimeFormat(undefined, { timeZone: tz });
7
+ return true;
8
+ }
9
+ catch (ex) {
10
+ return false;
11
+ }
12
+ }
13
+ exports.isValidTimezone = isValidTimezone;
package/dist/esm/log.js CHANGED
@@ -1,6 +1,5 @@
1
- import chalk from "chalk";
2
1
  export const log = (message) => {
3
- console.log(`${chalk.magenta("JamComments:")} ${message}`);
2
+ console.log(`JamComments: ${message}`);
4
3
  };
5
4
  export const logError = (message) => {
6
5
  console.error(`JamComments: ${message}`);
@@ -1,20 +1,27 @@
1
+ import { isValidTimezone } from "./utils";
1
2
  export const markupFetcher = (platform, fetchImplementation = fetch) => {
2
- return async ({ path, domain, apiKey, baseUrl = 'https://go.jamcomments.com', environment = 'production' }) => {
3
+ return async ({ tz = undefined, path, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = "production", }) => {
4
+ if (tz && !isValidTimezone(tz)) {
5
+ throw new Error(`The timezone passed to JamComments is invalid: ${tz}`);
6
+ }
3
7
  const params = new URLSearchParams({
4
8
  path: path || "/",
5
- domain
9
+ domain,
6
10
  });
7
- if (environment !== 'production') {
8
- params.set('stub', 'true');
11
+ if (tz) {
12
+ params.set("tz", tz);
13
+ }
14
+ if (environment !== "production") {
15
+ params.set("stub", "true");
9
16
  }
10
17
  const requestUrl = `${baseUrl}/api/v2/markup?${params}`;
11
18
  const response = await fetchImplementation(requestUrl, {
12
- method: 'GET',
19
+ method: "GET",
13
20
  headers: {
14
21
  Authorization: `Bearer ${apiKey}`,
15
- Accept: 'application/json',
16
- 'X-Platform': platform
17
- }
22
+ Accept: "application/json",
23
+ "X-Platform": platform,
24
+ },
18
25
  });
19
26
  if (response.status === 401) {
20
27
  throw new Error(`Unauthorized! Are your domain and JamComments API key set correctly?`);
@@ -1,4 +1,4 @@
1
- import { describe, expect, it, vi } from 'vitest';
1
+ import { describe, expect, it, vi } from "vitest";
2
2
  import { markupFetcher } from "./markupFetcher";
3
3
  describe("markupFetcher", () => {
4
4
  it("constructs fetch request correctly", async () => {
@@ -6,22 +6,22 @@ describe("markupFetcher", () => {
6
6
  return {
7
7
  status: 200,
8
8
  ok: true,
9
- text: () => "results!"
9
+ text: () => "results!",
10
10
  };
11
11
  });
12
12
  const fetcher = markupFetcher("test", fetchMock);
13
13
  const result = await fetcher({
14
14
  path: "/test",
15
15
  domain: "test.com",
16
- apiKey: "123abc"
16
+ apiKey: "123abc",
17
17
  });
18
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/markup?path=%2Ftest&domain=test.com", expect.objectContaining({
18
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2Ftest&domain=test.com", expect.objectContaining({
19
19
  headers: expect.objectContaining({
20
20
  Accept: "application/json",
21
21
  Authorization: "Bearer 123abc",
22
- "X-Platform": "test"
22
+ "X-Platform": "test",
23
23
  }),
24
- method: "GET"
24
+ method: "GET",
25
25
  }));
26
26
  expect(result).toEqual("results!");
27
27
  });
@@ -30,7 +30,7 @@ describe("markupFetcher", () => {
30
30
  return {
31
31
  status: 200,
32
32
  ok: true,
33
- text: () => "results!"
33
+ text: () => "results!",
34
34
  };
35
35
  });
36
36
  const fetcher = markupFetcher("test", fetchMock);
@@ -38,9 +38,9 @@ describe("markupFetcher", () => {
38
38
  path: "/test",
39
39
  domain: "test.com",
40
40
  apiKey: "123abc",
41
- environment: "development"
41
+ environment: "development",
42
42
  });
43
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/markup?path=%2Ftest&domain=test.com&stub=true", expect.anything());
43
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2Ftest&domain=test.com&stub=true", expect.anything());
44
44
  expect(result).toEqual("results!");
45
45
  });
46
46
  it("uses different base URL", async () => {
@@ -48,7 +48,7 @@ describe("markupFetcher", () => {
48
48
  return {
49
49
  status: 200,
50
50
  ok: true,
51
- text: () => "results!"
51
+ text: () => "results!",
52
52
  };
53
53
  });
54
54
  const fetcher = markupFetcher("test", fetchMock);
@@ -56,9 +56,9 @@ describe("markupFetcher", () => {
56
56
  path: "/test",
57
57
  domain: "test.com",
58
58
  apiKey: "123abc",
59
- baseUrl: "http://ur-mom.com"
59
+ baseUrl: "http://ur-mom.com",
60
60
  });
61
- expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/markup?path=%2Ftest&domain=test.com", expect.anything());
61
+ expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v2/markup?path=%2Ftest&domain=test.com", expect.anything());
62
62
  expect(result).toEqual("results!");
63
63
  });
64
64
  it("falls back to root path", async () => {
@@ -66,15 +66,15 @@ describe("markupFetcher", () => {
66
66
  return {
67
67
  status: 200,
68
68
  ok: true,
69
- text: () => "results!"
69
+ text: () => "results!",
70
70
  };
71
71
  });
72
72
  const fetcher = markupFetcher("test", fetchMock);
73
73
  const result = await fetcher({
74
74
  path: null,
75
- domain: "test.com"
75
+ domain: "test.com",
76
76
  });
77
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/markup?path=%2F&domain=test.com", expect.anything());
77
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2F&domain=test.com", expect.anything());
78
78
  expect(result).toEqual("results!");
79
79
  });
80
80
  it("credentials are invalid", async () => {
@@ -82,14 +82,14 @@ describe("markupFetcher", () => {
82
82
  return {
83
83
  status: 401,
84
84
  ok: false,
85
- text: () => "bad results!"
85
+ text: () => "bad results!",
86
86
  };
87
87
  });
88
88
  const fetcher = markupFetcher("test", fetchMock);
89
89
  expect(fetcher({
90
90
  path: "/test",
91
91
  domain: "test.com",
92
- apiKey: "123abc"
92
+ apiKey: "123abc",
93
93
  })).rejects.toThrowError(/Unauthorized!/);
94
94
  });
95
95
  it("response isn't ok", async () => {
@@ -97,14 +97,44 @@ describe("markupFetcher", () => {
97
97
  return {
98
98
  status: 500,
99
99
  ok: false,
100
- text: () => "bad results!"
100
+ text: () => "bad results!",
101
101
  };
102
102
  });
103
103
  const fetcher = markupFetcher("test", fetchMock);
104
104
  expect(fetcher({
105
105
  path: "/test",
106
106
  domain: "test.com",
107
- apiKey: "123abc"
107
+ apiKey: "123abc",
108
108
  })).rejects.toThrowError(/request failed! Status code: 500/);
109
109
  });
110
+ describe("timezone validation", () => {
111
+ it("throws error when invalid timezone is provided", async () => {
112
+ const fetchMock = vi.fn();
113
+ const fetcher = markupFetcher("test", fetchMock);
114
+ expect(fetchMock).not.toHaveBeenCalled();
115
+ expect(fetcher({
116
+ path: "/test",
117
+ domain: "test.com",
118
+ apiKey: "123abc",
119
+ tz: "in/valid",
120
+ })).rejects.toThrowError("The timezone passed to JamComments is invalid: in/valid");
121
+ });
122
+ it("does not throw error when valid timezone is provided", async () => {
123
+ const fetchMock = vi.fn().mockImplementation(() => {
124
+ return {
125
+ status: 200,
126
+ ok: true,
127
+ text: () => "results!",
128
+ };
129
+ });
130
+ const fetcher = markupFetcher("test", fetchMock);
131
+ const result = await fetcher({
132
+ path: null,
133
+ domain: "test.com",
134
+ tz: "America/New_York",
135
+ });
136
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v2/markup?path=%2F&domain=test.com&tz=America%2FNew_York", expect.anything());
137
+ expect(result).toEqual("results!");
138
+ });
139
+ });
110
140
  });
@@ -0,0 +1,9 @@
1
+ export function isValidTimezone(tz) {
2
+ try {
3
+ Intl.DateTimeFormat(undefined, { timeZone: tz });
4
+ return true;
5
+ }
6
+ catch (ex) {
7
+ return false;
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ export declare function isValidTimezone(tz: string): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jam-comments/server-utilities",
3
- "version": "3.0.0-beta.0",
3
+ "version": "3.1.0",
4
4
  "description": "Various JavaScript utilities for JamComments.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -13,20 +13,19 @@
13
13
  "build:esm": "tsc --module es2020 --outDir dist/esm",
14
14
  "build:cjs": "tsc --module commonjs --outDir dist/cjs",
15
15
  "test": "vitest run src",
16
+ "format": "prettier --write src/**/*.ts",
16
17
  "prepare": "npm run build"
17
18
  },
18
19
  "keywords": [],
19
20
  "author": "Alex MacArthur <alex@macarthur.me> (https://macarthur.me)",
20
21
  "homepage": "https://jamcomments.com",
21
22
  "license": "GPL-2.0",
22
- "dependencies": {
23
- "typescript": "^4.9.3"
24
- },
25
23
  "devDependencies": {
26
- "@types/node": "^18.11.9",
27
- "prettier": "^2.7.1",
28
- "vite": "^3.2.4",
29
- "vitest": "^0.25.3"
24
+ "@types/node": "^20.2.5",
25
+ "prettier": "^2.8.8",
26
+ "typescript": "^5.0.4",
27
+ "vite": "^4.3.9",
28
+ "vitest": "^0.31.1"
30
29
  },
31
30
  "publishConfig": {
32
31
  "access": "public"