@alipay/ams-checkout 0.0.1783663570-dev.1 → 0.0.1783663570-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,6 +11,7 @@ import type { AMSCheckoutOptions, IAppendParams, InitSecurityConfig, IoptionsPar
11
11
  import { EventCenter } from '../../util/index';
12
12
  import { Logger } from '../../util/logger';
13
13
  import { Security } from '../../util/security';
14
+ import type { ISecurity } from '../../util/security-registry';
14
15
  export default class AMSSDK {
15
16
  options: AMSCheckoutOptions;
16
17
  originOptions: IoptionsParams;
@@ -37,13 +38,20 @@ export default class AMSSDK {
37
38
  scene?: string;
38
39
  }): void;
39
40
  /**
40
- * @description Obtain security SDK through scenario identification
41
+ * @description Obtain security SDK through scenario identification (async-aware)
42
+ * Handles three states: ready, loading, not found
41
43
  */
42
- _getSecuritySDKByProductScene(securityConfig: InitSecurityConfig): Security;
44
+ _getSecuritySDKByProductScene(securityConfig: InitSecurityConfig): ISecurity;
43
45
  /**
44
- * @description New security SDK through scenario identification
46
+ * @description Await security SDK by product scene (async)
47
+ * Returns the Security instance even if currently loading
45
48
  */
46
- _newSecuritySDKByScene(securityConfig: InitSecurityConfig, successCallback?: () => void, failCallback?: (errMsg?: string) => void): Security;
49
+ _awaitSecuritySDKByProductScene(securityConfig: InitSecurityConfig): Promise<Security | undefined>;
50
+ /**
51
+ * @description New security SDK through scenario identification (async-aware)
52
+ * Uses shared SecuritySdkRegistry and triggers ApdidLoader
53
+ */
54
+ _newSecuritySDKByScene(securityConfig: InitSecurityConfig, successCallback?: () => void, failCallback?: (errMsg?: string) => void): void;
47
55
  /**
48
56
  * @description Obtain risk control configuration in local storage
49
57
  */
@@ -28,7 +28,9 @@ import { EnvironmentEnum, modeEnum, networkModeEnum, osTypeEnum, ProductSceneEnu
28
28
  import { checkTimeElapsed, device, EventCenter, getOrSetStorageId, getType, queryParse, safeJson } from "../../util/index";
29
29
  import CallApp from "../../util/intl-callapp/es/main";
30
30
  import { LogConfig, Logger } from "../../util/logger";
31
- import { getSecurityConfigStorageKey, getSecurityHost, getSecurityScene, Security, SecurityRegionEnum } from "../../util/security";
31
+ import { getSecurityConfigStorageKey, getSecurityHost, getSecurityScene, Security, SecurityRegionEnum, mapEnvironment } from "../../util/security";
32
+ import { SecuritySdkRegistry } from "../../util/security-registry";
33
+ import { ApdidLoader } from "../../util/jshield-apdid";
32
34
  import { compareVersion } from "../../util/versionCompare";
33
35
  import { BusManager, BusMessage } from "../bus";
34
36
  import PreloadHelper from "../../foundation/utils/preload_helper";
@@ -166,15 +168,44 @@ var AMSSDK = /*#__PURE__*/function () {
166
168
  }, {
167
169
  productScene: product
168
170
  }).send();
169
- var sdk = this._getSecuritySDKByProductScene({
170
- product: product || scene
171
- });
172
- if (sdk) {
173
- console.log('[web-sdk] skip init security sdk because it is already loaded');
174
- return;
171
+ var effectiveProduct = product || scene;
172
+ var storage = this.getSecurityConfigStorage(effectiveProduct);
173
+ var securityScene = storage.scene || getSecurityScene(effectiveProduct);
174
+
175
+ // Check shared registry for all states
176
+ var registryEntry = SecuritySdkRegistry.get(securityScene);
177
+ if (registryEntry) {
178
+ if (registryEntry.status === 'ready') {
179
+ console.log('[web-sdk] skip init security sdk because it is already loaded');
180
+ this.logger.logInfo({
181
+ title: 'sdk_event_securitySdkPreInitSuccess'
182
+ }, {
183
+ productScene: product
184
+ }).send();
185
+ return;
186
+ }
187
+ if (registryEntry.status === 'loading') {
188
+ console.log('[web-sdk] security sdk is already loading, waiting...');
189
+ registryEntry.loadingPromise.then(function () {
190
+ _this.logger.logInfo({
191
+ title: 'sdk_event_securitySdkPreInitSuccess'
192
+ }, {
193
+ productScene: product
194
+ }).send();
195
+ }).catch(function (err) {
196
+ _this.logger.logError({
197
+ title: 'sdk_error_securitySdkInitFailed',
198
+ msg: err === null || err === void 0 ? void 0 : err.message
199
+ }, {
200
+ productScene: product,
201
+ sign: 'Active initialization'
202
+ }).send();
203
+ });
204
+ return;
205
+ }
175
206
  }
176
207
  this._newSecuritySDKByScene({
177
- product: product || scene,
208
+ product: effectiveProduct,
178
209
  region: SecurityRegionEnum.SG
179
210
  }, function () {
180
211
  _this.logger.logInfo({
@@ -193,13 +224,27 @@ var AMSSDK = /*#__PURE__*/function () {
193
224
  });
194
225
  }
195
226
  /**
196
- * @description Obtain security SDK through scenario identification
227
+ * @description Obtain security SDK through scenario identification (async-aware)
228
+ * Handles three states: ready, loading, not found
197
229
  */
198
230
  }, {
199
231
  key: "_getSecuritySDKByProductScene",
200
232
  value: function _getSecuritySDKByProductScene(securityConfig) {
201
233
  var storage = this.getSecurityConfigStorage(securityConfig.product);
202
234
  var scene = storage.scene || getSecurityScene(securityConfig.product);
235
+
236
+ // First check the shared registry (handles ready/loading/failed states)
237
+ var registryEntry = SecuritySdkRegistry.get(scene);
238
+ if (registryEntry) {
239
+ if (registryEntry.status === 'ready') {
240
+ return registryEntry.instance;
241
+ }
242
+ // Loading or failed - return undefined for backward compatibility
243
+ // Callers should use _awaitSecuritySDKByProductScene for async access
244
+ return undefined;
245
+ }
246
+
247
+ // Fallback: check legacy map and preload helper
203
248
  var securitySdk = this.securitySdkMap.get(scene);
204
249
  if (!securitySdk) {
205
250
  securitySdk = PreloadHelper.getSecuritySdk(scene);
@@ -210,24 +255,105 @@ var AMSSDK = /*#__PURE__*/function () {
210
255
  }
211
256
  return securitySdk;
212
257
  }
258
+
259
+ /**
260
+ * @description Await security SDK by product scene (async)
261
+ * Returns the Security instance even if currently loading
262
+ */
263
+ }, {
264
+ key: "_awaitSecuritySDKByProductScene",
265
+ value: (function () {
266
+ var _awaitSecuritySDKByProductScene2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(securityConfig) {
267
+ var storage, scene, instance;
268
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
269
+ while (1) switch (_context.prev = _context.next) {
270
+ case 0:
271
+ storage = this.getSecurityConfigStorage(securityConfig.product);
272
+ scene = storage.scene || getSecurityScene(securityConfig.product);
273
+ _context.next = 4;
274
+ return SecuritySdkRegistry.getInstance(scene);
275
+ case 4:
276
+ instance = _context.sent;
277
+ return _context.abrupt("return", instance);
278
+ case 6:
279
+ case "end":
280
+ return _context.stop();
281
+ }
282
+ }, _callee, this);
283
+ }));
284
+ function _awaitSecuritySDKByProductScene(_x) {
285
+ return _awaitSecuritySDKByProductScene2.apply(this, arguments);
286
+ }
287
+ return _awaitSecuritySDKByProductScene;
288
+ }()
213
289
  /**
214
- * @description New security SDK through scenario identification
290
+ * @description New security SDK through scenario identification (async-aware)
291
+ * Uses shared SecuritySdkRegistry and triggers ApdidLoader
215
292
  */
293
+ )
216
294
  }, {
217
295
  key: "_newSecuritySDKByScene",
218
296
  value: function _newSecuritySDKByScene(securityConfig, successCallback, failCallback) {
297
+ var _this$options2;
219
298
  var storage = this.getSecurityConfigStorage(securityConfig.product);
220
299
  var scene = storage.scene || getSecurityScene(securityConfig.product);
221
300
  var h5gateway = storage.h5gateway || getSecurityHost(securityConfig.region);
301
+
302
+ // Check if already exists in registry (avoid duplicates)
303
+ var existingEntry = SecuritySdkRegistry.get(scene);
304
+ if (existingEntry) {
305
+ if (existingEntry.status === 'ready') {
306
+ successCallback && successCallback();
307
+ return;
308
+ }
309
+ if (existingEntry.status === 'loading') {
310
+ // Wait for existing loading to complete
311
+ existingEntry.loadingPromise.then(function () {
312
+ successCallback && successCallback();
313
+ }).catch(function (err) {
314
+ failCallback && failCallback(err === null || err === void 0 ? void 0 : err.message);
315
+ });
316
+ return;
317
+ }
318
+ // failed status - allow retry by proceeding below
319
+ }
320
+
321
+ // 非阻塞调度 ApdidLoader 加载,不阻塞 SDK 初始化
322
+ // Security 内部的 ensureApdidLoaded() 会在需要 token 时按需等待加载完成
323
+ var apdidEnv = mapEnvironment((_this$options2 = this.options) === null || _this$options2 === void 0 || (_this$options2 = _this$options2.env) === null || _this$options2 === void 0 ? void 0 : _this$options2.environment);
324
+ var loader = ApdidLoader.getInstance();
325
+ loader.scheduleLoad({
326
+ environment: apdidEnv
327
+ });
222
328
  try {
329
+ var _this$options3;
330
+ var environment = (_this$options3 = this.options) === null || _this$options3 === void 0 || (_this$options3 = _this$options3.env) === null || _this$options3 === void 0 ? void 0 : _this$options3.environment;
223
331
  var securitySdk = new Security({
224
332
  scene: scene,
225
- h5gateway: h5gateway
333
+ h5gateway: h5gateway,
334
+ environment: environment
335
+ });
336
+
337
+ // Create loading promise and register in registry
338
+ var loadingPromise = new Promise(function (resolveLoading, rejectLoading) {
339
+ securitySdk.initSecurity(function () {
340
+ SecuritySdkRegistry.setReady(scene, securitySdk);
341
+ successCallback && successCallback();
342
+ resolveLoading(securitySdk);
343
+ }, function (msg) {
344
+ SecuritySdkRegistry.setFailed(scene, new Error(msg || 'Security init failed'));
345
+ failCallback && failCallback(msg);
346
+ rejectLoading(new Error(msg || 'Security init failed'));
347
+ });
226
348
  });
349
+
350
+ // Register as loading in the shared registry
351
+ SecuritySdkRegistry.setLoading(scene, loadingPromise);
352
+
353
+ // Also keep reference in the legacy map for backward compatibility
227
354
  this.securitySdkMap.set(scene, securitySdk);
228
- securitySdk.initSecurity(successCallback, failCallback);
229
- return securitySdk;
230
355
  } catch (error) {
356
+ SecuritySdkRegistry.setFailed(scene, new Error(error === null || error === void 0 ? void 0 : error.toString()));
231
357
  failCallback && failCallback(error === null || error === void 0 ? void 0 : error.toString());
232
358
  }
233
359
  }
@@ -333,17 +459,17 @@ var AMSSDK = /*#__PURE__*/function () {
333
459
  if (options !== null && options !== void 0 && options.onBeforeSubmit) {
334
460
  if (typeof (options === null || options === void 0 ? void 0 : options.onBeforeSubmit) !== 'function') throw new Error(ERRORMESSAGE.INIT_PARAMETER_ERROR.EVENT_ERROR.message);
335
461
  this._overrideSubscription(EVENT.beforeSubmit.name, /*#__PURE__*/function () {
336
- var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(payload) {
462
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(payload) {
337
463
  var eventCallbackId, res;
338
- return _regeneratorRuntime().wrap(function _callee$(_context) {
339
- while (1) switch (_context.prev = _context.next) {
464
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
465
+ while (1) switch (_context2.prev = _context2.next) {
340
466
  case 0:
341
467
  eventCallbackId = uuid();
342
- _context.prev = 1;
343
- _context.next = 4;
468
+ _context2.prev = 1;
469
+ _context2.next = 4;
344
470
  return options.onBeforeSubmit(payload);
345
471
  case 4:
346
- res = _context.sent;
472
+ res = _context2.sent;
347
473
  _this2._componentApp.dispatchToApp({
348
474
  context: {
349
475
  event: EVENT.beforeSubmitDone.name,
@@ -351,11 +477,11 @@ var AMSSDK = /*#__PURE__*/function () {
351
477
  data: res
352
478
  }
353
479
  });
354
- _context.next = 12;
480
+ _context2.next = 12;
355
481
  break;
356
482
  case 8:
357
- _context.prev = 8;
358
- _context.t0 = _context["catch"](1);
483
+ _context2.prev = 8;
484
+ _context2.t0 = _context2["catch"](1);
359
485
  _this2._componentApp.dispatchToApp({
360
486
  context: {
361
487
  event: EVENT.beforeSubmitDone.name,
@@ -367,15 +493,15 @@ var AMSSDK = /*#__PURE__*/function () {
367
493
  });
368
494
  _this2.logger.logError({
369
495
  title: 'sdk_error_before_submit',
370
- msg: JSON.stringify(_context.t0)
496
+ msg: JSON.stringify(_context2.t0)
371
497
  }).send();
372
498
  case 12:
373
499
  case "end":
374
- return _context.stop();
500
+ return _context2.stop();
375
501
  }
376
- }, _callee, null, [[1, 8]]);
502
+ }, _callee2, null, [[1, 8]]);
377
503
  }));
378
- return function (_x) {
504
+ return function (_x2) {
379
505
  return _ref2.apply(this, arguments);
380
506
  };
381
507
  }(), EVENT.beforeSubmit.uniqueKey);
@@ -1,10 +1,9 @@
1
1
  import { DeviceIdParameter, IoptionsParams } from '../../../types';
2
2
  import { PaymentContext, SDKMetaData, Service } from '../../index';
3
- import { Security } from './security';
4
3
  export declare class SecurityService implements Service {
5
4
  private logger;
6
5
  private productScene;
7
- static securitySdkMap: Map<string, Security>;
6
+ private environment?;
8
7
  init(initOptions: IoptionsParams, instanceId: string, sdkMetaData: SDKMetaData): void;
9
8
  update(paymentContext: PaymentContext): void;
10
9
  destroy(): void;
@@ -14,11 +13,17 @@ export declare class SecurityService implements Service {
14
13
  private _initSecurity;
15
14
  private logDeviceId;
16
15
  /**
17
- * @description Obtain security SDK through scenario identification
16
+ * Get the scene string from product enum
17
+ */
18
+ private _getSceneByProduct;
19
+ /**
20
+ * @description Obtain security SDK through scenario identification (async-aware)
21
+ * Handles three states: ready, loading, not found
18
22
  */
19
23
  private _getSecuritySDKByProductScene;
20
24
  /**
21
- * @description New security SDK through scenario identification
25
+ * @description New security SDK through scenario identification (async)
26
+ * Uses shared SecuritySdkRegistry to avoid duplicate initialization
22
27
  */
23
28
  private _newSecuritySDKByScene;
24
29
  /**
@@ -9,20 +9,24 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
9
9
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
10
10
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
11
11
  import { ProductSceneEnum } from "../../../types";
12
- import { Security, SecurityRegionEnum, getSecurityConfigStorageKey, getSecurityHost, getSecurityScene } from "./security";
12
+ import { Security, SecurityRegionEnum, getSecurityConfigStorageKey, getSecurityHost, getSecurityScene, mapEnvironment } from "./security";
13
13
  import { getOrSetStorageId, safeJson } from "../../../util";
14
+ import { SecuritySdkRegistry } from "../../../util/security-registry";
15
+ import { ApdidLoader } from "../../../util/jshield-apdid";
14
16
  import { ServiceProvider } from '..';
15
17
  export var SecurityService = /*#__PURE__*/function () {
16
18
  function SecurityService() {
17
19
  _classCallCheck(this, SecurityService);
18
20
  _defineProperty(this, "logger", void 0);
19
21
  _defineProperty(this, "productScene", ProductSceneEnum.EASY_PAY);
22
+ _defineProperty(this, "environment", void 0);
20
23
  }
21
24
  _createClass(SecurityService, [{
22
25
  key: "init",
23
26
  value: function init(initOptions, instanceId, sdkMetaData) {
24
27
  this.logger = ServiceProvider.getInstance(instanceId).getService('Log');
25
28
  this.productScene = sdkMetaData.productScene;
29
+ this.environment = initOptions === null || initOptions === void 0 ? void 0 : initOptions.environment;
26
30
  }
27
31
  }, {
28
32
  key: "update",
@@ -46,40 +50,44 @@ export var SecurityService = /*#__PURE__*/function () {
46
50
  return _context2.abrupt("return", new Promise(function (resolve) {
47
51
  // To avoid rendering being blocked, move the logic to the next event loop for processing
48
52
  setTimeout( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
49
- var getDeviceIdStartTime, securitySDK, deviceId;
53
+ var getDeviceIdStartTime, product, securitySDK, deviceId;
50
54
  return _regeneratorRuntime().wrap(function _callee$(_context) {
51
55
  while (1) switch (_context.prev = _context.next) {
52
56
  case 0:
53
57
  getDeviceIdStartTime = Date.now();
54
- securitySDK = _this._getSecuritySDKByProductScene({
55
- product: (deviceIdParameter === null || deviceIdParameter === void 0 ? void 0 : deviceIdParameter.productScene) || _this.productScene
58
+ product = (deviceIdParameter === null || deviceIdParameter === void 0 ? void 0 : deviceIdParameter.productScene) || _this.productScene;
59
+ _context.next = 4;
60
+ return _this._getSecuritySDKByProductScene({
61
+ product: product
56
62
  });
63
+ case 4:
64
+ securitySDK = _context.sent;
57
65
  deviceId = '';
58
66
  if (!securitySDK) {
59
- _context.next = 15;
67
+ _context.next = 18;
60
68
  break;
61
69
  }
62
70
  if (!(isPolling && parseInt(deviceIdParameter === null || deviceIdParameter === void 0 ? void 0 : deviceIdParameter.tokenCollectTime) > 0)) {
63
- _context.next = 10;
71
+ _context.next = 13;
64
72
  break;
65
73
  }
66
- _context.next = 7;
74
+ _context.next = 10;
67
75
  return securitySDK.pollingGetApdidToken(deviceIdParameter);
68
- case 7:
76
+ case 10:
69
77
  _context.t0 = _context.sent;
70
- _context.next = 13;
78
+ _context.next = 16;
71
79
  break;
72
- case 10:
73
- _context.next = 12;
80
+ case 13:
81
+ _context.next = 15;
74
82
  return securitySDK.getApdidToken();
75
- case 12:
83
+ case 15:
76
84
  _context.t0 = _context.sent;
77
- case 13:
85
+ case 16:
78
86
  deviceId = _context.t0;
79
87
  _this.logDeviceId(deviceId, getDeviceIdStartTime);
80
- case 15:
88
+ case 18:
81
89
  resolve(deviceId);
82
- case 16:
90
+ case 19:
83
91
  case "end":
84
92
  return _context.stop();
85
93
  }
@@ -145,6 +153,10 @@ export var SecurityService = /*#__PURE__*/function () {
145
153
  var isPre,
146
154
  timeout,
147
155
  sdkAction,
156
+ scene,
157
+ existing,
158
+ apdidEnv,
159
+ loader,
148
160
  _args5 = arguments;
149
161
  return _regeneratorRuntime().wrap(function _callee5$(_context5) {
150
162
  while (1) switch (_context5.prev = _context5.next) {
@@ -152,17 +164,78 @@ export var SecurityService = /*#__PURE__*/function () {
152
164
  isPre = _args5.length > 0 && _args5[0] !== undefined ? _args5[0] : false;
153
165
  timeout = _args5.length > 1 ? _args5[1] : undefined;
154
166
  sdkAction = isPre ? 'PreInit' : 'Init';
155
- if (!this._getSecuritySDKByProductScene({
156
- product: this.productScene
157
- })) {
158
- _context5.next = 5;
167
+ scene = this._getSceneByProduct(this.productScene); // Check if already ready
168
+ if (!SecuritySdkRegistry.isReady(scene)) {
169
+ _context5.next = 6;
159
170
  break;
160
171
  }
161
172
  return _context5.abrupt("return", Promise.resolve());
162
- case 5:
173
+ case 6:
174
+ if (!SecuritySdkRegistry.isLoading(scene)) {
175
+ _context5.next = 19;
176
+ break;
177
+ }
178
+ existing = SecuritySdkRegistry.get(scene);
179
+ if (!(existing && existing.status === 'loading')) {
180
+ _context5.next = 19;
181
+ break;
182
+ }
183
+ _context5.prev = 9;
184
+ _context5.next = 12;
185
+ return existing.loadingPromise;
186
+ case 12:
187
+ this.logger.logInfo({
188
+ title: "sdk_event_securitySdk".concat(sdkAction, "Success")
189
+ }).send();
190
+ _context5.next = 18;
191
+ break;
192
+ case 15:
193
+ _context5.prev = 15;
194
+ _context5.t0 = _context5["catch"](9);
195
+ this.logger.logError({
196
+ title: 'sdk_error_securitySdkInitFailed'
197
+ }, {
198
+ productScene: this.productScene,
199
+ sign: isPre ? 'Active initialization' : 'SDK internal initialization'
200
+ }).send();
201
+ case 18:
202
+ return _context5.abrupt("return");
203
+ case 19:
163
204
  this.logger.logInfo({
164
205
  title: "sdk_event_securitySdk".concat(sdkAction)
165
206
  });
207
+
208
+ // 非阻塞调度 ApdidLoader 加载,在浏览器空闲时发起,2s 超时兜底
209
+ // Security 内部的 ensureApdidLoaded() 会在需要 token 时按需等待加载完成
210
+ apdidEnv = mapEnvironment(this.environment);
211
+ loader = ApdidLoader.getInstance();
212
+ loader.scheduleLoad({
213
+ environment: apdidEnv,
214
+ callbacks: {
215
+ onLoad: function onLoad(duration) {
216
+ _this2.logger.logInfo({
217
+ title: 'sdk_event_securitySdkScriptLoaded'
218
+ }, {
219
+ eventMessage: "".concat(duration)
220
+ }).send();
221
+ },
222
+ onLoadFailed: function onLoadFailed(error) {
223
+ _this2.logger.logError({
224
+ title: 'sdk_event_securitySdkLoadFailed',
225
+ msg: error.message
226
+ }, {
227
+ productScene: _this2.productScene
228
+ }).send();
229
+ },
230
+ onLoadTimeout: function onLoadTimeout() {
231
+ _this2.logger.logError({
232
+ title: 'sdk_event_securitySdkScriptLoadTimeout'
233
+ }, {
234
+ productScene: _this2.productScene
235
+ }).send();
236
+ }
237
+ }
238
+ });
166
239
  return _context5.abrupt("return", new Promise(function (resolve, reject) {
167
240
  if (timeout) {
168
241
  setTimeout(function () {
@@ -196,11 +269,11 @@ export var SecurityService = /*#__PURE__*/function () {
196
269
  reject();
197
270
  });
198
271
  }));
199
- case 7:
272
+ case 24:
200
273
  case "end":
201
274
  return _context5.stop();
202
275
  }
203
- }, _callee5, this);
276
+ }, _callee5, this, [[9, 15]]);
204
277
  }));
205
278
  function _initSecurity() {
206
279
  return _initSecurity3.apply(this, arguments);
@@ -227,34 +300,85 @@ export var SecurityService = /*#__PURE__*/function () {
227
300
  }
228
301
 
229
302
  /**
230
- * @description Obtain security SDK through scenario identification
303
+ * Get the scene string from product enum
231
304
  */
232
305
  }, {
233
- key: "_getSecuritySDKByProductScene",
234
- value: function _getSecuritySDKByProductScene(securityConfig) {
235
- var storage = this._getSecurityConfigStorage(securityConfig.product);
236
- var scene = storage.scene || getSecurityScene(securityConfig.product);
237
- var securitySdk = SecurityService.securitySdkMap.get(scene);
238
- return securitySdk;
306
+ key: "_getSceneByProduct",
307
+ value: function _getSceneByProduct(product) {
308
+ var storage = this._getSecurityConfigStorage(product);
309
+ return storage.scene || getSecurityScene(product);
239
310
  }
240
311
 
241
312
  /**
242
- * @description New security SDK through scenario identification
313
+ * @description Obtain security SDK through scenario identification (async-aware)
314
+ * Handles three states: ready, loading, not found
243
315
  */
316
+ }, {
317
+ key: "_getSecuritySDKByProductScene",
318
+ value: (function () {
319
+ var _getSecuritySDKByProductScene2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(securityConfig) {
320
+ var scene;
321
+ return _regeneratorRuntime().wrap(function _callee6$(_context6) {
322
+ while (1) switch (_context6.prev = _context6.next) {
323
+ case 0:
324
+ scene = this._getSceneByProduct(securityConfig.product);
325
+ return _context6.abrupt("return", SecuritySdkRegistry.getInstance(scene));
326
+ case 2:
327
+ case "end":
328
+ return _context6.stop();
329
+ }
330
+ }, _callee6, this);
331
+ }));
332
+ function _getSecuritySDKByProductScene(_x3) {
333
+ return _getSecuritySDKByProductScene2.apply(this, arguments);
334
+ }
335
+ return _getSecuritySDKByProductScene;
336
+ }()
337
+ /**
338
+ * @description New security SDK through scenario identification (async)
339
+ * Uses shared SecuritySdkRegistry to avoid duplicate initialization
340
+ */
341
+ )
244
342
  }, {
245
343
  key: "_newSecuritySDKByScene",
246
344
  value: function _newSecuritySDKByScene(securityConfig, successCallback, failCallback) {
247
345
  var storage = this._getSecurityConfigStorage(securityConfig.product);
248
346
  var scene = storage.scene || getSecurityScene(securityConfig.product);
249
347
  var h5gateway = storage.h5gateway || getSecurityHost(securityConfig.region);
348
+
349
+ // Check if already exists in registry (avoid duplicates)
350
+ var existingEntry = SecuritySdkRegistry.get(scene);
351
+ if (existingEntry && (existingEntry.status === 'ready' || existingEntry.status === 'loading')) {
352
+ if (existingEntry.status === 'ready') {
353
+ successCallback && successCallback();
354
+ }
355
+ // If loading, the existing callbacks will handle it
356
+ return;
357
+ }
250
358
  try {
251
359
  var securitySdk = new Security({
252
360
  scene: scene,
253
- h5gateway: h5gateway
361
+ h5gateway: h5gateway,
362
+ environment: this.environment
254
363
  });
255
- SecurityService.securitySdkMap.set(scene, securitySdk);
256
- securitySdk.initSecurity(successCallback, failCallback);
364
+
365
+ // Create loading promise and register in registry
366
+ var loadingPromise = new Promise(function (resolveLoading, rejectLoading) {
367
+ securitySdk.initSecurity(function () {
368
+ SecuritySdkRegistry.setReady(scene, securitySdk);
369
+ successCallback && successCallback();
370
+ resolveLoading(securitySdk);
371
+ }, function (msg) {
372
+ SecuritySdkRegistry.setFailed(scene, new Error(msg || 'Security init failed'));
373
+ failCallback && failCallback(msg);
374
+ rejectLoading(new Error(msg || 'Security init failed'));
375
+ });
376
+ });
377
+
378
+ // Register as loading in the shared registry
379
+ SecuritySdkRegistry.setLoading(scene, loadingPromise);
257
380
  } catch (error) {
381
+ SecuritySdkRegistry.setFailed(scene, new Error(error === null || error === void 0 ? void 0 : error.toString()));
258
382
  failCallback && failCallback(error === null || error === void 0 ? void 0 : error.toString());
259
383
  }
260
384
  }
@@ -280,5 +404,4 @@ export var SecurityService = /*#__PURE__*/function () {
280
404
  }
281
405
  }]);
282
406
  return SecurityService;
283
- }();
284
- _defineProperty(SecurityService, "securitySdkMap", new Map());
407
+ }();
@@ -1,4 +1,5 @@
1
1
  import { IsecurityConfig, ProductSceneEnum, DeviceIdParameter } from '../../../types';
2
+ import type { ApdidEnvironment } from '../../../util/jshield-apdid';
2
3
  export declare const getSecurityConfigStorageKey: (scene: ProductSceneEnum) => string;
3
4
  export declare enum SecurityRegionEnum {
4
5
  SG = "SG",
@@ -22,10 +23,30 @@ export declare const sceneMap: {
22
23
  };
23
24
  export declare const getSecurityHost: (region: string) => string;
24
25
  export declare const getSecurityScene: (product: string) => string;
26
+ /**
27
+ * Map SDK environment string to ApdidEnvironment for CDN URL selection.
28
+ */
29
+ export declare const mapEnvironment: (env?: string) => ApdidEnvironment;
25
30
  export declare class Security {
26
31
  scene: string;
27
32
  h5gateway: string;
28
- constructor(options: IsecurityConfig);
33
+ private environment?;
34
+ private apdidLoaded;
35
+ private apdidLoadFailed;
36
+ constructor(options: IsecurityConfig & {
37
+ environment?: string;
38
+ });
39
+ /**
40
+ * Ensure the apdid-core script is loaded async.
41
+ * Returns true if loaded successfully, false otherwise.
42
+ * On failure, sets apdidLoadFailed flag for graceful degradation.
43
+ */
44
+ private ensureApdidLoaded;
45
+ /**
46
+ * Get the APDID module from the loader.
47
+ * Returns undefined if not loaded.
48
+ */
49
+ private getAPDIDModule;
29
50
  initSecurity(successCallback: any, failCallback: any): void;
30
51
  private initToken;
31
52
  pollingGetApdidToken(config?: DeviceIdParameter): Promise<string>;