@replicated/portal-components 0.0.23 → 0.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/components/metadata/registry.json +2 -2
- package/components/metadata/registry.md +2 -2
- package/dist/actions/branding-actions.d.mts +7 -0
- package/dist/actions/branding-actions.d.ts +7 -0
- package/dist/actions/branding-actions.js +394 -0
- package/dist/actions/branding-actions.js.map +1 -0
- package/dist/actions/index.js +0 -3
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/invite-actions.d.mts +13 -0
- package/dist/actions/invite-actions.d.ts +13 -0
- package/dist/actions/invite-actions.js +527 -0
- package/dist/actions/invite-actions.js.map +1 -0
- package/dist/actions/magic-link-actions.d.mts +8 -0
- package/dist/actions/magic-link-actions.d.ts +8 -0
- package/dist/actions/magic-link-actions.js +478 -0
- package/dist/actions/magic-link-actions.js.map +1 -0
- package/dist/actions/trial-signup-actions.d.mts +7 -0
- package/dist/actions/trial-signup-actions.d.ts +7 -0
- package/dist/actions/trial-signup-actions.js +546 -0
- package/dist/actions/trial-signup-actions.js.map +1 -0
- package/dist/esm/actions/branding-actions.js +392 -0
- package/dist/esm/actions/branding-actions.js.map +1 -0
- package/dist/esm/actions/index.js +0 -3
- package/dist/esm/actions/index.js.map +1 -1
- package/dist/esm/actions/invite-actions.js +524 -0
- package/dist/esm/actions/invite-actions.js.map +1 -0
- package/dist/esm/actions/magic-link-actions.js +476 -0
- package/dist/esm/actions/magic-link-actions.js.map +1 -0
- package/dist/esm/actions/trial-signup-actions.js +544 -0
- package/dist/esm/actions/trial-signup-actions.js.map +1 -0
- package/dist/esm/index.js +2 -7
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logout-action.js +2 -3
- package/dist/esm/logout-action.js.map +1 -1
- package/dist/esm/logout-button.js +10 -7
- package/dist/esm/logout-button.js.map +1 -1
- package/dist/esm/use-verify-magic-link.js +74 -0
- package/dist/esm/use-verify-magic-link.js.map +1 -0
- package/dist/esm/utils/index.js +1 -6
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -7
- package/dist/index.js.map +1 -1
- package/dist/logout-action.d.mts +5 -2
- package/dist/logout-action.d.ts +5 -2
- package/dist/logout-action.js +2 -3
- package/dist/logout-action.js.map +1 -1
- package/dist/logout-button.d.mts +4 -1
- package/dist/logout-button.d.ts +4 -1
- package/dist/logout-button.js +10 -7
- package/dist/logout-button.js.map +1 -1
- package/dist/use-verify-magic-link.d.mts +34 -0
- package/dist/use-verify-magic-link.d.ts +34 -0
- package/dist/use-verify-magic-link.js +76 -0
- package/dist/use-verify-magic-link.js.map +1 -0
- package/dist/utils/index.d.mts +1 -16
- package/dist/utils/index.d.ts +1 -16
- package/dist/utils/index.js +0 -6
- package/dist/utils/index.js.map +1 -1
- package/package.json +32 -2
package/dist/logout-action.d.mts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Server action to log out the current user.
|
|
3
|
-
* Deletes the portal_session cookie and
|
|
3
|
+
* Deletes the portal_session cookie and returns success.
|
|
4
|
+
* The client is responsible for redirecting after logout.
|
|
4
5
|
*/
|
|
5
|
-
declare const logoutAction: (
|
|
6
|
+
declare const logoutAction: () => Promise<{
|
|
7
|
+
success: boolean;
|
|
8
|
+
}>;
|
|
6
9
|
|
|
7
10
|
export { logoutAction };
|
package/dist/logout-action.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Server action to log out the current user.
|
|
3
|
-
* Deletes the portal_session cookie and
|
|
3
|
+
* Deletes the portal_session cookie and returns success.
|
|
4
|
+
* The client is responsible for redirecting after logout.
|
|
4
5
|
*/
|
|
5
|
-
declare const logoutAction: (
|
|
6
|
+
declare const logoutAction: () => Promise<{
|
|
7
|
+
success: boolean;
|
|
8
|
+
}>;
|
|
6
9
|
|
|
7
10
|
export { logoutAction };
|
package/dist/logout-action.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var headers = require('next/headers');
|
|
4
|
-
var navigation = require('next/navigation');
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Enterprise Portal Components
|
|
@@ -177,10 +176,10 @@ function traceServerAction(name, fn) {
|
|
|
177
176
|
}
|
|
178
177
|
|
|
179
178
|
// src/actions/logout.ts
|
|
180
|
-
async function logoutActionImpl(
|
|
179
|
+
async function logoutActionImpl() {
|
|
181
180
|
const cookieStore = await headers.cookies();
|
|
182
181
|
cookieStore.delete("portal_session");
|
|
183
|
-
|
|
182
|
+
return { success: true };
|
|
184
183
|
}
|
|
185
184
|
var logoutAction = traceServerAction("logoutAction", logoutActionImpl);
|
|
186
185
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../datadog/tracer.ts","../src/utils/observability/tracing.ts","../src/actions/logout.ts"],"names":["rawFlag","isEnabled","tracer","cookies","redirect"],"mappings":"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","file":"logout-action.js","sourcesContent":["import type { Tracer, Span, init as ddTraceInit } from 'dd-trace';\nimport type { IncomingMessage } from 'http';\n\nconst rawFlag = String(process.env.USE_DATADOG_APM || '').toLowerCase();\nconst isEnabled = rawFlag === 'true';\n\nprocess.env.DD_TRACE_ENABLED = isEnabled ? '1' : '0';\n\nlet tracer: Tracer | null = null;\n\nif (isEnabled) {\n const serviceName = process.env.DD_SERVICE || 'enterprise-portal';\n const environment = process.env.DD_ENV || process.env.NODE_ENV || 'development';\n const version = process.env.DD_VERSION || process.env.NEXT_PUBLIC_VERSION || '0.0.0-dev';\n\n const agentHost = process.env.DD_AGENT_HOST || process.env.DATADOG_AGENT_HOST || '127.0.0.1';\n const agentPort = process.env.DD_TRACE_AGENT_PORT || '8126';\n\n process.env.DD_SERVICE = serviceName;\n process.env.DD_ENV = environment;\n if (version) {\n process.env.DD_VERSION = version;\n }\n process.env.DD_AGENT_HOST = agentHost;\n process.env.DD_TRACE_AGENT_PORT = agentPort;\n\n const dbmPropagationMode = (process.env.DD_DBM_PROPAGATION_MODE || 'full') as 'disabled' | 'service' | 'full';\n\n process.env.DD_DBM_PROPAGATION_MODE = dbmPropagationMode;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const ddTrace = require('dd-trace');\n tracer = (ddTrace.init as typeof ddTraceInit)({\n service: serviceName,\n env: environment,\n version,\n logInjection: true,\n runtimeMetrics: true,\n appsec: false,\n profiling: false,\n startupLogs: true, // Enable for debugging\n }) as Tracer;\n \n console.log(`[datadog] Tracer initialized: service=${serviceName}, env=${environment}, version=${version}, agent=${agentHost}:${agentPort}`);\n\n // Disable low-level network instrumentation for localhost connections\n tracer.use('dns', false);\n tracer.use('net', false);\n // Configure http plugin to normalize route patterns\n tracer.use('http', {\n server: {\n hooks: {\n request: (span?: Span, req?: IncomingMessage) => {\n if (!span) return;\n\n const url = req?.url || '';\n const method = req?.method || 'GET';\n const path = url.split('?')[0];\n\n // Drop Next.js internal requests\n if (path.startsWith('/_next/')) {\n // @ts-expect-error - using internal property to drop the trace\n span.context()._trace.isRecording = false;\n return;\n }\n\n const routePattern = getRoutePattern(path);\n\n span.setTag('resource.name', `${method} ${routePattern}`);\n span.setTag('http.route', routePattern);\n }\n }\n }\n });\n } catch (err) {\n // Do not crash the app if tracing fails to initialize\n console.error('[datadog] failed to initialize tracing', err);\n tracer = null;\n }\n}\n\n// Function to convert actual paths to route patterns\nconst getRoutePattern = (path: string): string => {\n // Define route patterns for dynamic routes in enterprise portal\n const routePatterns = [\n // Update instance routes - normalize dynamic segments (capture suffix to preserve sub-routes)\n { pattern: /^\\/update\\/instance\\/[^/]+(.*)$/, replacement: '/update/instance/[instanceId]$1' },\n ];\n\n for (const { pattern, replacement } of routePatterns) {\n if (pattern.test(path)) {\n return path.replace(pattern, replacement);\n }\n }\n\n // Return original path if no pattern matches\n return path;\n}\n\nexport default tracer;\n","import type { Span, Tracer } from 'dd-trace';\n\n// Type for a function that has been wrapped with tracing (always returns a Promise)\ntype TracedFunction<T extends (...args: any[]) => any> = (\n ...args: Parameters<T>\n) => Promise<Awaited<ReturnType<T>>>;\n\n// Lazy-load tracer only when tracing is enabled\n// Using undefined to distinguish between \"not loaded yet\" and \"loaded but null\"\nlet tracerCache: Tracer | null | undefined = undefined;\n\nfunction getTracer(): Tracer | null {\n // Return cached result if already loaded (prevents race conditions and multiple initializations)\n if (tracerCache !== undefined) {\n return tracerCache;\n }\n\n // Check if tracing is enabled at runtime (consistent with datadog/tracer.ts and instrumentation.ts)\n const rawFlag = String(process.env.USE_DATADOG_APM || '').toLowerCase();\n const isEnabled = rawFlag === 'true';\n\n if (!isEnabled) {\n tracerCache = null;\n return null;\n }\n\n // Lazy load the tracer module only when needed\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const tracerModule = require('../../../datadog/tracer');\n const tracer = tracerModule.default || tracerModule;\n\n if (tracer && typeof (tracer as any).trace === 'function') {\n tracerCache = tracer as Tracer;\n return tracerCache;\n }\n } catch (err) {\n console.warn('Failed to load tracer:', err);\n }\n\n tracerCache = null;\n return null;\n}\n\n/**\n * Get the currently active span from the tracer's scope.\n * This can be used to pass span context to database calls.\n */\nexport function getActiveSpan(): Span | undefined {\n const activeTracer = getTracer();\n if (!activeTracer || !activeTracer.scope) {\n return undefined;\n }\n const active = activeTracer.scope().active();\n return active || undefined;\n}\n\nexport async function withTrace<T>(\n name: string,\n fn: (span?: Span) => Promise<T> | T,\n): Promise<T> {\n const activeTracer = getTracer();\n if (!activeTracer) {\n return fn(undefined);\n }\n\n return activeTracer.trace(name, async (span?: Span) => {\n if (span) {\n span.setTag('component', 'application');\n }\n try {\n const result = await fn(span);\n return result;\n } catch (error) {\n if (span) {\n span.setTag('error', error as any);\n }\n throw error;\n }\n });\n}\n\nexport function traceServerAction<T extends (...args: any[]) => any>(\n name: string,\n fn: T,\n): TracedFunction<T> {\n const spanName = name.startsWith('server.action.') ? name : `server.action.${name}`;\n\n const traced: TracedFunction<T> = async (...args: Parameters<T>) => {\n return withTrace(spanName, async (span) => {\n if (span) {\n span.setTag('component', 'server-action');\n }\n const result = await fn(...args);\n return result;\n });\n };\n\n return traced;\n}\n\nexport function traceFunction<T extends (...args: any[]) => any>(\n name: string,\n fn: T,\n): TracedFunction<T> {\n const traced: TracedFunction<T> = async (...args: Parameters<T>) => {\n return withTrace(name, async () => {\n const result = await fn(...args);\n return result;\n });\n };\n\n return traced;\n}\n","import { cookies } from \"next/headers\";\nimport { redirect } from \"next/navigation\";\nimport { traceServerAction } from \"../utils/observability\";\n\nasync function logoutActionImpl(_formData: FormData): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(\"portal_session\");\n redirect(\"/\");\n}\n\n/**\n * Server action to log out the current user.\n * Deletes the portal_session cookie and redirects to home.\n */\nexport const logoutAction = traceServerAction(\"logoutAction\", logoutActionImpl);\n"]}
|
|
1
|
+
{"version":3,"sources":["../datadog/tracer.ts","../src/utils/observability/tracing.ts","../src/actions/logout.ts"],"names":["rawFlag","isEnabled","tracer","cookies"],"mappings":"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","file":"logout-action.js","sourcesContent":["import type { Tracer, Span, init as ddTraceInit } from 'dd-trace';\nimport type { IncomingMessage } from 'http';\n\nconst rawFlag = String(process.env.USE_DATADOG_APM || '').toLowerCase();\nconst isEnabled = rawFlag === 'true';\n\nprocess.env.DD_TRACE_ENABLED = isEnabled ? '1' : '0';\n\nlet tracer: Tracer | null = null;\n\nif (isEnabled) {\n const serviceName = process.env.DD_SERVICE || 'enterprise-portal';\n const environment = process.env.DD_ENV || process.env.NODE_ENV || 'development';\n const version = process.env.DD_VERSION || process.env.NEXT_PUBLIC_VERSION || '0.0.0-dev';\n\n const agentHost = process.env.DD_AGENT_HOST || process.env.DATADOG_AGENT_HOST || '127.0.0.1';\n const agentPort = process.env.DD_TRACE_AGENT_PORT || '8126';\n\n process.env.DD_SERVICE = serviceName;\n process.env.DD_ENV = environment;\n if (version) {\n process.env.DD_VERSION = version;\n }\n process.env.DD_AGENT_HOST = agentHost;\n process.env.DD_TRACE_AGENT_PORT = agentPort;\n\n const dbmPropagationMode = (process.env.DD_DBM_PROPAGATION_MODE || 'full') as 'disabled' | 'service' | 'full';\n\n process.env.DD_DBM_PROPAGATION_MODE = dbmPropagationMode;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const ddTrace = require('dd-trace');\n tracer = (ddTrace.init as typeof ddTraceInit)({\n service: serviceName,\n env: environment,\n version,\n logInjection: true,\n runtimeMetrics: true,\n appsec: false,\n profiling: false,\n startupLogs: true, // Enable for debugging\n }) as Tracer;\n \n console.log(`[datadog] Tracer initialized: service=${serviceName}, env=${environment}, version=${version}, agent=${agentHost}:${agentPort}`);\n\n // Disable low-level network instrumentation for localhost connections\n tracer.use('dns', false);\n tracer.use('net', false);\n // Configure http plugin to normalize route patterns\n tracer.use('http', {\n server: {\n hooks: {\n request: (span?: Span, req?: IncomingMessage) => {\n if (!span) return;\n\n const url = req?.url || '';\n const method = req?.method || 'GET';\n const path = url.split('?')[0];\n\n // Drop Next.js internal requests\n if (path.startsWith('/_next/')) {\n // @ts-expect-error - using internal property to drop the trace\n span.context()._trace.isRecording = false;\n return;\n }\n\n const routePattern = getRoutePattern(path);\n\n span.setTag('resource.name', `${method} ${routePattern}`);\n span.setTag('http.route', routePattern);\n }\n }\n }\n });\n } catch (err) {\n // Do not crash the app if tracing fails to initialize\n console.error('[datadog] failed to initialize tracing', err);\n tracer = null;\n }\n}\n\n// Function to convert actual paths to route patterns\nconst getRoutePattern = (path: string): string => {\n // Define route patterns for dynamic routes in enterprise portal\n const routePatterns = [\n // Update instance routes - normalize dynamic segments (capture suffix to preserve sub-routes)\n { pattern: /^\\/update\\/instance\\/[^/]+(.*)$/, replacement: '/update/instance/[instanceId]$1' },\n ];\n\n for (const { pattern, replacement } of routePatterns) {\n if (pattern.test(path)) {\n return path.replace(pattern, replacement);\n }\n }\n\n // Return original path if no pattern matches\n return path;\n}\n\nexport default tracer;\n","import type { Span, Tracer } from 'dd-trace';\n\n// Type for a function that has been wrapped with tracing (always returns a Promise)\ntype TracedFunction<T extends (...args: any[]) => any> = (\n ...args: Parameters<T>\n) => Promise<Awaited<ReturnType<T>>>;\n\n// Lazy-load tracer only when tracing is enabled\n// Using undefined to distinguish between \"not loaded yet\" and \"loaded but null\"\nlet tracerCache: Tracer | null | undefined = undefined;\n\nfunction getTracer(): Tracer | null {\n // Return cached result if already loaded (prevents race conditions and multiple initializations)\n if (tracerCache !== undefined) {\n return tracerCache;\n }\n\n // Check if tracing is enabled at runtime (consistent with datadog/tracer.ts and instrumentation.ts)\n const rawFlag = String(process.env.USE_DATADOG_APM || '').toLowerCase();\n const isEnabled = rawFlag === 'true';\n\n if (!isEnabled) {\n tracerCache = null;\n return null;\n }\n\n // Lazy load the tracer module only when needed\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const tracerModule = require('../../../datadog/tracer');\n const tracer = tracerModule.default || tracerModule;\n\n if (tracer && typeof (tracer as any).trace === 'function') {\n tracerCache = tracer as Tracer;\n return tracerCache;\n }\n } catch (err) {\n console.warn('Failed to load tracer:', err);\n }\n\n tracerCache = null;\n return null;\n}\n\n/**\n * Get the currently active span from the tracer's scope.\n * This can be used to pass span context to database calls.\n */\nexport function getActiveSpan(): Span | undefined {\n const activeTracer = getTracer();\n if (!activeTracer || !activeTracer.scope) {\n return undefined;\n }\n const active = activeTracer.scope().active();\n return active || undefined;\n}\n\nexport async function withTrace<T>(\n name: string,\n fn: (span?: Span) => Promise<T> | T,\n): Promise<T> {\n const activeTracer = getTracer();\n if (!activeTracer) {\n return fn(undefined);\n }\n\n return activeTracer.trace(name, async (span?: Span) => {\n if (span) {\n span.setTag('component', 'application');\n }\n try {\n const result = await fn(span);\n return result;\n } catch (error) {\n if (span) {\n span.setTag('error', error as any);\n }\n throw error;\n }\n });\n}\n\nexport function traceServerAction<T extends (...args: any[]) => any>(\n name: string,\n fn: T,\n): TracedFunction<T> {\n const spanName = name.startsWith('server.action.') ? name : `server.action.${name}`;\n\n const traced: TracedFunction<T> = async (...args: Parameters<T>) => {\n return withTrace(spanName, async (span) => {\n if (span) {\n span.setTag('component', 'server-action');\n }\n const result = await fn(...args);\n return result;\n });\n };\n\n return traced;\n}\n\nexport function traceFunction<T extends (...args: any[]) => any>(\n name: string,\n fn: T,\n): TracedFunction<T> {\n const traced: TracedFunction<T> = async (...args: Parameters<T>) => {\n return withTrace(name, async () => {\n const result = await fn(...args);\n return result;\n });\n };\n\n return traced;\n}\n","import { cookies } from \"next/headers\";\nimport { traceServerAction } from \"../utils/observability\";\n\nasync function logoutActionImpl(): Promise<{ success: boolean }> {\n const cookieStore = await cookies();\n cookieStore.delete(\"portal_session\");\n return { success: true };\n}\n\n/**\n * Server action to log out the current user.\n * Deletes the portal_session cookie and returns success.\n * The client is responsible for redirecting after logout.\n */\nexport const logoutAction = traceServerAction(\"logoutAction\", logoutActionImpl);\n"]}
|
package/dist/logout-button.d.mts
CHANGED
|
@@ -5,11 +5,14 @@ interface LogoutButtonProps {
|
|
|
5
5
|
* Action ID for the logout server action.
|
|
6
6
|
* This should be bound on the server side before passing to this component.
|
|
7
7
|
*/
|
|
8
|
-
action: (
|
|
8
|
+
action: () => Promise<{
|
|
9
|
+
success: boolean;
|
|
10
|
+
}>;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* Logout button for user menu dropdown.
|
|
12
14
|
* Uses red styling to indicate a destructive action.
|
|
15
|
+
* Redirects to login page after successful logout.
|
|
13
16
|
*/
|
|
14
17
|
declare function LogoutButton({ action }: LogoutButtonProps): react_jsx_runtime.JSX.Element;
|
|
15
18
|
|
package/dist/logout-button.d.ts
CHANGED
|
@@ -5,11 +5,14 @@ interface LogoutButtonProps {
|
|
|
5
5
|
* Action ID for the logout server action.
|
|
6
6
|
* This should be bound on the server side before passing to this component.
|
|
7
7
|
*/
|
|
8
|
-
action: (
|
|
8
|
+
action: () => Promise<{
|
|
9
|
+
success: boolean;
|
|
10
|
+
}>;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* Logout button for user menu dropdown.
|
|
12
14
|
* Uses red styling to indicate a destructive action.
|
|
15
|
+
* Redirects to login page after successful logout.
|
|
13
16
|
*/
|
|
14
17
|
declare function LogoutButton({ action }: LogoutButtonProps): react_jsx_runtime.JSX.Element;
|
|
15
18
|
|
package/dist/logout-button.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var navigation = require('next/navigation');
|
|
5
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -11,22 +12,24 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
11
12
|
|
|
12
13
|
function LogoutButton({ action }) {
|
|
13
14
|
const [isPending, startTransition] = react.useTransition();
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const formData = new FormData(event.currentTarget);
|
|
15
|
+
const router = navigation.useRouter();
|
|
16
|
+
const handleClick = () => {
|
|
17
17
|
startTransition(async () => {
|
|
18
|
-
await action(
|
|
18
|
+
const result = await action();
|
|
19
|
+
if (result.success) {
|
|
20
|
+
router.push("/");
|
|
21
|
+
}
|
|
19
22
|
});
|
|
20
23
|
};
|
|
21
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
24
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
22
25
|
"button",
|
|
23
26
|
{
|
|
24
|
-
|
|
27
|
+
onClick: handleClick,
|
|
25
28
|
disabled: isPending,
|
|
26
29
|
className: "block w-full px-4 py-2.5 text-sm text-left text-red-600 hover:bg-red-50 transition-colors disabled:opacity-50",
|
|
27
30
|
children: isPending ? "Logging out..." : "Logout"
|
|
28
31
|
}
|
|
29
|
-
)
|
|
32
|
+
);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
exports.LogoutButton = LogoutButton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/logout-button.tsx"],"names":["useTransition","jsx"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/components/logout-button.tsx"],"names":["useTransition","useRouter","jsx"],"mappings":";;;;;;;;;;;AAkBO,SAAS,YAAA,CAAa,EAAE,MAAA,EAAO,EAAsB;AAC1D,EAAA,MAAM,CAAC,SAAA,EAAW,eAAe,CAAA,GAAIA,mBAAA,EAAc;AACnD,EAAA,MAAM,SAASC,oBAAA,EAAU;AAEzB,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,eAAA,CAAgB,YAAY;AAC1B,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,EAAO;AAC5B,MAAA,IAAI,OAAO,OAAA,EAAS;AAClB,QAAA,MAAA,CAAO,KAAK,GAAG,CAAA;AAAA,MACjB;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,uBACEC,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAS,WAAA;AAAA,MACT,QAAA,EAAU,SAAA;AAAA,MACV,SAAA,EAAU,+GAAA;AAAA,MAET,sBAAY,gBAAA,GAAmB;AAAA;AAAA,GAClC;AAEJ","file":"logout-button.js","sourcesContent":["\"use client\";\n\nimport { useTransition } from \"react\";\nimport { useRouter } from \"next/navigation\";\n\nexport interface LogoutButtonProps {\n /** \n * Action ID for the logout server action.\n * This should be bound on the server side before passing to this component.\n */\n action: () => Promise<{ success: boolean }>;\n}\n\n/**\n * Logout button for user menu dropdown.\n * Uses red styling to indicate a destructive action.\n * Redirects to login page after successful logout.\n */\nexport function LogoutButton({ action }: LogoutButtonProps) {\n const [isPending, startTransition] = useTransition();\n const router = useRouter();\n\n const handleClick = () => {\n startTransition(async () => {\n const result = await action();\n if (result.success) {\n router.push(\"/\");\n }\n });\n };\n\n return (\n <button\n onClick={handleClick}\n disabled={isPending}\n className=\"block w-full px-4 py-2.5 text-sm text-left text-red-600 hover:bg-red-50 transition-colors disabled:opacity-50\"\n >\n {isPending ? \"Logging out...\" : \"Logout\"}\n </button>\n );\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type VerifyState = {
|
|
2
|
+
status: "verifying";
|
|
3
|
+
} | {
|
|
4
|
+
status: "success";
|
|
5
|
+
message: string;
|
|
6
|
+
} | {
|
|
7
|
+
status: "expired";
|
|
8
|
+
message: string;
|
|
9
|
+
} | {
|
|
10
|
+
status: "error";
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
interface VerifyActionResult {
|
|
14
|
+
success: boolean;
|
|
15
|
+
message?: string;
|
|
16
|
+
isExpired?: boolean;
|
|
17
|
+
}
|
|
18
|
+
type VerifyAction = (code: string) => Promise<VerifyActionResult>;
|
|
19
|
+
interface UseVerifyMagicLinkOptions {
|
|
20
|
+
verifyAction: VerifyAction;
|
|
21
|
+
onSuccess?: () => void;
|
|
22
|
+
redirectUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Shared hook for magic link and trial signup verification.
|
|
26
|
+
* Extracts the code from URL hash, calls the verification action,
|
|
27
|
+
* handles all error states, and redirects on success.
|
|
28
|
+
*
|
|
29
|
+
* Note: The verifyAction should be selected based on the verification type
|
|
30
|
+
* (regular magic link vs trial signup) before calling this hook.
|
|
31
|
+
*/
|
|
32
|
+
declare function useVerifyMagicLink({ verifyAction, onSuccess, redirectUrl }: UseVerifyMagicLinkOptions): VerifyState;
|
|
33
|
+
|
|
34
|
+
export { type UseVerifyMagicLinkOptions, type VerifyAction, type VerifyActionResult, type VerifyState, useVerifyMagicLink };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type VerifyState = {
|
|
2
|
+
status: "verifying";
|
|
3
|
+
} | {
|
|
4
|
+
status: "success";
|
|
5
|
+
message: string;
|
|
6
|
+
} | {
|
|
7
|
+
status: "expired";
|
|
8
|
+
message: string;
|
|
9
|
+
} | {
|
|
10
|
+
status: "error";
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
interface VerifyActionResult {
|
|
14
|
+
success: boolean;
|
|
15
|
+
message?: string;
|
|
16
|
+
isExpired?: boolean;
|
|
17
|
+
}
|
|
18
|
+
type VerifyAction = (code: string) => Promise<VerifyActionResult>;
|
|
19
|
+
interface UseVerifyMagicLinkOptions {
|
|
20
|
+
verifyAction: VerifyAction;
|
|
21
|
+
onSuccess?: () => void;
|
|
22
|
+
redirectUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Shared hook for magic link and trial signup verification.
|
|
26
|
+
* Extracts the code from URL hash, calls the verification action,
|
|
27
|
+
* handles all error states, and redirects on success.
|
|
28
|
+
*
|
|
29
|
+
* Note: The verifyAction should be selected based on the verification type
|
|
30
|
+
* (regular magic link vs trial signup) before calling this hook.
|
|
31
|
+
*/
|
|
32
|
+
declare function useVerifyMagicLink({ verifyAction, onSuccess, redirectUrl }: UseVerifyMagicLinkOptions): VerifyState;
|
|
33
|
+
|
|
34
|
+
export { type UseVerifyMagicLinkOptions, type VerifyAction, type VerifyActionResult, type VerifyState, useVerifyMagicLink };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var navigation = require('next/navigation');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Enterprise Portal Components
|
|
9
|
+
* This file is generated by tsup. Do not edit manually.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
function useVerifyMagicLink({
|
|
13
|
+
verifyAction,
|
|
14
|
+
onSuccess,
|
|
15
|
+
redirectUrl = "/"
|
|
16
|
+
}) {
|
|
17
|
+
const router = navigation.useRouter();
|
|
18
|
+
const [state, setState] = react.useState({ status: "verifying" });
|
|
19
|
+
const verifyingRef = react.useRef(false);
|
|
20
|
+
react.useEffect(() => {
|
|
21
|
+
if (typeof window === "undefined") return;
|
|
22
|
+
const hash = window.location.hash;
|
|
23
|
+
if (!hash || hash.length <= 1) {
|
|
24
|
+
setState({
|
|
25
|
+
status: "error",
|
|
26
|
+
message: "No verification code found. Please use the link from your email."
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const code = hash.substring(1).split("/")[0]?.trim() || "";
|
|
31
|
+
if (!code) {
|
|
32
|
+
setState({
|
|
33
|
+
status: "error",
|
|
34
|
+
message: "Invalid verification code. Please use the link from your email."
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (verifyingRef.current) return;
|
|
39
|
+
verifyingRef.current = true;
|
|
40
|
+
verifyAction(code).then((result) => {
|
|
41
|
+
if (result.success) {
|
|
42
|
+
setState({
|
|
43
|
+
status: "success",
|
|
44
|
+
message: "Verified! Redirecting to the portal..."
|
|
45
|
+
});
|
|
46
|
+
if (onSuccess) {
|
|
47
|
+
onSuccess();
|
|
48
|
+
}
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
router.push(redirectUrl);
|
|
51
|
+
}, 1500);
|
|
52
|
+
} else if (result.isExpired) {
|
|
53
|
+
setState({
|
|
54
|
+
status: "expired",
|
|
55
|
+
message: result.message || "Magic link has expired. A new link has been sent to your email."
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
setState({
|
|
59
|
+
status: "error",
|
|
60
|
+
message: result.message || "Failed to verify. Please try again."
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}).catch((err) => {
|
|
64
|
+
console.error("[use-verify-magic-link] Unexpected error:", err);
|
|
65
|
+
setState({
|
|
66
|
+
status: "error",
|
|
67
|
+
message: "An unexpected error occurred. Please try again."
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}, [verifyAction, router, redirectUrl, onSuccess]);
|
|
71
|
+
return state;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
exports.useVerifyMagicLink = useVerifyMagicLink;
|
|
75
|
+
//# sourceMappingURL=use-verify-magic-link.js.map
|
|
76
|
+
//# sourceMappingURL=use-verify-magic-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/use-verify-magic-link.ts"],"names":["useRouter","useState","useRef","useEffect"],"mappings":";;;;;;;;;;AAiCO,SAAS,kBAAA,CAAmB;AAAA,EACjC,YAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA,GAAc;AAChB,CAAA,EAA8B;AAC5B,EAAA,MAAM,SAASA,oBAAA,EAAU;AACzB,EAAA,MAAM,CAAC,OAAO,QAAQ,CAAA,GAAIC,eAAsB,EAAE,MAAA,EAAQ,aAAa,CAAA;AACvE,EAAA,MAAM,YAAA,GAAeC,aAAO,KAAK,CAAA;AAEjC,EAAAC,eAAA,CAAU,MAAM;AAEd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAEnC,IAAA,MAAM,IAAA,GAAO,OAAO,QAAA,CAAS,IAAA;AAE7B,IAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,MAAA,IAAU,CAAA,EAAG;AAC7B,MAAA,QAAA,CAAS;AAAA,QACP,MAAA,EAAQ,OAAA;AAAA,QACR,OAAA,EAAS;AAAA,OACV,CAAA;AACD,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAG,IAAA,EAAK,IAAK,EAAA;AAExD,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,QAAA,CAAS;AAAA,QACP,MAAA,EAAQ,OAAA;AAAA,QACR,OAAA,EAAS;AAAA,OACV,CAAA;AACD,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,aAAa,OAAA,EAAS;AAC1B,IAAA,YAAA,CAAa,OAAA,GAAU,IAAA;AAGvB,IAAA,YAAA,CAAa,IAAI,CAAA,CACd,IAAA,CAAK,CAAC,MAAA,KAAW;AAChB,MAAA,IAAI,OAAO,OAAA,EAAS;AAClB,QAAA,QAAA,CAAS;AAAA,UACP,MAAA,EAAQ,SAAA;AAAA,UACR,OAAA,EAAS;AAAA,SACV,CAAA;AAGD,QAAA,IAAI,SAAA,EAAW;AACb,UAAA,SAAA,EAAU;AAAA,QACZ;AAGA,QAAA,UAAA,CAAW,MAAM;AACf,UAAA,MAAA,CAAO,KAAK,WAAW,CAAA;AAAA,QACzB,GAAG,IAAI,CAAA;AAAA,MACT,CAAA,MAAA,IAAW,OAAO,SAAA,EAAW;AAC3B,QAAA,QAAA,CAAS;AAAA,UACP,MAAA,EAAQ,SAAA;AAAA,UACR,OAAA,EAAS,OAAO,OAAA,IAAW;AAAA,SAC5B,CAAA;AAAA,MACH,CAAA,MAAO;AACL,QAAA,QAAA,CAAS;AAAA,UACP,MAAA,EAAQ,OAAA;AAAA,UACR,OAAA,EAAS,OAAO,OAAA,IAAW;AAAA,SAC5B,CAAA;AAAA,MACH;AAAA,IACF,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAQ;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,6CAA6C,GAAG,CAAA;AAC9D,MAAA,QAAA,CAAS;AAAA,QACP,MAAA,EAAQ,OAAA;AAAA,QACR,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACL,GAAG,CAAC,YAAA,EAAc,MAAA,EAAQ,WAAA,EAAa,SAAS,CAAC,CAAA;AAEjD,EAAA,OAAO,KAAA;AACT","file":"use-verify-magic-link.js","sourcesContent":["\"use client\";\n\nimport { useEffect, useState, useRef } from \"react\";\nimport { useRouter } from \"next/navigation\";\n\nexport type VerifyState = \n | { status: \"verifying\" }\n | { status: \"success\"; message: string }\n | { status: \"expired\"; message: string }\n | { status: \"error\"; message: string };\n\nexport interface VerifyActionResult {\n success: boolean;\n message?: string;\n isExpired?: boolean;\n}\n\nexport type VerifyAction = (code: string) => Promise<VerifyActionResult>;\n\nexport interface UseVerifyMagicLinkOptions {\n verifyAction: VerifyAction;\n onSuccess?: () => void;\n redirectUrl?: string;\n}\n\n/**\n * Shared hook for magic link and trial signup verification.\n * Extracts the code from URL hash, calls the verification action,\n * handles all error states, and redirects on success.\n * \n * Note: The verifyAction should be selected based on the verification type\n * (regular magic link vs trial signup) before calling this hook.\n */\nexport function useVerifyMagicLink({\n verifyAction,\n onSuccess,\n redirectUrl = \"/\"\n}: UseVerifyMagicLinkOptions) {\n const router = useRouter();\n const [state, setState] = useState<VerifyState>({ status: \"verifying\" });\n const verifyingRef = useRef(false);\n\n useEffect(() => {\n // Extract code from URL hash\n if (typeof window === \"undefined\") return;\n\n const hash = window.location.hash;\n \n if (!hash || hash.length <= 1) {\n setState({ \n status: \"error\", \n message: \"No verification code found. Please use the link from your email.\" \n });\n return;\n }\n\n // Remove the # and any trailing path segments, trim whitespace\n const code = hash.substring(1).split(\"/\")[0]?.trim() || \"\";\n \n if (!code) {\n setState({ \n status: \"error\", \n message: \"Invalid verification code. Please use the link from your email.\" \n });\n return;\n }\n\n // Prevent duplicate verification attempts\n if (verifyingRef.current) return;\n verifyingRef.current = true;\n\n // Auto-verify on mount\n verifyAction(code)\n .then((result) => {\n if (result.success) {\n setState({ \n status: \"success\", \n message: \"Verified! Redirecting to the portal...\" \n });\n \n // Call success callback if provided\n if (onSuccess) {\n onSuccess();\n }\n \n // Redirect to dashboard after a short delay\n setTimeout(() => {\n router.push(redirectUrl);\n }, 1500);\n } else if (result.isExpired) {\n setState({ \n status: \"expired\", \n message: result.message || \"Magic link has expired. A new link has been sent to your email.\" \n });\n } else {\n setState({ \n status: \"error\", \n message: result.message || \"Failed to verify. Please try again.\" \n });\n }\n })\n .catch((err) => {\n console.error(\"[use-verify-magic-link] Unexpected error:\", err);\n setState({ \n status: \"error\", \n message: \"An unexpected error occurred. Please try again.\" \n });\n });\n }, [verifyAction, router, redirectUrl, onSuccess]);\n\n return state;\n}\n"]}
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -45,21 +45,6 @@ declare function authenticatedFetch(url: string, options?: ApiFetchOptions): Pro
|
|
|
45
45
|
* the session cookie before rendering authenticated content.
|
|
46
46
|
*/
|
|
47
47
|
declare function validateSession(token: string): Promise<boolean>;
|
|
48
|
-
/**
|
|
49
|
-
* Deletes the portal_session cookie.
|
|
50
|
-
* This MUST be called from a Server Action or Route Handler, not from Server Component render.
|
|
51
|
-
*
|
|
52
|
-
* Usage example in a Server Action:
|
|
53
|
-
* ```typescript
|
|
54
|
-
* "use server";
|
|
55
|
-
* import { deleteSessionCookie } from "@replicated/portal-components/utils";
|
|
56
|
-
* export async function logout() {
|
|
57
|
-
* await deleteSessionCookie();
|
|
58
|
-
* redirect("/");
|
|
59
|
-
* }
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
declare function deleteSessionCookie(): Promise<void>;
|
|
63
48
|
|
|
64
49
|
/**
|
|
65
50
|
* Format bytes to human-readable string
|
|
@@ -126,4 +111,4 @@ declare const DEFAULT_SECONDARY_COLOR = "#6366f1";
|
|
|
126
111
|
*/
|
|
127
112
|
declare const isHttpApiOrigin: () => boolean;
|
|
128
113
|
|
|
129
|
-
export { type ConvertToReleaseEntryOptions, DEFAULT_FAVICON, DEFAULT_PRIMARY_COLOR, DEFAULT_SECONDARY_COLOR, type ReleaseNotesMode, UnauthorizedError, authenticatedFetch, convertToReleaseEntry,
|
|
114
|
+
export { type ConvertToReleaseEntryOptions, DEFAULT_FAVICON, DEFAULT_PRIMARY_COLOR, DEFAULT_SECONDARY_COLOR, type ReleaseNotesMode, UnauthorizedError, authenticatedFetch, convertToReleaseEntry, formatBytes, formatDate, formatDateShort, formatDateTime, formatDateTimeLocal, isHttpApiOrigin, isRedirectError, validateSession };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -45,21 +45,6 @@ declare function authenticatedFetch(url: string, options?: ApiFetchOptions): Pro
|
|
|
45
45
|
* the session cookie before rendering authenticated content.
|
|
46
46
|
*/
|
|
47
47
|
declare function validateSession(token: string): Promise<boolean>;
|
|
48
|
-
/**
|
|
49
|
-
* Deletes the portal_session cookie.
|
|
50
|
-
* This MUST be called from a Server Action or Route Handler, not from Server Component render.
|
|
51
|
-
*
|
|
52
|
-
* Usage example in a Server Action:
|
|
53
|
-
* ```typescript
|
|
54
|
-
* "use server";
|
|
55
|
-
* import { deleteSessionCookie } from "@replicated/portal-components/utils";
|
|
56
|
-
* export async function logout() {
|
|
57
|
-
* await deleteSessionCookie();
|
|
58
|
-
* redirect("/");
|
|
59
|
-
* }
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
declare function deleteSessionCookie(): Promise<void>;
|
|
63
48
|
|
|
64
49
|
/**
|
|
65
50
|
* Format bytes to human-readable string
|
|
@@ -126,4 +111,4 @@ declare const DEFAULT_SECONDARY_COLOR = "#6366f1";
|
|
|
126
111
|
*/
|
|
127
112
|
declare const isHttpApiOrigin: () => boolean;
|
|
128
113
|
|
|
129
|
-
export { type ConvertToReleaseEntryOptions, DEFAULT_FAVICON, DEFAULT_PRIMARY_COLOR, DEFAULT_SECONDARY_COLOR, type ReleaseNotesMode, UnauthorizedError, authenticatedFetch, convertToReleaseEntry,
|
|
114
|
+
export { type ConvertToReleaseEntryOptions, DEFAULT_FAVICON, DEFAULT_PRIMARY_COLOR, DEFAULT_SECONDARY_COLOR, type ReleaseNotesMode, UnauthorizedError, authenticatedFetch, convertToReleaseEntry, formatBytes, formatDate, formatDateShort, formatDateTime, formatDateTimeLocal, isHttpApiOrigin, isRedirectError, validateSession };
|
package/dist/utils/index.js
CHANGED
|
@@ -288,11 +288,6 @@ async function validateSession(token) {
|
|
|
288
288
|
}
|
|
289
289
|
return true;
|
|
290
290
|
}
|
|
291
|
-
async function deleteSessionCookie() {
|
|
292
|
-
const { cookies } = await import('next/headers');
|
|
293
|
-
const cookieStore = await cookies();
|
|
294
|
-
cookieStore.delete("portal_session");
|
|
295
|
-
}
|
|
296
291
|
|
|
297
292
|
// src/utils/format.ts
|
|
298
293
|
function formatBytes(bytes, decimals = 1) {
|
|
@@ -407,7 +402,6 @@ exports.UnauthorizedError = UnauthorizedError;
|
|
|
407
402
|
exports.authenticatedFetch = authenticatedFetch;
|
|
408
403
|
exports.convertToReleaseEntry = convertToReleaseEntry;
|
|
409
404
|
exports.decodeBranding = decodeBranding;
|
|
410
|
-
exports.deleteSessionCookie = deleteSessionCookie;
|
|
411
405
|
exports.formatBytes = formatBytes;
|
|
412
406
|
exports.formatDate = formatDate;
|
|
413
407
|
exports.formatDateShort = formatDateShort;
|