@namiml/sdk-core 3.5.0-dev.202610272352 → 3.5.0-dev.202610311615
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.cjs +57 -2
- package/dist/index.d.ts +22 -1
- package/dist/index.mjs +57 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -106,7 +106,7 @@ const {
|
|
|
106
106
|
// version — stamped by scripts/version.sh
|
|
107
107
|
NAMI_SDK_VERSION: exports.NAMI_SDK_VERSION = "3.5.0",
|
|
108
108
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
109
|
-
NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.5.0-dev.
|
|
109
|
+
NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.5.0-dev.202610311615",
|
|
110
110
|
// environments
|
|
111
111
|
PRODUCTION: exports.PRODUCTION = "production", DEVELOPMENT: exports.DEVELOPMENT = "development",
|
|
112
112
|
// error messages
|
|
@@ -3110,7 +3110,11 @@ class PaywallBodyCache {
|
|
|
3110
3110
|
if (ttl === null)
|
|
3111
3111
|
return;
|
|
3112
3112
|
const expired = [...this.loadIndex().values()].filter((meta) => isExpired(meta, ttl, now));
|
|
3113
|
+
if (expired.length === 0)
|
|
3114
|
+
return;
|
|
3113
3115
|
this.dropPersisted(expired.map((meta) => meta.url));
|
|
3116
|
+
const oldestAge = ageSeconds(Math.min(...expired.map((meta) => meta.savedAt)), now);
|
|
3117
|
+
logger.debug(`Paywall body cache: evicted ${expired.length} expired entries (campaign_cache_ttl=${ttl}s, oldest_age=${oldestAge}s)`);
|
|
3114
3118
|
}
|
|
3115
3119
|
/**
|
|
3116
3120
|
* The entry stored under this exact URL, or null when there is none, it is past `ttl`, or its
|
|
@@ -3124,6 +3128,7 @@ class PaywallBodyCache {
|
|
|
3124
3128
|
return null;
|
|
3125
3129
|
if (ttl !== null && ttl > 0 && isExpired(meta, ttl, now)) {
|
|
3126
3130
|
this.dropPersisted([url]);
|
|
3131
|
+
logger.debug(`Paywall body cache: evicted expired entry on read (campaign_cache_ttl=${ttl}s, age=${ageSeconds(meta.savedAt, now)}s): ${url}`);
|
|
3127
3132
|
return null;
|
|
3128
3133
|
}
|
|
3129
3134
|
const body = this.read(PAYWALL_BODY_KEY_PREFIX + url);
|
|
@@ -3168,6 +3173,30 @@ class PaywallBodyCache {
|
|
|
3168
3173
|
const exists = this.memory ? this.memory.has(url) : this.loadIndex().has(url);
|
|
3169
3174
|
return exists ? false : this.store(url, contentHash, body, now);
|
|
3170
3175
|
}
|
|
3176
|
+
/**
|
|
3177
|
+
* Restarts the TTL window of a resolution's `content_hash` hits: the latest `campaign_rules` still
|
|
3178
|
+
* names each exact URL, and a `content_hash` is a pure function of the body, so the stored body is
|
|
3179
|
+
* still the current one. Rewrites only the metadata key (the body is untouched) and skips absent
|
|
3180
|
+
* entries. A renew that does not land keeps the old `savedAt`, which is harmless. Nothing is
|
|
3181
|
+
* renewed under `null` (never ages) or `0` (memory only). Returns the number of entries renewed.
|
|
3182
|
+
*/
|
|
3183
|
+
renew(urls, ttl, now = Date.now()) {
|
|
3184
|
+
if (ttl === null || ttl <= 0 || this.memory)
|
|
3185
|
+
return 0;
|
|
3186
|
+
const index = this.loadIndex();
|
|
3187
|
+
let renewed = 0;
|
|
3188
|
+
for (const url of urls) {
|
|
3189
|
+
const meta = index.get(url);
|
|
3190
|
+
if (!meta)
|
|
3191
|
+
continue;
|
|
3192
|
+
const fresh = { ...meta, savedAt: now };
|
|
3193
|
+
if (this.write(PAYWALL_BODY_META_KEY_PREFIX + url, JSON.stringify(fresh))) {
|
|
3194
|
+
index.set(url, fresh);
|
|
3195
|
+
renewed += 1;
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
return renewed;
|
|
3199
|
+
}
|
|
3171
3200
|
/** Deletes one entry — used for an undecodable body. Not eviction. */
|
|
3172
3201
|
remove(url) {
|
|
3173
3202
|
if (this.memory)
|
|
@@ -3186,7 +3215,11 @@ class PaywallBodyCache {
|
|
|
3186
3215
|
const unnamed = metas.filter((meta) => !currentUrls.has(meta.url)).map((meta) => meta.url);
|
|
3187
3216
|
const kept = metas.filter((meta) => currentUrls.has(meta.url)).sort((a, b) => a.savedAt - b.savedAt);
|
|
3188
3217
|
const overCap = kept.slice(0, Math.max(0, kept.length - this.maxEntries)).map((meta) => meta.url);
|
|
3218
|
+
if (unnamed.length === 0 && overCap.length === 0)
|
|
3219
|
+
return;
|
|
3189
3220
|
[...unnamed, ...overCap].forEach((url) => this.remove(url));
|
|
3221
|
+
logger.debug(`Paywall body cache: evicted ${unnamed.length} entries no longer named by campaign_rules, ` +
|
|
3222
|
+
`${overCap.length} over the ${this.maxEntries}-entry cap`);
|
|
3190
3223
|
}
|
|
3191
3224
|
/** Empties the store — persisted and in-memory entries alike. Called by `Nami.reset()`. */
|
|
3192
3225
|
purgeAll() {
|
|
@@ -3259,6 +3292,10 @@ class PaywallBodyCache {
|
|
|
3259
3292
|
function isExpired(meta, ttlSeconds, now) {
|
|
3260
3293
|
return (now - meta.savedAt) / 1000 >= ttlSeconds;
|
|
3261
3294
|
}
|
|
3295
|
+
/** Whole seconds since `savedAt` (epoch ms), as the cross-SDK eviction logs print it. */
|
|
3296
|
+
function ageSeconds(savedAt, now) {
|
|
3297
|
+
return Math.floor((now - savedAt) / 1000);
|
|
3298
|
+
}
|
|
3262
3299
|
function parseMeta(raw) {
|
|
3263
3300
|
if (raw === null)
|
|
3264
3301
|
return null;
|
|
@@ -58362,6 +58399,7 @@ class PaywallRepository {
|
|
|
58362
58399
|
cacheAfterFetchFailure: 0,
|
|
58363
58400
|
failed: 0,
|
|
58364
58401
|
retryCount: 0,
|
|
58402
|
+
renewableUrls: [],
|
|
58365
58403
|
};
|
|
58366
58404
|
const resolvedUrls = new Map();
|
|
58367
58405
|
resolutions.forEach((resolution, i) => {
|
|
@@ -58371,8 +58409,11 @@ class PaywallRepository {
|
|
|
58371
58409
|
return;
|
|
58372
58410
|
}
|
|
58373
58411
|
resolvedUrls.set(resolution.paywall, uniqueUrls[i]);
|
|
58374
|
-
if (resolution.paywall.fetchSource === "cacheHit")
|
|
58412
|
+
if (resolution.paywall.fetchSource === "cacheHit") {
|
|
58375
58413
|
outcome.cacheHits += 1;
|
|
58414
|
+
if (contentHashOf(uniqueUrls[i]))
|
|
58415
|
+
outcome.renewableUrls.push(uniqueUrls[i]);
|
|
58416
|
+
}
|
|
58376
58417
|
else if (resolution.paywall.fetchSource === "cacheAfterFetchFailure")
|
|
58377
58418
|
outcome.cacheAfterFetchFailure += 1;
|
|
58378
58419
|
else
|
|
@@ -58384,6 +58425,16 @@ class PaywallRepository {
|
|
|
58384
58425
|
}
|
|
58385
58426
|
return outcome;
|
|
58386
58427
|
}
|
|
58428
|
+
/**
|
|
58429
|
+
* Sliding expiry (§ 2.2 → TTL): under `campaign_cache_ttl > 0`, renews the `savedAt` of every
|
|
58430
|
+
* `content_hash` hit in one batch, so an entry expires only once no resolution has named it for a
|
|
58431
|
+
* full TTL. Un-hashed URLs never renew — nothing vouches that their stored body is current. The
|
|
58432
|
+
* caller runs this after reconcile, and only after a resolution that ran on `campaign_rules` from
|
|
58433
|
+
* the network, so a stale stored copy of the rules can never keep entries alive.
|
|
58434
|
+
*/
|
|
58435
|
+
renewCacheHits(outcome) {
|
|
58436
|
+
this.bodyCache.renew(outcome.renewableUrls, getCampaignCacheTtl());
|
|
58437
|
+
}
|
|
58387
58438
|
/**
|
|
58388
58439
|
* Seeds the body cache from the initial-config bundle (§ 2.2 "Seeding"): every **hashed** bundled
|
|
58389
58440
|
* URL whose paywall id matches a bundled body is stored under that exact URL unless an entry
|
|
@@ -62675,6 +62726,10 @@ class NamiRefs {
|
|
|
62675
62726
|
`campaigns=${campaignRulesDuration}ms, paywalls=${paywallsDuration}ms` +
|
|
62676
62727
|
`${outcome ? `, retry_count=${outcome.retryCount}` : ""}`);
|
|
62677
62728
|
}
|
|
62729
|
+
// After reconcile and the telemetry line, in one batch. `outcome` is set only when the rules
|
|
62730
|
+
// came from the network, so a stored copy of them never renews an entry.
|
|
62731
|
+
if (outcome)
|
|
62732
|
+
paywallRepo.renewCacheHits(outcome);
|
|
62678
62733
|
return campaignRepo.finalizeCampaignRules(rawCampaigns, paywalls);
|
|
62679
62734
|
}
|
|
62680
62735
|
reRenderPaywall() {
|
package/dist/index.d.ts
CHANGED
|
@@ -3862,12 +3862,15 @@ declare class EntitlementRepository {
|
|
|
3862
3862
|
* 2026-09-28, NFL Web Prod's largest set is 66 bodies / 2.1 MB, well inside localStorage's ~5 MB;
|
|
3863
3863
|
* a second copy beside an aggregate would have doubled that. Under `campaign_cache_ttl == 0`
|
|
3864
3864
|
* entries are held in memory instead. Every storage failure degrades to "not cached".
|
|
3865
|
+
*
|
|
3866
|
+
* Cache hits on `content_hash` URLs renew their entries (`renew`), so an entry expires only once
|
|
3867
|
+
* no resolution has named it for a full TTL (sliding expiry, NAM-5368). Every eviction is logged.
|
|
3865
3868
|
*/
|
|
3866
3869
|
type PaywallBodyMeta = {
|
|
3867
3870
|
url: string;
|
|
3868
3871
|
/** The URL's `content_hash`, absent for an un-hashed URL. */
|
|
3869
3872
|
contentHash?: string;
|
|
3870
|
-
/** Epoch milliseconds at which this entry was stored. */
|
|
3873
|
+
/** Epoch milliseconds at which this entry was stored, or last renewed by a cache hit. */
|
|
3871
3874
|
savedAt: number;
|
|
3872
3875
|
};
|
|
3873
3876
|
type PaywallBodyEntry = {
|
|
@@ -3904,6 +3907,14 @@ declare class PaywallBodyCache {
|
|
|
3904
3907
|
store(url: string, contentHash: string | undefined, body: string, now?: number): boolean;
|
|
3905
3908
|
/** Stores a bundled body unless an entry already exists — a body the SDK fetched always wins. */
|
|
3906
3909
|
seedIfAbsent(url: string, contentHash: string | undefined, body: string, now?: number): boolean;
|
|
3910
|
+
/**
|
|
3911
|
+
* Restarts the TTL window of a resolution's `content_hash` hits: the latest `campaign_rules` still
|
|
3912
|
+
* names each exact URL, and a `content_hash` is a pure function of the body, so the stored body is
|
|
3913
|
+
* still the current one. Rewrites only the metadata key (the body is untouched) and skips absent
|
|
3914
|
+
* entries. A renew that does not land keeps the old `savedAt`, which is harmless. Nothing is
|
|
3915
|
+
* renewed under `null` (never ages) or `0` (memory only). Returns the number of entries renewed.
|
|
3916
|
+
*/
|
|
3917
|
+
renew(urls: string[], ttl: number | null, now?: number): number;
|
|
3907
3918
|
/** Deletes one entry — used for an undecodable body. Not eviction. */
|
|
3908
3919
|
remove(url: string): void;
|
|
3909
3920
|
/**
|
|
@@ -3933,6 +3944,8 @@ type PaywallResolutionOutcome = {
|
|
|
3933
3944
|
cacheAfterFetchFailure: number;
|
|
3934
3945
|
failed: number;
|
|
3935
3946
|
retryCount: number;
|
|
3947
|
+
/** Hit-row URLs that carry a `content_hash`: the entries `renewCacheHits` renews. */
|
|
3948
|
+
renewableUrls: string[];
|
|
3936
3949
|
};
|
|
3937
3950
|
declare class PaywallRepository {
|
|
3938
3951
|
private readonly bodyCache;
|
|
@@ -3959,6 +3972,14 @@ declare class PaywallRepository {
|
|
|
3959
3972
|
* after a complete `campaign_rules` fetch.
|
|
3960
3973
|
*/
|
|
3961
3974
|
resolvePaywallsByUrls(urls: string[]): Promise<PaywallResolutionOutcome>;
|
|
3975
|
+
/**
|
|
3976
|
+
* Sliding expiry (§ 2.2 → TTL): under `campaign_cache_ttl > 0`, renews the `savedAt` of every
|
|
3977
|
+
* `content_hash` hit in one batch, so an entry expires only once no resolution has named it for a
|
|
3978
|
+
* full TTL. Un-hashed URLs never renew — nothing vouches that their stored body is current. The
|
|
3979
|
+
* caller runs this after reconcile, and only after a resolution that ran on `campaign_rules` from
|
|
3980
|
+
* the network, so a stale stored copy of the rules can never keep entries alive.
|
|
3981
|
+
*/
|
|
3982
|
+
renewCacheHits(outcome: PaywallResolutionOutcome): void;
|
|
3962
3983
|
/**
|
|
3963
3984
|
* Seeds the body cache from the initial-config bundle (§ 2.2 "Seeding"): every **hashed** bundled
|
|
3964
3985
|
* URL whose paywall id matches a bundled body is stored under that exact URL unless an entry
|
package/dist/index.mjs
CHANGED
|
@@ -104,7 +104,7 @@ const {
|
|
|
104
104
|
// version — stamped by scripts/version.sh
|
|
105
105
|
NAMI_SDK_VERSION = "3.5.0",
|
|
106
106
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
107
|
-
NAMI_SDK_PACKAGE_VERSION = "3.5.0-dev.
|
|
107
|
+
NAMI_SDK_PACKAGE_VERSION = "3.5.0-dev.202610311615",
|
|
108
108
|
// environments
|
|
109
109
|
PRODUCTION = "production", DEVELOPMENT = "development",
|
|
110
110
|
// error messages
|
|
@@ -3108,7 +3108,11 @@ class PaywallBodyCache {
|
|
|
3108
3108
|
if (ttl === null)
|
|
3109
3109
|
return;
|
|
3110
3110
|
const expired = [...this.loadIndex().values()].filter((meta) => isExpired(meta, ttl, now));
|
|
3111
|
+
if (expired.length === 0)
|
|
3112
|
+
return;
|
|
3111
3113
|
this.dropPersisted(expired.map((meta) => meta.url));
|
|
3114
|
+
const oldestAge = ageSeconds(Math.min(...expired.map((meta) => meta.savedAt)), now);
|
|
3115
|
+
logger.debug(`Paywall body cache: evicted ${expired.length} expired entries (campaign_cache_ttl=${ttl}s, oldest_age=${oldestAge}s)`);
|
|
3112
3116
|
}
|
|
3113
3117
|
/**
|
|
3114
3118
|
* The entry stored under this exact URL, or null when there is none, it is past `ttl`, or its
|
|
@@ -3122,6 +3126,7 @@ class PaywallBodyCache {
|
|
|
3122
3126
|
return null;
|
|
3123
3127
|
if (ttl !== null && ttl > 0 && isExpired(meta, ttl, now)) {
|
|
3124
3128
|
this.dropPersisted([url]);
|
|
3129
|
+
logger.debug(`Paywall body cache: evicted expired entry on read (campaign_cache_ttl=${ttl}s, age=${ageSeconds(meta.savedAt, now)}s): ${url}`);
|
|
3125
3130
|
return null;
|
|
3126
3131
|
}
|
|
3127
3132
|
const body = this.read(PAYWALL_BODY_KEY_PREFIX + url);
|
|
@@ -3166,6 +3171,30 @@ class PaywallBodyCache {
|
|
|
3166
3171
|
const exists = this.memory ? this.memory.has(url) : this.loadIndex().has(url);
|
|
3167
3172
|
return exists ? false : this.store(url, contentHash, body, now);
|
|
3168
3173
|
}
|
|
3174
|
+
/**
|
|
3175
|
+
* Restarts the TTL window of a resolution's `content_hash` hits: the latest `campaign_rules` still
|
|
3176
|
+
* names each exact URL, and a `content_hash` is a pure function of the body, so the stored body is
|
|
3177
|
+
* still the current one. Rewrites only the metadata key (the body is untouched) and skips absent
|
|
3178
|
+
* entries. A renew that does not land keeps the old `savedAt`, which is harmless. Nothing is
|
|
3179
|
+
* renewed under `null` (never ages) or `0` (memory only). Returns the number of entries renewed.
|
|
3180
|
+
*/
|
|
3181
|
+
renew(urls, ttl, now = Date.now()) {
|
|
3182
|
+
if (ttl === null || ttl <= 0 || this.memory)
|
|
3183
|
+
return 0;
|
|
3184
|
+
const index = this.loadIndex();
|
|
3185
|
+
let renewed = 0;
|
|
3186
|
+
for (const url of urls) {
|
|
3187
|
+
const meta = index.get(url);
|
|
3188
|
+
if (!meta)
|
|
3189
|
+
continue;
|
|
3190
|
+
const fresh = { ...meta, savedAt: now };
|
|
3191
|
+
if (this.write(PAYWALL_BODY_META_KEY_PREFIX + url, JSON.stringify(fresh))) {
|
|
3192
|
+
index.set(url, fresh);
|
|
3193
|
+
renewed += 1;
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
return renewed;
|
|
3197
|
+
}
|
|
3169
3198
|
/** Deletes one entry — used for an undecodable body. Not eviction. */
|
|
3170
3199
|
remove(url) {
|
|
3171
3200
|
if (this.memory)
|
|
@@ -3184,7 +3213,11 @@ class PaywallBodyCache {
|
|
|
3184
3213
|
const unnamed = metas.filter((meta) => !currentUrls.has(meta.url)).map((meta) => meta.url);
|
|
3185
3214
|
const kept = metas.filter((meta) => currentUrls.has(meta.url)).sort((a, b) => a.savedAt - b.savedAt);
|
|
3186
3215
|
const overCap = kept.slice(0, Math.max(0, kept.length - this.maxEntries)).map((meta) => meta.url);
|
|
3216
|
+
if (unnamed.length === 0 && overCap.length === 0)
|
|
3217
|
+
return;
|
|
3187
3218
|
[...unnamed, ...overCap].forEach((url) => this.remove(url));
|
|
3219
|
+
logger.debug(`Paywall body cache: evicted ${unnamed.length} entries no longer named by campaign_rules, ` +
|
|
3220
|
+
`${overCap.length} over the ${this.maxEntries}-entry cap`);
|
|
3188
3221
|
}
|
|
3189
3222
|
/** Empties the store — persisted and in-memory entries alike. Called by `Nami.reset()`. */
|
|
3190
3223
|
purgeAll() {
|
|
@@ -3257,6 +3290,10 @@ class PaywallBodyCache {
|
|
|
3257
3290
|
function isExpired(meta, ttlSeconds, now) {
|
|
3258
3291
|
return (now - meta.savedAt) / 1000 >= ttlSeconds;
|
|
3259
3292
|
}
|
|
3293
|
+
/** Whole seconds since `savedAt` (epoch ms), as the cross-SDK eviction logs print it. */
|
|
3294
|
+
function ageSeconds(savedAt, now) {
|
|
3295
|
+
return Math.floor((now - savedAt) / 1000);
|
|
3296
|
+
}
|
|
3260
3297
|
function parseMeta(raw) {
|
|
3261
3298
|
if (raw === null)
|
|
3262
3299
|
return null;
|
|
@@ -58360,6 +58397,7 @@ class PaywallRepository {
|
|
|
58360
58397
|
cacheAfterFetchFailure: 0,
|
|
58361
58398
|
failed: 0,
|
|
58362
58399
|
retryCount: 0,
|
|
58400
|
+
renewableUrls: [],
|
|
58363
58401
|
};
|
|
58364
58402
|
const resolvedUrls = new Map();
|
|
58365
58403
|
resolutions.forEach((resolution, i) => {
|
|
@@ -58369,8 +58407,11 @@ class PaywallRepository {
|
|
|
58369
58407
|
return;
|
|
58370
58408
|
}
|
|
58371
58409
|
resolvedUrls.set(resolution.paywall, uniqueUrls[i]);
|
|
58372
|
-
if (resolution.paywall.fetchSource === "cacheHit")
|
|
58410
|
+
if (resolution.paywall.fetchSource === "cacheHit") {
|
|
58373
58411
|
outcome.cacheHits += 1;
|
|
58412
|
+
if (contentHashOf(uniqueUrls[i]))
|
|
58413
|
+
outcome.renewableUrls.push(uniqueUrls[i]);
|
|
58414
|
+
}
|
|
58374
58415
|
else if (resolution.paywall.fetchSource === "cacheAfterFetchFailure")
|
|
58375
58416
|
outcome.cacheAfterFetchFailure += 1;
|
|
58376
58417
|
else
|
|
@@ -58382,6 +58423,16 @@ class PaywallRepository {
|
|
|
58382
58423
|
}
|
|
58383
58424
|
return outcome;
|
|
58384
58425
|
}
|
|
58426
|
+
/**
|
|
58427
|
+
* Sliding expiry (§ 2.2 → TTL): under `campaign_cache_ttl > 0`, renews the `savedAt` of every
|
|
58428
|
+
* `content_hash` hit in one batch, so an entry expires only once no resolution has named it for a
|
|
58429
|
+
* full TTL. Un-hashed URLs never renew — nothing vouches that their stored body is current. The
|
|
58430
|
+
* caller runs this after reconcile, and only after a resolution that ran on `campaign_rules` from
|
|
58431
|
+
* the network, so a stale stored copy of the rules can never keep entries alive.
|
|
58432
|
+
*/
|
|
58433
|
+
renewCacheHits(outcome) {
|
|
58434
|
+
this.bodyCache.renew(outcome.renewableUrls, getCampaignCacheTtl());
|
|
58435
|
+
}
|
|
58385
58436
|
/**
|
|
58386
58437
|
* Seeds the body cache from the initial-config bundle (§ 2.2 "Seeding"): every **hashed** bundled
|
|
58387
58438
|
* URL whose paywall id matches a bundled body is stored under that exact URL unless an entry
|
|
@@ -62673,6 +62724,10 @@ class NamiRefs {
|
|
|
62673
62724
|
`campaigns=${campaignRulesDuration}ms, paywalls=${paywallsDuration}ms` +
|
|
62674
62725
|
`${outcome ? `, retry_count=${outcome.retryCount}` : ""}`);
|
|
62675
62726
|
}
|
|
62727
|
+
// After reconcile and the telemetry line, in one batch. `outcome` is set only when the rules
|
|
62728
|
+
// came from the network, so a stored copy of them never renews an entry.
|
|
62729
|
+
if (outcome)
|
|
62730
|
+
paywallRepo.renewCacheHits(outcome);
|
|
62676
62731
|
return campaignRepo.finalizeCampaignRules(rawCampaigns, paywalls);
|
|
62677
62732
|
}
|
|
62678
62733
|
reRenderPaywall() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namiml/sdk-core",
|
|
3
|
-
"version": "3.5.0-dev.
|
|
3
|
+
"version": "3.5.0-dev.202610311615",
|
|
4
4
|
"description": "Platform-agnostic core for the Nami SDK — business logic, API, types, and state management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|