@tolinku/web-sdk 0.3.0 → 0.4.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/index.d.mts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +61 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +61 -5
- package/dist/index.mjs.map +1 -1
- package/dist/tolinku.min.js +71 -0
- package/dist/tolinku.min.js.map +1 -0
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -393,8 +393,41 @@ declare class Deferred {
|
|
|
393
393
|
constructor(client: HttpClient);
|
|
394
394
|
/** Claim a deferred deep link by referrer token (from Play Store referrer or clipboard) */
|
|
395
395
|
claimByToken(token: string): Promise<DeferredLink | null>;
|
|
396
|
+
/**
|
|
397
|
+
* Recover the link that led here, once.
|
|
398
|
+
*
|
|
399
|
+
* There is no Play Install Referrer on the web, so this is signal matching
|
|
400
|
+
* with the bookkeeping that makes calling it safe. That bookkeeping is the
|
|
401
|
+
* point: a claim is consumed the first time it succeeds, so an app calling
|
|
402
|
+
* claimBySignals on every page load asks again after the answer is already
|
|
403
|
+
* spent, and every one of those asks is recorded as a miss. The match rate on
|
|
404
|
+
* the dashboard then falls towards zero while the integration is working
|
|
405
|
+
* correctly, which is a hard thing to diagnose from the outside.
|
|
406
|
+
*
|
|
407
|
+
* Call it once on first run. Calling it again is free after the first.
|
|
408
|
+
*
|
|
409
|
+
* Named to match the Android, React Native and Flutter SDKs, where the same
|
|
410
|
+
* call also tries the install referrer before falling back to here.
|
|
411
|
+
*/
|
|
412
|
+
claimDeferredLink(options: {
|
|
413
|
+
appspaceId: string;
|
|
414
|
+
/** Claim again even if an attempt was already recorded. For tests. */
|
|
415
|
+
force?: boolean;
|
|
416
|
+
}): Promise<DeferredLink | null>;
|
|
417
|
+
private alreadyAttempted;
|
|
418
|
+
private rememberAttempt;
|
|
396
419
|
/** Claim a deferred deep link by device signal matching */
|
|
397
420
|
claimBySignals(options: ClaimBySignalsOptions): Promise<DeferredLink | null>;
|
|
421
|
+
/**
|
|
422
|
+
* The signal claim, with whether the server actually answered.
|
|
423
|
+
*
|
|
424
|
+
* `settled` separates "nothing is waiting for this device", which no amount
|
|
425
|
+
* of asking will change, from "the request never got there". Both surface as
|
|
426
|
+
* null to callers of claimBySignals, but claimDeferredLink has to tell them
|
|
427
|
+
* apart: recording an attempt that never reached the server would spend an
|
|
428
|
+
* install's one chance at attribution on a dropped connection.
|
|
429
|
+
*/
|
|
430
|
+
private attemptSignals;
|
|
398
431
|
}
|
|
399
432
|
|
|
400
433
|
declare class Tolinku {
|
package/dist/index.d.ts
CHANGED
|
@@ -393,8 +393,41 @@ declare class Deferred {
|
|
|
393
393
|
constructor(client: HttpClient);
|
|
394
394
|
/** Claim a deferred deep link by referrer token (from Play Store referrer or clipboard) */
|
|
395
395
|
claimByToken(token: string): Promise<DeferredLink | null>;
|
|
396
|
+
/**
|
|
397
|
+
* Recover the link that led here, once.
|
|
398
|
+
*
|
|
399
|
+
* There is no Play Install Referrer on the web, so this is signal matching
|
|
400
|
+
* with the bookkeeping that makes calling it safe. That bookkeeping is the
|
|
401
|
+
* point: a claim is consumed the first time it succeeds, so an app calling
|
|
402
|
+
* claimBySignals on every page load asks again after the answer is already
|
|
403
|
+
* spent, and every one of those asks is recorded as a miss. The match rate on
|
|
404
|
+
* the dashboard then falls towards zero while the integration is working
|
|
405
|
+
* correctly, which is a hard thing to diagnose from the outside.
|
|
406
|
+
*
|
|
407
|
+
* Call it once on first run. Calling it again is free after the first.
|
|
408
|
+
*
|
|
409
|
+
* Named to match the Android, React Native and Flutter SDKs, where the same
|
|
410
|
+
* call also tries the install referrer before falling back to here.
|
|
411
|
+
*/
|
|
412
|
+
claimDeferredLink(options: {
|
|
413
|
+
appspaceId: string;
|
|
414
|
+
/** Claim again even if an attempt was already recorded. For tests. */
|
|
415
|
+
force?: boolean;
|
|
416
|
+
}): Promise<DeferredLink | null>;
|
|
417
|
+
private alreadyAttempted;
|
|
418
|
+
private rememberAttempt;
|
|
396
419
|
/** Claim a deferred deep link by device signal matching */
|
|
397
420
|
claimBySignals(options: ClaimBySignalsOptions): Promise<DeferredLink | null>;
|
|
421
|
+
/**
|
|
422
|
+
* The signal claim, with whether the server actually answered.
|
|
423
|
+
*
|
|
424
|
+
* `settled` separates "nothing is waiting for this device", which no amount
|
|
425
|
+
* of asking will change, from "the request never got there". Both surface as
|
|
426
|
+
* null to callers of claimBySignals, but claimDeferredLink has to tell them
|
|
427
|
+
* apart: recording an attempt that never reached the server would spend an
|
|
428
|
+
* install's one chance at attribution on a dropped connection.
|
|
429
|
+
*/
|
|
430
|
+
private attemptSignals;
|
|
398
431
|
}
|
|
399
432
|
|
|
400
433
|
declare class Tolinku {
|
package/dist/index.js
CHANGED
|
@@ -169,7 +169,11 @@ var HttpClient = class {
|
|
|
169
169
|
}
|
|
170
170
|
headers() {
|
|
171
171
|
return {
|
|
172
|
-
"X-API-Key": this.apiKey
|
|
172
|
+
"X-API-Key": this.apiKey,
|
|
173
|
+
// Browsers default to "Accept: */*", which a server content-negotiating an
|
|
174
|
+
// error page reads as "HTML is fine". Saying so explicitly keeps an error
|
|
175
|
+
// parseable instead of arriving as a rendered page.
|
|
176
|
+
"Accept": "application/json"
|
|
173
177
|
};
|
|
174
178
|
}
|
|
175
179
|
};
|
|
@@ -527,6 +531,7 @@ var Referrals = class {
|
|
|
527
531
|
};
|
|
528
532
|
|
|
529
533
|
// src/deferred.ts
|
|
534
|
+
var CLAIMED_KEY = "tolinku_deferred_claimed";
|
|
530
535
|
var Deferred = class {
|
|
531
536
|
constructor(client) {
|
|
532
537
|
this.client = client;
|
|
@@ -540,10 +545,60 @@ var Deferred = class {
|
|
|
540
545
|
return null;
|
|
541
546
|
}
|
|
542
547
|
}
|
|
548
|
+
/**
|
|
549
|
+
* Recover the link that led here, once.
|
|
550
|
+
*
|
|
551
|
+
* There is no Play Install Referrer on the web, so this is signal matching
|
|
552
|
+
* with the bookkeeping that makes calling it safe. That bookkeeping is the
|
|
553
|
+
* point: a claim is consumed the first time it succeeds, so an app calling
|
|
554
|
+
* claimBySignals on every page load asks again after the answer is already
|
|
555
|
+
* spent, and every one of those asks is recorded as a miss. The match rate on
|
|
556
|
+
* the dashboard then falls towards zero while the integration is working
|
|
557
|
+
* correctly, which is a hard thing to diagnose from the outside.
|
|
558
|
+
*
|
|
559
|
+
* Call it once on first run. Calling it again is free after the first.
|
|
560
|
+
*
|
|
561
|
+
* Named to match the Android, React Native and Flutter SDKs, where the same
|
|
562
|
+
* call also tries the install referrer before falling back to here.
|
|
563
|
+
*/
|
|
564
|
+
async claimDeferredLink(options) {
|
|
565
|
+
if (!options.appspaceId || !options.appspaceId.trim()) {
|
|
566
|
+
throw new Error("Tolinku: appspaceId is required and must not be blank for claimDeferredLink.");
|
|
567
|
+
}
|
|
568
|
+
if (!options.force && this.alreadyAttempted()) return null;
|
|
569
|
+
const { link, settled } = await this.attemptSignals({ appspaceId: options.appspaceId });
|
|
570
|
+
if (settled) this.rememberAttempt();
|
|
571
|
+
return link;
|
|
572
|
+
}
|
|
573
|
+
alreadyAttempted() {
|
|
574
|
+
try {
|
|
575
|
+
return window.localStorage.getItem(CLAIMED_KEY) !== null;
|
|
576
|
+
} catch {
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
rememberAttempt() {
|
|
581
|
+
try {
|
|
582
|
+
window.localStorage.setItem(CLAIMED_KEY, (/* @__PURE__ */ new Date()).toISOString());
|
|
583
|
+
} catch {
|
|
584
|
+
}
|
|
585
|
+
}
|
|
543
586
|
/** Claim a deferred deep link by device signal matching */
|
|
544
587
|
async claimBySignals(options) {
|
|
588
|
+
return (await this.attemptSignals(options)).link;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* The signal claim, with whether the server actually answered.
|
|
592
|
+
*
|
|
593
|
+
* `settled` separates "nothing is waiting for this device", which no amount
|
|
594
|
+
* of asking will change, from "the request never got there". Both surface as
|
|
595
|
+
* null to callers of claimBySignals, but claimDeferredLink has to tell them
|
|
596
|
+
* apart: recording an attempt that never reached the server would spend an
|
|
597
|
+
* install's one chance at attribution on a dropped connection.
|
|
598
|
+
*/
|
|
599
|
+
async attemptSignals(options) {
|
|
545
600
|
try {
|
|
546
|
-
|
|
601
|
+
const link = await this.client.postPublic("/v1/api/deferred/claim-by-signals", {
|
|
547
602
|
appspace_id: options.appspaceId,
|
|
548
603
|
timezone: options.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
549
604
|
language: options.language || navigator.language,
|
|
@@ -552,10 +607,11 @@ var Deferred = class {
|
|
|
552
607
|
// Separates devices reporting identical logical dimensions.
|
|
553
608
|
device_pixel_ratio: options.devicePixelRatio || window.devicePixelRatio || 1
|
|
554
609
|
});
|
|
610
|
+
return { link, settled: true };
|
|
555
611
|
} catch (err) {
|
|
556
612
|
const status = err?.statusCode ?? err?.status;
|
|
557
613
|
if (status === 404) {
|
|
558
|
-
return null;
|
|
614
|
+
return { link: null, settled: true };
|
|
559
615
|
}
|
|
560
616
|
if (status === 403) {
|
|
561
617
|
console.warn(
|
|
@@ -564,10 +620,10 @@ var Deferred = class {
|
|
|
564
620
|
"under Settings), not your subdomain or slug.",
|
|
565
621
|
err
|
|
566
622
|
);
|
|
567
|
-
return null;
|
|
623
|
+
return { link: null, settled: false };
|
|
568
624
|
}
|
|
569
625
|
console.warn("[Tolinku] Failed to claim deferred link by signals:", err);
|
|
570
|
-
return null;
|
|
626
|
+
return { link: null, settled: false };
|
|
571
627
|
}
|
|
572
628
|
}
|
|
573
629
|
};
|