@monok/server 1.3.0 → 1.5.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/AGENTS.md +442 -0
- package/README.md +107 -16
- package/dist/affiliate.d.ts +15 -0
- package/dist/affiliate.d.ts.map +1 -0
- package/dist/affiliate.js +96 -0
- package/dist/affiliate.js.map +1 -0
- package/dist/client.d.ts +8 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +38 -6
- package/dist/client.js.map +1 -1
- package/dist/express.d.ts.map +1 -1
- package/dist/express.js +115 -15
- package/dist/express.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +98 -15
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +40 -4
- package/dist/utils.js.map +1 -1
- package/dist-cjs/affiliate.js +96 -0
- package/dist-cjs/affiliate.js.map +1 -0
- package/dist-cjs/client.js +38 -6
- package/dist-cjs/client.js.map +1 -1
- package/dist-cjs/express.js +115 -15
- package/dist-cjs/express.js.map +1 -1
- package/dist-cjs/index.js +1 -0
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/utils.js +40 -4
- package/dist-cjs/utils.js.map +1 -1
- package/package.json +5 -2
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
|
+
const DEFAULT_MAX_IMAGE_BYTES = 15 * 1024 * 1024;
|
|
4
5
|
export function timingSafeEqual(a, b) {
|
|
5
6
|
const abuf = Buffer.from(a);
|
|
6
7
|
const bbuf = Buffer.from(b);
|
|
@@ -9,24 +10,59 @@ export function timingSafeEqual(a, b) {
|
|
|
9
10
|
return crypto.timingSafeEqual(abuf, bbuf);
|
|
10
11
|
}
|
|
11
12
|
export function assertApiKey(headerValue, expected) {
|
|
12
|
-
|
|
13
|
+
const candidate = headerValue?.trim();
|
|
14
|
+
const configured = expected.trim();
|
|
15
|
+
if (!candidate || !configured || !timingSafeEqual(candidate, configured)) {
|
|
13
16
|
const err = new Error("Unauthorized");
|
|
14
17
|
// @ts-expect-error custom status
|
|
15
18
|
err.status = 401;
|
|
16
19
|
throw err;
|
|
17
20
|
}
|
|
18
21
|
}
|
|
19
|
-
export function makeThumbSaver(imageDir) {
|
|
22
|
+
export function makeThumbSaver(imageDir, maxImageBytes = DEFAULT_MAX_IMAGE_BYTES) {
|
|
20
23
|
return async (base, data) => {
|
|
21
24
|
if (!imageDir || !data)
|
|
22
25
|
return undefined;
|
|
23
|
-
|
|
26
|
+
if (!Number.isSafeInteger(maxImageBytes) || maxImageBytes <= 0) {
|
|
27
|
+
throw httpError(500, "maxImageBytes must be a positive safe integer");
|
|
28
|
+
}
|
|
29
|
+
const encoded = normalizeJpegBase64(data);
|
|
30
|
+
const estimatedBytes = Math.floor((encoded.length * 3) / 4);
|
|
31
|
+
if (estimatedBytes > maxImageBytes) {
|
|
32
|
+
throw httpError(413, `Thumbnail exceeds the ${maxImageBytes}-byte limit`);
|
|
33
|
+
}
|
|
34
|
+
const bytes = Buffer.from(encoded, "base64");
|
|
35
|
+
if (bytes.length === 0 || bytes.length > maxImageBytes) {
|
|
36
|
+
throw httpError(413, `Thumbnail exceeds the ${maxImageBytes}-byte limit`);
|
|
37
|
+
}
|
|
38
|
+
if (bytes.length < 3 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes[2] !== 0xff) {
|
|
39
|
+
throw httpError(400, "thumbImageData is not a valid JPEG image");
|
|
40
|
+
}
|
|
24
41
|
const safeName = (base || crypto.randomUUID()).replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
25
|
-
const fileName = `${safeName}.
|
|
42
|
+
const fileName = `${safeName}.jpg`;
|
|
26
43
|
await fs.mkdir(imageDir, { recursive: true });
|
|
27
44
|
const full = path.join(imageDir, fileName);
|
|
28
45
|
await fs.writeFile(full, bytes);
|
|
29
46
|
return full;
|
|
30
47
|
};
|
|
31
48
|
}
|
|
49
|
+
function normalizeJpegBase64(data) {
|
|
50
|
+
const trimmed = data.trim();
|
|
51
|
+
const dataUrl = /^data:image\/(?:jpeg|jpg);base64,/i;
|
|
52
|
+
if (/^data:/i.test(trimmed) && !dataUrl.test(trimmed)) {
|
|
53
|
+
throw httpError(400, "thumbImageData must be a JPEG data URL");
|
|
54
|
+
}
|
|
55
|
+
const encoded = trimmed.replace(dataUrl, "").replace(/\s+/g, "");
|
|
56
|
+
if (encoded.length === 0
|
|
57
|
+
|| encoded.length % 4 === 1
|
|
58
|
+
|| !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {
|
|
59
|
+
throw httpError(400, "thumbImageData is not valid base64");
|
|
60
|
+
}
|
|
61
|
+
return encoded;
|
|
62
|
+
}
|
|
63
|
+
function httpError(status, message) {
|
|
64
|
+
const error = new Error(message);
|
|
65
|
+
error.status = status;
|
|
66
|
+
return error;
|
|
67
|
+
}
|
|
32
68
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,aAAa,CAAC;AAE7B,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,CAAS;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAA+B,EAAE,QAAgB;IAC5E,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const DEFAULT_QUERY_PARAMETER = "monok_ref";
|
|
2
|
+
const DEFAULT_COOKIE_NAME = "monok_ref";
|
|
3
|
+
const MAX_TOKEN_LENGTH = 4096;
|
|
4
|
+
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
5
|
+
const MAX_ATTRIBUTION_WINDOW_DAYS = 365;
|
|
6
|
+
const TOKEN_PATTERN = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;
|
|
7
|
+
function validToken(value) {
|
|
8
|
+
return typeof value === "string" &&
|
|
9
|
+
value.length > 0 &&
|
|
10
|
+
value.length <= MAX_TOKEN_LENGTH &&
|
|
11
|
+
TOKEN_PATTERN.test(value);
|
|
12
|
+
}
|
|
13
|
+
function readAttribution(value, nowMs = Date.now()) {
|
|
14
|
+
if (!validToken(value))
|
|
15
|
+
return undefined;
|
|
16
|
+
try {
|
|
17
|
+
const [encodedPayload] = value.split(".");
|
|
18
|
+
const payload = JSON.parse(Buffer.from(encodedPayload, "base64url").toString("utf8"));
|
|
19
|
+
if (payload.version !== 1 ||
|
|
20
|
+
typeof payload.issuedAt !== "number" || !Number.isInteger(payload.issuedAt) ||
|
|
21
|
+
typeof payload.expiresAt !== "number" || !Number.isInteger(payload.expiresAt)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const lifetimeMs = (payload.expiresAt - payload.issuedAt) * 1000;
|
|
25
|
+
const maxAgeMs = payload.expiresAt * 1000 - nowMs;
|
|
26
|
+
if (lifetimeMs < MILLISECONDS_PER_DAY ||
|
|
27
|
+
lifetimeMs > MAX_ATTRIBUTION_WINDOW_DAYS * MILLISECONDS_PER_DAY ||
|
|
28
|
+
lifetimeMs % MILLISECONDS_PER_DAY !== 0 ||
|
|
29
|
+
payload.issuedAt * 1000 > nowMs + 60000 ||
|
|
30
|
+
maxAgeMs <= 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return { token: value, maxAgeMs };
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function readCookie(req, cookieName) {
|
|
40
|
+
const header = req.headers.cookie;
|
|
41
|
+
if (!header)
|
|
42
|
+
return undefined;
|
|
43
|
+
for (const part of header.split(";")) {
|
|
44
|
+
const separator = part.indexOf("=");
|
|
45
|
+
if (separator < 0 || part.slice(0, separator).trim() !== cookieName)
|
|
46
|
+
continue;
|
|
47
|
+
try {
|
|
48
|
+
const value = decodeURIComponent(part.slice(separator + 1).trim());
|
|
49
|
+
return readAttribution(value);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Preserve Monok's signed redirect token in an HttpOnly cookie and expose it as
|
|
59
|
+
* `req.monokAttribution`. This does not expose any content-receiving endpoint.
|
|
60
|
+
*/
|
|
61
|
+
export function monokAffiliateAttribution(options = {}) {
|
|
62
|
+
const queryParameter = options.queryParameter ?? DEFAULT_QUERY_PARAMETER;
|
|
63
|
+
const cookieName = options.cookieName ?? DEFAULT_COOKIE_NAME;
|
|
64
|
+
if (!queryParameter || !cookieName) {
|
|
65
|
+
throw new Error("Affiliate query parameter and cookie name cannot be empty");
|
|
66
|
+
}
|
|
67
|
+
return (req, res, next) => {
|
|
68
|
+
const queryToken = req.query[queryParameter];
|
|
69
|
+
const queryAttribution = readAttribution(queryToken);
|
|
70
|
+
const attribution = queryAttribution
|
|
71
|
+
? queryAttribution
|
|
72
|
+
: readCookie(req, cookieName);
|
|
73
|
+
if (attribution)
|
|
74
|
+
req.monokAttribution = attribution.token;
|
|
75
|
+
if (queryAttribution) {
|
|
76
|
+
res.cookie(cookieName, queryAttribution.token, {
|
|
77
|
+
httpOnly: true,
|
|
78
|
+
secure: options.secure ?? true,
|
|
79
|
+
sameSite: "lax",
|
|
80
|
+
path: "/",
|
|
81
|
+
maxAge: queryAttribution.maxAgeMs,
|
|
82
|
+
...(options.cookieDomain ? { domain: options.cookieDomain } : {})
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (validToken(queryToken)) {
|
|
86
|
+
if (options.cleanUrl ?? true) {
|
|
87
|
+
const cleanUrl = new URL(req.originalUrl, "http://monok.local");
|
|
88
|
+
cleanUrl.searchParams.delete(queryParameter);
|
|
89
|
+
res.redirect(302, cleanUrl.pathname + cleanUrl.search);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
next();
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=affiliate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"affiliate.js","sourceRoot":"","sources":["../src/affiliate.ts"],"names":[],"mappings":"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"}
|
package/dist-cjs/client.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import fetch from "node-fetch";
|
|
2
|
+
export const DEFAULT_MONOK_BASE_URL = "https://app.monok.com";
|
|
2
3
|
/**
|
|
3
4
|
* Send a linkback to Monok after you publish the article.
|
|
4
5
|
*/
|
|
5
|
-
export async function sendMonokLinkback({ monokId,
|
|
6
|
-
const endpoint = (opts?.monokBaseUrl ??
|
|
6
|
+
export async function sendMonokLinkback({ monokId, externalId, url, title, thumbnailUrl }, opts) {
|
|
7
|
+
const endpoint = (opts?.monokBaseUrl ?? DEFAULT_MONOK_BASE_URL) + "/api/v1/linkback";
|
|
7
8
|
const payload = {
|
|
8
|
-
puff: { title
|
|
9
|
+
puff: { title },
|
|
9
10
|
id: monokId,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
...(externalId !== undefined && externalId !== null
|
|
12
|
+
? { externalId: String(externalId) }
|
|
13
|
+
: {}),
|
|
14
|
+
url,
|
|
15
|
+
source: new URL(url).hostname,
|
|
13
16
|
...(thumbnailUrl ? { thumbnail: thumbnailUrl } : {})
|
|
14
17
|
};
|
|
15
18
|
const resp = await fetch(endpoint, {
|
|
@@ -25,4 +28,33 @@ export async function sendMonokLinkback({ monokId, publicUrl, title, articleText
|
|
|
25
28
|
throw new Error(`Monok linkback failed: ${resp.status} ${text}`);
|
|
26
29
|
}
|
|
27
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Register a newly created merchant customer against a signed attribution token.
|
|
33
|
+
* Repeating the same offer/customer pair is safe and returns the existing referral.
|
|
34
|
+
*/
|
|
35
|
+
export async function createMonokReferral({ attributionToken, customerReference }, { apiKey, monokBaseUrl = DEFAULT_MONOK_BASE_URL }) {
|
|
36
|
+
if (!apiKey.trim())
|
|
37
|
+
throw new Error("A Monok API key is required");
|
|
38
|
+
if (!attributionToken.trim())
|
|
39
|
+
throw new Error("An attribution token is required");
|
|
40
|
+
if (!customerReference.trim())
|
|
41
|
+
throw new Error("A customer reference is required");
|
|
42
|
+
const endpoint = monokBaseUrl.replace(/\/$/, "") + "/api/v1/affiliate/referrals";
|
|
43
|
+
const resp = await fetch(endpoint, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
"X-API-Key": apiKey
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
attributionToken,
|
|
51
|
+
customerReference
|
|
52
|
+
})
|
|
53
|
+
});
|
|
54
|
+
if (!resp.ok) {
|
|
55
|
+
const text = await resp.text().catch(() => "");
|
|
56
|
+
throw new Error(`Monok referral registration failed: ${resp.status} ${text}`);
|
|
57
|
+
}
|
|
58
|
+
return await resp.json();
|
|
59
|
+
}
|
|
28
60
|
//# sourceMappingURL=client.js.map
|
package/dist-cjs/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAQ/B,MAAM,CAAC,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;AAE9D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAmB,EAClE,IAAiD;IAEjD,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,YAAY,IAAI,sBAAsB,CAAC,GAAG,kBAAkB,CAAC;IACrF,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,EAAE,KAAK,EAAE;QACf,EAAE,EAAE,OAAO;QACX,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,IAAI;YACjD,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE;YACpC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG;QACH,MAAM,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ;QAC7B,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QACjC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAE,gBAAgB,EAAE,iBAAiB,EAA8B,EACnE,EAAE,MAAM,EAAE,YAAY,GAAG,sBAAsB,EAA+B;IAE9E,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACnE,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAClF,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAEnF,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,6BAA6B,CAAC;IACjF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QACjC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,WAAW,EAAE,MAAM;SACpB;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,gBAAgB;YAChB,iBAAiB;SAClB,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,MAAM,IAAI,CAAC,IAAI,EAAyB,CAAC;AAClD,CAAC"}
|
package/dist-cjs/express.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Router, json } from "express";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
2
3
|
import { assertApiKey, makeThumbSaver } from "./utils.js";
|
|
4
|
+
const PACKAGE_VERSION = readPackageVersion();
|
|
3
5
|
export function createMonokRouter(opts) {
|
|
4
6
|
const r = Router();
|
|
5
7
|
const base = opts.basePath ?? "";
|
|
@@ -7,34 +9,132 @@ export function createMonokRouter(opts) {
|
|
|
7
9
|
r.use(json({ limit: "20mb" }));
|
|
8
10
|
// POST /push
|
|
9
11
|
r.post(base + "/push", wrap(async (req, res) => {
|
|
10
|
-
|
|
12
|
+
assertRequestApiKey(req, opts.apiKey, true);
|
|
11
13
|
const body = req.body;
|
|
12
|
-
if (
|
|
14
|
+
if (body?.id === undefined
|
|
15
|
+
|| body.id === null
|
|
16
|
+
|| (typeof body.id === "string" && body.id.trim() === "")
|
|
17
|
+
|| typeof body.title !== "string"
|
|
18
|
+
|| body.title.trim() === "") {
|
|
13
19
|
return res.status(400).json({ error: "Invalid payload" });
|
|
14
20
|
}
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
const
|
|
21
|
+
// Monok's API integration sends action in the body. Retain query support
|
|
22
|
+
// for older callers and give an explicit query value precedence.
|
|
23
|
+
const action = parseAction(firstQueryValue(req.query.action) ?? body.action);
|
|
24
|
+
const saver = makeThumbSaver(opts.imageDir, opts.maxImageBytes);
|
|
18
25
|
await Promise.resolve(opts.onArticle(body, {
|
|
19
|
-
saveThumbImage: async (fileNameBase) => saver(fileNameBase ?? body.slug ?? body.id, body.thumbImageData),
|
|
26
|
+
saveThumbImage: async (fileNameBase) => saver(fileNameBase ?? body.slug ?? String(body.id), body.thumbImageData),
|
|
20
27
|
action
|
|
21
28
|
}));
|
|
22
|
-
res.json({ ok: true, monokId: body.id });
|
|
29
|
+
res.json({ ok: true, status: "accepted", monokId: body.id });
|
|
23
30
|
}));
|
|
24
31
|
// GET /info
|
|
25
32
|
r.get(base + "/info", wrap(async (req, res) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
setPrivateNoCacheHeaders(res);
|
|
34
|
+
assertRequestApiKey(req, opts.apiKey);
|
|
35
|
+
const configuredInfo = !opts.getSiteInfo
|
|
36
|
+
? undefined
|
|
37
|
+
: typeof opts.getSiteInfo === "function"
|
|
38
|
+
? await Promise.resolve(opts.getSiteInfo())
|
|
39
|
+
: opts.getSiteInfo;
|
|
40
|
+
const info = configuredInfo
|
|
41
|
+
? { ...configuredInfo, version: PACKAGE_VERSION }
|
|
42
|
+
: defaultSiteInfo();
|
|
34
43
|
res.json(info);
|
|
35
44
|
}));
|
|
45
|
+
// GET /postfilter
|
|
46
|
+
r.get(base + "/postfilter", wrap(async (req, res) => {
|
|
47
|
+
setPrivateNoCacheHeaders(res);
|
|
48
|
+
if (!opts.searchArticles) {
|
|
49
|
+
return res.status(404).json({ error: "Article search not configured" });
|
|
50
|
+
}
|
|
51
|
+
assertRequestApiKey(req, opts.apiKey);
|
|
52
|
+
const amount = parsePositiveInteger(firstQueryValue(req.query.amount), 10, "amount");
|
|
53
|
+
const page = parsePositiveInteger(firstQueryValue(req.query.page), 1, "page");
|
|
54
|
+
const query = {
|
|
55
|
+
postType: firstQueryValue(req.query.post_type)?.trim() || "post",
|
|
56
|
+
amount,
|
|
57
|
+
page,
|
|
58
|
+
...optionalTrimmed("section", firstQueryValue(req.query.section)),
|
|
59
|
+
...optionalTrimmed("tag", firstQueryValue(req.query.tag)),
|
|
60
|
+
...optionalTrimmed("query", firstQueryValue(req.query.q))
|
|
61
|
+
};
|
|
62
|
+
const articles = await Promise.resolve(opts.searchArticles(query));
|
|
63
|
+
if (!Array.isArray(articles)) {
|
|
64
|
+
throw httpError(500, "searchArticles must return an array");
|
|
65
|
+
}
|
|
66
|
+
res.json(articles);
|
|
67
|
+
}));
|
|
36
68
|
return r;
|
|
37
69
|
}
|
|
70
|
+
function assertRequestApiKey(req, expected, allowToken = false) {
|
|
71
|
+
const provided = ((allowToken ? req.header("token") : undefined)
|
|
72
|
+
?? req.header("x-api-key")
|
|
73
|
+
?? firstQueryValue(req.query.apikey));
|
|
74
|
+
assertApiKey(provided, expected);
|
|
75
|
+
}
|
|
76
|
+
function parseAction(value) {
|
|
77
|
+
if (value === undefined || value === null || value === "")
|
|
78
|
+
return undefined;
|
|
79
|
+
if (value === "draft" || value === "publish")
|
|
80
|
+
return value;
|
|
81
|
+
throw httpError(400, "action must be either draft or publish");
|
|
82
|
+
}
|
|
83
|
+
function parsePositiveInteger(value, fallback, name) {
|
|
84
|
+
if (value === undefined || value === "")
|
|
85
|
+
return fallback;
|
|
86
|
+
if (!/^\d+$/.test(value))
|
|
87
|
+
throw httpError(400, `${name} must be a positive integer`);
|
|
88
|
+
const parsed = Number(value);
|
|
89
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1) {
|
|
90
|
+
throw httpError(400, `${name} must be a positive integer`);
|
|
91
|
+
}
|
|
92
|
+
return parsed;
|
|
93
|
+
}
|
|
94
|
+
function firstQueryValue(value) {
|
|
95
|
+
if (typeof value === "string")
|
|
96
|
+
return value;
|
|
97
|
+
if (Array.isArray(value) && typeof value[0] === "string")
|
|
98
|
+
return value[0];
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
function optionalTrimmed(key, value) {
|
|
102
|
+
const trimmed = value?.trim();
|
|
103
|
+
return trimmed ? { [key]: trimmed } : {};
|
|
104
|
+
}
|
|
105
|
+
function setPrivateNoCacheHeaders(res) {
|
|
106
|
+
res.set({
|
|
107
|
+
"Cache-Control": "no-store, no-cache, must-revalidate, max-age=0, private",
|
|
108
|
+
"Pragma": "no-cache",
|
|
109
|
+
"Expires": "0",
|
|
110
|
+
"Surrogate-Control": "no-store",
|
|
111
|
+
"Vary": "Accept-Encoding"
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function defaultSiteInfo() {
|
|
115
|
+
return {
|
|
116
|
+
js_scripts: "Disabled",
|
|
117
|
+
version: PACKAGE_VERSION,
|
|
118
|
+
name: "Custom CMS",
|
|
119
|
+
logo: "",
|
|
120
|
+
categories: [],
|
|
121
|
+
post_types: ["post"],
|
|
122
|
+
tags: [],
|
|
123
|
+
authors: []
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function readPackageVersion() {
|
|
127
|
+
const packageJson = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
128
|
+
if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
|
|
129
|
+
throw new Error("@monok/server package version is missing");
|
|
130
|
+
}
|
|
131
|
+
return packageJson.version;
|
|
132
|
+
}
|
|
133
|
+
function httpError(status, message) {
|
|
134
|
+
const error = new Error(message);
|
|
135
|
+
error.status = status;
|
|
136
|
+
return error;
|
|
137
|
+
}
|
|
38
138
|
function wrap(fn) {
|
|
39
139
|
return (req, res, next) => fn(req, res, next).catch((err) => {
|
|
40
140
|
const status = typeof err?.status === "number" ? err.status : 500;
|
package/dist-cjs/express.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAkD,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"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"}
|
package/dist-cjs/index.js
CHANGED
package/dist-cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
|
package/dist-cjs/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
|
+
const DEFAULT_MAX_IMAGE_BYTES = 15 * 1024 * 1024;
|
|
4
5
|
export function timingSafeEqual(a, b) {
|
|
5
6
|
const abuf = Buffer.from(a);
|
|
6
7
|
const bbuf = Buffer.from(b);
|
|
@@ -9,24 +10,59 @@ export function timingSafeEqual(a, b) {
|
|
|
9
10
|
return crypto.timingSafeEqual(abuf, bbuf);
|
|
10
11
|
}
|
|
11
12
|
export function assertApiKey(headerValue, expected) {
|
|
12
|
-
|
|
13
|
+
const candidate = headerValue?.trim();
|
|
14
|
+
const configured = expected.trim();
|
|
15
|
+
if (!candidate || !configured || !timingSafeEqual(candidate, configured)) {
|
|
13
16
|
const err = new Error("Unauthorized");
|
|
14
17
|
// @ts-expect-error custom status
|
|
15
18
|
err.status = 401;
|
|
16
19
|
throw err;
|
|
17
20
|
}
|
|
18
21
|
}
|
|
19
|
-
export function makeThumbSaver(imageDir) {
|
|
22
|
+
export function makeThumbSaver(imageDir, maxImageBytes = DEFAULT_MAX_IMAGE_BYTES) {
|
|
20
23
|
return async (base, data) => {
|
|
21
24
|
if (!imageDir || !data)
|
|
22
25
|
return undefined;
|
|
23
|
-
|
|
26
|
+
if (!Number.isSafeInteger(maxImageBytes) || maxImageBytes <= 0) {
|
|
27
|
+
throw httpError(500, "maxImageBytes must be a positive safe integer");
|
|
28
|
+
}
|
|
29
|
+
const encoded = normalizeJpegBase64(data);
|
|
30
|
+
const estimatedBytes = Math.floor((encoded.length * 3) / 4);
|
|
31
|
+
if (estimatedBytes > maxImageBytes) {
|
|
32
|
+
throw httpError(413, `Thumbnail exceeds the ${maxImageBytes}-byte limit`);
|
|
33
|
+
}
|
|
34
|
+
const bytes = Buffer.from(encoded, "base64");
|
|
35
|
+
if (bytes.length === 0 || bytes.length > maxImageBytes) {
|
|
36
|
+
throw httpError(413, `Thumbnail exceeds the ${maxImageBytes}-byte limit`);
|
|
37
|
+
}
|
|
38
|
+
if (bytes.length < 3 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes[2] !== 0xff) {
|
|
39
|
+
throw httpError(400, "thumbImageData is not a valid JPEG image");
|
|
40
|
+
}
|
|
24
41
|
const safeName = (base || crypto.randomUUID()).replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
25
|
-
const fileName = `${safeName}.
|
|
42
|
+
const fileName = `${safeName}.jpg`;
|
|
26
43
|
await fs.mkdir(imageDir, { recursive: true });
|
|
27
44
|
const full = path.join(imageDir, fileName);
|
|
28
45
|
await fs.writeFile(full, bytes);
|
|
29
46
|
return full;
|
|
30
47
|
};
|
|
31
48
|
}
|
|
49
|
+
function normalizeJpegBase64(data) {
|
|
50
|
+
const trimmed = data.trim();
|
|
51
|
+
const dataUrl = /^data:image\/(?:jpeg|jpg);base64,/i;
|
|
52
|
+
if (/^data:/i.test(trimmed) && !dataUrl.test(trimmed)) {
|
|
53
|
+
throw httpError(400, "thumbImageData must be a JPEG data URL");
|
|
54
|
+
}
|
|
55
|
+
const encoded = trimmed.replace(dataUrl, "").replace(/\s+/g, "");
|
|
56
|
+
if (encoded.length === 0
|
|
57
|
+
|| encoded.length % 4 === 1
|
|
58
|
+
|| !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {
|
|
59
|
+
throw httpError(400, "thumbImageData is not valid base64");
|
|
60
|
+
}
|
|
61
|
+
return encoded;
|
|
62
|
+
}
|
|
63
|
+
function httpError(status, message) {
|
|
64
|
+
const error = new Error(message);
|
|
65
|
+
error.status = status;
|
|
66
|
+
return error;
|
|
67
|
+
}
|
|
32
68
|
//# sourceMappingURL=utils.js.map
|
package/dist-cjs/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,aAAa,CAAC;AAE7B,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,CAAS;IAClD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC9C,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAA+B,EAAE,QAAgB;IAC5E,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monok/server",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Monok server integration helpers
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "Monok server integration helpers for content and affiliate attribution",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist-cjs/index.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
19
|
"dist-cjs",
|
|
20
|
+
"AGENTS.md",
|
|
20
21
|
"README.md",
|
|
21
22
|
"LICENSE"
|
|
22
23
|
],
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
"sideEffects": false,
|
|
27
28
|
"scripts": {
|
|
28
29
|
"build": "tsc -p tsconfig.json && tsc -p tsconfig.cjs.json",
|
|
30
|
+
"test": "npm run build && node --test tests/*.test.mjs",
|
|
29
31
|
"dev": "tsc -w -p tsconfig.json",
|
|
30
32
|
"clean": "rimraf dist dist-cjs",
|
|
31
33
|
"prepublishOnly": "npm run build"
|
|
@@ -34,6 +36,7 @@
|
|
|
34
36
|
"monok",
|
|
35
37
|
"cms",
|
|
36
38
|
"express",
|
|
39
|
+
"affiliate",
|
|
37
40
|
"webhook"
|
|
38
41
|
],
|
|
39
42
|
"dependencies": {
|