@intenque/network-sdk 2.2.0-beta.1 → 2.2.0-beta.2
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/CHANGELOG.md +50 -1
- package/dist/capture/index.cjs +1 -1
- package/dist/capture/index.js +1 -1
- package/dist/cli/index.js +9 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/{constants-LVhc0PNb.d.cts → constants-C_6Zxu_k.d.cts} +1 -1
- package/dist/{constants-LVhc0PNb.d.ts → constants-C_6Zxu_k.d.ts} +1 -1
- package/dist/react/index.cjs +2 -2
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +2 -2
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +14 -9
- package/dist/server/index.d.ts +14 -9
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,56 @@
|
|
|
3
3
|
`@intenque/network-sdk`. The SDK major is the manifest schema major (spec §6.1). Design decisions are in the hub
|
|
4
4
|
repository: `docs/Network_CrossPromo_Plan.md` and `docs/spec-addendum-phase0-auth.md` ("# Phase 3: conversions").
|
|
5
5
|
|
|
6
|
-
## 2.2.0-beta.
|
|
6
|
+
## 2.2.0-beta.2
|
|
7
|
+
|
|
8
|
+
Security fix round (hub Phase 3 WP19). No API change; one new drop reason.
|
|
9
|
+
|
|
10
|
+
### Server entry (`@intenque/network-sdk/server`)
|
|
11
|
+
|
|
12
|
+
- **Misrouted answers are retried, not dropped.** `403`, `404` and any 3xx the classifier sees (`300`, `304`, or a
|
|
13
|
+
`fetch` that hands redirects back) were terminal after one attempt, so a missing route prefix, a WAF or a
|
|
14
|
+
maintenance page in front of the hub lost every report in that window. They are now `misrouted`
|
|
15
|
+
(`classifyResponse` returns the new kind): retried in process after 2, 8 and 30 s, then every 10 min from the
|
|
16
|
+
outbox, and dropped only 24 h after the first 401 / missing-config / misrouted answer with reason `misrouted_24h`
|
|
17
|
+
(the clock is the existing `unauthorizedSince` field, shared with the 401 rule; no outbox migration). A real
|
|
18
|
+
redirect (`301`/`302`/`303`/`307`/`308`, with or without `Location`) is still a transport error under
|
|
19
|
+
`redirect: 'error'` (status 0, retryable), as before. `400`, other `409`s, `402`, `413`, `422` and the rest of 4xx
|
|
20
|
+
stay terminal.
|
|
21
|
+
- **The responder's error code is bounded.** A code is kept (logged in `inr_outbox_dropped_total` /
|
|
22
|
+
`INR_UNAUTHORIZED`, stored in `lastError.code`) only when it matches `^[A-Z][A-Z0-9_]{0,63}$`; anything else
|
|
23
|
+
(a captive portal, a misrouted proxy, a 5000-character string) is `null`.
|
|
24
|
+
- **`referralMiddleware()` strips `inrRef` from any object body** (arrays and class instances too, not only plain
|
|
25
|
+
objects) with `Reflect.deleteProperty`, and never throws: a frozen body or a proxy that refuses keeps the field,
|
|
26
|
+
a `null` or primitive body is left alone. `req.inrRef` is set as before.
|
|
27
|
+
- **`forget()` stops a running send chain.** Before each in-process retry the chain checks that its outbox row (or
|
|
28
|
+
spill entry) still exists; once `forget(clickId)` purged it, no further attempt is sent. An outbox that errors or
|
|
29
|
+
times out on that check keeps the chain sending (as before).
|
|
30
|
+
- **`forget()` during a drain tick's spill move.** The drainer moved a snapshot of the in-memory spill, so a spilled
|
|
31
|
+
report that `forget(clickId)` removed while an earlier entry was being written was inserted into the outbox after
|
|
32
|
+
the purge (and `forget()` had returned `true`); the next tick sent the erased click id again. The move now skips an
|
|
33
|
+
entry no longer spilled, and removes the row again when the entry left the spill while its own write was in flight
|
|
34
|
+
(forget, or a send that finished). A failed write still leaves the entry spilled for the next tick.
|
|
35
|
+
|
|
36
|
+
### Verifier (`@intenque/network-sdk/react`, the manifest verifier)
|
|
37
|
+
|
|
38
|
+
- **Destination URLs: RFC 3986 characters only after the authority** (unreserved, sub-delims, `:`, `@`, `/`, `?`,
|
|
39
|
+
`%XX`, one `#`). The hub now stores business URLs with `^`, `|`, a backtick, `{`, `}`, `[`, `]` and non-ASCII
|
|
40
|
+
percent-encoded and refuses
|
|
41
|
+
to sign anything else, so the SDK and the hub agree on every URL in every engine (a raw `^` or `|` used to pass
|
|
42
|
+
the hub and fail the SDK in browsers, taking the whole manifest down).
|
|
43
|
+
- **Signer dates must be their own `toISOString()`** (`2027-02-30`, `T24:00`, second 60 are `malformed`), the same
|
|
44
|
+
rule as the hub's verifier: engines disagree on those dates.
|
|
45
|
+
- **A root key that is not exactly `crv: 'P-256'` never verifies** (Firefox's WebCrypto accepts `p-256`).
|
|
46
|
+
- **A root key must have the shape the hub requires of its own roots** (`PublicJwkSchema`: `kty: 'EC'`,
|
|
47
|
+
`crv: 'P-256'`, `x` / `y` canonical base64url of 32 bytes), else `root_sig`; other members are ignored, as
|
|
48
|
+
before. The SDK handed WebCrypto `kty: 'EC'` whatever the site's `manifestRootKeys` said, so `kty: 'ec'`, `'RSA'`
|
|
49
|
+
or none verified in every engine while the hub refuses such a key, and a padded `x` verified in WebKit only.
|
|
50
|
+
- **Hosts with right-to-left text** (hub side, no SDK change): the hub now refuses a business URL whose host breaks
|
|
51
|
+
the RFC 5893 bidi rule (e.g. `24.בדיקה.co.il`, `1shop.عرب.com`, `aא.com`, `٣.com`), which Firefox's URL parser
|
|
52
|
+
refuses, so a signed manifest can no longer be `malformed` in Firefox alone. The SDK schema does not repeat that
|
|
53
|
+
check (bundle size; the hub never signs such a host).
|
|
54
|
+
|
|
55
|
+
## 2.2.0-beta.1
|
|
7
56
|
|
|
8
57
|
### Server entry (`@intenque/network-sdk/server`)
|
|
9
58
|
|
package/dist/capture/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var u=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var C=(n,e)=>{for(var t in e)u(n,t,{get:e[t],enumerable:!0})},M=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of y(e))!k.call(n,r)&&r!==t&&u(n,r,{get:()=>e[r],enumerable:!(o=m(e,r))||o.enumerable});return n};var L=n=>M(u({},"__esModule",{value:!0}),n);var w={};C(w,{attachReferral:()=>A,attachReferralHeader:()=>O,captureReferral:()=>b,clearReferral:()=>N,getReferral:()=>I,onConsentChange:()=>T,setConsent:()=>E});module.exports=L(w);var _="2.2.0-beta.
|
|
1
|
+
"use strict";var u=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var C=(n,e)=>{for(var t in e)u(n,t,{get:e[t],enumerable:!0})},M=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of y(e))!k.call(n,r)&&r!==t&&u(n,r,{get:()=>e[r],enumerable:!(o=m(e,r))||o.enumerable});return n};var L=n=>M(u({},"__esModule",{value:!0}),n);var w={};C(w,{attachReferral:()=>A,attachReferralHeader:()=>O,captureReferral:()=>b,clearReferral:()=>N,getReferral:()=>I,onConsentChange:()=>T,setConsent:()=>E});module.exports=L(w);var _="2.2.0-beta.2";function S(n,e,t){let o=s=>{try{t?.(s)}catch{}return s};try{if(location.protocol=="https:"&&/^http:/i.test(n))return o(!1)}catch{}try{if(navigator.sendBeacon(n,e))return o(!0)}catch{}let r=s=>fetch(n,{method:"POST",mode:"no-cors",keepalive:s,credentials:"omit",body:e});try{return r(!0).then(()=>o(!0),()=>{try{if(document.visibilityState=="visible")return void r(!1).then(()=>o(!0),()=>o(!1))}catch{}o(!1)}),!0}catch{return o(!1)}}var f="inr_ref",h=2592e6,a={},l=null,c=(n,e)=>{try{let t=n?localStorage:sessionStorage;if(e===void 0)return JSON.parse(t.getItem(f)||"null");e?t.setItem(f,JSON.stringify(e)):t.removeItem(f)}catch{}return null},R=()=>!!navigator.globalPrivacyControl,p=()=>a.consent?.get()=="granted"&&!R(),g="",x=n=>{let e=a.endpoint,t=n.last.c;if(!e||!a.siteKey||g==t)return;g=t;let o=r=>{let s=Date.now();S(e.replace(/\/+$/,"")+"/landing",JSON.stringify({v:2,k:a.siteKey,c:t,scope:"session",ph:r&&[...new Uint8Array(r,0,8)].map(i=>(i+256).toString(16).slice(1)).join(""),sdk:_,t:s,d:Math.min(h,Math.max(0,s-n.last.t))}))};try{crypto.subtle.digest("SHA-256",new TextEncoder().encode(location.pathname)).then(o,()=>o())}catch{o()}};function b(n={}){a=n;try{let e=new URL(location.href),t=e.searchParams.get("inr");if(!t||(e.searchParams.delete("inr"),history.replaceState(history.state,"",e.href),!/^[A-Za-z0-9_-]{32}$/.test(t)))return;let o={c:t,t:Date.now(),from:e.searchParams.get("utm_source")},r=c(0),s={last:o,first:r?.first||o};if(n.consentMode=="require-consent"&&!p()){l=s;return}c(0,s),p()&&c(1,s),x(s)}catch{}}function E(n){try{if(n=="granted"){let e=l;if(l=null,e&&R())return;let t=e||c(0);t&&(c(0,t),p()&&c(1,t),e&&x(e))}else l=null,c(1,null)}catch{}}var T=E;function N(){l=null,c(0,null),c(1,null)}function I(){try{let n=c(0),e=c(1),t=n&&(!e||n.last.t>=e.last.t)?n:e;return!t||Date.now()-t.last.t>h?null:{clickId:t.last.c,firstClickId:t.first.c==t.last.c?null:t.first.c,capturedAt:t.last.t,tokenScope:n&&n.last.c==t.last.c?"session":"persistent",consented:!!p()}}catch{return null}}function A(n,e={}){n.interceptors.request.use(t=>{try{if(/^(get|head|options)?$/i.test(t.method||""))return t;let o=new URL((t.baseURL||n.defaults?.baseURL||"").replace(/\/*$/,"/"),location.origin),r=new URL((t.url||"").replace(/^\/(?!\/)/,""),o),s=r.pathname;if(r.origin!=o.origin&&!e.origins?.includes(r.origin)||e.routes&&!e.routes.some(d=>d.test?~s.search(d):d==s))return t;let i=I();if(!i)return t;e.mode=="header"?(t.headers=t.headers||{},t.headers["X-INR-Ref"]=i.clickId,t.headers["X-INR-Ref-Scope"]=i.tokenScope,i.firstClickId&&(t.headers["X-INR-Ref-First"]=i.firstClickId)):(t.data==null||Object.getPrototypeOf(t.data)==Object.prototype)&&(t.data={...t.data,inrRef:{clickId:i.clickId,firstClickId:i.firstClickId,tokenScope:i.tokenScope}})}catch{}return t})}var O=(n,e={})=>A(n,{...e,mode:"header"});
|
package/dist/capture/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var f="2.2.0-beta.
|
|
1
|
+
var f="2.2.0-beta.2";function _(n,e,t){let o=r=>{try{t?.(r)}catch{}return r};try{if(location.protocol=="https:"&&/^http:/i.test(n))return o(!1)}catch{}try{if(navigator.sendBeacon(n,e))return o(!0)}catch{}let s=r=>fetch(n,{method:"POST",mode:"no-cors",keepalive:r,credentials:"omit",body:e});try{return s(!0).then(()=>o(!0),()=>{try{if(document.visibilityState=="visible")return void s(!1).then(()=>o(!0),()=>o(!1))}catch{}o(!1)}),!0}catch{return o(!1)}}var u="inr_ref",g=2592e6,a={},l=null,c=(n,e)=>{try{let t=n?localStorage:sessionStorage;if(e===void 0)return JSON.parse(t.getItem(u)||"null");e?t.setItem(u,JSON.stringify(e)):t.removeItem(u)}catch{}return null},h=()=>!!navigator.globalPrivacyControl,p=()=>a.consent?.get()=="granted"&&!h(),S="",R=n=>{let e=a.endpoint,t=n.last.c;if(!e||!a.siteKey||S==t)return;S=t;let o=s=>{let r=Date.now();_(e.replace(/\/+$/,"")+"/landing",JSON.stringify({v:2,k:a.siteKey,c:t,scope:"session",ph:s&&[...new Uint8Array(s,0,8)].map(i=>(i+256).toString(16).slice(1)).join(""),sdk:f,t:r,d:Math.min(g,Math.max(0,r-n.last.t))}))};try{crypto.subtle.digest("SHA-256",new TextEncoder().encode(location.pathname)).then(o,()=>o())}catch{o()}};function C(n={}){a=n;try{let e=new URL(location.href),t=e.searchParams.get("inr");if(!t||(e.searchParams.delete("inr"),history.replaceState(history.state,"",e.href),!/^[A-Za-z0-9_-]{32}$/.test(t)))return;let o={c:t,t:Date.now(),from:e.searchParams.get("utm_source")},s=c(0),r={last:o,first:s?.first||o};if(n.consentMode=="require-consent"&&!p()){l=r;return}c(0,r),p()&&c(1,r),R(r)}catch{}}function x(n){try{if(n=="granted"){let e=l;if(l=null,e&&h())return;let t=e||c(0);t&&(c(0,t),p()&&c(1,t),e&&R(e))}else l=null,c(1,null)}catch{}}var M=x;function L(){l=null,c(0,null),c(1,null)}function E(){try{let n=c(0),e=c(1),t=n&&(!e||n.last.t>=e.last.t)?n:e;return!t||Date.now()-t.last.t>g?null:{clickId:t.last.c,firstClickId:t.first.c==t.last.c?null:t.first.c,capturedAt:t.last.t,tokenScope:n&&n.last.c==t.last.c?"session":"persistent",consented:!!p()}}catch{return null}}function I(n,e={}){n.interceptors.request.use(t=>{try{if(/^(get|head|options)?$/i.test(t.method||""))return t;let o=new URL((t.baseURL||n.defaults?.baseURL||"").replace(/\/*$/,"/"),location.origin),s=new URL((t.url||"").replace(/^\/(?!\/)/,""),o),r=s.pathname;if(s.origin!=o.origin&&!e.origins?.includes(s.origin)||e.routes&&!e.routes.some(d=>d.test?~r.search(d):d==r))return t;let i=E();if(!i)return t;e.mode=="header"?(t.headers=t.headers||{},t.headers["X-INR-Ref"]=i.clickId,t.headers["X-INR-Ref-Scope"]=i.tokenScope,i.firstClickId&&(t.headers["X-INR-Ref-First"]=i.firstClickId)):(t.data==null||Object.getPrototypeOf(t.data)==Object.prototype)&&(t.data={...t.data,inrRef:{clickId:i.clickId,firstClickId:i.firstClickId,tokenScope:i.tokenScope}})}catch{}return t})}var b=(n,e={})=>I(n,{...e,mode:"header"});export{I as attachReferral,b as attachReferralHeader,C as captureReferral,L as clearReferral,E as getReferral,M as onConsentChange,x as setConsent};
|
package/dist/cli/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { webcrypto } from "crypto";
|
|
5
5
|
|
|
6
6
|
// src/constants.ts
|
|
7
|
-
var SDK_VERSION = "2.2.0-beta.
|
|
7
|
+
var SDK_VERSION = "2.2.0-beta.2";
|
|
8
8
|
var MANIFEST_SCHEMA_MAJOR = 2;
|
|
9
9
|
var DEFAULT_CDN_BASE = "https://inr-network-public.nyc3.cdn.digitaloceanspaces.com/network/v1";
|
|
10
10
|
var MANIFEST_MAX_BYTES = 24 * 1024;
|
|
@@ -141,6 +141,7 @@ var COORD_RE = /^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/;
|
|
|
141
141
|
var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/;
|
|
142
142
|
var TOKEN_RE = /^[a-z0-9-]+\.\d+\.\d{8}\.[0-9a-f]{12}$/;
|
|
143
143
|
var HOST_RE = /^[a-z0-9.-]+$/;
|
|
144
|
+
var URL_TAIL_RE = /^([\w.~!$&'()*+,;=:@/?-]|%[\da-f]{2})*(#([\w.~!$&'()*+,;=:@/?-]|%[\da-f]{2})*)?$/i;
|
|
144
145
|
var Invalid = class extends Error {
|
|
145
146
|
};
|
|
146
147
|
var fail = () => {
|
|
@@ -220,7 +221,7 @@ function destinationUrlProblem(v) {
|
|
|
220
221
|
if (host.startsWith("[") || /^\d+(\.\d+){3}$/.test(host)) return "IP addresses are not allowed";
|
|
221
222
|
if (!HOST_RE.test(host) || !host.includes(".") || host.startsWith(".") || host.endsWith("."))
|
|
222
223
|
return "invalid hostname";
|
|
223
|
-
if (u.toString() !== v) return "must be normalised";
|
|
224
|
+
if (u.toString() !== v || !URL_TAIL_RE.test(v.slice(u.origin.length))) return "must be normalised";
|
|
224
225
|
return null;
|
|
225
226
|
}
|
|
226
227
|
function destinationUrl(v) {
|
|
@@ -470,9 +471,10 @@ var keyCache = /* @__PURE__ */ new WeakMap();
|
|
|
470
471
|
async function importKey(jwk, api) {
|
|
471
472
|
const hit = keyCache.get(jwk);
|
|
472
473
|
if (hit) return hit;
|
|
474
|
+
const { kty, crv, x, y } = jwk;
|
|
473
475
|
const p = api.importKey(
|
|
474
476
|
"jwk",
|
|
475
|
-
{ kty
|
|
477
|
+
{ ...parsePublicJwk({ kty, crv, x, y }), ext: true },
|
|
476
478
|
{ name: "ECDSA", namedCurve: "P-256" },
|
|
477
479
|
false,
|
|
478
480
|
["verify"]
|
|
@@ -514,7 +516,9 @@ function signedPayload(m) {
|
|
|
514
516
|
}
|
|
515
517
|
var isKidList = (v) => Array.isArray(v) && v.every((k) => typeof k === "string");
|
|
516
518
|
function parseIso(s) {
|
|
517
|
-
|
|
519
|
+
const t = Date.parse(s);
|
|
520
|
+
if (!new Date(t).toISOString().startsWith(s.slice(0, 19))) fail();
|
|
521
|
+
return t;
|
|
518
522
|
}
|
|
519
523
|
async function verifyManifest(input, opts) {
|
|
520
524
|
try {
|
|
@@ -541,8 +545,7 @@ async function verifyManifest(input, opts) {
|
|
|
541
545
|
return { ok: false, reason: "root_sig" };
|
|
542
546
|
const notBefore = parseIso(s.notBefore);
|
|
543
547
|
const notAfter = parseIso(s.notAfter);
|
|
544
|
-
if (
|
|
545
|
-
return { ok: false, reason: "malformed" };
|
|
548
|
+
if (notAfter < notBefore) return { ok: false, reason: "malformed" };
|
|
546
549
|
if (opts.source === "live" && (t < notBefore || t > notAfter + SIGNER_GRACE_MS))
|
|
547
550
|
return { ok: false, reason: "window" };
|
|
548
551
|
if (m.sig.kid !== s.kid) return { ok: false, reason: "kid_mismatch" };
|