@scalemule/nextjs 0.0.4 → 0.0.6

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/client.d.mts CHANGED
@@ -28,6 +28,12 @@ interface ClientConfig {
28
28
  enableRateLimitQueue?: boolean;
29
29
  /** Enable offline queue (queues requests when offline, syncs when back online) */
30
30
  enableOfflineQueue?: boolean;
31
+ /**
32
+ * Signal that a session will be established asynchronously (e.g. via auth proxy).
33
+ * When true, API requests will wait for the session to be resolved before sending,
34
+ * preventing race conditions where requests fire before the auth token is available.
35
+ */
36
+ pendingSessionInit?: boolean;
31
37
  }
32
38
  interface RequestOptions extends RequestInit {
33
39
  /** Skip adding auth headers (for public endpoints) */
@@ -56,6 +62,8 @@ declare class ScaleMuleClient {
56
62
  private offlineQueue;
57
63
  private enableRateLimitQueue;
58
64
  private enableOfflineQueue;
65
+ private sessionGate;
66
+ private resolveSessionGate;
59
67
  constructor(config: ClientConfig);
60
68
  /**
61
69
  * Sync offline queue when coming back online
@@ -85,6 +93,16 @@ declare class ScaleMuleClient {
85
93
  * Get the application ID (required for realtime features)
86
94
  */
87
95
  getApplicationId(): string | null;
96
+ /**
97
+ * Signal that a session is being established asynchronously.
98
+ * API requests will wait until resolveSessionPending() is called.
99
+ */
100
+ setSessionPending(): void;
101
+ /**
102
+ * Resolve the pending session gate, allowing queued API requests to proceed.
103
+ * Must be called after setSessionPending(), whether session was established or not.
104
+ */
105
+ resolveSessionPending(): void;
88
106
  /**
89
107
  * Initialize client by loading persisted session
90
108
  */
package/dist/client.d.ts CHANGED
@@ -28,6 +28,12 @@ interface ClientConfig {
28
28
  enableRateLimitQueue?: boolean;
29
29
  /** Enable offline queue (queues requests when offline, syncs when back online) */
30
30
  enableOfflineQueue?: boolean;
31
+ /**
32
+ * Signal that a session will be established asynchronously (e.g. via auth proxy).
33
+ * When true, API requests will wait for the session to be resolved before sending,
34
+ * preventing race conditions where requests fire before the auth token is available.
35
+ */
36
+ pendingSessionInit?: boolean;
31
37
  }
32
38
  interface RequestOptions extends RequestInit {
33
39
  /** Skip adding auth headers (for public endpoints) */
@@ -56,6 +62,8 @@ declare class ScaleMuleClient {
56
62
  private offlineQueue;
57
63
  private enableRateLimitQueue;
58
64
  private enableOfflineQueue;
65
+ private sessionGate;
66
+ private resolveSessionGate;
59
67
  constructor(config: ClientConfig);
60
68
  /**
61
69
  * Sync offline queue when coming back online
@@ -85,6 +93,16 @@ declare class ScaleMuleClient {
85
93
  * Get the application ID (required for realtime features)
86
94
  */
87
95
  getApplicationId(): string | null;
96
+ /**
97
+ * Signal that a session is being established asynchronously.
98
+ * API requests will wait until resolveSessionPending() is called.
99
+ */
100
+ setSessionPending(): void;
101
+ /**
102
+ * Resolve the pending session gate, allowing queued API requests to proceed.
103
+ * Must be called after setSessionPending(), whether session was established or not.
104
+ */
105
+ resolveSessionPending(): void;
88
106
  /**
89
107
  * Initialize client by loading persisted session
90
108
  */
package/dist/client.js CHANGED
@@ -273,6 +273,8 @@ var ScaleMuleClient = class {
273
273
  this.userId = null;
274
274
  this.rateLimitQueue = null;
275
275
  this.offlineQueue = null;
276
+ this.sessionGate = null;
277
+ this.resolveSessionGate = null;
276
278
  this.apiKey = config.apiKey;
277
279
  this.applicationId = config.applicationId || null;
278
280
  this.gatewayUrl = resolveGatewayUrl(config);
@@ -287,6 +289,9 @@ var ScaleMuleClient = class {
287
289
  this.offlineQueue = new OfflineQueue(this.storage);
288
290
  this.offlineQueue.setOnlineCallback(() => this.syncOfflineQueue());
289
291
  }
292
+ if (config.pendingSessionInit) {
293
+ this.setSessionPending();
294
+ }
290
295
  }
291
296
  /**
292
297
  * Sync offline queue when coming back online
@@ -352,6 +357,28 @@ var ScaleMuleClient = class {
352
357
  getApplicationId() {
353
358
  return this.applicationId;
354
359
  }
360
+ /**
361
+ * Signal that a session is being established asynchronously.
362
+ * API requests will wait until resolveSessionPending() is called.
363
+ */
364
+ setSessionPending() {
365
+ if (!this.sessionGate) {
366
+ this.sessionGate = new Promise((resolve) => {
367
+ this.resolveSessionGate = resolve;
368
+ });
369
+ }
370
+ }
371
+ /**
372
+ * Resolve the pending session gate, allowing queued API requests to proceed.
373
+ * Must be called after setSessionPending(), whether session was established or not.
374
+ */
375
+ resolveSessionPending() {
376
+ if (this.resolveSessionGate) {
377
+ this.resolveSessionGate();
378
+ this.resolveSessionGate = null;
379
+ this.sessionGate = null;
380
+ }
381
+ }
355
382
  /**
356
383
  * Initialize client by loading persisted session
357
384
  */
@@ -360,6 +387,9 @@ var ScaleMuleClient = class {
360
387
  const userId = await this.storage.getItem(USER_ID_STORAGE_KEY);
361
388
  if (token) this.sessionToken = token;
362
389
  if (userId) this.userId = userId;
390
+ if (token) {
391
+ this.resolveSessionPending();
392
+ }
363
393
  if (this.debug) {
364
394
  console.log("[ScaleMule] Initialized with session:", !!token);
365
395
  }
@@ -424,6 +454,9 @@ var ScaleMuleClient = class {
424
454
  * Make an HTTP request to the ScaleMule API
425
455
  */
426
456
  async request(path, options = {}) {
457
+ if (this.sessionGate) {
458
+ await this.sessionGate;
459
+ }
427
460
  const url = `${this.gatewayUrl}${path}`;
428
461
  const headers = this.buildHeaders(options);
429
462
  const maxRetries = options.skipRetry ? 0 : options.retries ?? 2;
package/dist/client.mjs CHANGED
@@ -271,6 +271,8 @@ var ScaleMuleClient = class {
271
271
  this.userId = null;
272
272
  this.rateLimitQueue = null;
273
273
  this.offlineQueue = null;
274
+ this.sessionGate = null;
275
+ this.resolveSessionGate = null;
274
276
  this.apiKey = config.apiKey;
275
277
  this.applicationId = config.applicationId || null;
276
278
  this.gatewayUrl = resolveGatewayUrl(config);
@@ -285,6 +287,9 @@ var ScaleMuleClient = class {
285
287
  this.offlineQueue = new OfflineQueue(this.storage);
286
288
  this.offlineQueue.setOnlineCallback(() => this.syncOfflineQueue());
287
289
  }
290
+ if (config.pendingSessionInit) {
291
+ this.setSessionPending();
292
+ }
288
293
  }
289
294
  /**
290
295
  * Sync offline queue when coming back online
@@ -350,6 +355,28 @@ var ScaleMuleClient = class {
350
355
  getApplicationId() {
351
356
  return this.applicationId;
352
357
  }
358
+ /**
359
+ * Signal that a session is being established asynchronously.
360
+ * API requests will wait until resolveSessionPending() is called.
361
+ */
362
+ setSessionPending() {
363
+ if (!this.sessionGate) {
364
+ this.sessionGate = new Promise((resolve) => {
365
+ this.resolveSessionGate = resolve;
366
+ });
367
+ }
368
+ }
369
+ /**
370
+ * Resolve the pending session gate, allowing queued API requests to proceed.
371
+ * Must be called after setSessionPending(), whether session was established or not.
372
+ */
373
+ resolveSessionPending() {
374
+ if (this.resolveSessionGate) {
375
+ this.resolveSessionGate();
376
+ this.resolveSessionGate = null;
377
+ this.sessionGate = null;
378
+ }
379
+ }
353
380
  /**
354
381
  * Initialize client by loading persisted session
355
382
  */
@@ -358,6 +385,9 @@ var ScaleMuleClient = class {
358
385
  const userId = await this.storage.getItem(USER_ID_STORAGE_KEY);
359
386
  if (token) this.sessionToken = token;
360
387
  if (userId) this.userId = userId;
388
+ if (token) {
389
+ this.resolveSessionPending();
390
+ }
361
391
  if (this.debug) {
362
392
  console.log("[ScaleMule] Initialized with session:", !!token);
363
393
  }
@@ -422,6 +452,9 @@ var ScaleMuleClient = class {
422
452
  * Make an HTTP request to the ScaleMule API
423
453
  */
424
454
  async request(path, options = {}) {
455
+ if (this.sessionGate) {
456
+ await this.sessionGate;
457
+ }
425
458
  const url = `${this.gatewayUrl}${path}`;
426
459
  const headers = this.buildHeaders(options);
427
460
  const maxRetries = options.skipRetry ? 0 : options.retries ?? 2;
package/dist/index.js CHANGED
@@ -278,6 +278,8 @@ var ScaleMuleClient = class {
278
278
  this.userId = null;
279
279
  this.rateLimitQueue = null;
280
280
  this.offlineQueue = null;
281
+ this.sessionGate = null;
282
+ this.resolveSessionGate = null;
281
283
  this.apiKey = config.apiKey;
282
284
  this.applicationId = config.applicationId || null;
283
285
  this.gatewayUrl = resolveGatewayUrl(config);
@@ -292,6 +294,9 @@ var ScaleMuleClient = class {
292
294
  this.offlineQueue = new OfflineQueue(this.storage);
293
295
  this.offlineQueue.setOnlineCallback(() => this.syncOfflineQueue());
294
296
  }
297
+ if (config.pendingSessionInit) {
298
+ this.setSessionPending();
299
+ }
295
300
  }
296
301
  /**
297
302
  * Sync offline queue when coming back online
@@ -357,6 +362,28 @@ var ScaleMuleClient = class {
357
362
  getApplicationId() {
358
363
  return this.applicationId;
359
364
  }
365
+ /**
366
+ * Signal that a session is being established asynchronously.
367
+ * API requests will wait until resolveSessionPending() is called.
368
+ */
369
+ setSessionPending() {
370
+ if (!this.sessionGate) {
371
+ this.sessionGate = new Promise((resolve) => {
372
+ this.resolveSessionGate = resolve;
373
+ });
374
+ }
375
+ }
376
+ /**
377
+ * Resolve the pending session gate, allowing queued API requests to proceed.
378
+ * Must be called after setSessionPending(), whether session was established or not.
379
+ */
380
+ resolveSessionPending() {
381
+ if (this.resolveSessionGate) {
382
+ this.resolveSessionGate();
383
+ this.resolveSessionGate = null;
384
+ this.sessionGate = null;
385
+ }
386
+ }
360
387
  /**
361
388
  * Initialize client by loading persisted session
362
389
  */
@@ -365,6 +392,9 @@ var ScaleMuleClient = class {
365
392
  const userId = await this.storage.getItem(USER_ID_STORAGE_KEY);
366
393
  if (token) this.sessionToken = token;
367
394
  if (userId) this.userId = userId;
395
+ if (token) {
396
+ this.resolveSessionPending();
397
+ }
368
398
  if (this.debug) {
369
399
  console.log("[ScaleMule] Initialized with session:", !!token);
370
400
  }
@@ -429,6 +459,9 @@ var ScaleMuleClient = class {
429
459
  * Make an HTTP request to the ScaleMule API
430
460
  */
431
461
  async request(path, options = {}) {
462
+ if (this.sessionGate) {
463
+ await this.sessionGate;
464
+ }
432
465
  const url = `${this.gatewayUrl}${path}`;
433
466
  const headers = this.buildHeaders(options);
434
467
  const maxRetries = options.skipRetry ? 0 : options.retries ?? 2;
@@ -765,9 +798,10 @@ function ScaleMuleProvider({
765
798
  environment,
766
799
  gatewayUrl,
767
800
  debug,
768
- storage
801
+ storage,
802
+ pendingSessionInit: !!authProxyUrl
769
803
  }),
770
- [apiKey, applicationId, environment, gatewayUrl, debug, storage]
804
+ [apiKey, applicationId, environment, gatewayUrl, debug, storage, authProxyUrl]
771
805
  );
772
806
  react.useEffect(() => {
773
807
  let mounted = true;
@@ -801,6 +835,8 @@ function ScaleMuleProvider({
801
835
  if (mounted && debug) {
802
836
  console.debug("[ScaleMule] Auth proxy session check failed");
803
837
  }
838
+ } finally {
839
+ client.resolveSessionPending();
804
840
  }
805
841
  } else if (client.isAuthenticated()) {
806
842
  if (cachedUser && mounted) {
package/dist/index.mjs CHANGED
@@ -276,6 +276,8 @@ var ScaleMuleClient = class {
276
276
  this.userId = null;
277
277
  this.rateLimitQueue = null;
278
278
  this.offlineQueue = null;
279
+ this.sessionGate = null;
280
+ this.resolveSessionGate = null;
279
281
  this.apiKey = config.apiKey;
280
282
  this.applicationId = config.applicationId || null;
281
283
  this.gatewayUrl = resolveGatewayUrl(config);
@@ -290,6 +292,9 @@ var ScaleMuleClient = class {
290
292
  this.offlineQueue = new OfflineQueue(this.storage);
291
293
  this.offlineQueue.setOnlineCallback(() => this.syncOfflineQueue());
292
294
  }
295
+ if (config.pendingSessionInit) {
296
+ this.setSessionPending();
297
+ }
293
298
  }
294
299
  /**
295
300
  * Sync offline queue when coming back online
@@ -355,6 +360,28 @@ var ScaleMuleClient = class {
355
360
  getApplicationId() {
356
361
  return this.applicationId;
357
362
  }
363
+ /**
364
+ * Signal that a session is being established asynchronously.
365
+ * API requests will wait until resolveSessionPending() is called.
366
+ */
367
+ setSessionPending() {
368
+ if (!this.sessionGate) {
369
+ this.sessionGate = new Promise((resolve) => {
370
+ this.resolveSessionGate = resolve;
371
+ });
372
+ }
373
+ }
374
+ /**
375
+ * Resolve the pending session gate, allowing queued API requests to proceed.
376
+ * Must be called after setSessionPending(), whether session was established or not.
377
+ */
378
+ resolveSessionPending() {
379
+ if (this.resolveSessionGate) {
380
+ this.resolveSessionGate();
381
+ this.resolveSessionGate = null;
382
+ this.sessionGate = null;
383
+ }
384
+ }
358
385
  /**
359
386
  * Initialize client by loading persisted session
360
387
  */
@@ -363,6 +390,9 @@ var ScaleMuleClient = class {
363
390
  const userId = await this.storage.getItem(USER_ID_STORAGE_KEY);
364
391
  if (token) this.sessionToken = token;
365
392
  if (userId) this.userId = userId;
393
+ if (token) {
394
+ this.resolveSessionPending();
395
+ }
366
396
  if (this.debug) {
367
397
  console.log("[ScaleMule] Initialized with session:", !!token);
368
398
  }
@@ -427,6 +457,9 @@ var ScaleMuleClient = class {
427
457
  * Make an HTTP request to the ScaleMule API
428
458
  */
429
459
  async request(path, options = {}) {
460
+ if (this.sessionGate) {
461
+ await this.sessionGate;
462
+ }
430
463
  const url = `${this.gatewayUrl}${path}`;
431
464
  const headers = this.buildHeaders(options);
432
465
  const maxRetries = options.skipRetry ? 0 : options.retries ?? 2;
@@ -763,9 +796,10 @@ function ScaleMuleProvider({
763
796
  environment,
764
797
  gatewayUrl,
765
798
  debug,
766
- storage
799
+ storage,
800
+ pendingSessionInit: !!authProxyUrl
767
801
  }),
768
- [apiKey, applicationId, environment, gatewayUrl, debug, storage]
802
+ [apiKey, applicationId, environment, gatewayUrl, debug, storage, authProxyUrl]
769
803
  );
770
804
  useEffect(() => {
771
805
  let mounted = true;
@@ -799,6 +833,8 @@ function ScaleMuleProvider({
799
833
  if (mounted && debug) {
800
834
  console.debug("[ScaleMule] Auth proxy session check failed");
801
835
  }
836
+ } finally {
837
+ client.resolveSessionPending();
802
838
  }
803
839
  } else if (client.isAuthenticated()) {
804
840
  if (cachedUser && mounted) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalemule/nextjs",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "ScaleMule SDK for Next.js applications - authentication, storage, and user management",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",