@replicated/portal-components 0.0.24 → 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.
@@ -174,7 +174,7 @@ function traceServerAction(name, fn) {
174
174
  }
175
175
 
176
176
  // src/actions/logout.ts
177
- async function logoutActionImpl(_formData) {
177
+ async function logoutActionImpl() {
178
178
  const cookieStore = await cookies();
179
179
  cookieStore.delete("portal_session");
180
180
  return { success: true };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../datadog/tracer.ts","../../src/utils/observability/tracing.ts","../../src/actions/logout.ts"],"names":["rawFlag","isEnabled","tracer"],"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(_formData: FormData): 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"]}
1
+ {"version":3,"sources":["../../datadog/tracer.ts","../../src/utils/observability/tracing.ts","../../src/actions/logout.ts"],"names":["rawFlag","isEnabled","tracer"],"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"]}
@@ -11,25 +11,23 @@ import { jsx } from 'react/jsx-runtime';
11
11
  function LogoutButton({ action }) {
12
12
  const [isPending, startTransition] = useTransition();
13
13
  const router = useRouter();
14
- const handleSubmit = (event) => {
15
- event.preventDefault();
16
- const formData = new FormData(event.currentTarget);
14
+ const handleClick = () => {
17
15
  startTransition(async () => {
18
- const result = await action(formData);
16
+ const result = await action();
19
17
  if (result.success) {
20
18
  router.push("/");
21
19
  }
22
20
  });
23
21
  };
24
- return /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsx(
22
+ return /* @__PURE__ */ jsx(
25
23
  "button",
26
24
  {
27
- type: "submit",
25
+ onClick: handleClick,
28
26
  disabled: isPending,
29
27
  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",
30
28
  children: isPending ? "Logging out..." : "Logout"
31
29
  }
32
- ) });
30
+ );
33
31
  }
34
32
 
35
33
  export { LogoutButton };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/logout-button.tsx"],"names":[],"mappings":";;;;;;;;;AAkBO,SAAS,YAAA,CAAa,EAAE,MAAA,EAAO,EAAsB;AAC1D,EAAA,MAAM,CAAC,SAAA,EAAW,eAAe,CAAA,GAAI,aAAA,EAAc;AACnD,EAAA,MAAM,SAAS,SAAA,EAAU;AAEzB,EAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAA4C;AAChE,IAAA,KAAA,CAAM,cAAA,EAAe;AACrB,IAAA,MAAM,QAAA,GAAW,IAAI,QAAA,CAAS,KAAA,CAAM,aAAa,CAAA;AACjD,IAAA,eAAA,CAAgB,YAAY;AAC1B,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,QAAQ,CAAA;AACpC,MAAA,IAAI,OAAO,OAAA,EAAS;AAClB,QAAA,MAAA,CAAO,KAAK,GAAG,CAAA;AAAA,MACjB;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,uBACE,GAAA,CAAC,MAAA,EAAA,EAAK,QAAA,EAAU,YAAA,EACd,QAAA,kBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,QAAA,EAAU,SAAA;AAAA,MACV,SAAA,EAAU,+GAAA;AAAA,MAET,sBAAY,gBAAA,GAAmB;AAAA;AAAA,GAClC,EACF,CAAA;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: (formData: FormData) => 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 handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n const formData = new FormData(event.currentTarget);\n startTransition(async () => {\n const result = await action(formData);\n if (result.success) {\n router.push(\"/\");\n }\n });\n };\n\n return (\n <form onSubmit={handleSubmit}>\n <button\n type=\"submit\"\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 </form>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/components/logout-button.tsx"],"names":[],"mappings":";;;;;;;;;AAkBO,SAAS,YAAA,CAAa,EAAE,MAAA,EAAO,EAAsB;AAC1D,EAAA,MAAM,CAAC,SAAA,EAAW,eAAe,CAAA,GAAI,aAAA,EAAc;AACnD,EAAA,MAAM,SAAS,SAAA,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,uBACE,GAAA;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"]}
@@ -286,11 +286,6 @@ async function validateSession(token) {
286
286
  }
287
287
  return true;
288
288
  }
289
- async function deleteSessionCookie() {
290
- const { cookies } = await import('next/headers');
291
- const cookieStore = await cookies();
292
- cookieStore.delete("portal_session");
293
- }
294
289
 
295
290
  // src/utils/format.ts
296
291
  function formatBytes(bytes, decimals = 1) {
@@ -398,6 +393,6 @@ function convertToReleaseEntry(release, channelName, options) {
398
393
  };
399
394
  }
400
395
 
401
- export { DEFAULT_FAVICON, DEFAULT_PRIMARY_COLOR, DEFAULT_SECONDARY_COLOR, UnauthorizedError, authenticatedFetch, convertToReleaseEntry, decodeBranding, deleteSessionCookie, formatBytes, formatDate, formatDateShort, formatDateTime, formatDateTimeLocal, isHttpApiOrigin, isRedirectError, normalizeColor, sanitizeUrlForCss, validateSession };
396
+ export { DEFAULT_FAVICON, DEFAULT_PRIMARY_COLOR, DEFAULT_SECONDARY_COLOR, UnauthorizedError, authenticatedFetch, convertToReleaseEntry, decodeBranding, formatBytes, formatDate, formatDateShort, formatDateTime, formatDateTimeLocal, isHttpApiOrigin, isRedirectError, normalizeColor, sanitizeUrlForCss, validateSession };
402
397
  //# sourceMappingURL=index.js.map
403
398
  //# sourceMappingURL=index.js.map