@hexclave/js 1.0.75 → 1.0.76

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.
Files changed (99) hide show
  1. package/dist/{admin-app-impl-BhrjJlxj.d.ts → admin-app-impl-B86v7B0O.d.ts} +7 -7
  2. package/dist/{admin-app-impl-BhrjJlxj.d.ts.map → admin-app-impl-B86v7B0O.d.ts.map} +1 -1
  3. package/dist/dev-tool/dev-tool-core.d.ts.map +1 -1
  4. package/dist/dev-tool/dev-tool-core.js +2 -2
  5. package/dist/dev-tool/dev-tool-core.js.map +1 -1
  6. package/dist/dev-tool/index.d.ts.map +1 -1
  7. package/dist/dev-tool/index.js +2 -8
  8. package/dist/dev-tool/index.js.map +1 -1
  9. package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
  10. package/dist/esm/dev-tool/dev-tool-core.js +1 -1
  11. package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
  12. package/dist/esm/dev-tool/index.d.ts.map +1 -1
  13. package/dist/esm/dev-tool/index.js +2 -8
  14. package/dist/esm/dev-tool/index.js.map +1 -1
  15. package/dist/esm/in-page-ui/dev-environment.d.ts +5 -0
  16. package/dist/esm/in-page-ui/dev-environment.d.ts.map +1 -0
  17. package/dist/esm/in-page-ui/dev-environment.js +18 -0
  18. package/dist/esm/in-page-ui/dev-environment.js.map +1 -0
  19. package/dist/esm/in-page-ui/issue-card.d.ts +52 -0
  20. package/dist/esm/in-page-ui/issue-card.d.ts.map +1 -0
  21. package/dist/esm/in-page-ui/issue-card.js +392 -0
  22. package/dist/esm/in-page-ui/issue-card.js.map +1 -0
  23. package/dist/esm/in-page-ui/issue-card.test.d.ts +1 -0
  24. package/dist/esm/in-page-ui/issue-card.test.js +60 -0
  25. package/dist/esm/in-page-ui/issue-card.test.js.map +1 -0
  26. package/dist/esm/in-page-ui/logo.d.ts +5 -0
  27. package/dist/esm/in-page-ui/logo.d.ts.map +1 -0
  28. package/dist/esm/in-page-ui/logo.js +6 -0
  29. package/dist/esm/in-page-ui/logo.js.map +1 -0
  30. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +4 -4
  31. package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  32. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +140 -15
  33. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  34. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +2 -2
  35. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  36. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +95 -12
  37. package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  38. package/dist/esm/lib/hexclave-app/apps/implementations/common.js +2 -2
  39. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +1 -0
  40. package/dist/esm/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
  41. package/dist/esm/pushed-config-error-overlay/index.d.ts.map +1 -1
  42. package/dist/esm/pushed-config-error-overlay/index.js +42 -343
  43. package/dist/esm/pushed-config-error-overlay/index.js.map +1 -1
  44. package/dist/esm/setup-error-overlay/index.d.ts +16 -0
  45. package/dist/esm/setup-error-overlay/index.d.ts.map +1 -0
  46. package/dist/esm/setup-error-overlay/index.js +106 -0
  47. package/dist/esm/setup-error-overlay/index.js.map +1 -0
  48. package/dist/esm/setup-error-overlay/index.test.d.ts +1 -0
  49. package/dist/esm/setup-error-overlay/index.test.js +125 -0
  50. package/dist/esm/setup-error-overlay/index.test.js.map +1 -0
  51. package/dist/in-page-ui/dev-environment.d.ts +5 -0
  52. package/dist/in-page-ui/dev-environment.d.ts.map +1 -0
  53. package/dist/in-page-ui/dev-environment.js +19 -0
  54. package/dist/in-page-ui/dev-environment.js.map +1 -0
  55. package/dist/in-page-ui/issue-card.d.ts +52 -0
  56. package/dist/in-page-ui/issue-card.d.ts.map +1 -0
  57. package/dist/in-page-ui/issue-card.js +397 -0
  58. package/dist/in-page-ui/issue-card.js.map +1 -0
  59. package/dist/in-page-ui/issue-card.test.d.ts +1 -0
  60. package/dist/in-page-ui/issue-card.test.js +59 -0
  61. package/dist/in-page-ui/issue-card.test.js.map +1 -0
  62. package/dist/in-page-ui/logo.d.ts +5 -0
  63. package/dist/in-page-ui/logo.d.ts.map +1 -0
  64. package/dist/in-page-ui/logo.js +7 -0
  65. package/dist/in-page-ui/logo.js.map +1 -0
  66. package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts +1 -1
  67. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js +140 -15
  68. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.js.map +1 -1
  69. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts +1 -1
  70. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +94 -11
  71. package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
  72. package/dist/lib/hexclave-app/apps/implementations/common.js +2 -2
  73. package/dist/lib/hexclave-app/apps/implementations/index.d.ts +1 -1
  74. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js +1 -0
  75. package/dist/lib/hexclave-app/apps/implementations/redirect-page-urls.test.js.map +1 -1
  76. package/dist/lib/hexclave-app/apps/implementations/server-app-impl.d.ts +1 -1
  77. package/dist/pushed-config-error-overlay/index.d.ts.map +1 -1
  78. package/dist/pushed-config-error-overlay/index.js +41 -342
  79. package/dist/pushed-config-error-overlay/index.js.map +1 -1
  80. package/dist/setup-error-overlay/index.d.ts +16 -0
  81. package/dist/setup-error-overlay/index.d.ts.map +1 -0
  82. package/dist/setup-error-overlay/index.js +108 -0
  83. package/dist/setup-error-overlay/index.js.map +1 -0
  84. package/dist/setup-error-overlay/index.test.d.ts +1 -0
  85. package/dist/setup-error-overlay/index.test.js +124 -0
  86. package/dist/setup-error-overlay/index.test.js.map +1 -0
  87. package/package.json +2 -2
  88. package/src/dev-tool/dev-tool-core.ts +1 -4
  89. package/src/dev-tool/index.ts +4 -15
  90. package/src/in-page-ui/dev-environment.ts +33 -0
  91. package/src/in-page-ui/issue-card.test.ts +67 -0
  92. package/src/in-page-ui/issue-card.ts +500 -0
  93. package/src/in-page-ui/logo.ts +8 -0
  94. package/src/lib/hexclave-app/apps/implementations/client-app-impl.cross-domain.test.ts +158 -0
  95. package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +125 -17
  96. package/src/lib/hexclave-app/apps/implementations/redirect-page-urls.test.ts +1 -0
  97. package/src/pushed-config-error-overlay/index.ts +45 -386
  98. package/src/setup-error-overlay/index.test.ts +133 -0
  99. package/src/setup-error-overlay/index.ts +150 -0
@@ -40,6 +40,7 @@ let __session_replay_js = require("./session-replay.js");
40
40
  let ____________clickmap_index_js = require("../../../../clickmap/index.js");
41
41
  let ____________dev_tool_index_js = require("../../../../dev-tool/index.js");
42
42
  let ____________pushed_config_error_overlay_index_js = require("../../../../pushed-config-error-overlay/index.js");
43
+ let ____________setup_error_overlay_index_js = require("../../../../setup-error-overlay/index.js");
43
44
  //#region src/lib/hexclave-app/apps/implementations/client-app-impl.ts
44
45
  const prefetchedCrossDomainHandoffTtlMs = 3300 * 1e3;
45
46
  const oauthAfterCallbackRedirectUrlQueryParam = "after_callback_redirect_url";
@@ -52,6 +53,50 @@ const nestedCrossDomainAuthQueryParams = {
52
53
  codeChallengeMethod: "code_challenge_method",
53
54
  afterCallbackRedirectUrl: oauthAfterCallbackRedirectUrlQueryParam
54
55
  };
56
+ /**
57
+ * An auth flow can only ever send the user to a URL that the project trusts, so an untrusted one means the flow is dead
58
+ * until someone changes the project's configuration. Describe the problem in terms of that configuration rather than in
59
+ * terms of the flow's internals, which nobody outside this file knows about.
60
+ */
61
+ function createUntrustedUrlError(options) {
62
+ const origin = (0, _hexclave_shared_dist_utils_urls.createUrlIfValid)(options.url)?.origin ?? options.url;
63
+ return new _hexclave_shared_dist_utils_errors.HexclaveSetupError({
64
+ title: "A domain in your authentication flow is not one of your project's trusted domains",
65
+ message: options.message,
66
+ howToFix: [
67
+ `If ${origin} is yours, add it to your project's trusted domains in the Hexclave dashboard, under Domains.`,
68
+ "Protocol, domain and port must all match a trusted domain exactly; a wildcard like https://*.example.com matches only one subdomain level.",
69
+ `If ${origin} is not yours, do not add it \u2014 somebody may be trying to redirect your users' credentials to it.`
70
+ ],
71
+ extraData: {
72
+ url: options.url,
73
+ projectId: options.projectId
74
+ }
75
+ });
76
+ }
77
+ function createUntrustedNestedCrossDomainUrlError(options) {
78
+ return createUntrustedUrlError({
79
+ message: `Nested cross-domain auth ${options.urlDescription} ${options.url} is not trusted.`,
80
+ url: options.url,
81
+ projectId: options.projectId
82
+ });
83
+ }
84
+ /**
85
+ * A URL that the auth flow cannot even parse is just as fatal as an untrusted one, and just as much a configuration
86
+ * problem: something in the developer's setup put a relative or malformed value where an absolute URL belongs.
87
+ */
88
+ function createMalformedNestedCrossDomainUrlError(options) {
89
+ return new _hexclave_shared_dist_utils_errors.HexclaveSetupError({
90
+ title: "A URL in your authentication flow is not a valid absolute URL",
91
+ message: `Nested cross-domain auth ${options.urlDescription} ${options.url} is not a valid absolute URL.`,
92
+ howToFix: [
93
+ "Handler URLs and after-auth redirect URLs must be absolute, including their protocol, like https://example.com/handler/oauth-callback.",
94
+ "Check the handler URLs configured for your project and the redirect URLs you pass to Hexclave's sign-in and sign-up methods.",
95
+ "If none of those look wrong, check whether a proxy or rewrite in front of your app is rewriting the authentication flow's query parameters."
96
+ ],
97
+ extraData: { url: options.url }
98
+ });
99
+ }
55
100
  function getRedirectHelperInstruction(handlerName) {
56
101
  if (handlerName === "handler") return "Use a page-specific redirect helper such as app.redirectToSignIn() instead.";
57
102
  return `Use app.${`redirectTo${handlerName.slice(0, 1).toUpperCase()}${handlerName.slice(1)}`}() instead.`;
@@ -457,6 +502,7 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
457
502
  await callback();
458
503
  } catch (error) {
459
504
  (0, _hexclave_shared_dist_utils_errors.captureError)("pending-auth-resolution-failed", error);
505
+ (0, ____________setup_error_overlay_index_js.showSetupErrorOverlay)(error);
460
506
  }
461
507
  })();
462
508
  this._pendingAuthResolutionPromises.push(promise);
@@ -573,13 +619,35 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
573
619
  codeChallenge
574
620
  });
575
621
  if ((currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.codeChallengeMethod) ?? "S256") !== "S256") throw new _hexclave_shared_dist_utils_errors.HexclaveAssertionError("Nested cross-domain auth only supports S256 PKCE");
576
- if ((0, _hexclave_shared_dist_utils_urls.isRelative)(redirectUri)) throw new Error("Nested cross-domain auth redirect URI must be absolute.");
577
- const redirectUriUrl = new URL(redirectUri);
578
- if (!await this._isTrusted(redirectUriUrl.toString())) throw new Error(`Nested cross-domain auth redirect URI ${redirectUri} is not trusted.`);
622
+ const validateHandoffOwnership = async () => {
623
+ if (await this._fetchCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: false }) !== refreshTokenId) throw new Error("Nested cross-domain auth source session does not match the requested refresh token ID.");
624
+ };
625
+ const setupErrorIfHandoffIsOwned = async (setupError) => {
626
+ await validateHandoffOwnership();
627
+ return setupError;
628
+ };
629
+ const redirectUriUrl = (0, _hexclave_shared_dist_utils_urls.isRelative)(redirectUri) ? null : (0, _hexclave_shared_dist_utils_urls.createUrlIfValid)(redirectUri);
630
+ if (redirectUriUrl == null) throw await setupErrorIfHandoffIsOwned(createMalformedNestedCrossDomainUrlError({
631
+ urlDescription: "redirect URI",
632
+ url: redirectUri
633
+ }));
634
+ if (!await this._isTrusted(redirectUriUrl.toString())) throw await setupErrorIfHandoffIsOwned(createUntrustedNestedCrossDomainUrlError({
635
+ urlDescription: "redirect URI",
636
+ url: redirectUri,
637
+ projectId: this.projectId
638
+ }));
579
639
  const afterCallbackRedirectUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.afterCallbackRedirectUrl);
580
- const afterCallbackRedirectUrl = afterCallbackRedirectUrlString == null ? redirectUriUrl : new URL(afterCallbackRedirectUrlString, redirectUriUrl);
581
- if (!await this._isTrusted(afterCallbackRedirectUrl.toString())) throw new Error(`Nested cross-domain auth after-callback redirect URL ${afterCallbackRedirectUrlString} is not trusted.`);
582
- if (await this._fetchCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: false }) !== refreshTokenId) throw new Error("Nested cross-domain auth source session does not match the requested refresh token ID.");
640
+ const afterCallbackRedirectUrl = afterCallbackRedirectUrlString == null ? redirectUriUrl : (0, _hexclave_shared_dist_utils_urls.createUrlIfValid)(afterCallbackRedirectUrlString, redirectUriUrl);
641
+ if (afterCallbackRedirectUrl == null) throw await setupErrorIfHandoffIsOwned(createMalformedNestedCrossDomainUrlError({
642
+ urlDescription: "after-callback redirect URL",
643
+ url: afterCallbackRedirectUrlString ?? ""
644
+ }));
645
+ if (!await this._isTrusted(afterCallbackRedirectUrl.toString())) throw await setupErrorIfHandoffIsOwned(createUntrustedNestedCrossDomainUrlError({
646
+ urlDescription: "after-callback redirect URL",
647
+ url: afterCallbackRedirectUrlString ?? afterCallbackRedirectUrl.toString(),
648
+ projectId: this.projectId
649
+ }));
650
+ await validateHandoffOwnership();
583
651
  await this._redirectTo({
584
652
  url: await this._createCrossDomainAuthRedirectUrl({
585
653
  redirectUri: redirectUriUrl.toString(),
@@ -597,9 +665,16 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
597
665
  if (currentRefreshTokenId != null) (await this._getSession(void 0, { awaitPendingAuthResolutions: false })).markInvalid();
598
666
  const callbackUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.callbackUrl);
599
667
  if (callbackUrlString == null) throw new _hexclave_shared_dist_utils_errors.HexclaveAssertionError("Nested cross-domain auth URL is missing callback URL");
600
- if ((0, _hexclave_shared_dist_utils_urls.isRelative)(callbackUrlString)) throw new Error("Nested cross-domain auth callback URL must be absolute.");
601
- const callbackUrl = new URL(callbackUrlString);
602
- if (!await this._isTrusted(callbackUrl.toString())) throw new Error(`Nested cross-domain auth callback URL ${callbackUrlString} is not trusted.`);
668
+ const callbackUrl = (0, _hexclave_shared_dist_utils_urls.isRelative)(callbackUrlString) ? null : (0, _hexclave_shared_dist_utils_urls.createUrlIfValid)(callbackUrlString);
669
+ if (callbackUrl == null) throw createMalformedNestedCrossDomainUrlError({
670
+ urlDescription: "callback URL",
671
+ url: callbackUrlString
672
+ });
673
+ if (!await this._isTrusted(callbackUrl.toString())) throw createUntrustedNestedCrossDomainUrlError({
674
+ urlDescription: "callback URL",
675
+ url: callbackUrlString,
676
+ projectId: this.projectId
677
+ });
603
678
  const afterCallbackRedirectUrl = new URL(currentUrl);
604
679
  afterCallbackRedirectUrl.searchParams.delete(nestedCrossDomainAuthQueryParams.refreshTokenId);
605
680
  afterCallbackRedirectUrl.searchParams.delete(nestedCrossDomainAuthQueryParams.callbackUrl);
@@ -1943,7 +2018,11 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
1943
2018
  await (0, _hexclave_shared_dist_utils_promises.wait)(2e3);
1944
2019
  }
1945
2020
  async _redirectIfTrusted(url, options) {
1946
- if (!await this._isTrusted(url)) throw new Error(`Redirect URL ${url} is not trusted; should be relative.`);
2021
+ if (!await this._isTrusted(url)) throw createUntrustedUrlError({
2022
+ message: `Redirect URL ${url} is not trusted; should be relative.`,
2023
+ url,
2024
+ projectId: this.projectId
2025
+ });
1947
2026
  return await this._redirectTo({
1948
2027
  url,
1949
2028
  ...options
@@ -1988,7 +2067,11 @@ var _HexclaveClientAppImplIncomplete = class _HexclaveClientAppImplIncomplete {
1988
2067
  awaitPendingAuthResolutions: internalOptions?.awaitPendingAuthResolutions,
1989
2068
  overrideTokenStoreInit: internalOptions?.overrideTokenStoreInit
1990
2069
  }) : plan.url;
1991
- if (!await this._isTrusted(redirectUrl)) throw new Error(`Redirect URL ${redirectUrl} is not trusted; should be relative.`);
2070
+ if (!await this._isTrusted(redirectUrl)) throw createUntrustedUrlError({
2071
+ message: `Redirect URL ${redirectUrl} is not trusted; should be relative.`,
2072
+ url: redirectUrl,
2073
+ projectId: this.projectId
2074
+ });
1992
2075
  return redirectUrl;
1993
2076
  }
1994
2077
  _redirectToHandlerDuringRender(handlerName, options) {