@hexclave/tanstack-start 1.0.23 → 1.0.25
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/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/dev-tool/dev-tool-core.js +3 -67
- package/dist/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.d.ts.map +1 -1
- package/dist/esm/dev-tool/dev-tool-core.js +3 -67
- package/dist/esm/dev-tool/dev-tool-core.js.map +1 -1
- package/dist/esm/generated/env.js +20 -20
- package/dist/esm/generated/env.js.map +1 -1
- package/dist/esm/lib/auth.js +2 -2
- package/dist/esm/lib/auth.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js +2 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js +9 -3
- package/dist/esm/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/common.js +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.js +2 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.test.js +26 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/event-tracker.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.d.ts +7 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js +11 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
- package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.test.js +43 -0
- package/dist/esm/lib/hexclave-app/apps/implementations/session-replay.test.js.map +1 -1
- package/dist/esm/lib/hexclave-app/projects/index.d.ts +6 -0
- package/dist/esm/lib/hexclave-app/projects/index.d.ts.map +1 -1
- package/dist/esm/lib/hexclave-app/projects/index.js.map +1 -1
- package/dist/esm/lib/hexclave-app/url-targets.test.js +7 -7
- package/dist/esm/lib/hexclave-app/url-targets.test.js.map +1 -1
- package/dist/esm/pushed-config-error-overlay/index.d.ts +7 -0
- package/dist/esm/pushed-config-error-overlay/index.d.ts.map +1 -0
- package/dist/esm/pushed-config-error-overlay/index.js +464 -0
- package/dist/esm/pushed-config-error-overlay/index.js.map +1 -0
- package/dist/generated/env.js +20 -20
- package/dist/generated/env.js.map +1 -1
- package/dist/lib/auth.js +2 -2
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js +2 -0
- package/dist/lib/hexclave-app/apps/implementations/admin-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js +9 -3
- package/dist/lib/hexclave-app/apps/implementations/client-app-impl.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/common.js +1 -1
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.js +1 -0
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.test.js +26 -0
- package/dist/lib/hexclave-app/apps/implementations/event-tracker.test.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/session-replay.d.ts +7 -1
- package/dist/lib/hexclave-app/apps/implementations/session-replay.d.ts.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/session-replay.js +11 -0
- package/dist/lib/hexclave-app/apps/implementations/session-replay.js.map +1 -1
- package/dist/lib/hexclave-app/apps/implementations/session-replay.test.js +43 -0
- package/dist/lib/hexclave-app/apps/implementations/session-replay.test.js.map +1 -1
- package/dist/lib/hexclave-app/projects/index.d.ts +6 -0
- package/dist/lib/hexclave-app/projects/index.d.ts.map +1 -1
- package/dist/lib/hexclave-app/projects/index.js.map +1 -1
- package/dist/lib/hexclave-app/url-targets.test.js +7 -7
- package/dist/lib/hexclave-app/url-targets.test.js.map +1 -1
- package/dist/pushed-config-error-overlay/index.d.ts +7 -0
- package/dist/pushed-config-error-overlay/index.d.ts.map +1 -0
- package/dist/pushed-config-error-overlay/index.js +466 -0
- package/dist/pushed-config-error-overlay/index.js.map +1 -0
- package/package.json +3 -3
- package/src/dev-tool/dev-tool-core.ts +4 -58
- package/src/lib/auth.ts +2 -2
- package/src/lib/hexclave-app/apps/implementations/admin-app-impl.ts +6 -0
- package/src/lib/hexclave-app/apps/implementations/client-app-impl.ts +11 -3
- package/src/lib/hexclave-app/apps/implementations/event-tracker.test.ts +33 -0
- package/src/lib/hexclave-app/apps/implementations/event-tracker.ts +6 -1
- package/src/lib/hexclave-app/apps/implementations/session-replay.test.ts +52 -0
- package/src/lib/hexclave-app/apps/implementations/session-replay.ts +20 -0
- package/src/lib/hexclave-app/projects/index.ts +2 -0
- package/src/lib/hexclave-app/url-targets.test.ts +7 -7
- package/src/pushed-config-error-overlay/index.ts +548 -0
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
//===========================================
|
|
3
3
|
// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY UNLESS YOU ALSO EDIT THE CORRESPONDING FILE IN packages/template
|
|
4
4
|
//===========================================
|
|
5
|
-
import {
|
|
6
|
-
import { KnownError, KnownErrors, HexclaveClientInterface } from "@hexclave/shared";
|
|
5
|
+
import { HexclaveClientInterface, KnownError, KnownErrors } from "@hexclave/shared";
|
|
7
6
|
import type { RequestListener } from "@hexclave/shared/dist/interface/client-interface";
|
|
8
7
|
import { ContactChannelsCrud } from "@hexclave/shared/dist/interface/crud/contact-channels";
|
|
9
8
|
import { CurrentUserCrud } from "@hexclave/shared/dist/interface/crud/current-user";
|
|
@@ -42,14 +41,15 @@ import { BotChallengeExecutionFailedError, BotChallengeUserCancelledError, withB
|
|
|
42
41
|
import { createUrlIfValid, getRelativePart, isRelative } from "@hexclave/shared/dist/utils/urls";
|
|
43
42
|
import { generateUuid } from "@hexclave/shared/dist/utils/uuids";
|
|
44
43
|
import * as tanstackStartServerContext from "@hexclave/tanstack-start/tanstack-start-server-context"; // THIS_LINE_PLATFORM tanstack-start
|
|
44
|
+
import { WebAuthnError, startAuthentication, startRegistration } from "@simplewebauthn/browser";
|
|
45
45
|
import * as TanStackRouter from "@tanstack/react-router"; // THIS_LINE_PLATFORM tanstack-start
|
|
46
46
|
import * as cookie from "cookie";
|
|
47
47
|
import React, { useCallback, useMemo } from "react"; // THIS_LINE_PLATFORM react-like
|
|
48
48
|
import type * as yup from "yup";
|
|
49
|
+
import { envVars } from "../../../../generated/env";
|
|
49
50
|
import { constructRedirectUrl } from "../../../../utils/url";
|
|
50
51
|
import { callOAuthCallback, getNewOAuthProviderOrScopeUrl } from "../../../auth";
|
|
51
52
|
import { CookieHelper, createBrowserCookieHelper, createCookieHelper, createPlaceholderCookieHelper, deleteCookie, deleteCookieClient, getCookieClient, isSecure as isSecureCookieContext, saveVerifierAndState, setOrDeleteCookie, setOrDeleteCookieClient } from "../../../cookie";
|
|
52
|
-
import { envVars } from "../../../../generated/env";
|
|
53
53
|
import { ApiKey, ApiKeyCreationOptions, ApiKeyUpdateOptions, apiKeyCreationOptionsToCrud } from "../../api-keys";
|
|
54
54
|
import { ConvexCtx, GetCurrentPartialUserOptions, GetCurrentUserOptions, HandlerUrlOptions, HandlerUrls, OAuthScopesOnSignIn, RedirectMethod, RedirectToOptions, RequestLike, ResolvedHandlerUrls, TokenStoreInit, hexclaveAppInternalsSymbol } from "../../common";
|
|
55
55
|
import { DeprecatedOAuthConnection, OAuthConnection } from "../../connected-accounts";
|
|
@@ -73,6 +73,7 @@ import { AnalyticsOptions, SessionRecorder, analyticsOptionsFromJson, analyticsO
|
|
|
73
73
|
import { useAsyncCache } from "./common";
|
|
74
74
|
import { mountClickmapOverlay } from "../../../../clickmap";
|
|
75
75
|
import { mountDevTool } from "../../../../dev-tool";
|
|
76
|
+
import { mountPushedConfigErrorOverlay } from "../../../../pushed-config-error-overlay";
|
|
76
77
|
|
|
77
78
|
let isReactServer = false;
|
|
78
79
|
|
|
@@ -742,6 +743,7 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
|
|
|
742
743
|
// when a dashboard-minted token is handed over, so the listener is
|
|
743
744
|
// mounted unconditionally (the heavy UI is lazy-loaded on demand).
|
|
744
745
|
mountClickmapOverlay(this as any);
|
|
746
|
+
mountPushedConfigErrorOverlay(this as any);
|
|
745
747
|
}
|
|
746
748
|
}
|
|
747
749
|
|
|
@@ -1636,6 +1638,12 @@ export class _HexclaveClientAppImplIncomplete<HasTokenStore extends boolean, Pro
|
|
|
1636
1638
|
return {
|
|
1637
1639
|
id: crud.id,
|
|
1638
1640
|
displayName: crud.display_name,
|
|
1641
|
+
pushedConfigError: crud.pushed_config_error == null ? null : {
|
|
1642
|
+
message: crud.pushed_config_error.message,
|
|
1643
|
+
},
|
|
1644
|
+
configWarnings: crud.config_warnings.map((warning) => ({
|
|
1645
|
+
message: warning.message,
|
|
1646
|
+
})),
|
|
1639
1647
|
config: {
|
|
1640
1648
|
signUpEnabled: crud.config.sign_up_enabled,
|
|
1641
1649
|
credentialEnabled: crud.config.credential_enabled,
|
|
@@ -391,6 +391,39 @@ describe("EventTracker", () => {
|
|
|
391
391
|
}
|
|
392
392
|
});
|
|
393
393
|
|
|
394
|
+
it("silently ignores network errors caused by ad blockers", async () => {
|
|
395
|
+
vi.useFakeTimers();
|
|
396
|
+
document.body.innerHTML = "<button>Click me</button>";
|
|
397
|
+
|
|
398
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
399
|
+
const sentBodies: string[] = [];
|
|
400
|
+
const tracker = new EventTracker({
|
|
401
|
+
projectId: "internal",
|
|
402
|
+
sendBatch: async (body) => {
|
|
403
|
+
sentBodies.push(body);
|
|
404
|
+
return Result.error(new TypeError("Failed to fetch"));
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
tracker.start();
|
|
410
|
+
|
|
411
|
+
await advancePastFlush();
|
|
412
|
+
expect(sentBodies).toHaveLength(1);
|
|
413
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
414
|
+
|
|
415
|
+
// Unlike ANALYTICS_NOT_ENABLED, ad blocker errors do NOT disable the
|
|
416
|
+
// tracker — subsequent flushes continue attempting delivery.
|
|
417
|
+
document.querySelector("button")?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
418
|
+
await advancePastFlush();
|
|
419
|
+
expect(sentBodies).toHaveLength(2);
|
|
420
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
421
|
+
} finally {
|
|
422
|
+
tracker.stop();
|
|
423
|
+
warnSpy.mockRestore();
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
394
427
|
it("silently disables when client interface returns ANALYTICS_NOT_ENABLED as an error", async () => {
|
|
395
428
|
vi.useFakeTimers();
|
|
396
429
|
document.body.innerHTML = "<button>Click me</button>";
|
|
@@ -8,7 +8,7 @@ import { cssEscapeIdent } from "@hexclave/shared/dist/utils/dom";
|
|
|
8
8
|
import { buildElementsChain, ELEMENTS_CHAIN_MAX_DEPTH } from "@hexclave/shared/dist/utils/elements-chain";
|
|
9
9
|
import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
|
|
10
10
|
import { Result } from "@hexclave/shared/dist/utils/results";
|
|
11
|
-
import { generateUuid, isAnalyticsNotEnabledError } from "./session-replay";
|
|
11
|
+
import { generateUuid, isAdBlockerNetworkError, isAnalyticsNotEnabledError } from "./session-replay";
|
|
12
12
|
|
|
13
13
|
const FLUSH_INTERVAL_MS = 10_000;
|
|
14
14
|
const MAX_EVENTS_PER_BATCH = 50;
|
|
@@ -511,6 +511,11 @@ export class EventTracker {
|
|
|
511
511
|
this._disable();
|
|
512
512
|
return;
|
|
513
513
|
}
|
|
514
|
+
// Ad blockers commonly block analytics endpoints, causing network
|
|
515
|
+
// errors. These are expected and should not pollute the console.
|
|
516
|
+
if (isAdBlockerNetworkError(res.error)) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
514
519
|
console.warn("EventTracker flush failed:", res.error);
|
|
515
520
|
return;
|
|
516
521
|
}
|
|
@@ -49,6 +49,58 @@ describe("analytics option JSON conversion", () => {
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
describe("SessionRecorder flush", () => {
|
|
52
|
+
it("silently ignores network errors caused by ad blockers", async () => {
|
|
53
|
+
vi.useFakeTimers();
|
|
54
|
+
|
|
55
|
+
const storageKey = `hexclave:session-replay:v1:test-project`;
|
|
56
|
+
localStorage.setItem(storageKey, JSON.stringify({
|
|
57
|
+
session_id: "test-session",
|
|
58
|
+
created_at_ms: Date.now(),
|
|
59
|
+
last_activity_ms: Date.now(),
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
const sentBodies: string[] = [];
|
|
63
|
+
const recorder = new SessionRecorder(
|
|
64
|
+
{
|
|
65
|
+
projectId: "test-project",
|
|
66
|
+
sendBatch: async (body) => {
|
|
67
|
+
sentBodies.push(body);
|
|
68
|
+
return Result.error(new TypeError("Failed to fetch"));
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
78
|
+
(recorder as any)._events = [{ type: 2, timestamp: Date.now(), data: {} }];
|
|
79
|
+
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
|
81
|
+
(recorder as any)._tick();
|
|
82
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
83
|
+
|
|
84
|
+
expect(sentBodies).toHaveLength(1);
|
|
85
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
86
|
+
|
|
87
|
+
// Unlike ANALYTICS_NOT_ENABLED, ad blocker errors do NOT disable the
|
|
88
|
+
// recorder — subsequent flushes continue attempting delivery.
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
90
|
+
(recorder as any)._events = [{ type: 3, timestamp: Date.now(), data: {} }];
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
|
92
|
+
(recorder as any)._tick();
|
|
93
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
94
|
+
expect(sentBodies).toHaveLength(2);
|
|
95
|
+
expect(warnSpy).not.toHaveBeenCalled();
|
|
96
|
+
} finally {
|
|
97
|
+
recorder.stop();
|
|
98
|
+
warnSpy.mockRestore();
|
|
99
|
+
localStorage.removeItem(storageKey);
|
|
100
|
+
vi.useRealTimers();
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
52
104
|
it("silently disables when client interface returns ANALYTICS_NOT_ENABLED as an error", async () => {
|
|
53
105
|
vi.useFakeTimers();
|
|
54
106
|
|
|
@@ -170,6 +170,21 @@ export function isAnalyticsNotEnabledError(error: unknown): boolean {
|
|
|
170
170
|
return KnownErrors.AnalyticsNotEnabled.isInstance(error);
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Whether the error looks like a network failure caused by an ad blocker or
|
|
175
|
+
* similar extension blocking analytics requests. These are expected in
|
|
176
|
+
* production and should be silently ignored rather than logged as warnings.
|
|
177
|
+
*/
|
|
178
|
+
export function isAdBlockerNetworkError(error: unknown): boolean {
|
|
179
|
+
if (error instanceof Error) {
|
|
180
|
+
return error.message.includes("Failed to fetch")
|
|
181
|
+
|| error.message.includes("NetworkError")
|
|
182
|
+
|| error.message.includes("Load failed")
|
|
183
|
+
|| error.message.includes("network connection");
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
173
188
|
export class SessionRecorder {
|
|
174
189
|
private _started = false;
|
|
175
190
|
private _cancelled = false;
|
|
@@ -278,6 +293,11 @@ export class SessionRecorder {
|
|
|
278
293
|
this._disable();
|
|
279
294
|
return;
|
|
280
295
|
}
|
|
296
|
+
// Ad blockers commonly block analytics endpoints, causing network
|
|
297
|
+
// errors. These are expected and should not pollute the console.
|
|
298
|
+
if (isAdBlockerNetworkError(res.error)) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
281
301
|
captureWarning("SessionRecorder.flush", res.error);
|
|
282
302
|
return;
|
|
283
303
|
}
|
|
@@ -30,6 +30,8 @@ export type PushConfigOptions = {
|
|
|
30
30
|
export type Project = {
|
|
31
31
|
readonly id: string,
|
|
32
32
|
readonly displayName: string,
|
|
33
|
+
readonly pushedConfigError: { message: string } | null,
|
|
34
|
+
readonly configWarnings: { message: string }[],
|
|
33
35
|
readonly config: ProjectConfig,
|
|
34
36
|
};
|
|
35
37
|
|
|
@@ -85,7 +85,7 @@ describe("handler URL targets", () => {
|
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
it("uses hosted defaults for unspecified URLs", () => {
|
|
88
|
-
vi.stubEnv("
|
|
88
|
+
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test");
|
|
89
89
|
|
|
90
90
|
const urls = resolveHandlerUrls({
|
|
91
91
|
projectId: "project-id",
|
|
@@ -101,7 +101,7 @@ describe("handler URL targets", () => {
|
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
it("keeps redirect-only post-auth targets local even when the default target is hosted", () => {
|
|
104
|
-
vi.stubEnv("
|
|
104
|
+
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test");
|
|
105
105
|
|
|
106
106
|
const urls = resolveHandlerUrls({
|
|
107
107
|
projectId: "project-id",
|
|
@@ -145,7 +145,7 @@ describe("handler URL targets", () => {
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
it("inherits a hosted default target for the OAuth callback", () => {
|
|
148
|
-
vi.stubEnv("
|
|
148
|
+
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test");
|
|
149
149
|
|
|
150
150
|
const urls = resolveHandlerUrls({
|
|
151
151
|
projectId: "project-id",
|
|
@@ -183,7 +183,7 @@ describe("handler URL targets", () => {
|
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
it("uses default target for unknown /handler/* pages", () => {
|
|
186
|
-
vi.stubEnv("
|
|
186
|
+
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_DOMAIN_SUFFIX", ".example-stack-hosted.test");
|
|
187
187
|
|
|
188
188
|
const url = resolveUnknownHandlerPathFallbackUrl({
|
|
189
189
|
defaultTarget: { type: "hosted" },
|
|
@@ -195,7 +195,7 @@ describe("handler URL targets", () => {
|
|
|
195
195
|
});
|
|
196
196
|
|
|
197
197
|
it("uses the full hosted handler URL template when configured", () => {
|
|
198
|
-
vi.stubEnv("
|
|
198
|
+
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE", "http://{projectId}.localhost:${NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX:-81}09/{hostedPath}");
|
|
199
199
|
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_PORT_PREFIX", "93");
|
|
200
200
|
|
|
201
201
|
const urls = resolveHandlerUrls({
|
|
@@ -210,7 +210,7 @@ describe("handler URL targets", () => {
|
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
it("validates the hosted handler URL template placeholders", () => {
|
|
213
|
-
vi.stubEnv("
|
|
213
|
+
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE", "http://localhost:9309/{projectId}/handler");
|
|
214
214
|
|
|
215
215
|
expect(() => resolveHandlerUrls({
|
|
216
216
|
projectId: "project-id",
|
|
@@ -221,7 +221,7 @@ describe("handler URL targets", () => {
|
|
|
221
221
|
});
|
|
222
222
|
|
|
223
223
|
it("rejects hosted handler URL templates that put the project ID in the path", () => {
|
|
224
|
-
vi.stubEnv("
|
|
224
|
+
vi.stubEnv("NEXT_PUBLIC_HEXCLAVE_HOSTED_HANDLER_URL_TEMPLATE", "http://localhost:9309/{projectId}/{hostedPath}");
|
|
225
225
|
|
|
226
226
|
expect(() => resolveHandlerUrls({
|
|
227
227
|
projectId: "project-id",
|