@guidelytech/nextjs 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/dist/index.cjs +32 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.js +29 -5
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +209 -6
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +122 -1
- package/dist/server.d.ts +122 -1
- package/dist/server.js +200 -5
- package/dist/server.js.map +1 -1
- package/package.json +4 -4
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * `@guidelytech/nextjs/server` — feature flags on the server: React Server Components, route\n * handlers, server actions, middleware and edge functions. No React and no `\"use client\"` here.\n *\n * ```ts\n * import { getFlags, getFlagsBootstrap } from \"@guidelytech/nextjs/server\";\n * const flags = await getFlags({ id: user.id, plan: user.plan });\n * if (flags.isEnabled(\"new-dashboard-banner\")) …\n * ```\n */\nimport { createFlagsClient, type Attributes, type FlagsBootstrap, type FlagsClient, type FlagsClientOptions, type FlagsEvaluator } from \"@guidelytech/flags\";\n\nexport type { Attributes, FlagsBootstrap, FlagsClient, FlagsClientOptions, FlagsEvaluator, FlagDetails, JsonValue } from \"@guidelytech/flags\";\n\ninterface Registry {\n clients: Map<string, FlagsClient>;\n current: FlagsClient | null;\n warned: Set<string>;\n}\n\n/** Kept on `globalThis` so dev-server hot reloads reuse the client (and its timers) instead of leaking new ones. */\nfunction registry(): Registry {\n const g = globalThis as { __guidelyServerFlags?: Registry };\n return (g.__guidelyServerFlags ??= { clients: new Map(), current: null, warned: new Set() });\n}\n\nfunction env(name: string): string | undefined {\n try {\n return (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.[name] || undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Flag downloads must always reach Guidely and outlive the request that started them: use the\n * fetch Next.js wrapped (no data cache, no request scope), else ask for `no-store`.\n */\nconst noStoreFetch: typeof fetch = (input, init) => {\n const original = (globalThis.fetch as typeof fetch & { _nextOriginalFetch?: typeof fetch })._nextOriginalFetch;\n return original ? original(input, init) : fetch(input, { ...init, cache: \"no-store\" });\n};\n\n/**\n * The process-wide flags client (created once, then reused across requests and hot reloads).\n * Options default to `GUIDELY_SDK_KEY` (a public `pk_…` or secret `gly_sk_…` key), falling back to\n * `NEXT_PUBLIC_GUIDELY_PROJECT_ID`, plus `GUIDELY_API_URL` / `NEXT_PUBLIC_GUIDELY_API_URL` and\n * `GUIDELY_ENV` / `NEXT_PUBLIC_GUIDELY_ENV`. Polls every 60 s by default; in middleware and\n * edge functions use `{ pollingMode: \"lazy\" }` (refreshes on read once the cache is stale).\n */\nexport function createServerFlags(options: Partial<FlagsClientOptions> = {}): FlagsClient {\n const sdkKey = options.sdkKey ?? options.projectId ?? env(\"GUIDELY_SDK_KEY\") ?? env(\"NEXT_PUBLIC_GUIDELY_PROJECT_ID\");\n if (!sdkKey) throw new Error(\"[Guidely] createServerFlags: pass `sdkKey` or set GUIDELY_SDK_KEY / NEXT_PUBLIC_GUIDELY_PROJECT_ID.\");\n const apiUrl = options.apiUrl ?? env(\"GUIDELY_API_URL\") ?? env(\"NEXT_PUBLIC_GUIDELY_API_URL\");\n const environment = options.environment ?? env(\"GUIDELY_ENV\") ?? env(\"NEXT_PUBLIC_GUIDELY_ENV\");\n const id = `${sdkKey}|${apiUrl ?? \"\"}|${environment ?? \"\"}|${options.pollingMode ?? \"auto\"}`;\n const reg = registry();\n let client = reg.clients.get(id);\n if (!client) {\n client = createFlagsClient({ storage: false, ...options, sdkKey, apiUrl, environment, fetch: options.fetch ?? noStoreFetch });\n reg.clients.set(id, client);\n }\n reg.current = client;\n return client;\n}\n\nfunction settle(client: FlagsClient, timeoutMs: number): Promise<void> {\n if (client.isReady()) return Promise.resolve();\n return Promise.race([client.ready(), new Promise<void>((r) => setTimeout(r, timeoutMs))]);\n}\n\nexport interface GetFlagsOptions {\n /** A client from `createServerFlags(...)` (default: the last one created, or one from environment variables). */\n client?: FlagsClient;\n /** How long to wait for the first download before serving fallbacks (default 1500 ms). */\n timeoutMs?: number;\n}\n\n/**\n * Flag getters for one user, for this request. Waits (briefly, the first time only) for the\n * flags to load. Pass the same attributes you give the browser (`flagAttributes` / `user`) so\n * server and client agree.\n */\nexport async function getFlags(attributes: Attributes = {}, options: GetFlagsOptions = {}): Promise<FlagsEvaluator> {\n const client = options.client ?? registry().current ?? createServerFlags();\n await settle(client, options.timeoutMs ?? 1500);\n return client.forUser(attributes);\n}\n\n/**\n * The payload to pass to `<GuidelyProvider flagsPayload={…}>` / `<FlagsProvider payload={…}>` so\n * the first render matches the server. Returns `null` for a `gly_sk_` client: its payload holds\n * server-only flags that must not reach browsers — bootstrap from a public-key client instead.\n */\nexport async function getFlagsBootstrap(options: GetFlagsOptions = {}): Promise<FlagsBootstrap | null> {\n const client = options.client ?? registry().current ?? createServerFlags();\n if (client.sdkKey.startsWith(\"gly_sk_\")) {\n const reg = registry();\n if (!reg.warned.has(client.sdkKey)) {\n reg.warned.add(client.sdkKey);\n console.warn(\"[Guidely] getFlagsBootstrap() needs a public-key client (pk_…): a gly_sk_ payload includes server-only flags. Pass { client: createServerFlags({ sdkKey: process.env.NEXT_PUBLIC_GUIDELY_PROJECT_ID }) }.\");\n }\n return null;\n }\n await settle(client, options.timeoutMs ?? 1500);\n return client.getPayload();\n}\n"],"mappings":";AAUA,SAAS,yBAA+H;AAWxI,SAAS,WAAqB;AAC5B,QAAM,IAAI;AACV,SAAQ,EAAE,yBAAF,EAAE,uBAAyB,EAAE,SAAS,oBAAI,IAAI,GAAG,SAAS,MAAM,QAAQ,oBAAI,IAAI,EAAE;AAC5F;AAEA,SAAS,IAAI,MAAkC;AAC7C,MAAI;AACF,WAAQ,WAA0E,SAAS,MAAM,IAAI,KAAK;AAAA,EAC5G,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,IAAM,eAA6B,CAAC,OAAO,SAAS;AAClD,QAAM,WAAY,WAAW,MAA+D;AAC5F,SAAO,WAAW,SAAS,OAAO,IAAI,IAAI,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,WAAW,CAAC;AACvF;AASO,SAAS,kBAAkB,UAAuC,CAAC,GAAgB;AACxF,QAAM,SAAS,QAAQ,UAAU,QAAQ,aAAa,IAAI,iBAAiB,KAAK,IAAI,gCAAgC;AACpH,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,qGAAqG;AAClI,QAAM,SAAS,QAAQ,UAAU,IAAI,iBAAiB,KAAK,IAAI,6BAA6B;AAC5F,QAAM,cAAc,QAAQ,eAAe,IAAI,aAAa,KAAK,IAAI,yBAAyB;AAC9F,QAAM,KAAK,GAAG,MAAM,IAAI,UAAU,EAAE,IAAI,eAAe,EAAE,IAAI,QAAQ,eAAe,MAAM;AAC1F,QAAM,MAAM,SAAS;AACrB,MAAI,SAAS,IAAI,QAAQ,IAAI,EAAE;AAC/B,MAAI,CAAC,QAAQ;AACX,aAAS,kBAAkB,EAAE,SAAS,OAAO,GAAG,SAAS,QAAQ,QAAQ,aAAa,OAAO,QAAQ,SAAS,aAAa,CAAC;AAC5H,QAAI,QAAQ,IAAI,IAAI,MAAM;AAAA,EAC5B;AACA,MAAI,UAAU;AACd,SAAO;AACT;AAEA,SAAS,OAAO,QAAqB,WAAkC;AACrE,MAAI,OAAO,QAAQ,EAAG,QAAO,QAAQ,QAAQ;AAC7C,SAAO,QAAQ,KAAK,CAAC,OAAO,MAAM,GAAG,IAAI,QAAc,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC;AAC1F;AAcA,eAAsB,SAAS,aAAyB,CAAC,GAAG,UAA2B,CAAC,GAA4B;AAClH,QAAM,SAAS,QAAQ,UAAU,SAAS,EAAE,WAAW,kBAAkB;AACzE,QAAM,OAAO,QAAQ,QAAQ,aAAa,IAAI;AAC9C,SAAO,OAAO,QAAQ,UAAU;AAClC;AAOA,eAAsB,kBAAkB,UAA2B,CAAC,GAAmC;AACrG,QAAM,SAAS,QAAQ,UAAU,SAAS,EAAE,WAAW,kBAAkB;AACzE,MAAI,OAAO,OAAO,WAAW,SAAS,GAAG;AACvC,UAAM,MAAM,SAAS;AACrB,QAAI,CAAC,IAAI,OAAO,IAAI,OAAO,MAAM,GAAG;AAClC,UAAI,OAAO,IAAI,OAAO,MAAM;AAC5B,cAAQ,KAAK,gNAA2M;AAAA,IAC1N;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,QAAQ,QAAQ,aAAa,IAAI;AAC9C,SAAO,OAAO,WAAW;AAC3B;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/server-errors.ts"],"sourcesContent":["/**\n * `@guidelytech/nextjs/server` — feature flags on the server: React Server Components, route\n * handlers, server actions, middleware and edge functions. No React and no `\"use client\"` here.\n *\n * ```ts\n * import { getFlags, getFlagsBootstrap } from \"@guidelytech/nextjs/server\";\n * const flags = await getFlags({ id: user.id, plan: user.plan });\n * if (flags.isEnabled(\"new-dashboard-banner\")) …\n * ```\n */\nimport { createFlagsClient, type Attributes, type FlagsBootstrap, type FlagsClient, type FlagsClientOptions, type FlagsEvaluator } from \"@guidelytech/flags\";\n\nexport type { Attributes, FlagsBootstrap, FlagsClient, FlagsClientOptions, FlagsEvaluator, FlagDetails, JsonValue } from \"@guidelytech/flags\";\n\ninterface Registry {\n clients: Map<string, FlagsClient>;\n current: FlagsClient | null;\n warned: Set<string>;\n}\n\n/** Kept on `globalThis` so dev-server hot reloads reuse the client (and its timers) instead of leaking new ones. */\nfunction registry(): Registry {\n const g = globalThis as { __guidelyServerFlags?: Registry };\n return (g.__guidelyServerFlags ??= { clients: new Map(), current: null, warned: new Set() });\n}\n\nfunction env(name: string): string | undefined {\n try {\n return (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.[name] || undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Flag downloads must always reach Guidely and outlive the request that started them: use the\n * fetch Next.js wrapped (no data cache, no request scope), else ask for `no-store`.\n */\nconst noStoreFetch: typeof fetch = (input, init) => {\n const original = (globalThis.fetch as typeof fetch & { _nextOriginalFetch?: typeof fetch })._nextOriginalFetch;\n return original ? original(input, init) : fetch(input, { ...init, cache: \"no-store\" });\n};\n\n/**\n * The process-wide flags client (created once, then reused across requests and hot reloads).\n * Options default to `GUIDELY_SDK_KEY` (a public `pk_…` or secret `gly_sk_…` key), falling back to\n * `NEXT_PUBLIC_GUIDELY_PROJECT_ID`, plus `GUIDELY_API_URL` / `NEXT_PUBLIC_GUIDELY_API_URL` and\n * `GUIDELY_ENV` / `NEXT_PUBLIC_GUIDELY_ENV`. Polls every 60 s by default; in middleware and\n * edge functions use `{ pollingMode: \"lazy\" }` (refreshes on read once the cache is stale).\n */\nexport function createServerFlags(options: Partial<FlagsClientOptions> = {}): FlagsClient {\n const sdkKey = options.sdkKey ?? options.projectId ?? env(\"GUIDELY_SDK_KEY\") ?? env(\"NEXT_PUBLIC_GUIDELY_PROJECT_ID\");\n if (!sdkKey) throw new Error(\"[Guidely] createServerFlags: pass `sdkKey` or set GUIDELY_SDK_KEY / NEXT_PUBLIC_GUIDELY_PROJECT_ID.\");\n const apiUrl = options.apiUrl ?? env(\"GUIDELY_API_URL\") ?? env(\"NEXT_PUBLIC_GUIDELY_API_URL\");\n const environment = options.environment ?? env(\"GUIDELY_ENV\") ?? env(\"NEXT_PUBLIC_GUIDELY_ENV\");\n const id = `${sdkKey}|${apiUrl ?? \"\"}|${environment ?? \"\"}|${options.pollingMode ?? \"auto\"}`;\n const reg = registry();\n let client = reg.clients.get(id);\n if (!client) {\n client = createFlagsClient({ storage: false, ...options, sdkKey, apiUrl, environment, fetch: options.fetch ?? noStoreFetch });\n reg.clients.set(id, client);\n }\n reg.current = client;\n return client;\n}\n\nfunction settle(client: FlagsClient, timeoutMs: number): Promise<void> {\n if (client.isReady()) return Promise.resolve();\n return Promise.race([client.ready(), new Promise<void>((r) => setTimeout(r, timeoutMs))]);\n}\n\nexport interface GetFlagsOptions {\n /** A client from `createServerFlags(...)` (default: the last one created, or one from environment variables). */\n client?: FlagsClient;\n /** How long to wait for the first download before serving fallbacks (default 1500 ms). */\n timeoutMs?: number;\n}\n\n/**\n * Flag getters for one user, for this request. Waits (briefly, the first time only) for the\n * flags to load. Pass the same attributes you give the browser (`flagAttributes` / `user`) so\n * server and client agree.\n */\nexport async function getFlags(attributes: Attributes = {}, options: GetFlagsOptions = {}): Promise<FlagsEvaluator> {\n const client = options.client ?? registry().current ?? createServerFlags();\n await settle(client, options.timeoutMs ?? 1500);\n return client.forUser(attributes);\n}\n\n/**\n * The payload to pass to `<GuidelyProvider flagsPayload={…}>` / `<FlagsProvider payload={…}>` so\n * the first render matches the server. Returns `null` for a `gly_sk_` client: its payload holds\n * server-only flags that must not reach browsers — bootstrap from a public-key client instead.\n */\nexport async function getFlagsBootstrap(options: GetFlagsOptions = {}): Promise<FlagsBootstrap | null> {\n const client = options.client ?? registry().current ?? createServerFlags();\n if (client.sdkKey.startsWith(\"gly_sk_\")) {\n const reg = registry();\n if (!reg.warned.has(client.sdkKey)) {\n reg.warned.add(client.sdkKey);\n console.warn(\"[Guidely] getFlagsBootstrap() needs a public-key client (pk_…): a gly_sk_ payload includes server-only flags. Pass { client: createServerFlags({ sdkKey: process.env.NEXT_PUBLIC_GUIDELY_PROJECT_ID }) }.\");\n }\n return null;\n }\n await settle(client, options.timeoutMs ?? 1500);\n return client.getPayload();\n}\n\n// Error monitoring: `onRequestError` for instrumentation.ts, route handler and server action wrappers.\nexport { captureRequestError, captureServerError, createOnRequestError, isNextControlError, onRequestError, setGuidelyServerClient, withGuidely, withServerActionGuidely } from \"./server-errors\";\nexport type { CaptureInput, GuidelyServerErrorClient, RequestErrorContext, RequestErrorRequest, RouteHandlerOptions, ServerActionOptions, ServerErrorOptions } from \"./server-errors\";\n","/**\n * Server-side error monitoring for Next.js: `onRequestError` for `instrumentation.ts`, plus wrappers\n * for route handlers and server actions. Errors go to a server Guidely client you register once\n * (`@guidelytech/node`'s `Guidely`, or anything with its `captureException`), typed structurally so\n * this entry stays free of Node built-ins and loads in the edge runtime and middleware too.\n * Nothing here throws into the request, and nothing waits for the network on the request's path.\n */\n\n/** What capture uses from a server client; `new Guidely({ secretKey, environment })` from `@guidelytech/node` fits. */\nexport interface GuidelyServerErrorClient {\n captureException(error: unknown, context?: Record<string, unknown>): string | void;\n /** Sends what is queued; used (bounded by `flushTimeoutMs`) to get the error out before a serverless function freezes. */\n flush?(): Promise<void>;\n /** Used to name the event's transaction (`GET /blog/[slug]`). */\n withScope?<T>(fn: (scope: { setTransactionName?(name: string | undefined): unknown }) => T): T;\n}\n\nexport interface ServerErrorOptions {\n /** The client to report to (default: the one given to `setGuidelyServerClient`). */\n client?: GuidelyServerErrorClient | null;\n /** Longest the background flush may run (default 2000 ms; 0 skips it). */\n flushTimeoutMs?: number;\n /**\n * Wait for the flush before returning, for serverless hosts that freeze the function after the\n * response and offer no `waitUntil` (Vercel and Next's own servers do). Default false.\n */\n waitForFlush?: boolean;\n}\n\n/** `onRequestError`'s second argument (Next.js 15). */\nexport interface RequestErrorRequest {\n path: string;\n method: string;\n headers: Record<string, string | string[] | undefined>;\n}\n\n/** `onRequestError`'s third argument (Next.js 15). */\nexport interface RequestErrorContext {\n routerKind: \"Pages Router\" | \"App Router\" | (string & {});\n routePath: string;\n routeType: \"render\" | \"route\" | \"action\" | \"middleware\" | (string & {});\n renderSource?: string;\n revalidateReason?: string;\n renderType?: string;\n}\n\ninterface ErrorRegistry {\n client: GuidelyServerErrorClient | null;\n /** Errors already reported: a route handler wrapper and `onRequestError` see the same error. */\n reported: WeakSet<object>;\n warned: boolean;\n}\n\n/** Kept on `globalThis` so dev-server hot reloads keep the registered client. */\nfunction registry(): ErrorRegistry {\n const g = globalThis as { __guidelyServerErrors?: ErrorRegistry };\n return (g.__guidelyServerErrors ??= { client: null, reported: new WeakSet(), warned: false });\n}\n\n/**\n * Registers the server client every capture here reports to. Call it from `register()` in\n * `instrumentation.ts` (Node.js runtime), or anywhere before the first request.\n */\nexport function setGuidelyServerClient(client: GuidelyServerErrorClient | null): void {\n registry().client = client;\n}\n\n/** Credentials never leave the server: cookies, auth headers and anything named like a secret. */\nconst SENSITIVE_HEADER = /^(?:cookie|set-cookie|authorization|proxy-authorization)$|token|secret|password|api[-_]?key|session|csrf/i;\n\n/** Request headers without credentials, as a plain record (at most 50, values ≤ 1000 characters). */\nexport function safeHeaders(headers: unknown): Record<string, string> {\n const out: Record<string, string> = {};\n const add = (name: string, value: unknown) => {\n if (Object.keys(out).length >= 50 || value === undefined || value === null || SENSITIVE_HEADER.test(name)) return;\n out[name.toLowerCase()] = (Array.isArray(value) ? value.join(\", \") : String(value)).slice(0, 1000);\n };\n try {\n const h = headers as { forEach?: (cb: (value: string, name: string) => void) => void } | null;\n if (h && typeof h.forEach === \"function\" && !Array.isArray(h)) h.forEach((value, name) => add(name, value));\n else if (h && typeof h === \"object\") for (const [name, value] of Object.entries(h)) add(name, value);\n } catch {\n // unreadable headers: report without them\n }\n return out;\n}\n\n/** `redirect()`, `notFound()`, dynamic-rendering bail-outs and React postpones: control flow, not errors. */\nexport function isNextControlError(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const e = error as { digest?: unknown; message?: unknown; $$typeof?: unknown };\n if (e.$$typeof === Symbol.for(\"react.postpone\")) return true;\n const digest = typeof e.digest === \"string\" ? e.digest : typeof e.message === \"string\" ? e.message : \"\";\n return /^(?:NEXT_REDIRECT|NEXT_NOT_FOUND|NEXT_HTTP_ERROR_FALLBACK|DYNAMIC_SERVER_USAGE|BAILOUT_TO_CLIENT_SIDE_RENDERING|NEXT_PRERENDER_INTERRUPTED|HANGING_PROMISE_REJECTION)/.test(digest);\n}\n\ntype WaitUntil = (promise: Promise<unknown>) => void;\n\n/** The host's `waitUntil` for the running request (Next.js 15's request context, else Vercel's). */\nfunction requestWaitUntil(): WaitUntil | undefined {\n try {\n const g = globalThis as Record<symbol, { get?: () => { waitUntil?: WaitUntil } | undefined } | undefined>;\n for (const key of [\"@next/request-context\", \"@vercel/request-context\"]) {\n const waitUntil = g[Symbol.for(key)]?.get?.()?.waitUntil;\n if (typeof waitUntil === \"function\") return waitUntil;\n }\n } catch {\n // no request context\n }\n return undefined;\n}\n\n/** Flushes in the background, bounded by `flushTimeoutMs`; the promise never rejects. */\nfunction flushSoon(client: GuidelyServerErrorClient, options: ServerErrorOptions): Promise<void> | undefined {\n const timeout = options.flushTimeoutMs ?? 2000;\n if (typeof client.flush !== \"function\" || timeout <= 0) return undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const p = Promise.race([\n Promise.resolve()\n .then(() => client.flush!())\n .catch(() => {}),\n new Promise<void>((resolve) => {\n timer = setTimeout(resolve, timeout);\n (timer as { unref?: () => void }).unref?.();\n }),\n ]).finally(() => clearTimeout(timer));\n const waitUntil = requestWaitUntil();\n if (waitUntil) {\n try {\n waitUntil(p);\n } catch {\n // the request already ended\n }\n }\n return p;\n}\n\nexport interface CaptureInput {\n tags?: Record<string, string>;\n contexts?: Record<string, Record<string, unknown>>;\n request?: { method?: string; url?: string; headers: Record<string, string> };\n /** `GET /blog/[slug]`, `serverAction/checkout`. */\n transaction?: string;\n mechanism: string;\n}\n\n/**\n * Reports one server error (once per error object, never Next.js control flow) and starts a\n * bounded background flush. Returns the event id (\"\" when nothing was reported) and the flush.\n */\nexport function captureServerError(error: unknown, input: CaptureInput, options: ServerErrorOptions = {}): { eventId: string; flushed?: Promise<void> } {\n try {\n if (isNextControlError(error)) return { eventId: \"\" };\n const reg = registry();\n const client = options.client ?? reg.client;\n if (!client) {\n if (!reg.warned) {\n reg.warned = true;\n console.warn(\"[Guidely] A server error was not reported: no server client. Call setGuidelyServerClient(new Guidely({ secretKey, environment })) from register() in instrumentation.ts.\");\n }\n return { eventId: \"\" };\n }\n if (error && typeof error === \"object\") {\n if (reg.reported.has(error)) return { eventId: \"\" };\n reg.reported.add(error);\n }\n const digest = error && typeof error === \"object\" && typeof (error as { digest?: unknown }).digest === \"string\" ? (error as { digest: string }).digest : undefined;\n const nextjs = { ...(input.contexts?.nextjs ?? {}), ...(digest ? { digest } : {}) };\n const ctx: Record<string, unknown> = {\n level: \"error\",\n ...(input.tags ? { tags: input.tags } : {}),\n contexts: { ...(input.contexts ?? {}), ...(Object.keys(nextjs).length ? { nextjs } : {}) },\n ...(input.request ? { request: input.request } : {}),\n mechanism: { type: input.mechanism, handled: false },\n };\n const run = () => client.captureException(error, ctx);\n const id = input.transaction && typeof client.withScope === \"function\"\n ? client.withScope((scope) => {\n scope.setTransactionName?.(input.transaction);\n return run();\n })\n : run();\n return { eventId: typeof id === \"string\" ? id : \"\", flushed: flushSoon(client, options) };\n } catch {\n return { eventId: \"\" };\n }\n}\n\nconst str = (v: unknown): string | undefined => (typeof v === \"string\" && v ? v : undefined);\n\n/**\n * `onRequestError` for `instrumentation.ts` (Next.js 15+): every error thrown while rendering, in\n * route handlers, server actions and middleware, with the request (credentials removed) and the\n * route as tags (`routerKind`, `routePath`, `routeType`).\n *\n * ```ts\n * // instrumentation.ts\n * import { setGuidelyServerClient } from \"@guidelytech/nextjs/server\";\n * export async function register() {\n * if (process.env.NEXT_RUNTIME === \"nodejs\") {\n * const { Guidely } = await import(\"@guidelytech/node\");\n * setGuidelyServerClient(new Guidely({ secretKey: process.env.GUIDELY_SECRET_KEY!, environment: \"production\" }));\n * }\n * }\n * export { onRequestError } from \"@guidelytech/nextjs/server\";\n * ```\n */\nexport function createOnRequestError(options: ServerErrorOptions = {}): (error: unknown, request: Readonly<RequestErrorRequest>, context: Readonly<RequestErrorContext>) => Promise<void> {\n return async (error, request, context) => {\n try {\n const tags: Record<string, string> = {};\n const nextjs: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(context ?? {})) {\n if (typeof v !== \"string\" || !v) continue;\n nextjs[k] = v;\n if (k === \"routerKind\" || k === \"routePath\" || k === \"routeType\") tags[k] = v;\n }\n const method = str(request?.method)?.toUpperCase();\n const route = str(context?.routePath);\n const { flushed } = captureServerError(\n error,\n {\n tags,\n contexts: { nextjs },\n request: { method, url: str(request?.path), headers: safeHeaders(request?.headers) },\n transaction: route ? (method && context?.routeType !== \"render\" ? `${method} ${route}` : route) : undefined,\n mechanism: \"nextjs.onRequestError\",\n },\n options,\n );\n // Next.js awaits this hook before it answers: only hold the response when asked to.\n if (options.waitForFlush && flushed) await flushed;\n } catch {\n // never break the request\n }\n };\n}\n\n/** `export { onRequestError } from \"@guidelytech/nextjs/server\"` (Sentry's `captureRequestError`). */\nexport const onRequestError = createOnRequestError();\nexport const captureRequestError = onRequestError;\n\n/** A Fetch `Request` (route handlers, middleware), read structurally. */\nfunction requestOf(input: unknown): { method?: string; url?: string; headers: Record<string, string>; path?: string } | undefined {\n if (!input || typeof input !== \"object\") return undefined;\n const r = input as { method?: unknown; url?: unknown; headers?: unknown };\n if (typeof r.url !== \"string\" || !r.headers) return undefined;\n let path: string | undefined;\n try {\n path = new URL(r.url).pathname;\n } catch {\n path = undefined;\n }\n return { method: str(r.method)?.toUpperCase(), url: r.url, headers: safeHeaders(r.headers), path };\n}\n\nexport interface RouteHandlerOptions extends ServerErrorOptions {\n /** The route's pattern for the transaction (`/api/users/[id]`; default: the request's path). */\n route?: string;\n}\n\n/**\n * Wraps a route handler (or any request handler): an error it throws is reported with the request\n * and rethrown unchanged, so Next.js answers as before. Sync handlers stay sync.\n *\n * ```ts\n * export const GET = withGuidely(async (req: Request) => Response.json(await load()));\n * ```\n */\nexport function withGuidely<F extends (...args: any[]) => any>(handler: F, options: RouteHandlerOptions = {}): F {\n const report = (error: unknown, args: unknown[]) => {\n const req = requestOf(args[0]);\n const route = options.route ?? req?.path;\n captureServerError(error, { tags: { routeType: \"route\", ...(options.route ? { routePath: options.route } : {}) }, request: req && { method: req.method, url: req.url, headers: req.headers }, transaction: route ? `${req?.method ? `${req.method} ` : \"\"}${route}` : undefined, mechanism: \"nextjs.route_handler\" }, options);\n };\n const wrapped = function (this: unknown, ...args: unknown[]) {\n let out: unknown;\n try {\n out = handler.apply(this, args);\n } catch (error) {\n report(error, args);\n throw error;\n }\n if (out && typeof (out as Promise<unknown>).then === \"function\") {\n return (out as Promise<unknown>).then(undefined, (error: unknown) => {\n report(error, args);\n throw error;\n });\n }\n return out;\n };\n return wrapped as unknown as F;\n}\n\ntype HeadersInput = unknown | Promise<unknown> | (() => unknown | Promise<unknown>);\n\nexport interface ServerActionOptions extends ServerErrorOptions {\n /** The request headers to report with errors: `headers` from `next/headers` (the function, or its result). */\n headers?: HeadersInput;\n}\n\n/**\n * Wraps a server action: an error it throws is reported (tagged `serverAction: <name>`) and\n * rethrown, so the client still sees it. `redirect()` and `notFound()` pass through unreported.\n *\n * ```ts\n * \"use server\";\n * import { headers } from \"next/headers\";\n * export const checkout = withServerActionGuidely(\"checkout\", async (form: FormData) => { … }, { headers });\n * ```\n */\nexport function withServerActionGuidely<A extends unknown[], R>(name: string, action: (...args: A) => R | Promise<R>, options: ServerActionOptions = {}): (...args: A) => Promise<R> {\n return async (...args: A): Promise<R> => {\n try {\n return await action(...args);\n } catch (error) {\n if (!isNextControlError(error)) {\n let headers: Record<string, string> | undefined;\n try {\n const h = typeof options.headers === \"function\" ? (options.headers as () => unknown)() : options.headers;\n headers = h ? safeHeaders(await h) : undefined;\n } catch {\n headers = undefined; // outside a request (tests, scripts)\n }\n const { flushed } = captureServerError(error, { tags: { routeType: \"action\", serverAction: name.slice(0, 200) }, contexts: { nextjs: { serverAction: name } }, ...(headers ? { request: { method: \"POST\", headers } } : {}), transaction: `serverAction/${name}`, mechanism: \"nextjs.server_action\" }, options);\n if (options.waitForFlush && flushed) await flushed;\n }\n throw error;\n }\n };\n}\n"],"mappings":"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","names":["registry"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guidelytech/nextjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Next.js App Router helpers for Guidely: provider, navigation bridge and server-side feature flags",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@guidelytech/
|
|
29
|
-
"@guidelytech/
|
|
30
|
-
"@guidelytech/sdk-core": "0.
|
|
28
|
+
"@guidelytech/react": "0.17.0",
|
|
29
|
+
"@guidelytech/flags": "0.17.0",
|
|
30
|
+
"@guidelytech/sdk-core": "0.17.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"tsup": "^8.5.1",
|