@jam-comments/server-utilities 4.2.0 → 4.3.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/index.js +8 -1
- package/dist/cjs/markupFetcher.js +93 -33
- package/dist/cjs/markupFetcher.test.js +223 -28
- package/dist/cjs/utils.js +52 -15
- package/dist/cjs/utils.test.js +43 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/markupFetcher.js +89 -33
- package/dist/esm/markupFetcher.test.js +212 -17
- package/dist/esm/utils.js +46 -14
- package/dist/esm/utils.test.js +44 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/markupFetcher.d.ts +24 -1
- package/dist/types/utils.d.ts +7 -0
- package/package.json +1 -1
package/dist/cjs/utils.test.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const vitest_1 = require("vitest");
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
|
+
const _1 = require(".");
|
|
5
6
|
const env = process.env;
|
|
6
7
|
(0, vitest_1.beforeEach)(() => {
|
|
7
8
|
vitest_1.vi.resetModules();
|
|
@@ -44,3 +45,45 @@ const env = process.env;
|
|
|
44
45
|
});
|
|
45
46
|
});
|
|
46
47
|
});
|
|
48
|
+
(0, vitest_1.describe)("createTempDirectory()", () => {
|
|
49
|
+
(0, vitest_1.it)("creates temp directory fresh", () => {
|
|
50
|
+
const mkdirSyncMock = vitest_1.vi.fn();
|
|
51
|
+
const existsSyncMock = vitest_1.vi.fn().mockReturnValue(false);
|
|
52
|
+
(0, vitest_1.expect)(() => (0, utils_1.createTempDirectory)(mkdirSyncMock, existsSyncMock)).not.toThrow();
|
|
53
|
+
(0, vitest_1.expect)(mkdirSyncMock).toHaveBeenCalledWith(_1.TEMP_DIRECTORY);
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)("does not throw error when it already exists", () => {
|
|
56
|
+
const mkdirSyncMock = vitest_1.vi.fn().mockImplementation(() => {
|
|
57
|
+
throw new Error("Directory already exists");
|
|
58
|
+
});
|
|
59
|
+
const existsSyncMock = vitest_1.vi.fn().mockReturnValue(true);
|
|
60
|
+
(0, vitest_1.expect)(() => (0, utils_1.createTempDirectory)(mkdirSyncMock, existsSyncMock)).not.toThrow();
|
|
61
|
+
(0, vitest_1.expect)(mkdirSyncMock).not.toHaveBeenCalledWith();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
(0, vitest_1.describe)("toSavedFileName()", () => {
|
|
65
|
+
(0, vitest_1.it)("replaces slashes with double colons", () => {
|
|
66
|
+
(0, vitest_1.expect)((0, utils_1.toSavedFileName)("/hey/there")).toEqual("hey::there");
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
(0, vitest_1.describe)("readFile()", () => {
|
|
70
|
+
(0, vitest_1.it)("reads the file", () => {
|
|
71
|
+
const readFileSyncMock = vitest_1.vi.fn().mockReturnValue("file contents");
|
|
72
|
+
(0, vitest_1.expect)((0, utils_1.readFile)("hey/there", readFileSyncMock)).toEqual("file contents");
|
|
73
|
+
(0, vitest_1.expect)(readFileSyncMock).toHaveBeenCalledWith(`${_1.TEMP_DIRECTORY}/hey::there`, "utf8");
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)("returns null when file doesn't exist", () => {
|
|
76
|
+
const readFileSyncMock = vitest_1.vi.fn().mockImplementation(() => {
|
|
77
|
+
throw new Error("File not found");
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.expect)((0, utils_1.readFile)("hey/there", readFileSyncMock)).toEqual(null);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
(0, vitest_1.describe)("saveFile()", () => {
|
|
83
|
+
(0, vitest_1.it)("saves the file", async () => {
|
|
84
|
+
const writeFileMock = vitest_1.vi.fn();
|
|
85
|
+
const result = (0, utils_1.saveFile)("hey/there", "file contents", writeFileMock);
|
|
86
|
+
(0, vitest_1.expect)(writeFileMock).toHaveBeenCalledWith(`${_1.TEMP_DIRECTORY}/hey::there`, "file contents", vitest_1.expect.any(Function));
|
|
87
|
+
(0, vitest_1.expect)(result).toBeInstanceOf(Promise);
|
|
88
|
+
});
|
|
89
|
+
});
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import path from "path";
|
|
2
|
+
export const TEMP_DIRECTORY = path.join(process.cwd(), "_temp_jc");
|
|
3
|
+
export { markupFetcher, fetchAll } from "./markupFetcher";
|
|
4
|
+
export { reAppendMarkup, deleteTempDirectory } from "./utils";
|
|
3
5
|
export { log, logError } from "./log";
|
|
@@ -1,37 +1,93 @@
|
|
|
1
1
|
import { injectSchema } from "./injectSchema";
|
|
2
|
-
import { getEnvironment, isValidTimezone, parseJson } from "./utils";
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
if (!response.ok) {
|
|
32
|
-
throw new Error(`JamComments request failed! Status code: ${response.status}, message: ${response.statusText}, request URL: ${requestUrl}`);
|
|
2
|
+
import { createTempDirectory, deleteTempDirectory, getEnvironment, isValidTimezone, parseJson, readFile, saveFile, } from "./utils";
|
|
3
|
+
export async function fetchAll({ tz = undefined, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }, platform, fetchImplementation, batchMarkupFetcherImpl = batchMarkupFetcher) {
|
|
4
|
+
const fetchBatchMarkup = batchMarkupFetcherImpl(platform, fetchImplementation);
|
|
5
|
+
createTempDirectory();
|
|
6
|
+
let shouldKeepFetching = true;
|
|
7
|
+
let page = 1;
|
|
8
|
+
console.log("Fetching comments from JamComments! This might take a sec.");
|
|
9
|
+
try {
|
|
10
|
+
while (shouldKeepFetching) {
|
|
11
|
+
const { data: items, meta: { current_page, last_page }, } = await fetchBatchMarkup({
|
|
12
|
+
domain,
|
|
13
|
+
apiKey,
|
|
14
|
+
baseUrl,
|
|
15
|
+
environment,
|
|
16
|
+
page,
|
|
17
|
+
tz,
|
|
18
|
+
});
|
|
19
|
+
console.log(`Checking for comment data. Batch: ${current_page}/${last_page}`);
|
|
20
|
+
const saveMarkupPromises = items.map((item) => {
|
|
21
|
+
return saveFile(item.path, item.markup);
|
|
22
|
+
});
|
|
23
|
+
await Promise.all(saveMarkupPromises);
|
|
24
|
+
if (current_page === last_page) {
|
|
25
|
+
shouldKeepFetching = false;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
page++;
|
|
29
|
+
}
|
|
33
30
|
}
|
|
34
|
-
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
deleteTempDirectory();
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function batchMarkupFetcher(platform, fetchImplementation = fetch) {
|
|
38
|
+
return async ({ tz = undefined, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), page = 1, }) => {
|
|
39
|
+
const response = await makeMarkupRequest({ tz, domain, apiKey, baseUrl, environment, page }, "/api/v3/markup/all", fetchImplementation, platform);
|
|
40
|
+
return response.json();
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export async function fetchFreshMarkup({ tz = undefined, path, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }, fetchImplementation = fetch, platform) {
|
|
44
|
+
const response = await makeMarkupRequest({ tz, path, domain, apiKey, baseUrl, environment }, "/api/v3/markup", fetchImplementation, platform);
|
|
45
|
+
return response.text();
|
|
46
|
+
}
|
|
47
|
+
export async function makeMarkupRequest({ tz = undefined, path = undefined, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), page = undefined, }, baseServicePath, fetchImplementation = fetch, platform) {
|
|
48
|
+
const trimmedTimezone = tz?.trim();
|
|
49
|
+
if (trimmedTimezone && !isValidTimezone(trimmedTimezone)) {
|
|
50
|
+
throw new Error(`The timezone passed to JamComments is invalid: ${trimmedTimezone}`);
|
|
51
|
+
}
|
|
52
|
+
const params = new URLSearchParams({
|
|
53
|
+
domain,
|
|
54
|
+
});
|
|
55
|
+
if (path) {
|
|
56
|
+
params.set("path", path);
|
|
57
|
+
}
|
|
58
|
+
if (page) {
|
|
59
|
+
params.set("page", page.toString());
|
|
60
|
+
}
|
|
61
|
+
if (trimmedTimezone) {
|
|
62
|
+
params.set("tz", trimmedTimezone);
|
|
63
|
+
}
|
|
64
|
+
if (environment !== "production") {
|
|
65
|
+
params.set("stub", "true");
|
|
66
|
+
}
|
|
67
|
+
const requestUrl = `${baseUrl}${baseServicePath}?${params}`;
|
|
68
|
+
const response = await fetchImplementation(requestUrl, {
|
|
69
|
+
method: "GET",
|
|
70
|
+
headers: {
|
|
71
|
+
Authorization: `Bearer ${apiKey}`,
|
|
72
|
+
Accept: "application/json",
|
|
73
|
+
"X-Platform": platform,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
if (response.status === 401) {
|
|
77
|
+
throw new Error(`Unauthorized! Are your domain and JamComments API key set correctly?`);
|
|
78
|
+
}
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw new Error(`JamComments request failed! Status code: ${response.status}, message: ${response.statusText}, request URL: ${requestUrl}`);
|
|
81
|
+
}
|
|
82
|
+
return response;
|
|
83
|
+
}
|
|
84
|
+
export function markupFetcher(platform, fetchImplementation = fetch) {
|
|
85
|
+
return async ({ tz = undefined, path, domain, apiKey, schema, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }) => {
|
|
86
|
+
path = path || "/";
|
|
87
|
+
const savedFile = readFile(path);
|
|
88
|
+
const markup = savedFile
|
|
89
|
+
? savedFile
|
|
90
|
+
: await fetchFreshMarkup({ tz, path, domain, apiKey, baseUrl, environment }, fetchImplementation, platform);
|
|
35
91
|
if (schema) {
|
|
36
92
|
const preparedSchema = typeof schema !== "string" ? JSON.stringify(schema) : schema;
|
|
37
93
|
const parsedSchema = parseJson(preparedSchema);
|
|
@@ -42,4 +98,4 @@ export const markupFetcher = (platform, fetchImplementation = fetch) => {
|
|
|
42
98
|
}
|
|
43
99
|
return markup;
|
|
44
100
|
};
|
|
45
|
-
}
|
|
101
|
+
}
|
|
@@ -1,6 +1,201 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import * as injectSchema from "./injectSchema";
|
|
3
|
-
import
|
|
3
|
+
import * as fetcherExports from "./markupFetcher";
|
|
4
|
+
import { afterEach } from "node:test";
|
|
5
|
+
import * as utilsExports from "./utils";
|
|
6
|
+
const { deleteTempDirectory } = utilsExports;
|
|
7
|
+
const { markupFetcher, batchMarkupFetcher } = fetcherExports;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
deleteTempDirectory();
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
vi.resetAllMocks();
|
|
13
|
+
});
|
|
14
|
+
describe("fetchAll()", () => {
|
|
15
|
+
it("fetches all comments in a single request", async () => {
|
|
16
|
+
const saveFileSpy = vi.spyOn(utilsExports, "saveFile");
|
|
17
|
+
const mockBatchFetcher = vi.fn().mockReturnValue({
|
|
18
|
+
data: [
|
|
19
|
+
{ path: "/test", markup: "markup1" },
|
|
20
|
+
{ path: "/test2", markup: "markup2" },
|
|
21
|
+
],
|
|
22
|
+
meta: {
|
|
23
|
+
current_page: 1,
|
|
24
|
+
from: 1,
|
|
25
|
+
last_page: 1,
|
|
26
|
+
path: "/test",
|
|
27
|
+
per_page: 10,
|
|
28
|
+
to: 2,
|
|
29
|
+
total: 2,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const batchMarkupFetcherMock = vi.fn().mockImplementation((a, b) => {
|
|
33
|
+
return mockBatchFetcher;
|
|
34
|
+
});
|
|
35
|
+
await fetcherExports.fetchAll({
|
|
36
|
+
domain: "test.com",
|
|
37
|
+
apiKey: "123abc",
|
|
38
|
+
environment: "production",
|
|
39
|
+
}, "test_platform", vi.fn(), batchMarkupFetcherMock);
|
|
40
|
+
expect(batchMarkupFetcherMock).toHaveBeenCalledWith("test_platform", expect.anything());
|
|
41
|
+
expect(mockBatchFetcher).toHaveBeenCalledWith({
|
|
42
|
+
domain: "test.com",
|
|
43
|
+
apiKey: "123abc",
|
|
44
|
+
baseUrl: "https://go.jamcomments.com",
|
|
45
|
+
environment: "production",
|
|
46
|
+
page: 1,
|
|
47
|
+
tz: undefined,
|
|
48
|
+
});
|
|
49
|
+
expect(saveFileSpy).toHaveBeenCalledTimes(2);
|
|
50
|
+
expect(saveFileSpy).toHaveBeenCalledWith("/test", "markup1");
|
|
51
|
+
expect(saveFileSpy).toHaveBeenCalledWith("/test2", "markup2");
|
|
52
|
+
});
|
|
53
|
+
it("fetches all comments in multiple requests", async () => {
|
|
54
|
+
const saveFileSpy = vi.spyOn(utilsExports, "saveFile");
|
|
55
|
+
const mockBatchFetcher = vi
|
|
56
|
+
.fn()
|
|
57
|
+
.mockReturnValueOnce({
|
|
58
|
+
data: [
|
|
59
|
+
{ path: "/test", markup: "markup1" },
|
|
60
|
+
{ path: "/test2", markup: "markup2" },
|
|
61
|
+
],
|
|
62
|
+
meta: {
|
|
63
|
+
current_page: 1,
|
|
64
|
+
from: 1,
|
|
65
|
+
last_page: 2,
|
|
66
|
+
path: "/test",
|
|
67
|
+
per_page: 2,
|
|
68
|
+
to: 2,
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
.mockReturnValueOnce({
|
|
72
|
+
data: [
|
|
73
|
+
{ path: "/test3", markup: "markup3" },
|
|
74
|
+
{ path: "/test4", markup: "markup4" },
|
|
75
|
+
],
|
|
76
|
+
meta: {
|
|
77
|
+
current_page: 2,
|
|
78
|
+
from: 3,
|
|
79
|
+
last_page: 2,
|
|
80
|
+
path: "/test",
|
|
81
|
+
per_page: 2,
|
|
82
|
+
to: 4,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
const batchMarkupFetcherMock = vi.fn().mockImplementation((a, b) => {
|
|
86
|
+
return mockBatchFetcher;
|
|
87
|
+
});
|
|
88
|
+
await fetcherExports.fetchAll({
|
|
89
|
+
domain: "test.com",
|
|
90
|
+
apiKey: "123abc",
|
|
91
|
+
environment: "production",
|
|
92
|
+
}, "test_platform", vi.fn(), batchMarkupFetcherMock);
|
|
93
|
+
expect(batchMarkupFetcherMock).toHaveBeenCalledWith("test_platform", expect.anything());
|
|
94
|
+
expect(mockBatchFetcher).toHaveBeenCalledWith({
|
|
95
|
+
domain: "test.com",
|
|
96
|
+
apiKey: "123abc",
|
|
97
|
+
baseUrl: "https://go.jamcomments.com",
|
|
98
|
+
environment: "production",
|
|
99
|
+
page: 1,
|
|
100
|
+
tz: undefined,
|
|
101
|
+
});
|
|
102
|
+
expect(mockBatchFetcher).toHaveBeenCalledTimes(2);
|
|
103
|
+
expect(mockBatchFetcher).toHaveBeenCalledWith({
|
|
104
|
+
domain: "test.com",
|
|
105
|
+
apiKey: "123abc",
|
|
106
|
+
baseUrl: "https://go.jamcomments.com",
|
|
107
|
+
environment: "production",
|
|
108
|
+
page: 2,
|
|
109
|
+
tz: undefined,
|
|
110
|
+
});
|
|
111
|
+
expect(saveFileSpy).toHaveBeenCalledTimes(4);
|
|
112
|
+
expect(saveFileSpy).toHaveBeenCalledWith("/test", "markup1");
|
|
113
|
+
expect(saveFileSpy).toHaveBeenCalledWith("/test2", "markup2");
|
|
114
|
+
});
|
|
115
|
+
it("deletes the temp directory of anything fails", async () => {
|
|
116
|
+
const deleteTempDirectorySpy = vi.spyOn(utilsExports, "deleteTempDirectory");
|
|
117
|
+
const mockBatchFetcher = vi.fn().mockImplementation(() => {
|
|
118
|
+
throw new Error("test error");
|
|
119
|
+
});
|
|
120
|
+
const batchMarkupFetcherMock = vi.fn().mockImplementation((a, b) => {
|
|
121
|
+
return mockBatchFetcher;
|
|
122
|
+
});
|
|
123
|
+
try {
|
|
124
|
+
await fetcherExports.fetchAll({
|
|
125
|
+
domain: "test.com",
|
|
126
|
+
apiKey: "123abc",
|
|
127
|
+
environment: "production",
|
|
128
|
+
}, "test_platform", vi.fn(), batchMarkupFetcherMock);
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
expect(e.message).toEqual("test error");
|
|
132
|
+
}
|
|
133
|
+
expect(deleteTempDirectorySpy).toHaveBeenCalledOnce();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe("batchMarkupFetcher", () => {
|
|
137
|
+
it("constructs fetch request correctly", async () => {
|
|
138
|
+
const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
|
|
139
|
+
const fetchMock = vi.fn().mockImplementation(() => {
|
|
140
|
+
return {
|
|
141
|
+
status: 200,
|
|
142
|
+
ok: true,
|
|
143
|
+
json: () => "results!",
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
const fetcher = batchMarkupFetcher("test", fetchMock);
|
|
147
|
+
const result = await fetcher({
|
|
148
|
+
domain: "test.com",
|
|
149
|
+
apiKey: "123abc",
|
|
150
|
+
environment: "production",
|
|
151
|
+
});
|
|
152
|
+
expect(injectSchemaSpy).not.toHaveBeenCalled();
|
|
153
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup/all?domain=test.com&page=1", expect.objectContaining({
|
|
154
|
+
headers: expect.objectContaining({
|
|
155
|
+
Accept: "application/json",
|
|
156
|
+
Authorization: "Bearer 123abc",
|
|
157
|
+
"X-Platform": "test",
|
|
158
|
+
}),
|
|
159
|
+
method: "GET",
|
|
160
|
+
}));
|
|
161
|
+
expect(result).toEqual("results!");
|
|
162
|
+
});
|
|
163
|
+
it("stubs comments", async () => {
|
|
164
|
+
const fetchMock = vi.fn().mockImplementation(() => {
|
|
165
|
+
return {
|
|
166
|
+
status: 200,
|
|
167
|
+
ok: true,
|
|
168
|
+
json: () => "results!",
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
const fetcher = batchMarkupFetcher("test", fetchMock);
|
|
172
|
+
const result = await fetcher({
|
|
173
|
+
domain: "test.com",
|
|
174
|
+
apiKey: "123abc",
|
|
175
|
+
environment: "development",
|
|
176
|
+
});
|
|
177
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup/all?domain=test.com&page=1&stub=true", expect.anything());
|
|
178
|
+
expect(result).toEqual("results!");
|
|
179
|
+
});
|
|
180
|
+
it("uses different base URL", async () => {
|
|
181
|
+
const fetchMock = vi.fn().mockImplementation(() => {
|
|
182
|
+
return {
|
|
183
|
+
status: 200,
|
|
184
|
+
ok: true,
|
|
185
|
+
json: () => "results!",
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
const fetcher = batchMarkupFetcher("test", fetchMock);
|
|
189
|
+
const result = await fetcher({
|
|
190
|
+
domain: "test.com",
|
|
191
|
+
apiKey: "123abc",
|
|
192
|
+
baseUrl: "http://ur-mom.com",
|
|
193
|
+
environment: "production",
|
|
194
|
+
});
|
|
195
|
+
expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup/all?domain=test.com&page=1", expect.anything());
|
|
196
|
+
expect(result).toEqual("results!");
|
|
197
|
+
});
|
|
198
|
+
});
|
|
4
199
|
describe("markupFetcher", () => {
|
|
5
200
|
it("constructs fetch request correctly", async () => {
|
|
6
201
|
const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
|
|
@@ -19,7 +214,7 @@ describe("markupFetcher", () => {
|
|
|
19
214
|
environment: "production",
|
|
20
215
|
});
|
|
21
216
|
expect(injectSchemaSpy).not.toHaveBeenCalled();
|
|
22
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
217
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.objectContaining({
|
|
23
218
|
headers: expect.objectContaining({
|
|
24
219
|
Accept: "application/json",
|
|
25
220
|
Authorization: "Bearer 123abc",
|
|
@@ -44,7 +239,7 @@ describe("markupFetcher", () => {
|
|
|
44
239
|
apiKey: "123abc",
|
|
45
240
|
environment: "development",
|
|
46
241
|
});
|
|
47
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
242
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest&stub=true", expect.anything());
|
|
48
243
|
expect(result).toEqual("results!");
|
|
49
244
|
});
|
|
50
245
|
it("uses different base URL", async () => {
|
|
@@ -63,7 +258,7 @@ describe("markupFetcher", () => {
|
|
|
63
258
|
baseUrl: "http://ur-mom.com",
|
|
64
259
|
environment: "production",
|
|
65
260
|
});
|
|
66
|
-
expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?
|
|
261
|
+
expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
|
|
67
262
|
expect(result).toEqual("results!");
|
|
68
263
|
});
|
|
69
264
|
it("respects production!!!", async () => {
|
|
@@ -82,7 +277,7 @@ describe("markupFetcher", () => {
|
|
|
82
277
|
baseUrl: "http://ur-mom.com",
|
|
83
278
|
environment: "production",
|
|
84
279
|
});
|
|
85
|
-
expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?
|
|
280
|
+
expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
|
|
86
281
|
expect(result).toEqual("results!");
|
|
87
282
|
});
|
|
88
283
|
it("falls back to root path", async () => {
|
|
@@ -100,7 +295,7 @@ describe("markupFetcher", () => {
|
|
|
100
295
|
apiKey: "123abc",
|
|
101
296
|
environment: "production",
|
|
102
297
|
});
|
|
103
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
298
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2F", expect.anything());
|
|
104
299
|
expect(result).toEqual("results!");
|
|
105
300
|
});
|
|
106
301
|
it("credentials are invalid", async () => {
|
|
@@ -135,9 +330,9 @@ describe("markupFetcher", () => {
|
|
|
135
330
|
});
|
|
136
331
|
describe("timezone validation", () => {
|
|
137
332
|
it("throws error when invalid timezone is provided", async () => {
|
|
138
|
-
const
|
|
139
|
-
const fetcher = markupFetcher("test",
|
|
140
|
-
expect(
|
|
333
|
+
const fetchImplMock = vi.fn();
|
|
334
|
+
const fetcher = markupFetcher("test", fetchImplMock);
|
|
335
|
+
expect(fetchImplMock).not.toHaveBeenCalled();
|
|
141
336
|
expect(fetcher({
|
|
142
337
|
path: "/test",
|
|
143
338
|
domain: "test.com",
|
|
@@ -156,13 +351,13 @@ describe("markupFetcher", () => {
|
|
|
156
351
|
});
|
|
157
352
|
const fetcher = markupFetcher("test", fetchMock);
|
|
158
353
|
const result = await fetcher({
|
|
159
|
-
path:
|
|
354
|
+
path: "/some/path",
|
|
160
355
|
domain: "test.com",
|
|
161
356
|
apiKey: "123abc",
|
|
162
357
|
tz: "America/New_York",
|
|
163
358
|
environment: "production",
|
|
164
359
|
});
|
|
165
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
360
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Fsome%2Fpath&tz=America%2FNew_York", expect.anything());
|
|
166
361
|
expect(result).toEqual("results!");
|
|
167
362
|
});
|
|
168
363
|
it("trims a valid timezone", async () => {
|
|
@@ -175,13 +370,13 @@ describe("markupFetcher", () => {
|
|
|
175
370
|
});
|
|
176
371
|
const fetcher = markupFetcher("test", fetchMock);
|
|
177
372
|
const result = await fetcher({
|
|
178
|
-
path:
|
|
373
|
+
path: "/some/path",
|
|
179
374
|
domain: "test.com",
|
|
180
375
|
apiKey: "123abc",
|
|
181
376
|
tz: " America/Chicago ",
|
|
182
377
|
environment: "production",
|
|
183
378
|
});
|
|
184
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
379
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Fsome%2Fpath&tz=America%2FChicago", expect.anything());
|
|
185
380
|
expect(result).toEqual("results!");
|
|
186
381
|
});
|
|
187
382
|
});
|
|
@@ -205,7 +400,7 @@ describe("passing schema", function () {
|
|
|
205
400
|
environment: "production",
|
|
206
401
|
});
|
|
207
402
|
expect(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
|
|
208
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
403
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
|
|
209
404
|
expect(result).toEqual("results!");
|
|
210
405
|
});
|
|
211
406
|
it("does not stringify schema if given a string", async () => {
|
|
@@ -226,7 +421,7 @@ describe("passing schema", function () {
|
|
|
226
421
|
environment: "production",
|
|
227
422
|
});
|
|
228
423
|
expect(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
|
|
229
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
424
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
|
|
230
425
|
expect(result).toEqual("results!");
|
|
231
426
|
});
|
|
232
427
|
it("returns markup if invalid json is provided", async () => {
|
|
@@ -247,7 +442,7 @@ describe("passing schema", function () {
|
|
|
247
442
|
environment: "production",
|
|
248
443
|
});
|
|
249
444
|
expect(injectSchemaSpy).not.toHaveBeenCalled();
|
|
250
|
-
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?
|
|
445
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
|
|
251
446
|
expect(result).toEqual("results!");
|
|
252
447
|
});
|
|
253
448
|
});
|
package/dist/esm/utils.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmdirSync, writeFile } from "fs";
|
|
2
|
+
import { TEMP_DIRECTORY } from ".";
|
|
1
3
|
export function isValidTimezone(tz) {
|
|
2
4
|
try {
|
|
3
5
|
Intl.DateTimeFormat(undefined, { timeZone: tz });
|
|
@@ -30,21 +32,21 @@ export function parseJson(json) {
|
|
|
30
32
|
return null;
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
|
-
var htmlEntities = {
|
|
34
|
-
nbsp: " ",
|
|
35
|
-
cent: "¢",
|
|
36
|
-
pound: "£",
|
|
37
|
-
yen: "¥",
|
|
38
|
-
euro: "€",
|
|
39
|
-
copy: "©",
|
|
40
|
-
reg: "®",
|
|
41
|
-
lt: "<",
|
|
42
|
-
gt: ">",
|
|
43
|
-
quot: '"',
|
|
44
|
-
amp: "&",
|
|
45
|
-
apos: "'",
|
|
46
|
-
};
|
|
47
35
|
export function unescapeHTML(str) {
|
|
36
|
+
var htmlEntities = {
|
|
37
|
+
nbsp: " ",
|
|
38
|
+
cent: "¢",
|
|
39
|
+
pound: "£",
|
|
40
|
+
yen: "¥",
|
|
41
|
+
euro: "€",
|
|
42
|
+
copy: "©",
|
|
43
|
+
reg: "®",
|
|
44
|
+
lt: "<",
|
|
45
|
+
gt: ">",
|
|
46
|
+
quot: '"',
|
|
47
|
+
amp: "&",
|
|
48
|
+
apos: "'",
|
|
49
|
+
};
|
|
48
50
|
return str.replace(/\&([^;]+);/g, function (entity, entityCode) {
|
|
49
51
|
var match;
|
|
50
52
|
if (entityCode in htmlEntities) {
|
|
@@ -61,3 +63,33 @@ export function unescapeHTML(str) {
|
|
|
61
63
|
}
|
|
62
64
|
});
|
|
63
65
|
}
|
|
66
|
+
export function deleteTempDirectory() {
|
|
67
|
+
if (existsSync(TEMP_DIRECTORY)) {
|
|
68
|
+
rmdirSync(TEMP_DIRECTORY, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export function createTempDirectory(mkdirSyncImpl = mkdirSync, existsSyncImpl = existsSync) {
|
|
72
|
+
if (!existsSyncImpl(TEMP_DIRECTORY)) {
|
|
73
|
+
mkdirSyncImpl(TEMP_DIRECTORY);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function toSavedFileName(name) {
|
|
77
|
+
return name.replace(/^\//, "").replace(/\//g, "::");
|
|
78
|
+
}
|
|
79
|
+
export function readFile(name, readFileSyncImpl = readFileSync) {
|
|
80
|
+
const fileName = toSavedFileName(name);
|
|
81
|
+
try {
|
|
82
|
+
return readFileSyncImpl(`${TEMP_DIRECTORY}/${fileName}`, "utf8");
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function saveFile(name, data, writeFileImpl = writeFile) {
|
|
89
|
+
const fileName = toSavedFileName(name);
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
writeFileImpl(`${TEMP_DIRECTORY}/${fileName}`, data, () => {
|
|
92
|
+
resolve();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
package/dist/esm/utils.test.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { getEnvironment } from "./utils";
|
|
2
|
+
import { getEnvironment, createTempDirectory, toSavedFileName, readFile, saveFile, } from "./utils";
|
|
3
|
+
import { TEMP_DIRECTORY } from ".";
|
|
3
4
|
const env = process.env;
|
|
4
5
|
beforeEach(() => {
|
|
5
6
|
vi.resetModules();
|
|
@@ -42,3 +43,45 @@ describe("getEnvironment()", () => {
|
|
|
42
43
|
});
|
|
43
44
|
});
|
|
44
45
|
});
|
|
46
|
+
describe("createTempDirectory()", () => {
|
|
47
|
+
it("creates temp directory fresh", () => {
|
|
48
|
+
const mkdirSyncMock = vi.fn();
|
|
49
|
+
const existsSyncMock = vi.fn().mockReturnValue(false);
|
|
50
|
+
expect(() => createTempDirectory(mkdirSyncMock, existsSyncMock)).not.toThrow();
|
|
51
|
+
expect(mkdirSyncMock).toHaveBeenCalledWith(TEMP_DIRECTORY);
|
|
52
|
+
});
|
|
53
|
+
it("does not throw error when it already exists", () => {
|
|
54
|
+
const mkdirSyncMock = vi.fn().mockImplementation(() => {
|
|
55
|
+
throw new Error("Directory already exists");
|
|
56
|
+
});
|
|
57
|
+
const existsSyncMock = vi.fn().mockReturnValue(true);
|
|
58
|
+
expect(() => createTempDirectory(mkdirSyncMock, existsSyncMock)).not.toThrow();
|
|
59
|
+
expect(mkdirSyncMock).not.toHaveBeenCalledWith();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe("toSavedFileName()", () => {
|
|
63
|
+
it("replaces slashes with double colons", () => {
|
|
64
|
+
expect(toSavedFileName("/hey/there")).toEqual("hey::there");
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe("readFile()", () => {
|
|
68
|
+
it("reads the file", () => {
|
|
69
|
+
const readFileSyncMock = vi.fn().mockReturnValue("file contents");
|
|
70
|
+
expect(readFile("hey/there", readFileSyncMock)).toEqual("file contents");
|
|
71
|
+
expect(readFileSyncMock).toHaveBeenCalledWith(`${TEMP_DIRECTORY}/hey::there`, "utf8");
|
|
72
|
+
});
|
|
73
|
+
it("returns null when file doesn't exist", () => {
|
|
74
|
+
const readFileSyncMock = vi.fn().mockImplementation(() => {
|
|
75
|
+
throw new Error("File not found");
|
|
76
|
+
});
|
|
77
|
+
expect(readFile("hey/there", readFileSyncMock)).toEqual(null);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("saveFile()", () => {
|
|
81
|
+
it("saves the file", async () => {
|
|
82
|
+
const writeFileMock = vi.fn();
|
|
83
|
+
const result = saveFile("hey/there", "file contents", writeFileMock);
|
|
84
|
+
expect(writeFileMock).toHaveBeenCalledWith(`${TEMP_DIRECTORY}/hey::there`, "file contents", expect.any(Function));
|
|
85
|
+
expect(result).toBeInstanceOf(Promise);
|
|
86
|
+
});
|
|
87
|
+
});
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export {
|
|
1
|
+
export declare const TEMP_DIRECTORY: string;
|
|
2
|
+
export { markupFetcher, fetchAll } from "./markupFetcher";
|
|
3
|
+
export { reAppendMarkup, deleteTempDirectory } from "./utils";
|
|
3
4
|
export { log, logError } from "./log";
|