astrogators-shared-ui 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -175,54 +175,76 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
175
175
  S(e), T(t);
176
176
  }, O = () => {
177
177
  C(), E();
178
- }, ee = () => !!x(), k = "", A, j = null, M = (e) => {
179
- k = e.baseURL, A = e.onUnauthorized;
180
- }, N = () => j || (j = (async () => {
178
+ }, ee = () => !!x(), te = "", k, A = null, j = (e) => {
179
+ te = e.baseURL, k = e.onUnauthorized;
180
+ }, M = () => A || (A = (async () => {
181
181
  let e = w();
182
182
  if (!e) throw Error("No refresh token available");
183
- let t = await fetch(`${k}/api/v1/auth/refresh`, {
183
+ let t = await fetch(`${te}/api/v1/auth/refresh`, {
184
184
  method: "POST",
185
185
  headers: { "Content-Type": "application/json" },
186
186
  body: JSON.stringify({ refresh_token: e })
187
187
  });
188
- if (!t.ok) throw O(), A?.(), Error("Token refresh failed");
188
+ if (!t.ok) throw O(), k?.(), Error("Token refresh failed");
189
189
  let n = await t.json();
190
190
  return D(n.access_token, n.refresh_token), n.access_token;
191
191
  })().finally(() => {
192
- j = null;
193
- }), j), P = 30, F = (e) => {
192
+ A = null;
193
+ }), A), N = 30, P = [700, 1500], ne = new Set([
194
+ 502,
195
+ 503,
196
+ 504
197
+ ]), F = (e) => {
198
+ let t = (e ?? "GET").toUpperCase();
199
+ return t === "GET" || t === "HEAD" || t === "OPTIONS";
200
+ }, I = (e) => e == null || typeof e == "string", re = (e) => new Promise((t) => setTimeout(t, e)), ie = async (e, t) => {
201
+ let n = F(t.method) && I(t.body), r = I(t.body), i;
202
+ for (let a = 0; a <= P.length; a++) {
203
+ a > 0 && await re(P[a - 1]);
204
+ let o = a < P.length;
205
+ try {
206
+ let r = await fetch(e, t);
207
+ if (o && n && ne.has(r.status)) continue;
208
+ return r;
209
+ } catch (e) {
210
+ if (i = e, o && r) continue;
211
+ throw e;
212
+ }
213
+ }
214
+ throw i ?? /* @__PURE__ */ Error("fetchWithRetry: retries exhausted");
215
+ }, ae = (e) => {
194
216
  try {
195
217
  let t = e.split(".")[1].replace(/-/g, "+").replace(/_/g, "/"), { exp: n } = JSON.parse(atob(t));
196
- return typeof n == "number" && Date.now() / 1e3 >= n - P;
218
+ return typeof n == "number" && Date.now() / 1e3 >= n - N;
197
219
  } catch {
198
220
  return !1;
199
221
  }
200
- }, I = async (e, t = {}) => {
222
+ }, oe = async (e, t = {}) => {
201
223
  let n = x();
202
- if (n && F(n)) try {
203
- n = await N();
224
+ if (n && ae(n)) try {
225
+ n = await M();
204
226
  } catch {
205
227
  n = x();
206
228
  }
207
229
  let r = { ...t.headers };
208
230
  n && (r.Authorization = `Bearer ${n}`);
209
- let i = await fetch(e, {
231
+ let i = await ie(e, {
210
232
  ...t,
211
233
  headers: r
212
234
  });
213
235
  if (i.status !== 401 || !n) return i;
214
236
  try {
215
- return r.Authorization = `Bearer ${await N()}`, await fetch(e, {
237
+ return r.Authorization = `Bearer ${await M()}`, await ie(e, {
216
238
  ...t,
217
239
  headers: r
218
240
  });
219
241
  } catch {
220
242
  return i;
221
243
  }
222
- }, L = class {
244
+ }, se = class {
223
245
  baseURL;
224
246
  constructor(e) {
225
- this.baseURL = e.baseURL, M({
247
+ this.baseURL = e.baseURL, j({
226
248
  baseURL: e.baseURL,
227
249
  onUnauthorized: e.onUnauthorized
228
250
  });
@@ -231,7 +253,7 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
231
253
  let n = {
232
254
  "Content-Type": "application/json",
233
255
  ...t.headers
234
- }, r = await I(`${this.baseURL}${e}`, {
256
+ }, r = await oe(`${this.baseURL}${e}`, {
235
257
  ...t,
236
258
  headers: n
237
259
  });
@@ -281,53 +303,53 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
281
303
  method: "DELETE"
282
304
  });
283
305
  }
284
- }, R, te = (e) => {
285
- R = new L(e);
286
- }, z = "astrogators_ally_codes", B = "astrogators_selected_ally_code", V = () => {
306
+ }, L, ce = (e) => {
307
+ L = new se(e);
308
+ }, R = "astrogators_ally_codes", z = "astrogators_selected_ally_code", B = () => {
287
309
  try {
288
- let e = localStorage.getItem(z);
310
+ let e = localStorage.getItem(R);
289
311
  return e ? JSON.parse(e) : [];
290
312
  } catch (e) {
291
313
  return console.error("Failed to read ally codes from localStorage:", e), [];
292
314
  }
293
- }, ne = (e) => {
315
+ }, le = (e) => {
294
316
  try {
295
- let t = V();
317
+ let t = B();
296
318
  if (t.some((t) => t.ally_code === e.ally_code)) return;
297
- t.push(e), localStorage.setItem(z, JSON.stringify(t));
319
+ t.push(e), localStorage.setItem(R, JSON.stringify(t));
298
320
  } catch (e) {
299
321
  console.error("Failed to save ally code to localStorage:", e);
300
322
  }
301
- }, re = (e) => {
323
+ }, ue = (e) => {
302
324
  try {
303
- let t = V().filter((t) => t.ally_code !== e);
304
- localStorage.setItem(z, JSON.stringify(t));
325
+ let t = B().filter((t) => t.ally_code !== e);
326
+ localStorage.setItem(R, JSON.stringify(t));
305
327
  } catch (e) {
306
328
  console.error("Failed to remove ally code from localStorage:", e);
307
329
  }
308
- }, H = (e) => {
330
+ }, V = (e) => {
309
331
  try {
310
- let t = V().map((t) => t.ally_code === e ? {
332
+ let t = B().map((t) => t.ally_code === e ? {
311
333
  ...t,
312
334
  last_used_at: (/* @__PURE__ */ new Date()).toISOString()
313
335
  } : t);
314
- localStorage.setItem(z, JSON.stringify(t));
336
+ localStorage.setItem(R, JSON.stringify(t));
315
337
  } catch (e) {
316
338
  console.error("Failed to update ally code last used:", e);
317
339
  }
318
- }, ie = () => localStorage.getItem(B), U = (e) => {
319
- e ? localStorage.setItem(B, e) : localStorage.removeItem(B);
320
- }, ae = () => {
321
- localStorage.removeItem(z), localStorage.removeItem(B);
322
- }, oe = t(void 0), se = ({ children: e, apiBaseUrl: t }) => {
340
+ }, de = () => localStorage.getItem(z), H = (e) => {
341
+ e ? localStorage.setItem(z, e) : localStorage.removeItem(z);
342
+ }, fe = () => {
343
+ localStorage.removeItem(R), localStorage.removeItem(z);
344
+ }, pe = t(void 0), me = ({ children: e, apiBaseUrl: t }) => {
323
345
  let [r, o] = a(null), [c, l] = a(!0), [u, d] = a(!0), [f, p] = a(!0), [m, h] = a([]), [g, _] = a(null), [v, y] = a(!1), [b, x] = a({
324
346
  show: !1,
325
347
  localStorageCodes: []
326
348
  });
327
- te({ baseURL: t }), i(() => {
349
+ ce({ baseURL: t }), i(() => {
328
350
  (async () => {
329
351
  try {
330
- d((await R.get("/api/v1/config/features")).auth_enabled);
352
+ d((await L.get("/api/v1/config/features")).auth_enabled);
331
353
  } catch (e) {
332
354
  console.error("Failed to fetch features:", e), d(!0);
333
355
  } finally {
@@ -341,7 +363,7 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
341
363
  return;
342
364
  }
343
365
  try {
344
- o(await R.get("/api/v1/users/me"));
366
+ o(await L.get("/api/v1/users/me"));
345
367
  } catch (e) {
346
368
  console.error("Failed to fetch user:", e), o(null), O();
347
369
  } finally {
@@ -353,123 +375,123 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
353
375
  }, [S]);
354
376
  let C = async (e) => {
355
377
  try {
356
- let t = await R.post("/api/v1/auth/login", e);
357
- D(t.access_token, t.refresh_token), o(await R.get("/api/v1/users/me"));
378
+ let t = await L.post("/api/v1/auth/login", e);
379
+ D(t.access_token, t.refresh_token), o(await L.get("/api/v1/users/me"));
358
380
  } catch (e) {
359
381
  throw console.error("Login failed:", e), e;
360
382
  }
361
383
  }, w = async (e) => {
362
384
  try {
363
- await R.post("/api/v1/auth/register", e);
385
+ await L.post("/api/v1/auth/register", e);
364
386
  } catch (e) {
365
387
  throw console.error("Registration failed:", e), e;
366
388
  }
367
389
  }, T = () => {
368
- O(), o(null), h([]), _(null), U(null), x({
390
+ O(), o(null), h([]), _(null), H(null), x({
369
391
  show: !1,
370
392
  localStorageCodes: []
371
393
  });
372
394
  }, E = async () => {
373
395
  await S();
374
- }, k = async (e) => {
396
+ }, te = async (e) => {
375
397
  try {
376
- return (await R.post("/api/v1/auth/forgot-password", e)).message;
398
+ return (await L.post("/api/v1/auth/forgot-password", e)).message;
377
399
  } catch (e) {
378
400
  throw console.error("Forgot password failed:", e), e;
379
401
  }
380
- }, A = async (e) => {
402
+ }, k = async (e) => {
381
403
  try {
382
- return (await R.post("/api/v1/auth/reset-password", e)).message;
404
+ return (await L.post("/api/v1/auth/reset-password", e)).message;
383
405
  } catch (e) {
384
406
  throw console.error("Reset password failed:", e), e;
385
407
  }
386
- }, j = async (e) => {
408
+ }, A = async (e) => {
387
409
  try {
388
- return (await R.post("/api/v1/auth/resend-verification", e)).message;
410
+ return (await L.post("/api/v1/auth/resend-verification", e)).message;
389
411
  } catch (e) {
390
412
  throw console.error("Resend verification failed:", e), e;
391
413
  }
392
- }, M = n(async () => {
414
+ }, j = n(async () => {
393
415
  y(!0);
394
416
  try {
395
417
  let e = [];
396
418
  if (r) {
397
- let t = await R.get("/api/v1/users/me/ally-codes");
419
+ let t = await L.get("/api/v1/users/me/ally-codes");
398
420
  h(t.ally_codes), e = t.ally_codes.map((e) => e.ally_code);
399
- let n = V();
421
+ let n = B();
400
422
  n.length > 0 && x({
401
423
  show: !0,
402
424
  localStorageCodes: n.map((e) => e.ally_code)
403
425
  });
404
426
  } else {
405
- let t = V();
427
+ let t = B();
406
428
  h(t), e = t.map((e) => e.ally_code);
407
429
  }
408
- let t = ie(), n = t && e.includes(t) ? t : null;
409
- _(n), n !== t && U(n);
430
+ let t = de(), n = t && e.includes(t) ? t : null;
431
+ _(n), n !== t && H(n);
410
432
  } catch (e) {
411
433
  console.error("Failed to fetch ally codes:", e), h([]);
412
434
  } finally {
413
435
  y(!1);
414
436
  }
415
- }, [r]), N = n(async (e) => {
416
- r && typeof e == "number" ? (await R.put(`/api/v1/users/me/ally-codes/${e}/use`, {}), await M()) : !r && typeof e == "string" && (H(e), h(V()));
417
- }, [r, M]), P = n((e) => {
418
- if (_(e), U(e), e && r) {
437
+ }, [r]), M = n(async (e) => {
438
+ r && typeof e == "number" ? (await L.put(`/api/v1/users/me/ally-codes/${e}/use`, {}), await j()) : !r && typeof e == "string" && (V(e), h(B()));
439
+ }, [r, j]), N = n((e) => {
440
+ if (_(e), H(e), e && r) {
419
441
  let t = m.find((t) => "ally_code" in t && t.ally_code === e);
420
- t && "id" in t && N(t.id);
421
- } else e && !r && H(e);
442
+ t && "id" in t && M(t.id);
443
+ } else e && !r && V(e);
422
444
  }, [
423
445
  r,
424
446
  m,
425
- N
426
- ]), F = n(async (e) => {
447
+ M
448
+ ]), P = n(async (e) => {
427
449
  if (!/^\d{9}$/.test(e)) throw Error("Ally code must be exactly 9 digits");
428
450
  if (r) {
429
- let t = await R.post("/api/v1/users/me/ally-codes", { ally_code: e });
430
- h((e) => [t, ...e]), m.length === 0 && P(e);
451
+ let t = await L.post("/api/v1/users/me/ally-codes", { ally_code: e });
452
+ h((e) => [t, ...e]), m.length === 0 && N(e);
431
453
  } else {
432
- let t = await R.get(`/api/v1/player-data/player/${e}`);
454
+ let t = await L.get(`/api/v1/player-data/player/${e}`);
433
455
  if (!t) throw Error("Invalid ally code - player not found");
434
- ne({
456
+ le({
435
457
  ally_code: e,
436
458
  player_name: t.data?.name ?? null,
437
459
  last_used_at: (/* @__PURE__ */ new Date()).toISOString()
438
- }), h(V()), m.length === 0 && P(e);
460
+ }), h(B()), m.length === 0 && N(e);
439
461
  }
440
462
  }, [
441
463
  r,
442
464
  m.length,
443
- P
444
- ]), I = n(async (e) => {
445
- r && typeof e == "number" ? (await R.delete(`/api/v1/users/me/ally-codes/${e}`), h((t) => t.filter((t) => "id" in t && t.id !== e))) : !r && typeof e == "string" && (re(e), h(V()), g === e && P(null));
465
+ N
466
+ ]), ne = n(async (e) => {
467
+ r && typeof e == "number" ? (await L.delete(`/api/v1/users/me/ally-codes/${e}`), h((t) => t.filter((t) => "id" in t && t.id !== e))) : !r && typeof e == "string" && (ue(e), h(B()), g === e && N(null));
446
468
  }, [
447
469
  r,
448
470
  g,
449
- P
450
- ]), L = n(() => {
471
+ N
472
+ ]), F = n(() => {
451
473
  x({
452
474
  show: !1,
453
475
  localStorageCodes: []
454
476
  });
455
- }, []), z = n(async () => {
477
+ }, []), I = n(async () => {
456
478
  if (!r) return;
457
- let e = V();
479
+ let e = B();
458
480
  for (let t of e) try {
459
- await F(t.ally_code);
481
+ await P(t.ally_code);
460
482
  } catch (e) {
461
483
  console.error(`Failed to migrate ally code ${t.ally_code}:`, e);
462
484
  }
463
- ae(), L();
485
+ fe(), F();
464
486
  }, [
465
487
  r,
466
- F,
467
- L
488
+ P,
489
+ F
468
490
  ]);
469
491
  i(() => {
470
- M();
471
- }, [M]);
472
- let B = {
492
+ j();
493
+ }, [j]);
494
+ let re = {
473
495
  user: r,
474
496
  isAuthenticated: !!r,
475
497
  isLoading: c,
@@ -477,32 +499,32 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
477
499
  register: w,
478
500
  logout: T,
479
501
  refreshUser: E,
480
- forgotPassword: k,
481
- resetPassword: A,
482
- resendVerification: j,
502
+ forgotPassword: te,
503
+ resetPassword: k,
504
+ resendVerification: A,
483
505
  authEnabled: u,
484
506
  isLoadingFeatures: f,
485
507
  allyCodes: m,
486
508
  selectedAllyCode: g,
487
509
  isLoadingAllyCodes: v,
488
- fetchAllyCodes: M,
489
- addAllyCode: F,
490
- removeAllyCode: I,
491
- selectAllyCode: P,
492
- updateAllyCodeLastUsed: N,
510
+ fetchAllyCodes: j,
511
+ addAllyCode: P,
512
+ removeAllyCode: ne,
513
+ selectAllyCode: N,
514
+ updateAllyCodeLastUsed: M,
493
515
  migrationPrompt: b,
494
- dismissMigrationPrompt: L,
495
- migrateLocalStorageCodes: z
516
+ dismissMigrationPrompt: F,
517
+ migrateLocalStorageCodes: I
496
518
  };
497
- return /* @__PURE__ */ s(oe.Provider, {
498
- value: B,
519
+ return /* @__PURE__ */ s(pe.Provider, {
520
+ value: re,
499
521
  children: e
500
522
  });
501
- }, W = () => {
502
- let e = r(oe);
523
+ }, U = () => {
524
+ let e = r(pe);
503
525
  if (e === void 0) throw Error("useAuth must be used within an AuthProvider");
504
526
  return e;
505
- }, G = (e) => !e || e.length !== 9 ? e : `${e.slice(0, 3)}-${e.slice(3, 6)}-${e.slice(6, 9)}`, ce = (e) => e.replace(/-/g, ""), K = {
527
+ }, W = (e) => !e || e.length !== 9 ? e : `${e.slice(0, 3)}-${e.slice(3, 6)}-${e.slice(6, 9)}`, he = (e) => e.replace(/-/g, ""), G = {
506
528
  allyCodeDropdown: "_allyCodeDropdown_1m0tw_1",
507
529
  select: "_select_1m0tw_8",
508
530
  manageButton: "_manageButton_1m0tw_12",
@@ -514,10 +536,10 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
514
536
  codesList: "_codesList_1m0tw_67",
515
537
  codeItem: "_codeItem_1m0tw_71",
516
538
  doneButton: "_doneButton_1m0tw_88"
517
- }, le = ({ onAllyCodeSelected: e, className: t = "" }) => {
518
- let { allyCodes: n, selectedAllyCode: r, selectAllyCode: i, removeAllyCode: o, addAllyCode: l, isLoadingAllyCodes: u } = W(), [d, f] = a(!1), [p, h] = a(""), [_, y] = a(""), [b, x] = a(""), [S, C] = a(!1), w = n.map((e) => ({
539
+ }, ge = ({ onAllyCodeSelected: e, className: t = "" }) => {
540
+ let { allyCodes: n, selectedAllyCode: r, selectAllyCode: i, removeAllyCode: o, addAllyCode: l, isLoadingAllyCodes: u } = U(), [d, f] = a(!1), [p, h] = a(""), [_, y] = a(""), [b, x] = a(""), [S, C] = a(!1), w = n.map((e) => ({
519
541
  value: e.ally_code,
520
- label: e.player_name ? `${e.player_name} (${G(e.ally_code)})` : G(e.ally_code)
542
+ label: e.player_name ? `${e.player_name} (${W(e.ally_code)})` : W(e.ally_code)
521
543
  })), T = (t) => {
522
544
  let n = t.target.value || null;
523
545
  i(n), e?.(n);
@@ -539,7 +561,7 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
539
561
  }
540
562
  }, O = n.length > 0;
541
563
  return /* @__PURE__ */ c("div", {
542
- className: `${K.allyCodeDropdown} ${t}`,
564
+ className: `${G.allyCodeDropdown} ${t}`,
543
565
  children: [
544
566
  O && /* @__PURE__ */ s(g, {
545
567
  options: w,
@@ -547,17 +569,17 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
547
569
  onChange: T,
548
570
  placeholder: "Select ally code",
549
571
  disabled: u,
550
- className: K.select
572
+ className: G.select
551
573
  }),
552
574
  d && /* @__PURE__ */ c("div", {
553
- className: K.managePanel,
575
+ className: G.managePanel,
554
576
  children: [
555
577
  /* @__PURE__ */ s("h4", { children: "Manage Ally Codes" }),
556
578
  /* @__PURE__ */ c("div", {
557
- className: K.addSection,
579
+ className: G.addSection,
558
580
  children: [
559
581
  /* @__PURE__ */ c("div", {
560
- className: K.addInputGroup,
582
+ className: G.addInputGroup,
561
583
  children: [/* @__PURE__ */ s(v, {
562
584
  type: "text",
563
585
  placeholder: "9-digit ally code",
@@ -574,20 +596,20 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
574
596
  })]
575
597
  }),
576
598
  _ && /* @__PURE__ */ s("div", {
577
- className: K.error,
599
+ className: G.error,
578
600
  children: _
579
601
  }),
580
602
  b && /* @__PURE__ */ s("div", {
581
- className: K.success,
603
+ className: G.success,
582
604
  children: b
583
605
  })
584
606
  ]
585
607
  }),
586
608
  /* @__PURE__ */ s("div", {
587
- className: K.codesList,
609
+ className: G.codesList,
588
610
  children: n.map((e) => /* @__PURE__ */ c("div", {
589
- className: K.codeItem,
590
- children: [/* @__PURE__ */ s("span", { children: e.player_name ? `${e.player_name} (${G(e.ally_code)})` : G(e.ally_code) }), /* @__PURE__ */ s(m, {
611
+ className: G.codeItem,
612
+ children: [/* @__PURE__ */ s("span", { children: e.player_name ? `${e.player_name} (${W(e.ally_code)})` : W(e.ally_code) }), /* @__PURE__ */ s(m, {
591
613
  variant: "ghost",
592
614
  size: "sm",
593
615
  onClick: () => E(e.ally_code),
@@ -599,7 +621,7 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
599
621
  variant: "secondary",
600
622
  size: "sm",
601
623
  onClick: () => f(!1),
602
- className: K.doneButton,
624
+ className: G.doneButton,
603
625
  children: "Done"
604
626
  })
605
627
  ]
@@ -608,12 +630,12 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
608
630
  variant: "ghost",
609
631
  size: "sm",
610
632
  onClick: () => f(!d),
611
- className: K.manageButton,
633
+ className: G.manageButton,
612
634
  children: O ? "Manage" : "+ Add ally code"
613
635
  })
614
636
  ]
615
637
  });
616
- }, q = {
638
+ }, K = {
617
639
  logoLink: "_logoLink_84pn2_3",
618
640
  appNav: "_appNav_84pn2_9",
619
641
  appName: "_appName_84pn2_15",
@@ -623,14 +645,14 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
623
645
  extrasGroup: "_extrasGroup_84pn2_64",
624
646
  authCluster: "_authCluster_84pn2_70",
625
647
  userLink: "_userLink_84pn2_76"
626
- }, ue = ({ hubUrl: t = "/", appName: n, appHref: r = "/", navItems: i, showAllyCode: a = !1, showAuth: l = !0, rightExtras: u, className: d }) => {
627
- let { user: p, isAuthenticated: h, logout: g, authEnabled: _ } = W(), v = () => {
648
+ }, _e = ({ hubUrl: t = "/", appName: n, appHref: r = "/", navItems: i, showAllyCode: a = !1, showAuth: l = !0, rightExtras: u, className: d }) => {
649
+ let { user: p, isAuthenticated: h, logout: g, authEnabled: _ } = U(), v = () => {
628
650
  g(), window.location.href = t;
629
651
  }, y = !!u || a, b = !!(i && i.length > 0), x = !!n || b, S = l ? h ? /* @__PURE__ */ c("div", {
630
- className: q.authCluster,
652
+ className: K.authCluster,
631
653
  children: [/* @__PURE__ */ s("a", {
632
654
  href: "/profile",
633
- className: q.userLink,
655
+ className: K.userLink,
634
656
  children: p?.username
635
657
  }), /* @__PURE__ */ s(m, {
636
658
  variant: "ghost",
@@ -639,7 +661,7 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
639
661
  children: "Logout"
640
662
  })]
641
663
  }) : _ ? /* @__PURE__ */ c("div", {
642
- className: q.authCluster,
664
+ className: K.authCluster,
643
665
  children: [/* @__PURE__ */ s("a", {
644
666
  href: "/login",
645
667
  children: /* @__PURE__ */ s(m, {
@@ -660,19 +682,19 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
660
682
  className: d,
661
683
  logo: /* @__PURE__ */ s("a", {
662
684
  href: t,
663
- className: q.logoLink,
685
+ className: K.logoLink,
664
686
  children: "The Astrogator's Table"
665
687
  }),
666
688
  leftContent: x ? /* @__PURE__ */ c("div", {
667
- className: q.appNav,
689
+ className: K.appNav,
668
690
  children: [n && /* @__PURE__ */ s("a", {
669
691
  href: r,
670
- className: q.appName,
692
+ className: K.appName,
671
693
  children: n
672
694
  }), b && /* @__PURE__ */ s("nav", {
673
- className: q.tabs,
695
+ className: K.tabs,
674
696
  children: i.map((t) => {
675
- let n = `${q.tab} ${t.active ? q.tabActive : ""}`;
697
+ let n = `${K.tab} ${t.active ? K.tabActive : ""}`;
676
698
  return t.render ? /* @__PURE__ */ s(e.Fragment, { children: t.render({
677
699
  className: n,
678
700
  children: t.label
@@ -685,31 +707,31 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
685
707
  })]
686
708
  }) : void 0,
687
709
  rightContent: /* @__PURE__ */ c(o, { children: [y && /* @__PURE__ */ c("div", {
688
- className: q.extrasGroup,
689
- children: [u, a && /* @__PURE__ */ s(le, {})]
710
+ className: K.extrasGroup,
711
+ children: [u, a && /* @__PURE__ */ s(ge, {})]
690
712
  }), S] })
691
713
  });
692
- }, J = {
714
+ }, q = {
693
715
  footer: "_footer_zjuj8_1",
694
716
  content: "_content_zjuj8_7",
695
717
  defaultContent: "_defaultContent_zjuj8_13",
696
718
  copyright: "_copyright_zjuj8_21",
697
719
  disclaimer: "_disclaimer_zjuj8_26"
698
- }, de = ({ children: e, className: t = "" }) => /* @__PURE__ */ s("footer", {
699
- className: `${J.footer} ${t}`,
720
+ }, ve = ({ children: e, className: t = "" }) => /* @__PURE__ */ s("footer", {
721
+ className: `${q.footer} ${t}`,
700
722
  children: /* @__PURE__ */ s("div", {
701
- className: J.content,
723
+ className: q.content,
702
724
  children: e || /* @__PURE__ */ c("div", {
703
- className: J.defaultContent,
725
+ className: q.defaultContent,
704
726
  children: [/* @__PURE__ */ c("p", {
705
- className: J.copyright,
727
+ className: q.copyright,
706
728
  children: [
707
729
  "© ",
708
730
  (/* @__PURE__ */ new Date()).getFullYear(),
709
731
  " The Astrogator's Table. All rights reserved."
710
732
  ]
711
733
  }), /* @__PURE__ */ s("p", {
712
- className: J.disclaimer,
734
+ className: q.disclaimer,
713
735
  children: "Star Wars: Galaxy of Heroes is a trademark of Electronic Arts Inc."
714
736
  })]
715
737
  })
@@ -717,11 +739,11 @@ var y = "astrogators_access_token", b = "astrogators_refresh_token", x = () => l
717
739
  });
718
740
  //#endregion
719
741
  //#region src/utils/formatTime.ts
720
- function fe(e) {
742
+ function ye(e) {
721
743
  let t = /([zZ]|[+-]\d{2}:?\d{2})$/.test(e);
722
744
  return new Date(t ? e : `${e}Z`);
723
745
  }
724
- function pe(e, t) {
746
+ function be(e, t) {
725
747
  let n = Math.max(0, Math.floor((t - e.getTime()) / 1e3));
726
748
  if (n < 60) return `${n}s ago`;
727
749
  let r = Math.floor(n / 60);
@@ -729,28 +751,28 @@ function pe(e, t) {
729
751
  let i = Math.floor(r / 60);
730
752
  return i < 24 ? `${i}h ago` : `${Math.floor(i / 24)}d ago`;
731
753
  }
732
- function Y(e) {
754
+ function J(e) {
733
755
  return `${Math.floor(e / 60)}:${(e % 60).toString().padStart(2, "0")}`;
734
756
  }
735
- var X = {
757
+ var Y = {
736
758
  rosterRefresh: "_rosterRefresh_1rbul_3",
737
759
  updatedLabel: "_updatedLabel_1rbul_11",
738
760
  refreshButton: "_refreshButton_1rbul_19",
739
761
  spin: "_spin_1rbul_31"
740
- }, me = ({ onRefresh: e, isRefreshing: t, cachedAt: n = null, refreshAvailableAt: r = null, labelPrefix: o = "Updated", className: l = "" }) => {
762
+ }, xe = ({ onRefresh: e, isRefreshing: t, cachedAt: n = null, refreshAvailableAt: r = null, labelPrefix: o = "Updated", className: l = "" }) => {
741
763
  let [u, d] = a(() => Date.now()), f = !!n || r != null && r > u;
742
764
  i(() => {
743
765
  if (!f) return;
744
766
  let e = setInterval(() => d(Date.now()), 1e3);
745
767
  return () => clearInterval(e);
746
768
  }, [f]);
747
- let p = r ? Math.max(0, Math.ceil((r - u) / 1e3)) : 0, h = n ? pe(fe(n), u) : null, g = t || p > 0, _ = p > 0 ? `Fresh data available in ${Y(p)}` : "Refresh roster";
769
+ let p = r ? Math.max(0, Math.ceil((r - u) / 1e3)) : 0, h = n ? be(ye(n), u) : null, g = t || p > 0, _ = p > 0 ? `Fresh data available in ${J(p)}` : "Refresh roster";
748
770
  return /* @__PURE__ */ c("div", {
749
- className: `${X.rosterRefresh} ${l}`,
771
+ className: `${Y.rosterRefresh} ${l}`,
750
772
  children: [h && /* @__PURE__ */ s("span", {
751
- className: X.updatedLabel,
773
+ className: Y.updatedLabel,
752
774
  title: _,
753
- children: p > 0 ? `${o} ${h} · fresh in ${Y(p)}` : `${o} ${h}`
775
+ children: p > 0 ? `${o} ${h} · fresh in ${J(p)}` : `${o} ${h}`
754
776
  }), /* @__PURE__ */ s(m, {
755
777
  variant: "outline",
756
778
  size: "sm",
@@ -758,14 +780,14 @@ var X = {
758
780
  disabled: g,
759
781
  title: _,
760
782
  "aria-label": "Refresh roster",
761
- className: X.refreshButton,
783
+ className: Y.refreshButton,
762
784
  children: /* @__PURE__ */ s("span", {
763
- className: t ? X.spin : void 0,
785
+ className: t ? Y.spin : void 0,
764
786
  children: "⟳"
765
787
  })
766
788
  })]
767
789
  });
768
- }, Z = {
790
+ }, X = {
769
791
  card: "_card_1vw8g_1",
770
792
  chamfered: "_chamfered_1vw8g_15",
771
793
  default: "_default_1vw8g_20",
@@ -776,13 +798,13 @@ var X = {
776
798
  "padding-md": "_padding-md_1vw8g_43",
777
799
  "padding-lg": "_padding-lg_1vw8g_47",
778
800
  hoverable: "_hoverable_1vw8g_52"
779
- }, he = ({ children: e, variant: t = "default", chamfered: n = !1, chamferSize: r = "md", padding: i = "md", hoverable: a = !1, showDiagonalBorders: l = !0, edgeColor: u, className: d = "", onClick: f, style: p }) => {
801
+ }, Se = ({ children: e, variant: t = "default", chamfered: n = !1, chamferSize: r = "md", padding: i = "md", hoverable: a = !1, showDiagonalBorders: l = !0, edgeColor: u, className: d = "", onClick: f, style: p }) => {
780
802
  let m = n ? r === "asymmetric" ? "chamfered-box-asymmetric" : r === "sm" ? "chamfered-box-sm" : r === "lg" ? "chamfered-box-lg" : "chamfered-box" : "", h = u ?? (n ? "var(--color-border)" : void 0), g = h ? { color: h } : void 0, _ = h ? {
781
803
  ...p,
782
804
  "--card-edge-color": h
783
805
  } : p;
784
806
  return /* @__PURE__ */ c("div", {
785
- className: `${Z.card} ${n ? Z.chamfered : ""} ${Z[t]} ${Z[`padding-${i}`]} ${m} ${a ? Z.hoverable : ""} ${d}`,
807
+ className: `${X.card} ${n ? X.chamfered : ""} ${X[t]} ${X[`padding-${i}`]} ${m} ${a ? X.hoverable : ""} ${d}`,
786
808
  onClick: f,
787
809
  role: f ? "button" : void 0,
788
810
  tabIndex: f ? 0 : void 0,
@@ -806,7 +828,7 @@ var X = {
806
828
  })
807
829
  ] }), e]
808
830
  });
809
- }, ge = {
831
+ }, Z = {
810
832
  badge: "_badge_rk7t5_1",
811
833
  sm: "_sm_rk7t5_11",
812
834
  md: "_md_rk7t5_16",
@@ -818,8 +840,8 @@ var X = {
818
840
  warning: "_warning_rk7t5_47",
819
841
  error: "_error_rk7t5_52",
820
842
  info: "_info_rk7t5_57"
821
- }, _e = ({ children: e, variant: t = "default", size: n = "md", className: r = "" }) => /* @__PURE__ */ s("span", {
822
- className: `${ge.badge} ${ge[t]} ${ge[n]} ${r}`,
843
+ }, Ce = ({ children: e, variant: t = "default", size: n = "md", className: r = "" }) => /* @__PURE__ */ s("span", {
844
+ className: `${Z.badge} ${Z[t]} ${Z[n]} ${r}`,
823
845
  children: e
824
846
  }), Q = {
825
847
  overlay: "_overlay_1b3yt_1",
@@ -834,7 +856,7 @@ var X = {
834
856
  title: "_title_1b3yt_53",
835
857
  closeButton: "_closeButton_1b3yt_60",
836
858
  content: "_content_1b3yt_78"
837
- }, ve = ({ isOpen: e, onClose: t, title: n, children: r, size: a = "md", closeOnOverlayClick: o = !0, className: l = "" }) => (i(() => (e ? document.body.style.overflow = "hidden" : document.body.style.overflow = "unset", () => {
859
+ }, we = ({ isOpen: e, onClose: t, title: n, children: r, size: a = "md", closeOnOverlayClick: o = !0, className: l = "" }) => (i(() => (e ? document.body.style.overflow = "hidden" : document.body.style.overflow = "unset", () => {
838
860
  document.body.style.overflow = "unset";
839
861
  }), [e]), i(() => {
840
862
  let n = (n) => {
@@ -876,7 +898,7 @@ var X = {
876
898
  dot: "_dot_1uhnh_34",
877
899
  bounce: "_bounce_1uhnh_1",
878
900
  visuallyHidden: "_visuallyHidden_1uhnh_91"
879
- }, ye = ({ size: e = "md", variant: t = "spinner", className: n = "" }) => t === "dots" ? /* @__PURE__ */ c("div", {
901
+ }, Te = ({ size: e = "md", variant: t = "spinner", className: n = "" }) => t === "dots" ? /* @__PURE__ */ c("div", {
880
902
  className: `${$.dots} ${$[e]} ${n}`,
881
903
  children: [
882
904
  /* @__PURE__ */ s("span", { className: $.dot }),
@@ -890,10 +912,10 @@ var X = {
890
912
  className: $.visuallyHidden,
891
913
  children: "Loading..."
892
914
  })
893
- }), be = async (e) => {
915
+ }), Ee = async (e) => {
894
916
  if (e.length === 0) return {};
895
- let t = [...new Set(e)], n = await R.get(`/api/v1/users/lookup?ids=${t.join(",")}`);
917
+ let t = [...new Set(e)], n = await L.get(`/api/v1/users/lookup?ids=${t.join(",")}`);
896
918
  return Object.fromEntries(n.users.map((e) => [e.id, e.username]));
897
919
  };
898
920
  //#endregion
899
- export { le as AllyCodeDropdown, L as ApiClient, se as AuthProvider, _e as Badge, m as Button, he as Card, u as Container, de as Footer, v as Input, ye as Loader, ve as Modal, ue as NavBar, me as RosterRefresh, g as Select, f as TopBar, R as apiClient, I as authedFetch, ae as clearAllyCodes, O as clearTokens, M as configureAuthRefresh, be as fetchUsernames, G as formatAllyCode, Y as formatCountdown, pe as formatRelativeTime, x as getAccessToken, V as getAllyCodesFromStorage, w as getRefreshToken, ie as getSelectedAllyCode, te as initializeApiClient, ee as isAuthenticated, fe as parseBackendTimestamp, N as refreshAccessToken, C as removeAccessToken, re as removeAllyCodeFromStorage, E as removeRefreshToken, ne as saveAllyCodeToStorage, S as setAccessToken, T as setRefreshToken, U as setSelectedAllyCode, D as setTokens, ce as unformatAllyCode, H as updateAllyCodeLastUsed, W as useAuth };
921
+ export { ge as AllyCodeDropdown, se as ApiClient, me as AuthProvider, Ce as Badge, m as Button, Se as Card, u as Container, ve as Footer, v as Input, Te as Loader, we as Modal, _e as NavBar, xe as RosterRefresh, g as Select, f as TopBar, L as apiClient, oe as authedFetch, fe as clearAllyCodes, O as clearTokens, j as configureAuthRefresh, Ee as fetchUsernames, W as formatAllyCode, J as formatCountdown, be as formatRelativeTime, x as getAccessToken, B as getAllyCodesFromStorage, w as getRefreshToken, de as getSelectedAllyCode, ce as initializeApiClient, ee as isAuthenticated, ye as parseBackendTimestamp, M as refreshAccessToken, C as removeAccessToken, ue as removeAllyCodeFromStorage, E as removeRefreshToken, le as saveAllyCodeToStorage, S as setAccessToken, T as setRefreshToken, H as setSelectedAllyCode, D as setTokens, he as unformatAllyCode, V as updateAllyCodeLastUsed, U as useAuth };
@@ -19,6 +19,11 @@ export declare const refreshAccessToken: () => Promise<string>;
19
19
  * refresh is needed but fails (e.g. the refresh token is also expired), the
20
20
  * original 401 Response is returned so the caller can surface a re-login state.
21
21
  *
22
+ * Transient unavailability (a backend swapped mid-deploy, a 502/503/504, a
23
+ * dropped connection) is retried a couple of times — see `fetchWithRetry` for
24
+ * the exact, deliberately-narrow policy (non-idempotent writes are only
25
+ * retried when no response was ever received).
26
+ *
22
27
  * Works against ANY resource URL; only the refresh hop uses the configured
23
28
  * auth base URL.
24
29
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astrogators-shared-ui",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Shared UI components and utilities for Astrogator's Table applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",