@monok/server 1.4.0 → 1.5.1
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 +129 -5
- package/README.md +69 -3
- 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 +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +31 -1
- package/dist/client.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 +28 -0
- package/dist/types.d.ts.map +1 -1
- package/dist-cjs/affiliate.js +96 -0
- package/dist-cjs/affiliate.js.map +1 -0
- package/dist-cjs/client.js +31 -1
- package/dist-cjs/client.js.map +1 -1
- package/dist-cjs/index.js +1 -0
- package/dist-cjs/index.js.map +1 -1
- package/package.json +3 -2
package/AGENTS.md
CHANGED
|
@@ -5,9 +5,23 @@ and developers integrating Monok with an Express application or CMS. Follow the
|
|
|
5
5
|
requirements below rather than inventing alternate endpoint paths or response
|
|
6
6
|
shapes.
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Choose the integration mode
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Before changing the host application, establish which mode the developer wants:
|
|
11
|
+
|
|
12
|
+
1. **Content only** — implement `createMonokRouter` and publication linkbacks.
|
|
13
|
+
2. **Affiliate only** — implement `monokAffiliateAttribution` and
|
|
14
|
+
`createMonokReferral`; do not expose content endpoints.
|
|
15
|
+
3. **Content and affiliate** — implement both independent contracts.
|
|
16
|
+
|
|
17
|
+
Do not assume affiliate functionality merely because the package supports it.
|
|
18
|
+
Updating an existing content-only installation requires no affiliate code or
|
|
19
|
+
configuration. Do not assume content delivery for an affiliate-only merchant.
|
|
20
|
+
|
|
21
|
+
## Content integration
|
|
22
|
+
|
|
23
|
+
Follow this section only for **content only** or **content and affiliate** mode.
|
|
24
|
+
Expose a public HTTPS Monok content integration at these routes:
|
|
11
25
|
|
|
12
26
|
- `POST /api/monok/push`
|
|
13
27
|
- `GET /api/monok/info`
|
|
@@ -19,7 +33,7 @@ default API base, or at an intentional custom base such as
|
|
|
19
33
|
site origin to select the default or the complete custom base URL. Monok appends
|
|
20
34
|
`/info`, `/push`, and `/postfilter` to that base.
|
|
21
35
|
|
|
22
|
-
##
|
|
36
|
+
## Content implementation
|
|
23
37
|
|
|
24
38
|
Install the package and Express:
|
|
25
39
|
|
|
@@ -208,7 +222,7 @@ If `getSiteInfo` is omitted, `/info` returns this authenticated fallback:
|
|
|
208
222
|
```json
|
|
209
223
|
{
|
|
210
224
|
"js_scripts": "Disabled",
|
|
211
|
-
"version": "1.
|
|
225
|
+
"version": "1.5.1",
|
|
212
226
|
"name": "Custom CMS",
|
|
213
227
|
"logo": "",
|
|
214
228
|
"categories": [],
|
|
@@ -270,6 +284,9 @@ When an article is actually published, notify Monok only after the public
|
|
|
270
284
|
canonical URL exists. This applies both to a draft published later and to an
|
|
271
285
|
asynchronous `action: "publish"` job:
|
|
272
286
|
|
|
287
|
+
The default destination is `https://app.monok.com/api/v1/linkback`.
|
|
288
|
+
`monokBaseUrl` is only an override for another Monok environment.
|
|
289
|
+
|
|
273
290
|
```ts
|
|
274
291
|
await sendMonokLinkback({
|
|
275
292
|
monokId: storedMonokId,
|
|
@@ -289,7 +306,7 @@ When useful, `externalId` is the stable article ID assigned by the host CMS; it
|
|
|
289
306
|
is optional because the canonical URL also identifies the publication. When
|
|
290
307
|
supplied, `thumbnailUrl` is the public thumbnail URL.
|
|
291
308
|
|
|
292
|
-
##
|
|
309
|
+
## Content verification checklist
|
|
293
310
|
|
|
294
311
|
Before declaring the integration complete, verify all applicable items:
|
|
295
312
|
|
|
@@ -316,3 +333,110 @@ routes and confirm one durable draft or draft job, one publication or publicatio
|
|
|
316
333
|
job, one repeated delivery, and one discovery query against the host
|
|
317
334
|
application's persistence layer. For asynchronous publishing, also complete one
|
|
318
335
|
job and verify its eventual linkback.
|
|
336
|
+
|
|
337
|
+
## Affiliate integration
|
|
338
|
+
|
|
339
|
+
Follow this section only for **affiliate only** or **content and affiliate**
|
|
340
|
+
mode. A content-only installation must not be changed based on this section.
|
|
341
|
+
|
|
342
|
+
For Express, mount attribution before landing, signup, authentication, and
|
|
343
|
+
account-creation routes:
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import express from "express";
|
|
347
|
+
import {
|
|
348
|
+
createMonokReferral,
|
|
349
|
+
monokAffiliateAttribution
|
|
350
|
+
} from "@monok/server";
|
|
351
|
+
|
|
352
|
+
const app = express();
|
|
353
|
+
|
|
354
|
+
app.use(monokAffiliateAttribution());
|
|
355
|
+
app.use(express.json());
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The middleware reads the signed `monok_ref` query parameter, stores it in an
|
|
359
|
+
HttpOnly, Secure, SameSite=Lax cookie, and redirects to the same URL without the
|
|
360
|
+
token. The offer controls attribution duration; cookie expiry comes from the
|
|
361
|
+
token. Do not add a merchant-configured attribution duration. Only set
|
|
362
|
+
`secure: false` for local HTTP development.
|
|
363
|
+
|
|
364
|
+
For an apex landing site and an account application on a subdomain, explicitly
|
|
365
|
+
share the cookie across the parent domain:
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
app.use(monokAffiliateAttribution({ cookieDomain: ".example.com" }));
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
A cookie created on `example.com` with `Domain=.example.com` is sent to
|
|
372
|
+
`app.example.com`. Omit `cookieDomain` when landing and signup use the same
|
|
373
|
+
hostname. Avoid simultaneous host-only and parent-domain cookies with the same
|
|
374
|
+
name because they produce ambiguous duplicate cookies.
|
|
375
|
+
|
|
376
|
+
After durably creating a new customer, call Monok from that same successful
|
|
377
|
+
account-creation path:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
if (req.monokAttribution) {
|
|
381
|
+
await createMonokReferral(
|
|
382
|
+
{
|
|
383
|
+
attributionToken: req.monokAttribution,
|
|
384
|
+
customerReference: customer.id
|
|
385
|
+
},
|
|
386
|
+
{ apiKey: process.env.MONOK_API_KEY! }
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Use a durable internal customer ID for `customerReference`, never an email or
|
|
392
|
+
other personal data. Do not register referrals during ordinary login,
|
|
393
|
+
invitation acceptance, or flows that do not create a new merchant customer.
|
|
394
|
+
Registration is idempotent for an offer/customer. A temporary Monok failure
|
|
395
|
+
must not roll back an already-created customer; retain the token and customer ID
|
|
396
|
+
in durable retry work. Keep `MONOK_API_KEY` server-side.
|
|
397
|
+
|
|
398
|
+
Monok's own sites use this same public package and API flow. Do not replace it
|
|
399
|
+
with direct database writes, an internal-only attribution service, or
|
|
400
|
+
`referredWorkspaceId` handling.
|
|
401
|
+
|
|
402
|
+
`monokAffiliateAttribution` is Express middleware;
|
|
403
|
+
`createMonokReferral` is framework-independent server code. In another server
|
|
404
|
+
framework, reproduce the capture contract server-side: read `monok_ref`, derive
|
|
405
|
+
expiry from the token, set the secure HttpOnly cookie, and redirect to the clean
|
|
406
|
+
URL. Then read the cookie during customer creation and pass it to
|
|
407
|
+
`createMonokReferral`. A static frontend cannot create an HttpOnly cookie; it
|
|
408
|
+
requires a server or CDN/edge capture handler. Client-side JavaScript cookies
|
|
409
|
+
are not an equivalent secure integration.
|
|
410
|
+
|
|
411
|
+
### Configure the offer on app.monok.com
|
|
412
|
+
|
|
413
|
+
Briefly tell the developer to:
|
|
414
|
+
|
|
415
|
+
1. Sign in to `app.monok.com` and select the merchant workspace.
|
|
416
|
+
2. Open the relevant Brand and choose **Affiliate Program**.
|
|
417
|
+
3. Create the offer with its exact HTTPS landing URL, commission terms,
|
|
418
|
+
duration, and attribution window.
|
|
419
|
+
4. Deploy the integration, click **Test setup**, and confirm **Capture
|
|
420
|
+
verified**.
|
|
421
|
+
5. Activate the offer when it is ready to receive attributed traffic.
|
|
422
|
+
|
|
423
|
+
The Affiliate Program page is currently development-only. If it is absent,
|
|
424
|
+
explain that it is not enabled in that environment. Do not invent another route
|
|
425
|
+
or substitute the content `/info` endpoint.
|
|
426
|
+
|
|
427
|
+
Affiliate integration does not require `createMonokRouter`, `/push`, `/info`,
|
|
428
|
+
or `/postfilter`.
|
|
429
|
+
|
|
430
|
+
### Affiliate verification checklist
|
|
431
|
+
|
|
432
|
+
- Test the exact production landing URL through **Test setup**; do not fabricate
|
|
433
|
+
an attribution token locally.
|
|
434
|
+
- Confirm the offer becomes **Capture verified** before activation.
|
|
435
|
+
- For cross-subdomain flows, confirm the parent-domain cookie reaches the
|
|
436
|
+
account-creation hostname.
|
|
437
|
+
- Exercise each qualifying customer-creation path, including credentials and
|
|
438
|
+
OAuth where applicable, and confirm it calls `createMonokReferral`.
|
|
439
|
+
- Confirm login and invitation-only flows do not create referrals.
|
|
440
|
+
- Do not claim end-to-end verification yet. The dashboard currently validates
|
|
441
|
+
capture only; one-time test-customer callback validation is reserved for a
|
|
442
|
+
later implementation.
|
package/README.md
CHANGED
|
@@ -3,14 +3,27 @@
|
|
|
3
3
|
# `@monok/server`
|
|
4
4
|
|
|
5
5
|
Monok server integration helpers for Node.js/Express.
|
|
6
|
-
|
|
6
|
+
Connect a backend to Monok for content delivery, affiliate attribution, or both.
|
|
7
7
|
|
|
8
8
|
Using an AI coding assistant? Give it [`AGENTS.md`](./AGENTS.md). The guide contains
|
|
9
9
|
the complete host-implementation contract, response shapes, and verification checklist.
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Choose the integration mode
|
|
14
|
+
|
|
15
|
+
Use `@monok/server` in one of three modes:
|
|
16
|
+
|
|
17
|
+
1. **Content only** — receive and publish Monok content.
|
|
18
|
+
2. **Affiliate only** — capture affiliate attribution and register referred customers.
|
|
19
|
+
3. **Content and affiliate** — implement both independent integrations.
|
|
20
|
+
|
|
21
|
+
Only implement the mode your project needs. Existing content-only integrations
|
|
22
|
+
do not need affiliate middleware or configuration when updating this package.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ⚡ Content quick start
|
|
14
27
|
|
|
15
28
|
```ts
|
|
16
29
|
import express from "express";
|
|
@@ -47,7 +60,7 @@ npm install @monok/server express
|
|
|
47
60
|
|
|
48
61
|
---
|
|
49
62
|
|
|
50
|
-
## 📚
|
|
63
|
+
## 📚 Content integration
|
|
51
64
|
|
|
52
65
|
### Express setup (TypeScript)
|
|
53
66
|
|
|
@@ -196,6 +209,8 @@ private no-cache headers. `POST /push` also accepts Monok's `token` header.
|
|
|
196
209
|
|
|
197
210
|
The push acknowledgement confirms delivery only. If publication is asynchronous,
|
|
198
211
|
send the linkback later, after the public canonical URL actually exists.
|
|
212
|
+
Linkbacks default to `https://app.monok.com/api/v1/linkback`; use
|
|
213
|
+
`monokBaseUrl` only when targeting another Monok environment.
|
|
199
214
|
|
|
200
215
|
```ts
|
|
201
216
|
import { sendMonokLinkback } from "@monok/server";
|
|
@@ -225,6 +240,57 @@ await sendMonokLinkback({
|
|
|
225
240
|
|
|
226
241
|
---
|
|
227
242
|
|
|
243
|
+
## Affiliate integration
|
|
244
|
+
|
|
245
|
+
Follow this section for **affiliate only** or **content and affiliate** mode.
|
|
246
|
+
Content-only integrations can ignore it completely.
|
|
247
|
+
|
|
248
|
+
The affiliate middleware preserves the signed `monok_ref` value from a Monok
|
|
249
|
+
redirect in an HttpOnly, SameSite=Lax cookie, then redirects to the same URL
|
|
250
|
+
without the token. The offer controls the attribution window and the middleware
|
|
251
|
+
derives the cookie expiry from the token, so merchants do not configure it.
|
|
252
|
+
Mount it before the merchant's landing and signup routes. After the customer has
|
|
253
|
+
been durably created, register the referral using the merchant's own stable
|
|
254
|
+
customer ID.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import express from "express";
|
|
258
|
+
import {
|
|
259
|
+
createMonokReferral,
|
|
260
|
+
monokAffiliateAttribution
|
|
261
|
+
} from "@monok/server";
|
|
262
|
+
|
|
263
|
+
const app = express();
|
|
264
|
+
app.use(monokAffiliateAttribution());
|
|
265
|
+
app.use(express.json());
|
|
266
|
+
|
|
267
|
+
app.post("/signup", async (req, res) => {
|
|
268
|
+
const customer = await createCustomer(req.body);
|
|
269
|
+
|
|
270
|
+
if (req.monokAttribution) {
|
|
271
|
+
await createMonokReferral(
|
|
272
|
+
{
|
|
273
|
+
attributionToken: req.monokAttribution,
|
|
274
|
+
customerReference: customer.id
|
|
275
|
+
},
|
|
276
|
+
{ apiKey: process.env.MONOK_API_KEY! }
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
res.status(201).json({ id: customer.id });
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
The middleware defaults to secure cookies. For local HTTP development only, use
|
|
285
|
+
`monokAffiliateAttribution({ secure: false })`. `customerReference` should be a
|
|
286
|
+
durable internal ID, not an email address or other personal data. Repeating the
|
|
287
|
+
same offer/customer registration is idempotent and retains the first referral.
|
|
288
|
+
|
|
289
|
+
Affiliate-only merchants do **not** need to mount `createMonokRouter` or expose
|
|
290
|
+
`/push`, `/info`, or `/postfilter`.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
228
294
|
## 🛠 Development
|
|
229
295
|
|
|
230
296
|
Build the package:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RequestHandler } from "express";
|
|
2
|
+
import type { MonokAffiliateAttributionOptions } from "./types.js";
|
|
3
|
+
declare global {
|
|
4
|
+
namespace Express {
|
|
5
|
+
interface Request {
|
|
6
|
+
monokAttribution?: string;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Preserve Monok's signed redirect token in an HttpOnly cookie and expose it as
|
|
12
|
+
* `req.monokAttribution`. This does not expose any content-receiving endpoint.
|
|
13
|
+
*/
|
|
14
|
+
export declare function monokAffiliateAttribution(options?: MonokAffiliateAttributionOptions): RequestHandler;
|
|
15
|
+
//# sourceMappingURL=affiliate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"affiliate.d.ts","sourceRoot":"","sources":["../src/affiliate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAC/E,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAC;AAcnE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B;KACF;CACF;AAgED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gCAAqC,GAC7C,cAAc,CAuChB"}
|
|
@@ -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":"AAGA,MAAM,uBAAuB,GAAG,WAAW,CAAC;AAC5C,MAAM,mBAAmB,GAAG,WAAW,CAAC;AACxC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC9B,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACjD,MAAM,2BAA2B,GAAG,GAAG,CAAC;AACxC,MAAM,aAAa,GAAG,kCAAkC,CAAC;AAezD,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ;QAC9B,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,MAAM,IAAI,gBAAgB;QAChC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE;IACzD,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzC,IAAI,CAAC;QACH,MAAM,CAAC,cAAc,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,cAAe,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAIpF,CAAC;QACF,IACE,OAAO,CAAC,OAAO,KAAK,CAAC;YACrB,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC;YAC3E,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAC7E,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;QACjE,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,GAAG,KAAK,CAAC;QAClD,IACE,UAAU,GAAG,oBAAoB;YACjC,UAAU,GAAG,2BAA2B,GAAG,oBAAoB;YAC/D,UAAU,GAAG,oBAAoB,KAAK,CAAC;YACvC,OAAO,CAAC,QAAQ,GAAG,IAAI,GAAG,KAAK,GAAG,KAAM;YACxC,QAAQ,IAAI,CAAC,EACb,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,GAAY,EAAE,UAAkB;IAClD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;IAClC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,SAAS,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,KAAK,UAAU;YAAE,SAAS;QAE9E,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACnE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAA4C,EAAE;IAE9C,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,uBAAuB,CAAC;IACzE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC;IAE7D,IAAI,CAAC,cAAc,IAAI,CAAC,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IAED,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC7C,MAAM,gBAAgB,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,gBAAgB;YAClC,CAAC,CAAC,gBAAgB;YAClB,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAEhC,IAAI,WAAW;YAAE,GAAG,CAAC,gBAAgB,GAAG,WAAW,CAAC,KAAK,CAAC;QAE1D,IAAI,gBAAgB,EAAE,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,KAAK,EAAE;gBAC7C,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;gBAC9B,QAAQ,EAAE,KAAK;gBACf,IAAI,EAAE,GAAG;gBACT,MAAM,EAAE,gBAAgB,CAAC,QAAQ;gBACjC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClE,CAAC,CAAC;QACL,CAAC;QAED,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;gBAC7B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;gBAChE,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC7C,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACvD,OAAO;YACT,CAAC;QACH,CAAC;QAED,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { LinkbackPayload } from "./types.js";
|
|
1
|
+
import type { CreateMonokReferralPayload, LinkbackPayload, MonokAffiliateClientOptions, MonokReferralResult } from "./types.js";
|
|
2
|
+
export declare 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
|
*/
|
|
@@ -6,4 +7,9 @@ export declare function sendMonokLinkback({ monokId, externalId, url, title, thu
|
|
|
6
7
|
monokBaseUrl?: string;
|
|
7
8
|
apiKey?: string;
|
|
8
9
|
}): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Register a newly created merchant customer against a signed attribution token.
|
|
12
|
+
* Repeating the same offer/customer pair is safe and returns the existing referral.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createMonokReferral({ attributionToken, customerReference }: CreateMonokReferralPayload, { apiKey, monokBaseUrl }: MonokAffiliateClientOptions): Promise<MonokReferralResult>;
|
|
9
15
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,0BAA0B,EAC1B,eAAe,EACf,2BAA2B,EAC3B,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAE9D;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,eAAe,EAClE,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,EAAE,0BAA0B,EACnE,EAAE,MAAM,EAAE,YAAqC,EAAE,EAAE,2BAA2B,GAC7E,OAAO,CAAC,mBAAmB,CAAC,CAwB9B"}
|
package/dist/client.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
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
6
|
export async function sendMonokLinkback({ monokId, externalId, url, title, thumbnailUrl }, opts) {
|
|
6
|
-
const endpoint = (opts?.monokBaseUrl ??
|
|
7
|
+
const endpoint = (opts?.monokBaseUrl ?? DEFAULT_MONOK_BASE_URL) + "/api/v1/linkback";
|
|
7
8
|
const payload = {
|
|
8
9
|
puff: { title },
|
|
9
10
|
id: monokId,
|
|
@@ -27,4 +28,33 @@ export async function sendMonokLinkback({ monokId, externalId, url, title, thumb
|
|
|
27
28
|
throw new Error(`Monok linkback failed: ${resp.status} ${text}`);
|
|
28
29
|
}
|
|
29
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
|
+
}
|
|
30
60
|
//# sourceMappingURL=client.js.map
|
package/dist/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":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","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/index.js
CHANGED
package/dist/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/types.d.ts
CHANGED
|
@@ -89,6 +89,34 @@ export interface LinkbackPayload {
|
|
|
89
89
|
title: string;
|
|
90
90
|
thumbnailUrl?: string;
|
|
91
91
|
}
|
|
92
|
+
export interface MonokAffiliateAttributionOptions {
|
|
93
|
+
/** Query parameter carrying the signed Monok attribution token. */
|
|
94
|
+
queryParameter?: string;
|
|
95
|
+
/** HttpOnly cookie used to preserve attribution until signup. */
|
|
96
|
+
cookieName?: string;
|
|
97
|
+
/** Optional cookie domain, for example `.example.com`. */
|
|
98
|
+
cookieDomain?: string;
|
|
99
|
+
/** Defaults to true. Set false only for local HTTP development. */
|
|
100
|
+
secure?: boolean;
|
|
101
|
+
/** Remove the token from the address bar with a safe same-site redirect. Defaults to true. */
|
|
102
|
+
cleanUrl?: boolean;
|
|
103
|
+
}
|
|
104
|
+
export interface CreateMonokReferralPayload {
|
|
105
|
+
attributionToken: string;
|
|
106
|
+
/** The merchant's durable, non-sensitive customer ID. */
|
|
107
|
+
customerReference: string;
|
|
108
|
+
}
|
|
109
|
+
export interface MonokAffiliateClientOptions {
|
|
110
|
+
apiKey: string;
|
|
111
|
+
monokBaseUrl?: string;
|
|
112
|
+
}
|
|
113
|
+
export interface MonokReferralResult {
|
|
114
|
+
id: string;
|
|
115
|
+
status: "created" | "existing";
|
|
116
|
+
offerId: string;
|
|
117
|
+
publisherWorkspaceId: string;
|
|
118
|
+
customerReference: string;
|
|
119
|
+
}
|
|
92
120
|
export interface CreateRouterOptions {
|
|
93
121
|
/**
|
|
94
122
|
* Token Monok will send in the `token` header.
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.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,9 +1,10 @@
|
|
|
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
6
|
export async function sendMonokLinkback({ monokId, externalId, url, title, thumbnailUrl }, opts) {
|
|
6
|
-
const endpoint = (opts?.monokBaseUrl ??
|
|
7
|
+
const endpoint = (opts?.monokBaseUrl ?? DEFAULT_MONOK_BASE_URL) + "/api/v1/linkback";
|
|
7
8
|
const payload = {
|
|
8
9
|
puff: { title },
|
|
9
10
|
id: monokId,
|
|
@@ -27,4 +28,33 @@ export async function sendMonokLinkback({ monokId, externalId, url, title, thumb
|
|
|
27
28
|
throw new Error(`Monok linkback failed: ${resp.status} ${text}`);
|
|
28
29
|
}
|
|
29
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
|
+
}
|
|
30
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":"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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/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.1",
|
|
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",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"monok",
|
|
37
37
|
"cms",
|
|
38
38
|
"express",
|
|
39
|
+
"affiliate",
|
|
39
40
|
"webhook"
|
|
40
41
|
],
|
|
41
42
|
"dependencies": {
|