@namiml/sdk-core 3.4.12-dev.202609251500 → 3.4.12-dev.202609252349
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 +247 -18
- package/dist/index.d.ts +107 -2
- package/dist/index.mjs +248 -19
- 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.4.12",
|
|
108
108
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
109
|
-
NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.12-dev.
|
|
109
|
+
NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.12-dev.202609252349",
|
|
110
110
|
// environments
|
|
111
111
|
PRODUCTION: exports.PRODUCTION = "production", DEVELOPMENT: exports.DEVELOPMENT = "development",
|
|
112
112
|
// error messages
|
|
@@ -116,7 +116,19 @@ AUTH_DEVICE: exports.AUTH_DEVICE = "nami_auth_device", NAMI_CONFIGURATION: expor
|
|
|
116
116
|
// API settings
|
|
117
117
|
API_VERSION: exports.API_VERSION = "v3", BASE_URL_PATH: exports.BASE_URL_PATH = `sdk/${exports.API_VERSION}/platform`, BASE_URL: exports.BASE_URL = "https://app.namiml.com", BASE_STAGING_URL: exports.BASE_STAGING_URL = "https://app-staging.namiml.com", CUSTOM_HOST_PREFIX: exports.CUSTOM_HOST_PREFIX = "namiAPIHost=", USE_STAGING_API: exports.USE_STAGING_API = "useStagingAPI",
|
|
118
118
|
// // extended client info
|
|
119
|
-
EXTENDED_CLIENT_INFO_PREFIX: exports.EXTENDED_CLIENT_INFO_PREFIX = "extendedClientInfo", EXTENDED_CLIENT_INFO_DELIMITER: exports.EXTENDED_CLIENT_INFO_DELIMITER = ":", VALIDATE_PRODUCT_GROUPS: exports.VALIDATE_PRODUCT_GROUPS = "validateProductGroups", LOG_HTTP_REQUESTS: exports.LOG_HTTP_REQUESTS = "logHTTPRequests", LOG_HTTP_TRAFFIC: exports.LOG_HTTP_TRAFFIC = "logHTTPTraffic", API_TRAFFIC_OBSERVER: exports.API_TRAFFIC_OBSERVER = "apiTrafficObserver", STARTUP_TELEMETRY: exports.STARTUP_TELEMETRY = "startupTelemetry",
|
|
119
|
+
EXTENDED_CLIENT_INFO_PREFIX: exports.EXTENDED_CLIENT_INFO_PREFIX = "extendedClientInfo", EXTENDED_CLIENT_INFO_DELIMITER: exports.EXTENDED_CLIENT_INFO_DELIMITER = ":", VALIDATE_PRODUCT_GROUPS: exports.VALIDATE_PRODUCT_GROUPS = "validateProductGroups", LOG_HTTP_REQUESTS: exports.LOG_HTTP_REQUESTS = "logHTTPRequests", LOG_HTTP_TRAFFIC: exports.LOG_HTTP_TRAFFIC = "logHTTPTraffic", API_TRAFFIC_OBSERVER: exports.API_TRAFFIC_OBSERVER = "apiTrafficObserver", STARTUP_TELEMETRY: exports.STARTUP_TELEMETRY = "startupTelemetry",
|
|
120
|
+
// Test hook: every platform-config fetch attempt fails before the request leaves.
|
|
121
|
+
// Same namiCommand as Apple's and Android's, so the shared first-run flows drive it.
|
|
122
|
+
SIMULATE_CONFIG_FETCH_FAILURE: exports.SIMULATE_CONFIG_FETCH_FAILURE = "simulateConfigFetchFailure", EXTENDED_PLATFORM: exports.EXTENDED_PLATFORM = "extended-platform", EXTENDED_PLATFORM_VERSION: exports.EXTENDED_PLATFORM_VERSION = "extended-platform-version", API_MAX_CALLS_LIMIT: exports.API_MAX_CALLS_LIMIT = 2, API_RETRY_DELAY_SEC: exports.API_RETRY_DELAY_SEC = 2, API_TIMEOUT_LIMIT: exports.API_TIMEOUT_LIMIT = 20000, DEVICE_API_TIMEOUT_LIMIT: exports.DEVICE_API_TIMEOUT_LIMIT = 2000,
|
|
123
|
+
// Platform-config attempts when no initial config was supplied (Android's
|
|
124
|
+
// CONFIG_MAX_ATTEMPTS; Apple's retry(maxAttempts: 3)).
|
|
125
|
+
CONFIG_MAX_ATTEMPTS: exports.CONFIG_MAX_ATTEMPTS = 3,
|
|
126
|
+
// Per-attempt timeout for GET config/. Android's config client allows 5 s to connect plus 5 s
|
|
127
|
+
// to read (Apple allows 30 s); three attempts keep a total outage near 30 s.
|
|
128
|
+
CONFIG_API_TIMEOUT_LIMIT: exports.CONFIG_API_TIMEOUT_LIMIT = 10000,
|
|
129
|
+
// A foreground within this long of the last launch/resume run is skipped — Apple's
|
|
130
|
+
// NamiStartupCoordinator.shouldRunResume window.
|
|
131
|
+
RESUME_THROTTLE_MS: exports.RESUME_THROTTLE_MS = 30000,
|
|
120
132
|
// status codes
|
|
121
133
|
STATUS_SUCCESS: exports.STATUS_SUCCESS = 200, STATUS_BAD_REQUEST: exports.STATUS_BAD_REQUEST = 400, STATUS_NOT_FOUND: exports.STATUS_NOT_FOUND = 404, STATUS_CONFLICT: exports.STATUS_CONFLICT = 409, STATUS_INTERNAL_SERVER_ERROR: exports.STATUS_INTERNAL_SERVER_ERROR = 500,
|
|
122
134
|
// configuration states
|
|
@@ -58033,27 +58045,125 @@ class PaywallRepository {
|
|
|
58033
58045
|
PaywallRepository.instance = new PaywallRepository();
|
|
58034
58046
|
|
|
58035
58047
|
class ConfigRepository {
|
|
58048
|
+
/**
|
|
58049
|
+
* One `GET config/` attempt. Persists the config on success and throws on any failure —
|
|
58050
|
+
* a non-2xx or a transport error alike. `withRetry`'s own retries are turned off, so the
|
|
58051
|
+
* attempt count belongs to {@link fetchConfigForStartup} alone.
|
|
58052
|
+
*/
|
|
58036
58053
|
async fetchConfig() {
|
|
58037
|
-
|
|
58038
|
-
|
|
58039
|
-
|
|
58040
|
-
;
|
|
58041
|
-
}
|
|
58042
|
-
catch (error) {
|
|
58043
|
-
data = storageService.getAppConfig(exports.API_CONFIG)
|
|
58044
|
-
|| storageService.getAppConfig(exports.INITIAL_APP_CONFIG);
|
|
58045
|
-
if (!data) {
|
|
58046
|
-
logger.error(handleErrors(error.status, "config/"));
|
|
58047
|
-
throw error;
|
|
58048
|
-
}
|
|
58054
|
+
// Thrown from *inside* the attempt on purpose, like Apple's and Android's: the ladder then
|
|
58055
|
+
// treats it exactly as a real 500, which is the whole point of the mock.
|
|
58056
|
+
if (storageService.getNamiConfig()?.namiCommands?.includes(exports.SIMULATE_CONFIG_FETCH_FAILURE)) {
|
|
58057
|
+
throw new RetryLimitExceededError(exports.STATUS_INTERNAL_SERVER_ERROR, exports.SIMULATE_CONFIG_FETCH_FAILURE);
|
|
58049
58058
|
}
|
|
58050
|
-
|
|
58059
|
+
const platformId = storageService.getNamiConfig()?.appPlatformID;
|
|
58060
|
+
const data = await NamiAPI.instance.fetchAPI("config/", exports.CONFIG_API_TIMEOUT_LIMIT, 0);
|
|
58061
|
+
// A late answer (the startup await gave up on it) must not overwrite another platform's
|
|
58062
|
+
// config after a reset or a platform-switching reconfigure.
|
|
58063
|
+
if (storageService.getNamiConfig()?.appPlatformID === platformId) {
|
|
58051
58064
|
storageService.setAppConfig(exports.API_CONFIG, data);
|
|
58052
58065
|
}
|
|
58066
|
+
else {
|
|
58067
|
+
logger.debug("Discarding an app config response for a platform that is no longer configured");
|
|
58068
|
+
}
|
|
58053
58069
|
return data;
|
|
58054
58070
|
}
|
|
58071
|
+
/**
|
|
58072
|
+
* The startup platform-config step, converged on Apple's `NamiPlatformConfigService.fetch` and
|
|
58073
|
+
* Android's `fetchAppConfigOnce` (NAM-4470, NAM-4589):
|
|
58074
|
+
*
|
|
58075
|
+
* | case | outcome |
|
|
58076
|
+
* |---|---|
|
|
58077
|
+
* | an initial config was supplied | NOT awaited: one attempt runs in the background and stores the config when it lands; usable |
|
|
58078
|
+
* | no initial config, success, capabilities include `sdk` | usable |
|
|
58079
|
+
* | no initial config, success, capabilities lack `sdk` | not usable |
|
|
58080
|
+
* | no initial config, failure | {@link CONFIG_MAX_ATTEMPTS} attempts of up to {@link CONFIG_API_TIMEOUT_LIMIT} each, then usable only if a config is cached (and grants `sdk`) |
|
|
58081
|
+
*
|
|
58082
|
+
* The two fallbacks are consulted at two different points, deliberately. An initial config
|
|
58083
|
+
* decides the case *before* any request: startup does not wait on the network at all, since the
|
|
58084
|
+
* initial config is what makes the SDK ready without it (Apple: "Initial config is available.
|
|
58085
|
+
* Skipping retry."). The config cached by a previous launch is consulted only *after* the
|
|
58086
|
+
* retries run out. A stored `INITIAL_APP_CONFIG` is not that cache.
|
|
58087
|
+
*
|
|
58088
|
+
* One check does apply with an initial config, because it costs no wait: a cached config that
|
|
58089
|
+
* withholds `sdk` still stops startup, as Apple's cache load re-applies `updateSdkFlags`.
|
|
58090
|
+
* Without it a kill switch could never reach an app that ships an initial config — the
|
|
58091
|
+
* background fetch lands after startup has already run, so it takes effect from the next launch.
|
|
58092
|
+
*
|
|
58093
|
+
* A `404` is treated as any other 4xx, matching Apple's effective behaviour (its dedicated 404
|
|
58094
|
+
* branch is unreachable, NAM-4471) and Android's.
|
|
58095
|
+
*
|
|
58096
|
+
* @param hasInitialConfig whether the host passed an `initialConfig` that decoded to content.
|
|
58097
|
+
*/
|
|
58098
|
+
async fetchConfigForStartup(hasInitialConfig) {
|
|
58099
|
+
if (hasInitialConfig)
|
|
58100
|
+
return this.startupOnInitialConfig();
|
|
58101
|
+
const maxAttempts = exports.CONFIG_MAX_ATTEMPTS;
|
|
58102
|
+
let lastError;
|
|
58103
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
58104
|
+
if (attempt > 1) {
|
|
58105
|
+
logger.debug(`Retrying app config fetch (attempt ${attempt} of ${maxAttempts})`);
|
|
58106
|
+
}
|
|
58107
|
+
try {
|
|
58108
|
+
return outcomeOf(await this.fetchConfig());
|
|
58109
|
+
}
|
|
58110
|
+
catch (error) {
|
|
58111
|
+
lastError = error;
|
|
58112
|
+
}
|
|
58113
|
+
}
|
|
58114
|
+
const cached = storageService.getAppConfig(exports.API_CONFIG);
|
|
58115
|
+
if (cached) {
|
|
58116
|
+
// A cached kill switch still holds: Apple re-applies `updateSdkFlags` when it loads the
|
|
58117
|
+
// cached config, so one that withheld `sdk` keeps the SDK disabled through an outage.
|
|
58118
|
+
if (!grantsSdk(cached)) {
|
|
58119
|
+
return { usable: false, reason: "the cached app config does not grant the 'sdk' capability" };
|
|
58120
|
+
}
|
|
58121
|
+
logger.info(`App config fetch failed after ${maxAttempts} attempts - continuing on the cached config`);
|
|
58122
|
+
return { usable: true };
|
|
58123
|
+
}
|
|
58124
|
+
return {
|
|
58125
|
+
usable: false,
|
|
58126
|
+
reason: `app config fetch failed after ${maxAttempts} attempts (${describeFailure(lastError)}) ` +
|
|
58127
|
+
"and no initial or cached config is available",
|
|
58128
|
+
};
|
|
58129
|
+
}
|
|
58130
|
+
/**
|
|
58131
|
+
* The initial-config case: nothing is awaited. The cached kill switch is a storage read; the
|
|
58132
|
+
* config request is left running and persists its answer (`fetchConfig`) when it lands.
|
|
58133
|
+
*/
|
|
58134
|
+
startupOnInitialConfig() {
|
|
58135
|
+
// Read before the request can land, so this launch is judged on what the last one stored.
|
|
58136
|
+
const cached = storageService.getAppConfig(exports.API_CONFIG);
|
|
58137
|
+
// Issued even when the cache holds a kill switch: that is how a LIFTED kill switch reaches
|
|
58138
|
+
// the next launch.
|
|
58139
|
+
this.fetchConfig().then((config) => {
|
|
58140
|
+
if (!grantsSdk(config)) {
|
|
58141
|
+
logger.warn("App config does not grant the 'sdk' capability - it takes effect from the next launch");
|
|
58142
|
+
}
|
|
58143
|
+
}, (error) => {
|
|
58144
|
+
logger.info(`App config fetch failed (${describeFailure(error)}). Initial config is available. Skipping retry.`);
|
|
58145
|
+
});
|
|
58146
|
+
if (cached && !grantsSdk(cached)) {
|
|
58147
|
+
return { usable: false, reason: "the cached app config does not grant the 'sdk' capability" };
|
|
58148
|
+
}
|
|
58149
|
+
return { usable: true };
|
|
58150
|
+
}
|
|
58055
58151
|
}
|
|
58056
58152
|
ConfigRepository.instance = new ConfigRepository();
|
|
58153
|
+
function outcomeOf(config) {
|
|
58154
|
+
return grantsSdk(config)
|
|
58155
|
+
? { usable: true }
|
|
58156
|
+
: { usable: false, reason: "app config does not grant the 'sdk' capability" };
|
|
58157
|
+
}
|
|
58158
|
+
function grantsSdk(config) {
|
|
58159
|
+
return config.capabilities?.includes(exports.Capabilities.SDK) ?? false;
|
|
58160
|
+
}
|
|
58161
|
+
function describeFailure(error) {
|
|
58162
|
+
const status = error?.status;
|
|
58163
|
+
if (typeof status === "number")
|
|
58164
|
+
return `HTTP ${status}`;
|
|
58165
|
+
return error instanceof Error ? error.message : String(error);
|
|
58166
|
+
}
|
|
58057
58167
|
|
|
58058
58168
|
// Global reference to avoid circular imports
|
|
58059
58169
|
let namiRefsInstance = null;
|
|
@@ -60779,6 +60889,7 @@ const initialState = {
|
|
|
60779
60889
|
isLoggedIn: false,
|
|
60780
60890
|
darkMode: false,
|
|
60781
60891
|
safeAreaTop: 0,
|
|
60892
|
+
safeAreaBottom: 0,
|
|
60782
60893
|
groups: [],
|
|
60783
60894
|
selectedProducts: {},
|
|
60784
60895
|
formStates: {},
|
|
@@ -61147,6 +61258,9 @@ class PaywallState extends SimpleEventTarget {
|
|
|
61147
61258
|
setSafeAreaTop(safeAreaTop) {
|
|
61148
61259
|
this.setState({ ...this.state, safeAreaTop });
|
|
61149
61260
|
}
|
|
61261
|
+
setSafeAreaBottom(safeAreaBottom) {
|
|
61262
|
+
this.setState({ ...this.state, safeAreaBottom });
|
|
61263
|
+
}
|
|
61150
61264
|
setFullScreenPresentation(fullScreenPresentation) {
|
|
61151
61265
|
this.setState({ ...this.state, fullScreenPresentation });
|
|
61152
61266
|
}
|
|
@@ -61593,6 +61707,15 @@ class NamiRefs {
|
|
|
61593
61707
|
this.inMemoryAnonymousMode = false;
|
|
61594
61708
|
// Captured before device registration; true only on genuine fresh installs
|
|
61595
61709
|
this.isFirstSession = false;
|
|
61710
|
+
// Set when the platform-config step leaves no usable config (see isStartupDisabled)
|
|
61711
|
+
this.startupDisabled = false;
|
|
61712
|
+
// Whether this configure() supplied an initial config (the config ladder's early exit)
|
|
61713
|
+
this.hasInitialConfig = false;
|
|
61714
|
+
// Resume bookkeeping: the configuration startup last ran with, when it (or a resume) last
|
|
61715
|
+
// ran, and whether one is running now.
|
|
61716
|
+
this.lastConfig = null;
|
|
61717
|
+
this.lastStartupRunAt = 0;
|
|
61718
|
+
this.startupInFlight = false;
|
|
61596
61719
|
// Register this instance to avoid circular dependency issues
|
|
61597
61720
|
setNamiRefsInstance(this);
|
|
61598
61721
|
}
|
|
@@ -61610,13 +61733,101 @@ class NamiRefs {
|
|
|
61610
61733
|
getIsFirstSession() {
|
|
61611
61734
|
return this.isFirstSession;
|
|
61612
61735
|
}
|
|
61736
|
+
/**
|
|
61737
|
+
* True when the platform-config step found no usable config and startup stopped after it —
|
|
61738
|
+
* the equivalent of Apple's `sdkEnabled = false` and Android's `NamiRefs.startupDisabled`.
|
|
61739
|
+
* Like both, it gates only the startup sequence, nothing else.
|
|
61740
|
+
*/
|
|
61741
|
+
isStartupDisabled() {
|
|
61742
|
+
return this.startupDisabled;
|
|
61743
|
+
}
|
|
61613
61744
|
async init(config) {
|
|
61614
61745
|
this.isFirstSession = storageService.getDevice() === null && !storageService.getAnonymousMode();
|
|
61746
|
+
// Cleared per configure so a transient failure cannot disable a later run.
|
|
61747
|
+
this.startupDisabled = false;
|
|
61748
|
+
// `Nami.configure` has already normalised a missing or undecodable initialConfig to `{}`,
|
|
61749
|
+
// so "has content" is Apple's `initialConfig != nil`.
|
|
61750
|
+
this.hasInitialConfig = Object.keys(config.initialConfig ?? {}).length > 0;
|
|
61615
61751
|
this.setInitialValues(config);
|
|
61616
|
-
|
|
61752
|
+
this.lastConfig = config;
|
|
61753
|
+
this.lastStartupRunAt = Date.now();
|
|
61754
|
+
this.startupInFlight = true;
|
|
61755
|
+
try {
|
|
61756
|
+
if (!(await this.fetchPlatformConfig()))
|
|
61757
|
+
return;
|
|
61758
|
+
await this.runStartupAfterConfig(config);
|
|
61759
|
+
}
|
|
61760
|
+
finally {
|
|
61761
|
+
this.startupInFlight = false;
|
|
61762
|
+
}
|
|
61763
|
+
}
|
|
61764
|
+
/**
|
|
61765
|
+
* The app returned to the foreground. Re-reads the platform config, as Apple's `.appResume`
|
|
61766
|
+
* and Android's `onAppComesFromBackground` do, so a config change — the `sdk` kill switch
|
|
61767
|
+
* included — reaches a long-lived tab or app without a cold start.
|
|
61768
|
+
*
|
|
61769
|
+
* - Skipped within {@link RESUME_THROTTLE_MS} of the last launch/resume, and while one is
|
|
61770
|
+
* still running.
|
|
61771
|
+
* - When the launch had **stopped** for want of a config and one is now usable, the rest of
|
|
61772
|
+
* startup runs — the steps an Apple resume re-runs because the launch never executed them.
|
|
61773
|
+
* - Otherwise this is a config refresh only. Apple and Android also re-run device, campaigns,
|
|
61774
|
+
* profile, products and the session start on resume; core does not yet, and has no
|
|
61775
|
+
* session end on background for a second session start to pair with (NAM-4623).
|
|
61776
|
+
*/
|
|
61777
|
+
async resume() {
|
|
61778
|
+
if (!this.lastConfig || this.startupInFlight)
|
|
61779
|
+
return;
|
|
61780
|
+
if (Date.now() - this.lastStartupRunAt < exports.RESUME_THROTTLE_MS) {
|
|
61781
|
+
logger.debug("Resuming too quickly to call the service.");
|
|
61782
|
+
return;
|
|
61783
|
+
}
|
|
61784
|
+
const config = this.lastConfig;
|
|
61785
|
+
const wasStopped = this.startupDisabled;
|
|
61786
|
+
this.lastStartupRunAt = Date.now();
|
|
61787
|
+
this.startupInFlight = true;
|
|
61788
|
+
this.startupDisabled = false;
|
|
61789
|
+
try {
|
|
61790
|
+
if (!(await this.fetchPlatformConfig()) || !wasStopped)
|
|
61791
|
+
return;
|
|
61792
|
+
logger.info("Usable app config on resume - completing the startup that stopped at launch");
|
|
61793
|
+
await this.runStartupAfterConfig(config);
|
|
61794
|
+
}
|
|
61795
|
+
catch (error) {
|
|
61796
|
+
logger.warn(`Resume refresh failed: ${error}`);
|
|
61797
|
+
}
|
|
61798
|
+
finally {
|
|
61799
|
+
this.startupInFlight = false;
|
|
61800
|
+
}
|
|
61801
|
+
}
|
|
61802
|
+
/** Everything startup runs once the platform-config step has found a usable config. */
|
|
61803
|
+
async runStartupAfterConfig(config) {
|
|
61617
61804
|
await this.initAndFetchRequiredData(config);
|
|
61618
61805
|
SessionService.instance.startSession();
|
|
61619
61806
|
}
|
|
61807
|
+
/** Forgets the configuration a resume would run against; called by `Nami.reset()`. */
|
|
61808
|
+
clearResumeState() {
|
|
61809
|
+
this.lastConfig = null;
|
|
61810
|
+
this.lastStartupRunAt = 0;
|
|
61811
|
+
this.startupDisabled = false;
|
|
61812
|
+
}
|
|
61813
|
+
/**
|
|
61814
|
+
* The platform-config startup step, ahead of device registration — the position it holds on
|
|
61815
|
+
* Apple (`.fetchPlatformConfig`) and Android (`fetchAppConfigOnce`) (NAM-4464, NAM-4589).
|
|
61816
|
+
* Without an initial config it is awaited, so everything downstream — `campaign_cache_ttl`
|
|
61817
|
+
* included — is evaluated against the config it leaves in storage. With one it resolves at
|
|
61818
|
+
* once and the request finishes in the background (see `fetchConfigForStartup`).
|
|
61819
|
+
*
|
|
61820
|
+
* @returns false when there is no usable config, in which case startup must stop.
|
|
61821
|
+
*/
|
|
61822
|
+
async fetchPlatformConfig() {
|
|
61823
|
+
const outcome = await ConfigRepository.instance.fetchConfigForStartup(this.hasInitialConfig);
|
|
61824
|
+
if (!outcome.usable) {
|
|
61825
|
+
this.startupDisabled = true;
|
|
61826
|
+
logger.error(`Nami startup stopped: ${outcome.reason}`);
|
|
61827
|
+
return false;
|
|
61828
|
+
}
|
|
61829
|
+
return true;
|
|
61830
|
+
}
|
|
61620
61831
|
setInitialValues(config) {
|
|
61621
61832
|
const baseConfig = { ...config };
|
|
61622
61833
|
delete baseConfig.initialConfig;
|
|
@@ -61877,7 +62088,7 @@ class LastLaunchStore {
|
|
|
61877
62088
|
}
|
|
61878
62089
|
}
|
|
61879
62090
|
|
|
61880
|
-
var _Nami_isInitialized;
|
|
62091
|
+
var _Nami_isInitialized, _Nami_removeForegroundListener;
|
|
61881
62092
|
// NamiFlowManager is intentionally NOT imported at top level — it
|
|
61882
62093
|
// transitively imports back to this module (`Nami` for logging), and
|
|
61883
62094
|
// pulling it in here causes a load-order cycle that breaks tests
|
|
@@ -61885,6 +62096,7 @@ var _Nami_isInitialized;
|
|
|
61885
62096
|
class Nami {
|
|
61886
62097
|
constructor() {
|
|
61887
62098
|
_Nami_isInitialized.set(this, false);
|
|
62099
|
+
_Nami_removeForegroundListener.set(this, null);
|
|
61888
62100
|
this.maxLogging = false;
|
|
61889
62101
|
}
|
|
61890
62102
|
get isInitialized() {
|
|
@@ -61908,9 +62120,13 @@ class Nami {
|
|
|
61908
62120
|
* integrating app, consistent with the Apple and Android SDKs.
|
|
61909
62121
|
*/
|
|
61910
62122
|
static async reset() {
|
|
62123
|
+
var _a;
|
|
61911
62124
|
storageService.clearAll();
|
|
61912
62125
|
clearInMemoryAnonymousMode();
|
|
61913
62126
|
__classPrivateFieldSet(Nami.instance, _Nami_isInitialized, false, "f");
|
|
62127
|
+
__classPrivateFieldGet((_a = Nami.instance), _Nami_removeForegroundListener, "f")?.call(_a);
|
|
62128
|
+
__classPrivateFieldSet(Nami.instance, _Nami_removeForegroundListener, null, "f");
|
|
62129
|
+
NamiRefs.instance.clearResumeState();
|
|
61914
62130
|
// In-memory singleton state that previously survived reset and
|
|
61915
62131
|
// bled into the next configure() cycle.
|
|
61916
62132
|
NamiProfileManager$1.instance.setExternalId(undefined);
|
|
@@ -61973,6 +62189,18 @@ class Nami {
|
|
|
61973
62189
|
}
|
|
61974
62190
|
config.initialConfig = {};
|
|
61975
62191
|
}
|
|
62192
|
+
/**
|
|
62193
|
+
* Subscribes the resume config refresh to the host's foreground signal, once per process —
|
|
62194
|
+
* a reconfigure must not stack a second listener (the Android defect NAM-4541 fixed).
|
|
62195
|
+
* Registered before startup runs; `resume()` itself skips while startup is in flight.
|
|
62196
|
+
*/
|
|
62197
|
+
listenForAppForeground() {
|
|
62198
|
+
if (__classPrivateFieldGet(this, _Nami_removeForegroundListener, "f"))
|
|
62199
|
+
return;
|
|
62200
|
+
__classPrivateFieldSet(this, _Nami_removeForegroundListener, getPlatformAdapters().device.onAppForeground?.(() => {
|
|
62201
|
+
void NamiRefs.instance.resume();
|
|
62202
|
+
}) ?? null, "f");
|
|
62203
|
+
}
|
|
61976
62204
|
async initializeSDK(config) {
|
|
61977
62205
|
let fullReconfig = false;
|
|
61978
62206
|
let partialReconfig = false;
|
|
@@ -62013,6 +62241,7 @@ class Nami {
|
|
|
62013
62241
|
// configure SDK with new config
|
|
62014
62242
|
__classPrivateFieldSet(this, _Nami_isInitialized, true, "f");
|
|
62015
62243
|
NamiAPI.configure(config);
|
|
62244
|
+
this.listenForAppForeground();
|
|
62016
62245
|
await NamiRefs.instance.init(config);
|
|
62017
62246
|
logger.info("SDK successfully initialized!");
|
|
62018
62247
|
const state = partialReconfig || fullReconfig ? exports.RECONFIG_SUCCESS : exports.INITIAL_SUCCESS;
|
|
@@ -62024,7 +62253,7 @@ class Nami {
|
|
|
62024
62253
|
};
|
|
62025
62254
|
}
|
|
62026
62255
|
}
|
|
62027
|
-
_Nami_isInitialized = new WeakMap();
|
|
62256
|
+
_Nami_isInitialized = new WeakMap(), _Nami_removeForegroundListener = new WeakMap();
|
|
62028
62257
|
Nami.instance = new Nami();
|
|
62029
62258
|
|
|
62030
62259
|
const VALID_STYLES = new Set(['fullscreen', 'sheet', 'compact_sheet', 'modal']);
|
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,13 @@ interface IDeviceAdapter {
|
|
|
65
65
|
generateUUID(): string;
|
|
66
66
|
getScreenInfo(): ScreenInfo;
|
|
67
67
|
getLanguage(): string;
|
|
68
|
+
/**
|
|
69
|
+
* Calls `listener` each time the app returns to the foreground — a browser tab becoming
|
|
70
|
+
* visible, a React Native app going `active` — and returns a function that stops listening.
|
|
71
|
+
* Drives core's resume config refresh (NAM-4589). Optional: a host with no foreground
|
|
72
|
+
* concept (the CLI) omits it and simply never resumes.
|
|
73
|
+
*/
|
|
74
|
+
onAppForeground?(listener: () => void): () => void;
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
interface FormFactor {
|
|
@@ -1828,6 +1835,7 @@ type TPaywallContext = TInitialState & {
|
|
|
1828
1835
|
anySkuHasIntroOffer: boolean;
|
|
1829
1836
|
anySkuHasPromoOffer: boolean;
|
|
1830
1837
|
safeAreaTop: number;
|
|
1838
|
+
safeAreaBottom: number;
|
|
1831
1839
|
slides?: TCarouselSlidesState;
|
|
1832
1840
|
currentPage: string;
|
|
1833
1841
|
pageHistory: string[];
|
|
@@ -2121,6 +2129,12 @@ declare class Nami {
|
|
|
2121
2129
|
*/
|
|
2122
2130
|
static configure(options: NamiConfiguration): Promise<NamiConfigurationState>;
|
|
2123
2131
|
private static setInitialConfig;
|
|
2132
|
+
/**
|
|
2133
|
+
* Subscribes the resume config refresh to the host's foreground signal, once per process —
|
|
2134
|
+
* a reconfigure must not stack a second listener (the Android defect NAM-4541 fixed).
|
|
2135
|
+
* Registered before startup runs; `resume()` itself skips while startup is in flight.
|
|
2136
|
+
*/
|
|
2137
|
+
private listenForAppForeground;
|
|
2124
2138
|
private initializeSDK;
|
|
2125
2139
|
}
|
|
2126
2140
|
|
|
@@ -2551,6 +2565,7 @@ declare class PaywallState extends SimpleEventTarget {
|
|
|
2551
2565
|
setIsLoggedIn(isLoggedIn: boolean): void;
|
|
2552
2566
|
setMediaList(media: TPaywallMedia[]): void;
|
|
2553
2567
|
setSafeAreaTop(safeAreaTop: number): void;
|
|
2568
|
+
setSafeAreaBottom(safeAreaBottom: number): void;
|
|
2554
2569
|
setFullScreenPresentation(fullScreenPresentation: boolean): void;
|
|
2555
2570
|
setFormFactor(formFactor: TDevice): void;
|
|
2556
2571
|
getFormFactor(): TDevice;
|
|
@@ -3181,12 +3196,16 @@ declare const LOG_HTTP_REQUESTS: string;
|
|
|
3181
3196
|
declare const LOG_HTTP_TRAFFIC: string;
|
|
3182
3197
|
declare const API_TRAFFIC_OBSERVER: string;
|
|
3183
3198
|
declare const STARTUP_TELEMETRY: string;
|
|
3199
|
+
declare const SIMULATE_CONFIG_FETCH_FAILURE: string;
|
|
3184
3200
|
declare const EXTENDED_PLATFORM: string;
|
|
3185
3201
|
declare const EXTENDED_PLATFORM_VERSION: string;
|
|
3186
3202
|
declare const API_MAX_CALLS_LIMIT: number;
|
|
3187
3203
|
declare const API_RETRY_DELAY_SEC: number;
|
|
3188
3204
|
declare const API_TIMEOUT_LIMIT: number;
|
|
3189
3205
|
declare const DEVICE_API_TIMEOUT_LIMIT: number;
|
|
3206
|
+
declare const CONFIG_MAX_ATTEMPTS: number;
|
|
3207
|
+
declare const CONFIG_API_TIMEOUT_LIMIT: number;
|
|
3208
|
+
declare const RESUME_THROTTLE_MS: number;
|
|
3190
3209
|
declare const STATUS_SUCCESS: number;
|
|
3191
3210
|
declare const STATUS_BAD_REQUEST: number;
|
|
3192
3211
|
declare const STATUS_NOT_FOUND: number;
|
|
@@ -3390,12 +3409,51 @@ declare class NamiRefs {
|
|
|
3390
3409
|
static instance: NamiRefs;
|
|
3391
3410
|
private inMemoryAnonymousMode;
|
|
3392
3411
|
private isFirstSession;
|
|
3412
|
+
private startupDisabled;
|
|
3413
|
+
private hasInitialConfig;
|
|
3414
|
+
private lastConfig;
|
|
3415
|
+
private lastStartupRunAt;
|
|
3416
|
+
private startupInFlight;
|
|
3393
3417
|
constructor();
|
|
3394
3418
|
setInMemoryAnonymousMode(enabled: boolean): void;
|
|
3395
3419
|
isInMemoryAnonymousMode(): boolean;
|
|
3396
3420
|
isAnonymousMode(): boolean;
|
|
3397
3421
|
getIsFirstSession(): boolean;
|
|
3422
|
+
/**
|
|
3423
|
+
* True when the platform-config step found no usable config and startup stopped after it —
|
|
3424
|
+
* the equivalent of Apple's `sdkEnabled = false` and Android's `NamiRefs.startupDisabled`.
|
|
3425
|
+
* Like both, it gates only the startup sequence, nothing else.
|
|
3426
|
+
*/
|
|
3427
|
+
isStartupDisabled(): boolean;
|
|
3398
3428
|
init(config: NamiConfiguration): Promise<void>;
|
|
3429
|
+
/**
|
|
3430
|
+
* The app returned to the foreground. Re-reads the platform config, as Apple's `.appResume`
|
|
3431
|
+
* and Android's `onAppComesFromBackground` do, so a config change — the `sdk` kill switch
|
|
3432
|
+
* included — reaches a long-lived tab or app without a cold start.
|
|
3433
|
+
*
|
|
3434
|
+
* - Skipped within {@link RESUME_THROTTLE_MS} of the last launch/resume, and while one is
|
|
3435
|
+
* still running.
|
|
3436
|
+
* - When the launch had **stopped** for want of a config and one is now usable, the rest of
|
|
3437
|
+
* startup runs — the steps an Apple resume re-runs because the launch never executed them.
|
|
3438
|
+
* - Otherwise this is a config refresh only. Apple and Android also re-run device, campaigns,
|
|
3439
|
+
* profile, products and the session start on resume; core does not yet, and has no
|
|
3440
|
+
* session end on background for a second session start to pair with (NAM-4623).
|
|
3441
|
+
*/
|
|
3442
|
+
resume(): Promise<void>;
|
|
3443
|
+
/** Everything startup runs once the platform-config step has found a usable config. */
|
|
3444
|
+
private runStartupAfterConfig;
|
|
3445
|
+
/** Forgets the configuration a resume would run against; called by `Nami.reset()`. */
|
|
3446
|
+
clearResumeState(): void;
|
|
3447
|
+
/**
|
|
3448
|
+
* The platform-config startup step, ahead of device registration — the position it holds on
|
|
3449
|
+
* Apple (`.fetchPlatformConfig`) and Android (`fetchAppConfigOnce`) (NAM-4464, NAM-4589).
|
|
3450
|
+
* Without an initial config it is awaited, so everything downstream — `campaign_cache_ttl`
|
|
3451
|
+
* included — is evaluated against the config it leaves in storage. With one it resolves at
|
|
3452
|
+
* once and the request finishes in the background (see `fetchConfigForStartup`).
|
|
3453
|
+
*
|
|
3454
|
+
* @returns false when there is no usable config, in which case startup must stop.
|
|
3455
|
+
*/
|
|
3456
|
+
private fetchPlatformConfig;
|
|
3399
3457
|
private setInitialValues;
|
|
3400
3458
|
private initAnonymousDevice;
|
|
3401
3459
|
private initIdentifiedDevice;
|
|
@@ -3600,9 +3658,56 @@ declare class CampaignRuleRepository {
|
|
|
3600
3658
|
private fallbackData;
|
|
3601
3659
|
}
|
|
3602
3660
|
|
|
3661
|
+
/**
|
|
3662
|
+
* Whether startup may continue past the platform-config step; `reason` explains a `false`.
|
|
3663
|
+
* A plain shape rather than a discriminated union: core does not compile with
|
|
3664
|
+
* `strictNullChecks`, so a union on `usable` would not narrow.
|
|
3665
|
+
*/
|
|
3666
|
+
type ConfigStartupOutcome = {
|
|
3667
|
+
usable: boolean;
|
|
3668
|
+
reason?: string;
|
|
3669
|
+
};
|
|
3603
3670
|
declare class ConfigRepository {
|
|
3604
3671
|
static instance: ConfigRepository;
|
|
3605
|
-
|
|
3672
|
+
/**
|
|
3673
|
+
* One `GET config/` attempt. Persists the config on success and throws on any failure —
|
|
3674
|
+
* a non-2xx or a transport error alike. `withRetry`'s own retries are turned off, so the
|
|
3675
|
+
* attempt count belongs to {@link fetchConfigForStartup} alone.
|
|
3676
|
+
*/
|
|
3677
|
+
fetchConfig(): Promise<IConfig>;
|
|
3678
|
+
/**
|
|
3679
|
+
* The startup platform-config step, converged on Apple's `NamiPlatformConfigService.fetch` and
|
|
3680
|
+
* Android's `fetchAppConfigOnce` (NAM-4470, NAM-4589):
|
|
3681
|
+
*
|
|
3682
|
+
* | case | outcome |
|
|
3683
|
+
* |---|---|
|
|
3684
|
+
* | an initial config was supplied | NOT awaited: one attempt runs in the background and stores the config when it lands; usable |
|
|
3685
|
+
* | no initial config, success, capabilities include `sdk` | usable |
|
|
3686
|
+
* | no initial config, success, capabilities lack `sdk` | not usable |
|
|
3687
|
+
* | no initial config, failure | {@link CONFIG_MAX_ATTEMPTS} attempts of up to {@link CONFIG_API_TIMEOUT_LIMIT} each, then usable only if a config is cached (and grants `sdk`) |
|
|
3688
|
+
*
|
|
3689
|
+
* The two fallbacks are consulted at two different points, deliberately. An initial config
|
|
3690
|
+
* decides the case *before* any request: startup does not wait on the network at all, since the
|
|
3691
|
+
* initial config is what makes the SDK ready without it (Apple: "Initial config is available.
|
|
3692
|
+
* Skipping retry."). The config cached by a previous launch is consulted only *after* the
|
|
3693
|
+
* retries run out. A stored `INITIAL_APP_CONFIG` is not that cache.
|
|
3694
|
+
*
|
|
3695
|
+
* One check does apply with an initial config, because it costs no wait: a cached config that
|
|
3696
|
+
* withholds `sdk` still stops startup, as Apple's cache load re-applies `updateSdkFlags`.
|
|
3697
|
+
* Without it a kill switch could never reach an app that ships an initial config — the
|
|
3698
|
+
* background fetch lands after startup has already run, so it takes effect from the next launch.
|
|
3699
|
+
*
|
|
3700
|
+
* A `404` is treated as any other 4xx, matching Apple's effective behaviour (its dedicated 404
|
|
3701
|
+
* branch is unreachable, NAM-4471) and Android's.
|
|
3702
|
+
*
|
|
3703
|
+
* @param hasInitialConfig whether the host passed an `initialConfig` that decoded to content.
|
|
3704
|
+
*/
|
|
3705
|
+
fetchConfigForStartup(hasInitialConfig: boolean): Promise<ConfigStartupOutcome>;
|
|
3706
|
+
/**
|
|
3707
|
+
* The initial-config case: nothing is awaited. The cached kill switch is a storage read; the
|
|
3708
|
+
* config request is left running and persists its answer (`fetchConfig`) when it lands.
|
|
3709
|
+
*/
|
|
3710
|
+
private startupOnInitialConfig;
|
|
3606
3711
|
}
|
|
3607
3712
|
|
|
3608
3713
|
declare class CustomerJourneyRepository {
|
|
@@ -4115,5 +4220,5 @@ declare namespace internal {
|
|
|
4115
4220
|
};
|
|
4116
4221
|
}
|
|
4117
4222
|
|
|
4118
|
-
export { ALREADY_CONFIGURED, ANONYMOUS_MODE, ANONYMOUS_MODE_ALREADY_OFF, ANONYMOUS_MODE_ALREADY_ON, ANONYMOUS_MODE_LOGIN_NOT_ALLOWED, ANONYMOUS_UUID, APIError, API_ACTIVE_ENTITLEMENTS, API_CAMPAIGN_RULES, API_CAMPAIGN_SESSION_TIMESTAMP, API_CONFIG, API_MAX_CALLS_LIMIT, API_PAYWALLS, API_PRODUCTS, API_RETRY_DELAY_SEC, API_TIMEOUT_LIMIT, API_TRAFFIC_OBSERVER, API_VERSION, AUTH_DEVICE, AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, AVAILABLE_CAMPAIGNS_CHANGED, AccountStateAction, AnonymousCDPError, AnonymousLoginError, AnonymousModeAlreadyOffError, AnonymousModeAlreadyOnError, BASE_STAGING_URL, BASE_URL, BASE_URL_PATH, BadRequestError, BasicNamiFlow, BorderMap, BorderSideMap, CAMPAIGN_NOT_AVAILABLE, CUSTOMER_ATTRIBUTES_KEY_PREFIX, CUSTOMER_JOURNEY_STATE_CHANGED, CUSTOM_HOST_PREFIX, CampaignNotAvailableError, CampaignRuleConversionEventType, CampaignRuleRepository, Capabilities, ClientError, ConfigRepository, ConflictError, CustomerJourneyRepository, DEFAULT_JOURNEY_SETTINGS, DEVELOPMENT, DEVICE_API_TIMEOUT_LIMIT, DEVICE_ID_NOT_SET, DEVICE_ID_REQUIRED, DISABLE_ASYNC_LOGIN_LOGOUT, DeviceIDRequiredError, DeviceRepository, EXTENDED_CLIENT_INFO_DELIMITER, EXTENDED_CLIENT_INFO_PREFIX, EXTENDED_PLATFORM, EXTENDED_PLATFORM_VERSION, EXTERNAL_ID_REQUIRED, EntitlementRepository, EntitlementUtils, ExternalIDRequiredError, FLOW_SCREENS_NOT_AVAILABLE, FlowScreensNotAvailableError, HTML_REGEX, INITIAL_APP_CONFIG, INITIAL_CAMPAIGN_RULES, INITIAL_PAYWALLS, INITIAL_PRODUCTS, INITIAL_SESSION_COUNTER_VALUE, INITIAL_SUCCESS, InternalServerError, KEY_SESSION_COUNTER, LIQUID_VARIABLE_REGEX, LOCAL_NAMI_ENTITLEMENTS, LOG_HTTP_REQUESTS, LOG_HTTP_TRAFFIC, LaunchCampaignError, LaunchContextResolver, LogLevel, NAMI_CONFIGURATION, NAMI_CUSTOMER_JOURNEY_STATE, NAMI_LANGUAGE_CODE, NAMI_LAST_IMPRESSION_ID, NAMI_LAUNCH_ID, NAMI_PROFILE, NAMI_PURCHASE_CHANNEL, NAMI_PURCHASE_IMPRESSION_ID, NAMI_SDK_PACKAGE_VERSION, NAMI_SDK_VERSION, NAMI_SESSION_ID, NAMI_STORAGE_KEYS, Nami, NamiAPI, NamiAnimationType, NamiCampaignManager$2 as NamiCampaignManager, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager$2 as NamiCustomerManager, NamiEntitlementManager$2 as NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager$1 as NamiFlowManager, NamiFlowStepType, NamiHandoffTag, NamiPaywallAction, NamiPaywallManager$2 as NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiPermissionOutcome, NamiPurchaseManager$2 as NamiPurchaseManager, NamiRefs, NamiReservedActions, NotFoundError, PAYWALL_ACTION_EVENT, PLATFORM_ID_REQUIRED, PRODUCTION, PaywallManagerEvents, PaywallRepository, PaywallState, PlacementLabelResolver, PlatformIDRequiredError, ProductRepository, RECONFIG_SUCCESS, RetryLimitExceededError, SDKNotInitializedError, SDK_NOT_INITIALIZED, SERVER_NAMI_ENTITLEMENTS, SESSION_REQUIRED, SHOULD_SHOW_LOADING_INDICATOR, SKU_TEXT_REGEX, SMART_TEXT_PATTERN, STARTUP_TELEMETRY, STATUS_BAD_REQUEST, STATUS_CONFLICT, STATUS_INTERNAL_SERVER_ERROR, STATUS_NOT_FOUND, STATUS_SUCCESS, SessionService, SimpleEventTarget, StorageService, TRANSPORT_FAILURE_STATUS, UNABLE_TO_UPDATE_CDP_ID, USE_STAGING_API, VALIDATE_PRODUCT_GROUPS, VAR_REGEX, NamiProfileManager$1 as _NamiProfileManager, internal as _internal, activateEntitlementByPurchase, activeEntitlements, aggregateScreenreaderText, allCampaigns, allPaywalls, applyEntitlementActivation, audienceSplitPosition, bestUrlCampaignMatch, bigintToUuid, checkAnySkuHasPromoOffer, checkAnySkuHasTrialOffer, convertISO8601PeriodToText, convertLocale, convertOfferToPricingPhase, createNamiEntitlements, currentSku, didReceiveResponse, empty, extractStandardPricingPhases, formatDate, formattedPrice, generateUUID, getApiCampaigns, getApiPaywalls, getBaseUrl, getBillingPeriodNumber, getCurrencyFormat, getDeviceData, getDeviceFormFactor, getDeviceScaleFactor, getEffectiveWebStyle, getEntitlementRefIdsForSku, getExtendedClientInfo, getFreeTrialPeriod, getInitialCampaigns, getInitialPaywalls, getJourneySettings, getPaywall, getPaywallDataFromLabel, getPercentagePriceDifference, getPeriodNumberInDays, getPeriodNumberInWeeks, getPlatformAdapters, getPriceDifference, getPricePerMonth, getProductDetail, getPurchaseAdapter, getReferenceSku, getSkuProductDetailKeys, getSkuSmartTextValue, getSlideSmartTextValue, getStandardBillingPeriod, getTranslate, getUrlParams, handleErrors, hasAllPaywalls, hasCapability, hasPurchaseManagement, initialState, invokeHandler, isAnonymousMode, isInitialConfigCompressed, isNamiFlowCampaign, isSubscription, isValidISODate, isValidUrl, logger, mapAnonymousCampaigns, namiBuySKU, normalizeLaunchContext, parseToSemver, postConversion, productDetail, registerAPITrafficObserver, registerPlatformAdapters, registerPurchaseAdapter, resolveLoopSource, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateForm, validateMinSDKVersion, validateTextInput };
|
|
4223
|
+
export { ALREADY_CONFIGURED, ANONYMOUS_MODE, ANONYMOUS_MODE_ALREADY_OFF, ANONYMOUS_MODE_ALREADY_ON, ANONYMOUS_MODE_LOGIN_NOT_ALLOWED, ANONYMOUS_UUID, APIError, API_ACTIVE_ENTITLEMENTS, API_CAMPAIGN_RULES, API_CAMPAIGN_SESSION_TIMESTAMP, API_CONFIG, API_MAX_CALLS_LIMIT, API_PAYWALLS, API_PRODUCTS, API_RETRY_DELAY_SEC, API_TIMEOUT_LIMIT, API_TRAFFIC_OBSERVER, API_VERSION, AUTH_DEVICE, AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, AVAILABLE_CAMPAIGNS_CHANGED, AccountStateAction, AnonymousCDPError, AnonymousLoginError, AnonymousModeAlreadyOffError, AnonymousModeAlreadyOnError, BASE_STAGING_URL, BASE_URL, BASE_URL_PATH, BadRequestError, BasicNamiFlow, BorderMap, BorderSideMap, CAMPAIGN_NOT_AVAILABLE, CONFIG_API_TIMEOUT_LIMIT, CONFIG_MAX_ATTEMPTS, CUSTOMER_ATTRIBUTES_KEY_PREFIX, CUSTOMER_JOURNEY_STATE_CHANGED, CUSTOM_HOST_PREFIX, CampaignNotAvailableError, CampaignRuleConversionEventType, CampaignRuleRepository, Capabilities, ClientError, ConfigRepository, ConflictError, CustomerJourneyRepository, DEFAULT_JOURNEY_SETTINGS, DEVELOPMENT, DEVICE_API_TIMEOUT_LIMIT, DEVICE_ID_NOT_SET, DEVICE_ID_REQUIRED, DISABLE_ASYNC_LOGIN_LOGOUT, DeviceIDRequiredError, DeviceRepository, EXTENDED_CLIENT_INFO_DELIMITER, EXTENDED_CLIENT_INFO_PREFIX, EXTENDED_PLATFORM, EXTENDED_PLATFORM_VERSION, EXTERNAL_ID_REQUIRED, EntitlementRepository, EntitlementUtils, ExternalIDRequiredError, FLOW_SCREENS_NOT_AVAILABLE, FlowScreensNotAvailableError, HTML_REGEX, INITIAL_APP_CONFIG, INITIAL_CAMPAIGN_RULES, INITIAL_PAYWALLS, INITIAL_PRODUCTS, INITIAL_SESSION_COUNTER_VALUE, INITIAL_SUCCESS, InternalServerError, KEY_SESSION_COUNTER, LIQUID_VARIABLE_REGEX, LOCAL_NAMI_ENTITLEMENTS, LOG_HTTP_REQUESTS, LOG_HTTP_TRAFFIC, LaunchCampaignError, LaunchContextResolver, LogLevel, NAMI_CONFIGURATION, NAMI_CUSTOMER_JOURNEY_STATE, NAMI_LANGUAGE_CODE, NAMI_LAST_IMPRESSION_ID, NAMI_LAUNCH_ID, NAMI_PROFILE, NAMI_PURCHASE_CHANNEL, NAMI_PURCHASE_IMPRESSION_ID, NAMI_SDK_PACKAGE_VERSION, NAMI_SDK_VERSION, NAMI_SESSION_ID, NAMI_STORAGE_KEYS, Nami, NamiAPI, NamiAnimationType, NamiCampaignManager$2 as NamiCampaignManager, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager$2 as NamiCustomerManager, NamiEntitlementManager$2 as NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager$1 as NamiFlowManager, NamiFlowStepType, NamiHandoffTag, NamiPaywallAction, NamiPaywallManager$2 as NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiPermissionOutcome, NamiPurchaseManager$2 as NamiPurchaseManager, NamiRefs, NamiReservedActions, NotFoundError, PAYWALL_ACTION_EVENT, PLATFORM_ID_REQUIRED, PRODUCTION, PaywallManagerEvents, PaywallRepository, PaywallState, PlacementLabelResolver, PlatformIDRequiredError, ProductRepository, RECONFIG_SUCCESS, RESUME_THROTTLE_MS, RetryLimitExceededError, SDKNotInitializedError, SDK_NOT_INITIALIZED, SERVER_NAMI_ENTITLEMENTS, SESSION_REQUIRED, SHOULD_SHOW_LOADING_INDICATOR, SIMULATE_CONFIG_FETCH_FAILURE, SKU_TEXT_REGEX, SMART_TEXT_PATTERN, STARTUP_TELEMETRY, STATUS_BAD_REQUEST, STATUS_CONFLICT, STATUS_INTERNAL_SERVER_ERROR, STATUS_NOT_FOUND, STATUS_SUCCESS, SessionService, SimpleEventTarget, StorageService, TRANSPORT_FAILURE_STATUS, UNABLE_TO_UPDATE_CDP_ID, USE_STAGING_API, VALIDATE_PRODUCT_GROUPS, VAR_REGEX, NamiProfileManager$1 as _NamiProfileManager, internal as _internal, activateEntitlementByPurchase, activeEntitlements, aggregateScreenreaderText, allCampaigns, allPaywalls, applyEntitlementActivation, audienceSplitPosition, bestUrlCampaignMatch, bigintToUuid, checkAnySkuHasPromoOffer, checkAnySkuHasTrialOffer, convertISO8601PeriodToText, convertLocale, convertOfferToPricingPhase, createNamiEntitlements, currentSku, didReceiveResponse, empty, extractStandardPricingPhases, formatDate, formattedPrice, generateUUID, getApiCampaigns, getApiPaywalls, getBaseUrl, getBillingPeriodNumber, getCurrencyFormat, getDeviceData, getDeviceFormFactor, getDeviceScaleFactor, getEffectiveWebStyle, getEntitlementRefIdsForSku, getExtendedClientInfo, getFreeTrialPeriod, getInitialCampaigns, getInitialPaywalls, getJourneySettings, getPaywall, getPaywallDataFromLabel, getPercentagePriceDifference, getPeriodNumberInDays, getPeriodNumberInWeeks, getPlatformAdapters, getPriceDifference, getPricePerMonth, getProductDetail, getPurchaseAdapter, getReferenceSku, getSkuProductDetailKeys, getSkuSmartTextValue, getSlideSmartTextValue, getStandardBillingPeriod, getTranslate, getUrlParams, handleErrors, hasAllPaywalls, hasCapability, hasPurchaseManagement, initialState, invokeHandler, isAnonymousMode, isInitialConfigCompressed, isNamiFlowCampaign, isSubscription, isValidISODate, isValidUrl, logger, mapAnonymousCampaigns, namiBuySKU, normalizeLaunchContext, parseToSemver, postConversion, productDetail, registerAPITrafficObserver, registerPlatformAdapters, registerPurchaseAdapter, resolveLoopSource, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateForm, validateMinSDKVersion, validateTextInput };
|
|
4119
4224
|
export type { AccountStateHandler$1 as AccountStateHandler, AlignmentType, AmazonProduct, ApiResponse, AppleProduct, AvailableCampaignsResponseHandler, BorderLocationType, BorderSideType, Callback$1 as Callback, CloseHandler, CustomerJourneyState, DeepLinkUrlHandler, Device, DevicePayload, DeviceProfile, DirectionType, ExtendedPlatformInfo, FlexDirectionObject, FlowNavigationOptions, FontCollection, FontDetails, FormFactor, FormFieldValidator, GoogleProduct, IConfig, IDeviceAdapter, IEntitlements$1 as IEntitlements, IPaywall, IPlatformAdapters, IProductsWithComponents, IPurchaseAdapter, ISkuMenu, IStorageAdapter, IUIAdapter, Impression, InitialConfig, InitialConfigCompressed, InitiateStateGroup, JourneySettings, LoginResponse, NamiAPITrafficKind, NamiAPITrafficObserver, NamiAPITrafficRecord, NamiAnimation, NamiAnimationObjectSpec, NamiAnimationSpec, NamiAnonymousCampaign, NamiAppSuppliedVideoDetails, NamiCampaign, NamiCampaignManagerStatic, NamiCampaignSegment, NamiCompletionResult, NamiConfiguration, NamiConfigurationState, NamiCustomAttributeValue, NamiCustomerManagerStatic, NamiEntitlement$1 as NamiEntitlement, NamiEntitlementManagerStatic, NamiFlowAction, NamiFlowAnimation, NamiFlowCampaign, NamiFlowCompletionCondition, NamiFlowDTO, NamiFlowEventHandler, NamiFlowHandoffStepHandler, NamiFlowManagerStatic, NamiFlowObjectDTO, NamiFlowOn, NamiFlowStep, NamiFlowTransition, NamiFlowTransitionDirection, NamiFlowWithObject, NamiHandoffAttributeValue, NamiHandoffComplete, NamiHandoffOutcome, NamiHandoffTagValue, NamiInitialConfig, NamiKnownHandoffTag, NamiLanguageCodes, NamiLogLevel, NamiLoginSuccess, NamiPaywallActionHandler, NamiPaywallComponentChange, NamiPaywallEvent, NamiPaywallEventVideoMetadata, NamiPaywallLaunchContext, NamiPaywallManagerStatic, NamiPresentationStyle, NamiProductDetails, NamiProductOffer, NamiProfile, NamiPurchase, NamiPurchaseCompleteResult, NamiPurchaseDetails, NamiPurchaseManagerStatic, NamiPurchaseSuccess, NamiPurchasesState, NamiSKU, NamiSKUType, NamiSubscriptionInterval, NamiSubscriptionPeriod, NamiUserDataEnvelope, None, NoneSpec, PaywallActionEvent, PaywallHandle, PaywallResultHandler, PaywallSKU, PricingPhase, ProductGroup, Pulse, PulseSpec, PurchaseContext, PurchaseResult, PurchaseValidationRequest, SKU, SKUActionHandler, ScreenInfo, Session, TBaseComponent, TButtonContainer, TCarouselContainer, TCarouselSlide, TCarouselSlidesState, TCollapseContainer, TComponent, TConditionalAttributes, TConditionalComponent, TContainer, TContainerPosition, TCountdownTimerTextComponent, TDevice, TDisabledButton, TField, TFieldSettings, TFlexProductContainer, THeaderFooter, TImageComponent, TInitialState, TMediaTypes, TOffer, TPages, TPaywallContext, TPaywallLaunchContext, TPaywallMedia, TPaywallTemplate, TPlayPauseButton, TProductContainer, TProductGroup, TProgressBarComponent, TProgressIndicatorComponent, TQRCodeComponent, TRadioButton, TRepeatingGrid, TResponsiveGrid, TSegmentPicker, TSegmentPickerItem, TSemverObj, TSlot, TSlotGroupSelector, TSpacerComponent, TStack, TSvgImageComponent, TSymbolComponent, TTestObject, TTextComponent, TTextInputComponent, TTextInputType, TTextLikeComponent, TTextListComponent, TTimelineRail, TToggleButtonComponent, TToggleSwitch, TVariablePattern, TVideoComponent, TVolumeButton, TimerState, TransactionRequest, UserAction, UserActionParameters, Wave, WaveSpec };
|
package/dist/index.mjs
CHANGED
|
@@ -104,7 +104,7 @@ const {
|
|
|
104
104
|
// version — stamped by scripts/version.sh
|
|
105
105
|
NAMI_SDK_VERSION = "3.4.12",
|
|
106
106
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
107
|
-
NAMI_SDK_PACKAGE_VERSION = "3.4.12-dev.
|
|
107
|
+
NAMI_SDK_PACKAGE_VERSION = "3.4.12-dev.202609252349",
|
|
108
108
|
// environments
|
|
109
109
|
PRODUCTION = "production", DEVELOPMENT = "development",
|
|
110
110
|
// error messages
|
|
@@ -114,7 +114,19 @@ AUTH_DEVICE = "nami_auth_device", NAMI_CONFIGURATION = "nami_configuration", NAM
|
|
|
114
114
|
// API settings
|
|
115
115
|
API_VERSION = "v3", BASE_URL_PATH = `sdk/${API_VERSION}/platform`, BASE_URL = "https://app.namiml.com", BASE_STAGING_URL = "https://app-staging.namiml.com", CUSTOM_HOST_PREFIX = "namiAPIHost=", USE_STAGING_API = "useStagingAPI",
|
|
116
116
|
// // extended client info
|
|
117
|
-
EXTENDED_CLIENT_INFO_PREFIX = "extendedClientInfo", EXTENDED_CLIENT_INFO_DELIMITER = ":", VALIDATE_PRODUCT_GROUPS = "validateProductGroups", LOG_HTTP_REQUESTS = "logHTTPRequests", LOG_HTTP_TRAFFIC = "logHTTPTraffic", API_TRAFFIC_OBSERVER = "apiTrafficObserver", STARTUP_TELEMETRY = "startupTelemetry",
|
|
117
|
+
EXTENDED_CLIENT_INFO_PREFIX = "extendedClientInfo", EXTENDED_CLIENT_INFO_DELIMITER = ":", VALIDATE_PRODUCT_GROUPS = "validateProductGroups", LOG_HTTP_REQUESTS = "logHTTPRequests", LOG_HTTP_TRAFFIC = "logHTTPTraffic", API_TRAFFIC_OBSERVER = "apiTrafficObserver", STARTUP_TELEMETRY = "startupTelemetry",
|
|
118
|
+
// Test hook: every platform-config fetch attempt fails before the request leaves.
|
|
119
|
+
// Same namiCommand as Apple's and Android's, so the shared first-run flows drive it.
|
|
120
|
+
SIMULATE_CONFIG_FETCH_FAILURE = "simulateConfigFetchFailure", EXTENDED_PLATFORM = "extended-platform", EXTENDED_PLATFORM_VERSION = "extended-platform-version", API_MAX_CALLS_LIMIT = 2, API_RETRY_DELAY_SEC = 2, API_TIMEOUT_LIMIT = 20000, DEVICE_API_TIMEOUT_LIMIT = 2000,
|
|
121
|
+
// Platform-config attempts when no initial config was supplied (Android's
|
|
122
|
+
// CONFIG_MAX_ATTEMPTS; Apple's retry(maxAttempts: 3)).
|
|
123
|
+
CONFIG_MAX_ATTEMPTS = 3,
|
|
124
|
+
// Per-attempt timeout for GET config/. Android's config client allows 5 s to connect plus 5 s
|
|
125
|
+
// to read (Apple allows 30 s); three attempts keep a total outage near 30 s.
|
|
126
|
+
CONFIG_API_TIMEOUT_LIMIT = 10000,
|
|
127
|
+
// A foreground within this long of the last launch/resume run is skipped — Apple's
|
|
128
|
+
// NamiStartupCoordinator.shouldRunResume window.
|
|
129
|
+
RESUME_THROTTLE_MS = 30000,
|
|
118
130
|
// status codes
|
|
119
131
|
STATUS_SUCCESS = 200, STATUS_BAD_REQUEST = 400, STATUS_NOT_FOUND = 404, STATUS_CONFLICT = 409, STATUS_INTERNAL_SERVER_ERROR = 500,
|
|
120
132
|
// configuration states
|
|
@@ -58031,27 +58043,125 @@ class PaywallRepository {
|
|
|
58031
58043
|
PaywallRepository.instance = new PaywallRepository();
|
|
58032
58044
|
|
|
58033
58045
|
class ConfigRepository {
|
|
58046
|
+
/**
|
|
58047
|
+
* One `GET config/` attempt. Persists the config on success and throws on any failure —
|
|
58048
|
+
* a non-2xx or a transport error alike. `withRetry`'s own retries are turned off, so the
|
|
58049
|
+
* attempt count belongs to {@link fetchConfigForStartup} alone.
|
|
58050
|
+
*/
|
|
58034
58051
|
async fetchConfig() {
|
|
58035
|
-
|
|
58036
|
-
|
|
58037
|
-
|
|
58038
|
-
;
|
|
58039
|
-
}
|
|
58040
|
-
catch (error) {
|
|
58041
|
-
data = storageService.getAppConfig(API_CONFIG)
|
|
58042
|
-
|| storageService.getAppConfig(INITIAL_APP_CONFIG);
|
|
58043
|
-
if (!data) {
|
|
58044
|
-
logger.error(handleErrors(error.status, "config/"));
|
|
58045
|
-
throw error;
|
|
58046
|
-
}
|
|
58052
|
+
// Thrown from *inside* the attempt on purpose, like Apple's and Android's: the ladder then
|
|
58053
|
+
// treats it exactly as a real 500, which is the whole point of the mock.
|
|
58054
|
+
if (storageService.getNamiConfig()?.namiCommands?.includes(SIMULATE_CONFIG_FETCH_FAILURE)) {
|
|
58055
|
+
throw new RetryLimitExceededError(STATUS_INTERNAL_SERVER_ERROR, SIMULATE_CONFIG_FETCH_FAILURE);
|
|
58047
58056
|
}
|
|
58048
|
-
|
|
58057
|
+
const platformId = storageService.getNamiConfig()?.appPlatformID;
|
|
58058
|
+
const data = await NamiAPI.instance.fetchAPI("config/", CONFIG_API_TIMEOUT_LIMIT, 0);
|
|
58059
|
+
// A late answer (the startup await gave up on it) must not overwrite another platform's
|
|
58060
|
+
// config after a reset or a platform-switching reconfigure.
|
|
58061
|
+
if (storageService.getNamiConfig()?.appPlatformID === platformId) {
|
|
58049
58062
|
storageService.setAppConfig(API_CONFIG, data);
|
|
58050
58063
|
}
|
|
58064
|
+
else {
|
|
58065
|
+
logger.debug("Discarding an app config response for a platform that is no longer configured");
|
|
58066
|
+
}
|
|
58051
58067
|
return data;
|
|
58052
58068
|
}
|
|
58069
|
+
/**
|
|
58070
|
+
* The startup platform-config step, converged on Apple's `NamiPlatformConfigService.fetch` and
|
|
58071
|
+
* Android's `fetchAppConfigOnce` (NAM-4470, NAM-4589):
|
|
58072
|
+
*
|
|
58073
|
+
* | case | outcome |
|
|
58074
|
+
* |---|---|
|
|
58075
|
+
* | an initial config was supplied | NOT awaited: one attempt runs in the background and stores the config when it lands; usable |
|
|
58076
|
+
* | no initial config, success, capabilities include `sdk` | usable |
|
|
58077
|
+
* | no initial config, success, capabilities lack `sdk` | not usable |
|
|
58078
|
+
* | no initial config, failure | {@link CONFIG_MAX_ATTEMPTS} attempts of up to {@link CONFIG_API_TIMEOUT_LIMIT} each, then usable only if a config is cached (and grants `sdk`) |
|
|
58079
|
+
*
|
|
58080
|
+
* The two fallbacks are consulted at two different points, deliberately. An initial config
|
|
58081
|
+
* decides the case *before* any request: startup does not wait on the network at all, since the
|
|
58082
|
+
* initial config is what makes the SDK ready without it (Apple: "Initial config is available.
|
|
58083
|
+
* Skipping retry."). The config cached by a previous launch is consulted only *after* the
|
|
58084
|
+
* retries run out. A stored `INITIAL_APP_CONFIG` is not that cache.
|
|
58085
|
+
*
|
|
58086
|
+
* One check does apply with an initial config, because it costs no wait: a cached config that
|
|
58087
|
+
* withholds `sdk` still stops startup, as Apple's cache load re-applies `updateSdkFlags`.
|
|
58088
|
+
* Without it a kill switch could never reach an app that ships an initial config — the
|
|
58089
|
+
* background fetch lands after startup has already run, so it takes effect from the next launch.
|
|
58090
|
+
*
|
|
58091
|
+
* A `404` is treated as any other 4xx, matching Apple's effective behaviour (its dedicated 404
|
|
58092
|
+
* branch is unreachable, NAM-4471) and Android's.
|
|
58093
|
+
*
|
|
58094
|
+
* @param hasInitialConfig whether the host passed an `initialConfig` that decoded to content.
|
|
58095
|
+
*/
|
|
58096
|
+
async fetchConfigForStartup(hasInitialConfig) {
|
|
58097
|
+
if (hasInitialConfig)
|
|
58098
|
+
return this.startupOnInitialConfig();
|
|
58099
|
+
const maxAttempts = CONFIG_MAX_ATTEMPTS;
|
|
58100
|
+
let lastError;
|
|
58101
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
58102
|
+
if (attempt > 1) {
|
|
58103
|
+
logger.debug(`Retrying app config fetch (attempt ${attempt} of ${maxAttempts})`);
|
|
58104
|
+
}
|
|
58105
|
+
try {
|
|
58106
|
+
return outcomeOf(await this.fetchConfig());
|
|
58107
|
+
}
|
|
58108
|
+
catch (error) {
|
|
58109
|
+
lastError = error;
|
|
58110
|
+
}
|
|
58111
|
+
}
|
|
58112
|
+
const cached = storageService.getAppConfig(API_CONFIG);
|
|
58113
|
+
if (cached) {
|
|
58114
|
+
// A cached kill switch still holds: Apple re-applies `updateSdkFlags` when it loads the
|
|
58115
|
+
// cached config, so one that withheld `sdk` keeps the SDK disabled through an outage.
|
|
58116
|
+
if (!grantsSdk(cached)) {
|
|
58117
|
+
return { usable: false, reason: "the cached app config does not grant the 'sdk' capability" };
|
|
58118
|
+
}
|
|
58119
|
+
logger.info(`App config fetch failed after ${maxAttempts} attempts - continuing on the cached config`);
|
|
58120
|
+
return { usable: true };
|
|
58121
|
+
}
|
|
58122
|
+
return {
|
|
58123
|
+
usable: false,
|
|
58124
|
+
reason: `app config fetch failed after ${maxAttempts} attempts (${describeFailure(lastError)}) ` +
|
|
58125
|
+
"and no initial or cached config is available",
|
|
58126
|
+
};
|
|
58127
|
+
}
|
|
58128
|
+
/**
|
|
58129
|
+
* The initial-config case: nothing is awaited. The cached kill switch is a storage read; the
|
|
58130
|
+
* config request is left running and persists its answer (`fetchConfig`) when it lands.
|
|
58131
|
+
*/
|
|
58132
|
+
startupOnInitialConfig() {
|
|
58133
|
+
// Read before the request can land, so this launch is judged on what the last one stored.
|
|
58134
|
+
const cached = storageService.getAppConfig(API_CONFIG);
|
|
58135
|
+
// Issued even when the cache holds a kill switch: that is how a LIFTED kill switch reaches
|
|
58136
|
+
// the next launch.
|
|
58137
|
+
this.fetchConfig().then((config) => {
|
|
58138
|
+
if (!grantsSdk(config)) {
|
|
58139
|
+
logger.warn("App config does not grant the 'sdk' capability - it takes effect from the next launch");
|
|
58140
|
+
}
|
|
58141
|
+
}, (error) => {
|
|
58142
|
+
logger.info(`App config fetch failed (${describeFailure(error)}). Initial config is available. Skipping retry.`);
|
|
58143
|
+
});
|
|
58144
|
+
if (cached && !grantsSdk(cached)) {
|
|
58145
|
+
return { usable: false, reason: "the cached app config does not grant the 'sdk' capability" };
|
|
58146
|
+
}
|
|
58147
|
+
return { usable: true };
|
|
58148
|
+
}
|
|
58053
58149
|
}
|
|
58054
58150
|
ConfigRepository.instance = new ConfigRepository();
|
|
58151
|
+
function outcomeOf(config) {
|
|
58152
|
+
return grantsSdk(config)
|
|
58153
|
+
? { usable: true }
|
|
58154
|
+
: { usable: false, reason: "app config does not grant the 'sdk' capability" };
|
|
58155
|
+
}
|
|
58156
|
+
function grantsSdk(config) {
|
|
58157
|
+
return config.capabilities?.includes(Capabilities.SDK) ?? false;
|
|
58158
|
+
}
|
|
58159
|
+
function describeFailure(error) {
|
|
58160
|
+
const status = error?.status;
|
|
58161
|
+
if (typeof status === "number")
|
|
58162
|
+
return `HTTP ${status}`;
|
|
58163
|
+
return error instanceof Error ? error.message : String(error);
|
|
58164
|
+
}
|
|
58055
58165
|
|
|
58056
58166
|
// Global reference to avoid circular imports
|
|
58057
58167
|
let namiRefsInstance = null;
|
|
@@ -60777,6 +60887,7 @@ const initialState = {
|
|
|
60777
60887
|
isLoggedIn: false,
|
|
60778
60888
|
darkMode: false,
|
|
60779
60889
|
safeAreaTop: 0,
|
|
60890
|
+
safeAreaBottom: 0,
|
|
60780
60891
|
groups: [],
|
|
60781
60892
|
selectedProducts: {},
|
|
60782
60893
|
formStates: {},
|
|
@@ -61145,6 +61256,9 @@ class PaywallState extends SimpleEventTarget {
|
|
|
61145
61256
|
setSafeAreaTop(safeAreaTop) {
|
|
61146
61257
|
this.setState({ ...this.state, safeAreaTop });
|
|
61147
61258
|
}
|
|
61259
|
+
setSafeAreaBottom(safeAreaBottom) {
|
|
61260
|
+
this.setState({ ...this.state, safeAreaBottom });
|
|
61261
|
+
}
|
|
61148
61262
|
setFullScreenPresentation(fullScreenPresentation) {
|
|
61149
61263
|
this.setState({ ...this.state, fullScreenPresentation });
|
|
61150
61264
|
}
|
|
@@ -61591,6 +61705,15 @@ class NamiRefs {
|
|
|
61591
61705
|
this.inMemoryAnonymousMode = false;
|
|
61592
61706
|
// Captured before device registration; true only on genuine fresh installs
|
|
61593
61707
|
this.isFirstSession = false;
|
|
61708
|
+
// Set when the platform-config step leaves no usable config (see isStartupDisabled)
|
|
61709
|
+
this.startupDisabled = false;
|
|
61710
|
+
// Whether this configure() supplied an initial config (the config ladder's early exit)
|
|
61711
|
+
this.hasInitialConfig = false;
|
|
61712
|
+
// Resume bookkeeping: the configuration startup last ran with, when it (or a resume) last
|
|
61713
|
+
// ran, and whether one is running now.
|
|
61714
|
+
this.lastConfig = null;
|
|
61715
|
+
this.lastStartupRunAt = 0;
|
|
61716
|
+
this.startupInFlight = false;
|
|
61594
61717
|
// Register this instance to avoid circular dependency issues
|
|
61595
61718
|
setNamiRefsInstance(this);
|
|
61596
61719
|
}
|
|
@@ -61608,13 +61731,101 @@ class NamiRefs {
|
|
|
61608
61731
|
getIsFirstSession() {
|
|
61609
61732
|
return this.isFirstSession;
|
|
61610
61733
|
}
|
|
61734
|
+
/**
|
|
61735
|
+
* True when the platform-config step found no usable config and startup stopped after it —
|
|
61736
|
+
* the equivalent of Apple's `sdkEnabled = false` and Android's `NamiRefs.startupDisabled`.
|
|
61737
|
+
* Like both, it gates only the startup sequence, nothing else.
|
|
61738
|
+
*/
|
|
61739
|
+
isStartupDisabled() {
|
|
61740
|
+
return this.startupDisabled;
|
|
61741
|
+
}
|
|
61611
61742
|
async init(config) {
|
|
61612
61743
|
this.isFirstSession = storageService.getDevice() === null && !storageService.getAnonymousMode();
|
|
61744
|
+
// Cleared per configure so a transient failure cannot disable a later run.
|
|
61745
|
+
this.startupDisabled = false;
|
|
61746
|
+
// `Nami.configure` has already normalised a missing or undecodable initialConfig to `{}`,
|
|
61747
|
+
// so "has content" is Apple's `initialConfig != nil`.
|
|
61748
|
+
this.hasInitialConfig = Object.keys(config.initialConfig ?? {}).length > 0;
|
|
61613
61749
|
this.setInitialValues(config);
|
|
61614
|
-
|
|
61750
|
+
this.lastConfig = config;
|
|
61751
|
+
this.lastStartupRunAt = Date.now();
|
|
61752
|
+
this.startupInFlight = true;
|
|
61753
|
+
try {
|
|
61754
|
+
if (!(await this.fetchPlatformConfig()))
|
|
61755
|
+
return;
|
|
61756
|
+
await this.runStartupAfterConfig(config);
|
|
61757
|
+
}
|
|
61758
|
+
finally {
|
|
61759
|
+
this.startupInFlight = false;
|
|
61760
|
+
}
|
|
61761
|
+
}
|
|
61762
|
+
/**
|
|
61763
|
+
* The app returned to the foreground. Re-reads the platform config, as Apple's `.appResume`
|
|
61764
|
+
* and Android's `onAppComesFromBackground` do, so a config change — the `sdk` kill switch
|
|
61765
|
+
* included — reaches a long-lived tab or app without a cold start.
|
|
61766
|
+
*
|
|
61767
|
+
* - Skipped within {@link RESUME_THROTTLE_MS} of the last launch/resume, and while one is
|
|
61768
|
+
* still running.
|
|
61769
|
+
* - When the launch had **stopped** for want of a config and one is now usable, the rest of
|
|
61770
|
+
* startup runs — the steps an Apple resume re-runs because the launch never executed them.
|
|
61771
|
+
* - Otherwise this is a config refresh only. Apple and Android also re-run device, campaigns,
|
|
61772
|
+
* profile, products and the session start on resume; core does not yet, and has no
|
|
61773
|
+
* session end on background for a second session start to pair with (NAM-4623).
|
|
61774
|
+
*/
|
|
61775
|
+
async resume() {
|
|
61776
|
+
if (!this.lastConfig || this.startupInFlight)
|
|
61777
|
+
return;
|
|
61778
|
+
if (Date.now() - this.lastStartupRunAt < RESUME_THROTTLE_MS) {
|
|
61779
|
+
logger.debug("Resuming too quickly to call the service.");
|
|
61780
|
+
return;
|
|
61781
|
+
}
|
|
61782
|
+
const config = this.lastConfig;
|
|
61783
|
+
const wasStopped = this.startupDisabled;
|
|
61784
|
+
this.lastStartupRunAt = Date.now();
|
|
61785
|
+
this.startupInFlight = true;
|
|
61786
|
+
this.startupDisabled = false;
|
|
61787
|
+
try {
|
|
61788
|
+
if (!(await this.fetchPlatformConfig()) || !wasStopped)
|
|
61789
|
+
return;
|
|
61790
|
+
logger.info("Usable app config on resume - completing the startup that stopped at launch");
|
|
61791
|
+
await this.runStartupAfterConfig(config);
|
|
61792
|
+
}
|
|
61793
|
+
catch (error) {
|
|
61794
|
+
logger.warn(`Resume refresh failed: ${error}`);
|
|
61795
|
+
}
|
|
61796
|
+
finally {
|
|
61797
|
+
this.startupInFlight = false;
|
|
61798
|
+
}
|
|
61799
|
+
}
|
|
61800
|
+
/** Everything startup runs once the platform-config step has found a usable config. */
|
|
61801
|
+
async runStartupAfterConfig(config) {
|
|
61615
61802
|
await this.initAndFetchRequiredData(config);
|
|
61616
61803
|
SessionService.instance.startSession();
|
|
61617
61804
|
}
|
|
61805
|
+
/** Forgets the configuration a resume would run against; called by `Nami.reset()`. */
|
|
61806
|
+
clearResumeState() {
|
|
61807
|
+
this.lastConfig = null;
|
|
61808
|
+
this.lastStartupRunAt = 0;
|
|
61809
|
+
this.startupDisabled = false;
|
|
61810
|
+
}
|
|
61811
|
+
/**
|
|
61812
|
+
* The platform-config startup step, ahead of device registration — the position it holds on
|
|
61813
|
+
* Apple (`.fetchPlatformConfig`) and Android (`fetchAppConfigOnce`) (NAM-4464, NAM-4589).
|
|
61814
|
+
* Without an initial config it is awaited, so everything downstream — `campaign_cache_ttl`
|
|
61815
|
+
* included — is evaluated against the config it leaves in storage. With one it resolves at
|
|
61816
|
+
* once and the request finishes in the background (see `fetchConfigForStartup`).
|
|
61817
|
+
*
|
|
61818
|
+
* @returns false when there is no usable config, in which case startup must stop.
|
|
61819
|
+
*/
|
|
61820
|
+
async fetchPlatformConfig() {
|
|
61821
|
+
const outcome = await ConfigRepository.instance.fetchConfigForStartup(this.hasInitialConfig);
|
|
61822
|
+
if (!outcome.usable) {
|
|
61823
|
+
this.startupDisabled = true;
|
|
61824
|
+
logger.error(`Nami startup stopped: ${outcome.reason}`);
|
|
61825
|
+
return false;
|
|
61826
|
+
}
|
|
61827
|
+
return true;
|
|
61828
|
+
}
|
|
61618
61829
|
setInitialValues(config) {
|
|
61619
61830
|
const baseConfig = { ...config };
|
|
61620
61831
|
delete baseConfig.initialConfig;
|
|
@@ -61875,7 +62086,7 @@ class LastLaunchStore {
|
|
|
61875
62086
|
}
|
|
61876
62087
|
}
|
|
61877
62088
|
|
|
61878
|
-
var _Nami_isInitialized;
|
|
62089
|
+
var _Nami_isInitialized, _Nami_removeForegroundListener;
|
|
61879
62090
|
// NamiFlowManager is intentionally NOT imported at top level — it
|
|
61880
62091
|
// transitively imports back to this module (`Nami` for logging), and
|
|
61881
62092
|
// pulling it in here causes a load-order cycle that breaks tests
|
|
@@ -61883,6 +62094,7 @@ var _Nami_isInitialized;
|
|
|
61883
62094
|
class Nami {
|
|
61884
62095
|
constructor() {
|
|
61885
62096
|
_Nami_isInitialized.set(this, false);
|
|
62097
|
+
_Nami_removeForegroundListener.set(this, null);
|
|
61886
62098
|
this.maxLogging = false;
|
|
61887
62099
|
}
|
|
61888
62100
|
get isInitialized() {
|
|
@@ -61906,9 +62118,13 @@ class Nami {
|
|
|
61906
62118
|
* integrating app, consistent with the Apple and Android SDKs.
|
|
61907
62119
|
*/
|
|
61908
62120
|
static async reset() {
|
|
62121
|
+
var _a;
|
|
61909
62122
|
storageService.clearAll();
|
|
61910
62123
|
clearInMemoryAnonymousMode();
|
|
61911
62124
|
__classPrivateFieldSet(Nami.instance, _Nami_isInitialized, false, "f");
|
|
62125
|
+
__classPrivateFieldGet((_a = Nami.instance), _Nami_removeForegroundListener, "f")?.call(_a);
|
|
62126
|
+
__classPrivateFieldSet(Nami.instance, _Nami_removeForegroundListener, null, "f");
|
|
62127
|
+
NamiRefs.instance.clearResumeState();
|
|
61912
62128
|
// In-memory singleton state that previously survived reset and
|
|
61913
62129
|
// bled into the next configure() cycle.
|
|
61914
62130
|
NamiProfileManager$1.instance.setExternalId(undefined);
|
|
@@ -61971,6 +62187,18 @@ class Nami {
|
|
|
61971
62187
|
}
|
|
61972
62188
|
config.initialConfig = {};
|
|
61973
62189
|
}
|
|
62190
|
+
/**
|
|
62191
|
+
* Subscribes the resume config refresh to the host's foreground signal, once per process —
|
|
62192
|
+
* a reconfigure must not stack a second listener (the Android defect NAM-4541 fixed).
|
|
62193
|
+
* Registered before startup runs; `resume()` itself skips while startup is in flight.
|
|
62194
|
+
*/
|
|
62195
|
+
listenForAppForeground() {
|
|
62196
|
+
if (__classPrivateFieldGet(this, _Nami_removeForegroundListener, "f"))
|
|
62197
|
+
return;
|
|
62198
|
+
__classPrivateFieldSet(this, _Nami_removeForegroundListener, getPlatformAdapters().device.onAppForeground?.(() => {
|
|
62199
|
+
void NamiRefs.instance.resume();
|
|
62200
|
+
}) ?? null, "f");
|
|
62201
|
+
}
|
|
61974
62202
|
async initializeSDK(config) {
|
|
61975
62203
|
let fullReconfig = false;
|
|
61976
62204
|
let partialReconfig = false;
|
|
@@ -62011,6 +62239,7 @@ class Nami {
|
|
|
62011
62239
|
// configure SDK with new config
|
|
62012
62240
|
__classPrivateFieldSet(this, _Nami_isInitialized, true, "f");
|
|
62013
62241
|
NamiAPI.configure(config);
|
|
62242
|
+
this.listenForAppForeground();
|
|
62014
62243
|
await NamiRefs.instance.init(config);
|
|
62015
62244
|
logger.info("SDK successfully initialized!");
|
|
62016
62245
|
const state = partialReconfig || fullReconfig ? RECONFIG_SUCCESS : INITIAL_SUCCESS;
|
|
@@ -62022,7 +62251,7 @@ class Nami {
|
|
|
62022
62251
|
};
|
|
62023
62252
|
}
|
|
62024
62253
|
}
|
|
62025
|
-
_Nami_isInitialized = new WeakMap();
|
|
62254
|
+
_Nami_isInitialized = new WeakMap(), _Nami_removeForegroundListener = new WeakMap();
|
|
62026
62255
|
Nami.instance = new Nami();
|
|
62027
62256
|
|
|
62028
62257
|
const VALID_STYLES = new Set(['fullscreen', 'sheet', 'compact_sheet', 'modal']);
|
|
@@ -65992,4 +66221,4 @@ var internal = /*#__PURE__*/Object.freeze({
|
|
|
65992
66221
|
NamiPurchaseManager: NamiPurchaseManager
|
|
65993
66222
|
});
|
|
65994
66223
|
|
|
65995
|
-
export { ALREADY_CONFIGURED, ANONYMOUS_MODE, ANONYMOUS_MODE_ALREADY_OFF, ANONYMOUS_MODE_ALREADY_ON, ANONYMOUS_MODE_LOGIN_NOT_ALLOWED, ANONYMOUS_UUID, APIError, API_ACTIVE_ENTITLEMENTS, API_CAMPAIGN_RULES, API_CAMPAIGN_SESSION_TIMESTAMP, API_CONFIG, API_MAX_CALLS_LIMIT, API_PAYWALLS, API_PRODUCTS, API_RETRY_DELAY_SEC, API_TIMEOUT_LIMIT, API_TRAFFIC_OBSERVER, API_VERSION, AUTH_DEVICE, AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, AVAILABLE_CAMPAIGNS_CHANGED, AccountStateAction, AnonymousCDPError, AnonymousLoginError, AnonymousModeAlreadyOffError, AnonymousModeAlreadyOnError, BASE_STAGING_URL, BASE_URL, BASE_URL_PATH, BadRequestError, BasicNamiFlow, BorderMap, BorderSideMap, CAMPAIGN_NOT_AVAILABLE, CUSTOMER_ATTRIBUTES_KEY_PREFIX, CUSTOMER_JOURNEY_STATE_CHANGED, CUSTOM_HOST_PREFIX, CampaignNotAvailableError, CampaignRuleConversionEventType, CampaignRuleRepository, Capabilities, ClientError, ConfigRepository, ConflictError, CustomerJourneyRepository, DEFAULT_JOURNEY_SETTINGS, DEVELOPMENT, DEVICE_API_TIMEOUT_LIMIT, DEVICE_ID_NOT_SET, DEVICE_ID_REQUIRED, DISABLE_ASYNC_LOGIN_LOGOUT, DeviceIDRequiredError, DeviceRepository, EXTENDED_CLIENT_INFO_DELIMITER, EXTENDED_CLIENT_INFO_PREFIX, EXTENDED_PLATFORM, EXTENDED_PLATFORM_VERSION, EXTERNAL_ID_REQUIRED, EntitlementRepository, EntitlementUtils, ExternalIDRequiredError, FLOW_SCREENS_NOT_AVAILABLE, FlowScreensNotAvailableError, HTML_REGEX, INITIAL_APP_CONFIG, INITIAL_CAMPAIGN_RULES, INITIAL_PAYWALLS, INITIAL_PRODUCTS, INITIAL_SESSION_COUNTER_VALUE, INITIAL_SUCCESS, InternalServerError, KEY_SESSION_COUNTER, LIQUID_VARIABLE_REGEX, LOCAL_NAMI_ENTITLEMENTS, LOG_HTTP_REQUESTS, LOG_HTTP_TRAFFIC, LaunchCampaignError, LaunchContextResolver, LogLevel, NAMI_CONFIGURATION, NAMI_CUSTOMER_JOURNEY_STATE, NAMI_LANGUAGE_CODE, NAMI_LAST_IMPRESSION_ID, NAMI_LAUNCH_ID, NAMI_PROFILE, NAMI_PURCHASE_CHANNEL, NAMI_PURCHASE_IMPRESSION_ID, NAMI_SDK_PACKAGE_VERSION, NAMI_SDK_VERSION, NAMI_SESSION_ID, NAMI_STORAGE_KEYS, Nami, NamiAPI, NamiAnimationType, NamiCampaignManager$1 as NamiCampaignManager, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager$1 as NamiCustomerManager, NamiEntitlementManager$1 as NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager$1 as NamiFlowManager, NamiFlowStepType, NamiHandoffTag, NamiPaywallAction, NamiPaywallManager$1 as NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiPermissionOutcome, NamiPurchaseManager$1 as NamiPurchaseManager, NamiRefs, NamiReservedActions, NotFoundError, PAYWALL_ACTION_EVENT, PLATFORM_ID_REQUIRED, PRODUCTION, PaywallManagerEvents, PaywallRepository, PaywallState, PlacementLabelResolver, PlatformIDRequiredError, ProductRepository, RECONFIG_SUCCESS, RetryLimitExceededError, SDKNotInitializedError, SDK_NOT_INITIALIZED, SERVER_NAMI_ENTITLEMENTS, SESSION_REQUIRED, SHOULD_SHOW_LOADING_INDICATOR, SKU_TEXT_REGEX, SMART_TEXT_PATTERN, STARTUP_TELEMETRY, STATUS_BAD_REQUEST, STATUS_CONFLICT, STATUS_INTERNAL_SERVER_ERROR, STATUS_NOT_FOUND, STATUS_SUCCESS, SessionService, SimpleEventTarget, StorageService, TRANSPORT_FAILURE_STATUS, UNABLE_TO_UPDATE_CDP_ID, USE_STAGING_API, VALIDATE_PRODUCT_GROUPS, VAR_REGEX, NamiProfileManager$1 as _NamiProfileManager, internal as _internal, activateEntitlementByPurchase, activeEntitlements, aggregateScreenreaderText, allCampaigns, allPaywalls, applyEntitlementActivation, audienceSplitPosition, bestUrlCampaignMatch, bigintToUuid, checkAnySkuHasPromoOffer, checkAnySkuHasTrialOffer, convertISO8601PeriodToText, convertLocale, convertOfferToPricingPhase, createNamiEntitlements, currentSku, didReceiveResponse, empty, extractStandardPricingPhases, formatDate, formattedPrice, generateUUID, getApiCampaigns, getApiPaywalls, getBaseUrl, getBillingPeriodNumber, getCurrencyFormat, getDeviceData, getDeviceFormFactor, getDeviceScaleFactor, getEffectiveWebStyle, getEntitlementRefIdsForSku, getExtendedClientInfo, getFreeTrialPeriod, getInitialCampaigns, getInitialPaywalls, getJourneySettings, getPaywall, getPaywallDataFromLabel, getPercentagePriceDifference, getPeriodNumberInDays, getPeriodNumberInWeeks, getPlatformAdapters, getPriceDifference, getPricePerMonth, getProductDetail, getPurchaseAdapter, getReferenceSku, getSkuProductDetailKeys, getSkuSmartTextValue, getSlideSmartTextValue, getStandardBillingPeriod, getTranslate, getUrlParams, handleErrors, hasAllPaywalls, hasCapability, hasPurchaseManagement, initialState, invokeHandler, isAnonymousMode, isInitialConfigCompressed, isNamiFlowCampaign, isSubscription, isValidISODate, isValidUrl, logger, mapAnonymousCampaigns, namiBuySKU, normalizeLaunchContext, parseToSemver, postConversion, productDetail, registerAPITrafficObserver, registerPlatformAdapters, registerPurchaseAdapter, resolveLoopSource, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateForm, validateMinSDKVersion, validateTextInput };
|
|
66224
|
+
export { ALREADY_CONFIGURED, ANONYMOUS_MODE, ANONYMOUS_MODE_ALREADY_OFF, ANONYMOUS_MODE_ALREADY_ON, ANONYMOUS_MODE_LOGIN_NOT_ALLOWED, ANONYMOUS_UUID, APIError, API_ACTIVE_ENTITLEMENTS, API_CAMPAIGN_RULES, API_CAMPAIGN_SESSION_TIMESTAMP, API_CONFIG, API_MAX_CALLS_LIMIT, API_PAYWALLS, API_PRODUCTS, API_RETRY_DELAY_SEC, API_TIMEOUT_LIMIT, API_TRAFFIC_OBSERVER, API_VERSION, AUTH_DEVICE, AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, AVAILABLE_CAMPAIGNS_CHANGED, AccountStateAction, AnonymousCDPError, AnonymousLoginError, AnonymousModeAlreadyOffError, AnonymousModeAlreadyOnError, BASE_STAGING_URL, BASE_URL, BASE_URL_PATH, BadRequestError, BasicNamiFlow, BorderMap, BorderSideMap, CAMPAIGN_NOT_AVAILABLE, CONFIG_API_TIMEOUT_LIMIT, CONFIG_MAX_ATTEMPTS, CUSTOMER_ATTRIBUTES_KEY_PREFIX, CUSTOMER_JOURNEY_STATE_CHANGED, CUSTOM_HOST_PREFIX, CampaignNotAvailableError, CampaignRuleConversionEventType, CampaignRuleRepository, Capabilities, ClientError, ConfigRepository, ConflictError, CustomerJourneyRepository, DEFAULT_JOURNEY_SETTINGS, DEVELOPMENT, DEVICE_API_TIMEOUT_LIMIT, DEVICE_ID_NOT_SET, DEVICE_ID_REQUIRED, DISABLE_ASYNC_LOGIN_LOGOUT, DeviceIDRequiredError, DeviceRepository, EXTENDED_CLIENT_INFO_DELIMITER, EXTENDED_CLIENT_INFO_PREFIX, EXTENDED_PLATFORM, EXTENDED_PLATFORM_VERSION, EXTERNAL_ID_REQUIRED, EntitlementRepository, EntitlementUtils, ExternalIDRequiredError, FLOW_SCREENS_NOT_AVAILABLE, FlowScreensNotAvailableError, HTML_REGEX, INITIAL_APP_CONFIG, INITIAL_CAMPAIGN_RULES, INITIAL_PAYWALLS, INITIAL_PRODUCTS, INITIAL_SESSION_COUNTER_VALUE, INITIAL_SUCCESS, InternalServerError, KEY_SESSION_COUNTER, LIQUID_VARIABLE_REGEX, LOCAL_NAMI_ENTITLEMENTS, LOG_HTTP_REQUESTS, LOG_HTTP_TRAFFIC, LaunchCampaignError, LaunchContextResolver, LogLevel, NAMI_CONFIGURATION, NAMI_CUSTOMER_JOURNEY_STATE, NAMI_LANGUAGE_CODE, NAMI_LAST_IMPRESSION_ID, NAMI_LAUNCH_ID, NAMI_PROFILE, NAMI_PURCHASE_CHANNEL, NAMI_PURCHASE_IMPRESSION_ID, NAMI_SDK_PACKAGE_VERSION, NAMI_SDK_VERSION, NAMI_SESSION_ID, NAMI_STORAGE_KEYS, Nami, NamiAPI, NamiAnimationType, NamiCampaignManager$1 as NamiCampaignManager, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager$1 as NamiCustomerManager, NamiEntitlementManager$1 as NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager$1 as NamiFlowManager, NamiFlowStepType, NamiHandoffTag, NamiPaywallAction, NamiPaywallManager$1 as NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiPermissionOutcome, NamiPurchaseManager$1 as NamiPurchaseManager, NamiRefs, NamiReservedActions, NotFoundError, PAYWALL_ACTION_EVENT, PLATFORM_ID_REQUIRED, PRODUCTION, PaywallManagerEvents, PaywallRepository, PaywallState, PlacementLabelResolver, PlatformIDRequiredError, ProductRepository, RECONFIG_SUCCESS, RESUME_THROTTLE_MS, RetryLimitExceededError, SDKNotInitializedError, SDK_NOT_INITIALIZED, SERVER_NAMI_ENTITLEMENTS, SESSION_REQUIRED, SHOULD_SHOW_LOADING_INDICATOR, SIMULATE_CONFIG_FETCH_FAILURE, SKU_TEXT_REGEX, SMART_TEXT_PATTERN, STARTUP_TELEMETRY, STATUS_BAD_REQUEST, STATUS_CONFLICT, STATUS_INTERNAL_SERVER_ERROR, STATUS_NOT_FOUND, STATUS_SUCCESS, SessionService, SimpleEventTarget, StorageService, TRANSPORT_FAILURE_STATUS, UNABLE_TO_UPDATE_CDP_ID, USE_STAGING_API, VALIDATE_PRODUCT_GROUPS, VAR_REGEX, NamiProfileManager$1 as _NamiProfileManager, internal as _internal, activateEntitlementByPurchase, activeEntitlements, aggregateScreenreaderText, allCampaigns, allPaywalls, applyEntitlementActivation, audienceSplitPosition, bestUrlCampaignMatch, bigintToUuid, checkAnySkuHasPromoOffer, checkAnySkuHasTrialOffer, convertISO8601PeriodToText, convertLocale, convertOfferToPricingPhase, createNamiEntitlements, currentSku, didReceiveResponse, empty, extractStandardPricingPhases, formatDate, formattedPrice, generateUUID, getApiCampaigns, getApiPaywalls, getBaseUrl, getBillingPeriodNumber, getCurrencyFormat, getDeviceData, getDeviceFormFactor, getDeviceScaleFactor, getEffectiveWebStyle, getEntitlementRefIdsForSku, getExtendedClientInfo, getFreeTrialPeriod, getInitialCampaigns, getInitialPaywalls, getJourneySettings, getPaywall, getPaywallDataFromLabel, getPercentagePriceDifference, getPeriodNumberInDays, getPeriodNumberInWeeks, getPlatformAdapters, getPriceDifference, getPricePerMonth, getProductDetail, getPurchaseAdapter, getReferenceSku, getSkuProductDetailKeys, getSkuSmartTextValue, getSlideSmartTextValue, getStandardBillingPeriod, getTranslate, getUrlParams, handleErrors, hasAllPaywalls, hasCapability, hasPurchaseManagement, initialState, invokeHandler, isAnonymousMode, isInitialConfigCompressed, isNamiFlowCampaign, isSubscription, isValidISODate, isValidUrl, logger, mapAnonymousCampaigns, namiBuySKU, normalizeLaunchContext, parseToSemver, postConversion, productDetail, registerAPITrafficObserver, registerPlatformAdapters, registerPurchaseAdapter, resolveLoopSource, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateForm, validateMinSDKVersion, validateTextInput };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namiml/sdk-core",
|
|
3
|
-
"version": "3.4.12-dev.
|
|
3
|
+
"version": "3.4.12-dev.202609252349",
|
|
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",
|